1use super::calendar_item::date_of;
10use super::{
11 CalendarBlackoutDatesCollection, CalendarButton, CalendarDateRange, CalendarDayButton, CalendarExtensions,
12 CalendarItem, DateTimeHelper, SelectedDatesCollection,
13};
14use crate::primitives::{SelectingItemsControl, TemplateAppliedEventArgs, TemplatedControl, TemplatedControlImpl};
15use crate::{ControlImpl, Panel, SelectionChangedEventArgs};
16use ferroui_base::data::BindingMode;
17use ferroui_base::input::{
18 FocusChangedEventArgs, InputElement, InputElementImpl, InputElementImplExt, Key, KeyEventArgs, MouseButton,
19 PointerReleasedEventArgs, PointerWheelEventArgs,
20};
21use ferroui_base::interactivity::{InteractiveImpl, RoutedEventArgs};
22use ferroui_base::layout::LayoutableImpl;
23use ferroui_base::media::IBrush;
24use ferroui_base::reactive::{Disposable, IDisposable};
25use ferroui_base::utilities::{CalendarWeekRule, DateTime, DayOfWeek, HandlerList};
26use ferroui_base::{
27 ferro_class, ferro_class_info, ferro_impl_classes, ferro_properties, ferro_routed_event_args, instantiate,
28 BoxedValue, FerroObjectImpl, FerroObjectImplExt, FerroProperty, Ref, StyledElementImpl, StyledProperty,
29 StyledPropertyOptions, VisualImpl,
30};
31use std::cell::{Cell, OnceCell, RefCell};
32use std::rc::Rc;
33
34#[repr(i32)]
37#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
38pub enum CalendarMode {
39 #[default]
41 Month = 0,
42
43 Year = 1,
45
46 Decade = 2,
48}
49
50#[repr(i32)]
56#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
57pub enum CalendarSelectionMode {
58 #[default]
61 SingleDate = 0,
62
63 SingleRange = 1,
67
68 MultipleRange = 2,
72
73 None = 3,
75}
76
77#[derive(Clone)]
79pub struct CalendarDateChangedEventArgs {
80 base: RoutedEventArgs,
81 removed_date: Option<DateTime>,
82 added_date: Option<DateTime>,
83}
84
85ferro_routed_event_args!(CalendarDateChangedEventArgs: RoutedEventArgs);
86
87impl CalendarDateChangedEventArgs {
88 pub(crate) fn new(removed_date: Option<DateTime>, added_date: Option<DateTime>) -> Self {
94 Self { base: RoutedEventArgs::new(), removed_date, added_date }
95 }
96
97 pub fn removed_date(&self) -> Option<DateTime> {
99 self.removed_date
100 }
101
102 pub fn added_date(&self) -> Option<DateTime> {
104 self.added_date
105 }
106}
107
108#[derive(Clone)]
110pub struct CalendarModeChangedEventArgs {
111 base: RoutedEventArgs,
112 old_mode: CalendarMode,
113 new_mode: CalendarMode,
114}
115
116ferro_routed_event_args!(CalendarModeChangedEventArgs: RoutedEventArgs);
117
118impl CalendarModeChangedEventArgs {
119 pub fn new(old_mode: CalendarMode, new_mode: CalendarMode) -> Self {
122 Self { base: RoutedEventArgs::new(), old_mode, new_mode }
123 }
124
125 pub fn old_mode(&self) -> CalendarMode {
127 self.old_mode
128 }
129
130 pub fn new_mode(&self) -> CalendarMode {
132 self.new_mode
133 }
134}
135
136impl std::fmt::Display for Calendar {
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 match self.selected_date() {
141 Some(selected_date) => {
142 f.write_str(&selected_date.to_string_provider(&DateTimeHelper::get_current_date_format()))
143 }
144 None => Ok(()),
145 }
146 }
147}
148
149const PART_ELEMENT_ROOT: &str = "PART_Root";
150const PART_ELEMENT_MONTH: &str = "PART_CalendarItem";
151
152fn date_of_item(item: &Option<BoxedValue>) -> Option<DateTime> {
154 item.as_ref().and_then(|item| item.downcast_ref::<DateTime>().copied())
155}
156
157#[repr(C)]
206pub struct Calendar {
207 base: TemplatedControl,
208
209 selected_month: Cell<DateTime>,
210 selected_year: Cell<DateTime>,
211
212 is_shift_pressed: Cell<bool>,
213 display_date_is_changing: Cell<bool>,
214 is_tap_range_selection_active: Cell<bool>,
215 tap_range_start: Cell<Option<DateTime>>,
216
217 focus_button: RefCell<Option<Ref<CalendarDayButton>>>,
218 focus_calendar_button: RefCell<Option<Ref<CalendarButton>>>,
219
220 root: RefCell<Option<Ref<Panel>>>,
221
222 selected_dates: OnceCell<SelectedDatesCollection>,
223 blackout_dates: OnceCell<CalendarBlackoutDatesCollection>,
224 removed_items: RefCell<Vec<DateTime>>,
225 last_selected_date_internal: Cell<Option<DateTime>>,
226 display_date_internal: Cell<DateTime>,
227
228 hover_start: Cell<Option<DateTime>>,
229 hover_start_index: Cell<Option<i32>>,
230 hover_end_internal: Cell<Option<DateTime>>,
231 hover_end_index: Cell<Option<i32>>,
232 has_focus_internal: Cell<bool>,
233 is_mouse_selection: Cell<bool>,
234
235 calendar_date_picker_display_date_flag: Cell<bool>,
238
239 selected_dates_changed: HandlerList<dyn Fn(&SelectionChangedEventArgs)>,
240 display_date_changed: HandlerList<dyn Fn(&CalendarDateChangedEventArgs)>,
241 display_mode_changed: HandlerList<dyn Fn(&CalendarModeChangedEventArgs)>,
242 day_button_mouse_up: HandlerList<dyn Fn(&PointerReleasedEventArgs)>,
243}
244
245ferro_class!(Calendar: TemplatedControl);
246
247ferro_class_info!(Calendar {
248 new: Calendar::new,
249 markup: {
250 properties: [
251 SelectedDates: SelectedDatesCollection { get: Calendar::selected_dates },
252 BlackoutDates: CalendarBlackoutDatesCollection { get: Calendar::blackout_dates },
253 ],
254 attributes: [
255 TemplatePart("PART_CalendarItem", type(Ref<CalendarItem>)),
256 TemplatePart("PART_Root", type(Ref<Panel>)),
257 ],
258 },
259});
260
261ferro_impl_classes!(Calendar: StyledElementImpl, VisualImpl, LayoutableImpl, InteractiveImpl);
262
263impl FerroObjectImpl for Calendar {
264 fn constructed(this: &Self) {
266 Self::parent_constructed(this);
267
268 this.set_current_value(Self::display_date_property(), DateTime::today());
269 Self::update_display_date(this, this.display_date(), DateTime::MIN_VALUE);
270 let this_ref = this.to_ref();
271 let _ = this.blackout_dates.set(CalendarBlackoutDatesCollection::new(&this_ref));
272 let _ = this.selected_dates.set(SelectedDatesCollection::new(&this_ref));
273 }
274}
275
276impl InputElementImpl for Calendar {
277 fn on_pointer_released(this: &Self, e: &PointerReleasedEventArgs) {
278 Self::parent_on_pointer_released(this, e);
279 if !this.has_focus_internal() && e.initial_press_mouse_button() == MouseButton::Left {
280 this.focus();
281 }
282 }
283
284 fn on_pointer_wheel_changed(this: &Self, e: &PointerWheelEventArgs) {
286 Self::parent_on_pointer_wheel_changed(this, e);
287 if !e.handled() {
288 let (ctrl, shift) = CalendarExtensions::get_meta_key_state(e.key_modifiers());
289
290 if !ctrl {
291 if e.delta().y > 0.0 {
292 this.process_page_up_key(false);
293 } else {
294 this.process_page_down_key(false);
295 }
296 } else if e.delta().y > 0.0 {
297 this.process_down_key(ctrl, shift);
298 } else {
299 this.process_up_key(ctrl, shift);
300 }
301 e.set_handled(true);
302 }
303 }
304
305 fn on_got_focus(this: &Self, e: &FocusChangedEventArgs) {
306 Self::parent_on_got_focus(this, e);
307 this.has_focus_internal.set(true);
308
309 match this.display_mode() {
310 CalendarMode::Month => {
311 let focus_date;
312 match this.last_selected_date() {
313 Some(last_selected_date)
314 if DateTimeHelper::compare_year_month(this.display_date_internal(), last_selected_date) == 0 =>
315 {
316 focus_date = last_selected_date;
317 }
318 _ => {
319 focus_date = this.display_date();
320 this.set_last_selected_date(Some(this.display_date()));
321 }
322 }
323 let focus_button = this.find_day_button_from_day(focus_date);
324 this.set_focus_button(focus_button.clone());
325
326 if let Some(focus_button) = focus_button {
327 focus_button.set_is_current(true);
328 }
329 }
330 CalendarMode::Year | CalendarMode::Decade => {
331 if let Some(focus_calendar_button) = this.focus_calendar_button() {
332 focus_calendar_button.set_is_calendar_button_focused(true);
333 }
334 }
335 }
336 }
337
338 fn on_lost_focus(this: &Self, e: &FocusChangedEventArgs) {
339 Self::parent_on_lost_focus(this, e);
340 this.has_focus_internal.set(false);
341
342 match this.display_mode() {
343 CalendarMode::Month => {
344 if let Some(focus_button) = this.focus_button() {
345 focus_button.set_is_current(false);
346 }
347 }
348 CalendarMode::Year | CalendarMode::Decade => {
349 if let Some(focus_calendar_button) = this.focus_calendar_button() {
350 focus_calendar_button.set_is_calendar_button_focused(false);
351 }
352 }
353 }
354 }
355}
356
357impl TemplatedControlImpl for Calendar {
358 fn on_apply_template(this: &Self, e: &TemplateAppliedEventArgs) {
361 let root = e.name_scope().find_as::<Panel>(PART_ELEMENT_ROOT);
362 *this.root.borrow_mut() = root.clone();
363
364 this.set_selected_month(this.display_date());
365 this.set_selected_year(this.display_date());
366
367 if root.is_some() {
368 let month = e.name_scope().find_as::<CalendarItem>(PART_ELEMENT_MONTH);
369
370 if let Some(month) = month {
371 month.set_owner(Some(&this.to_ref()));
372 }
373 }
374 }
375}
376
377impl ControlImpl for Calendar {
378 fn on_create_automation_peer(this: &Self) -> Ref<crate::automation::peers::AutomationPeer> {
379 crate::automation::peers::CalendarAutomationPeer::new(this).upcast()
380 }
381}
382
383ferro_properties! {
384 impl Calendar {
385 pub fn first_day_of_week_property() -> StyledProperty<DayOfWeek> {
387 FerroProperty::register::<Calendar, _>(
388 "FirstDayOfWeek",
389 DateTimeHelper::get_current_date_format().first_day_of_week(),
390 )
391 }
392
393 pub fn is_today_highlighted_property() -> StyledProperty<bool> {
395 FerroProperty::register::<Calendar, _>("IsTodayHighlighted", true)
396 }
397
398 pub fn header_background_property() -> StyledProperty<Option<Rc<dyn IBrush>>> {
400 FerroProperty::register::<Calendar, _>("HeaderBackground", None)
401 }
402
403 pub fn is_week_number_visible_property() -> StyledProperty<bool> {
405 FerroProperty::register::<Calendar, _>("IsWeekNumberVisible", false)
406 }
407
408 pub fn week_number_rule_property() -> StyledProperty<CalendarWeekRule> {
410 FerroProperty::register::<Calendar, _>(
411 "WeekNumberRule",
412 DateTimeHelper::get_current_date_format().calendar_week_rule(),
413 )
414 }
415
416 pub fn display_mode_property() -> StyledProperty<CalendarMode> {
418 FerroProperty::register_with::<Calendar, _>(
419 "DisplayMode",
420 StyledPropertyOptions::new(CalendarMode::Month).validate(Calendar::is_valid_display_mode),
421 )
422 }
423
424 pub fn selection_mode_property() -> StyledProperty<CalendarSelectionMode> {
426 FerroProperty::register::<Calendar, _>("SelectionMode", CalendarSelectionMode::SingleDate)
427 }
428
429 pub fn allow_tap_range_selection_property() -> StyledProperty<bool> {
431 FerroProperty::register::<Calendar, _>("AllowTapRangeSelection", true)
432 }
433
434 pub fn selected_date_property() -> StyledProperty<Option<DateTime>> {
436 FerroProperty::register_with::<Calendar, _>(
437 "SelectedDate",
438 StyledPropertyOptions::new(None).default_binding_mode(BindingMode::TwoWay),
439 )
440 }
441
442 pub fn display_date_property() -> StyledProperty<DateTime> {
444 FerroProperty::register_with::<Calendar, _>(
445 "DisplayDate",
446 StyledPropertyOptions::new(DateTime::MIN_VALUE).default_binding_mode(BindingMode::TwoWay),
447 )
448 }
449
450 pub fn display_date_start_property() -> StyledProperty<Option<DateTime>> {
452 FerroProperty::register_with::<Calendar, _>(
453 "DisplayDateStart",
454 StyledPropertyOptions::new(None).default_binding_mode(BindingMode::TwoWay),
455 )
456 }
457
458 pub fn display_date_end_property() -> StyledProperty<Option<DateTime>> {
460 FerroProperty::register_with::<Calendar, _>(
461 "DisplayDateEnd",
462 StyledPropertyOptions::new(None).default_binding_mode(BindingMode::TwoWay),
463 )
464 }
465 }
466}
467
468impl Calendar {
469 pub(crate) const ROWS_PER_MONTH: i32 = 7;
470 pub(crate) const COLUMNS_PER_MONTH: i32 = 7;
471 pub(crate) const ROWS_PER_YEAR: i32 = 3;
472 pub(crate) const COLUMNS_PER_YEAR: i32 = 4;
473
474 fn static_constructor() {
475 InputElement::is_enabled_property()
476 .changed()
477 .add_class_handler::<Calendar>(|x, e| x.on_is_enabled_changed(e.get_new_value::<bool>()));
478 Self::first_day_of_week_property()
479 .changed()
480 .add_class_handler::<Calendar>(|x, e| x.on_first_day_of_week_changed(e.get_new_value::<DayOfWeek>()));
481 Self::is_today_highlighted_property()
482 .changed()
483 .add_class_handler::<Calendar>(|x, _| x.on_is_today_highlighted_changed());
484 Self::display_mode_property().changed().add_class_handler::<Calendar>(|x, e| {
485 let (old_mode, mode) = e.get_old_and_new_value::<CalendarMode>();
486 x.on_display_mode_property_changed(old_mode, mode);
487 });
488 Self::selection_mode_property().changed().add_class_handler::<Calendar>(|x, e| {
489 x.on_selection_mode_changed(e.get_new_value::<CalendarSelectionMode>())
490 });
491 Self::allow_tap_range_selection_property()
492 .changed()
493 .add_class_handler::<Calendar>(|x, _| x.on_allow_tap_range_selection_changed());
494 Self::selected_date_property()
495 .changed()
496 .add_class_handler::<Calendar>(|x, e| x.on_selected_date_changed(e.get_new_value::<Option<DateTime>>()));
497 Self::display_date_property().changed().add_class_handler::<Calendar>(|x, e| {
498 let (old_value, new_value) = e.get_old_and_new_value::<DateTime>();
499 x.on_display_date_changed(new_value, old_value);
500 });
501 Self::display_date_start_property().changed().add_class_handler::<Calendar>(|x, e| {
502 x.on_display_date_start_changed(e.get_new_value::<Option<DateTime>>())
503 });
504 Self::display_date_end_property()
505 .changed()
506 .add_class_handler::<Calendar>(|x, e| x.on_display_date_end_changed(e.get_new_value::<Option<DateTime>>()));
507 Self::is_week_number_visible_property().changed().add_class_handler::<Calendar>(|x, _| x.update_months());
508 Self::week_number_rule_property().changed().add_class_handler::<Calendar>(|x, _| x.update_months());
509 InputElement::key_down_event().add_class_handler::<Calendar>(|x, e| x.calendar_key_down(e));
510 InputElement::key_up_event().add_class_handler::<Calendar>(|x, e| x.calendar_key_up(e));
511 }
512
513 pub fn construct() -> Self {
515 Self {
516 base: TemplatedControl::construct(),
517 selected_month: Cell::new(DateTime::MIN_VALUE),
518 selected_year: Cell::new(DateTime::MIN_VALUE),
519 is_shift_pressed: Cell::new(false),
520 display_date_is_changing: Cell::new(false),
521 is_tap_range_selection_active: Cell::new(false),
522 tap_range_start: Cell::new(None),
523 focus_button: RefCell::new(None),
524 focus_calendar_button: RefCell::new(None),
525 root: RefCell::new(None),
526 selected_dates: OnceCell::new(),
527 blackout_dates: OnceCell::new(),
528 removed_items: RefCell::new(Vec::new()),
529 last_selected_date_internal: Cell::new(None),
530 display_date_internal: Cell::new(DateTime::MIN_VALUE),
531 hover_start: Cell::new(None),
532 hover_start_index: Cell::new(None),
533 hover_end_internal: Cell::new(None),
534 hover_end_index: Cell::new(None),
535 has_focus_internal: Cell::new(false),
536 is_mouse_selection: Cell::new(false),
537 calendar_date_picker_display_date_flag: Cell::new(false),
538 selected_dates_changed: HandlerList::new(),
539 display_date_changed: HandlerList::new(),
540 display_mode_changed: HandlerList::new(),
541 day_button_mouse_up: HandlerList::new(),
542 }
543 }
544
545 pub fn new() -> Ref<Self> {
547 instantiate(Self::construct())
548 }
549
550 pub(crate) fn focus_button(&self) -> Option<Ref<CalendarDayButton>> {
551 self.focus_button.borrow().clone()
552 }
553
554 pub(crate) fn set_focus_button(&self, value: Option<Ref<CalendarDayButton>>) {
555 *self.focus_button.borrow_mut() = value;
556 }
557
558 pub(crate) fn focus_calendar_button(&self) -> Option<Ref<CalendarButton>> {
559 self.focus_calendar_button.borrow().clone()
560 }
561
562 pub(crate) fn set_focus_calendar_button(&self, value: Option<Ref<CalendarButton>>) {
563 *self.focus_calendar_button.borrow_mut() = value;
564 }
565
566 pub(crate) fn root(&self) -> Option<Ref<Panel>> {
567 self.root.borrow().clone()
568 }
569
570 pub(crate) fn set_root(&self, value: Option<Ref<Panel>>) {
571 *self.root.borrow_mut() = value;
572 }
573
574 pub(crate) fn month_control(&self) -> Option<Ref<CalendarItem>> {
575 let root = self.root()?;
576 if root.children().count() > 0 {
577 return root.children().get(0).cast::<CalendarItem>();
578 }
579 None
580 }
581
582 pub fn first_day_of_week(&self) -> DayOfWeek {
586 self.get_value(Self::first_day_of_week_property())
587 }
588
589 pub fn set_first_day_of_week(&self, value: DayOfWeek) {
590 self.set_value(Self::first_day_of_week_property(), value)
591 }
592
593 fn on_first_day_of_week_changed(&self, new_value: DayOfWeek) {
595 if Self::is_valid_first_day_of_week(new_value) {
596 self.update_months();
597 } else {
598 panic!("Invalid DayOfWeek (Parameter 'e')");
599 }
600 }
601
602 fn is_valid_first_day_of_week(day: DayOfWeek) -> bool {
605 matches!(
606 day,
607 DayOfWeek::Sunday
608 | DayOfWeek::Monday
609 | DayOfWeek::Tuesday
610 | DayOfWeek::Wednesday
611 | DayOfWeek::Thursday
612 | DayOfWeek::Friday
613 | DayOfWeek::Saturday
614 )
615 }
616
617 pub fn is_today_highlighted(&self) -> bool {
620 self.get_value(Self::is_today_highlighted_property())
621 }
622
623 pub fn set_is_today_highlighted(&self, value: bool) {
624 self.set_value(Self::is_today_highlighted_property(), value)
625 }
626
627 fn on_is_today_highlighted_changed(&self) {
629 let i = DateTimeHelper::compare_year_month(self.display_date_internal(), DateTime::today());
630
631 if i > -2 && i < 2 {
632 self.update_months();
633 }
634 }
635
636 pub fn header_background(&self) -> Option<Rc<dyn IBrush>> {
638 self.get_value(Self::header_background_property())
639 }
640
641 pub fn set_header_background(&self, value: Option<Rc<dyn IBrush>>) {
642 self.set_value(Self::header_background_property(), value)
643 }
644
645 pub fn is_week_number_visible(&self) -> bool {
648 self.get_value(Self::is_week_number_visible_property())
649 }
650
651 pub fn set_is_week_number_visible(&self, value: bool) {
652 self.set_value(Self::is_week_number_visible_property(), value)
653 }
654
655 pub fn week_number_rule(&self) -> CalendarWeekRule {
663 self.get_value(Self::week_number_rule_property())
664 }
665
666 pub fn set_week_number_rule(&self, value: CalendarWeekRule) {
667 self.set_value(Self::week_number_rule_property(), value)
668 }
669
670 pub fn display_mode(&self) -> CalendarMode {
673 self.get_value(Self::display_mode_property())
674 }
675
676 pub fn set_display_mode(&self, value: CalendarMode) {
677 self.set_value(Self::display_mode_property(), value)
678 }
679
680 fn on_display_mode_property_changed(&self, old_mode: CalendarMode, mode: CalendarMode) {
682 let month_control = self.month_control();
683
684 if month_control.is_some() {
685 match old_mode {
686 CalendarMode::Month => {
687 self.set_selected_year(self.display_date_internal());
688 self.set_selected_month(self.display_date_internal());
689 }
690 CalendarMode::Year => {
691 self.set_current_value(Self::display_date_property(), self.selected_month());
692 self.set_selected_year(self.selected_month());
693 }
694 CalendarMode::Decade => {
695 self.set_current_value(Self::display_date_property(), self.selected_year());
696 self.set_selected_month(self.selected_year());
697 }
698 }
699
700 match mode {
701 CalendarMode::Month => self.on_month_click(),
702 CalendarMode::Year | CalendarMode::Decade => self.on_header_click(),
703 }
704 }
705 if let Some(month_control) = &month_control {
706 month_control.update_week_number_labels_visibility();
707 }
708 self.on_display_mode_changed(&CalendarModeChangedEventArgs::new(old_mode, mode));
709 }
710
711 fn is_valid_display_mode(mode: &CalendarMode) -> bool {
712 matches!(mode, CalendarMode::Month | CalendarMode::Year | CalendarMode::Decade)
713 }
714
715 fn on_display_mode_changed(&self, args: &CalendarModeChangedEventArgs) {
716 for (_, handler) in self.display_mode_changed.snapshot().iter() {
717 handler(args);
718 }
719 }
720
721 pub fn selection_mode(&self) -> CalendarSelectionMode {
729 self.get_value(Self::selection_mode_property())
730 }
731
732 pub fn set_selection_mode(&self, value: CalendarSelectionMode) {
733 self.set_value(Self::selection_mode_property(), value)
734 }
735
736 pub fn allow_tap_range_selection(&self) -> bool {
745 self.get_value(Self::allow_tap_range_selection_property())
746 }
747
748 pub fn set_allow_tap_range_selection(&self, value: bool) {
749 self.set_value(Self::allow_tap_range_selection_property(), value)
750 }
751
752 fn on_selection_mode_changed(&self, new_value: CalendarSelectionMode) {
753 if Self::is_valid_selection_mode(new_value) {
754 self.display_date_is_changing.set(true);
755 self.set_current_value(Self::selected_date_property(), None);
756 self.display_date_is_changing.set(false);
757 self.selected_dates().clear();
758
759 self.is_tap_range_selection_active.set(false);
761 self.tap_range_start.set(None);
762 } else {
763 panic!("Invalid SelectionMode (Parameter 'e')");
764 }
765 }
766
767 fn on_allow_tap_range_selection_changed(&self) {
768 self.is_tap_range_selection_active.set(false);
769 self.tap_range_start.set(None);
770 }
771
772 fn is_valid_selection_mode(mode: CalendarSelectionMode) -> bool {
775 matches!(
776 mode,
777 CalendarSelectionMode::SingleDate
778 | CalendarSelectionMode::SingleRange
779 | CalendarSelectionMode::MultipleRange
780 | CalendarSelectionMode::None
781 )
782 }
783
784 pub fn selected_date(&self) -> Option<DateTime> {
793 self.get_value(Self::selected_date_property())
794 }
795
796 pub fn set_selected_date(&self, value: Option<DateTime>) {
797 self.set_value(Self::selected_date_property(), value)
798 }
799
800 fn on_selected_date_changed(&self, added_date: Option<DateTime>) {
801 if !self.display_date_is_changing.get() {
802 if self.selection_mode() != CalendarSelectionMode::None {
803 if Self::is_valid_date_selection(self, added_date) {
804 let selected_dates = self.selected_dates();
805 match added_date {
806 None => selected_dates.clear(),
807 Some(added_date) => {
808 if !(selected_dates.count() > 0 && selected_dates.get(0) == added_date) {
809 self.add_removed_items(&selected_dates.to_vec());
810 selected_dates.clear_internal();
811 selected_dates.add_range(added_date, added_date);
815 }
816 }
817 }
818
819 if self.selection_mode() == CalendarSelectionMode::SingleDate {
823 self.set_last_selected_date(added_date);
824 }
825 } else {
826 panic!("SelectedDate value is not valid. (Parameter 'e')");
827 }
828 } else {
829 panic!("The SelectedDate property cannot be set when the selection mode is None.");
830 }
831 }
832 }
833
834 pub fn selected_dates(&self) -> SelectedDatesCollection {
873 self.selected_dates.get().expect("the calendar is constructed").clone()
874 }
875
876 fn is_selection_changed(e: &SelectionChangedEventArgs) -> bool {
877 if e.added_items().len() != e.removed_items().len() {
878 return true;
879 }
880 for added_date in e.added_items() {
881 let added_date = date_of_item(added_date);
882 if !e.removed_items().iter().any(|removed_date| date_of_item(removed_date) == added_date) {
883 return true;
884 }
885 }
886 false
887 }
888
889 pub(crate) fn on_selected_dates_collection_changed(&self, e: &SelectionChangedEventArgs) {
890 if Self::is_selection_changed(e) {
891 e.set_routed_event(Some(SelectingItemsControl::selection_changed_event()));
892 e.set_source(self.to_ref());
893 for (_, handler) in self.selected_dates_changed.snapshot().iter() {
894 handler(e);
895 }
896 }
897 }
898
899 pub(crate) fn removed_items(&self) -> Vec<DateTime> {
902 self.removed_items.borrow().clone()
903 }
904
905 pub(crate) fn add_removed_items(&self, items: &[DateTime]) {
906 self.removed_items.borrow_mut().extend_from_slice(items);
907 }
908
909 pub(crate) fn clear_removed_items(&self) {
910 self.removed_items.borrow_mut().clear();
911 }
912
913 pub(crate) fn last_selected_date_internal(&self) -> Option<DateTime> {
914 self.last_selected_date_internal.get()
915 }
916
917 pub(crate) fn last_selected_date(&self) -> Option<DateTime> {
918 self.last_selected_date_internal()
919 }
920
921 pub(crate) fn set_last_selected_date(&self, value: Option<DateTime>) {
922 self.last_selected_date_internal.set(value);
923
924 if self.selection_mode() == CalendarSelectionMode::None {
925 if let Some(focus_button) = self.focus_button() {
926 focus_button.set_is_current(false);
927 }
928 let focus_button = self
929 .find_day_button_from_day(self.last_selected_date().expect("Nullable object must have a value."));
930 self.set_focus_button(focus_button.clone());
931 if let Some(focus_button) = focus_button {
932 focus_button.set_is_current(self.has_focus_internal());
933 }
934 }
935 }
936
937 pub(crate) fn selected_month(&self) -> DateTime {
938 self.selected_month.get()
939 }
940
941 pub(crate) fn set_selected_month(&self, value: DateTime) {
942 let month_difference_start = DateTimeHelper::compare_year_month(value, self.display_date_range_start());
943 let month_difference_end = DateTimeHelper::compare_year_month(value, self.display_date_range_end());
944
945 if month_difference_start >= 0 && month_difference_end <= 0 {
946 self.selected_month.set(DateTimeHelper::discard_day_time(value));
947 } else if month_difference_start < 0 {
948 self.selected_month.set(DateTimeHelper::discard_day_time(self.display_date_range_start()));
949 } else {
950 debug_assert!(month_difference_end > 0, "monthDifferenceEnd should be greater than 0!");
951 self.selected_month.set(DateTimeHelper::discard_day_time(self.display_date_range_end()));
952 }
953 }
954
955 pub(crate) fn selected_year(&self) -> DateTime {
956 self.selected_year.get()
957 }
958
959 pub(crate) fn set_selected_year(&self, value: DateTime) {
960 if value.year() < self.display_date_range_start().year() {
961 self.selected_year.set(self.display_date_range_start());
962 } else if value.year() > self.display_date_range_end().year() {
963 self.selected_year.set(self.display_date_range_end());
964 } else {
965 self.selected_year.set(value);
966 }
967 }
968
969 pub fn display_date(&self) -> DateTime {
975 self.get_value(Self::display_date_property())
976 }
977
978 pub fn set_display_date(&self, value: DateTime) {
979 self.set_value(Self::display_date_property(), value)
980 }
981
982 pub(crate) fn display_date_internal(&self) -> DateTime {
983 self.display_date_internal.get()
984 }
985
986 fn on_display_date_changed(&self, new_value: DateTime, old_value: DateTime) {
987 Self::update_display_date(self, new_value, old_value);
988 }
989
990 fn update_display_date(c: &Calendar, added_date: DateTime, removed_date: DateTime) {
991 if DateTime::compare(added_date, c.display_date_range_start()) < 0 {
993 c.set_display_date(c.display_date_range_start());
994 return;
995 }
996
997 if DateTime::compare(added_date, c.display_date_range_end()) > 0 {
999 c.set_display_date(c.display_date_range_end());
1000 return;
1001 }
1002
1003 c.display_date_internal.set(DateTimeHelper::discard_day_time(added_date));
1004 c.update_months();
1005 c.on_display_date(&CalendarDateChangedEventArgs::new(Some(removed_date), Some(added_date)));
1006 }
1007
1008 fn on_display_date(&self, e: &CalendarDateChangedEventArgs) {
1009 for (_, handler) in self.display_date_changed.snapshot().iter() {
1010 handler(e);
1011 }
1012 }
1013
1014 pub fn display_date_start(&self) -> Option<DateTime> {
1016 self.get_value(Self::display_date_start_property())
1017 }
1018
1019 pub fn set_display_date_start(&self, value: Option<DateTime>) {
1020 self.set_value(Self::display_date_start_property(), value)
1021 }
1022
1023 fn on_display_date_start_changed(&self, new_value: Option<DateTime>) {
1024 if !self.display_date_is_changing.get() {
1025 if let Some(new_value) = new_value {
1026 let selected_date_min = Self::selected_date_min(self);
1029
1030 if let Some(selected_date_min) = selected_date_min {
1031 if DateTime::compare(selected_date_min, new_value) < 0 {
1032 self.set_current_value(Self::display_date_start_property(), Some(selected_date_min));
1033 return;
1034 }
1035 }
1036
1037 if DateTime::compare(new_value, self.display_date_range_end()) > 0 {
1040 self.set_current_value(Self::display_date_end_property(), self.display_date_start());
1041 }
1042
1043 if DateTimeHelper::compare_year_month(new_value, self.display_date_internal()) > 0 {
1046 self.set_current_value(Self::display_date_property(), new_value);
1047 }
1048 }
1049 self.update_months();
1050 }
1051 }
1052
1053 pub fn blackout_dates(&self) -> CalendarBlackoutDatesCollection {
1065 self.blackout_dates.get().expect("the calendar is constructed").clone()
1066 }
1067
1068 fn selected_date_min(cal: &Calendar) -> Option<DateTime> {
1069 let selected_dates = cal.selected_dates().to_vec();
1070 let mut selected_date_min = *selected_dates.first()?;
1071 debug_assert!(
1072 cal.selected_date().is_some_and(|selected| DateTime::compare(selected, selected_date_min) == 0),
1073 "The SelectedDate should be the minimum selected date!"
1074 );
1075
1076 for selected_date in selected_dates {
1077 if DateTime::compare(selected_date, selected_date_min) < 0 {
1078 selected_date_min = selected_date;
1079 }
1080 }
1081 Some(selected_date_min)
1082 }
1083
1084 pub(crate) fn display_date_range_start(&self) -> DateTime {
1085 self.display_date_start().unwrap_or(DateTime::MIN_VALUE)
1086 }
1087
1088 pub fn display_date_end(&self) -> Option<DateTime> {
1090 self.get_value(Self::display_date_end_property())
1091 }
1092
1093 pub fn set_display_date_end(&self, value: Option<DateTime>) {
1094 self.set_value(Self::display_date_end_property(), value)
1095 }
1096
1097 fn on_display_date_end_changed(&self, new_value: Option<DateTime>) {
1098 if !self.display_date_is_changing.get() {
1099 if let Some(new_value) = new_value {
1100 let selected_date_max = Self::selected_date_max(self);
1103
1104 if let Some(selected_date_max) = selected_date_max {
1105 if DateTime::compare(selected_date_max, new_value) > 0 {
1106 self.set_current_value(Self::display_date_end_property(), Some(selected_date_max));
1107 return;
1108 }
1109 }
1110
1111 if DateTime::compare(new_value, self.display_date_range_start()) < 0 {
1114 self.set_current_value(Self::display_date_end_property(), self.display_date_start());
1115 return;
1116 }
1117
1118 if DateTimeHelper::compare_year_month(new_value, self.display_date_internal()) < 0 {
1121 self.set_current_value(Self::display_date_property(), new_value);
1122 }
1123 }
1124 self.update_months();
1125 }
1126 }
1127
1128 fn selected_date_max(cal: &Calendar) -> Option<DateTime> {
1129 let selected_dates = cal.selected_dates().to_vec();
1130 let mut selected_date_max = *selected_dates.first()?;
1131 debug_assert!(
1132 cal.selected_date().is_some_and(|selected| DateTime::compare(selected, selected_date_max) == 0),
1133 "The SelectedDate should be the maximum SelectedDate!"
1134 );
1135
1136 for selected_date in selected_dates {
1137 if DateTime::compare(selected_date, selected_date_max) > 0 {
1138 selected_date_max = selected_date;
1139 }
1140 }
1141 Some(selected_date_max)
1142 }
1143
1144 pub(crate) fn display_date_range_end(&self) -> DateTime {
1145 self.display_date_end().unwrap_or(DateTime::MAX_VALUE)
1146 }
1147
1148 pub(crate) fn hover_start(&self) -> Option<DateTime> {
1149 self.hover_start.get()
1150 }
1151
1152 pub(crate) fn set_hover_start(&self, value: Option<DateTime>) {
1153 self.hover_start.set(value);
1154 }
1155
1156 pub(crate) fn hover_start_index(&self) -> Option<i32> {
1157 self.hover_start_index.get()
1158 }
1159
1160 pub(crate) fn set_hover_start_index(&self, value: Option<i32>) {
1161 self.hover_start_index.set(value);
1162 }
1163
1164 pub(crate) fn hover_end_internal(&self) -> Option<DateTime> {
1165 self.hover_end_internal.get()
1166 }
1167
1168 pub(crate) fn hover_end(&self) -> Option<DateTime> {
1169 self.hover_end_internal()
1170 }
1171
1172 pub(crate) fn set_hover_end(&self, value: Option<DateTime>) {
1173 self.hover_end_internal.set(value);
1174 self.set_last_selected_date(value);
1175 }
1176
1177 pub(crate) fn hover_end_index(&self) -> Option<i32> {
1178 self.hover_end_index.get()
1179 }
1180
1181 pub(crate) fn set_hover_end_index(&self, value: Option<i32>) {
1182 self.hover_end_index.set(value);
1183 }
1184
1185 pub(crate) fn has_focus_internal(&self) -> bool {
1186 self.has_focus_internal.get()
1187 }
1188
1189 pub(crate) fn is_mouse_selection(&self) -> bool {
1190 self.is_mouse_selection.get()
1191 }
1192
1193 pub(crate) fn set_is_mouse_selection(&self, value: bool) {
1194 self.is_mouse_selection.set(value);
1195 }
1196
1197 pub(crate) fn calendar_date_picker_display_date_flag(&self) -> bool {
1200 self.calendar_date_picker_display_date_flag.get()
1201 }
1202
1203 pub(crate) fn set_calendar_date_picker_display_date_flag(&self, value: bool) {
1204 self.calendar_date_picker_display_date_flag.set(value);
1205 }
1206
1207 pub(crate) fn find_day_button_from_day(&self, day: DateTime) -> Option<Ref<CalendarDayButton>> {
1208 let month_control = self.month_control();
1209
1210 let count = Self::ROWS_PER_MONTH * Self::COLUMNS_PER_MONTH;
1212 if let Some(month_view) = month_control.and_then(|month_control| month_control.month_view()) {
1213 for child_index in Self::COLUMNS_PER_MONTH..count {
1214 if let Some(b) = month_view.children().get(child_index as usize).cast::<CalendarDayButton>() {
1215 if let Some(d) = date_of(&b) {
1216 if DateTimeHelper::compare_days(d, day) == 0 {
1217 return Some(b);
1218 }
1219 }
1220 }
1221 }
1222 }
1223 None
1224 }
1225
1226 fn on_selected_month_changed(&self, selected_month: Option<DateTime>) {
1227 if let Some(selected_month) = selected_month {
1228 debug_assert!(self.display_mode() == CalendarMode::Year, "DisplayMode should be Year!");
1229 self.set_selected_month(selected_month);
1230 self.update_months();
1231 }
1232 }
1233
1234 fn on_selected_year_changed(&self, selected_year: Option<DateTime>) {
1235 if let Some(selected_year) = selected_year {
1236 debug_assert!(self.display_mode() == CalendarMode::Decade, "DisplayMode should be Decade!");
1237 self.set_selected_year(selected_year);
1238 self.update_months();
1239 }
1240 }
1241
1242 pub(crate) fn on_header_click(&self) {
1243 debug_assert!(
1244 self.display_mode() == CalendarMode::Year || self.display_mode() == CalendarMode::Decade,
1245 "The DisplayMode should be Year or Decade"
1246 );
1247 if let Some(month_control) = self.month_control() {
1248 if let (Some(month_view), Some(year_view)) = (month_control.month_view(), month_control.year_view()) {
1249 month_view.set_is_visible(false);
1250 year_view.set_is_visible(true);
1251 self.update_months();
1252 }
1253 }
1254 }
1255
1256 pub(crate) fn reset_states(&self) {
1257 let month_control = self.month_control();
1258 let count = Self::ROWS_PER_MONTH * Self::COLUMNS_PER_MONTH;
1259 if let Some(month_view) = month_control.and_then(|month_control| month_control.month_view()) {
1260 for child_index in Self::COLUMNS_PER_MONTH..count {
1261 let d = month_view
1262 .children()
1263 .get(child_index as usize)
1264 .cast::<CalendarDayButton>()
1265 .expect("the child of the month view is a CalendarDayButton");
1266 d.ignore_mouse_over_state();
1267 }
1268 }
1269 }
1270
1271 pub(crate) fn update_months(&self) {
1272 if let Some(month_control) = self.month_control() {
1273 match self.display_mode() {
1274 CalendarMode::Month => month_control.update_month_mode(),
1275 CalendarMode::Year => month_control.update_year_mode(),
1276 CalendarMode::Decade => month_control.update_decade_mode(),
1277 }
1278 }
1279 }
1280
1281 pub(crate) fn is_valid_date_selection(cal: &Calendar, value: Option<DateTime>) -> bool {
1282 let Some(value) = value else {
1283 return true;
1284 };
1285
1286 if cal.blackout_dates().contains_date(value) {
1287 false
1288 } else {
1289 cal.display_date_is_changing.set(true);
1290 if DateTime::compare(value, cal.display_date_range_start()) < 0 {
1291 cal.set_display_date_start(Some(value));
1292 } else if DateTime::compare(value, cal.display_date_range_end()) > 0 {
1293 cal.set_display_date_end(Some(value));
1294 }
1295 cal.display_date_is_changing.set(false);
1296
1297 true
1298 }
1299 }
1300
1301 fn is_valid_keyboard_selection(cal: &Calendar, value: Option<DateTime>) -> bool {
1302 let Some(value) = value else {
1303 return true;
1304 };
1305
1306 if cal.blackout_dates().contains_date(value) {
1307 false
1308 } else {
1309 DateTime::compare(value, cal.display_date_range_start()) >= 0
1310 && DateTime::compare(value, cal.display_date_range_end()) <= 0
1311 }
1312 }
1313
1314 pub(crate) fn highlight_days(&self) {
1317 if let (Some(hover_end), Some(_)) = (self.hover_end(), self.hover_start()) {
1318 let month_control = self.month_control();
1319 debug_assert!(month_control.is_some());
1320
1321 if self.hover_end_index().is_some() && self.hover_start_index().is_some() {
1323 let month_view = month_control
1324 .and_then(|month_control| month_control.month_view())
1325 .expect("the calendar has a month view");
1326 let (start_index, end_index) = self.sort_hover_indexes();
1327
1328 for i in start_index..=end_index {
1329 if let Some(b) = month_view.children().get(i as usize).cast::<CalendarDayButton>() {
1330 b.set_is_selected(true);
1331
1332 if date_of(&b).is_some_and(|d| DateTimeHelper::compare_days(hover_end, d) == 0) {
1333 if let Some(focus_button) = self.focus_button() {
1334 focus_button.set_is_current(false);
1335 }
1336 b.set_is_current(self.has_focus_internal());
1337 self.set_focus_button(Some(b));
1338 }
1339 }
1340 }
1341 }
1342 }
1343 }
1344
1345 pub(crate) fn un_highlight_days(&self) {
1349 if self.hover_end().is_some() && self.hover_start().is_some() {
1350 let month_control = self.month_control();
1351 debug_assert!(month_control.is_some());
1352
1353 if self.hover_end_index().is_some() && self.hover_start_index().is_some() {
1354 let month_view = month_control
1355 .and_then(|month_control| month_control.month_view())
1356 .expect("the calendar has a month view");
1357 let (start_index, end_index) = self.sort_hover_indexes();
1358
1359 if self.selection_mode() == CalendarSelectionMode::MultipleRange {
1360 for i in start_index..=end_index {
1361 if let Some(b) = month_view.children().get(i as usize).cast::<CalendarDayButton>() {
1362 if let Some(d) = date_of(&b) {
1363 if !self.selected_dates().contains(d) {
1364 b.set_is_selected(false);
1365 }
1366 }
1367 }
1368 }
1369 } else {
1370 for i in start_index..=end_index {
1372 month_view
1373 .children()
1374 .get(i as usize)
1375 .cast::<CalendarDayButton>()
1376 .expect("the child of the month view is a CalendarDayButton")
1377 .set_is_selected(false);
1378 }
1379 }
1380 }
1381 }
1382 }
1383
1384 pub(crate) fn sort_hover_indexes(&self) -> (i32, i32) {
1387 let hover_start = self.hover_start().expect("the hover range has a start");
1388 let hover_end = self.hover_end().expect("the hover range has an end");
1389 let hover_start_index = self.hover_start_index().expect("the hover range has a start index");
1390 let hover_end_index = self.hover_end_index().expect("the hover range has an end index");
1391
1392 if DateTimeHelper::compare_days(hover_end, hover_start) > 0 {
1393 (hover_start_index, hover_end_index)
1394 } else {
1395 (hover_end_index, hover_start_index)
1396 }
1397 }
1398
1399 pub(crate) fn on_previous_click(&self) {
1400 if self.display_mode() == CalendarMode::Month {
1401 let d = DateTimeHelper::add_months(DateTimeHelper::discard_day_time(self.display_date()), -1);
1402 if let Some(d) = d {
1403 if !self
1404 .last_selected_date()
1405 .is_some_and(|last_selected_date| DateTimeHelper::compare_year_month(last_selected_date, d) == 0)
1406 {
1407 self.set_last_selected_date(Some(d));
1408 }
1409 self.set_current_value(Self::display_date_property(), d);
1410 }
1411 } else {
1412 if self.display_mode() == CalendarMode::Year {
1413 let d = DateTimeHelper::add_years(DateTime::new(self.selected_month().year(), 1, 1), -1);
1414
1415 match d {
1416 Some(d) => self.set_selected_month(d),
1417 None => self.set_selected_month(DateTimeHelper::discard_day_time(self.display_date_range_start())),
1418 }
1419 } else {
1420 debug_assert!(self.display_mode() == CalendarMode::Decade, "DisplayMode should be Decade!");
1421
1422 let d = DateTimeHelper::add_years(DateTime::new(self.selected_year().year(), 1, 1), -10);
1423
1424 match d {
1425 Some(d) => {
1426 let decade = DateTimeHelper::decade_of_date(d).max(1);
1427 self.set_selected_year(DateTime::new(decade, 1, 1));
1428 }
1429 None => self.set_selected_year(DateTimeHelper::discard_day_time(self.display_date_range_start())),
1430 }
1431 }
1432 self.update_months();
1433 }
1434 }
1435
1436 pub(crate) fn on_next_click(&self) {
1437 if self.display_mode() == CalendarMode::Month {
1438 let d = DateTimeHelper::add_months(DateTimeHelper::discard_day_time(self.display_date()), 1);
1439 if let Some(d) = d {
1440 if !self
1441 .last_selected_date()
1442 .is_some_and(|last_selected_date| DateTimeHelper::compare_year_month(last_selected_date, d) == 0)
1443 {
1444 self.set_last_selected_date(Some(d));
1445 }
1446 self.set_current_value(Self::display_date_property(), d);
1447 }
1448 } else {
1449 if self.display_mode() == CalendarMode::Year {
1450 let d = DateTimeHelper::add_years(DateTime::new(self.selected_month().year(), 1, 1), 1);
1451
1452 match d {
1453 Some(d) => self.set_selected_month(d),
1454 None => self.set_selected_month(DateTimeHelper::discard_day_time(self.display_date_range_end())),
1455 }
1456 } else {
1457 debug_assert!(self.display_mode() == CalendarMode::Decade, "DisplayMode should be Decade");
1458
1459 let d = DateTimeHelper::add_years(DateTime::new(self.selected_year().year(), 1, 1), 10);
1460
1461 match d {
1462 Some(d) => {
1463 let decade = DateTimeHelper::decade_of_date(d).max(1);
1464 self.set_selected_year(DateTime::new(decade, 1, 1));
1465 }
1466 None => self.set_selected_year(DateTimeHelper::discard_day_time(self.display_date_range_end())),
1467 }
1468 }
1469 self.update_months();
1470 }
1471 }
1472
1473 pub(crate) fn on_day_click(&self, selected_date: DateTime) {
1475 debug_assert!(self.display_mode() == CalendarMode::Month, "DisplayMode should be Month!");
1476 let i = DateTimeHelper::compare_year_month(selected_date, self.display_date_internal());
1477
1478 if self.selection_mode() == CalendarSelectionMode::None {
1479 self.set_last_selected_date(Some(selected_date));
1480 }
1481
1482 if i > 0 {
1483 self.on_next_click();
1484 } else if i < 0 {
1485 self.on_previous_click();
1486 }
1487 }
1488
1489 fn on_month_click(&self) {
1490 let month_control = self.month_control();
1491 debug_assert!(month_control.is_some());
1492
1493 if let Some(month_control) = month_control {
1494 if let (Some(year_view), Some(month_view)) = (month_control.year_view(), month_control.month_view()) {
1495 year_view.set_is_visible(false);
1496 month_view.set_is_visible(true);
1497
1498 if !self.last_selected_date().is_some_and(|last_selected_date| {
1499 DateTimeHelper::compare_year_month(last_selected_date, self.display_date()) == 0
1500 }) {
1501 self.set_last_selected_date(Some(self.display_date()));
1502 }
1503
1504 self.update_months();
1505 }
1506 }
1507 }
1508
1509 pub fn selected_dates_changed(
1512 &self,
1513 handler: impl Fn(&SelectionChangedEventArgs) + 'static,
1514 ) -> Rc<dyn IDisposable> {
1515 let token = self.selected_dates_changed.add(Rc::new(handler));
1516 let weak = self.to_ref().downgrade();
1517 Disposable::create(move || {
1518 if let Some(this) = weak.upgrade() {
1519 this.selected_dates_changed.remove(token);
1520 }
1521 })
1522 }
1523
1524 pub fn display_date_changed(
1528 &self,
1529 handler: impl Fn(&CalendarDateChangedEventArgs) + 'static,
1530 ) -> Rc<dyn IDisposable> {
1531 let token = self.display_date_changed.add(Rc::new(handler));
1532 let weak = self.to_ref().downgrade();
1533 Disposable::create(move || {
1534 if let Some(this) = weak.upgrade() {
1535 this.display_date_changed.remove(token);
1536 }
1537 })
1538 }
1539
1540 pub fn display_mode_changed(
1542 &self,
1543 handler: impl Fn(&CalendarModeChangedEventArgs) + 'static,
1544 ) -> Rc<dyn IDisposable> {
1545 let token = self.display_mode_changed.add(Rc::new(handler));
1546 let weak = self.to_ref().downgrade();
1547 Disposable::create(move || {
1548 if let Some(this) = weak.upgrade() {
1549 this.display_mode_changed.remove(token);
1550 }
1551 })
1552 }
1553
1554 pub(crate) fn day_button_mouse_up(
1557 &self,
1558 handler: impl Fn(&PointerReleasedEventArgs) + 'static,
1559 ) -> Rc<dyn IDisposable> {
1560 let token = self.day_button_mouse_up.add(Rc::new(handler));
1561 let weak = self.to_ref().downgrade();
1562 Disposable::create(move || {
1563 if let Some(this) = weak.upgrade() {
1564 this.day_button_mouse_up.remove(token);
1565 }
1566 })
1567 }
1568
1569 fn add_selection(&self) {
1572 if let (Some(hover_end), Some(hover_start)) = (self.hover_end(), self.hover_start()) {
1573 let selected_dates = self.selected_dates();
1574 self.add_removed_items(&selected_dates.to_vec());
1575
1576 selected_dates.clear_internal();
1577 selected_dates.add_range(hover_start, hover_end);
1580 }
1581 }
1582
1583 fn move_selection_to_removed_items(&self) {
1586 let selected_dates = self.selected_dates();
1587 self.add_removed_items(&selected_dates.to_vec());
1588 selected_dates.clear_internal();
1589 }
1590
1591 pub(crate) fn process_tap_range_selection(&self, selected_date: DateTime) -> bool {
1596 if !self.allow_tap_range_selection()
1597 || (self.selection_mode() != CalendarSelectionMode::SingleRange
1598 && self.selection_mode() != CalendarSelectionMode::MultipleRange)
1599 {
1600 return false;
1601 }
1602
1603 if !Self::is_valid_date_selection(self, Some(selected_date)) {
1604 return false;
1605 }
1606
1607 let selected_dates = self.selected_dates();
1608
1609 match self.tap_range_start.get().filter(|_| self.is_tap_range_selection_active.get()) {
1610 None => {
1611 self.is_tap_range_selection_active.set(true);
1612 self.tap_range_start.set(Some(selected_date));
1613
1614 if self.selection_mode() == CalendarSelectionMode::SingleRange {
1615 self.move_selection_to_removed_items();
1616 }
1617
1618 if !selected_dates.contains(selected_date) {
1619 selected_dates.add(selected_date);
1620 }
1621
1622 true
1623 }
1624 Some(tap_range_start) => {
1625 let mut start_date = tap_range_start;
1626 let mut end_date = selected_date;
1627
1628 if DateTime::compare(start_date, end_date) > 0 {
1629 std::mem::swap(&mut start_date, &mut end_date);
1630 }
1631
1632 let range = CalendarDateRange::new_range(start_date, end_date);
1633 if self.blackout_dates().contains_any(&range) {
1634 self.tap_range_start.set(Some(selected_date));
1635
1636 if self.selection_mode() == CalendarSelectionMode::SingleRange {
1637 self.move_selection_to_removed_items();
1638 }
1639
1640 if !selected_dates.contains(selected_date) {
1641 selected_dates.add(selected_date);
1642 }
1643 return true;
1644 }
1645
1646 if self.selection_mode() == CalendarSelectionMode::SingleRange {
1647 self.move_selection_to_removed_items();
1648 }
1649
1650 selected_dates.add_range(start_date, end_date);
1651
1652 self.is_tap_range_selection_active.set(false);
1653 self.tap_range_start.set(None);
1654
1655 true
1656 }
1657 }
1658 }
1659
1660 fn process_selection(&self, shift: bool, last_selected_date: Option<DateTime>, index: Option<i32>) {
1661 if let (CalendarSelectionMode::None, Some(last_selected_date)) = (self.selection_mode(), last_selected_date) {
1662 self.on_day_click(last_selected_date);
1663 return;
1664 }
1665
1666 if let Some(last_selected_date) = last_selected_date {
1668 if index.is_none() && !shift && self.process_tap_range_selection(last_selected_date) {
1669 self.on_day_click(last_selected_date);
1670 return;
1671 }
1672 }
1673
1674 let Some(last_selected_date) = last_selected_date else {
1675 return;
1676 };
1677
1678 if Self::is_valid_keyboard_selection(self, Some(last_selected_date)) {
1679 if self.selection_mode() == CalendarSelectionMode::SingleRange
1680 || self.selection_mode() == CalendarSelectionMode::MultipleRange
1681 {
1682 self.move_selection_to_removed_items();
1683 if shift {
1684 self.is_shift_pressed.set(true);
1685 let hover_start = match self.hover_start() {
1686 Some(hover_start) => hover_start,
1687 None => {
1688 let hover_start = match self.last_selected_date() {
1689 Some(last_selected_date) => last_selected_date,
1690 None => {
1691 if DateTimeHelper::compare_year_month(self.display_date_internal(), DateTime::today())
1692 == 0
1693 {
1694 DateTime::today()
1695 } else {
1696 self.display_date_internal()
1697 }
1698 }
1699 };
1700 self.set_hover_start(Some(hover_start));
1701
1702 if let Some(b) = self.find_day_button_from_day(hover_start) {
1703 self.set_hover_start_index(Some(b.index()));
1704 }
1705 hover_start
1706 }
1707 };
1708 self.un_highlight_days();
1711 let range = if DateTime::compare(hover_start, last_selected_date) < 0 {
1714 CalendarDateRange::new_range(hover_start, last_selected_date)
1715 } else {
1716 CalendarDateRange::new_range(last_selected_date, hover_start)
1717 };
1718
1719 if !self.blackout_dates().contains_any(&range) {
1720 self.set_hover_end(Some(last_selected_date));
1721
1722 match index {
1723 Some(index) => {
1724 self.set_hover_end_index(self.hover_end_index().map(|current| current + index));
1725 }
1726 None => {
1727 let hover_end_internal =
1730 self.hover_end_internal().expect("the hover range has an end");
1731 if let Some(b) = self.find_day_button_from_day(hover_end_internal) {
1732 self.set_hover_end_index(Some(b.index()));
1733 }
1734 }
1735 }
1736 }
1737
1738 self.on_day_click(self.hover_end().expect("the hover range has an end"));
1739 self.highlight_days();
1740 } else {
1741 self.set_hover_start(Some(last_selected_date));
1742 self.set_hover_end(Some(last_selected_date));
1743 self.add_selection();
1744 self.on_day_click(last_selected_date);
1745 }
1746 } else {
1747 self.set_last_selected_date(Some(last_selected_date));
1749 let selected_dates = self.selected_dates();
1750 if selected_dates.count() > 0 {
1751 selected_dates.set(0, last_selected_date);
1752 } else {
1753 selected_dates.add(last_selected_date);
1754 }
1755 self.on_day_click(last_selected_date);
1756 }
1757 }
1758 }
1759
1760 pub(crate) fn on_day_button_mouse_up(&self, e: &PointerReleasedEventArgs) {
1761 for (_, handler) in self.day_button_mouse_up.snapshot().iter() {
1762 handler(e);
1763 }
1764 }
1765
1766 pub(crate) fn calendar_key_down(&self, e: &KeyEventArgs) {
1767 if !e.handled() && self.is_enabled() {
1768 e.set_handled(self.process_calendar_key(e));
1769 }
1770 }
1771
1772 pub(crate) fn process_calendar_key(&self, e: &KeyEventArgs) -> bool {
1773 if self.display_mode() == CalendarMode::Month {
1774 if let Some(last_selected_date) = self.last_selected_date() {
1775 if DateTimeHelper::compare_year_month(last_selected_date, self.display_date_internal()) != 0
1780 && self.focus_button().is_some_and(|focus_button| !focus_button.is_inactive())
1781 {
1782 return true;
1783 }
1784 }
1785 }
1786
1787 let invariant_key = e.key;
1789
1790 let (ctrl, shift) = CalendarExtensions::get_meta_key_state(e.key_modifiers);
1791
1792 match invariant_key {
1793 Key::Up => {
1794 self.process_up_key(ctrl, shift);
1795 true
1796 }
1797 Key::Down => {
1798 self.process_down_key(ctrl, shift);
1799 true
1800 }
1801 Key::Left => {
1802 self.process_left_key(shift);
1803 true
1804 }
1805 Key::Right => {
1806 self.process_right_key(shift);
1807 true
1808 }
1809 Key::PageDown => {
1810 self.process_page_down_key(shift);
1811 true
1812 }
1813 Key::PageUp => {
1814 self.process_page_up_key(shift);
1815 true
1816 }
1817 Key::Home => {
1818 self.process_home_key(shift);
1819 true
1820 }
1821 Key::End => {
1822 self.process_end_key(shift);
1823 true
1824 }
1825 Key::Enter | Key::Space => self.process_enter_key(),
1826 _ => false,
1827 }
1828 }
1829
1830 fn last_selected_date_or_today(&self) -> DateTime {
1832 self.last_selected_date().unwrap_or_else(DateTime::today)
1833 }
1834
1835 pub(crate) fn process_up_key(&self, ctrl: bool, shift: bool) {
1836 match self.display_mode() {
1837 CalendarMode::Month => {
1838 if ctrl {
1839 self.set_selected_month(self.display_date_internal());
1840 self.set_current_value(Self::display_mode_property(), CalendarMode::Year);
1841 } else {
1842 let selected_date =
1843 DateTimeHelper::add_days(self.last_selected_date_or_today(), -Self::COLUMNS_PER_MONTH);
1844 self.process_selection(shift, selected_date, Some(-Self::COLUMNS_PER_MONTH));
1845 }
1846 }
1847 CalendarMode::Year => {
1848 if ctrl {
1849 self.set_selected_year(self.selected_month());
1850 self.set_current_value(Self::display_mode_property(), CalendarMode::Decade);
1851 } else {
1852 let selected_month = DateTimeHelper::add_months(self.selected_month.get(), -Self::COLUMNS_PER_YEAR);
1853 self.on_selected_month_changed(selected_month);
1854 }
1855 }
1856 CalendarMode::Decade => {
1857 if !ctrl {
1858 let selected_year = DateTimeHelper::add_years(self.selected_year(), -Self::COLUMNS_PER_YEAR);
1859 self.on_selected_year_changed(selected_year);
1860 }
1861 }
1862 }
1863 }
1864
1865 pub(crate) fn process_down_key(&self, ctrl: bool, shift: bool) {
1866 match self.display_mode() {
1867 CalendarMode::Month => {
1868 if !ctrl || shift {
1869 let selected_date =
1870 DateTimeHelper::add_days(self.last_selected_date_or_today(), Self::COLUMNS_PER_MONTH);
1871 self.process_selection(shift, selected_date, Some(Self::COLUMNS_PER_MONTH));
1872 }
1873 }
1874 CalendarMode::Year => {
1875 if ctrl {
1876 self.set_current_value(Self::display_date_property(), self.selected_month());
1877 self.set_current_value(Self::display_mode_property(), CalendarMode::Month);
1878 } else {
1879 let selected_month = DateTimeHelper::add_months(self.selected_month.get(), Self::COLUMNS_PER_YEAR);
1880 self.on_selected_month_changed(selected_month);
1881 }
1882 }
1883 CalendarMode::Decade => {
1884 if ctrl {
1885 self.set_selected_month(self.selected_year());
1886 self.set_current_value(Self::display_mode_property(), CalendarMode::Year);
1887 } else {
1888 let selected_year = DateTimeHelper::add_years(self.selected_year(), Self::COLUMNS_PER_YEAR);
1889 self.on_selected_year_changed(selected_year);
1890 }
1891 }
1892 }
1893 }
1894
1895 pub(crate) fn process_left_key(&self, shift: bool) {
1896 match self.display_mode() {
1897 CalendarMode::Month => {
1898 let selected_date = DateTimeHelper::add_days(self.last_selected_date_or_today(), -1);
1899 self.process_selection(shift, selected_date, Some(-1));
1900 }
1901 CalendarMode::Year => {
1902 let selected_month = DateTimeHelper::add_months(self.selected_month.get(), -1);
1903 self.on_selected_month_changed(selected_month);
1904 }
1905 CalendarMode::Decade => {
1906 let selected_year = DateTimeHelper::add_years(self.selected_year(), -1);
1907 self.on_selected_year_changed(selected_year);
1908 }
1909 }
1910 }
1911
1912 pub(crate) fn process_right_key(&self, shift: bool) {
1913 match self.display_mode() {
1914 CalendarMode::Month => {
1915 let selected_date = DateTimeHelper::add_days(self.last_selected_date_or_today(), 1);
1916 self.process_selection(shift, selected_date, Some(1));
1917 }
1918 CalendarMode::Year => {
1919 let selected_month = DateTimeHelper::add_months(self.selected_month.get(), 1);
1920 self.on_selected_month_changed(selected_month);
1921 }
1922 CalendarMode::Decade => {
1923 let selected_year = DateTimeHelper::add_years(self.selected_year(), 1);
1924 self.on_selected_year_changed(selected_year);
1925 }
1926 }
1927 }
1928
1929 fn process_enter_key(&self) -> bool {
1930 match self.display_mode() {
1931 CalendarMode::Year => {
1932 self.set_current_value(Self::display_date_property(), self.selected_month());
1933 self.set_current_value(Self::display_mode_property(), CalendarMode::Month);
1934 true
1935 }
1936 CalendarMode::Decade => {
1937 self.set_selected_month(self.selected_year());
1938 self.set_current_value(Self::display_mode_property(), CalendarMode::Year);
1939 true
1940 }
1941 CalendarMode::Month => false,
1942 }
1943 }
1944
1945 pub(crate) fn process_home_key(&self, shift: bool) {
1946 match self.display_mode() {
1947 CalendarMode::Month => {
1948 let display_date_internal = self.display_date_internal();
1950 let selected_date = DateTime::new(display_date_internal.year(), display_date_internal.month(), 1);
1951 self.process_selection(shift, Some(selected_date), None);
1952 }
1953 CalendarMode::Year => {
1954 let selected_month = DateTime::new(self.selected_month.get().year(), 1, 1);
1955 self.on_selected_month_changed(Some(selected_month));
1956 }
1957 CalendarMode::Decade => {
1958 let selected_year = DateTime::new(DateTimeHelper::decade_of_date(self.selected_year()), 1, 1);
1959 self.on_selected_year_changed(Some(selected_year));
1960 }
1961 }
1962 }
1963
1964 pub(crate) fn process_end_key(&self, shift: bool) {
1965 match self.display_mode() {
1966 CalendarMode::Month => {
1967 let display_date_internal = self.display_date_internal();
1968 let mut selected_date = DateTime::new(display_date_internal.year(), display_date_internal.month(), 1);
1969
1970 if DateTimeHelper::compare_year_month(DateTime::MAX_VALUE, selected_date) > 0 {
1971 selected_date =
1975 DateTimeHelper::add_months(selected_date, 1).expect("the next month is a representable date");
1976 selected_date =
1977 DateTimeHelper::add_days(selected_date, -1).expect("the previous day is a representable date");
1978 } else {
1979 selected_date = DateTime::MAX_VALUE;
1980 }
1981 self.process_selection(shift, Some(selected_date), None);
1982 }
1983 CalendarMode::Year => {
1984 let selected_month = DateTime::new(self.selected_month.get().year(), 12, 1);
1985 self.on_selected_month_changed(Some(selected_month));
1986 }
1987 CalendarMode::Decade => {
1988 let selected_year = DateTime::new(DateTimeHelper::end_of_decade(self.selected_year()), 1, 1);
1989 self.on_selected_year_changed(Some(selected_year));
1990 }
1991 }
1992 }
1993
1994 pub(crate) fn process_page_down_key(&self, shift: bool) {
1995 if !shift {
1996 self.on_next_click();
1997 return;
1998 }
1999 match self.display_mode() {
2000 CalendarMode::Month => {
2001 let selected_date = DateTimeHelper::add_months(self.last_selected_date_or_today(), 1);
2002 self.process_selection(shift, selected_date, None);
2003 }
2004 CalendarMode::Year => {
2005 let selected_month = DateTimeHelper::add_years(self.selected_month.get(), 1);
2006 self.on_selected_month_changed(selected_month);
2007 }
2008 CalendarMode::Decade => {
2009 let selected_year = DateTimeHelper::add_years(self.selected_year(), 10);
2010 self.on_selected_year_changed(selected_year);
2011 }
2012 }
2013 }
2014
2015 pub(crate) fn process_page_up_key(&self, shift: bool) {
2016 if !shift {
2017 self.on_previous_click();
2018 return;
2019 }
2020 match self.display_mode() {
2021 CalendarMode::Month => {
2022 let selected_date = DateTimeHelper::add_months(self.last_selected_date_or_today(), -1);
2023 self.process_selection(shift, selected_date, None);
2024 }
2025 CalendarMode::Year => {
2026 let selected_month = DateTimeHelper::add_years(self.selected_month.get(), -1);
2027 self.on_selected_month_changed(selected_month);
2028 }
2029 CalendarMode::Decade => {
2030 let selected_year = DateTimeHelper::add_years(self.selected_year(), -10);
2031 self.on_selected_year_changed(selected_year);
2032 }
2033 }
2034 }
2035
2036 fn calendar_key_up(&self, e: &KeyEventArgs) {
2037 if !e.handled() && (e.key == Key::LeftShift || e.key == Key::RightShift) {
2038 self.process_shift_key_up();
2039 }
2040 }
2041
2042 pub(crate) fn process_shift_key_up(&self) {
2043 if self.is_shift_pressed.get()
2044 && (self.selection_mode() == CalendarSelectionMode::SingleRange
2045 || self.selection_mode() == CalendarSelectionMode::MultipleRange)
2046 {
2047 self.add_selection();
2048 self.is_shift_pressed.set(false);
2049 }
2050 }
2051
2052 fn on_is_enabled_changed(&self, is_enabled: bool) {
2054 if let Some(month_control) = self.month_control() {
2055 month_control.update_disabled(is_enabled);
2056 }
2057 }
2058}