ferroui_xaml_interactions_custom/control/
delayed_load_behavior.rs1use crate::{AttachedToVisualTreeBehavior, AttachedToVisualTreeBehaviorImpl};
4use ferroui_base::animation::TimeSpan;
5use ferroui_base::reactive::IDisposable;
6use ferroui_base::threading::DispatcherTimer;
7use ferroui_base::{
8 ferro_class, ferro_class_info, ferro_properties, instantiate, FerroObjectImpl, FerroProperty, Ref, StaticType,
9 StyledElementImpl, StyledProperty, Visual,
10};
11use ferroui_controls::Control;
12use ferroui_xaml_interactivity::{DisposableAction, DisposingBehaviorImpl, StyledElementBehaviorImpl};
13use std::cell::RefCell;
14use std::rc::Rc;
15
16#[repr(C)]
19pub struct DelayedLoadBehavior {
20 base: AttachedToVisualTreeBehavior,
21 timer: RefCell<Option<(Rc<DispatcherTimer>, Rc<dyn IDisposable>)>>,
23}
24
25ferro_class!(DelayedLoadBehavior: AttachedToVisualTreeBehavior);
26ferro_class_info!(DelayedLoadBehavior { new: DelayedLoadBehavior::new });
27ferroui_base::ferro_impl_classes!(
28 DelayedLoadBehavior: FerroObjectImpl,
29 StyledElementImpl,
30 StyledElementBehaviorImpl,
31 DisposingBehaviorImpl,
32);
33
34ferro_properties! {
35 impl DelayedLoadBehavior {
36 pub fn delay_property() -> StyledProperty<TimeSpan> {
38 FerroProperty::register::<DelayedLoadBehavior, _>("Delay", TimeSpan::from_milliseconds(500.0))
39 }
40 }
41}
42
43ferroui_base::ferro_overrides! {
44 impl AttachedToVisualTreeBehaviorImpl for DelayedLoadBehavior {
45 fn on_attached_to_visual_tree_override(this: &Self) -> Rc<dyn IDisposable> {
46 let Some(associated_object) = this.associated_object_as::<Control>() else {
47 return DisposableAction::empty();
48 };
49
50 associated_object.set_is_visible(false);
51
52 let timer = DispatcherTimer::new();
53 timer.set_interval(this.delay().to_duration().unwrap_or_default());
54 let behavior = this.to_ref().downgrade();
55 let tick = timer.tick(move |_timer: &DispatcherTimer| {
56 if let Some(behavior) = behavior.upgrade() {
57 behavior.on_tick();
58 }
59 });
60 timer.start();
61
62 *this.timer.borrow_mut() = Some((timer, tick));
64
65 let behavior = this.to_ref().downgrade();
66 DisposableAction::create(move || {
67 if let Some(behavior) = behavior.upgrade() {
68 behavior.dispose_timer();
69 }
70 })
71 }
72 }
73}
74
75impl DelayedLoadBehavior {
76 pub fn construct() -> Self {
78 Self { base: AttachedToVisualTreeBehavior::construct(<Control as StaticType>::TYPE), timer: RefCell::new(None) }
79 }
80
81 pub fn new() -> Ref<Self> {
83 instantiate(Self::construct())
84 }
85
86 pub fn delay(&self) -> TimeSpan {
89 self.get_value(Self::delay_property())
90 }
91
92 pub fn set_delay(&self, value: TimeSpan) {
93 self.set_value(Self::delay_property(), value)
94 }
95
96 fn on_tick(&self) {
97 if let Some(associated_object) = self.associated_object_as::<Control>() {
98 associated_object.set_current_value(Visual::is_visible_property(), true);
99 }
100 self.dispose_timer();
101 }
102
103 fn dispose_timer(&self) {
104 let timer = self.timer.borrow_mut().take();
105 if let Some((timer, tick)) = timer {
106 tick.dispose();
107 timer.stop();
108 }
109 }
110}