ferroui_controls/
spinner.rs1use crate::primitives::TemplatedControlImpl;
2use crate::{ContentControl, ContentControlImpl, ControlImpl};
3use bitflags::bitflags;
4use ferroui_base::input::InputElementImpl;
5use ferroui_base::interactivity::{
6 Interactive, InteractiveImpl, RoutedEvent, RoutedEventArgs, RoutedEventHandlerToken, RoutingStrategies,
7};
8use ferroui_base::layout::LayoutableImpl;
9use ferroui_base::{
10 ferro_class, ferro_impl_classes, ferro_property, ferro_routed_event, ferro_routed_event_args, FerroObjectImpl, FerroProperty, StyledElementImpl, StyledProperty, VisualImpl,
11};
12
13bitflags! {
14 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
16 pub struct ValidSpinDirections: i32 {
17 const NONE = 0;
19
20 const INCREASE = 1;
22
23 const DECREASE = 2;
25 }
26}
27
28#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
30#[repr(i32)]
31pub enum SpinDirection {
32 #[default]
35 Increase = 0,
36
37 Decrease = 1,
40}
41
42#[derive(Clone)]
44pub struct SpinEventArgs {
45 base: RoutedEventArgs,
46 direction: SpinDirection,
47 using_mouse_wheel: bool,
48}
49
50ferro_routed_event_args!(SpinEventArgs: RoutedEventArgs);
51
52impl SpinEventArgs {
53 pub fn new(direction: SpinDirection) -> Self {
55 Self { base: RoutedEventArgs::new(), direction, using_mouse_wheel: false }
56 }
57
58 pub fn with_event<T: ?Sized>(routed_event: Option<&RoutedEvent<T>>, direction: SpinDirection) -> Self {
60 Self::with_event_and_mouse_wheel(routed_event, direction, false)
61 }
62
63 pub fn with_mouse_wheel(direction: SpinDirection, using_mouse_wheel: bool) -> Self {
66 Self { base: RoutedEventArgs::new(), direction, using_mouse_wheel }
67 }
68
69 pub fn with_event_and_mouse_wheel<T: ?Sized>(
72 routed_event: Option<&RoutedEvent<T>>,
73 direction: SpinDirection,
74 using_mouse_wheel: bool,
75 ) -> Self {
76 let base = RoutedEventArgs::new();
77 base.set_routed_event(routed_event);
78 Self { base, direction, using_mouse_wheel }
79 }
80
81 #[inline]
83 pub fn direction(&self) -> SpinDirection {
84 self.direction
85 }
86
87 #[inline]
89 pub fn using_mouse_wheel(&self) -> bool {
90 self.using_mouse_wheel
91 }
92}
93
94#[repr(C)]
98pub struct Spinner {
99 base: ContentControl,
100}
101
102ferro_class! {
103 Spinner: ContentControl, virtuals SpinnerImpl: ContentControlImpl {
104 fn on_valid_spin_direction_changed(this, old_value: ValidSpinDirections, new_value: ValidSpinDirections);
106 fn on_spin(this, e: &SpinEventArgs);
109 }
110}
111
112ferro_impl_classes!(
113 Spinner: StyledElementImpl,
114 VisualImpl,
115 LayoutableImpl,
116 InteractiveImpl,
117 InputElementImpl,
118 ControlImpl,
119 TemplatedControlImpl,
120 ContentControlImpl
121);
122
123ferroui_base::ferro_impl_classes!(Spinner: FerroObjectImpl);
124
125impl SpinnerImpl for Spinner {
126 fn on_valid_spin_direction_changed(_this: &Self, _old_value: ValidSpinDirections, _new_value: ValidSpinDirections) {}
127
128 fn on_spin(this: &Self, e: &SpinEventArgs) {
129 let valid = if e.direction() == SpinDirection::Increase {
130 ValidSpinDirections::INCREASE
131 } else {
132 ValidSpinDirections::DECREASE
133 };
134
135 if this.valid_spin_direction() & valid == valid {
137 this.raise_event(e);
138 }
139 }
140}
141
142ferroui_base::ferro_properties! { impl Spinner {
143 ferro_property!(
144 pub fn valid_spin_direction_property() -> StyledProperty<ValidSpinDirections> {
146 FerroProperty::register::<Spinner, _>(
147 "ValidSpinDirection",
148 ValidSpinDirections::INCREASE | ValidSpinDirections::DECREASE,
149 )
150 }
151 );
152} }
153
154impl Spinner {
155 ferro_routed_event!(
156 pub fn spin_event() -> RoutedEvent<SpinEventArgs> {
158 RoutedEvent::register::<Spinner, _>("Spin", RoutingStrategies::BUBBLE)
159 }
160 );
161
162 fn static_constructor() {
163 Self::valid_spin_direction_property().changed().add_class_handler::<Spinner>(|spinner, e| {
164 let (old_value, new_value) = e.get_old_and_new_value::<ValidSpinDirections>();
165 spinner.on_valid_spin_direction_changed(old_value, new_value);
166 });
167 }
168
169 pub fn construct() -> Self {
171 Self { base: ContentControl::construct() }
172 }
173
174 pub fn spin(&self, handler: impl Fn(&Interactive, &SpinEventArgs) + 'static) -> RoutedEventHandlerToken {
176 self.add_handler(Self::spin_event(), handler)
177 }
178
179 pub fn valid_spin_direction(&self) -> ValidSpinDirections {
181 self.get_value(Self::valid_spin_direction_property())
182 }
183
184 pub fn set_valid_spin_direction(&self, value: ValidSpinDirections) {
185 self.set_value(Self::valid_spin_direction_property(), value)
186 }
187}