ferroui_xaml_interactions_custom/writeable_bitmap/
writeable_bitmap_timer_trigger.rs1use crate::WriteableBitmapRef;
4use ferroui_base::reactive::IDisposable;
5use ferroui_base::threading::DispatcherTimer;
6use ferroui_base::{
7 ferro_class, ferro_class_info, ferro_properties, instantiate, BoxedValue, FerroObjectImpl, FerroProperty, Ref,
8 StyledElementImpl, StyledProperty,
9};
10use ferroui_xaml_interactivity::{
11 Interaction, StyledElementBehaviorImpl, StyledElementBehaviorImplExt, StyledElementTrigger,
12};
13use std::cell::RefCell;
14use std::rc::Rc;
15use std::time::Duration;
16
17#[repr(C)]
20pub struct WriteableBitmapTimerTrigger {
21 base: StyledElementTrigger,
22 timer: RefCell<Option<(Rc<DispatcherTimer>, Rc<dyn IDisposable>)>>,
23}
24
25ferro_class!(WriteableBitmapTimerTrigger: StyledElementTrigger);
26ferro_class_info!(WriteableBitmapTimerTrigger {
27 new: WriteableBitmapTimerTrigger::new,
28 markup: {
29 property_attributes: [
30 Bitmap: [ResolveByName],
31 ],
32 },
33});
34ferroui_base::ferro_impl_classes!(WriteableBitmapTimerTrigger: FerroObjectImpl, StyledElementImpl);
35
36ferro_properties! {
37 impl WriteableBitmapTimerTrigger {
38 pub fn bitmap_property() -> StyledProperty<Option<WriteableBitmapRef>> {
40 FerroProperty::register::<WriteableBitmapTimerTrigger, _>("Bitmap", None)
41 }
42
43 pub fn milliseconds_per_tick_property() -> StyledProperty<i32> {
45 FerroProperty::register::<WriteableBitmapTimerTrigger, _>("MillisecondsPerTick", 16)
46 }
47 }
48}
49
50ferroui_base::ferro_overrides! {
51 impl StyledElementBehaviorImpl for WriteableBitmapTimerTrigger {
52 fn on_attached(this: &Self) {
53 Self::parent_on_attached(this);
54
55 this.start_timer();
56 }
57
58 fn on_detaching(this: &Self) {
59 this.stop_timer();
60
61 Self::parent_on_detaching(this);
62 }
63 }
64}
65
66impl WriteableBitmapTimerTrigger {
67 pub fn construct() -> Self {
69 Self { base: StyledElementTrigger::construct(), timer: RefCell::new(None) }
70 }
71
72 pub fn new() -> Ref<Self> {
74 instantiate(Self::construct())
75 }
76
77 pub fn bitmap(&self) -> Option<WriteableBitmapRef> {
79 self.get_value(Self::bitmap_property())
80 }
81
82 pub fn set_bitmap(&self, value: Option<WriteableBitmapRef>) {
83 self.set_value(Self::bitmap_property(), value)
84 }
85
86 pub fn milliseconds_per_tick(&self) -> i32 {
88 self.get_value(Self::milliseconds_per_tick_property())
89 }
90
91 pub fn set_milliseconds_per_tick(&self, value: i32) {
92 self.set_value(Self::milliseconds_per_tick_property(), value)
93 }
94
95 fn start_timer(&self) {
96 if self.timer.borrow().is_some() {
97 return;
98 }
99
100 let timer = DispatcherTimer::new();
101 timer.set_interval(Duration::from_millis(self.milliseconds_per_tick().max(0) as u64));
102 let trigger = self.to_ref().downgrade();
103 let tick = timer.tick(move |_timer: &DispatcherTimer| {
104 if let Some(trigger) = trigger.upgrade() {
105 trigger.on_tick();
106 }
107 });
108 timer.start();
109 *self.timer.borrow_mut() = Some((timer, tick));
110 }
111
112 fn stop_timer(&self) {
113 let timer = self.timer.borrow_mut().take();
114 if let Some((timer, tick)) = timer {
115 tick.dispose();
116 timer.stop();
117 }
118 }
119
120 fn on_tick(&self) {
121 if !self.is_enabled() {
122 return;
123 }
124
125 let sender = self.associated_object().map(|associated_object| Rc::new(associated_object) as BoxedValue);
126 let parameter = self.bitmap().map(|bitmap| Rc::new(bitmap) as BoxedValue);
127 Interaction::execute_actions(sender.as_ref(), self.actions().as_ref(), parameter.as_ref());
128 }
129}