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 let char_position = paragraph.get_glyph_position_at_coordinate(
66 location.mul(*scale_factor).to_i32().to_tuple(),
67 );
68 let new_cursor =
69 text_editor.measure_new_cursor(char_position.position as usize, editor_id);
70
71 if *text_editor.cursor() != new_cursor {
73 *text_editor.cursor_mut() = new_cursor;
74 if let TextDragging::FromCursorToPoint { cursor: from, .. } = &*dragging.peek()
75 {
76 let to = text_editor.cursor_pos();
77 text_editor.set_selection((*from, to));
78 } else {
79 text_editor.clear_selection();
80 }
81 }
82 }
83 EditableEvent::Move {
84 location,
85 editor_id,
86 holder,
87 } => {
88 if let Some(origin) = dragging.peek().get_cursor_coords() {
89 let paragraph = holder.0.borrow();
90 let ParagraphHolderInner {
91 paragraph,
92 scale_factor,
93 } = paragraph.as_ref().unwrap();
94
95 let origin_position = origin;
96 let dist_position = location.mul(*scale_factor);
97
98 let origin_char = paragraph
100 .get_glyph_position_at_coordinate(origin_position.to_i32().to_tuple());
101 let dist_char = paragraph
103 .get_glyph_position_at_coordinate(dist_position.to_i32().to_tuple());
104 let from = origin_char.position as usize;
105 let to = dist_char.position as usize;
106
107 let current_cursor = editor.peek().cursor().clone();
108 let current_selection = editor.peek().get_selection();
109
110 let maybe_new_cursor = editor.peek().measure_new_cursor(to, editor_id);
111 let maybe_new_selection =
112 editor.peek().measure_new_selection(from, to, editor_id);
113
114 if let Some(current_selection) = current_selection {
116 if current_selection != maybe_new_selection {
117 let mut text_editor = editor.write();
118 text_editor.set_selection(maybe_new_selection);
119 }
120 } else {
121 let mut text_editor = editor.write();
122 text_editor.set_selection(maybe_new_selection);
123 }
124
125 if current_cursor != maybe_new_cursor {
127 let mut text_editor = editor.write();
128 *text_editor.cursor_mut() = maybe_new_cursor;
129 }
130 }
131 }
132 EditableEvent::Release => {
133 let dragging = &mut *dragging.write();
134 match dragging {
135 TextDragging::FromCursorToPoint { shift, clicked, .. } if *shift => {
136 *clicked = false;
137 }
138 _ => {
139 *dragging = TextDragging::None;
140 }
141 }
142 }
143 EditableEvent::KeyDown { key, modifiers } => {
144 match key {
145 Key::Shift => {
147 let dragging = &mut *dragging.write();
148 match dragging {
149 TextDragging::FromCursorToPoint {
150 shift: shift_pressed,
151 ..
152 } => {
153 *shift_pressed = true;
154 }
155 TextDragging::None => {
156 *dragging = TextDragging::FromCursorToPoint {
157 shift: true,
158 clicked: false,
159 cursor: editor.peek().cursor_pos(),
160 dist: None,
161 }
162 }
163 _ => {}
164 }
165 }
166 _ => {
168 editor.write_if(|mut ditor| {
169 let event = ditor.process_key(
170 key,
171 &modifiers,
172 config.allow_tabs,
173 config.allow_changes,
174 config.allow_clipboard,
175 );
176 if event.contains(TextEvent::TEXT_CHANGED) {
177 *dragging.write() = TextDragging::None;
178 }
179 !event.is_empty()
180 });
181 }
182 }
183 }
184 EditableEvent::KeyUp { key } => {
185 if *key == Key::Shift {
186 if let TextDragging::FromCursorToPoint { shift, .. } = &mut *dragging.write() {
187 *shift = false;
188 }
189 } else {
190 *dragging.write() = TextDragging::None;
191 }
192 }
193 };
194 }
195}
196
197#[derive(Debug, PartialEq, Clone)]
199pub enum TextDragging {
200 None,
201 FromPointToPoint {
202 src: CursorPoint,
203 },
204 FromCursorToPoint {
205 shift: bool,
206 clicked: bool,
207 cursor: usize,
208 dist: Option<CursorPoint>,
209 },
210}
211
212impl TextDragging {
213 pub fn has_cursor_coords(&self) -> bool {
214 match self {
215 Self::None => false,
216 Self::FromPointToPoint { .. } => true,
217 Self::FromCursorToPoint { dist, .. } => dist.is_some(),
218 }
219 }
220
221 pub fn set_cursor_coords(&mut self, cursor: CursorPoint) {
222 match self {
223 Self::FromPointToPoint { src } => *src = cursor,
224 Self::FromCursorToPoint {
225 dist, shift: true, ..
226 } => *dist = Some(cursor),
227 _ => *self = Self::FromPointToPoint { src: cursor },
228 }
229 }
230
231 pub fn get_cursor_coords(&self) -> Option<CursorPoint> {
232 match self {
233 Self::None => None,
234 Self::FromPointToPoint { src } => Some(*src),
235 Self::FromCursorToPoint { dist, clicked, .. } => {
236 if *clicked {
237 *dist
238 } else {
239 None
240 }
241 }
242 }
243 }
244}