android.rs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::cmp::{max, min};
  19. use super::driver::ParleyDriverWrapper;
  20. use crate::{
  21. android::textinput::{AndroidTextInput, AndroidTextInputState},
  22. gfx::Point,
  23. mesh::Color,
  24. prop::{PropertyAtomicGuard, PropertyColor, PropertyFloat32, PropertyStr},
  25. text,
  26. };
  27. macro_rules! t { ($($arg:tt)*) => { trace!(target: "text::editor::android", $($arg)*); } }
  28. pub struct Editor {
  29. input: AndroidTextInput,
  30. pub state: AndroidTextInputState,
  31. pub recvr: async_channel::Receiver<AndroidTextInputState>,
  32. layout: parley::Layout<Color>,
  33. width: Option<f32>,
  34. text: PropertyStr,
  35. font_size: PropertyFloat32,
  36. text_color: PropertyColor,
  37. window_scale: PropertyFloat32,
  38. lineheight: PropertyFloat32,
  39. }
  40. impl Editor {
  41. pub fn new(
  42. text: PropertyStr,
  43. font_size: PropertyFloat32,
  44. text_color: PropertyColor,
  45. window_scale: PropertyFloat32,
  46. lineheight: PropertyFloat32,
  47. ) -> Self {
  48. let (sender, recvr) = async_channel::unbounded();
  49. let input = AndroidTextInput::new(sender);
  50. Self {
  51. input,
  52. state: Default::default(),
  53. recvr,
  54. layout: Default::default(),
  55. width: None,
  56. text,
  57. font_size,
  58. text_color,
  59. window_scale,
  60. lineheight,
  61. }
  62. }
  63. pub fn on_text_prop_changed(&mut self) {
  64. // Update GameTextInput state
  65. self.state.text = self.text.get();
  66. let text_len = self.state.text.len();
  67. self.state.select = (text_len, text_len);
  68. self.state.compose = None;
  69. self.input.set_state(self.state.clone());
  70. // Refresh our layout
  71. self.refresh();
  72. }
  73. pub fn on_buffer_changed(&mut self, atom: &mut PropertyAtomicGuard) {
  74. // Only refresh layout if text content actually changed
  75. // Avoid triggering expensive recomputes of layout and property tree.
  76. let old_text = self.text.get();
  77. if old_text == self.state.text {
  78. return
  79. }
  80. self.refresh();
  81. // Update the text attribute
  82. self.text.set(atom, &self.state.text);
  83. }
  84. pub fn focus(&mut self) {
  85. self.input.show();
  86. }
  87. pub fn unfocus(&mut self) {
  88. self.input.hide();
  89. }
  90. pub fn refresh(&mut self) {
  91. let font_size = self.font_size.get();
  92. let text_color = self.text_color.get();
  93. let window_scale = self.window_scale.get();
  94. let lineheight = self.lineheight.get();
  95. let mut underlines = vec![];
  96. if let Some((compose_start, compose_end)) = self.state.compose {
  97. underlines.push(compose_start..compose_end);
  98. }
  99. self.layout = text::make_layout(
  100. &self.state.text,
  101. text_color,
  102. font_size,
  103. lineheight,
  104. window_scale,
  105. self.width,
  106. &underlines,
  107. );
  108. }
  109. pub fn layout(&self) -> &parley::Layout<Color> {
  110. &self.layout
  111. }
  112. pub fn move_to_pos(&mut self, pos: Point) {
  113. let cursor = parley::Cursor::from_point(&self.layout, pos.x, pos.y);
  114. let cursor_idx = cursor.index();
  115. t!(" move_to_pos: {cursor_idx}");
  116. assert!(cursor_idx <= self.state.text.len());
  117. assert_eq!(self.state.text, self.text.get());
  118. self.state.select = (cursor_idx, cursor_idx);
  119. self.input.set_select(cursor_idx, cursor_idx);
  120. }
  121. pub fn select_word_at_point(&mut self, pos: Point) {
  122. let select = parley::Selection::word_from_point(&self.layout, pos.x, pos.y);
  123. assert!(!select.is_collapsed());
  124. let select = select.text_range();
  125. self.set_selection(select.start, select.end);
  126. }
  127. pub fn get_cursor_pos(&self) -> Point {
  128. let lineheight = self.lineheight.get();
  129. let cursor_idx = self.state.select.0;
  130. let cursor = if cursor_idx >= self.state.text.len() {
  131. parley::Cursor::from_byte_index(
  132. &self.layout,
  133. self.state.text.len(),
  134. parley::Affinity::Upstream,
  135. )
  136. } else {
  137. parley::Cursor::from_byte_index(&self.layout, cursor_idx, parley::Affinity::Downstream)
  138. };
  139. let cursor_rect = cursor.geometry(&self.layout, lineheight);
  140. Point::new(cursor_rect.x0 as f32, cursor_rect.y0 as f32)
  141. }
  142. pub fn insert(&mut self, txt: &str, atom: &mut PropertyAtomicGuard) {
  143. // TODO: need to verify this is correct
  144. // Insert text by updating the state
  145. self.state.text.push_str(txt);
  146. let cursor_idx = self.state.text.len();
  147. self.state.select = (cursor_idx, cursor_idx);
  148. self.state.compose = None;
  149. self.input.set_state(self.state.clone());
  150. self.on_buffer_changed(atom);
  151. }
  152. pub fn driver(&mut self) -> ParleyDriverWrapper<'_> {
  153. ParleyDriverWrapper::new(&mut self.layout)
  154. }
  155. pub fn set_width(&mut self, w: f32) {
  156. self.width = Some(w);
  157. }
  158. pub fn width(&self) -> f32 {
  159. self.layout().full_width()
  160. }
  161. pub fn height(&self) -> f32 {
  162. self.layout().height()
  163. }
  164. pub fn selected_text(&self) -> Option<String> {
  165. let (start, end) = (self.state.select.0, self.state.select.1);
  166. if start == end {
  167. return None
  168. }
  169. let (start, end) = (min(start, end), max(start, end));
  170. Some(self.state.text[start..end].to_string())
  171. }
  172. pub fn selection(&self, side: isize) -> parley::Selection {
  173. assert!(side.abs() == 1);
  174. //t!("selection({side}) [state={:?}]", self.state);
  175. let (start, end) = (self.state.select.0, self.state.select.1);
  176. let (anchor, focus) = match side {
  177. -1 => (end, start),
  178. 1 => (start, end),
  179. _ => panic!(),
  180. };
  181. let anchor =
  182. parley::Cursor::from_byte_index(&self.layout, anchor, parley::Affinity::Downstream);
  183. let focus =
  184. parley::Cursor::from_byte_index(&self.layout, focus, parley::Affinity::Downstream);
  185. parley::Selection::new(anchor, focus)
  186. }
  187. pub fn set_selection(&mut self, select_start: usize, select_end: usize) {
  188. assert!(select_start <= self.state.text.len());
  189. assert!(select_end <= self.state.text.len());
  190. assert_eq!(self.state.text, self.text.get());
  191. self.state.select = (select_start, select_end);
  192. self.input.set_select(select_start, select_end);
  193. }
  194. pub fn select_all(&mut self) {
  195. let text_len = self.state.text.len();
  196. self.state.select = (0, text_len);
  197. self.input.set_select(0, text_len);
  198. }
  199. #[allow(dead_code)]
  200. pub fn buffer(&self) -> String {
  201. self.state.text.clone()
  202. }
  203. pub fn set_input_type(&mut self, input_type: u32) {
  204. self.input.set_input_type(input_type);
  205. }
  206. }