Skip to main content

freya_edit/
event.rs

1use std::ops::Mul;
2
3use freya_core::{
4    elements::paragraph::ParagraphHolderInner,
5    prelude::*,
6};
7use keyboard_types::NamedKey;
8use torin::prelude::CursorPoint;
9
10use crate::{
11    EditableConfig,
12    EditorLine,
13    TextSelection,
14    text_editor::{
15        TextEditor,
16        TextEvent,
17    },
18};
19
20#[derive(Debug)]
21pub enum EditableEvent<'a> {
22    Release,
23    Move {
24        location: CursorPoint,
25        editor_line: EditorLine,
26        holder: &'a ParagraphHolder,
27    },
28    Down {
29        location: CursorPoint,
30        editor_line: EditorLine,
31        holder: &'a ParagraphHolder,
32    },
33    KeyDown {
34        key: &'a Key,
35        modifiers: Modifiers,
36    },
37    KeyUp {
38        key: &'a Key,
39    },
40}
41
42impl EditableEvent<'_> {
43    pub fn process<T: TextEditor>(
44        self,
45        mut editor: Writable<T>,
46        mut dragging: Writable<TextDragging>,
47        config: &'_ EditableConfig,
48    ) {
49        match self {
50            EditableEvent::Down {
51                location,
52                editor_line,
53                holder,
54            } => {
55                let holder = holder.0.borrow();
56                let ParagraphHolderInner {
57                    paragraph,
58                    scale_factor,
59                } = holder.as_ref().unwrap();
60
61                let mut text_editor = editor.write();
62
63                if dragging.peek().shift || dragging.peek().clicked {
64                    text_editor.selection_mut().set_as_range();
65                } else {
66                    text_editor.clear_selection();
67                }
68
69                dragging.write().clicked = true;
70
71                match EventsCombos::pressed(location) {
72                    PressEventType::Triple => {
73                        let current_selection = text_editor.selection().clone();
74
75                        let char_position = paragraph.get_glyph_position_at_coordinate(
76                            location.mul(*scale_factor).to_i32().to_tuple(),
77                        );
78                        let press_selection = text_editor
79                            .measure_selection(char_position.position as usize, editor_line);
80
81                        // Get the line start char and its length
82                        let line = text_editor.char_to_line(press_selection.pos());
83                        let line_char = text_editor.line_to_char(line);
84                        let line_len = text_editor.line(line).unwrap().utf16_len();
85                        let new_selection =
86                            TextSelection::new_range((line_char, line_char + line_len));
87
88                        // Select the whole line
89                        if current_selection != new_selection {
90                            *text_editor.selection_mut() = new_selection;
91                        }
92                    }
93                    PressEventType::Double => {
94                        let current_selection = text_editor.selection().clone();
95
96                        let char_position = paragraph.get_glyph_position_at_coordinate(
97                            location.mul(*scale_factor).to_i32().to_tuple(),
98                        );
99                        let press_selection = text_editor
100                            .measure_selection(char_position.position as usize, editor_line);
101
102                        // Find word boundaries
103                        let range = text_editor.find_word_boundaries(press_selection.pos());
104                        let new_selection = TextSelection::new_range(range);
105
106                        // Select the word
107                        if current_selection != new_selection {
108                            *text_editor.selection_mut() = new_selection;
109                        }
110                    }
111                    PressEventType::Quadruple => {
112                        let current_selection = text_editor.selection().clone();
113                        let new_selection =
114                            TextSelection::new_range((0, text_editor.len_utf16_cu()));
115
116                        if current_selection != new_selection {
117                            *text_editor.selection_mut() = new_selection;
118                        }
119                    }
120                    PressEventType::Single => {
121                        let current_selection = text_editor.selection().clone();
122
123                        let char_position = paragraph.get_glyph_position_at_coordinate(
124                            location.mul(*scale_factor).to_i32().to_tuple(),
125                        );
126                        let new_selection = text_editor
127                            .measure_selection(char_position.position as usize, editor_line);
128
129                        // Move the cursor
130                        if current_selection != new_selection {
131                            *text_editor.selection_mut() = new_selection;
132                        }
133                    }
134                }
135            }
136            EditableEvent::Move {
137                location,
138                editor_line,
139                holder,
140            } => {
141                if dragging.peek().clicked {
142                    let paragraph = holder.0.borrow();
143                    let ParagraphHolderInner {
144                        paragraph,
145                        scale_factor,
146                    } = paragraph.as_ref().unwrap();
147
148                    let dist_position = location.mul(*scale_factor);
149
150                    // Calculate the end of the highlighting
151                    let dist_char = paragraph
152                        .get_glyph_position_at_coordinate(dist_position.to_i32().to_tuple());
153                    let to = dist_char.position as usize;
154
155                    if editor.peek().get_selection().is_none() {
156                        editor.write().selection_mut().set_as_range();
157                    }
158
159                    let current_selection = editor.peek().selection().clone();
160
161                    let new_selection = editor.peek().measure_selection(to, editor_line);
162
163                    // Update the cursor if it has changed
164                    if current_selection != new_selection {
165                        let mut text_editor = editor.write();
166                        *text_editor.selection_mut() = new_selection;
167                    }
168                }
169            }
170            EditableEvent::Release => {
171                dragging.write().clicked = false;
172            }
173            EditableEvent::KeyDown { key, modifiers } => {
174                match key {
175                    // Handle dragging
176                    Key::Named(NamedKey::Shift) => {
177                        dragging.write().shift = true;
178                    }
179                    // Handle editing
180                    _ => {
181                        editor.write_if(|mut editor| {
182                            let event = editor.process_key(
183                                key,
184                                &modifiers,
185                                config.allow_tabs,
186                                config.allow_changes,
187                                config.allow_clipboard,
188                            );
189                            if event.contains(TextEvent::TEXT_CHANGED) {
190                                *dragging.write() = TextDragging::default();
191                            }
192                            !event.is_empty()
193                        });
194                    }
195                }
196            }
197            EditableEvent::KeyUp { key, .. } => {
198                if *key == Key::Named(NamedKey::Shift) {
199                    dragging.write().shift = false;
200                }
201            }
202        };
203    }
204}
205
206#[derive(Debug, PartialEq, Clone, Default)]
207pub struct TextDragging {
208    pub shift: bool,
209    pub clicked: bool,
210}