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 new_selection = if config.select_all_on_double_click {
97                            TextSelection::new_range((0, text_editor.len_utf16_cu()))
98                        } else {
99                            let char_position = paragraph.get_glyph_position_at_coordinate(
100                                location.mul(*scale_factor).to_i32().to_tuple(),
101                            );
102                            let press_selection = text_editor
103                                .measure_selection(char_position.position as usize, editor_line);
104
105                            let range = text_editor.find_word_boundaries(press_selection.pos());
106                            TextSelection::new_range(range)
107                        };
108
109                        if current_selection != new_selection {
110                            *text_editor.selection_mut() = new_selection;
111                        }
112                    }
113                    PressEventType::Quadruple => {
114                        let current_selection = text_editor.selection().clone();
115                        let new_selection =
116                            TextSelection::new_range((0, text_editor.len_utf16_cu()));
117
118                        if current_selection != new_selection {
119                            *text_editor.selection_mut() = new_selection;
120                        }
121                    }
122                    PressEventType::Single => {
123                        let current_selection = text_editor.selection().clone();
124
125                        let char_position = paragraph.get_glyph_position_at_coordinate(
126                            location.mul(*scale_factor).to_i32().to_tuple(),
127                        );
128                        let new_selection = text_editor
129                            .measure_selection(char_position.position as usize, editor_line);
130
131                        // Move the cursor
132                        if current_selection != new_selection {
133                            *text_editor.selection_mut() = new_selection;
134                        }
135                    }
136                }
137            }
138            EditableEvent::Move {
139                location,
140                editor_line,
141                holder,
142            } => {
143                if dragging.peek().clicked {
144                    let paragraph = holder.0.borrow();
145                    let ParagraphHolderInner {
146                        paragraph,
147                        scale_factor,
148                    } = paragraph.as_ref().unwrap();
149
150                    let dist_position = location.mul(*scale_factor);
151
152                    // Calculate the end of the highlighting
153                    let dist_char = paragraph
154                        .get_glyph_position_at_coordinate(dist_position.to_i32().to_tuple());
155                    let to = dist_char.position as usize;
156
157                    if editor.peek().get_selection().is_none() {
158                        editor.write().selection_mut().set_as_range();
159                    }
160
161                    let current_selection = editor.peek().selection().clone();
162
163                    let new_selection = editor.peek().measure_selection(to, editor_line);
164
165                    // Update the cursor if it has changed
166                    if current_selection != new_selection {
167                        let mut text_editor = editor.write();
168                        *text_editor.selection_mut() = new_selection;
169                    }
170                }
171            }
172            EditableEvent::Release => {
173                dragging.write().clicked = false;
174            }
175            EditableEvent::KeyDown { key, modifiers } => {
176                match key {
177                    // Handle dragging
178                    Key::Named(NamedKey::Shift) => {
179                        dragging.write().shift = true;
180                    }
181                    // Handle editing
182                    _ => {
183                        editor.write_if(|mut editor| {
184                            let event = editor.process_key(
185                                key,
186                                &modifiers,
187                                config.allow_tabs,
188                                config.allow_changes,
189                                config.allow_read_clipboard,
190                                config.allow_write_clipboard,
191                            );
192                            if event.contains(TextEvent::TEXT_CHANGED) {
193                                *dragging.write() = TextDragging::default();
194                            }
195                            !event.is_empty()
196                        });
197                    }
198                }
199            }
200            EditableEvent::KeyUp { key, .. } => {
201                if *key == Key::Named(NamedKey::Shift) {
202                    dragging.write().shift = false;
203                }
204            }
205        };
206    }
207}
208
209#[derive(Debug, PartialEq, Clone, Default)]
210pub struct TextDragging {
211    pub shift: bool,
212    pub clicked: bool,
213}