ferroui_controls/calendar/
calendar_day_button.rs1use super::{Calendar, DateTimeHelper};
10use crate::primitives::{TemplateAppliedEventArgs, TemplatedControlImpl};
11use crate::{Button, ButtonImpl, ContentControl, ContentControlImpl, ControlImpl};
12use ferroui_base::input::{
13 InputElementImpl, InputElementImplExt, MouseButton, PointerPressedEventArgs, PointerReleasedEventArgs,
14};
15use ferroui_base::interactivity::InteractiveImpl;
16use ferroui_base::layout::LayoutableImpl;
17use ferroui_base::reactive::{Disposable, IDisposable};
18use ferroui_base::utilities::HandlerList;
19use ferroui_base::{
20 ferro_class, ferro_class_info, ferro_impl_classes, instantiate, BoxedValue, FerroObjectImpl, FerroObjectImplExt,
21 Ref, StyledElementImpl, VisualImpl, WeakRef,
22};
23use std::cell::{Cell, RefCell};
24use std::rc::Rc;
25
26const DEFAULT_CONTENT: i32 = 1;
28
29#[repr(C)]
31pub struct CalendarDayButton {
32 base: Button,
33
34 is_current: Cell<bool>,
35 ignoring_mouse_over_state: Cell<bool>,
36 is_blackout: Cell<bool>,
37 is_today: Cell<bool>,
38 is_inactive: Cell<bool>,
39 is_selected: Cell<bool>,
40
41 owner: RefCell<Option<WeakRef<Calendar>>>,
43 index: Cell<i32>,
44
45 calendar_day_button_mouse_down: HandlerList<dyn Fn(&CalendarDayButton, &PointerPressedEventArgs)>,
46 calendar_day_button_mouse_up: HandlerList<dyn Fn(&CalendarDayButton, &PointerReleasedEventArgs)>,
47}
48
49ferro_class!(CalendarDayButton: Button);
50
51ferro_class_info!(CalendarDayButton {
52 new: CalendarDayButton::new,
53 markup: {
54 attributes: [PseudoClasses(":pressed", ":disabled", ":selected", ":inactive", ":today", ":blackout", ":dayfocused")],
55 },
56});
57
58ferro_impl_classes!(
59 CalendarDayButton: StyledElementImpl,
60 VisualImpl,
61 LayoutableImpl,
62 InteractiveImpl,
63 ContentControlImpl,
64 ButtonImpl
65);
66
67impl FerroObjectImpl for CalendarDayButton {
68 fn constructed(this: &Self) {
69 Self::parent_constructed(this);
70
71 let content: BoxedValue = Rc::new(DateTimeHelper::format_number(DEFAULT_CONTENT));
72 this.set_current_value(ContentControl::content_property(), Some(content));
73 }
74}
75
76impl InputElementImpl for CalendarDayButton {
77 fn on_pointer_pressed(this: &Self, e: &PointerPressedEventArgs) {
86 Self::parent_on_pointer_pressed(this, e);
87
88 if e.get_current_point(Some(this)).properties.is_left_button_pressed {
89 for (_, handler) in this.calendar_day_button_mouse_down.snapshot().iter() {
90 handler(this, e);
91 }
92 }
93 }
94
95 fn on_pointer_released(this: &Self, e: &PointerReleasedEventArgs) {
104 Self::parent_on_pointer_released(this, e);
105
106 if e.initial_press_mouse_button() == MouseButton::Left {
107 for (_, handler) in this.calendar_day_button_mouse_up.snapshot().iter() {
108 handler(this, e);
109 }
110 }
111 }
112}
113
114impl TemplatedControlImpl for CalendarDayButton {
115 fn on_apply_template(this: &Self, _e: &TemplateAppliedEventArgs) {
118 this.set_pseudo_classes();
119 }
120}
121
122impl ControlImpl for CalendarDayButton {
123 fn on_create_automation_peer(this: &Self) -> Ref<crate::automation::peers::AutomationPeer> {
124 crate::automation::peers::CalendarDayButtonAutomationPeer::new(this).upcast()
125 }
126}
127
128impl CalendarDayButton {
129 pub fn construct() -> Self {
131 Self {
132 base: Button::construct(),
133 is_current: Cell::new(false),
134 ignoring_mouse_over_state: Cell::new(false),
135 is_blackout: Cell::new(false),
136 is_today: Cell::new(false),
137 is_inactive: Cell::new(false),
138 is_selected: Cell::new(false),
139 owner: RefCell::new(None),
140 index: Cell::new(0),
141 calendar_day_button_mouse_down: HandlerList::new(),
142 calendar_day_button_mouse_up: HandlerList::new(),
143 }
144 }
145
146 pub fn new() -> Ref<Self> {
148 instantiate(Self::construct())
149 }
150
151 pub(crate) fn owner(&self) -> Option<Ref<Calendar>> {
153 self.owner.borrow().as_ref().and_then(WeakRef::upgrade)
154 }
155
156 pub(crate) fn set_owner(&self, value: Option<&Ref<Calendar>>) {
158 *self.owner.borrow_mut() = value.map(Ref::downgrade);
159 }
160
161 pub(crate) fn index(&self) -> i32 {
163 self.index.get()
164 }
165
166 pub(crate) fn set_index(&self, value: i32) {
167 self.index.set(value);
168 }
169
170 pub(crate) fn is_current(&self) -> bool {
173 self.is_current.get()
174 }
175
176 pub(crate) fn set_is_current(&self, value: bool) {
179 if self.is_current.get() != value {
180 self.is_current.set(value);
181 self.set_pseudo_classes();
182 }
183 }
184
185 pub(crate) fn ignore_mouse_over_state(&self) {
193 self.ignoring_mouse_over_state.set(false);
198
199 if self.is_pointer_over() {
203 self.ignoring_mouse_over_state.set(true);
204 self.set_pseudo_classes();
205 }
206 }
207
208 pub(crate) fn is_blackout(&self) -> bool {
210 self.is_blackout.get()
211 }
212
213 pub(crate) fn set_is_blackout(&self, value: bool) {
215 if self.is_blackout.get() != value {
216 self.is_blackout.set(value);
217 self.set_pseudo_classes();
218 }
219 }
220
221 pub(crate) fn is_today(&self) -> bool {
223 self.is_today.get()
224 }
225
226 pub(crate) fn set_is_today(&self, value: bool) {
228 if self.is_today.get() != value {
229 self.is_today.set(value);
230 self.set_pseudo_classes();
231 }
232 }
233
234 pub(crate) fn is_inactive(&self) -> bool {
236 self.is_inactive.get()
237 }
238
239 pub(crate) fn set_is_inactive(&self, value: bool) {
241 if self.is_inactive.get() != value {
242 self.is_inactive.set(value);
243 self.set_pseudo_classes();
244 }
245 }
246
247 pub(crate) fn is_selected(&self) -> bool {
249 self.is_selected.get()
250 }
251
252 pub(crate) fn set_is_selected(&self, value: bool) {
254 if self.is_selected.get() != value {
255 self.is_selected.set(value);
256 self.set_pseudo_classes();
257 }
258 }
259
260 fn set_pseudo_classes(&self) {
261 if self.ignoring_mouse_over_state.get() {
262 self.pseudo_classes().set(":pressed", self.is_pressed());
263 self.pseudo_classes().set(":disabled", !self.is_enabled());
264 }
265
266 self.pseudo_classes().set(":selected", self.is_selected());
267 self.pseudo_classes().set(":inactive", self.is_inactive());
268 self.pseudo_classes().set(":today", self.is_today());
269 self.pseudo_classes().set(":blackout", self.is_blackout());
270 self.pseudo_classes().set(":dayfocused", self.is_current() && self.is_enabled());
271 }
272
273 pub fn calendar_day_button_mouse_down(
277 &self,
278 handler: impl Fn(&CalendarDayButton, &PointerPressedEventArgs) + 'static,
279 ) -> Rc<dyn IDisposable> {
280 let token = self.calendar_day_button_mouse_down.add(Rc::new(handler));
281 let weak = self.to_ref().downgrade();
282 Disposable::create(move || {
283 if let Some(this) = weak.upgrade() {
284 this.calendar_day_button_mouse_down.remove(token);
285 }
286 })
287 }
288
289 pub fn calendar_day_button_mouse_up(
294 &self,
295 handler: impl Fn(&CalendarDayButton, &PointerReleasedEventArgs) + 'static,
296 ) -> Rc<dyn IDisposable> {
297 let token = self.calendar_day_button_mouse_up.add(Rc::new(handler));
298 let weak = self.to_ref().downgrade();
299 Disposable::create(move || {
300 if let Some(this) = weak.upgrade() {
301 this.calendar_day_button_mouse_up.remove(token);
302 }
303 })
304 }
305}