Skip to main content

ferroui_controls/calendar/
calendar_item.rs

1// (c) Copyright Microsoft Corporation.
2// This source is subject to the Microsoft Public License (Ms-PL).
3// Please see https://go.microsoft.com/fwlink/?LinkID=131993 for details.
4// All other rights reserved.
5//
6// Ported from the Silverlight Toolkit sources as adapted by the upstream
7// project; the license text is in the `NOTICE.md` of this crate.
8
9use super::{
10    Calendar, CalendarButton, CalendarDayButton, CalendarExtensions, CalendarMode, CalendarSelectionMode,
11    DateTimeHelper,
12};
13use crate::primitives::{TemplateAppliedEventArgs, TemplatedControl, TemplatedControlImpl};
14use crate::templates::ITemplateOf;
15use crate::{Button, ContentControl, Control, ControlImpl, Grid};
16use ferroui_base::data::BindingMode;
17use ferroui_base::input::{InputElement, InputElementImpl, PointerPressedEventArgs, PointerReleasedEventArgs};
18use ferroui_base::interactivity::{InteractiveImpl, RoutedEventHandlerToken};
19use ferroui_base::layout::LayoutableImpl;
20use ferroui_base::media::IBrush;
21use ferroui_base::utilities::{DateTime, DayOfWeek, GregorianCalendar};
22use ferroui_base::{
23    ferro_class, ferro_class_info, ferro_impl_classes, ferro_properties, instantiate, BoxedValue, FerroObject,
24    FerroObjectImpl, FerroProperty, Ref, StyledElementImpl, StyledProperty, StyledPropertyOptions, VisualImpl,
25    VisualImplExt, VisualTreeAttachmentEventArgs, WeakRef,
26};
27use std::cell::{Cell, RefCell};
28use std::rc::Rc;
29
30/// The number of days per week.
31const NUMBER_OF_DAYS_PER_WEEK: i32 = 7;
32
33const PART_ELEMENT_HEADER_BUTTON: &str = "PART_HeaderButton";
34const PART_ELEMENT_PREVIOUS_BUTTON: &str = "PART_PreviousButton";
35const PART_ELEMENT_NEXT_BUTTON: &str = "PART_NextButton";
36const PART_ELEMENT_MONTH_VIEW: &str = "PART_MonthView";
37const PART_ELEMENT_YEAR_VIEW: &str = "PART_YearView";
38const PART_ELEMENT_WEEK_NUMBER_LABELS: &str = "PART_ElementWeekNumberLabels";
39
40/// A button part and the handler attached to its click event.
41type ButtonPart = (Ref<Button>, RoutedEventHandlerToken);
42
43fn boxed_text(text: impl Into<String>) -> Option<BoxedValue> {
44    Some(Rc::new(text.into()) as BoxedValue)
45}
46
47fn boxed_date(date: DateTime) -> Option<BoxedValue> {
48    Some(Rc::new(date) as BoxedValue)
49}
50
51/// The date a control has as its data context, if it has one.
52pub(crate) fn date_of(control: &Control) -> Option<DateTime> {
53    let data_context = control.data_context()?;
54    data_context
55        .downcast_ref::<DateTime>()
56        .copied()
57        .or_else(|| data_context.downcast_ref::<Option<DateTime>>().copied().flatten())
58}
59
60/// Represents the currently displayed month or year on a [`Calendar`].
61#[repr(C)]
62pub struct CalendarItem {
63    base: TemplatedControl,
64
65    header_button: RefCell<Option<ButtonPart>>,
66    next_button: RefCell<Option<ButtonPart>>,
67    previous_button: RefCell<Option<ButtonPart>>,
68
69    current_month: Cell<DateTime>,
70    is_mouse_left_button_down: Cell<bool>,
71    is_mouse_left_button_down_year_view: Cell<bool>,
72    is_control_pressed: Cell<bool>,
73
74    calendar: GregorianCalendar,
75
76    owner: RefCell<Option<WeakRef<Calendar>>>,
77
78    /// The Grid that hosts the content when in month mode.
79    month_view: RefCell<Option<Ref<Grid>>>,
80    /// The Grid that hosts the content when in year or decade mode.
81    year_view: RefCell<Option<Ref<Grid>>>,
82    /// The Grid that hosts the week number labels when in month mode.
83    week_number_labels: RefCell<Option<Ref<Grid>>>,
84}
85
86ferro_class!(CalendarItem: TemplatedControl);
87
88ferro_class_info!(CalendarItem {
89    new: CalendarItem::new,
90    markup: {
91        attributes: [
92            TemplatePart("PART_HeaderButton", type(Ref<Button>)),
93            TemplatePart("PART_MonthView", type(Ref<Grid>)),
94            TemplatePart("PART_NextButton", type(Ref<Button>)),
95            TemplatePart("PART_PreviousButton", type(Ref<Button>)),
96            TemplatePart("PART_YearView", type(Ref<Grid>)),
97            TemplatePart("PART_ElementWeekNumberLabels", type(Ref<Grid>)),
98            PseudoClasses(":calendardisabled", ":hasweeknumbers"),
99        ],
100    },
101});
102
103ferro_impl_classes!(
104    CalendarItem: FerroObjectImpl,
105    StyledElementImpl,
106    LayoutableImpl,
107    InteractiveImpl,
108    InputElementImpl,
109    ControlImpl
110);
111
112impl VisualImpl for CalendarItem {
113    fn on_detached_from_visual_tree(this: &Self, e: &VisualTreeAttachmentEventArgs) {
114        Self::parent_on_detached_from_visual_tree(this, e);
115
116        // Reset mouse button tracking state. When the calendar popup closes
117        // (e.g. due to a programmatic window change during date selection),
118        // the pointer released event never fires, leaving these flags
119        // stuck.
120        this.is_mouse_left_button_down.set(false);
121        this.is_mouse_left_button_down_year_view.set(false);
122    }
123}
124
125impl TemplatedControlImpl for CalendarItem {
126    /// Builds the visual tree for the [`CalendarItem`] when a new template
127    /// is applied.
128    fn on_apply_template(this: &Self, e: &TemplateAppliedEventArgs) {
129        this.set_header_button(e.name_scope().find_as::<Button>(PART_ELEMENT_HEADER_BUTTON));
130        this.set_previous_button(e.name_scope().find_as::<Button>(PART_ELEMENT_PREVIOUS_BUTTON));
131        this.set_next_button(e.name_scope().find_as::<Button>(PART_ELEMENT_NEXT_BUTTON));
132        *this.month_view.borrow_mut() = e.name_scope().find_as::<Grid>(PART_ELEMENT_MONTH_VIEW);
133        *this.year_view.borrow_mut() = e.name_scope().find_as::<Grid>(PART_ELEMENT_YEAR_VIEW);
134        *this.week_number_labels.borrow_mut() = e.name_scope().find_as::<Grid>(PART_ELEMENT_WEEK_NUMBER_LABELS);
135
136        let owner = this.owner();
137
138        if let Some(owner) = &owner {
139            this.update_disabled(owner.is_enabled());
140        }
141
142        this.populate_grids();
143
144        if let (Some(month_view), Some(year_view)) = (this.month_view(), this.year_view()) {
145            if let Some(owner) = &owner {
146                owner.set_selected_month(owner.display_date_internal());
147                owner.set_selected_year(owner.display_date_internal());
148
149                if owner.display_mode() == CalendarMode::Year {
150                    this.update_year_mode();
151                } else if owner.display_mode() == CalendarMode::Decade {
152                    this.update_decade_mode();
153                }
154
155                if owner.display_mode() == CalendarMode::Month {
156                    this.update_month_mode();
157                    month_view.set_is_visible(true);
158                    year_view.set_is_visible(false);
159                } else {
160                    year_view.set_is_visible(true);
161                    month_view.set_is_visible(false);
162                }
163            } else {
164                this.update_month_mode();
165                month_view.set_is_visible(true);
166                year_view.set_is_visible(false);
167            }
168        }
169    }
170}
171
172ferro_properties! {
173    impl CalendarItem {
174        /// Defines the `HeaderBackground` property.
175        pub fn header_background_property() -> StyledProperty<Option<Rc<dyn IBrush>>> {
176            Calendar::header_background_property().add_owner::<CalendarItem>()
177        }
178
179        /// Defines the `DayTitleTemplate` property.
180        pub fn day_title_template_property() -> StyledProperty<Option<Rc<dyn ITemplateOf<Option<Ref<Control>>>>>> {
181            FerroProperty::register_with::<CalendarItem, _>(
182                "DayTitleTemplate",
183                StyledPropertyOptions::new(None).default_binding_mode(BindingMode::OneTime),
184            )
185        }
186    }
187}
188
189impl CalendarItem {
190    /// Creates the class data; see [`ferroui_base::FerroObject::construct`].
191    pub fn construct() -> Self {
192        Self {
193            base: TemplatedControl::construct(),
194            header_button: RefCell::new(None),
195            next_button: RefCell::new(None),
196            previous_button: RefCell::new(None),
197            current_month: Cell::new(DateTime::MIN_VALUE),
198            is_mouse_left_button_down: Cell::new(false),
199            is_mouse_left_button_down_year_view: Cell::new(false),
200            is_control_pressed: Cell::new(false),
201            calendar: GregorianCalendar::new(),
202            owner: RefCell::new(None),
203            month_view: RefCell::new(None),
204            year_view: RefCell::new(None),
205            week_number_labels: RefCell::new(None),
206        }
207    }
208
209    /// Initializes a new instance of the [`CalendarItem`] class.
210    pub fn new() -> Ref<Self> {
211        instantiate(Self::construct())
212    }
213
214    /// The calendar this item displays a month or year of.
215    pub(crate) fn owner(&self) -> Option<Ref<Calendar>> {
216        self.owner.borrow().as_ref().and_then(WeakRef::upgrade)
217    }
218
219    pub(crate) fn set_owner(&self, value: Option<&Ref<Calendar>>) {
220        *self.owner.borrow_mut() = value.map(Ref::downgrade);
221    }
222
223    /// The brush of the background of the header.
224    pub fn header_background(&self) -> Option<Rc<dyn IBrush>> {
225        self.get_value(Self::header_background_property())
226    }
227
228    pub fn set_header_background(&self, value: Option<Rc<dyn IBrush>>) {
229        self.set_value(Self::header_background_property(), value)
230    }
231
232    /// The template of the titles of the days of the week.
233    pub fn day_title_template(&self) -> Option<Rc<dyn ITemplateOf<Option<Ref<Control>>>>> {
234        self.get_value(Self::day_title_template_property())
235    }
236
237    pub fn set_day_title_template(&self, value: Option<Rc<dyn ITemplateOf<Option<Ref<Control>>>>>) {
238        self.set_value(Self::day_title_template_property(), value)
239    }
240
241    /// Attaches a handler of this item to the click event of a button
242    /// part; the handler receives the button.
243    fn attach_click(&self, button: &Ref<Button>, handler: fn(&CalendarItem, &Button)) -> RoutedEventHandlerToken {
244        let weak = self.to_ref().downgrade();
245        let weak_button = button.downgrade();
246        button.click(move |_, _| {
247            if let (Some(this), Some(button)) = (weak.upgrade(), weak_button.upgrade()) {
248                handler(&this, &button);
249            }
250        })
251    }
252
253    /// Gets the button that allows switching between month mode, year mode,
254    /// and decade mode.
255    pub(crate) fn header_button(&self) -> Option<Ref<Button>> {
256        self.header_button.borrow().as_ref().map(|(button, _)| button.clone())
257    }
258
259    fn set_header_button(&self, value: Option<Ref<Button>>) {
260        if let Some((button, token)) = self.header_button.take() {
261            button.remove_handler(Button::click_event(), token);
262        }
263
264        if let Some(button) = value {
265            let token = self.attach_click(&button, Self::header_button_click);
266            *self.header_button.borrow_mut() = Some((button.clone(), token));
267            button.set_focusable(false);
268        }
269    }
270
271    /// Gets the button that displays the next page of the calendar when it
272    /// is clicked.
273    pub(crate) fn next_button(&self) -> Option<Ref<Button>> {
274        self.next_button.borrow().as_ref().map(|(button, _)| button.clone())
275    }
276
277    fn set_next_button(&self, value: Option<Ref<Button>>) {
278        if let Some((button, token)) = self.next_button.take() {
279            button.remove_handler(Button::click_event(), token);
280        }
281
282        if let Some(button) = value {
283            // If the user does not provide a Content value in template,
284            // we provide a helper text that can be used in
285            // Accessibility this text is not shown on the UI, just used
286            // for Accessibility purposes
287            if button.content().is_none() {
288                button.set_content(boxed_text("next button"));
289            }
290
291            button.set_is_visible(true);
292            let token = self.attach_click(&button, Self::next_button_click);
293            *self.next_button.borrow_mut() = Some((button.clone(), token));
294            button.set_focusable(false);
295        }
296    }
297
298    /// Gets the button that displays the previous page of the calendar when
299    /// it is clicked.
300    pub(crate) fn previous_button(&self) -> Option<Ref<Button>> {
301        self.previous_button.borrow().as_ref().map(|(button, _)| button.clone())
302    }
303
304    fn set_previous_button(&self, value: Option<Ref<Button>>) {
305        if let Some((button, token)) = self.previous_button.take() {
306            button.remove_handler(Button::click_event(), token);
307        }
308
309        if let Some(button) = value {
310            // If the user does not provide a Content value in template,
311            // we provide a helper text that can be used in
312            // Accessibility this text is not shown on the UI, just used
313            // for Accessibility purposes
314            if button.content().is_none() {
315                button.set_content(boxed_text("previous button"));
316            }
317
318            button.set_is_visible(true);
319            let token = self.attach_click(&button, Self::previous_button_click);
320            *self.previous_button.borrow_mut() = Some((button.clone(), token));
321            button.set_focusable(false);
322        }
323    }
324
325    /// Gets the Grid that hosts the content when in month mode.
326    pub(crate) fn month_view(&self) -> Option<Ref<Grid>> {
327        self.month_view.borrow().clone()
328    }
329
330    pub(crate) fn set_month_view(&self, value: Option<Ref<Grid>>) {
331        *self.month_view.borrow_mut() = value;
332    }
333
334    /// Gets the Grid that hosts the content when in year or decade mode.
335    pub(crate) fn year_view(&self) -> Option<Ref<Grid>> {
336        self.year_view.borrow().clone()
337    }
338
339    /// Gets the Grid that hosts the week number labels when in month mode.
340    fn week_number_labels(&self) -> Option<Ref<Grid>> {
341        self.week_number_labels.borrow().clone()
342    }
343
344    fn populate_grids(&self) {
345        let owner = self.owner();
346
347        if let Some(month_view) = self.month_view() {
348            let child_count = Calendar::ROWS_PER_MONTH + Calendar::ROWS_PER_MONTH * Calendar::COLUMNS_PER_MONTH;
349            let mut children: Vec<Ref<Control>> = Vec::with_capacity(child_count as usize);
350
351            let day_title_template = self.day_title_template();
352            for i in 0..Calendar::COLUMNS_PER_MONTH {
353                if let Some(cell) = day_title_template.as_ref().and_then(|template| template.build_typed()) {
354                    cell.set_data_context(boxed_text(""));
355                    cell.set_value(Grid::row_property(), 0);
356                    cell.set_value(Grid::column_property(), i);
357                    children.push(cell);
358                }
359            }
360
361            for i in 1..Calendar::ROWS_PER_MONTH {
362                for j in 0..Calendar::COLUMNS_PER_MONTH {
363                    let cell = CalendarDayButton::new();
364
365                    if let Some(owner) = &owner {
366                        cell.set_owner(Some(owner));
367                    }
368                    cell.set_value(Grid::row_property(), i);
369                    cell.set_value(Grid::column_property(), j);
370
371                    // The cells keep these subscriptions for as long as
372                    // they live.
373                    let weak = self.to_ref().downgrade();
374                    let _ = cell.calendar_day_button_mouse_down(move |sender, e| {
375                        if let Some(this) = weak.upgrade() {
376                            this.cell_mouse_left_button_down(sender, e);
377                        }
378                    });
379                    let weak = self.to_ref().downgrade();
380                    let _ = cell.calendar_day_button_mouse_up(move |sender, e| {
381                        if let Some(this) = weak.upgrade() {
382                            this.cell_mouse_left_button_up(sender, e);
383                        }
384                    });
385                    let weak = self.to_ref().downgrade();
386                    let weak_cell = cell.downgrade();
387                    cell.add_handler(InputElement::pointer_entered_event(), move |_, _| {
388                        if let (Some(this), Some(cell)) = (weak.upgrade(), weak_cell.upgrade()) {
389                            this.cell_mouse_entered(&cell);
390                        }
391                    });
392                    let weak = self.to_ref().downgrade();
393                    let weak_cell = cell.downgrade();
394                    cell.click(move |_, _| {
395                        if let Some(this) = weak.upgrade() {
396                            this.cell_click(weak_cell.upgrade().as_deref());
397                        }
398                    });
399                    children.push(cell.upcast());
400                }
401            }
402
403            month_view.children().add_range(children);
404        }
405
406        if let Some(week_number_labels) = self.week_number_labels() {
407            let mut children: Vec<Ref<Control>> = Vec::with_capacity(Calendar::ROWS_PER_MONTH as usize);
408
409            for i in 1..Calendar::ROWS_PER_MONTH {
410                let cell = ContentControl::new();
411                cell.set_value(Grid::row_property(), i);
412                cell.set_templated_parent(self.to_ref().upcast::<FerroObject>());
413                children.push(cell.upcast());
414            }
415
416            week_number_labels.children().add_range(children);
417        }
418
419        if let Some(year_view) = self.year_view() {
420            let child_count = Calendar::ROWS_PER_YEAR * Calendar::COLUMNS_PER_YEAR;
421            let mut children: Vec<Ref<Control>> = Vec::with_capacity(child_count as usize);
422
423            for i in 0..Calendar::ROWS_PER_YEAR {
424                for j in 0..Calendar::COLUMNS_PER_YEAR {
425                    let month = CalendarButton::new();
426
427                    if let Some(owner) = &owner {
428                        month.set_owner(Some(owner));
429                    }
430                    month.set_value(Grid::row_property(), i);
431                    month.set_value(Grid::column_property(), j);
432
433                    let weak = self.to_ref().downgrade();
434                    let _ = month.calendar_left_mouse_button_down(move |sender, _| {
435                        if let Some(this) = weak.upgrade() {
436                            this.month_calendar_button_mouse_down(Some(sender));
437                        }
438                    });
439                    let weak = self.to_ref().downgrade();
440                    let _ = month.calendar_left_mouse_button_up(move |sender, _| {
441                        if let Some(this) = weak.upgrade() {
442                            this.month_calendar_button_mouse_up(Some(sender));
443                        }
444                    });
445                    let weak = self.to_ref().downgrade();
446                    let weak_month = month.downgrade();
447                    month.add_handler(InputElement::pointer_entered_event(), move |_, _| {
448                        if let Some(this) = weak.upgrade() {
449                            this.month_mouse_entered(weak_month.upgrade().as_deref());
450                        }
451                    });
452                    children.push(month.upcast());
453                }
454            }
455
456            year_view.children().add_range(children);
457        }
458    }
459
460    fn set_day_titles(&self) {
461        let month_view = self.month_view().expect("the month view is present");
462        let date_format = DateTimeHelper::get_current_date_format();
463        let first_day_of_week = match self.owner() {
464            Some(owner) => owner.first_day_of_week(),
465            None => date_format.first_day_of_week(),
466        };
467
468        for child_index in 0..Calendar::COLUMNS_PER_MONTH {
469            let day_title = month_view.children().get(child_index as usize);
470            let name = &date_format.shortest_day_names()
471                [((child_index + first_day_of_week as i32) % NUMBER_OF_DAYS_PER_WEEK) as usize];
472            day_title.set_data_context(boxed_text(name.as_str()));
473        }
474    }
475
476    /// How many days of the previous month need to be displayed.
477    fn previous_month_days(&self, first_of_month: DateTime) -> i32 {
478        let day: DayOfWeek = self.calendar.get_day_of_week(first_of_month);
479        let first_day_of_week = match self.owner() {
480            Some(owner) => owner.first_day_of_week(),
481            None => DateTimeHelper::get_current_date_format().first_day_of_week(),
482        };
483
484        let i = (day as i32 - first_day_of_week as i32 + NUMBER_OF_DAYS_PER_WEEK) % NUMBER_OF_DAYS_PER_WEEK;
485
486        if i == 0 {
487            NUMBER_OF_DAYS_PER_WEEK
488        } else {
489            i
490        }
491    }
492
493    pub(crate) fn update_month_mode(&self) {
494        match self.owner() {
495            Some(owner) => self.current_month.set(owner.display_date_internal()),
496            None => self.current_month.set(DateTime::today()),
497        }
498
499        self.set_month_mode_header_button();
500        self.set_month_mode_previous_button(self.current_month.get());
501        self.set_month_mode_next_button(self.current_month.get());
502
503        if self.month_view().is_some() {
504            self.set_day_titles();
505            self.set_calendar_day_buttons(self.current_month.get());
506            self.update_week_number_labels(self.current_month.get());
507        }
508    }
509
510    fn set_month_mode_header_button(&self) {
511        if let Some(header_button) = self.header_button() {
512            let date_format = DateTimeHelper::get_current_date_format();
513            if let Some(owner) = self.owner() {
514                header_button.set_content(boxed_text(owner.display_date_internal().to_string_format("Y", &date_format)));
515                header_button.set_is_enabled(true);
516            } else {
517                header_button.set_content(boxed_text(DateTime::today().to_string_format("Y", &date_format)));
518            }
519        }
520    }
521
522    fn set_month_mode_next_button(&self, first_day_of_month: DateTime) {
523        if let (Some(owner), Some(next_button)) = (self.owner(), self.next_button()) {
524            // DisplayDate is equal to DateTime.MaxValue
525            if DateTimeHelper::compare_year_month(first_day_of_month, DateTime::MAX_VALUE) == 0 {
526                next_button.set_is_enabled(false);
527            } else {
528                // Since we are sure DisplayDate is not equal to
529                // DateTime.MaxValue, it is safe to use AddMonths
530                let first_day_of_next_month = self.calendar.add_months(first_day_of_month, 1);
531                next_button.set_is_enabled(
532                    DateTimeHelper::compare_days(owner.display_date_range_end(), first_day_of_next_month) > -1,
533                );
534            }
535        }
536    }
537
538    fn set_month_mode_previous_button(&self, first_day_of_month: DateTime) {
539        if let (Some(owner), Some(previous_button)) = (self.owner(), self.previous_button()) {
540            previous_button
541                .set_is_enabled(DateTimeHelper::compare_days(owner.display_date_range_start(), first_day_of_month) < 0);
542        }
543    }
544
545    fn set_button_state(&self, child_button: &Ref<CalendarDayButton>, date_to_add: DateTime) {
546        if let Some(owner) = self.owner() {
547            child_button.set_opacity(1.0);
548
549            // If the day is outside the DisplayDateStart/End boundary, do
550            // not show it
551            if DateTimeHelper::compare_days(date_to_add, owner.display_date_range_start()) < 0
552                || DateTimeHelper::compare_days(date_to_add, owner.display_date_range_end()) > 0
553            {
554                child_button.set_is_enabled(false);
555                child_button.set_is_today(false);
556                child_button.set_is_selected(false);
557                child_button.set_opacity(0.0);
558            } else {
559                // SET IF THE DAY IS SELECTABLE OR NOT
560                child_button.set_is_blackout(owner.blackout_dates().contains_date(date_to_add));
561                child_button.set_is_enabled(true);
562
563                // SET IF THE DAY IS INACTIVE OR NOT: set if the day is a
564                // trailing day or not
565                child_button.set_is_inactive(
566                    DateTimeHelper::compare_year_month(date_to_add, owner.display_date_internal()) != 0,
567                );
568
569                // SET IF THE DAY IS TODAY OR NOT
570                child_button.set_is_today(owner.is_today_highlighted() && date_to_add == DateTime::today());
571
572                // SET IF THE DAY IS SELECTED OR NOT
573                child_button.set_is_selected(false);
574                for item in owner.selected_dates().to_vec() {
575                    // Since we should be comparing the Date values not
576                    // DateTime values, we can't use
577                    // Owner.SelectedDates.Contains(dateToAdd) directly
578                    child_button
579                        .set_is_selected(child_button.is_selected() | (DateTimeHelper::compare_days(date_to_add, item) == 0));
580                }
581
582                // SET THE FOCUS ELEMENT
583                if let Some(last_selected_date) = owner.last_selected_date() {
584                    if DateTimeHelper::compare_days(last_selected_date, date_to_add) == 0 {
585                        if let Some(focus_button) = owner.focus_button() {
586                            focus_button.set_is_current(false);
587                        }
588                        owner.set_focus_button(Some(child_button.clone()));
589                        if owner.has_focus_internal() {
590                            child_button.set_is_current(true);
591                        }
592                    } else {
593                        child_button.set_is_current(false);
594                    }
595                }
596            }
597        }
598    }
599
600    fn day_button_at(month_view: &Grid, index: i32) -> Ref<CalendarDayButton> {
601        month_view
602            .children()
603            .get(index as usize)
604            .cast::<CalendarDayButton>()
605            .expect("the child of the month view is a CalendarDayButton")
606    }
607
608    fn set_calendar_day_buttons(&self, first_day_of_month: DateTime) {
609        let month_view = self.month_view().expect("the month view is present");
610        let owner = self.owner();
611        let last_month_to_display = self.previous_month_days(first_day_of_month);
612        let mut date_to_add;
613
614        if DateTimeHelper::compare_year_month(first_day_of_month, DateTime::MIN_VALUE) > 0 {
615            // DisplayDate is not equal to DateTime.MinValue we can subtract
616            // days from the DisplayDate
617            date_to_add = self.calendar.add_days(first_day_of_month, -last_month_to_display);
618        } else {
619            date_to_add = first_day_of_month;
620        }
621
622        if let Some(owner) = &owner {
623            if owner.hover_end().is_some() && owner.hover_start().is_some() {
624                owner.set_hover_end_index(None);
625                owner.set_hover_start_index(None);
626            }
627        }
628
629        let count = Calendar::ROWS_PER_MONTH * Calendar::COLUMNS_PER_MONTH;
630
631        let mut child_index = Calendar::COLUMNS_PER_MONTH;
632        while child_index < count {
633            let child_button = Self::day_button_at(&month_view, child_index);
634
635            child_button.set_index(child_index);
636            self.set_button_state(&child_button, date_to_add);
637
638            // Update the indexes of hoverStart and hoverEnd
639            if let Some(owner) = &owner {
640                if let (Some(hover_end), Some(hover_start)) = (owner.hover_end(), owner.hover_start()) {
641                    if DateTimeHelper::compare_days(date_to_add, hover_end) == 0 {
642                        owner.set_hover_end_index(Some(child_index));
643                    }
644
645                    if DateTimeHelper::compare_days(date_to_add, hover_start) == 0 {
646                        owner.set_hover_start_index(Some(child_index));
647                    }
648                }
649            }
650
651            child_button.set_content(boxed_text(DateTimeHelper::format_number(date_to_add.day())));
652            child_button.set_data_context(boxed_date(date_to_add));
653
654            if DateTime::compare(DateTimeHelper::discard_time(DateTime::MAX_VALUE), date_to_add) > 0 {
655                // Since we are sure DisplayDate is not equal to
656                // DateTime.MaxValue, it is safe to use AddDays
657                date_to_add = self.calendar.add_days(date_to_add, 1);
658            } else {
659                // DisplayDate is equal to the DateTime.MaxValue, so there
660                // are no trailing days
661                child_index += 1;
662                for i in child_index..count {
663                    let child_button = Self::day_button_at(&month_view, i);
664                    // button needs a content to occupy the necessary space
665                    // for the content presenter
666                    child_button.set_content(boxed_text(DateTimeHelper::format_number(i)));
667                    child_button.set_is_enabled(false);
668                    child_button.set_opacity(0.0);
669                }
670                return;
671            }
672
673            child_index += 1;
674        }
675
676        // If the HoverStart or HoverEndInternal could not be found on the
677        // DisplayMonth set the values of the HoverStartIndex or
678        // HoverEndIndex to be the first or last day indexes on the current
679        // month
680        if let Some(owner) = &owner {
681            if let (Some(hover_start), Some(hover_end_internal)) = (owner.hover_start(), owner.hover_end_internal()) {
682                if owner.hover_end_index().is_none() {
683                    if DateTimeHelper::compare_days(hover_end_internal, hover_start) > 0 {
684                        owner.set_hover_end_index(Some(Calendar::COLUMNS_PER_MONTH * Calendar::ROWS_PER_MONTH - 1));
685                    } else {
686                        owner.set_hover_end_index(Some(Calendar::COLUMNS_PER_MONTH));
687                    }
688                }
689
690                if owner.hover_start_index().is_none() {
691                    if DateTimeHelper::compare_days(hover_end_internal, hover_start) > 0 {
692                        owner.set_hover_start_index(Some(Calendar::COLUMNS_PER_MONTH));
693                    } else {
694                        owner.set_hover_start_index(Some(Calendar::COLUMNS_PER_MONTH * Calendar::ROWS_PER_MONTH - 1));
695                    }
696                }
697            }
698        }
699    }
700
701    /// Updates the week number labels if `Calendar::is_week_number_visible`
702    /// is true and the display mode of the calendar is
703    /// [`CalendarMode::Month`].
704    fn update_week_number_labels(&self, first_day_of_month: DateTime) {
705        let owner = self.owner();
706
707        // first set the pseudo classes
708        let show = owner.as_ref().is_some_and(|owner| owner.is_week_number_visible());
709        self.pseudo_classes().set(":hasweeknumbers", show);
710
711        // if we don't have a week number labels grid, or it has no children, then we don't need to update
712        let Some(week_number_labels) = self.week_number_labels() else {
713            return;
714        };
715        if week_number_labels.children().count() == 0 {
716            return;
717        }
718
719        self.update_week_number_labels_visibility();
720
721        let last_month_to_display = self.previous_month_days(first_day_of_month);
722        let first_date_displayed = if DateTimeHelper::compare_year_month(first_day_of_month, DateTime::MIN_VALUE) > 0 {
723            self.calendar.add_days(first_day_of_month, -last_month_to_display)
724        } else {
725            first_day_of_month
726        };
727
728        let date_format = DateTimeHelper::get_current_date_format();
729        let rule = owner.as_ref().map_or_else(|| date_format.calendar_week_rule(), |owner| owner.week_number_rule());
730        let first_day_of_week =
731            owner.as_ref().map_or_else(|| date_format.first_day_of_week(), |owner| owner.first_day_of_week());
732
733        // We have 6 rows with weeks. The control theme may have added more children to the Grid (Header, Background, ...).
734        // We only want to update the last 6 children of the Grid, which are the week number labels.
735        let count = week_number_labels.children().count() as i32;
736        let start_index = count - (Calendar::ROWS_PER_MONTH - 1);
737        for i in start_index..count {
738            let days_to_add = (i - start_index) * NUMBER_OF_DAYS_PER_WEEK;
739            let first_day_of_row = self.calendar.add_days(first_date_displayed, days_to_add);
740
741            let label = week_number_labels.children().get(i as usize).cast::<ContentControl>();
742            if let Some(label) = label {
743                let week = DateTimeHelper::get_week_of_year(first_day_of_row, rule, first_day_of_week, &self.calendar);
744                label.set_content(Some(Rc::new(week) as BoxedValue));
745            }
746        }
747    }
748
749    /// Updates the visibility of the week number labels based on the
750    /// `IsWeekNumberVisible` property and the display mode of the calendar.
751    pub(crate) fn update_week_number_labels_visibility(&self) {
752        if let (Some(week_number_labels), Some(owner)) = (self.week_number_labels(), self.owner()) {
753            week_number_labels
754                .set_is_visible(owner.is_week_number_visible() && owner.display_mode() == CalendarMode::Month);
755        }
756    }
757
758    pub(crate) fn update_year_mode(&self) {
759        match self.owner() {
760            Some(owner) => self.current_month.set(owner.selected_month()),
761            None => self.current_month.set(DateTime::today()),
762        }
763
764        self.set_year_mode_header_button();
765        self.set_year_mode_previous_button();
766        self.set_year_mode_next_button();
767
768        if self.year_view().is_some() {
769            self.set_month_buttons_for_year_mode();
770        }
771    }
772
773    fn set_year_mode_header_button(&self) {
774        if let Some(header_button) = self.header_button() {
775            header_button.set_is_enabled(true);
776            header_button.set_content(boxed_text(DateTimeHelper::format_number(self.current_month.get().year())));
777        }
778    }
779
780    fn set_year_mode_previous_button(&self) {
781        if let (Some(owner), Some(previous_button)) = (self.owner(), self.previous_button()) {
782            previous_button.set_is_enabled(owner.display_date_range_start().year() != self.current_month.get().year());
783        }
784    }
785
786    fn set_year_mode_next_button(&self) {
787        if let (Some(owner), Some(next_button)) = (self.owner(), self.next_button()) {
788            next_button.set_is_enabled(owner.display_date_range_end().year() != self.current_month.get().year());
789        }
790    }
791
792    fn calendar_button_of(child: &Ref<Control>) -> Ref<CalendarButton> {
793        child.cast::<CalendarButton>().expect("the child of the year view is a CalendarButton")
794    }
795
796    fn set_month_buttons_for_year_mode(&self) {
797        let year_view = self.year_view().expect("the year view is present");
798        let owner = self.owner();
799        let current_month = self.current_month.get();
800        let date_format = DateTimeHelper::get_current_date_format();
801
802        for (count, child) in year_view.children().snapshot().iter().enumerate() {
803            let child_button = Self::calendar_button_of(child);
804            // There should be no time component. Time is 12:00 AM
805            let day = DateTime::new(current_month.year(), count as i32 + 1, 1);
806            child_button.set_data_context(boxed_date(day));
807
808            child_button.set_content(boxed_text(date_format.abbreviated_month_names()[count].as_str()));
809            child_button.set_is_visible(true);
810
811            if let Some(owner) = &owner {
812                if day.year() == current_month.year()
813                    && day.month() == current_month.month()
814                    && day.day() == current_month.day()
815                {
816                    owner.set_focus_calendar_button(Some(child_button.clone()));
817                    child_button.set_is_calendar_button_focused(owner.has_focus_internal());
818                } else {
819                    child_button.set_is_calendar_button_focused(false);
820                }
821
822                child_button
823                    .set_is_selected(DateTimeHelper::compare_year_month(day, owner.display_date_internal()) == 0);
824
825                if DateTimeHelper::compare_year_month(day, owner.display_date_range_start()) < 0
826                    || DateTimeHelper::compare_year_month(day, owner.display_date_range_end()) > 0
827                {
828                    child_button.set_is_enabled(false);
829                    child_button.set_opacity(0.0);
830                } else {
831                    child_button.set_is_enabled(true);
832                    child_button.set_opacity(1.0);
833                }
834            }
835
836            child_button.set_is_inactive(false);
837        }
838    }
839
840    pub(crate) fn update_decade_mode(&self) {
841        let selected_year;
842
843        match self.owner() {
844            Some(owner) => {
845                selected_year = owner.selected_year();
846                self.current_month.set(owner.selected_month());
847            }
848            None => {
849                self.current_month.set(DateTime::today());
850                selected_year = DateTime::today();
851            }
852        }
853
854        let decade = DateTimeHelper::decade_of_date(selected_year);
855        let decade_end = DateTimeHelper::end_of_decade(selected_year);
856
857        self.set_decade_mode_header_button(decade, decade_end);
858        self.set_decade_mode_previous_button(decade);
859        self.set_decade_mode_next_button(decade_end);
860
861        if self.year_view().is_some() {
862            self.set_year_buttons(decade, decade_end);
863        }
864    }
865
866    pub(crate) fn update_year_view_selection(&self, calendar_button: Option<&CalendarButton>) {
867        let Some(owner) = self.owner() else {
868            return;
869        };
870        let Some(calendar_button) = calendar_button else {
871            return;
872        };
873        if let Some(selected_date) = date_of(calendar_button) {
874            owner
875                .focus_calendar_button()
876                .expect("the calendar has a focused calendar button")
877                .set_is_calendar_button_focused(false);
878            owner.set_focus_calendar_button(Some(calendar_button.to_ref()));
879            calendar_button.set_is_calendar_button_focused(owner.has_focus_internal());
880
881            if owner.display_mode() == CalendarMode::Year {
882                owner.set_selected_month(selected_date);
883            } else {
884                owner.set_selected_year(selected_date);
885            }
886        }
887    }
888
889    fn set_year_buttons(&self, decade: i32, decade_end: i32) {
890        let year_view = self.year_view().expect("the year view is present");
891        let owner = self.owner();
892
893        for (count, child) in (-1..).zip(year_view.children().snapshot().iter()) {
894            let child_button = Self::calendar_button_of(child);
895            let year = decade + count;
896
897            if year <= DateTime::MAX_VALUE.year() && year >= DateTime::MIN_VALUE.year() {
898                // There should be no time component. Time is 12:00 AM
899                let day = DateTime::new(year, 1, 1);
900                child_button.set_data_context(boxed_date(day));
901                child_button.set_content(boxed_text(DateTimeHelper::format_number(year)));
902                child_button.set_is_visible(true);
903
904                if let Some(owner) = &owner {
905                    if year == owner.selected_year().year() {
906                        owner.set_focus_calendar_button(Some(child_button.clone()));
907                        child_button.set_is_calendar_button_focused(owner.has_focus_internal());
908                    } else {
909                        child_button.set_is_calendar_button_focused(false);
910                    }
911                    child_button.set_is_selected(owner.display_date().year() == year);
912
913                    if year < owner.display_date_range_start().year() || year > owner.display_date_range_end().year() {
914                        child_button.set_is_enabled(false);
915                        child_button.set_opacity(0.0);
916                    } else {
917                        child_button.set_is_enabled(true);
918                        child_button.set_opacity(1.0);
919                    }
920                }
921
922                // SET IF THE YEAR IS INACTIVE OR NOT: set if the year is a
923                // trailing year or not
924                child_button.set_is_inactive(year < decade || year > decade_end);
925            } else {
926                child_button.set_is_enabled(false);
927                child_button.set_opacity(0.0);
928            }
929        }
930    }
931
932    fn set_decade_mode_header_button(&self, decade: i32, decade_end: i32) {
933        if let Some(header_button) = self.header_button() {
934            header_button.set_content(boxed_text(format!(
935                "{}-{}",
936                DateTimeHelper::format_number(decade),
937                DateTimeHelper::format_number(decade_end)
938            )));
939            header_button.set_is_enabled(false);
940        }
941    }
942
943    fn set_decade_mode_next_button(&self, decade_end: i32) {
944        if let (Some(owner), Some(next_button)) = (self.owner(), self.next_button()) {
945            next_button.set_is_enabled(owner.display_date_range_end().year() > decade_end);
946        }
947    }
948
949    fn set_decade_mode_previous_button(&self, decade: i32) {
950        if let (Some(owner), Some(previous_button)) = (self.owner(), self.previous_button()) {
951            previous_button.set_is_enabled(decade > owner.display_date_range_start().year());
952        }
953    }
954
955    /// The handler of the click event of the header button; `sender` is
956    /// the button.
957    pub(crate) fn header_button_click(&self, sender: &Button) {
958        if let Some(owner) = self.owner() {
959            if !owner.has_focus_internal() {
960                owner.focus();
961            }
962
963            if sender.is_enabled() {
964                if owner.display_mode() == CalendarMode::Month {
965                    let d = owner.display_date_internal();
966                    owner.set_selected_month(DateTime::new(d.year(), d.month(), 1));
967                    owner.set_display_mode(CalendarMode::Year);
968                } else {
969                    debug_assert!(
970                        owner.display_mode() == CalendarMode::Year,
971                        "The Owner Calendar's DisplayMode should be Year!"
972                    );
973                    let d = owner.selected_month();
974                    owner.set_selected_year(DateTime::new(d.year(), d.month(), 1));
975                    owner.set_display_mode(CalendarMode::Decade);
976                }
977            }
978        }
979    }
980
981    /// The handler of the click event of the previous button; `sender` is
982    /// the button.
983    pub(crate) fn previous_button_click(&self, sender: &Button) {
984        if let Some(owner) = self.owner() {
985            if !owner.has_focus_internal() {
986                owner.focus();
987            }
988
989            if sender.is_enabled() {
990                owner.on_previous_click();
991            }
992        }
993    }
994
995    /// The handler of the click event of the next button; `sender` is the
996    /// button.
997    pub(crate) fn next_button_click(&self, sender: &Button) {
998        if let Some(owner) = self.owner() {
999            if !owner.has_focus_internal() {
1000                owner.focus();
1001            }
1002
1003            if sender.is_enabled() {
1004                owner.on_next_click();
1005            }
1006        }
1007    }
1008
1009    /// The handler of the pointer entered event of a day button; `sender`
1010    /// is the button.
1011    pub(crate) fn cell_mouse_entered(&self, sender: &CalendarDayButton) {
1012        if let Some(owner) = self.owner() {
1013            if !self.is_mouse_left_button_down.get() || !sender.is_enabled() || sender.is_blackout() {
1014                return;
1015            }
1016            let Some(selected_date) = date_of(sender) else {
1017                return;
1018            };
1019
1020            // Update the states of all buttons to be selected starting
1021            // from HoverStart to b
1022            match owner.selection_mode() {
1023                CalendarSelectionMode::SingleDate => {
1024                    owner.set_calendar_date_picker_display_date_flag(true);
1025                    if owner.selected_dates().count() == 0 {
1026                        owner.selected_dates().add(selected_date);
1027                    } else {
1028                        owner.selected_dates().set(0, selected_date);
1029                    }
1030                }
1031                CalendarSelectionMode::SingleRange | CalendarSelectionMode::MultipleRange => {
1032                    owner.un_highlight_days();
1033                    owner.set_hover_end_index(Some(sender.index()));
1034                    owner.set_hover_end(Some(selected_date));
1035                    // Update the States of the buttons
1036                    owner.highlight_days();
1037                }
1038                CalendarSelectionMode::None => {}
1039            }
1040        }
1041    }
1042
1043    /// The handler of the mouse down event of a day button; `sender` is
1044    /// the button.
1045    pub(crate) fn cell_mouse_left_button_down(&self, sender: &CalendarDayButton, e: &PointerPressedEventArgs) {
1046        if let Some(owner) = self.owner() {
1047            if !owner.has_focus_internal() {
1048                owner.focus();
1049            }
1050
1051            let (ctrl, shift) = CalendarExtensions::get_meta_key_state(e.key_modifiers());
1052
1053            // The sender is always a day button here, so the branch of the
1054            // reference for another kind of sender (which clears the
1055            // control state) has no counterpart.
1056            let b = sender;
1057            self.is_control_pressed.set(ctrl);
1058            let selected_date = date_of(b).filter(|_| b.is_enabled() && !b.is_blackout());
1059            if let Some(selected_date) = selected_date {
1060                self.is_mouse_left_button_down.set(true);
1061
1062                match owner.selection_mode() {
1063                    CalendarSelectionMode::None => {}
1064                    CalendarSelectionMode::SingleDate => {
1065                        owner.set_calendar_date_picker_display_date_flag(true);
1066                        if owner.selected_dates().count() == 0 {
1067                            owner.selected_dates().add(selected_date);
1068                        } else {
1069                            owner.selected_dates().set(0, selected_date);
1070                        }
1071                    }
1072                    CalendarSelectionMode::SingleRange => {
1073                        // Set the start or end of the selection
1074                        // range
1075                        if shift {
1076                            owner.un_highlight_days();
1077                            owner.set_hover_end(Some(selected_date));
1078                            owner.set_hover_end_index(Some(b.index()));
1079                            owner.highlight_days();
1080                        } else {
1081                            owner.un_highlight_days();
1082                            owner.set_hover_start(Some(selected_date));
1083                            owner.set_hover_start_index(Some(b.index()));
1084                        }
1085                    }
1086                    CalendarSelectionMode::MultipleRange => {
1087                        if shift {
1088                            if !ctrl {
1089                                // clear the list, set the states to
1090                                // default
1091                                owner.add_removed_items(&owner.selected_dates().to_vec());
1092                                owner.selected_dates().clear_internal();
1093                            }
1094                            owner.set_hover_end(Some(selected_date));
1095                            owner.set_hover_end_index(Some(b.index()));
1096                            owner.highlight_days();
1097                        } else {
1098                            if !ctrl {
1099                                // clear the list, set the states to
1100                                // default
1101                                owner.add_removed_items(&owner.selected_dates().to_vec());
1102                                owner.selected_dates().clear_internal();
1103                                owner.un_highlight_days();
1104                            }
1105                            owner.set_hover_start(Some(selected_date));
1106                            owner.set_hover_start_index(Some(b.index()));
1107                        }
1108                    }
1109                }
1110            } else {
1111                // If a click occurs on a BlackOutDay we set the
1112                // HoverStart to be null
1113                owner.set_hover_start(None);
1114            }
1115        }
1116    }
1117
1118    fn add_selection(&self, b: &CalendarDayButton, selected_date: DateTime) {
1119        if let Some(owner) = self.owner() {
1120            owner.set_hover_end_index(Some(b.index()));
1121            owner.set_hover_end(Some(selected_date));
1122
1123            if let (Some(hover_end), Some(hover_start)) = (owner.hover_end(), owner.hover_start()) {
1124                // this is selection with Mouse, we do not guarantee the
1125                // range does not include BlackOutDates.  AddRange method
1126                // will throw away the BlackOutDates based on the
1127                // SelectionMode
1128                owner.set_is_mouse_selection(true);
1129                owner.selected_dates().add_range(hover_start, hover_end);
1130                owner.on_day_click(selected_date);
1131            }
1132        }
1133    }
1134
1135    /// The handler of the mouse up event of a day button; `sender` is the
1136    /// button.
1137    pub(crate) fn cell_mouse_left_button_up(&self, sender: &CalendarDayButton, e: &PointerReleasedEventArgs) {
1138        if let Some(owner) = self.owner() {
1139            let b = sender;
1140            if !b.is_blackout() {
1141                owner.on_day_button_mouse_up(e);
1142            }
1143            self.is_mouse_left_button_down.set(false);
1144            if let Some(selected_date) = date_of(b) {
1145                if owner.selection_mode() == CalendarSelectionMode::None
1146                    || owner.selection_mode() == CalendarSelectionMode::SingleDate
1147                {
1148                    owner.on_day_click(selected_date);
1149                    return;
1150                }
1151                if owner.allow_tap_range_selection()
1152                    && (owner.selection_mode() == CalendarSelectionMode::SingleRange
1153                        || owner.selection_mode() == CalendarSelectionMode::MultipleRange)
1154                    && owner.process_tap_range_selection(selected_date)
1155                {
1156                    owner.on_day_click(selected_date);
1157                    return;
1158                }
1159                if owner.hover_start().is_some() {
1160                    match owner.selection_mode() {
1161                        CalendarSelectionMode::SingleRange => {
1162                            // Update SelectedDates
1163                            owner.add_removed_items(&owner.selected_dates().to_vec());
1164                            owner.selected_dates().clear_internal();
1165                            self.add_selection(b, selected_date);
1166                        }
1167                        CalendarSelectionMode::MultipleRange => {
1168                            // add the selection (either single day or
1169                            // SingleRange day)
1170                            self.add_selection(b, selected_date);
1171                        }
1172                        _ => {}
1173                    }
1174                } else {
1175                    // If the day is Disabled but a trailing day we should
1176                    // be able to switch months
1177                    if b.is_inactive() && b.is_blackout() {
1178                        owner.on_day_click(selected_date);
1179                    }
1180                }
1181            }
1182        }
1183    }
1184
1185    /// The handler of the click event of a day button; `sender` is the
1186    /// button.
1187    fn cell_click(&self, sender: Option<&CalendarDayButton>) {
1188        if let Some(owner) = self.owner() {
1189            if self.is_control_pressed.get() && owner.selection_mode() == CalendarSelectionMode::MultipleRange {
1190                let b = sender.expect("the sender of the click is a CalendarDayButton");
1191
1192                if b.is_selected() {
1193                    owner.set_hover_start(None);
1194                    self.is_mouse_left_button_down.set(false);
1195                    b.set_is_selected(false);
1196                    if let Some(selected_date) = date_of(b) {
1197                        owner.selected_dates().remove(selected_date);
1198                    }
1199                }
1200            }
1201        }
1202        self.is_control_pressed.set(false);
1203    }
1204
1205    fn month_calendar_button_mouse_down(&self, sender: Option<&CalendarButton>) {
1206        self.is_mouse_left_button_down_year_view.set(true);
1207
1208        self.update_year_view_selection(sender);
1209    }
1210
1211    /// The handler of the mouse up event of a month or year button;
1212    /// `sender` is the button.
1213    pub(crate) fn month_calendar_button_mouse_up(&self, sender: Option<&CalendarButton>) {
1214        self.is_mouse_left_button_down_year_view.set(false);
1215
1216        if let (Some(owner), Some(new_month)) = (self.owner(), sender.and_then(|sender| date_of(sender))) {
1217            if owner.display_mode() == CalendarMode::Year {
1218                owner.set_display_date(new_month);
1219                owner.set_display_mode(CalendarMode::Month);
1220            } else {
1221                debug_assert!(
1222                    owner.display_mode() == CalendarMode::Decade,
1223                    "The owning Calendar should be in decade mode!"
1224                );
1225                owner.set_selected_month(new_month);
1226                owner.set_display_mode(CalendarMode::Year);
1227            }
1228        }
1229    }
1230
1231    fn month_mouse_entered(&self, sender: Option<&CalendarButton>) {
1232        if self.is_mouse_left_button_down_year_view.get() {
1233            self.update_year_view_selection(sender);
1234        }
1235    }
1236
1237    pub(crate) fn update_disabled(&self, is_enabled: bool) {
1238        self.pseudo_classes().set(":calendardisabled", !is_enabled);
1239    }
1240
1241    /// The state of the tracking of the left mouse button in the year view.
1242    #[cfg(test)]
1243    pub(crate) fn is_mouse_left_button_down_year_view(&self) -> bool {
1244        self.is_mouse_left_button_down_year_view.get()
1245    }
1246
1247    #[cfg(test)]
1248    pub(crate) fn set_is_mouse_left_button_down_year_view(&self, value: bool) {
1249        self.is_mouse_left_button_down_year_view.set(value);
1250    }
1251}