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