1use std::ops::Mul;
2
3use freya_core::{
4 elements::paragraph::ParagraphHolderInner,
5 prelude::*,
6};
7use torin::prelude::CursorPoint;
8
9use crate::{
10 EditableConfig,
11 rope_editor::RopeEditor,
12 text_editor::{
13 TextEditor,
14 TextEvent,
15 },
16};
17
18pub enum EditableEvent<'a> {
19 Release,
20 Move {
21 location: CursorPoint,
22 editor_id: usize,
23 holder: &'a ParagraphHolder,
24 },
25 Down {
26 location: CursorPoint,
27 editor_id: usize,
28 holder: &'a ParagraphHolder,
29 },
30 KeyDown {
31 key: &'a Key,
32 modifiers: Modifiers,
33 },
34 KeyUp {
35 key: &'a Key,
36 },
37}
38
39impl EditableEvent<'_> {
40 pub fn process<'a, 'b>(
41 self,
42 mut editor: impl MutView<'b, RopeEditor>,
43 mut dragging: impl MutView<'b, TextDragging>,
44 config: &'_ EditableConfig,
45 ) {
46 match self {
47 EditableEvent::Down {
48 location,
49 editor_id,
50 holder,
51 } => {
52 let holder = holder.0.borrow();
53 let ParagraphHolderInner {
54 paragraph,
55 scale_factor,
56 } = holder.as_ref().unwrap();
57
58 dragging
59 .write()
60 .set_cursor_coords(location.mul(*scale_factor));
61
62 let mut text_editor = editor.write();
63 text_editor.clear_selection();
64
65 match EventsCombos::pressed(location) {
66 PressEventType::Triple => {
67 let char_position = paragraph.get_glyph_position_at_coordinate(
68 location.mul(*scale_factor).to_i32().to_tuple(),
69 );
70 let new_cursor = text_editor
71 .measure_new_cursor(char_position.position as usize, editor_id);
72
73 let line = text_editor.rope().char_to_line(new_cursor.pos());
75 let line_char = text_editor.rope().line_to_char(line);
76 let line_len = text_editor.rope().line(line).len_utf16_cu();
77
78 text_editor.set_selection((line_char, line_char + line_len));
80 }
81 PressEventType::Double => {
82 let char_position = paragraph.get_glyph_position_at_coordinate(
83 location.mul(*scale_factor).to_i32().to_tuple(),
84 );
85 let new_cursor = text_editor
86 .measure_new_cursor(char_position.position as usize, editor_id);
87
88 let selection = text_editor.find_word_boundaries(new_cursor.pos());
90
91 *text_editor.cursor_mut() = new_cursor.clone();
93 text_editor.set_selection(selection);
94 }
95 PressEventType::Single => {
96 let char_position = paragraph.get_glyph_position_at_coordinate(
97 location.mul(*scale_factor).to_i32().to_tuple(),
98 );
99 let new_cursor = text_editor
100 .measure_new_cursor(char_position.position as usize, editor_id);
101
102 if *text_editor.cursor() != new_cursor {
104 *text_editor.cursor_mut() = new_cursor;
105 if let TextDragging::FromCursorToPoint { cursor: from, .. } =
106 &*dragging.peek()
107 {
108 let to = text_editor.cursor_pos();
109 text_editor.set_selection((*from, to));
110 } else {
111 text_editor.clear_selection();
112 }
113 }
114 }
115 }
116 }
117 EditableEvent::Move {
118 location,
119 editor_id,
120 holder,
121 } => {
122 if let Some(origin) = dragging.peek().get_cursor_coords() {
123 let paragraph = holder.0.borrow();
124 let ParagraphHolderInner {
125 paragraph,
126 scale_factor,
127 } = paragraph.as_ref().unwrap();
128
129 let origin_position = origin;
130 let dist_position = location.mul(*scale_factor);
131
132 let origin_char = paragraph
134 .get_glyph_position_at_coordinate(origin_position.to_i32().to_tuple());
135 let dist_char = paragraph
137 .get_glyph_position_at_coordinate(dist_position.to_i32().to_tuple());
138 let from = origin_char.position as usize;
139 let to = dist_char.position as usize;
140
141 let current_cursor = editor.peek().cursor().clone();
142 let current_selection = editor.peek().get_selection();
143
144 let maybe_new_cursor = editor.peek().measure_new_cursor(to, editor_id);
145 let maybe_new_selection =
146 editor.peek().measure_new_selection(from, to, editor_id);
147
148 if let Some(current_selection) = current_selection {
150 if current_selection != maybe_new_selection {
151 let mut text_editor = editor.write();
152 text_editor.set_selection(maybe_new_selection);
153 }
154 } else {
155 let mut text_editor = editor.write();
156 text_editor.set_selection(maybe_new_selection);
157 }
158
159 if current_cursor != maybe_new_cursor {
161 let mut text_editor = editor.write();
162 *text_editor.cursor_mut() = maybe_new_cursor;
163 }
164 }
165 }
166 EditableEvent::Release => {
167 let dragging = &mut *dragging.write();
168 match dragging {
169 TextDragging::FromCursorToPoint { shift, clicked, .. } if *shift => {
170 *clicked = false;
171 }
172 _ => {
173 *dragging = TextDragging::None;
174 }
175 }
176 }
177 EditableEvent::KeyDown { key, modifiers } => {
178 match key {
179 Key::Shift => {
181 let dragging = &mut *dragging.write();
182 match dragging {
183 TextDragging::FromCursorToPoint {
184 shift: shift_pressed,
185 ..
186 } => {
187 *shift_pressed = true;
188 }
189 TextDragging::None => {
190 *dragging = TextDragging::FromCursorToPoint {
191 shift: true,
192 clicked: false,
193 cursor: editor.peek().cursor_pos(),
194 dist: None,
195 }
196 }
197 _ => {}
198 }
199 }
200 _ => {
202 editor.write_if(|mut ditor| {
203 let event = ditor.process_key(
204 key,
205 &modifiers,
206 config.allow_tabs,
207 config.allow_changes,
208 config.allow_clipboard,
209 );
210 if event.contains(TextEvent::TEXT_CHANGED) {
211 *dragging.write() = TextDragging::None;
212 }
213 !event.is_empty()
214 });
215 }
216 }
217 }
218 EditableEvent::KeyUp { key } => {
219 if *key == Key::Shift {
220 if let TextDragging::FromCursorToPoint { shift, .. } = &mut *dragging.write() {
221 *shift = false;
222 }
223 } else {
224 *dragging.write() = TextDragging::None;
225 }
226 }
227 };
228 }
229}
230
231#[derive(Debug, PartialEq, Clone)]
233pub enum TextDragging {
234 None,
235 FromPointToPoint {
236 src: CursorPoint,
237 },
238 FromCursorToPoint {
239 shift: bool,
240 clicked: bool,
241 cursor: usize,
242 dist: Option<CursorPoint>,
243 },
244}
245
246impl TextDragging {
247 pub fn has_cursor_coords(&self) -> bool {
248 match self {
249 Self::None => false,
250 Self::FromPointToPoint { .. } => true,
251 Self::FromCursorToPoint { dist, .. } => dist.is_some(),
252 }
253 }
254
255 pub fn set_cursor_coords(&mut self, cursor: CursorPoint) {
256 match self {
257 Self::FromPointToPoint { src } => *src = cursor,
258 Self::FromCursorToPoint {
259 dist, shift: true, ..
260 } => *dist = Some(cursor),
261 _ => *self = Self::FromPointToPoint { src: cursor },
262 }
263 }
264
265 pub fn get_cursor_coords(&self) -> Option<CursorPoint> {
266 match self {
267 Self::None => None,
268 Self::FromPointToPoint { src } => Some(*src),
269 Self::FromCursorToPoint { dist, clicked, .. } => {
270 if *clicked {
271 *dist
272 } else {
273 None
274 }
275 }
276 }
277 }
278}