ferroui_xaml_interactions_custom/carousel/
carousel_key_navigation_behavior.rs1use ferroui_base::input::{InputElement, Key, KeyEventArgs};
4use ferroui_base::interactivity::{Interactive, RoutedEventHandlerToken, RoutingStrategies};
5use ferroui_base::layout::Orientation;
6use ferroui_base::{
7 ferro_class, ferro_class_info, ferro_properties, instantiate, FerroObjectImpl, FerroProperty, Ref, StaticType,
8 StyledElementImpl, StyledProperty,
9};
10use ferroui_controls::Carousel;
11use ferroui_xaml_interactivity::{StyledElementBehaviorImpl, StyledElementBehaviorImplExt, StyledElementBehaviorOfT};
12use std::cell::Cell;
13
14#[repr(C)]
16pub struct CarouselKeyNavigationBehavior {
17 base: StyledElementBehaviorOfT,
18 key_down_handler: Cell<Option<RoutedEventHandlerToken>>,
20}
21
22ferro_class!(CarouselKeyNavigationBehavior: StyledElementBehaviorOfT);
23ferro_class_info!(CarouselKeyNavigationBehavior { new: CarouselKeyNavigationBehavior::new });
24ferroui_base::ferro_impl_classes!(CarouselKeyNavigationBehavior: FerroObjectImpl, StyledElementImpl);
25
26ferro_properties! {
27 impl CarouselKeyNavigationBehavior {
28 pub fn orientation_property() -> StyledProperty<Orientation> {
30 FerroProperty::register::<CarouselKeyNavigationBehavior, _>("Orientation", Orientation::Horizontal)
31 }
32 }
33}
34
35ferroui_base::ferro_overrides! {
36 impl StyledElementBehaviorImpl for CarouselKeyNavigationBehavior {
37 fn on_attached(this: &Self) {
38 Self::parent_on_attached(this);
39
40 if let Some(associated_object) = this.associated_object_as::<Carousel>() {
41 let behavior = this.to_ref().downgrade();
42 let token = associated_object.add_handler_with(
43 InputElement::key_down_event(),
44 move |_sender: &Interactive, e: &KeyEventArgs| {
45 if let Some(behavior) = behavior.upgrade() {
46 behavior.on_key_down(e);
47 }
48 },
49 RoutingStrategies::TUNNEL,
50 false,
51 );
52 this.key_down_handler.set(Some(token));
53 }
54 }
55
56 fn on_detaching(this: &Self) {
57 if let Some(token) = this.key_down_handler.take() {
58 if let Some(associated_object) = this.associated_object_as::<Carousel>() {
59 associated_object.remove_handler(InputElement::key_down_event(), token);
60 }
61 }
62
63 Self::parent_on_detaching(this);
64 }
65 }
66}
67
68impl CarouselKeyNavigationBehavior {
69 pub fn construct() -> Self {
71 Self { base: StyledElementBehaviorOfT::construct(<Carousel as StaticType>::TYPE), key_down_handler: Cell::new(None) }
72 }
73
74 pub fn new() -> Ref<Self> {
76 instantiate(Self::construct())
77 }
78
79 pub fn orientation(&self) -> Orientation {
81 self.get_value(Self::orientation_property())
82 }
83
84 pub fn set_orientation(&self, value: Orientation) {
85 self.set_value(Self::orientation_property(), value)
86 }
87
88 fn on_key_down(&self, e: &KeyEventArgs) {
89 if !self.is_enabled() {
90 return;
91 }
92 let Some(associated_object) = self.associated_object_as::<Carousel>() else {
93 return;
94 };
95
96 let (next_key, previous_key) = match self.orientation() {
97 Orientation::Horizontal => (Key::Right, Key::Left),
98 Orientation::Vertical => (Key::Down, Key::Up),
99 };
100
101 if e.key == next_key {
102 associated_object.next();
103 e.set_handled(true);
104 } else if e.key == previous_key {
105 associated_object.previous();
106 e.set_handled(true);
107 }
108 }
109}