1use cranpose_ui::FocusDirection;
2
3use super::*;
4
5mod dispatch_stop;
6pub(crate) mod key_activation;
7mod key_navigation;
8
9use dispatch_stop::Stop;
10
11impl<R> SurfaceMut<'_, R>
12where
13 R: Renderer,
14 R::Error: Debug,
15{
16 fn pointer_event(
17 &self,
18 kind: PointerEventKind,
19 position: Point,
20 global_position: Point,
21 event_time: PointerEventTime,
22 ) -> PointerEvent {
23 let screen_position = self.surface().screen_origin.map(|origin| Point {
24 x: origin.x + global_position.x,
25 y: origin.y + global_position.y,
26 });
27 let mut event = PointerEvent::new(kind, position, global_position)
28 .with_time_ms(event_time.platform_time_ms)
29 .with_animation_time_nanos(event_time.animation_time_nanos)
30 .with_screen_position(screen_position);
31 event.modifiers = self.shell.app.modifiers;
32 event
33 }
34
35 fn resolve_gesture_targets(
36 &self,
37 pointer: PointerId,
38 ) -> Vec<<<R as Renderer>::Scene as RenderScene>::HitTarget> {
39 self.resolve_hit_path(pointer)
40 }
41
42 fn resolve_hit_path(
43 &self,
44 pointer: PointerId,
45 ) -> Vec<<<R as Renderer>::Scene as RenderScene>::HitTarget> {
46 let Some(node_ids) = self.surface().hit_path_tracker.dispatch_order(pointer) else {
47 return Vec::new();
48 };
49
50 let scene = self.surface().renderer.scene();
51 let targets: Vec<_> = node_ids
52 .iter()
53 .filter_map(|&id| scene.find_target(id))
54 .collect();
55 log::trace!(
56 target: "cranpose::input",
57 "resolve_hit_path pointer={pointer:?} cached={node_ids:?} resolved_count={}",
58 targets.len()
59 );
60 targets
61 }
62
63 fn dispatch_targets<I>(&mut self, targets: I, event: PointerEvent, stop: Stop)
64 where
65 I: IntoIterator<Item = <<R as Renderer>::Scene as RenderScene>::HitTarget>,
66 {
67 let mut applier = self.shell.app.composition.applier_mut();
68 for target in targets {
69 let node_id = target.node_id();
70 target.dispatch_with_applier(&mut applier, event.clone());
71 log::trace!(
72 target: "cranpose::input",
73 "dispatch {:?} node={} consumed={} stop={:?}",
74 event.kind,
75 node_id,
76 event.is_consumed(),
77 stop,
78 );
79 if stop == Stop::AtConsumer && event.is_consumed() {
80 break;
81 }
82 }
83 event.finish_post_dispatch();
84 }
85
86 fn dispatch_to_hits(
87 &mut self,
88 hits: &[<<R as Renderer>::Scene as RenderScene>::HitTarget],
89 event: PointerEvent,
90 ) -> bool {
91 let capture_paths = hits
92 .iter()
93 .map(HitTestTarget::capture_path)
94 .collect::<Vec<_>>();
95 let targets = hit_path_tracker::dispatch_order_for_paths(&capture_paths)
96 .into_iter()
97 .filter_map(|node_id| self.surface().renderer.scene().find_target(node_id))
98 .collect::<Vec<_>>();
99
100 self.dispatch_targets(targets, event.clone(), Stop::AtConsumer);
101
102 event.is_consumed()
103 }
104
105 pub fn set_pointer_source(&mut self, source: PointerSource) {
111 self.surface_mut().pointer_source = source;
112 }
113
114 pub fn pointer_source(&self) -> PointerSource {
116 self.surface().pointer_source
117 }
118
119 pub fn set_cursor(&mut self, x: f32, y: f32) -> bool {
122 self.set_cursor_at_time(x, y, None)
123 }
124
125 pub fn set_cursor_at_time(&mut self, x: f32, y: f32, time_ms: Option<i64>) -> bool {
132 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
133 self.set_cursor_at_event_time(x, y, event_time)
134 }
135
136 pub fn set_cursor_at_event_time(
138 &mut self,
139 x: f32,
140 y: f32,
141 event_time: PointerEventTime,
142 ) -> bool {
143 let _event_handler = enter_event_handler_scope();
144 let result = {
145 let _app_context = self.shell.app.app_context.enter_scope();
146 run_in_mutable_snapshot(|| self.set_cursor_inner(x, y, event_time)).unwrap_or(false)
147 };
148 self.route_drag_and_drop();
149 if result {
150 self.mark_dirty();
151 }
152 log::trace!(
153 target: "cranpose::input",
154 "set_cursor ({x:.2},{y:.2}) time_ms={:?} animation_time_nanos={} -> {result}",
155 event_time.platform_time_ms,
156 event_time.animation_time_nanos,
157 );
158 result
159 }
160
161 fn set_cursor_inner(&mut self, x: f32, y: f32, event_time: PointerEventTime) -> bool {
162 self.surface_mut().cursor = (x, y);
163 if self.inspector_move(x, y) {
164 return true;
165 }
166
167 if self.surface().buttons_pressed != PointerButtons::NONE {
168 if self.surface().hit_path_tracker.has_path(PointerId::PRIMARY) {
169 let targets = self.resolve_gesture_targets(PointerId::PRIMARY);
170 if !targets.is_empty() {
171 let event = self
172 .pointer_event(
173 PointerEventKind::Move,
174 Point { x, y },
175 Point { x, y },
176 event_time,
177 )
178 .with_buttons(self.surface().buttons_pressed)
179 .with_source(self.surface().pointer_source);
180 self.dispatch_targets(targets, event, Stop::Never);
181 return true;
182 }
183
184 return false;
185 }
186
187 return false;
188 }
189
190 let hits = if self.inspector_blocks_pointer(x, y) {
191 Vec::new()
192 } else {
193 self.surface().renderer.scene().hit_test(x, y)
194 };
195 let new_ids: Vec<NodeId> = hits.iter().map(HitTestTarget::node_id).collect();
196
197 let pos = Point { x, y };
198 let previously_hovered = self.surface().hovered_nodes.clone();
199 for old_id in previously_hovered {
200 if !new_ids.contains(&old_id)
201 && let Some(target) = self.surface().renderer.scene().find_target(old_id)
202 {
203 let exit_event = self
204 .pointer_event(PointerEventKind::Exit, pos, pos, event_time)
205 .with_buttons(self.surface().buttons_pressed)
206 .with_source(self.surface().pointer_source);
207 self.dispatch_targets(std::iter::once(target), exit_event, Stop::Never);
208 }
209 }
210
211 for hit in &hits {
212 if !self.surface().hovered_nodes.contains(&hit.node_id()) {
213 let enter_event = self
214 .pointer_event(PointerEventKind::Enter, pos, pos, event_time)
215 .with_buttons(self.surface().buttons_pressed)
216 .with_source(self.surface().pointer_source);
217 self.dispatch_targets(std::iter::once(hit.clone()), enter_event, Stop::Never);
218 }
219 }
220
221 self.surface_mut().hovered_nodes = new_ids;
222 self.apply_hovered_pointer_icon(&hits);
223
224 if !hits.is_empty() {
225 let event = self
226 .pointer_event(PointerEventKind::Move, pos, pos, event_time)
227 .with_buttons(self.surface().buttons_pressed)
228 .with_source(self.surface().pointer_source);
229 self.dispatch_targets(hits, event, Stop::AtConsumer);
230 true
231 } else {
232 false
233 }
234 }
235
236 pub fn pointer_pressed(&mut self) -> bool {
239 self.pointer_pressed_at_time(None)
240 }
241
242 pub fn pointer_pressed_at_time(&mut self, time_ms: Option<i64>) -> bool {
245 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
246 self.pointer_pressed_at_event_time(event_time)
247 }
248
249 pub fn pointer_pressed_at_event_time(&mut self, event_time: PointerEventTime) -> bool {
251 let (cursor_x, cursor_y) = self.surface().cursor;
252 if self.inspector_press(cursor_x, cursor_y) {
253 return true;
254 }
255 if self.dev_overlay_press(cursor_x, cursor_y) {
256 return true;
257 }
258 let _event_handler = enter_event_handler_scope();
259 let result = {
260 let _app_context = self.shell.app.app_context.enter_scope();
261 run_in_mutable_snapshot(|| self.pointer_pressed_inner(event_time)).unwrap_or(false)
262 };
263 if result {
264 self.mark_dirty();
265 }
266 log::trace!(
267 target: "cranpose::input",
268 "pointer_pressed time_ms={:?} animation_time_nanos={} -> {result}",
269 event_time.platform_time_ms,
270 event_time.animation_time_nanos,
271 );
272 result
273 }
274
275 fn pointer_pressed_inner(&mut self, event_time: PointerEventTime) -> bool {
276 self.activate();
277 self.note_focus_moved_by_keyboard(false);
278 self.surface_mut()
279 .buttons_pressed
280 .insert(PointerButton::Primary);
281
282 let (cursor_x, cursor_y) = self.surface().cursor;
283 let mut hits = self.surface().renderer.scene().hit_test(cursor_x, cursor_y);
284 if self.surface().pointer_source.is_touch_like()
285 && let Some(near) = self
286 .surface()
287 .renderer
288 .scene()
289 .hit_test_near(cursor_x, cursor_y)
290 && hits.iter().all(|hit| {
291 hit.node_id() != near.node_id() && near.capture_path().contains(&hit.node_id())
292 })
293 {
294 hits.insert(0, near);
295 }
296 let event = self.cursor_event(PointerEventKind::Down, event_time);
297 self.press_hits(hits, event, PointerId::PRIMARY)
298 }
299
300 fn cursor_event(&self, kind: PointerEventKind, event_time: PointerEventTime) -> PointerEvent {
303 let (x, y) = self.surface().cursor;
304 self.pointer_event(kind, Point { x, y }, Point { x, y }, event_time)
305 .with_buttons(self.surface().buttons_pressed)
306 .with_source(self.surface().pointer_source)
307 }
308
309 fn press_hits(
312 &mut self,
313 hits: Vec<<<R as Renderer>::Scene as RenderScene>::HitTarget>,
314 event: PointerEvent,
315 pointer: PointerId,
316 ) -> bool {
317 if hits.is_empty() {
318 self.surface_mut().hit_path_tracker.remove_path(pointer);
319 return false;
320 }
321 let mut delivered_capture_paths = Vec::new();
322 let (app, surface) = self.parts();
323 let mut applier = app.composition.applier_mut();
324 for hit in hits {
325 let node_id = hit.node_id();
326 delivered_capture_paths.push(hit.capture_path());
327 hit.dispatch_with_applier(&mut applier, event.clone());
328 log::trace!(
329 target: "cranpose::input",
330 "dispatch {:?} node={} consumed={} stop=AtConsumer",
331 event.kind,
332 node_id,
333 event.is_consumed(),
334 );
335 if event.is_consumed() {
336 break;
337 }
338 }
339
340 surface
341 .hit_path_tracker
342 .add_hit_path(pointer, delivered_capture_paths);
343 log::trace!(
344 target: "cranpose::input",
345 "press cached_hit_path={:?}",
346 surface.hit_path_tracker.get_path(pointer),
347 );
348 true
349 }
350
351 pub fn mouse_button_pressed(&mut self, button: PointerButton) -> bool {
358 if button == PointerButton::Primary {
359 return self.pointer_pressed();
360 }
361 self.mouse_button_change(|surface, event_time| {
362 surface.other_button_pressed(button, event_time)
363 })
364 }
365
366 pub fn mouse_button_released(&mut self, button: PointerButton) -> bool {
371 if button == PointerButton::Primary {
372 return self.pointer_released();
373 }
374 self.mouse_button_change(|surface, event_time| {
375 surface.other_button_released(button, event_time)
376 })
377 }
378
379 fn mouse_button_change(
380 &mut self,
381 change: impl FnOnce(&mut Self, PointerEventTime) -> bool,
382 ) -> bool {
383 let event_time = self.shell.app.realtime_pointer_event_time(None);
384 let _event_handler = enter_event_handler_scope();
385 let result = {
386 let _app_context = self.shell.app.app_context.enter_scope();
387 run_in_mutable_snapshot(|| change(self, event_time)).unwrap_or(false)
388 };
389 if result {
390 self.mark_dirty();
391 }
392 result
393 }
394
395 fn other_button_pressed(
396 &mut self,
397 button: PointerButton,
398 event_time: PointerEventTime,
399 ) -> bool {
400 self.activate();
401 let first = self.surface().buttons_pressed == PointerButtons::NONE;
402 self.surface_mut().buttons_pressed.insert(button);
403 let event = self.cursor_event(PointerEventKind::ButtonDown(button), event_time);
404 if first {
405 let (x, y) = self.surface().cursor;
406 let hits = self.surface().renderer.scene().hit_test(x, y);
407 return self.press_hits(hits, event, PointerId::PRIMARY);
408 }
409 let targets = self.resolve_gesture_targets(PointerId::PRIMARY);
410 if targets.is_empty() {
411 return false;
412 }
413 self.dispatch_targets(targets, event, Stop::Never);
414 true
415 }
416
417 fn other_button_released(
418 &mut self,
419 button: PointerButton,
420 event_time: PointerEventTime,
421 ) -> bool {
422 if !self.surface().buttons_pressed.contains(button) {
423 return false;
424 }
425 self.surface_mut().buttons_pressed.remove(button);
426 let targets = self.resolve_gesture_targets(PointerId::PRIMARY);
427 if self.surface().buttons_pressed == PointerButtons::NONE {
428 self.surface_mut()
429 .hit_path_tracker
430 .remove_path(PointerId::PRIMARY);
431 }
432 if targets.is_empty() {
433 return false;
434 }
435 let event = self.cursor_event(PointerEventKind::ButtonUp(button), event_time);
436 self.dispatch_targets(targets, event, Stop::Never);
437 true
438 }
439
440 pub fn pointer_released(&mut self) -> bool {
443 self.pointer_released_at_time(None)
444 }
445
446 pub fn pointer_released_at_position(&mut self, x: f32, y: f32) -> bool {
459 self.pointer_released_at_position_time(x, y, None)
460 }
461
462 pub fn pointer_released_at_position_time(
466 &mut self,
467 x: f32,
468 y: f32,
469 time_ms: Option<i64>,
470 ) -> bool {
471 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
472 self.pointer_released_at_position_event_time(x, y, event_time)
473 }
474
475 pub fn pointer_released_at_position_event_time(
477 &mut self,
478 x: f32,
479 y: f32,
480 event_time: PointerEventTime,
481 ) -> bool {
482 let _event_handler = enter_event_handler_scope();
483 let result = {
484 let _app_context = self.shell.app.app_context.enter_scope();
485 run_in_mutable_snapshot(|| {
486 self.surface_mut().cursor = (x, y);
487 self.pointer_released_inner(event_time)
488 })
489 .unwrap_or(false)
490 };
491 self.route_drag_and_drop();
492 if result {
493 self.mark_dirty();
494 }
495 log::trace!(
496 target: "cranpose::input",
497 "pointer_released_at_position ({x:.2},{y:.2}) time_ms={:?} animation_time_nanos={} -> {result}",
498 event_time.platform_time_ms,
499 event_time.animation_time_nanos,
500 );
501 result
502 }
503
504 pub fn pointer_released_at_time(&mut self, time_ms: Option<i64>) -> bool {
507 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
508 self.pointer_released_at_event_time(event_time)
509 }
510
511 pub fn pointer_released_at_event_time(&mut self, event_time: PointerEventTime) -> bool {
513 let _event_handler = enter_event_handler_scope();
514 let result = {
515 let _app_context = self.shell.app.app_context.enter_scope();
516 run_in_mutable_snapshot(|| self.pointer_released_inner(event_time)).unwrap_or(false)
517 };
518 self.route_drag_and_drop();
519 if result {
520 self.mark_dirty();
521 }
522 log::trace!(
523 target: "cranpose::input",
524 "pointer_released time_ms={:?} animation_time_nanos={} -> {result}",
525 event_time.platform_time_ms,
526 event_time.animation_time_nanos,
527 );
528 result
529 }
530
531 fn pointer_released_inner(&mut self, event_time: PointerEventTime) -> bool {
532 if self.surface_mut().inspector.release_pointer() {
533 return true;
534 }
535 self.release_app_pointer(event_time)
536 }
537
538 fn release_app_pointer(&mut self, event_time: PointerEventTime) -> bool {
539 self.surface_mut()
540 .buttons_pressed
541 .remove(PointerButton::Primary);
542 let corrected_buttons = self.surface().buttons_pressed;
543 let targets = self.resolve_gesture_targets(PointerId::PRIMARY);
544
545 if corrected_buttons == PointerButtons::NONE {
548 self.surface_mut()
549 .hit_path_tracker
550 .remove_path(PointerId::PRIMARY);
551 }
552
553 if !targets.is_empty() {
554 let event = self
555 .pointer_event(
556 PointerEventKind::Up,
557 Point {
558 x: self.surface().cursor.0,
559 y: self.surface().cursor.1,
560 },
561 Point {
562 x: self.surface().cursor.0,
563 y: self.surface().cursor.1,
564 },
565 event_time,
566 )
567 .with_buttons(corrected_buttons)
568 .with_source(self.surface().pointer_source);
569
570 self.dispatch_targets(targets, event, Stop::Never);
571 true
572 } else {
573 false
574 }
575 }
576
577 pub fn secondary_pointer_pressed(
586 &mut self,
587 pointer_id: PointerId,
588 x: f32,
589 y: f32,
590 time_ms: Option<i64>,
591 ) -> bool {
592 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
593 self.dispatch_secondary_pointer(PointerEventKind::Down, pointer_id, x, y, event_time)
594 }
595
596 pub fn secondary_pointer_moved(
598 &mut self,
599 pointer_id: PointerId,
600 x: f32,
601 y: f32,
602 time_ms: Option<i64>,
603 ) -> bool {
604 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
605 self.dispatch_secondary_pointer(PointerEventKind::Move, pointer_id, x, y, event_time)
606 }
607
608 pub fn secondary_pointer_released(
610 &mut self,
611 pointer_id: PointerId,
612 x: f32,
613 y: f32,
614 time_ms: Option<i64>,
615 ) -> bool {
616 let event_time = self.shell.app.realtime_pointer_event_time(time_ms);
617 self.dispatch_secondary_pointer(PointerEventKind::Up, pointer_id, x, y, event_time)
618 }
619
620 fn dispatch_secondary_pointer(
621 &mut self,
622 kind: PointerEventKind,
623 pointer_id: PointerId,
624 x: f32,
625 y: f32,
626 event_time: PointerEventTime,
627 ) -> bool {
628 if pointer_id.is_primary() {
629 log::warn!(
630 target: "cranpose::input",
631 "secondary pointer dispatch called with the primary pointer id"
632 );
633 return false;
634 }
635
636 let _event_handler = enter_event_handler_scope();
637 let result = {
638 let _app_context = self.shell.app.app_context.enter_scope();
639 run_in_mutable_snapshot(|| {
640 if !self.surface().hit_path_tracker.has_path(PointerId::PRIMARY) {
641 return false;
642 }
643 let targets = self.resolve_gesture_targets(PointerId::PRIMARY);
644 if targets.is_empty() {
645 return false;
646 }
647 let pos = Point { x, y };
648 let event = self
649 .pointer_event(kind, pos, pos, event_time)
650 .with_buttons(self.surface().buttons_pressed)
651 .with_id(pointer_id)
652 .with_source(self.surface().pointer_source);
653 self.dispatch_targets(targets, event, Stop::Never);
654 true
655 })
656 .unwrap_or(false)
657 };
658 if result {
659 self.mark_dirty();
660 }
661 log::trace!(
662 target: "cranpose::input",
663 "secondary_pointer {kind:?} id={pointer_id} ({x:.2},{y:.2}) time_ms={:?} animation_time_nanos={} -> {result}",
664 event_time.platform_time_ms,
665 event_time.animation_time_nanos,
666 );
667 result
668 }
669
670 pub fn ray_pointer(
679 &mut self,
680 (pointer_id, scene): (PointerId, NodeId),
681 ray: cranpose_ui_graphics::space::Ray,
682 kind: PointerEventKind,
683 ) -> bool {
684 if pointer_id.is_primary() {
685 log::warn!(
686 target: "cranpose::input",
687 "ray pointer dispatch called with the primary pointer id"
688 );
689 return false;
690 }
691 let event_time = self.shell.app.realtime_pointer_event_time(None);
692 let _event_handler = enter_event_handler_scope();
693 let result = {
694 let _app_context = self.shell.app.app_context.enter_scope();
695 run_in_mutable_snapshot(|| {
696 let pointer = pointer_id;
697 let event = self
698 .pointer_event(kind, Point::default(), Point::default(), event_time)
699 .with_id(pointer)
700 .with_ray(ray);
701 if kind == PointerEventKind::Down {
702 let hits = self.surface().renderer.scene().hit_test_ray(scene, ray);
703 return self.press_hits(hits, event, pointer);
704 }
705 let targets = self.resolve_gesture_targets(pointer);
706 if matches!(kind, PointerEventKind::Up | PointerEventKind::Cancel) {
707 self.surface_mut().hit_path_tracker.remove_path(pointer);
708 }
709 if targets.is_empty() {
710 return false;
711 }
712 self.dispatch_targets(targets, event, Stop::Never);
713 true
714 })
715 .unwrap_or(false)
716 };
717 if result {
718 self.mark_dirty();
719 }
720 result
721 }
722
723 pub fn pointer_zoomed(&mut self, zoom_factor: f32) -> bool {
729 let event_time = self.shell.app.realtime_pointer_event_time(None);
730 let _event_handler = enter_event_handler_scope();
731 let result = {
732 let _app_context = self.shell.app.app_context.enter_scope();
733 run_in_mutable_snapshot(|| self.pointer_zoomed_inner(zoom_factor, event_time))
734 .unwrap_or(false)
735 };
736 if result {
737 self.mark_dirty();
738 }
739 log::trace!(
740 target: "cranpose::input",
741 "pointer_zoomed factor={zoom_factor:.4} -> {result}"
742 );
743 result
744 }
745
746 fn pointer_zoomed_inner(&mut self, zoom_factor: f32, event_time: PointerEventTime) -> bool {
747 if !zoom_factor.is_finite() || zoom_factor <= 0.0 || zoom_factor == 1.0 {
748 return false;
749 }
750
751 let hits = self
752 .surface()
753 .renderer
754 .scene()
755 .hit_test(self.surface().cursor.0, self.surface().cursor.1);
756 if hits.is_empty() {
757 return false;
758 }
759
760 let pos = Point {
761 x: self.surface().cursor.0,
762 y: self.surface().cursor.1,
763 };
764 let event = self
765 .pointer_event(PointerEventKind::Zoom, pos, pos, event_time)
766 .with_buttons(self.surface().buttons_pressed)
767 .with_zoom_delta(zoom_factor)
768 .with_source(self.surface().pointer_source);
769
770 self.dispatch_to_hits(&hits, event)
771 }
772
773 pub fn wheel_scrolled(&mut self, wheel: WheelScroll) -> bool {
798 if self.inspector_scroll(wheel.delta.y) {
799 return true;
800 }
801 if wheel.is_zoom() {
802 let zoom_factor = wheel.zoom_factor();
803 log::trace!(
804 target: "cranpose::input",
805 "wheel zoom factor={zoom_factor:.4}"
806 );
807 return self.pointer_zoomed(zoom_factor);
808 }
809
810 let rotary =
811 RotaryScrollEvent::from_wheel_pixels(wheel.delta.y, wheel.delta.x, wheel.uptime_millis);
812 if self.rotary_scrolled(rotary) {
813 return true;
814 }
815
816 let delta = wheel.scroll_delta();
817 log::trace!(
818 target: "cranpose::input",
819 "wheel delta ({:.2},{:.2}) alt={}",
820 delta.x,
821 delta.y,
822 wheel.modifiers.alt
823 );
824 self.pointer_scrolled(delta.x, delta.y)
825 }
826
827 pub fn pointer_scrolled(&mut self, delta_x: f32, delta_y: f32) -> bool {
835 if self.inspector_scroll(delta_y) {
836 return true;
837 }
838 let event_time = self.shell.app.realtime_pointer_event_time(None);
839 let _event_handler = enter_event_handler_scope();
840 let result = {
841 let _app_context = self.shell.app.app_context.enter_scope();
842 run_in_mutable_snapshot(|| self.pointer_scrolled_inner(delta_x, delta_y, event_time))
843 .unwrap_or(false)
844 };
845 if result {
846 self.mark_dirty();
847 }
848 log::trace!(
849 target: "cranpose::input",
850 "pointer_scrolled ({delta_x:.2},{delta_y:.2}) -> {result}"
851 );
852 result
853 }
854
855 fn pointer_scrolled_inner(
856 &mut self,
857 delta_x: f32,
858 delta_y: f32,
859 event_time: PointerEventTime,
860 ) -> bool {
861 if delta_x.abs() <= f32::EPSILON && delta_y.abs() <= f32::EPSILON {
862 return false;
863 }
864
865 let hits = self
866 .surface()
867 .renderer
868 .scene()
869 .hit_test(self.surface().cursor.0, self.surface().cursor.1);
870 if hits.is_empty() {
871 return false;
872 }
873
874 let event = self
875 .pointer_event(
876 PointerEventKind::Scroll,
877 Point {
878 x: self.surface().cursor.0,
879 y: self.surface().cursor.1,
880 },
881 Point {
882 x: self.surface().cursor.0,
883 y: self.surface().cursor.1,
884 },
885 event_time,
886 )
887 .with_buttons(self.surface().buttons_pressed)
888 .with_scroll_delta(Point {
889 x: delta_x,
890 y: delta_y,
891 })
892 .with_source(self.surface().pointer_source);
893
894 self.dispatch_to_hits(&hits, event)
895 }
896
897 pub fn set_on_rotary_scroll<F>(&mut self, handler: F)
908 where
909 F: Fn(RotaryScrollEvent) -> bool + 'static,
910 {
911 self.surface_mut().on_rotary_scroll = Some(Rc::new(handler));
912 }
913
914 pub fn clear_on_rotary_scroll(&mut self) {
916 self.surface_mut().on_rotary_scroll = None;
917 }
918
919 pub fn rotary_scrolled_by_detents(&mut self, detents: f32, uptime_millis: u64) -> bool {
925 let factor = self.shell.app.rotary_scroll_factor;
926 self.rotary_scrolled(RotaryScrollEvent::from_detents(
927 detents,
928 factor,
929 factor,
930 uptime_millis,
931 ))
932 }
933
934 pub fn rotary_scrolled(&mut self, event: RotaryScrollEvent) -> bool {
953 let _event_handler = enter_event_handler_scope();
954 let result = {
955 let _app_context = self.shell.app.app_context.enter_scope();
956 run_in_mutable_snapshot(|| self.rotary_scrolled_inner(event)).unwrap_or(false)
957 };
958 if result {
959 self.mark_dirty();
960 }
961 log::trace!(
962 target: "cranpose::input",
963 "rotary_scrolled v={:.2} h={:.2} uptime={} -> {result}",
964 event.vertical_scroll_pixels,
965 event.horizontal_scroll_pixels,
966 event.uptime_millis,
967 );
968 result
969 }
970
971 fn rotary_scrolled_inner(&mut self, rotary: RotaryScrollEvent) -> bool {
972 if rotary.is_empty() {
973 return false;
974 }
975
976 let bubble_order = self.rotary_dispatch_order();
977 let position = Point {
978 x: self.surface().cursor.0,
979 y: self.surface().cursor.1,
980 };
981
982 if !bubble_order.is_empty() {
983 let capture_targets = bubble_order
984 .iter()
985 .rev()
986 .filter_map(|&node_id| self.surface().renderer.scene().find_target(node_id))
987 .collect::<Vec<_>>();
988 let mut capture_event =
989 PointerEvent::rotary(PointerEventKind::RotaryScrollPre, rotary, position);
990 capture_event.modifiers = self.shell.app.modifiers;
991 self.dispatch_targets(capture_targets, capture_event.clone(), Stop::AtConsumer);
992 if capture_event.is_consumed() {
993 return true;
994 }
995
996 let bubble_targets = bubble_order
997 .iter()
998 .filter_map(|&node_id| self.surface().renderer.scene().find_target(node_id))
999 .collect::<Vec<_>>();
1000 let mut bubble_event =
1001 PointerEvent::rotary(PointerEventKind::RotaryScroll, rotary, position);
1002 bubble_event.modifiers = self.shell.app.modifiers;
1003 self.dispatch_targets(bubble_targets, bubble_event.clone(), Stop::AtConsumer);
1004 if bubble_event.is_consumed() {
1005 return true;
1006 }
1007 }
1008
1009 if let Some(handler) = self.surface().on_rotary_scroll.clone() {
1010 return handler(rotary);
1011 }
1012
1013 false
1014 }
1015
1016 fn rotary_dispatch_order(&self) -> Vec<NodeId> {
1017 if let Some(focused) = cranpose_ui::active_focus_target()
1018 && let Some(target) = self.surface().renderer.scene().find_target(focused)
1019 {
1020 let path = target.capture_path();
1021 if !path.is_empty() {
1022 return hit_path_tracker::dispatch_order_for_paths(&[path]);
1023 }
1024 }
1025
1026 let hits = self
1027 .surface()
1028 .renderer
1029 .scene()
1030 .hit_test(self.surface().cursor.0, self.surface().cursor.1);
1031 if hits.is_empty() {
1032 return Vec::new();
1033 }
1034 let capture_paths = hits
1035 .iter()
1036 .map(HitTestTarget::capture_path)
1037 .collect::<Vec<_>>();
1038 hit_path_tracker::dispatch_order_for_paths(&capture_paths)
1039 }
1040
1041 pub fn cancel_gesture(&mut self) {
1047 let event_time = self.shell.app.realtime_pointer_event_time(None);
1048 let _event_handler = enter_event_handler_scope();
1049 let _ = {
1050 let _app_context = self.shell.app.app_context.enter_scope();
1051 run_in_mutable_snapshot(|| {
1052 self.cancel_gesture_inner(event_time);
1053 })
1054 };
1055 self.route_drag_and_drop();
1056 }
1057
1058 pub(crate) fn give_press_to(&mut self, node: NodeId) {
1064 let holds = self
1065 .surface()
1066 .hit_path_tracker
1067 .get_path(PointerId::PRIMARY)
1068 .is_some_and(|paths| paths.iter().any(|path| path.contains(&node)));
1069 if !holds {
1070 return;
1071 }
1072 let event_time = self.shell.app.realtime_pointer_event_time(None);
1073 let targets = self.resolve_gesture_targets(PointerId::PRIMARY);
1074 self.surface_mut()
1075 .hit_path_tracker
1076 .add_hit_path(PointerId::PRIMARY, vec![vec![node]]);
1077 let cursor = Point {
1078 x: self.surface().cursor.0,
1079 y: self.surface().cursor.1,
1080 };
1081 let event = self
1082 .pointer_event(PointerEventKind::Cancel, cursor, cursor, event_time)
1083 .with_source(self.surface().pointer_source);
1084 let _event_handler = enter_event_handler_scope();
1085 let _ = run_in_mutable_snapshot(|| self.dispatch_targets(targets, event, Stop::Never));
1086 }
1087
1088 fn route_drag_and_drop(&mut self) {
1089 let source = self.index;
1090 let shell = &*self.shell;
1091 let app_context = &shell.app.app_context;
1092 let routed = app_context.enter(|| {
1093 run_in_mutable_snapshot(|| {
1094 app_context
1095 .drag_and_drop()
1096 .route(|point| shell.drag_and_drop_target_at(point, source))
1097 })
1098 .unwrap_or(false)
1099 });
1100 if routed {
1101 self.shell.mark_all_dirty();
1102 }
1103 }
1104
1105 pub fn cancel_gesture_unless_pressed(&mut self) {
1114 if self.surface().buttons_pressed != PointerButtons::NONE
1115 || self.surface().inspector.pointer_captured
1116 {
1117 return;
1118 }
1119 self.cancel_gesture();
1120 }
1121
1122 fn cancel_gesture_inner(&mut self, event_time: PointerEventTime) {
1123 self.surface_mut().inspector.cancel_pointer();
1124 let targets = self.resolve_gesture_targets(PointerId::PRIMARY);
1125
1126 self.surface_mut().hit_path_tracker.clear();
1127 self.surface_mut().buttons_pressed = PointerButtons::NONE;
1128
1129 if !targets.is_empty() {
1130 let event = self
1131 .pointer_event(
1132 PointerEventKind::Cancel,
1133 Point {
1134 x: self.surface().cursor.0,
1135 y: self.surface().cursor.1,
1136 },
1137 Point {
1138 x: self.surface().cursor.0,
1139 y: self.surface().cursor.1,
1140 },
1141 event_time,
1142 )
1143 .with_source(self.surface().pointer_source);
1144
1145 self.dispatch_targets(targets, event, Stop::Never);
1146 }
1147
1148 let pos = Point {
1149 x: self.surface().cursor.0,
1150 y: self.surface().cursor.1,
1151 };
1152 let hovered_nodes = self.surface().hovered_nodes.clone();
1153 for node_id in hovered_nodes {
1154 if let Some(target) = self.surface().renderer.scene().find_target(node_id) {
1155 let exit_event = self
1156 .pointer_event(PointerEventKind::Exit, pos, pos, event_time)
1157 .with_source(self.surface().pointer_source);
1158 self.dispatch_targets(std::iter::once(target), exit_event, Stop::Never);
1159 }
1160 }
1161 self.surface_mut().hovered_nodes.clear();
1162 self.surface().pointer_icon.set(PointerIcon::DEFAULT);
1163 }
1164
1165 fn apply_hovered_pointer_icon(
1166 &self,
1167 hits: &[<<R as Renderer>::Scene as RenderScene>::HitTarget],
1168 ) {
1169 let icon = hits
1170 .iter()
1171 .find_map(HitTestTarget::pointer_icon)
1172 .unwrap_or(PointerIcon::DEFAULT);
1173 self.surface().pointer_icon.set(icon);
1174 }
1175
1176 pub fn on_key_event(&mut self, event: &KeyEvent) -> bool {
1179 let _event_handler = enter_event_handler_scope();
1180 let _app_context = self.shell.app.app_context.enter_scope();
1181 let handled = self.on_key_event_inner(event);
1182 self.run_requested_focus_move();
1183 handled
1184 }
1185
1186 fn run_requested_focus_move(&mut self) {
1188 if let Some(direction) = cranpose_ui::take_requested_focus_move() {
1189 self.move_focus_in_context(direction);
1190 }
1191 }
1192
1193 fn on_key_event_inner(&mut self, event: &KeyEvent) -> bool {
1194 if self.inspector_key(event) {
1195 return true;
1196 }
1197 let root = self.key_event_root();
1198 if root.is_none() && self.id() != RootId::Primary {
1199 return false;
1200 }
1201 let route =
1202 cranpose_ui::KeyEventRoute::new(&mut self.shell.app.composition.applier_mut(), root);
1203 if self.dispatch_modifier_key(&route, event, true) {
1204 return true;
1205 }
1206 if route.focus_is_current() && self.on_focused_key_event(event) {
1207 return true;
1208 }
1209 if self.dispatch_modifier_key(&route, event, false) {
1210 return true;
1211 }
1212 route.focus_is_current() && self.on_unconsumed_key(event)
1213 }
1214
1215 fn dispatch_modifier_key(
1216 &mut self,
1217 route: &cranpose_ui::KeyEventRoute,
1218 event: &KeyEvent,
1219 preview: bool,
1220 ) -> bool {
1221 let handled = run_in_mutable_snapshot(|| {
1222 let mut applier = self.shell.app.composition.applier_mut();
1223 if preview {
1224 route.dispatch_preview(&mut applier, event)
1225 } else {
1226 route.dispatch_bubble(&mut applier, event)
1227 }
1228 })
1229 .unwrap_or(false);
1230 if handled {
1231 self.mark_dirty();
1232 self.shell.app.request_layout_pass();
1233 }
1234 handled
1235 }
1236
1237 fn key_event_root(&self) -> Option<NodeId> {
1238 self.surface()
1239 .modal_focus
1240 .last()
1241 .map(|entry| entry.0)
1242 .or_else(|| self.surface().root)
1243 .or_else(|| match self.id() {
1244 RootId::Primary => self.shell.app.composition.root(),
1245 RootId::Window(_) => None,
1246 })
1247 }
1248
1249 fn receives_focused_input(&mut self) -> bool {
1250 let root = self.key_event_root();
1251 cranpose_ui::KeyEventRoute::contains_focus(
1252 &mut self.shell.app.composition.applier_mut(),
1253 root,
1254 )
1255 }
1256
1257 fn on_focused_key_event(&mut self, event: &KeyEvent) -> bool {
1258 use KeyEventType::KeyDown;
1259
1260 if event.type_() == KeyDown && event.modifiers().command_or_ctrl() {
1261 #[cfg(all(
1262 feature = "clipboard-native",
1263 not(target_arch = "wasm32"),
1264 not(target_os = "android"),
1265 not(target_os = "ios")
1266 ))]
1267 {
1268 match event.key() {
1269 Key::C => {
1270 if let Some(text) = self.on_copy_inner() {
1271 cranpose_ui::clipboard_session::clipboard_write_text(&text);
1272 return true;
1273 }
1274 }
1275 Key::X => {
1276 if let Some(text) = self.on_cut_inner() {
1277 cranpose_ui::clipboard_session::clipboard_write_text(&text);
1278 self.mark_dirty();
1279 self.shell.app.request_layout_pass();
1280 return true;
1281 }
1282 }
1283 Key::V => {
1284 if let Some(text) = cranpose_ui::clipboard_session::clipboard_read_text()
1285 && self.on_paste_inner(&text)
1286 {
1287 return true;
1288 }
1289 }
1290 _ => {}
1291 }
1292 }
1293 }
1294
1295 if self.on_focus_key(event) {
1296 return true;
1297 }
1298
1299 if self.on_escape_key(event) {
1300 return true;
1301 }
1302
1303 if self.on_activation_key(event) || self.on_field_dpad_key(event) {
1304 return true;
1305 }
1306
1307 let handled =
1308 run_in_mutable_snapshot(|| cranpose_ui::text_field_focus::dispatch_key_event(event))
1309 .unwrap_or(false);
1310
1311 if handled {
1312 self.mark_dirty();
1313 self.shell.app.request_layout_pass();
1314 }
1315
1316 handled
1317 }
1318
1319 pub fn on_paste(&mut self, text: &str) -> bool {
1322 if self.inspector_owns_keyboard() {
1323 return true;
1324 }
1325 let _event_handler = enter_event_handler_scope();
1326 let _app_context = self.shell.app.app_context.enter_scope();
1327 self.on_paste_inner(text)
1328 }
1329
1330 fn on_paste_inner(&mut self, text: &str) -> bool {
1331 if !self.receives_focused_input() {
1332 return false;
1333 }
1334 let handled =
1335 run_in_mutable_snapshot(|| cranpose_ui::text_field_focus::dispatch_paste(text))
1336 .unwrap_or(false);
1337
1338 if handled {
1339 self.mark_dirty();
1340 self.shell.app.request_layout_pass();
1341 }
1342
1343 handled
1344 }
1345
1346 pub fn on_copy(&mut self) -> Option<String> {
1349 if self.inspector_owns_keyboard() {
1350 return None;
1351 }
1352 let _app_context = self.shell.app.app_context.enter_scope();
1353 self.on_copy_inner()
1354 }
1355
1356 fn on_copy_inner(&mut self) -> Option<String> {
1357 if !self.receives_focused_input() {
1358 return None;
1359 }
1360 cranpose_ui::text_field_focus::dispatch_copy()
1361 }
1362
1363 pub fn on_cut(&mut self) -> Option<String> {
1366 let _event_handler = enter_event_handler_scope();
1367 if self.inspector_owns_keyboard() {
1368 return None;
1369 }
1370 let _app_context = self.shell.app.app_context.enter_scope();
1371 self.on_cut_inner()
1372 }
1373
1374 fn on_cut_inner(&mut self) -> Option<String> {
1375 if !self.receives_focused_input() {
1376 return None;
1377 }
1378 let text =
1379 run_in_mutable_snapshot(cranpose_ui::text_field_focus::dispatch_cut).unwrap_or(None);
1380
1381 if text.is_some() {
1382 self.mark_dirty();
1383 self.shell.app.request_layout_pass();
1384 }
1385
1386 text
1387 }
1388
1389 pub fn on_ime_preedit(&mut self, text: &str, cursor: Option<(usize, usize)>) -> bool {
1397 if self.inspector_owns_keyboard() {
1398 return true;
1399 }
1400 let _event_handler = enter_event_handler_scope();
1401 let _app_context = self.shell.app.app_context.enter_scope();
1402 self.on_ime_preedit_inner(text, cursor)
1403 }
1404
1405 fn on_ime_preedit_inner(&mut self, text: &str, cursor: Option<(usize, usize)>) -> bool {
1406 if !self.receives_focused_input() {
1407 return false;
1408 }
1409 let handled = run_in_mutable_snapshot(|| {
1410 cranpose_ui::text_field_focus::dispatch_ime_preedit(text, cursor)
1411 })
1412 .unwrap_or(false);
1413
1414 if handled {
1415 self.mark_dirty();
1416 self.shell.app.request_layout_pass();
1417 }
1418
1419 handled
1420 }
1421
1422 pub fn on_ime_finish_composing(&mut self) -> bool {
1426 if self.inspector_owns_keyboard() {
1427 return true;
1428 }
1429 let _event_handler = enter_event_handler_scope();
1430 let _app_context = self.shell.app.app_context.enter_scope();
1431 self.on_ime_finish_composing_inner()
1432 }
1433
1434 fn on_ime_finish_composing_inner(&mut self) -> bool {
1435 if !self.receives_focused_input() {
1436 return false;
1437 }
1438 let handled =
1439 run_in_mutable_snapshot(cranpose_ui::text_field_focus::dispatch_ime_finish_composing)
1440 .unwrap_or(false);
1441
1442 if handled {
1443 self.mark_dirty();
1444 self.shell.app.request_layout_pass();
1445 }
1446
1447 handled
1448 }
1449
1450 pub fn on_ime_action(&mut self, action: cranpose_ui::ImeAction) -> bool {
1456 if self.inspector_owns_keyboard() {
1457 return true;
1458 }
1459 let _event_handler = enter_event_handler_scope();
1460 let _app_context = self.shell.app.app_context.enter_scope();
1461 if !self.receives_focused_input() {
1462 return false;
1463 }
1464 let handled =
1465 run_in_mutable_snapshot(|| cranpose_ui::text_field_focus::dispatch_ime_action(action))
1466 .unwrap_or(false);
1467 if handled {
1468 self.mark_dirty();
1469 self.shell.app.request_layout_pass();
1470 }
1471 self.run_requested_focus_move();
1472 handled
1473 }
1474
1475 pub fn on_ime_set_composing_region(&mut self, start_bytes: usize, end_bytes: usize) -> bool {
1479 if self.inspector_owns_keyboard() {
1480 return true;
1481 }
1482 let _event_handler = enter_event_handler_scope();
1483 let _app_context = self.shell.app.app_context.enter_scope();
1484 if !self.receives_focused_input() {
1485 return false;
1486 }
1487 let handled = run_in_mutable_snapshot(|| {
1488 cranpose_ui::text_field_focus::dispatch_ime_set_composing_region(start_bytes, end_bytes)
1489 })
1490 .unwrap_or(false);
1491
1492 if handled {
1493 self.mark_dirty();
1494 self.shell.app.request_layout_pass();
1495 }
1496
1497 handled
1498 }
1499
1500 pub fn on_ime_set_selection(&mut self, start_bytes: usize, end_bytes: usize) -> bool {
1505 if self.inspector_owns_keyboard() {
1506 return true;
1507 }
1508 let _event_handler = enter_event_handler_scope();
1509 let _app_context = self.shell.app.app_context.enter_scope();
1510 if !self.receives_focused_input() {
1511 return false;
1512 }
1513 let handled = run_in_mutable_snapshot(|| {
1514 cranpose_ui::text_field_focus::dispatch_ime_set_selection(start_bytes, end_bytes)
1515 })
1516 .unwrap_or(false);
1517
1518 if handled {
1519 self.mark_dirty();
1520 }
1521
1522 handled
1523 }
1524
1525 pub fn ime_editor_state(&mut self) -> Option<ImeEditorState> {
1529 let _app_context = self.shell.app.app_context.enter_scope();
1530 self.receives_focused_input()
1531 .then(cranpose_ui::text_field_focus::focused_editor_state)
1532 .flatten()
1533 }
1534
1535 pub fn ime_caret_geometry(
1539 &mut self,
1540 ) -> Option<cranpose_ui::text_field_focus::ImeCaretGeometry> {
1541 let _app_context = self.shell.app.app_context.enter_scope();
1542 self.receives_focused_input()
1543 .then(cranpose_ui::text_field_focus::focused_caret_geometry)
1544 .flatten()
1545 }
1546
1547 pub fn ime_field_bounds(&mut self) -> Option<Rect> {
1551 let _app_context = self.shell.app.app_context.enter_scope();
1552 self.receives_focused_input()
1553 .then(cranpose_ui::text_field_focus::focused_field_bounds)
1554 .flatten()
1555 }
1556
1557 pub fn ime_field_is_password(&mut self) -> bool {
1564 let _app_context = self.shell.app.app_context.enter_scope();
1565 let Some(field) = self
1566 .receives_focused_input()
1567 .then(cranpose_ui::text_field_focus::focused_field_target)
1568 .flatten()
1569 else {
1570 return false;
1571 };
1572 let mut applier = self.shell.app.composition.applier_mut();
1573 applier
1574 .with_node::<LayoutNode, _>(field, |node| node.semantics_configuration())
1575 .or_else(|_| {
1576 applier.with_node::<SubcomposeLayoutNode, _>(field, |node| {
1577 node.semantics_configuration()
1578 })
1579 })
1580 .ok()
1581 .flatten()
1582 .is_some_and(|config| config.password)
1583 }
1584
1585 pub fn clear_text_field_focus(&mut self) {
1588 let _event_handler = enter_event_handler_scope();
1589 let _app_context = self.shell.app.app_context.enter_scope();
1590 if self.receives_focused_input() {
1591 cranpose_ui::text_field_focus::clear_focus();
1592 self.mark_dirty();
1593 self.shell.app.request_layout_pass();
1594 }
1595 }
1596
1597 pub fn on_ime_delete_surrounding(&mut self, before_bytes: usize, after_bytes: usize) -> bool {
1600 if self.inspector_owns_keyboard() {
1601 return true;
1602 }
1603 let _event_handler = enter_event_handler_scope();
1604 let _app_context = self.shell.app.app_context.enter_scope();
1605 self.on_ime_delete_surrounding_inner(before_bytes, after_bytes)
1606 }
1607
1608 fn on_ime_delete_surrounding_inner(&mut self, before_bytes: usize, after_bytes: usize) -> bool {
1609 if !self.receives_focused_input() {
1610 return false;
1611 }
1612 let handled = run_in_mutable_snapshot(|| {
1613 cranpose_ui::text_field_focus::dispatch_delete_surrounding(before_bytes, after_bytes)
1614 })
1615 .unwrap_or(false);
1616
1617 if handled {
1618 self.mark_dirty();
1619 self.shell.app.request_layout_pass();
1620 }
1621
1622 handled
1623 }
1624}
1625
1626impl<R> AppShell<R>
1627where
1628 R: Renderer,
1629 R::Error: Debug,
1630{
1631 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
1640 self.app.modifiers = Some(modifiers);
1641 }
1642
1643 pub fn modifiers(&self) -> Option<Modifiers> {
1647 self.app.modifiers
1648 }
1649
1650 pub fn rotary_scroll_factor(&self) -> f32 {
1653 self.app.rotary_scroll_factor
1654 }
1655
1656 pub fn set_rotary_scroll_factor(&mut self, factor: f32) {
1665 if factor.is_finite() && factor > 0.0 {
1666 self.app.rotary_scroll_factor = factor;
1667 }
1668 }
1669
1670 pub fn notify_app_paused(&mut self) {
1677 self.app
1678 .app_context
1679 .enter(cranpose_ui::text_input_session::notify_app_paused);
1680 }
1681
1682 pub fn notify_app_resumed(&mut self) -> bool {
1690 self.app
1691 .app_context
1692 .enter(cranpose_ui::text_input_session::notify_app_resumed)
1693 }
1694
1695 #[cfg(all(
1697 feature = "clipboard-native",
1698 target_os = "linux",
1699 not(target_arch = "wasm32")
1700 ))]
1701 pub fn set_primary_selection(&mut self, text: &str) {
1702 use arboard::{LinuxClipboardKind, SetExtLinux};
1703 if let Some(ref mut clipboard) = self.app.clipboard {
1704 let result = clipboard
1705 .set()
1706 .clipboard(LinuxClipboardKind::Primary)
1707 .text(text.to_string());
1708 if let Err(e) = result {
1709 log::debug!("Primary selection set failed: {e:?}");
1710 }
1711 }
1712 }
1713
1714 #[cfg(not(all(
1717 feature = "clipboard-native",
1718 target_os = "linux",
1719 not(target_arch = "wasm32")
1720 )))]
1721 pub fn set_primary_selection(&mut self, _text: &str) {}
1722
1723 #[cfg(all(
1725 feature = "clipboard-native",
1726 target_os = "linux",
1727 not(target_arch = "wasm32")
1728 ))]
1729 pub fn get_primary_selection(&mut self) -> Option<String> {
1730 use arboard::{GetExtLinux, LinuxClipboardKind};
1731 if let Some(ref mut clipboard) = self.app.clipboard {
1732 clipboard
1733 .get()
1734 .clipboard(LinuxClipboardKind::Primary)
1735 .text()
1736 .ok()
1737 } else {
1738 None
1739 }
1740 }
1741
1742 #[cfg(not(all(
1744 feature = "clipboard-native",
1745 target_os = "linux",
1746 not(target_arch = "wasm32")
1747 )))]
1748 pub fn get_primary_selection(&mut self) -> Option<String> {
1749 None
1750 }
1751
1752 pub fn sync_selection_to_primary(&mut self) {
1755 #[cfg(all(target_os = "linux", not(target_arch = "wasm32")))]
1756 {
1757 if let Some(text) = self.on_copy() {
1758 self.set_primary_selection(&text);
1759 }
1760 }
1761 }
1762
1763 pub fn set_pointer_source(&mut self, source: PointerSource) {
1765 self.primary().set_pointer_source(source);
1766 }
1767
1768 pub fn pointer_source(&self) -> PointerSource {
1770 self.surfaces[0].pointer_source
1771 }
1772
1773 pub fn set_cursor(&mut self, x: f32, y: f32) -> bool {
1775 self.primary().set_cursor(x, y)
1776 }
1777
1778 pub fn set_cursor_at_time(&mut self, x: f32, y: f32, time_ms: Option<i64>) -> bool {
1780 self.primary().set_cursor_at_time(x, y, time_ms)
1781 }
1782
1783 pub fn set_cursor_at_event_time(
1785 &mut self,
1786 x: f32,
1787 y: f32,
1788 event_time: PointerEventTime,
1789 ) -> bool {
1790 self.primary().set_cursor_at_event_time(x, y, event_time)
1791 }
1792
1793 pub fn pointer_pressed(&mut self) -> bool {
1795 self.primary().pointer_pressed()
1796 }
1797
1798 pub fn accessibility_activate(&mut self, node_id: NodeId, canvas_key: Option<u64>) -> bool {
1800 self.primary().accessibility_activate(node_id, canvas_key)
1801 }
1802
1803 pub fn pointer_pressed_at_time(&mut self, time_ms: Option<i64>) -> bool {
1805 self.primary().pointer_pressed_at_time(time_ms)
1806 }
1807
1808 pub fn pointer_pressed_at_event_time(&mut self, event_time: PointerEventTime) -> bool {
1810 self.primary().pointer_pressed_at_event_time(event_time)
1811 }
1812
1813 pub fn pointer_released(&mut self) -> bool {
1815 self.primary().pointer_released()
1816 }
1817
1818 pub fn pointer_released_at_position(&mut self, x: f32, y: f32) -> bool {
1820 self.primary().pointer_released_at_position(x, y)
1821 }
1822
1823 pub fn pointer_released_at_position_time(
1826 &mut self,
1827 x: f32,
1828 y: f32,
1829 time_ms: Option<i64>,
1830 ) -> bool {
1831 self.primary()
1832 .pointer_released_at_position_time(x, y, time_ms)
1833 }
1834
1835 pub fn pointer_released_at_position_event_time(
1838 &mut self,
1839 x: f32,
1840 y: f32,
1841 event_time: PointerEventTime,
1842 ) -> bool {
1843 self.primary()
1844 .pointer_released_at_position_event_time(x, y, event_time)
1845 }
1846
1847 pub fn pointer_released_at_time(&mut self, time_ms: Option<i64>) -> bool {
1849 self.primary().pointer_released_at_time(time_ms)
1850 }
1851
1852 pub fn pointer_released_at_event_time(&mut self, event_time: PointerEventTime) -> bool {
1854 self.primary().pointer_released_at_event_time(event_time)
1855 }
1856
1857 pub fn secondary_pointer_pressed(
1859 &mut self,
1860 pointer_id: PointerId,
1861 x: f32,
1862 y: f32,
1863 time_ms: Option<i64>,
1864 ) -> bool {
1865 self.primary()
1866 .secondary_pointer_pressed(pointer_id, x, y, time_ms)
1867 }
1868
1869 pub fn ray_pointer(
1871 &mut self,
1872 (pointer_id, scene): (PointerId, NodeId),
1873 ray: cranpose_ui_graphics::space::Ray,
1874 kind: PointerEventKind,
1875 ) -> bool {
1876 self.primary().ray_pointer((pointer_id, scene), ray, kind)
1877 }
1878
1879 pub fn secondary_pointer_moved(
1881 &mut self,
1882 pointer_id: PointerId,
1883 x: f32,
1884 y: f32,
1885 time_ms: Option<i64>,
1886 ) -> bool {
1887 self.primary()
1888 .secondary_pointer_moved(pointer_id, x, y, time_ms)
1889 }
1890
1891 pub fn secondary_pointer_released(
1893 &mut self,
1894 pointer_id: PointerId,
1895 x: f32,
1896 y: f32,
1897 time_ms: Option<i64>,
1898 ) -> bool {
1899 self.primary()
1900 .secondary_pointer_released(pointer_id, x, y, time_ms)
1901 }
1902
1903 pub fn pointer_zoomed(&mut self, zoom_factor: f32) -> bool {
1905 self.primary().pointer_zoomed(zoom_factor)
1906 }
1907
1908 pub fn wheel_scrolled(&mut self, wheel: WheelScroll) -> bool {
1910 self.primary().wheel_scrolled(wheel)
1911 }
1912
1913 pub fn pointer_scrolled(&mut self, delta_x: f32, delta_y: f32) -> bool {
1915 self.primary().pointer_scrolled(delta_x, delta_y)
1916 }
1917
1918 pub fn set_on_rotary_scroll<F>(&mut self, handler: F)
1920 where
1921 F: Fn(RotaryScrollEvent) -> bool + 'static,
1922 {
1923 self.primary().set_on_rotary_scroll(handler);
1924 }
1925
1926 pub fn clear_on_rotary_scroll(&mut self) {
1928 self.primary().clear_on_rotary_scroll();
1929 }
1930
1931 pub fn rotary_scrolled_by_detents(&mut self, detents: f32, uptime_millis: u64) -> bool {
1933 self.primary()
1934 .rotary_scrolled_by_detents(detents, uptime_millis)
1935 }
1936
1937 pub fn rotary_scrolled(&mut self, event: RotaryScrollEvent) -> bool {
1939 self.primary().rotary_scrolled(event)
1940 }
1941
1942 pub fn cancel_gesture(&mut self) {
1944 self.primary().cancel_gesture();
1945 }
1946
1947 pub fn cancel_gesture_unless_pressed(&mut self) {
1949 self.primary().cancel_gesture_unless_pressed();
1950 }
1951
1952 pub fn refresh_pointer_icon(&self) {
1956 self.surfaces[0].pointer_icon.refresh();
1957 }
1958
1959 pub fn take_pointer_icon_change(&self) -> Option<PointerIcon> {
1966 self.surfaces[0].pointer_icon.take_change()
1967 }
1968
1969 pub fn set_platform_text_input(&mut self, handler: Rc<dyn PlatformTextInputHandler>) {
1976 self.primary().set_platform_text_input(handler);
1977 }
1978
1979 pub fn dismiss_top_modal(&mut self) -> bool {
1981 self.primary().dismiss_top_modal()
1982 }
1983
1984 pub fn move_focus_in_context(&mut self, direction: FocusDirection) -> bool {
1986 self.primary().move_focus_in_context(direction)
1987 }
1988
1989 pub fn on_key_event(&mut self, event: &KeyEvent) -> bool {
1991 self.primary().on_key_event(event)
1992 }
1993
1994 pub fn on_paste(&mut self, text: &str) -> bool {
1996 self.primary().on_paste(text)
1997 }
1998
1999 pub fn on_copy(&mut self) -> Option<String> {
2001 self.primary().on_copy()
2002 }
2003
2004 pub fn on_cut(&mut self) -> Option<String> {
2006 self.primary().on_cut()
2007 }
2008
2009 pub fn on_ime_preedit(&mut self, text: &str, cursor: Option<(usize, usize)>) -> bool {
2011 self.primary().on_ime_preedit(text, cursor)
2012 }
2013
2014 pub fn on_ime_finish_composing(&mut self) -> bool {
2016 self.primary().on_ime_finish_composing()
2017 }
2018
2019 pub fn on_ime_action(&mut self, action: cranpose_ui::ImeAction) -> bool {
2021 self.primary().on_ime_action(action)
2022 }
2023
2024 pub fn on_ime_set_composing_region(&mut self, start_bytes: usize, end_bytes: usize) -> bool {
2026 self.primary()
2027 .on_ime_set_composing_region(start_bytes, end_bytes)
2028 }
2029
2030 pub fn on_ime_set_selection(&mut self, start_bytes: usize, end_bytes: usize) -> bool {
2032 self.primary().on_ime_set_selection(start_bytes, end_bytes)
2033 }
2034
2035 pub fn ime_editor_state(&mut self) -> Option<ImeEditorState> {
2037 self.primary().ime_editor_state()
2038 }
2039
2040 pub fn ime_caret_geometry(
2042 &mut self,
2043 ) -> Option<cranpose_ui::text_field_focus::ImeCaretGeometry> {
2044 self.primary().ime_caret_geometry()
2045 }
2046
2047 pub fn ime_field_bounds(&mut self) -> Option<Rect> {
2049 self.primary().ime_field_bounds()
2050 }
2051
2052 pub fn ime_field_is_password(&mut self) -> bool {
2054 self.primary().ime_field_is_password()
2055 }
2056
2057 pub fn clear_text_field_focus(&mut self) {
2059 self.primary().clear_text_field_focus();
2060 }
2061
2062 pub fn on_ime_delete_surrounding(&mut self, before_bytes: usize, after_bytes: usize) -> bool {
2064 self.primary()
2065 .on_ime_delete_surrounding(before_bytes, after_bytes)
2066 }
2067}