1use cranpose_ui::FocusDirection;
2
3use super::*;
4
5impl<R> SurfaceMut<'_, R>
6where
7 R: Renderer,
8 R::Error: Debug,
9{
10 fn pointer_event(
11 &self,
12 kind: PointerEventKind,
13 position: Point,
14 global_position: Point,
15 event_time: PointerEventTime,
16 ) -> PointerEvent {
17 let screen_position = self.surface().screen_origin.map(|origin| Point {
18 x: origin.x + global_position.x,
19 y: origin.y + global_position.y,
20 });
21 let mut event = PointerEvent::new(kind, position, global_position)
22 .with_time_ms(event_time.platform_time_ms)
23 .with_animation_time_nanos(event_time.animation_time_nanos)
24 .with_screen_position(screen_position);
25 event.modifiers = self.shell.app.modifiers;
26 event
27 }
28
29 fn resolve_gesture_targets(
30 &self,
31 pointer: PointerId,
32 ) -> Vec<<<R as Renderer>::Scene as RenderScene>::HitTarget> {
33 self.resolve_hit_path(pointer)
34 }
35
36 fn resolve_hit_path(
37 &self,
38 pointer: PointerId,
39 ) -> Vec<<<R as Renderer>::Scene as RenderScene>::HitTarget> {
40 let Some(node_ids) = self.surface().hit_path_tracker.dispatch_order(pointer) else {
41 return Vec::new();
42 };
43
44 let scene = self.surface().renderer.scene();
45 let targets: Vec<_> = node_ids
46 .iter()
47 .filter_map(|&id| scene.find_target(id))
48 .collect();
49 log::trace!(
50 target: "cranpose::input",
51 "resolve_hit_path pointer={pointer:?} cached={node_ids:?} resolved_count={}",
52 targets.len()
53 );
54 targets
55 }
56
57 fn dispatch_targets<I>(&mut self, targets: I, event: PointerEvent, stop_on_consume: bool)
58 where
59 I: IntoIterator<Item = <<R as Renderer>::Scene as RenderScene>::HitTarget>,
60 {
61 let mut applier = self.shell.app.composition.applier_mut();
62 for target in targets {
63 let node_id = target.node_id();
64 target.dispatch_with_applier(&mut applier, event.clone());
65 log::trace!(
66 target: "cranpose::input",
67 "dispatch {:?} node={} consumed={} stop_on_consume={}",
68 event.kind,
69 node_id,
70 event.is_consumed(),
71 stop_on_consume,
72 );
73 if stop_on_consume && event.is_consumed() {
74 break;
75 }
76 }
77 event.finish_post_dispatch();
78 }
79
80 fn dispatch_to_hits(
81 &mut self,
82 hits: &[<<R as Renderer>::Scene as RenderScene>::HitTarget],
83 event: PointerEvent,
84 ) -> bool {
85 let capture_paths = hits
86 .iter()
87 .map(|hit| hit.capture_path())
88 .collect::<Vec<_>>();
89 let targets = crate::hit_path_tracker::dispatch_order_for_paths(&capture_paths)
90 .into_iter()
91 .filter_map(|node_id| self.surface().renderer.scene().find_target(node_id))
92 .collect::<Vec<_>>();
93
94 self.dispatch_targets(targets, event.clone(), true);
95
96 event.is_consumed()
97 }
98
99 pub fn set_pointer_source(&mut self, source: PointerSource) {
105 self.surface_mut().pointer_source = source;
106 }
107
108 pub fn pointer_source(&self) -> PointerSource {
110 self.surface().pointer_source
111 }
112
113 pub fn set_cursor(&mut self, x: f32, y: f32) -> bool {
114 self.set_cursor_at_time(x, y, None)
115 }
116
117 pub fn set_cursor_at_time(&mut self, x: f32, y: f32, time_ms: Option<i64>) -> bool {
124 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
125 self.set_cursor_at_event_time(x, y, event_time)
126 }
127
128 pub fn set_cursor_at_event_time(
130 &mut self,
131 x: f32,
132 y: f32,
133 event_time: PointerEventTime,
134 ) -> bool {
135 let _event_handler = enter_event_handler_scope();
136 let app_context = Rc::clone(&self.shell.app.app_context);
137 let result = app_context.enter(|| {
138 run_in_mutable_snapshot(|| self.set_cursor_inner(x, y, event_time)).unwrap_or(false)
139 });
140 self.route_drag_and_drop();
141 if result {
142 self.mark_dirty();
143 }
144 log::trace!(
145 target: "cranpose::input",
146 "set_cursor ({x:.2},{y:.2}) time_ms={:?} animation_time_nanos={} -> {result}",
147 event_time.platform_time_ms,
148 event_time.animation_time_nanos,
149 );
150 result
151 }
152
153 fn set_cursor_inner(&mut self, x: f32, y: f32, event_time: PointerEventTime) -> bool {
154 self.surface_mut().cursor = (x, y);
155
156 if self.surface().buttons_pressed != PointerButtons::NONE {
157 if self.surface().hit_path_tracker.has_path(PointerId::PRIMARY) {
158 let targets = self.resolve_gesture_targets(PointerId::PRIMARY);
159 if !targets.is_empty() {
160 let event = self
161 .pointer_event(
162 PointerEventKind::Move,
163 Point { x, y },
164 Point { x, y },
165 event_time,
166 )
167 .with_buttons(self.surface().buttons_pressed)
168 .with_source(self.surface().pointer_source);
169 self.dispatch_targets(targets, event, false);
170 return true;
171 }
172
173 return false;
174 }
175
176 return false;
177 }
178
179 let hits = self.surface().renderer.scene().hit_test(x, y);
180 let new_ids: Vec<NodeId> = hits.iter().map(|h| h.node_id()).collect();
181
182 let pos = Point { x, y };
183 let previously_hovered = self.surface().hovered_nodes.clone();
184 for old_id in previously_hovered {
185 if !new_ids.contains(&old_id)
186 && let Some(target) = self.surface().renderer.scene().find_target(old_id)
187 {
188 let exit_event = self
189 .pointer_event(PointerEventKind::Exit, pos, pos, event_time)
190 .with_buttons(self.surface().buttons_pressed)
191 .with_source(self.surface().pointer_source);
192 self.dispatch_targets(std::iter::once(target), exit_event, false);
193 }
194 }
195
196 for hit in &hits {
197 if !self.surface().hovered_nodes.contains(&hit.node_id()) {
198 let enter_event = self
199 .pointer_event(PointerEventKind::Enter, pos, pos, event_time)
200 .with_buttons(self.surface().buttons_pressed)
201 .with_source(self.surface().pointer_source);
202 self.dispatch_targets(std::iter::once(hit.clone()), enter_event, false);
203 }
204 }
205
206 self.surface_mut().hovered_nodes = new_ids;
207 self.apply_hovered_pointer_icon(&hits);
208
209 if !hits.is_empty() {
210 let event = self
211 .pointer_event(PointerEventKind::Move, pos, pos, event_time)
212 .with_buttons(self.surface().buttons_pressed)
213 .with_source(self.surface().pointer_source);
214 self.dispatch_targets(hits, event, true);
215 true
216 } else {
217 false
218 }
219 }
220
221 pub fn pointer_pressed(&mut self) -> bool {
222 self.pointer_pressed_at_time(None)
223 }
224
225 pub fn pointer_pressed_at_time(&mut self, time_ms: Option<i64>) -> bool {
228 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
229 self.pointer_pressed_at_event_time(event_time)
230 }
231
232 pub fn pointer_pressed_at_event_time(&mut self, event_time: PointerEventTime) -> bool {
234 let (cursor_x, cursor_y) = self.surface().cursor;
235 if self.dev_overlay_press(cursor_x, cursor_y) {
236 return true;
237 }
238 let _event_handler = enter_event_handler_scope();
239 let app_context = Rc::clone(&self.shell.app.app_context);
240 let result = app_context.enter(|| {
241 run_in_mutable_snapshot(|| self.pointer_pressed_inner(event_time)).unwrap_or(false)
242 });
243 if result {
244 self.mark_dirty();
245 }
246 log::trace!(
247 target: "cranpose::input",
248 "pointer_pressed time_ms={:?} animation_time_nanos={} -> {result}",
249 event_time.platform_time_ms,
250 event_time.animation_time_nanos,
251 );
252 result
253 }
254
255 fn pointer_pressed_inner(&mut self, event_time: PointerEventTime) -> bool {
256 self.activate();
257 self.note_focus_moved_by_keyboard(false);
258 self.surface_mut()
259 .buttons_pressed
260 .insert(PointerButton::Primary);
261
262 let (cursor_x, cursor_y) = self.surface().cursor;
263 let mut hits = self.surface().renderer.scene().hit_test(cursor_x, cursor_y);
264 if self.surface().pointer_source.is_touch_like()
265 && let Some(near) = self
266 .surface()
267 .renderer
268 .scene()
269 .hit_test_near(cursor_x, cursor_y)
270 && hits.iter().all(|hit| {
271 hit.node_id() != near.node_id() && near.capture_path().contains(&hit.node_id())
272 })
273 {
274 hits.insert(0, near);
275 }
276 if hits.is_empty() {
277 self.surface_mut()
278 .hit_path_tracker
279 .remove_path(PointerId::PRIMARY);
280 false
281 } else {
282 let event = self
283 .pointer_event(
284 PointerEventKind::Down,
285 Point {
286 x: self.surface().cursor.0,
287 y: self.surface().cursor.1,
288 },
289 Point {
290 x: self.surface().cursor.0,
291 y: self.surface().cursor.1,
292 },
293 event_time,
294 )
295 .with_buttons(self.surface().buttons_pressed)
296 .with_source(self.surface().pointer_source);
297
298 let mut delivered_capture_paths = Vec::new();
299 let (app, surface) = self.parts();
300 let mut applier = app.composition.applier_mut();
301 for hit in hits {
302 let node_id = hit.node_id();
303 delivered_capture_paths.push(hit.capture_path());
304 hit.dispatch_with_applier(&mut applier, event.clone());
305 log::trace!(
306 target: "cranpose::input",
307 "dispatch {:?} node={} consumed={} stop_on_consume=true",
308 event.kind,
309 node_id,
310 event.is_consumed(),
311 );
312 if event.is_consumed() {
313 break;
314 }
315 }
316
317 surface
318 .hit_path_tracker
319 .add_hit_path(PointerId::PRIMARY, delivered_capture_paths);
320 log::trace!(
321 target: "cranpose::input",
322 "pointer_pressed_inner cached_hit_path={:?}",
323 surface.hit_path_tracker.get_path(PointerId::PRIMARY),
324 );
325
326 true
327 }
328 }
329
330 pub fn pointer_released(&mut self) -> bool {
331 self.pointer_released_at_time(None)
332 }
333
334 pub fn pointer_released_at_position(&mut self, x: f32, y: f32) -> bool {
347 self.pointer_released_at_position_time(x, y, None)
348 }
349
350 pub fn pointer_released_at_position_time(
354 &mut self,
355 x: f32,
356 y: f32,
357 time_ms: Option<i64>,
358 ) -> bool {
359 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
360 self.pointer_released_at_position_event_time(x, y, event_time)
361 }
362
363 pub fn pointer_released_at_position_event_time(
365 &mut self,
366 x: f32,
367 y: f32,
368 event_time: PointerEventTime,
369 ) -> bool {
370 let _event_handler = enter_event_handler_scope();
371 let app_context = Rc::clone(&self.shell.app.app_context);
372 let result = app_context.enter(|| {
373 run_in_mutable_snapshot(|| {
374 self.surface_mut().cursor = (x, y);
375 self.pointer_released_inner(event_time)
376 })
377 .unwrap_or(false)
378 });
379 self.route_drag_and_drop();
380 if result {
381 self.mark_dirty();
382 }
383 log::trace!(
384 target: "cranpose::input",
385 "pointer_released_at_position ({x:.2},{y:.2}) time_ms={:?} animation_time_nanos={} -> {result}",
386 event_time.platform_time_ms,
387 event_time.animation_time_nanos,
388 );
389 result
390 }
391
392 pub fn pointer_released_at_time(&mut self, time_ms: Option<i64>) -> bool {
395 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
396 self.pointer_released_at_event_time(event_time)
397 }
398
399 pub fn pointer_released_at_event_time(&mut self, event_time: PointerEventTime) -> bool {
401 let _event_handler = enter_event_handler_scope();
402 let app_context = Rc::clone(&self.shell.app.app_context);
403 let result = app_context.enter(|| {
404 run_in_mutable_snapshot(|| self.pointer_released_inner(event_time)).unwrap_or(false)
405 });
406 self.route_drag_and_drop();
407 if result {
408 self.mark_dirty();
409 }
410 log::trace!(
411 target: "cranpose::input",
412 "pointer_released time_ms={:?} animation_time_nanos={} -> {result}",
413 event_time.platform_time_ms,
414 event_time.animation_time_nanos,
415 );
416 result
417 }
418
419 fn pointer_released_inner(&mut self, event_time: PointerEventTime) -> bool {
420 self.surface_mut()
421 .buttons_pressed
422 .remove(PointerButton::Primary);
423 let corrected_buttons = self.surface().buttons_pressed;
424 let targets = self.resolve_gesture_targets(PointerId::PRIMARY);
425
426 self.surface_mut()
427 .hit_path_tracker
428 .remove_path(PointerId::PRIMARY);
429
430 if !targets.is_empty() {
431 let event = self
432 .pointer_event(
433 PointerEventKind::Up,
434 Point {
435 x: self.surface().cursor.0,
436 y: self.surface().cursor.1,
437 },
438 Point {
439 x: self.surface().cursor.0,
440 y: self.surface().cursor.1,
441 },
442 event_time,
443 )
444 .with_buttons(corrected_buttons)
445 .with_source(self.surface().pointer_source);
446
447 self.dispatch_targets(targets, event, false);
448 true
449 } else {
450 false
451 }
452 }
453
454 pub fn secondary_pointer_pressed(
463 &mut self,
464 pointer_id: u64,
465 x: f32,
466 y: f32,
467 time_ms: Option<i64>,
468 ) -> bool {
469 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
470 self.dispatch_secondary_pointer(PointerEventKind::Down, pointer_id, x, y, event_time)
471 }
472
473 pub fn secondary_pointer_moved(
475 &mut self,
476 pointer_id: u64,
477 x: f32,
478 y: f32,
479 time_ms: Option<i64>,
480 ) -> bool {
481 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
482 self.dispatch_secondary_pointer(PointerEventKind::Move, pointer_id, x, y, event_time)
483 }
484
485 pub fn secondary_pointer_released(
487 &mut self,
488 pointer_id: u64,
489 x: f32,
490 y: f32,
491 time_ms: Option<i64>,
492 ) -> bool {
493 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
494 self.dispatch_secondary_pointer(PointerEventKind::Up, pointer_id, x, y, event_time)
495 }
496
497 fn dispatch_secondary_pointer(
498 &mut self,
499 kind: PointerEventKind,
500 pointer_id: u64,
501 x: f32,
502 y: f32,
503 event_time: PointerEventTime,
504 ) -> bool {
505 if pointer_id == 0 {
506 log::warn!(
507 target: "cranpose::input",
508 "secondary pointer dispatch called with the primary pointer id"
509 );
510 return false;
511 }
512
513 let _event_handler = enter_event_handler_scope();
514 let app_context = Rc::clone(&self.shell.app.app_context);
515 let result = app_context.enter(|| {
516 run_in_mutable_snapshot(|| {
517 if !self.surface().hit_path_tracker.has_path(PointerId::PRIMARY) {
518 return false;
519 }
520 let targets = self.resolve_gesture_targets(PointerId::PRIMARY);
521 if targets.is_empty() {
522 return false;
523 }
524 let pos = Point { x, y };
525 let event = self
526 .pointer_event(kind, pos, pos, event_time)
527 .with_buttons(self.surface().buttons_pressed)
528 .with_id(pointer_id)
529 .with_source(self.surface().pointer_source);
530 self.dispatch_targets(targets, event, false);
531 true
532 })
533 .unwrap_or(false)
534 });
535 if result {
536 self.mark_dirty();
537 }
538 log::trace!(
539 target: "cranpose::input",
540 "secondary_pointer {kind:?} id={pointer_id} ({x:.2},{y:.2}) time_ms={:?} animation_time_nanos={} -> {result}",
541 event_time.platform_time_ms,
542 event_time.animation_time_nanos,
543 );
544 result
545 }
546
547 pub fn pointer_zoomed(&mut self, zoom_factor: f32) -> bool {
553 let event_time = self.shell.app.realtime_pointer_event_time(None);
554 let _event_handler = enter_event_handler_scope();
555 let app_context = Rc::clone(&self.shell.app.app_context);
556 let result = app_context.enter(|| {
557 run_in_mutable_snapshot(|| self.pointer_zoomed_inner(zoom_factor, event_time))
558 .unwrap_or(false)
559 });
560 if result {
561 self.mark_dirty();
562 }
563 log::trace!(
564 target: "cranpose::input",
565 "pointer_zoomed factor={zoom_factor:.4} -> {result}"
566 );
567 result
568 }
569
570 fn pointer_zoomed_inner(&mut self, zoom_factor: f32, event_time: PointerEventTime) -> bool {
571 if !zoom_factor.is_finite() || zoom_factor <= 0.0 || zoom_factor == 1.0 {
572 return false;
573 }
574
575 let hits = self
576 .surface()
577 .renderer
578 .scene()
579 .hit_test(self.surface().cursor.0, self.surface().cursor.1);
580 if hits.is_empty() {
581 return false;
582 }
583
584 let pos = Point {
585 x: self.surface().cursor.0,
586 y: self.surface().cursor.1,
587 };
588 let event = self
589 .pointer_event(PointerEventKind::Zoom, pos, pos, event_time)
590 .with_buttons(self.surface().buttons_pressed)
591 .with_zoom_delta(zoom_factor)
592 .with_source(self.surface().pointer_source);
593
594 self.dispatch_to_hits(&hits, event)
595 }
596
597 pub fn wheel_scrolled(&mut self, wheel: crate::WheelScroll) -> bool {
622 if wheel.is_zoom() {
623 let zoom_factor = wheel.zoom_factor();
624 log::trace!(
625 target: "cranpose::input",
626 "wheel zoom factor={zoom_factor:.4}"
627 );
628 return self.pointer_zoomed(zoom_factor);
629 }
630
631 let rotary =
632 RotaryScrollEvent::from_wheel_pixels(wheel.delta.y, wheel.delta.x, wheel.uptime_millis);
633 if self.rotary_scrolled(rotary) {
634 return true;
635 }
636
637 let delta = wheel.scroll_delta();
638 log::trace!(
639 target: "cranpose::input",
640 "wheel delta ({:.2},{:.2}) alt={}",
641 delta.x,
642 delta.y,
643 wheel.modifiers.alt
644 );
645 self.pointer_scrolled(delta.x, delta.y)
646 }
647
648 pub fn pointer_scrolled(&mut self, delta_x: f32, delta_y: f32) -> bool {
656 let event_time = self.shell.app.realtime_pointer_event_time(None);
657 let _event_handler = enter_event_handler_scope();
658 let app_context = Rc::clone(&self.shell.app.app_context);
659 let result = app_context.enter(|| {
660 run_in_mutable_snapshot(|| self.pointer_scrolled_inner(delta_x, delta_y, event_time))
661 .unwrap_or(false)
662 });
663 if result {
664 self.mark_dirty();
665 }
666 log::trace!(
667 target: "cranpose::input",
668 "pointer_scrolled ({delta_x:.2},{delta_y:.2}) -> {result}"
669 );
670 result
671 }
672
673 fn pointer_scrolled_inner(
674 &mut self,
675 delta_x: f32,
676 delta_y: f32,
677 event_time: PointerEventTime,
678 ) -> bool {
679 if delta_x.abs() <= f32::EPSILON && delta_y.abs() <= f32::EPSILON {
680 return false;
681 }
682
683 let hits = self
684 .surface()
685 .renderer
686 .scene()
687 .hit_test(self.surface().cursor.0, self.surface().cursor.1);
688 if hits.is_empty() {
689 return false;
690 }
691
692 let event = self
693 .pointer_event(
694 PointerEventKind::Scroll,
695 Point {
696 x: self.surface().cursor.0,
697 y: self.surface().cursor.1,
698 },
699 Point {
700 x: self.surface().cursor.0,
701 y: self.surface().cursor.1,
702 },
703 event_time,
704 )
705 .with_buttons(self.surface().buttons_pressed)
706 .with_scroll_delta(Point {
707 x: delta_x,
708 y: delta_y,
709 })
710 .with_source(self.surface().pointer_source);
711
712 self.dispatch_to_hits(&hits, event)
713 }
714
715 pub fn set_on_rotary_scroll<F>(&mut self, handler: F)
726 where
727 F: Fn(RotaryScrollEvent) -> bool + 'static,
728 {
729 self.surface_mut().on_rotary_scroll = Some(Rc::new(handler));
730 }
731
732 pub fn clear_on_rotary_scroll(&mut self) {
734 self.surface_mut().on_rotary_scroll = None;
735 }
736
737 pub fn rotary_scrolled_by_detents(&mut self, detents: f32, uptime_millis: u64) -> bool {
743 let factor = self.shell.app.rotary_scroll_factor;
744 self.rotary_scrolled(RotaryScrollEvent::from_detents(
745 detents,
746 factor,
747 factor,
748 uptime_millis,
749 ))
750 }
751
752 pub fn rotary_scrolled(&mut self, event: RotaryScrollEvent) -> bool {
773 let _event_handler = enter_event_handler_scope();
774 let app_context = Rc::clone(&self.shell.app.app_context);
775 let result = app_context.enter(|| {
776 run_in_mutable_snapshot(|| self.rotary_scrolled_inner(event)).unwrap_or(false)
777 });
778 if result {
779 self.mark_dirty();
780 }
781 log::trace!(
782 target: "cranpose::input",
783 "rotary_scrolled v={:.2} h={:.2} uptime={} -> {result}",
784 event.vertical_scroll_pixels,
785 event.horizontal_scroll_pixels,
786 event.uptime_millis,
787 );
788 result
789 }
790
791 fn rotary_scrolled_inner(&mut self, rotary: RotaryScrollEvent) -> bool {
792 if rotary.is_empty() {
793 return false;
794 }
795
796 let bubble_order = self.rotary_dispatch_order();
797 let position = Point {
798 x: self.surface().cursor.0,
799 y: self.surface().cursor.1,
800 };
801
802 if !bubble_order.is_empty() {
803 let capture_targets = bubble_order
804 .iter()
805 .rev()
806 .filter_map(|&node_id| self.surface().renderer.scene().find_target(node_id))
807 .collect::<Vec<_>>();
808 let mut capture_event =
809 PointerEvent::rotary(PointerEventKind::RotaryScrollPre, rotary, position);
810 capture_event.modifiers = self.shell.app.modifiers;
811 self.dispatch_targets(capture_targets, capture_event.clone(), true);
812 if capture_event.is_consumed() {
813 return true;
814 }
815
816 let bubble_targets = bubble_order
817 .iter()
818 .filter_map(|&node_id| self.surface().renderer.scene().find_target(node_id))
819 .collect::<Vec<_>>();
820 let mut bubble_event =
821 PointerEvent::rotary(PointerEventKind::RotaryScroll, rotary, position);
822 bubble_event.modifiers = self.shell.app.modifiers;
823 self.dispatch_targets(bubble_targets, bubble_event.clone(), true);
824 if bubble_event.is_consumed() {
825 return true;
826 }
827 }
828
829 if let Some(handler) = self.surface().on_rotary_scroll.clone() {
830 return handler(rotary);
831 }
832
833 false
834 }
835
836 fn rotary_dispatch_order(&self) -> Vec<NodeId> {
837 if let Some(focused) = cranpose_ui::active_focus_target()
838 && let Some(target) = self.surface().renderer.scene().find_target(focused)
839 {
840 let path = target.capture_path();
841 if !path.is_empty() {
842 return crate::hit_path_tracker::dispatch_order_for_paths(&[path]);
843 }
844 }
845
846 let hits = self
847 .surface()
848 .renderer
849 .scene()
850 .hit_test(self.surface().cursor.0, self.surface().cursor.1);
851 if hits.is_empty() {
852 return Vec::new();
853 }
854 let capture_paths = hits
855 .iter()
856 .map(|hit| hit.capture_path())
857 .collect::<Vec<_>>();
858 crate::hit_path_tracker::dispatch_order_for_paths(&capture_paths)
859 }
860
861 pub fn cancel_gesture(&mut self) {
867 let event_time = self.shell.app.realtime_pointer_event_time(None);
868 let _event_handler = enter_event_handler_scope();
869 let app_context = Rc::clone(&self.shell.app.app_context);
870 let _ = app_context.enter(|| {
871 run_in_mutable_snapshot(|| {
872 self.cancel_gesture_inner(event_time);
873 })
874 });
875 self.route_drag_and_drop();
876 }
877
878 fn route_drag_and_drop(&mut self) {
879 let app_context = Rc::clone(&self.shell.app.app_context);
880 let source = self.index;
881 let shell = &mut *self.shell;
882 let routed = app_context.enter(|| {
883 run_in_mutable_snapshot(|| {
884 app_context
885 .drag_and_drop()
886 .route(|point| shell.drag_and_drop_target_at(point, source))
887 })
888 .unwrap_or(false)
889 });
890 if routed {
891 shell.mark_all_dirty();
892 }
893 }
894
895 pub fn cancel_gesture_unless_pressed(&mut self) {
904 if self.surface().buttons_pressed != PointerButtons::NONE {
905 return;
906 }
907 self.cancel_gesture();
908 }
909
910 fn cancel_gesture_inner(&mut self, event_time: PointerEventTime) {
911 let targets = self.resolve_gesture_targets(PointerId::PRIMARY);
912
913 self.surface_mut().hit_path_tracker.clear();
914 self.surface_mut().buttons_pressed = PointerButtons::NONE;
915
916 if !targets.is_empty() {
917 let event = self
918 .pointer_event(
919 PointerEventKind::Cancel,
920 Point {
921 x: self.surface().cursor.0,
922 y: self.surface().cursor.1,
923 },
924 Point {
925 x: self.surface().cursor.0,
926 y: self.surface().cursor.1,
927 },
928 event_time,
929 )
930 .with_source(self.surface().pointer_source);
931
932 self.dispatch_targets(targets, event, false);
933 }
934
935 let pos = Point {
936 x: self.surface().cursor.0,
937 y: self.surface().cursor.1,
938 };
939 let hovered_nodes = self.surface().hovered_nodes.clone();
940 for node_id in hovered_nodes {
941 if let Some(target) = self.surface().renderer.scene().find_target(node_id) {
942 let exit_event = self
943 .pointer_event(PointerEventKind::Exit, pos, pos, event_time)
944 .with_source(self.surface().pointer_source);
945 self.dispatch_targets(std::iter::once(target), exit_event, false);
946 }
947 }
948 self.surface_mut().hovered_nodes.clear();
949 self.surface().pointer_icon.set(PointerIcon::DEFAULT);
950 }
951
952 fn apply_hovered_pointer_icon(
953 &self,
954 hits: &[<<R as Renderer>::Scene as RenderScene>::HitTarget],
955 ) {
956 let icon = hits
957 .iter()
958 .find_map(HitTestTarget::pointer_icon)
959 .unwrap_or(PointerIcon::DEFAULT);
960 self.surface().pointer_icon.set(icon);
961 }
962
963 fn on_focus_key(&mut self, event: &KeyEvent) -> bool {
964 if !plain_key_down(event) || event.key_code != KeyCode::Tab {
965 return false;
966 }
967 let direction = if event.modifiers.shift {
968 FocusDirection::Previous
969 } else {
970 FocusDirection::Next
971 };
972 self.move_focus_in_context(direction)
973 }
974
975 fn on_activation_key(&mut self, event: &KeyEvent) -> bool {
976 if !plain_key_down(event)
977 || !matches!(event.key_code, KeyCode::Enter | KeyCode::Space)
978 || cranpose_ui::text_field_focus::has_focused_field()
979 {
980 return false;
981 }
982 let Some(focused) = cranpose_ui::active_focus_target() else {
983 return false;
984 };
985 let center = self.with_layout_tree(|layout_tree| {
986 layout_tree
987 .map(cranpose_ui::collect_focus_order)
988 .unwrap_or_default()
989 .iter()
990 .find(|entry| entry.node_id == focused)
991 .map(cranpose_ui::FocusEntry::center)
992 });
993 let Some((x, y)) = center else {
994 return false;
995 };
996 self.set_cursor(x, y);
997 let pressed = self.pointer_pressed();
998 let released = self.pointer_released_at_position(x, y);
999 self.note_focus_moved_by_keyboard(true);
1000 pressed || released
1001 }
1002
1003 fn on_arrow_key(&mut self, event: &KeyEvent) -> bool {
1004 if !plain_key_down(event) || cranpose_ui::text_field_focus::has_focused_field() {
1005 return false;
1006 }
1007 let direction = match event.key_code {
1008 KeyCode::ArrowLeft => FocusDirection::Left,
1009 KeyCode::ArrowRight => FocusDirection::Right,
1010 KeyCode::ArrowUp => FocusDirection::Up,
1011 KeyCode::ArrowDown => FocusDirection::Down,
1012 _ => return false,
1013 };
1014 let Some(focused) = cranpose_ui::active_focus_target() else {
1015 return false;
1016 };
1017 let order = self.with_layout_tree(|layout_tree| {
1018 let layout_tree = layout_tree?;
1019 let group = cranpose_ui::selectable_group_of(layout_tree, focused)?;
1020 Some(cranpose_ui::collect_focus_order_under(layout_tree, group))
1021 });
1022 order.is_some_and(|order| self.move_focus_in_order(order, direction))
1023 }
1024
1025 fn note_focus_moved_by_keyboard(&mut self, keyboard: bool) {
1026 if cranpose_ui::set_keyboard_focus_visible(keyboard) {
1027 cranpose_ui::request_render_invalidation();
1028 self.mark_dirty();
1029 }
1030 }
1031
1032 fn on_escape_key(&mut self, event: &KeyEvent) -> bool {
1033 if event.event_type != KeyEventType::KeyDown || event.key_code != KeyCode::Escape {
1034 return false;
1035 }
1036 self.dismiss_top_modal_in_context()
1037 }
1038
1039 pub fn dismiss_top_modal(&mut self) -> bool {
1042 let _event_handler = enter_event_handler_scope();
1043 let app_context = Rc::clone(&self.shell.app.app_context);
1044 app_context.enter(|| self.dismiss_top_modal_in_context())
1045 }
1046
1047 fn dismiss_top_modal_in_context(&mut self) -> bool {
1048 let closed = run_in_mutable_snapshot(|| {
1049 if cranpose_ui::modal_depth() > 0 {
1050 cranpose_ui::dispatch_modal_back()
1051 } else {
1052 cranpose_ui::dismiss_top_popup()
1053 }
1054 })
1055 .unwrap_or(false);
1056 if closed {
1057 self.mark_dirty();
1058 }
1059 closed
1060 }
1061
1062 pub fn move_focus_in_context(&mut self, direction: FocusDirection) -> bool {
1065 let order = self.with_layout_tree(|layout_tree| {
1066 layout_tree
1067 .map(cranpose_ui::collect_focus_order)
1068 .unwrap_or_default()
1069 });
1070 self.move_focus_in_order(order, direction)
1071 }
1072
1073 fn move_focus_in_order(
1074 &mut self,
1075 order: Vec<cranpose_ui::FocusEntry>,
1076 direction: FocusDirection,
1077 ) -> bool {
1078 cranpose_ui::set_focus_order(order);
1079 let moved = run_in_mutable_snapshot(|| cranpose_ui::FocusManager.move_focus(direction))
1080 .unwrap_or(false);
1081 if moved {
1082 self.mark_dirty();
1083 self.note_focus_moved_by_keyboard(true);
1084 }
1085 moved
1086 }
1087
1088 pub fn on_key_event(&mut self, event: &KeyEvent) -> bool {
1089 let _event_handler = enter_event_handler_scope();
1090 let app_context = Rc::clone(&self.shell.app.app_context);
1091 app_context.enter(|| self.on_key_event_inner(event))
1092 }
1093
1094 fn on_key_event_inner(&mut self, event: &KeyEvent) -> bool {
1095 use KeyEventType::KeyDown;
1096
1097 if event.event_type == KeyDown && event.modifiers.command_or_ctrl() {
1098 #[cfg(all(
1099 feature = "clipboard-native",
1100 not(target_arch = "wasm32"),
1101 not(target_os = "android"),
1102 not(target_os = "ios")
1103 ))]
1104 {
1105 match event.key_code {
1106 KeyCode::C => {
1107 if let Some(text) = self.on_copy_inner() {
1108 cranpose_ui::clipboard_session::clipboard_write_text(&text);
1109 return true;
1110 }
1111 }
1112 KeyCode::X => {
1113 if let Some(text) = self.on_cut_inner() {
1114 cranpose_ui::clipboard_session::clipboard_write_text(&text);
1115 self.mark_dirty();
1116 self.shell.app.request_layout_pass();
1117 return true;
1118 }
1119 }
1120 KeyCode::V => {
1121 if let Some(text) = cranpose_ui::clipboard_session::clipboard_read_text()
1122 && self.on_paste_inner(&text)
1123 {
1124 return true;
1125 }
1126 }
1127 _ => {}
1128 }
1129 }
1130 }
1131
1132 if self.on_focus_key(event) {
1133 return true;
1134 }
1135
1136 if self.on_escape_key(event) {
1137 return true;
1138 }
1139
1140 if self.on_activation_key(event) || self.on_arrow_key(event) {
1141 return true;
1142 }
1143
1144 if !cranpose_ui::text_field_focus::has_focused_field() {
1145 return false;
1146 }
1147
1148 let handled =
1149 run_in_mutable_snapshot(|| cranpose_ui::text_field_focus::dispatch_key_event(event))
1150 .unwrap_or(false);
1151
1152 if handled {
1153 self.mark_dirty();
1154 self.shell.app.request_layout_pass();
1155 }
1156
1157 handled
1158 }
1159
1160 pub fn on_paste(&mut self, text: &str) -> bool {
1164 let _event_handler = enter_event_handler_scope();
1165 let app_context = Rc::clone(&self.shell.app.app_context);
1166 app_context.enter(|| self.on_paste_inner(text))
1167 }
1168
1169 fn on_paste_inner(&mut self, text: &str) -> bool {
1170 let handled =
1171 run_in_mutable_snapshot(|| cranpose_ui::text_field_focus::dispatch_paste(text))
1172 .unwrap_or(false);
1173
1174 if handled {
1175 self.mark_dirty();
1176 self.shell.app.request_layout_pass();
1177 }
1178
1179 handled
1180 }
1181
1182 pub fn on_copy(&mut self) -> Option<String> {
1186 let app_context = Rc::clone(&self.shell.app.app_context);
1187 app_context.enter(|| self.on_copy_inner())
1188 }
1189
1190 fn on_copy_inner(&mut self) -> Option<String> {
1191 cranpose_ui::text_field_focus::dispatch_copy()
1192 }
1193
1194 pub fn on_cut(&mut self) -> Option<String> {
1198 let _event_handler = enter_event_handler_scope();
1199 let app_context = Rc::clone(&self.shell.app.app_context);
1200 app_context.enter(|| self.on_cut_inner())
1201 }
1202
1203 fn on_cut_inner(&mut self) -> Option<String> {
1204 let text =
1205 run_in_mutable_snapshot(cranpose_ui::text_field_focus::dispatch_cut).unwrap_or(None);
1206
1207 if text.is_some() {
1208 self.mark_dirty();
1209 self.shell.app.request_layout_pass();
1210 }
1211
1212 text
1213 }
1214
1215 pub fn on_ime_preedit(&mut self, text: &str, cursor: Option<(usize, usize)>) -> bool {
1223 let _event_handler = enter_event_handler_scope();
1224 let app_context = Rc::clone(&self.shell.app.app_context);
1225 app_context.enter(|| self.on_ime_preedit_inner(text, cursor))
1226 }
1227
1228 fn on_ime_preedit_inner(&mut self, text: &str, cursor: Option<(usize, usize)>) -> bool {
1229 let handled = run_in_mutable_snapshot(|| {
1230 cranpose_ui::text_field_focus::dispatch_ime_preedit(text, cursor)
1231 })
1232 .unwrap_or(false);
1233
1234 if handled {
1235 self.mark_dirty();
1236 self.shell.app.request_layout_pass();
1237 }
1238
1239 handled
1240 }
1241
1242 pub fn on_ime_finish_composing(&mut self) -> bool {
1246 let _event_handler = enter_event_handler_scope();
1247 let app_context = Rc::clone(&self.shell.app.app_context);
1248 app_context.enter(|| self.on_ime_finish_composing_inner())
1249 }
1250
1251 fn on_ime_finish_composing_inner(&mut self) -> bool {
1252 let handled =
1253 run_in_mutable_snapshot(cranpose_ui::text_field_focus::dispatch_ime_finish_composing)
1254 .unwrap_or(false);
1255
1256 if handled {
1257 self.mark_dirty();
1258 self.shell.app.request_layout_pass();
1259 }
1260
1261 handled
1262 }
1263
1264 pub fn on_ime_set_composing_region(&mut self, start_bytes: usize, end_bytes: usize) -> bool {
1268 let _event_handler = enter_event_handler_scope();
1269 let app_context = Rc::clone(&self.shell.app.app_context);
1270 app_context.enter(|| {
1271 let handled = run_in_mutable_snapshot(|| {
1272 cranpose_ui::text_field_focus::dispatch_ime_set_composing_region(
1273 start_bytes,
1274 end_bytes,
1275 )
1276 })
1277 .unwrap_or(false);
1278
1279 if handled {
1280 self.mark_dirty();
1281 self.shell.app.request_layout_pass();
1282 }
1283
1284 handled
1285 })
1286 }
1287
1288 pub fn on_ime_set_selection(&mut self, start_bytes: usize, end_bytes: usize) -> bool {
1293 let _event_handler = enter_event_handler_scope();
1294 let app_context = Rc::clone(&self.shell.app.app_context);
1295 app_context.enter(|| {
1296 let handled = run_in_mutable_snapshot(|| {
1297 cranpose_ui::text_field_focus::dispatch_ime_set_selection(start_bytes, end_bytes)
1298 })
1299 .unwrap_or(false);
1300
1301 if handled {
1302 self.mark_dirty();
1303 }
1304
1305 handled
1306 })
1307 }
1308
1309 pub fn ime_editor_state(&mut self) -> Option<cranpose_ui::text_field_focus::ImeEditorState> {
1313 let app_context = Rc::clone(&self.shell.app.app_context);
1314 app_context.enter(cranpose_ui::text_field_focus::focused_editor_state)
1315 }
1316
1317 pub fn ime_caret_geometry(
1321 &mut self,
1322 ) -> Option<cranpose_ui::text_field_focus::ImeCaretGeometry> {
1323 let app_context = Rc::clone(&self.shell.app.app_context);
1324 app_context.enter(cranpose_ui::text_field_focus::focused_caret_geometry)
1325 }
1326
1327 pub fn clear_text_field_focus(&mut self) {
1330 let _event_handler = enter_event_handler_scope();
1331 let app_context = Rc::clone(&self.shell.app.app_context);
1332 app_context.enter(cranpose_ui::text_field_focus::clear_focus);
1333 self.mark_dirty();
1334 self.shell.app.request_layout_pass();
1335 }
1336
1337 pub fn on_ime_delete_surrounding(&mut self, before_bytes: usize, after_bytes: usize) -> bool {
1340 let _event_handler = enter_event_handler_scope();
1341 let app_context = Rc::clone(&self.shell.app.app_context);
1342 app_context.enter(|| self.on_ime_delete_surrounding_inner(before_bytes, after_bytes))
1343 }
1344
1345 fn on_ime_delete_surrounding_inner(&mut self, before_bytes: usize, after_bytes: usize) -> bool {
1346 let handled = run_in_mutable_snapshot(|| {
1347 cranpose_ui::text_field_focus::dispatch_delete_surrounding(before_bytes, after_bytes)
1348 })
1349 .unwrap_or(false);
1350
1351 if handled {
1352 self.mark_dirty();
1353 self.shell.app.request_layout_pass();
1354 }
1355
1356 handled
1357 }
1358}
1359
1360impl<R> AppShell<R>
1361where
1362 R: Renderer,
1363 R::Error: Debug,
1364{
1365 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
1374 self.app.modifiers = Some(modifiers);
1375 }
1376
1377 pub fn modifiers(&self) -> Option<Modifiers> {
1381 self.app.modifiers
1382 }
1383
1384 pub fn rotary_scroll_factor(&self) -> f32 {
1387 self.app.rotary_scroll_factor
1388 }
1389
1390 pub fn set_rotary_scroll_factor(&mut self, factor: f32) {
1399 if factor.is_finite() && factor > 0.0 {
1400 self.app.rotary_scroll_factor = factor;
1401 }
1402 }
1403
1404 pub fn notify_app_paused(&mut self) {
1411 let app_context = Rc::clone(&self.app.app_context);
1412 app_context.enter(cranpose_ui::text_input_session::notify_app_paused);
1413 }
1414
1415 pub fn notify_app_resumed(&mut self) -> bool {
1423 let app_context = Rc::clone(&self.app.app_context);
1424 app_context.enter(cranpose_ui::text_input_session::notify_app_resumed)
1425 }
1426
1427 #[cfg(all(
1428 feature = "clipboard-native",
1429 target_os = "linux",
1430 not(target_arch = "wasm32")
1431 ))]
1432 pub fn set_primary_selection(&mut self, text: &str) {
1433 use arboard::{LinuxClipboardKind, SetExtLinux};
1434 if let Some(ref mut clipboard) = self.app.clipboard {
1435 let result = clipboard
1436 .set()
1437 .clipboard(LinuxClipboardKind::Primary)
1438 .text(text.to_string());
1439 if let Err(e) = result {
1440 log::debug!("Primary selection set failed: {:?}", e);
1441 }
1442 }
1443 }
1444
1445 #[cfg(not(all(
1446 feature = "clipboard-native",
1447 target_os = "linux",
1448 not(target_arch = "wasm32")
1449 )))]
1450 pub fn set_primary_selection(&mut self, _text: &str) {}
1451
1452 #[cfg(all(
1453 feature = "clipboard-native",
1454 target_os = "linux",
1455 not(target_arch = "wasm32")
1456 ))]
1457 pub fn get_primary_selection(&mut self) -> Option<String> {
1458 use arboard::{GetExtLinux, LinuxClipboardKind};
1459 if let Some(ref mut clipboard) = self.app.clipboard {
1460 clipboard
1461 .get()
1462 .clipboard(LinuxClipboardKind::Primary)
1463 .text()
1464 .ok()
1465 } else {
1466 None
1467 }
1468 }
1469
1470 #[cfg(not(all(
1471 feature = "clipboard-native",
1472 target_os = "linux",
1473 not(target_arch = "wasm32")
1474 )))]
1475 pub fn get_primary_selection(&mut self) -> Option<String> {
1476 None
1477 }
1478
1479 pub fn sync_selection_to_primary(&mut self) {
1482 #[cfg(all(target_os = "linux", not(target_arch = "wasm32")))]
1483 {
1484 if let Some(text) = self.on_copy() {
1485 self.set_primary_selection(&text);
1486 }
1487 }
1488 }
1489
1490 pub fn set_pointer_source(&mut self, source: PointerSource) {
1492 self.primary().set_pointer_source(source);
1493 }
1494
1495 pub fn pointer_source(&self) -> PointerSource {
1497 self.surfaces[0].pointer_source
1498 }
1499
1500 pub fn set_cursor(&mut self, x: f32, y: f32) -> bool {
1502 self.primary().set_cursor(x, y)
1503 }
1504
1505 pub fn set_cursor_at_time(&mut self, x: f32, y: f32, time_ms: Option<i64>) -> bool {
1507 self.primary().set_cursor_at_time(x, y, time_ms)
1508 }
1509
1510 pub fn set_cursor_at_event_time(
1512 &mut self,
1513 x: f32,
1514 y: f32,
1515 event_time: PointerEventTime,
1516 ) -> bool {
1517 self.primary().set_cursor_at_event_time(x, y, event_time)
1518 }
1519
1520 pub fn pointer_pressed(&mut self) -> bool {
1522 self.primary().pointer_pressed()
1523 }
1524
1525 pub fn pointer_pressed_at_time(&mut self, time_ms: Option<i64>) -> bool {
1527 self.primary().pointer_pressed_at_time(time_ms)
1528 }
1529
1530 pub fn pointer_pressed_at_event_time(&mut self, event_time: PointerEventTime) -> bool {
1532 self.primary().pointer_pressed_at_event_time(event_time)
1533 }
1534
1535 pub fn pointer_released(&mut self) -> bool {
1537 self.primary().pointer_released()
1538 }
1539
1540 pub fn pointer_released_at_position(&mut self, x: f32, y: f32) -> bool {
1542 self.primary().pointer_released_at_position(x, y)
1543 }
1544
1545 pub fn pointer_released_at_position_time(
1548 &mut self,
1549 x: f32,
1550 y: f32,
1551 time_ms: Option<i64>,
1552 ) -> bool {
1553 self.primary()
1554 .pointer_released_at_position_time(x, y, time_ms)
1555 }
1556
1557 pub fn pointer_released_at_position_event_time(
1560 &mut self,
1561 x: f32,
1562 y: f32,
1563 event_time: PointerEventTime,
1564 ) -> bool {
1565 self.primary()
1566 .pointer_released_at_position_event_time(x, y, event_time)
1567 }
1568
1569 pub fn pointer_released_at_time(&mut self, time_ms: Option<i64>) -> bool {
1571 self.primary().pointer_released_at_time(time_ms)
1572 }
1573
1574 pub fn pointer_released_at_event_time(&mut self, event_time: PointerEventTime) -> bool {
1576 self.primary().pointer_released_at_event_time(event_time)
1577 }
1578
1579 pub fn secondary_pointer_pressed(
1581 &mut self,
1582 pointer_id: u64,
1583 x: f32,
1584 y: f32,
1585 time_ms: Option<i64>,
1586 ) -> bool {
1587 self.primary()
1588 .secondary_pointer_pressed(pointer_id, x, y, time_ms)
1589 }
1590
1591 pub fn secondary_pointer_moved(
1593 &mut self,
1594 pointer_id: u64,
1595 x: f32,
1596 y: f32,
1597 time_ms: Option<i64>,
1598 ) -> bool {
1599 self.primary()
1600 .secondary_pointer_moved(pointer_id, x, y, time_ms)
1601 }
1602
1603 pub fn secondary_pointer_released(
1605 &mut self,
1606 pointer_id: u64,
1607 x: f32,
1608 y: f32,
1609 time_ms: Option<i64>,
1610 ) -> bool {
1611 self.primary()
1612 .secondary_pointer_released(pointer_id, x, y, time_ms)
1613 }
1614
1615 pub fn pointer_zoomed(&mut self, zoom_factor: f32) -> bool {
1617 self.primary().pointer_zoomed(zoom_factor)
1618 }
1619
1620 pub fn wheel_scrolled(&mut self, wheel: crate::WheelScroll) -> bool {
1622 self.primary().wheel_scrolled(wheel)
1623 }
1624
1625 pub fn pointer_scrolled(&mut self, delta_x: f32, delta_y: f32) -> bool {
1627 self.primary().pointer_scrolled(delta_x, delta_y)
1628 }
1629
1630 pub fn set_on_rotary_scroll<F>(&mut self, handler: F)
1632 where
1633 F: Fn(RotaryScrollEvent) -> bool + 'static,
1634 {
1635 self.primary().set_on_rotary_scroll(handler);
1636 }
1637
1638 pub fn clear_on_rotary_scroll(&mut self) {
1640 self.primary().clear_on_rotary_scroll();
1641 }
1642
1643 pub fn rotary_scrolled_by_detents(&mut self, detents: f32, uptime_millis: u64) -> bool {
1645 self.primary()
1646 .rotary_scrolled_by_detents(detents, uptime_millis)
1647 }
1648
1649 pub fn rotary_scrolled(&mut self, event: RotaryScrollEvent) -> bool {
1651 self.primary().rotary_scrolled(event)
1652 }
1653
1654 pub fn cancel_gesture(&mut self) {
1656 self.primary().cancel_gesture();
1657 }
1658
1659 pub fn cancel_gesture_unless_pressed(&mut self) {
1661 self.primary().cancel_gesture_unless_pressed();
1662 }
1663
1664 pub fn refresh_pointer_icon(&self) {
1668 self.surfaces[0].pointer_icon.refresh();
1669 }
1670
1671 pub fn take_pointer_icon_change(&self) -> Option<PointerIcon> {
1678 self.surfaces[0].pointer_icon.take_change()
1679 }
1680
1681 pub fn set_platform_text_input(
1688 &mut self,
1689 handler: Rc<dyn cranpose_ui::PlatformTextInputHandler>,
1690 ) {
1691 self.primary().set_platform_text_input(handler);
1692 }
1693
1694 pub fn dismiss_top_modal(&mut self) -> bool {
1696 self.primary().dismiss_top_modal()
1697 }
1698
1699 pub fn move_focus_in_context(&mut self, direction: FocusDirection) -> bool {
1701 self.primary().move_focus_in_context(direction)
1702 }
1703
1704 pub fn on_key_event(&mut self, event: &KeyEvent) -> bool {
1706 self.primary().on_key_event(event)
1707 }
1708
1709 pub fn on_paste(&mut self, text: &str) -> bool {
1711 self.primary().on_paste(text)
1712 }
1713
1714 pub fn on_copy(&mut self) -> Option<String> {
1716 self.primary().on_copy()
1717 }
1718
1719 pub fn on_cut(&mut self) -> Option<String> {
1721 self.primary().on_cut()
1722 }
1723
1724 pub fn on_ime_preedit(&mut self, text: &str, cursor: Option<(usize, usize)>) -> bool {
1726 self.primary().on_ime_preedit(text, cursor)
1727 }
1728
1729 pub fn on_ime_finish_composing(&mut self) -> bool {
1731 self.primary().on_ime_finish_composing()
1732 }
1733
1734 pub fn on_ime_set_composing_region(&mut self, start_bytes: usize, end_bytes: usize) -> bool {
1736 self.primary()
1737 .on_ime_set_composing_region(start_bytes, end_bytes)
1738 }
1739
1740 pub fn on_ime_set_selection(&mut self, start_bytes: usize, end_bytes: usize) -> bool {
1742 self.primary().on_ime_set_selection(start_bytes, end_bytes)
1743 }
1744
1745 pub fn ime_editor_state(&mut self) -> Option<cranpose_ui::text_field_focus::ImeEditorState> {
1747 self.primary().ime_editor_state()
1748 }
1749
1750 pub fn ime_caret_geometry(
1752 &mut self,
1753 ) -> Option<cranpose_ui::text_field_focus::ImeCaretGeometry> {
1754 self.primary().ime_caret_geometry()
1755 }
1756
1757 pub fn clear_text_field_focus(&mut self) {
1759 self.primary().clear_text_field_focus();
1760 }
1761
1762 pub fn on_ime_delete_surrounding(&mut self, before_bytes: usize, after_bytes: usize) -> bool {
1764 self.primary()
1765 .on_ime_delete_surrounding(before_bytes, after_bytes)
1766 }
1767}
1768
1769fn plain_key_down(event: &KeyEvent) -> bool {
1770 event.event_type == KeyEventType::KeyDown
1771 && !event.modifiers.ctrl
1772 && !event.modifiers.meta
1773 && !event.modifiers.alt
1774}