1use epaint::{text::cursor::*, Galley};
2
3use crate::{os::OperatingSystem, Event, Id, Key, Modifiers};
4
5use super::text_cursor_state::{ccursor_next_word, ccursor_previous_word, slice_char_range};
6
7#[derive(Clone, Copy, Debug, Default, PartialEq)]
9#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
10pub struct CursorRange {
11 pub primary: Cursor,
15
16 pub secondary: Cursor,
19}
20
21impl CursorRange {
22 #[inline]
24 pub fn one(cursor: Cursor) -> Self {
25 Self {
26 primary: cursor,
27 secondary: cursor,
28 }
29 }
30
31 #[inline]
32 pub fn two(min: Cursor, max: Cursor) -> Self {
33 Self {
34 primary: max,
35 secondary: min,
36 }
37 }
38
39 pub fn select_all(galley: &Galley) -> Self {
41 Self::two(galley.begin(), galley.end())
42 }
43
44 pub fn as_ccursor_range(&self) -> CCursorRange {
45 CCursorRange {
46 primary: self.primary.ccursor,
47 secondary: self.secondary.ccursor,
48 }
49 }
50
51 pub fn as_sorted_char_range(&self) -> std::ops::Range<usize> {
53 let [start, end] = self.sorted_cursors();
54 std::ops::Range {
55 start: start.ccursor.index,
56 end: end.ccursor.index,
57 }
58 }
59
60 #[inline]
62 pub fn is_empty(&self) -> bool {
63 self.primary.ccursor == self.secondary.ccursor
64 }
65
66 pub fn contains(&self, other: &Self) -> bool {
68 let [self_min, self_max] = self.sorted_cursors();
69 let [other_min, other_max] = other.sorted_cursors();
70 self_min.ccursor.index <= other_min.ccursor.index
71 && other_max.ccursor.index <= self_max.ccursor.index
72 }
73
74 pub fn single(&self) -> Option<Cursor> {
77 if self.is_empty() {
78 Some(self.primary)
79 } else {
80 None
81 }
82 }
83
84 pub fn is_sorted(&self) -> bool {
85 let p = self.primary.ccursor;
86 let s = self.secondary.ccursor;
87 (p.index, p.prefer_next_row) <= (s.index, s.prefer_next_row)
88 }
89
90 pub fn sorted(self) -> Self {
91 if self.is_sorted() {
92 self
93 } else {
94 Self {
95 primary: self.secondary,
96 secondary: self.primary,
97 }
98 }
99 }
100
101 pub fn sorted_cursors(&self) -> [Cursor; 2] {
103 if self.is_sorted() {
104 [self.primary, self.secondary]
105 } else {
106 [self.secondary, self.primary]
107 }
108 }
109
110 pub fn slice_str<'s>(&self, text: &'s str) -> &'s str {
111 let [min, max] = self.sorted_cursors();
112 slice_char_range(text, min.ccursor.index..max.ccursor.index)
113 }
114
115 pub fn on_key_press(
119 &mut self,
120 os: OperatingSystem,
121 galley: &Galley,
122 modifiers: &Modifiers,
123 key: Key,
124 ) -> bool {
125 match key {
126 Key::A if modifiers.command => {
127 *self = Self::select_all(galley);
128 true
129 }
130
131 Key::ArrowLeft | Key::ArrowRight if modifiers.is_none() && !self.is_empty() => {
132 if key == Key::ArrowLeft {
133 *self = Self::one(self.sorted_cursors()[0]);
134 } else {
135 *self = Self::one(self.sorted_cursors()[1]);
136 }
137 true
138 }
139
140 Key::ArrowLeft
141 | Key::ArrowRight
142 | Key::ArrowUp
143 | Key::ArrowDown
144 | Key::Home
145 | Key::End => {
146 move_single_cursor(os, &mut self.primary, galley, key, modifiers);
147 if !modifiers.shift {
148 self.secondary = self.primary;
149 }
150 true
151 }
152
153 Key::P | Key::N | Key::B | Key::F | Key::A | Key::E
154 if os == OperatingSystem::Mac && modifiers.ctrl && !modifiers.shift =>
155 {
156 move_single_cursor(os, &mut self.primary, galley, key, modifiers);
157 self.secondary = self.primary;
158 true
159 }
160
161 _ => false,
162 }
163 }
164
165 pub fn on_event(
169 &mut self,
170 os: OperatingSystem,
171 event: &Event,
172 galley: &Galley,
173 _widget_id: Id,
174 ) -> bool {
175 match event {
176 Event::Key {
177 modifiers,
178 key,
179 pressed: true,
180 ..
181 } => self.on_key_press(os, galley, modifiers, *key),
182
183 #[cfg(feature = "accesskit")]
184 Event::AccessKitActionRequest(accesskit::ActionRequest {
185 action: accesskit::Action::SetTextSelection,
186 target,
187 data: Some(accesskit::ActionData::SetTextSelection(selection)),
188 }) => {
189 if _widget_id.accesskit_id() == *target {
190 let primary =
191 ccursor_from_accesskit_text_position(_widget_id, galley, &selection.focus);
192 let secondary =
193 ccursor_from_accesskit_text_position(_widget_id, galley, &selection.anchor);
194 if let (Some(primary), Some(secondary)) = (primary, secondary) {
195 *self = Self {
196 primary: galley.from_ccursor(primary),
197 secondary: galley.from_ccursor(secondary),
198 };
199 return true;
200 }
201 }
202 false
203 }
204
205 _ => false,
206 }
207 }
208}
209
210#[derive(Clone, Copy, Debug, Default, PartialEq)]
214#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
215pub struct CCursorRange {
216 pub primary: CCursor,
220
221 pub secondary: CCursor,
224}
225
226impl CCursorRange {
227 #[inline]
229 pub fn one(ccursor: CCursor) -> Self {
230 Self {
231 primary: ccursor,
232 secondary: ccursor,
233 }
234 }
235
236 #[inline]
237 pub fn two(min: impl Into<CCursor>, max: impl Into<CCursor>) -> Self {
238 Self {
239 primary: max.into(),
240 secondary: min.into(),
241 }
242 }
243
244 #[inline]
245 pub fn is_sorted(&self) -> bool {
246 let p = self.primary;
247 let s = self.secondary;
248 (p.index, p.prefer_next_row) <= (s.index, s.prefer_next_row)
249 }
250
251 #[inline]
253 pub fn sorted(&self) -> [CCursor; 2] {
254 if self.is_sorted() {
255 [self.primary, self.secondary]
256 } else {
257 [self.secondary, self.primary]
258 }
259 }
260}
261
262#[derive(Clone, Copy, Debug, Default, PartialEq)]
263#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
264pub struct PCursorRange {
265 pub primary: PCursor,
269
270 pub secondary: PCursor,
273}
274
275#[cfg(feature = "accesskit")]
278fn ccursor_from_accesskit_text_position(
279 id: Id,
280 galley: &Galley,
281 position: &accesskit::TextPosition,
282) -> Option<CCursor> {
283 let mut total_length = 0usize;
284 for (i, row) in galley.rows.iter().enumerate() {
285 let row_id = id.with(i);
286 if row_id.accesskit_id() == position.node {
287 return Some(CCursor {
288 index: total_length + position.character_index,
289 prefer_next_row: !(position.character_index == row.glyphs.len()
290 && !row.ends_with_newline
291 && (i + 1) < galley.rows.len()),
292 });
293 }
294 total_length += row.glyphs.len() + (row.ends_with_newline as usize);
295 }
296 None
297}
298
299fn move_single_cursor(
303 os: OperatingSystem,
304 cursor: &mut Cursor,
305 galley: &Galley,
306 key: Key,
307 modifiers: &Modifiers,
308) {
309 if os == OperatingSystem::Mac && modifiers.ctrl && !modifiers.shift {
310 match key {
311 Key::A => *cursor = galley.cursor_begin_of_row(cursor),
312 Key::E => *cursor = galley.cursor_end_of_row(cursor),
313 Key::P => *cursor = galley.cursor_up_one_row(cursor),
314 Key::N => *cursor = galley.cursor_down_one_row(cursor),
315 Key::B => *cursor = galley.cursor_left_one_character(cursor),
316 Key::F => *cursor = galley.cursor_right_one_character(cursor),
317 _ => (),
318 }
319 return;
320 }
321 match key {
322 Key::ArrowLeft => {
323 if modifiers.alt || modifiers.ctrl {
324 *cursor = galley.from_ccursor(ccursor_previous_word(galley, cursor.ccursor));
326 } else if modifiers.mac_cmd {
327 *cursor = galley.cursor_begin_of_row(cursor);
328 } else {
329 *cursor = galley.cursor_left_one_character(cursor);
330 }
331 }
332 Key::ArrowRight => {
333 if modifiers.alt || modifiers.ctrl {
334 *cursor = galley.from_ccursor(ccursor_next_word(galley, cursor.ccursor));
336 } else if modifiers.mac_cmd {
337 *cursor = galley.cursor_end_of_row(cursor);
338 } else {
339 *cursor = galley.cursor_right_one_character(cursor);
340 }
341 }
342 Key::ArrowUp => {
343 if modifiers.command {
344 *cursor = galley.begin();
346 } else {
347 *cursor = galley.cursor_up_one_row(cursor);
348 }
349 }
350 Key::ArrowDown => {
351 if modifiers.command {
352 *cursor = galley.end();
354 } else {
355 *cursor = galley.cursor_down_one_row(cursor);
356 }
357 }
358
359 Key::Home => {
360 if modifiers.ctrl {
361 *cursor = galley.begin();
363 } else {
364 *cursor = galley.cursor_begin_of_row(cursor);
365 }
366 }
367 Key::End => {
368 if modifiers.ctrl {
369 *cursor = galley.end();
371 } else {
372 *cursor = galley.cursor_end_of_row(cursor);
373 }
374 }
375
376 _ => unreachable!(),
377 }
378}