1use 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
30const 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
40type 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
51pub(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#[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 month_view: RefCell<Option<Ref<Grid>>>,
80 year_view: RefCell<Option<Ref<Grid>>>,
82 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 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 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 pub fn header_background_property() -> StyledProperty<Option<Rc<dyn IBrush>>> {
176 Calendar::header_background_property().add_owner::<CalendarItem>()
177 }
178
179 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 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 pub fn new() -> Ref<Self> {
211 instantiate(Self::construct())
212 }
213
214 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 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 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 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 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 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 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 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 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 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 pub(crate) fn year_view(&self) -> Option<Ref<Grid>> {
336 self.year_view.borrow().clone()
337 }
338
339 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 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 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 if DateTimeHelper::compare_year_month(first_day_of_month, DateTime::MAX_VALUE) == 0 {
526 next_button.set_is_enabled(false);
527 } else {
528 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 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 child_button.set_is_blackout(owner.blackout_dates().contains_date(date_to_add));
561 child_button.set_is_enabled(true);
562
563 child_button.set_is_inactive(
566 DateTimeHelper::compare_year_month(date_to_add, owner.display_date_internal()) != 0,
567 );
568
569 child_button.set_is_today(owner.is_today_highlighted() && date_to_add == DateTime::today());
571
572 child_button.set_is_selected(false);
574 for item in owner.selected_dates().to_vec() {
575 child_button
579 .set_is_selected(child_button.is_selected() | (DateTimeHelper::compare_days(date_to_add, item) == 0));
580 }
581
582 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 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 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 date_to_add = self.calendar.add_days(date_to_add, 1);
658 } else {
659 child_index += 1;
662 for i in child_index..count {
663 let child_button = Self::day_button_at(&month_view, i);
664 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 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 fn update_week_number_labels(&self, first_day_of_month: DateTime) {
705 let owner = self.owner();
706
707 let show = owner.as_ref().is_some_and(|owner| owner.is_week_number_visible());
709 self.pseudo_classes().set(":hasweeknumbers", show);
710
711 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 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 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 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 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 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 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 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 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 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 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 owner.highlight_days();
1037 }
1038 CalendarSelectionMode::None => {}
1039 }
1040 }
1041 }
1042
1043 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 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 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 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 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 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 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 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 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 self.add_selection(b, selected_date);
1171 }
1172 _ => {}
1173 }
1174 } else {
1175 if b.is_inactive() && b.is_blackout() {
1178 owner.on_day_click(selected_date);
1179 }
1180 }
1181 }
1182 }
1183 }
1184
1185 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 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 #[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}