diff --git a/src/AtomUI.Controls/Calendar/Calendar.cs b/src/AtomUI.Controls/Calendar/Calendar.cs index a514b0ea0..ab180a4b7 100644 --- a/src/AtomUI.Controls/Calendar/Calendar.cs +++ b/src/AtomUI.Controls/Calendar/Calendar.cs @@ -569,7 +569,7 @@ public class Calendar : TemplatedControl } } - internal DateTime DisplayDateInternal { get; private set; } + internal DateTime DisplayDateInternal { get; set; } #endregion @@ -807,7 +807,7 @@ public class Calendar : TemplatedControl RemovedItems = new Collection(); } - private void OnDisplayDateChanged(AvaloniaPropertyChangedEventArgs e) + protected virtual void OnDisplayDateChanged(AvaloniaPropertyChangedEventArgs e) { UpdateDisplayDate(this, (DateTime)e.NewValue!, (DateTime)e.OldValue!); } @@ -833,7 +833,7 @@ public class Calendar : TemplatedControl c.OnDisplayDate(new CalendarDateChangedEventArgs(removedDate, addedDate)); } - private void OnDisplayDate(CalendarDateChangedEventArgs e) + protected void OnDisplayDate(CalendarDateChangedEventArgs e) { DisplayDateChanged?.Invoke(this, e); } @@ -1073,26 +1073,31 @@ public class Calendar : TemplatedControl } } - internal void UpdateMonths() + protected internal virtual void UpdateMonths() { CalendarItem? monthControl = MonthControl; if (monthControl != null) { - switch (DisplayMode) { - case CalendarMode.Month: - { - monthControl.UpdateMonthMode(); - break; - } - case CalendarMode.Year: - { - monthControl.UpdateYearMode(); - break; - } - case CalendarMode.Decade: - { - monthControl.UpdateDecadeMode(); - break; - } + UpdateCalendarMonths(monthControl); + } + } + + internal void UpdateCalendarMonths(CalendarItem calendarItem) + { + switch (DisplayMode) { + case CalendarMode.Month: + { + calendarItem.UpdateMonthMode(); + break; + } + case CalendarMode.Year: + { + calendarItem.UpdateYearMode(); + break; + } + case CalendarMode.Decade: + { + calendarItem.UpdateDecadeMode(); + break; } } } diff --git a/src/AtomUI.Controls/Calendar/CalendarItem.cs b/src/AtomUI.Controls/Calendar/CalendarItem.cs index 64ff69959..e9a4c2958 100644 --- a/src/AtomUI.Controls/Calendar/CalendarItem.cs +++ b/src/AtomUI.Controls/Calendar/CalendarItem.cs @@ -25,7 +25,7 @@ namespace AtomUI.Controls; [PseudoClasses(CalendarDisabledPC)] internal class CalendarItem : TemplatedControl { - private const string CalendarDisabledPC = ":calendardisabled"; + internal const string CalendarDisabledPC = ":calendardisabled"; #region 公共属性定义 @@ -182,20 +182,20 @@ internal class CalendarItem : TemplatedControl /// /// The number of days per week. /// - private const int NumberOfDaysPerWeek = 7; + internal const int NumberOfDaysPerWeek = 7; - private HeadTextButton? _headerButton; - private IconButton? _nextButton; - private IconButton? _previousButton; - private IconButton? _nextMonthButton; - private IconButton? _previousMonthButton; + protected HeadTextButton? _headerButton; + protected IconButton? _nextButton; + protected IconButton? _previousButton; + protected IconButton? _nextMonthButton; + protected IconButton? _previousMonthButton; - private DateTime _currentMonth; - private bool _isMouseLeftButtonDown; - private bool _isMouseLeftButtonDownYearView; - private bool _isControlPressed; + protected DateTime _currentMonth; + protected bool _isMouseLeftButtonDown; + protected bool _isMouseLeftButtonDownYearView; + protected bool _isControlPressed; - private readonly System.Globalization.Calendar _calendar = new GregorianCalendar(); + protected readonly System.Globalization.Calendar _calendar = new GregorianCalendar(); internal Calendar? Owner { get; set; } internal CalendarDayButton? CurrentButton { get; set; } @@ -328,7 +328,7 @@ internal class CalendarItem : TemplatedControl } } - private void SetDayTitles() + protected void SetDayTitles() { for (int childIndex = 0; childIndex < Calendar.ColumnsPerMonth; childIndex++) { var daytitle = MonthView!.Children[childIndex]; @@ -364,7 +364,7 @@ internal class CalendarItem : TemplatedControl } } - internal void UpdateMonthMode() + protected internal virtual void UpdateMonthMode() { if (Owner != null) { _currentMonth = Owner.DisplayDateInternal; @@ -382,7 +382,7 @@ internal class CalendarItem : TemplatedControl } } - private void SetMonthModeHeaderButton() + protected virtual void SetMonthModeHeaderButton() { if (HeaderButton != null) { if (Owner != null) { @@ -394,7 +394,7 @@ internal class CalendarItem : TemplatedControl } } - private void SetMonthModeNextButton(DateTime firstDayOfMonth) + protected void SetMonthModeNextButton(DateTime firstDayOfMonth) { if (Owner != null && NextButton != null) { // DisplayDate is equal to DateTime.MaxValue @@ -409,7 +409,7 @@ internal class CalendarItem : TemplatedControl } } - private void SetMonthModePreviousButton(DateTime firstDayOfMonth) + protected void SetMonthModePreviousButton(DateTime firstDayOfMonth) { if (Owner != null && PreviousButton != null) { PreviousButton.IsEnabled = (DateTimeHelper.CompareDays(Owner.DisplayDateRangeStart, firstDayOfMonth) < 0); @@ -441,10 +441,10 @@ internal class CalendarItem : TemplatedControl // SET IF THE DAY IS INACTIVE OR NOT: set if the day is a // trailing day or not - childButton.IsInactive = (DateTimeHelper.CompareYearMonth(dateToAdd, Owner.DisplayDateInternal) != 0); - + childButton.IsInactive = CheckDayInactiveState(dateToAdd); + // SET IF THE DAY IS TODAY OR NOT - childButton.IsToday = (Owner.IsTodayHighlighted && dateToAdd == DateTime.Today); + childButton.IsToday = CheckDayIsTodayState(dateToAdd); // SET IF THE DAY IS SELECTED OR NOT childButton.IsSelected = false; @@ -474,7 +474,25 @@ internal class CalendarItem : TemplatedControl } } - private void SetCalendarDayButtons(DateTime firstDayOfMonth) + protected virtual bool CheckDayInactiveState(DateTime dateToAdd) + { + if (Owner is not null) { + return DateTimeHelper.CompareYearMonth(dateToAdd, Owner.DisplayDateInternal) != 0; + } + + return false; + } + + protected virtual bool CheckDayIsTodayState(DateTime dateToAdd) + { + if (Owner is not null) { + return Owner.IsTodayHighlighted && dateToAdd == DateTime.Today; + } + + return false; + } + + protected void SetCalendarDayButtons(DateTime firstDayOfMonth) { int lastMonthToDisplay = PreviousMonthDays(firstDayOfMonth); DateTime dateToAdd; diff --git a/src/AtomUI.Controls/Calendar/RangeCalendar.cs b/src/AtomUI.Controls/Calendar/RangeCalendar.cs index 88bc5e26d..8de3583b9 100644 --- a/src/AtomUI.Controls/Calendar/RangeCalendar.cs +++ b/src/AtomUI.Controls/Calendar/RangeCalendar.cs @@ -6,6 +6,13 @@ namespace AtomUI.Controls; public class RangeCalendar : Calendar { + public RangeCalendar() + { + SelectionMode = CalendarSelectionMode.SingleRange; + } + + internal DateTime SecondaryDisplayDateInternal { get; private set; } + internal CalendarItem? SecondaryMonthControl { get @@ -17,7 +24,34 @@ public class RangeCalendar : Calendar return null; } } + + protected override void OnDisplayDateChanged(AvaloniaPropertyChangedEventArgs e) + { + UpdateDisplayDate(this, (DateTime)e.NewValue!, (DateTime)e.OldValue!); + } + + private static void UpdateDisplayDate(RangeCalendar c, DateTime addedDate, DateTime removedDate) + { + _ = c ?? throw new ArgumentNullException(nameof(c)); + // If DisplayDate < DisplayDateStart, DisplayDate = DisplayDateStart + if (DateTime.Compare(addedDate, c.DisplayDateRangeStart) < 0) { + c.DisplayDate = c.DisplayDateRangeStart; + return; + } + + // If DisplayDate > DisplayDateEnd, DisplayDate = DisplayDateEnd + if (DateTime.Compare(addedDate, c.DisplayDateRangeEnd) > 0) { + c.DisplayDate = c.DisplayDateRangeEnd; + return; + } + + c.DisplayDateInternal = DateTimeHelper.DiscardDayTime(addedDate); + c.SecondaryDisplayDateInternal = DateTimeHelper.AddMonths(DateTimeHelper.DiscardDayTime(addedDate), 1) ?? c.DisplayDateInternal; + c.UpdateMonths(); + c.OnDisplayDate(new CalendarDateChangedEventArgs(removedDate, addedDate)); + } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); @@ -56,4 +90,12 @@ public class RangeCalendar : Calendar } } } + + protected internal override void UpdateMonths() + { + base.UpdateMonths(); + if (SecondaryMonthControl is not null) { + UpdateCalendarMonths(SecondaryMonthControl); + } + } } \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/RangeCalendarItem.cs b/src/AtomUI.Controls/Calendar/RangeCalendarItem.cs index 26c7570b9..5ece4f658 100644 --- a/src/AtomUI.Controls/Calendar/RangeCalendarItem.cs +++ b/src/AtomUI.Controls/Calendar/RangeCalendarItem.cs @@ -1,5 +1,6 @@ using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; @@ -54,6 +55,12 @@ internal class RangeCalendarItem : CalendarItem } } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + SetupNextButtonVisible(); + } + private void SetupNextButtonVisible() { IsNextButtonVisible = !IsPrimary || Owner?.DisplayMode == CalendarMode.Decade || @@ -77,4 +84,45 @@ internal class RangeCalendarItem : CalendarItem base.HandleMonthCalendarButtonMouseUp(sender, e); SetupNextButtonVisible(); } + + protected internal override void UpdateMonthMode() + { + if (Owner is RangeCalendar owner) { + _currentMonth = IsPrimary ? owner.DisplayDateInternal : owner.SecondaryDisplayDateInternal; + } else { + _currentMonth = DateTime.Today; + } + + SetMonthModeHeaderButton(); + SetMonthModePreviousButton(_currentMonth); + SetMonthModeNextButton(_currentMonth); + + if (MonthView != null) { + SetDayTitles(); + SetCalendarDayButtons(_currentMonth); + } + } + + protected override void SetMonthModeHeaderButton() + { + if (HeaderButton != null) { + if (Owner is RangeCalendar owner) { + var targetDate = _isPrimary ? owner.DisplayDateInternal : owner.SecondaryDisplayDateInternal; + HeaderButton.Content = targetDate.ToString("Y", DateTimeHelper.GetCurrentDateFormat()); + HeaderButton.IsEnabled = true; + } else { + HeaderButton.Content = DateTime.Today.ToString("Y", DateTimeHelper.GetCurrentDateFormat()); + } + } + } + + protected override bool CheckDayInactiveState(DateTime dateToAdd) + { + if (Owner is RangeCalendar owner) { + var targetDate = _isPrimary ? owner.DisplayDateInternal : owner.SecondaryDisplayDateInternal; + return DateTimeHelper.CompareYearMonth(dateToAdd, targetDate) != 0; + } + + return false; + } } \ No newline at end of file