ferroui_controls/
repeat_button.rs1use crate::primitives::TemplatedControlImpl;
2use crate::{Button, ButtonImpl, ContentControlImpl, ControlImpl};
3use ferroui_base::input::{
4 InputElementImpl, InputElementImplExt, Key, KeyEventArgs, MouseButton, PointerPressedEventArgs,
5 PointerReleasedEventArgs,
6};
7use ferroui_base::interactivity::InteractiveImpl;
8use ferroui_base::layout::LayoutableImpl;
9use ferroui_base::threading::DispatcherTimer;
10use ferroui_base::{
11 ferro_class, ferro_impl_classes, ferro_property, instantiate, FerroObjectImpl, FerroObjectImplExt,
12 FerroProperty, FerroPropertyChangedEventArgs, Ref, StyledElementImpl, StyledProperty, VisualImpl,
13};
14use std::cell::RefCell;
15use std::rc::Rc;
16use std::time::Duration;
17
18#[repr(C)]
21pub struct RepeatButton {
22 base: Button,
23 repeat_timer: RefCell<Option<Rc<DispatcherTimer>>>,
24}
25
26ferro_class!(RepeatButton: Button);
27ferroui_base::ferro_class_info!(RepeatButton { new: RepeatButton::new });
28ferro_impl_classes!(
29 RepeatButton: StyledElementImpl,
30 VisualImpl,
31 LayoutableImpl,
32 InteractiveImpl,
33 ControlImpl,
34 TemplatedControlImpl,
35 ContentControlImpl,
36 ButtonImpl
37);
38
39impl FerroObjectImpl for RepeatButton {
40 fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
41 Self::parent_on_property_changed(this, change);
42
43 if change.property() == Button::is_pressed_property().as_property() && !change.get_new_value::<bool>() {
44 this.stop_timer();
45 }
46 }
47}
48
49impl InputElementImpl for RepeatButton {
50 fn on_key_down(this: &Self, e: &KeyEventArgs) {
51 Self::parent_on_key_down(this, e);
52
53 if e.key == Key::Space {
54 this.start_timer();
55 }
56 }
57
58 fn on_key_up(this: &Self, e: &KeyEventArgs) {
59 Self::parent_on_key_up(this, e);
60
61 this.stop_timer();
62 }
63
64 fn on_pointer_pressed(this: &Self, e: &PointerPressedEventArgs) {
65 Self::parent_on_pointer_pressed(this, e);
66
67 if e.get_current_point(Some(this)).properties.is_left_button_pressed {
68 this.start_timer();
69 }
70 }
71
72 fn on_pointer_released(this: &Self, e: &PointerReleasedEventArgs) {
73 Self::parent_on_pointer_released(this, e);
74
75 if e.initial_press_mouse_button() == MouseButton::Left {
76 this.stop_timer();
77 }
78 }
79}
80
81ferroui_base::ferro_properties! { impl RepeatButton {
82 ferro_property!(
83 pub fn interval_property() -> StyledProperty<i32> {
85 FerroProperty::register::<RepeatButton, _>("Interval", 100)
86 }
87 );
88
89 ferro_property!(
90 pub fn delay_property() -> StyledProperty<i32> {
92 FerroProperty::register::<RepeatButton, _>("Delay", 300)
93 }
94 );
95} }
96
97impl RepeatButton {
98 pub fn construct() -> Self {
100 Self { base: Button::construct(), repeat_timer: RefCell::new(None) }
101 }
102
103 pub fn new() -> Ref<Self> {
105 instantiate(Self::construct())
106 }
107
108 pub fn interval(&self) -> i32 {
110 self.get_value(Self::interval_property())
111 }
112
113 pub fn set_interval(&self, value: i32) {
114 self.set_value(Self::interval_property(), value)
115 }
116
117 pub fn delay(&self) -> i32 {
119 self.get_value(Self::delay_property())
120 }
121
122 pub fn set_delay(&self, value: i32) {
123 self.set_value(Self::delay_property(), value)
124 }
125
126 fn from_milliseconds(milliseconds: i32) -> Duration {
129 Duration::from_millis(u64::try_from(milliseconds).unwrap_or(0))
130 }
131
132 fn start_timer(&self) {
133 let existing = self.repeat_timer.borrow().clone();
134 let repeat_timer = match existing {
135 Some(repeat_timer) => repeat_timer,
136 None => {
137 let repeat_timer = DispatcherTimer::new();
138 let weak = self.to_ref().downgrade();
139 let _ = repeat_timer.tick(move |_| {
141 if let Some(this) = weak.upgrade() {
142 this.repeat_timer_on_tick();
143 }
144 });
145 *self.repeat_timer.borrow_mut() = Some(repeat_timer.clone());
146 repeat_timer
147 }
148 };
149
150 if repeat_timer.is_enabled() {
151 return;
152 }
153
154 repeat_timer.set_interval(Self::from_milliseconds(self.delay()));
155 repeat_timer.start();
156 }
157
158 fn repeat_timer_on_tick(&self) {
159 let interval = Self::from_milliseconds(self.interval());
160 let repeat_timer = self.repeat_timer.borrow().clone();
161 if let Some(repeat_timer) = repeat_timer {
162 if repeat_timer.interval() != interval {
163 repeat_timer.set_interval(interval);
164 }
165 }
166 self.on_click();
167 }
168
169 fn stop_timer(&self) {
170 let repeat_timer = self.repeat_timer.borrow().clone();
171 if let Some(repeat_timer) = repeat_timer {
172 repeat_timer.stop();
173 }
174 }
175}
176
177impl Drop for RepeatButton {
179 fn drop(&mut self) {
180 if let Some(repeat_timer) = self.repeat_timer.get_mut().take() {
181 repeat_timer.stop();
182 }
183 }
184}