feat: day button initialization.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Ursa.Demo.Pages.DatePickerDemo">
|
||||
<StackPanel Margin="20" HorizontalAlignment="Left">
|
||||
<u:CalendarMonthView/>
|
||||
<u:CalendarDayButton />
|
||||
<u:CalendarDayButton IsSelected="True" />
|
||||
<u:CalendarDayButton IsBlackout="True" />
|
||||
|
||||
@@ -4,38 +4,14 @@
|
||||
xmlns:u="https://irihi.tech/ursa">
|
||||
<Design.PreviewWith>
|
||||
<StackPanel Margin="20" Spacing="5">
|
||||
<u:CalendarDayButton />
|
||||
<u:CalendarDayButton IsSelected="True" />
|
||||
<u:CalendarDayButton IsBlackout="True" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<u:CalendarDayButton IsStartDate="True" />
|
||||
<u:CalendarDayButton IsInRange="True" />
|
||||
<u:CalendarDayButton IsInRange="True" />
|
||||
<u:CalendarDayButton IsInRange="True" />
|
||||
<u:CalendarDayButton IsEndDate="True" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<u:CalendarDayButton IsPreviewStartDate="True" />
|
||||
<u:CalendarDayButton IsInRange="True" />
|
||||
<u:CalendarDayButton IsInRange="True" />
|
||||
<u:CalendarDayButton IsInRange="True" />
|
||||
<u:CalendarDayButton IsPreviewEndDate="True" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<u:CalendarDayButton IsInRange="True" />
|
||||
<u:CalendarDayButton IsInRange="True" IsStartDate="True" />
|
||||
<u:CalendarDayButton IsInRange="True" />
|
||||
<u:CalendarDayButton IsEndDate="True" IsInRange="True" />
|
||||
<u:CalendarDayButton IsInRange="True" />
|
||||
</StackPanel>
|
||||
|
||||
<u:CalendarMonthView/>
|
||||
<u:Calendar />
|
||||
</StackPanel>
|
||||
</Design.PreviewWith>
|
||||
<!-- Add Resources Here -->
|
||||
<ControlTheme x:Key="{x:Type u:CalendarDayButton}" TargetType="u:CalendarDayButton">
|
||||
<Setter Property="Width" Value="32" />
|
||||
<Setter Property="Height" Value="32" />
|
||||
<Setter Property="MinWidth" Value="32" />
|
||||
<Setter Property="MinHeight" Value="32" />
|
||||
<Setter Property="Margin" Value="0 2" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
@@ -66,6 +42,16 @@
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:today">
|
||||
<Setter Property="Background" Value="{DynamicResource SemiGrey1}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource SemiBlue5}" />
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:not-current-month">
|
||||
<Setter Property="Foreground" Value="{DynamicResource SemiGrey3}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="^:pointerover">
|
||||
<Setter Property="Background" Value="{DynamicResource SemiGrey1}" />
|
||||
@@ -199,64 +185,28 @@
|
||||
Foreground="{DynamicResource CalendarItemIconForeground}" />
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid Grid.Row="1" ColumnDefinitions="*, *, *, *, *, *, *">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" MinHeight="24" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Center"
|
||||
Text="M" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Center"
|
||||
Text="T" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Center"
|
||||
Text="W" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="3"
|
||||
HorizontalAlignment="Center"
|
||||
Text="T" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="4"
|
||||
HorizontalAlignment="Center"
|
||||
Text="F" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="5"
|
||||
HorizontalAlignment="Center"
|
||||
Text="S" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="6"
|
||||
HorizontalAlignment="Center"
|
||||
Text="S" />
|
||||
<Rectangle
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="7"
|
||||
Height="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
Fill="{DynamicResource SemiGrey2}" />
|
||||
|
||||
</Grid>
|
||||
<u:CalendarMonthView Grid.Row="1"></u:CalendarMonthView>
|
||||
</Grid>
|
||||
|
||||
</Panel>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme TargetType="u:CalendarMonthView" x:Key="{x:Type u:CalendarMonthView}">
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Grid Name="{x:Static u:CalendarMonthView.PART_Grid}" ColumnDefinitions="*, *, *, *, *, *, *" RowDefinitions="*, Auto, *, *, *, *, *, *">
|
||||
<Rectangle
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="7"
|
||||
Height="1"
|
||||
Margin="8 8 8 0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Fill="{DynamicResource SemiGrey2}" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</ControlTheme>
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -10,7 +10,7 @@ using Irihi.Avalonia.Shared.Helpers;
|
||||
namespace Ursa.Controls;
|
||||
|
||||
[PseudoClasses(PseudoClassName.PC_Pressed, PseudoClassName.PC_Selected,
|
||||
PC_StartDate, PC_EndDate, PC_PreviewStartDate, PC_PreviewEndDate, PC_InRange, PC_Today, PC_Blackout)]
|
||||
PC_StartDate, PC_EndDate, PC_PreviewStartDate, PC_PreviewEndDate, PC_InRange, PC_Today, PC_Blackout, PC_NotCurrentMonth)]
|
||||
public class CalendarDayButton: ContentControl
|
||||
{
|
||||
public const string PC_StartDate = ":start-date";
|
||||
@@ -19,7 +19,10 @@ public class CalendarDayButton: ContentControl
|
||||
public const string PC_PreviewEndDate = ":preview-end-date";
|
||||
public const string PC_InRange = ":in-range";
|
||||
public const string PC_Today = ":today";
|
||||
public const string PC_NotCurrentMonth = ":not-current-month";
|
||||
public const string PC_Blackout = ":blackout";
|
||||
|
||||
internal Calendar? Owner { get; set; }
|
||||
|
||||
private bool _isToday;
|
||||
public bool IsToday
|
||||
@@ -111,6 +114,20 @@ public class CalendarDayButton: ContentControl
|
||||
PseudoClasses.Set(PC_Blackout, value);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isNotCurrentMonth;
|
||||
/// <summary>
|
||||
/// Notice: IsNotCurrentMonth is not equivalent to not IsEnabled. Not current month dates still react to pointerover and press action.
|
||||
/// </summary>
|
||||
public bool IsNotCurrentMonth
|
||||
{
|
||||
get => _isNotCurrentMonth;
|
||||
set
|
||||
{
|
||||
_isNotCurrentMonth = value;
|
||||
PseudoClasses.Set(PC_NotCurrentMonth, value);
|
||||
}
|
||||
}
|
||||
|
||||
static CalendarDayButton()
|
||||
{
|
||||
@@ -127,6 +144,5 @@ public class CalendarDayButton: ContentControl
|
||||
PseudoClasses.Set(PC_PreviewEndDate, IsPreviewEndDate);
|
||||
PseudoClasses.Set(PC_InRange, IsInRange);
|
||||
PseudoClasses.Set(PseudoClassName.PC_Selected, IsSelected);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
using System.Globalization;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Layout;
|
||||
using Irihi.Avalonia.Shared;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
@@ -12,23 +17,29 @@ namespace Ursa.Controls;
|
||||
public class CalendarMonthView: TemplatedControl
|
||||
{
|
||||
public const string PART_Grid = "PART_Grid";
|
||||
internal Calendar? Owner { get; set; }
|
||||
|
||||
private Grid? _grid;
|
||||
private readonly System.Globalization.Calendar _calendar = new GregorianCalendar();
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
_grid = e.NameScope.Find<Grid>(PART_Grid);
|
||||
// GenerateGridElements();
|
||||
GenerateGridElements();
|
||||
SetDayButtons(DateTime.Today);
|
||||
}
|
||||
|
||||
private int _month;
|
||||
public int Month
|
||||
|
||||
private DateTime _contextDate = DateTime.Today;
|
||||
/// <summary>
|
||||
/// The DateTime used to generate the month view. This date will be within the month.
|
||||
/// </summary>
|
||||
public DateTime ContextDate
|
||||
{
|
||||
get => _month;
|
||||
get => _contextDate;
|
||||
set
|
||||
{
|
||||
_month = value;
|
||||
// Update();
|
||||
_contextDate = value;
|
||||
// GenerateGridElements();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,10 +51,117 @@ public class CalendarMonthView: TemplatedControl
|
||||
get => GetValue(FirstDayOfWeekProperty);
|
||||
set => SetValue(FirstDayOfWeekProperty, value);
|
||||
}
|
||||
|
||||
static CalendarMonthView()
|
||||
{
|
||||
FirstDayOfWeekProperty.Changed.AddClassHandler<CalendarMonthView, DayOfWeek>((view, args) => view.OnDayOfWeekChanged(args));
|
||||
}
|
||||
|
||||
private void OnDayOfWeekChanged(AvaloniaPropertyChangedEventArgs<DayOfWeek> args)
|
||||
{
|
||||
// throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
private void GenerateGridElements()
|
||||
{
|
||||
// Generate Day titles (Sun, Mon, Tue, Wed, Thu, Fri, Sat) based on FirstDayOfWeek and culture.
|
||||
int count = 7 + 7 * 7;
|
||||
var children = new List<Control>(count);
|
||||
int dayOfWeek = (int)FirstDayOfWeek;
|
||||
var info = DateTimeHelper.GetCurrentDateTimeFormatInfo();
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
int d = ((dayOfWeek + i) % DateTimeHelper.NumberOfDaysPerWeek);
|
||||
var cell = new TextBlock(){ Text = info.ShortestDayNames[d] };
|
||||
cell.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Center);
|
||||
cell.SetValue(Grid.RowProperty, 0);
|
||||
cell.SetValue(Grid.ColumnProperty, i);
|
||||
children.Add(cell);
|
||||
}
|
||||
|
||||
// Generate day buttons.
|
||||
for (int i = 2; i < DateTimeHelper.NumberOfWeeksPerMonth+2; i++)
|
||||
{
|
||||
for (int j = 0; j < DateTimeHelper.NumberOfDaysPerWeek; j++)
|
||||
{
|
||||
var cell = new CalendarDayButton();
|
||||
cell.SetValue(Grid.RowProperty, i);
|
||||
cell.SetValue(Grid.ColumnProperty, j);
|
||||
cell.PointerPressed += OnDayButtonPressed;
|
||||
cell.PointerReleased += OnDayButtonReleased;
|
||||
cell.PointerEntered += OnDayButtonPointerEnter;
|
||||
children.Add(cell);
|
||||
}
|
||||
}
|
||||
|
||||
_grid?.Children.AddRange(children);
|
||||
}
|
||||
|
||||
private void SetDayButtons(DateTime date)
|
||||
{
|
||||
if (_grid is null) return;
|
||||
var children = _grid.Children;
|
||||
var info = DateTimeHelper.GetCurrentDateTimeFormatInfo();
|
||||
int dayBefore = PreviousMonthDays(date);
|
||||
var dateToSet = date.GetFirstDayOfMonth().AddDays(-dayBefore);
|
||||
for (var i = 8; i < children.Count; i++)
|
||||
{
|
||||
var day = dateToSet;
|
||||
var cell = children[i] as CalendarDayButton;
|
||||
if (cell is null) continue;
|
||||
cell.DataContext = day;
|
||||
cell.IsToday = day == DateTime.Today;
|
||||
cell.Content = day.Day.ToString(info);
|
||||
dateToSet = dateToSet.AddDays(1);
|
||||
}
|
||||
FadeOutDayButtons();
|
||||
}
|
||||
|
||||
private void OnDayButtonPressed(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (sender is CalendarDayButton button)
|
||||
{
|
||||
// button.IsSelected = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDayButtonReleased(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
if (sender is CalendarDayButton button)
|
||||
{
|
||||
// button.IsSelected = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDayButtonPointerEnter(object sender, PointerEventArgs e)
|
||||
{
|
||||
if(sender is CalendarDayButton button)
|
||||
{
|
||||
// button.IsPreviewStartDate = true;
|
||||
}
|
||||
}
|
||||
|
||||
private int PreviousMonthDays(DateTime date)
|
||||
{
|
||||
var firstDay = date.GetFirstDayOfMonth();
|
||||
var dayOfWeek = _calendar.GetDayOfWeek(firstDay);
|
||||
var firstDayOfWeek = this.FirstDayOfWeek;
|
||||
int i = (dayOfWeek - firstDayOfWeek + DateTimeHelper.NumberOfDaysPerWeek) % DateTimeHelper.NumberOfDaysPerWeek;
|
||||
return i == 0 ? DateTimeHelper.NumberOfDaysPerWeek : i;
|
||||
}
|
||||
|
||||
private void FadeOutDayButtons()
|
||||
{
|
||||
if (_grid is null) return;
|
||||
var children = _grid.Children;
|
||||
for (var i = 8; i < children.Count; i++)
|
||||
{
|
||||
if (children[i] is CalendarDayButton button && button.DataContext is DateTime d && d.Month != _contextDate.Month)
|
||||
{
|
||||
button.IsNotCurrentMonth = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,9 @@ namespace Ursa.Controls;
|
||||
|
||||
internal static class DateTimeHelper
|
||||
{
|
||||
public const int NumberOfDaysPerWeek = 7;
|
||||
public const int NumberOfWeeksPerMonth = 6;
|
||||
|
||||
public static DateTimeFormatInfo GetCurrentDateTimeFormatInfo()
|
||||
{
|
||||
if (CultureInfo.CurrentCulture.Calendar is GregorianCalendar) return CultureInfo.CurrentCulture.DateTimeFormat;
|
||||
@@ -14,4 +17,20 @@ internal static class DateTimeHelper
|
||||
dt.Calendar = calendar ?? new GregorianCalendar();
|
||||
return dt;
|
||||
}
|
||||
|
||||
public static DateTime GetFirstDayOfMonth(this DateTime date)
|
||||
{
|
||||
return new DateTime(date.Year, date.Month, 1);
|
||||
}
|
||||
|
||||
public static DateTime GetLastDayOfMonth(this DateTime date)
|
||||
{
|
||||
return new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
|
||||
}
|
||||
|
||||
public static int CompareYearMonth(DateTime dt1, DateTime dt2)
|
||||
{
|
||||
return (dt1.Year - dt2.Year) * 12 + dt1.Month - dt2.Month;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user