完成基本的日历

This commit is contained in:
polarboy
2024-09-11 11:53:27 +08:00
parent b765f58c87
commit 2e4e4de2a1
14 changed files with 464 additions and 67 deletions
+16 -6
View File
@@ -1,4 +1,8 @@
using Avalonia.Controls;
using AtomUI.Media;
using AtomUI.Theme.Styling;
using AtomUI.Theme.Utils;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
@@ -10,9 +14,10 @@ namespace AtomUI.Controls;
/// Represents a button on a
/// <see cref="T:Avalonia.Controls.Calendar" />.
/// </summary>
[PseudoClasses(":selected", ":inactive", ":btnfocused")]
[PseudoClasses(StdPseudoClass.Selected, StdPseudoClass.InActive, BtnFocusedPC)]
internal sealed class CalendarButton : AvaloniaButton
{
private const string BtnFocusedPC = ":btnfocused";
/// <summary>
/// A value indicating whether the button is focused.
/// </summary>
@@ -34,7 +39,6 @@ internal sealed class CalendarButton : AvaloniaButton
/// class.
/// </summary>
public CalendarButton()
: base()
{
SetCurrentValue(ContentProperty, DateTimeHelper.GetCurrentDateFormat().AbbreviatedMonthNames[0]);
}
@@ -97,6 +101,12 @@ internal sealed class CalendarButton : AvaloniaButton
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
SetPseudoClasses();
if (Transitions is null) {
Transitions = new Transitions()
{
AnimationUtils.CreateTransition<SolidColorBrushTransition>(BackgroundProperty, GlobalTokenResourceKey.MotionDurationFast)
};
}
}
/// <summary>
@@ -104,9 +114,9 @@ internal sealed class CalendarButton : AvaloniaButton
/// </summary>
private void SetPseudoClasses()
{
PseudoClasses.Set(":selected", IsSelected);
PseudoClasses.Set(":inactive", IsInactive);
PseudoClasses.Set(":btnfocused", IsCalendarButtonFocused && IsEnabled);
PseudoClasses.Set(StdPseudoClass.Selected, IsSelected);
PseudoClasses.Set(StdPseudoClass.InActive, IsInactive);
PseudoClasses.Set(BtnFocusedPC, IsCalendarButtonFocused && IsEnabled);
}
/// <summary>
@@ -0,0 +1,88 @@
using AtomUI.Theme;
using AtomUI.Theme.Styling;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Styling;
namespace AtomUI.Controls;
[ControlThemeProvider]
internal class CalendarButtonTheme : BaseControlTheme
{
private const string ContentPart = "PART_Content";
public CalendarButtonTheme()
: base(typeof(CalendarButton))
{
}
protected override IControlTemplate BuildControlTemplate()
{
return new FuncControlTemplate<CalendarButton>((calendarButton, scope) =>
{
var contentPresenter = new ContentPresenter()
{
Name = ContentPart,
};
CreateTemplateParentBinding(contentPresenter, ContentPresenter.PaddingProperty, CalendarButton.PaddingProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ForegroundProperty, CalendarButton.ForegroundProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BackgroundProperty, CalendarButton.BackgroundProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.CornerRadiusProperty, CalendarButton.CornerRadiusProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BorderBrushProperty, CalendarButton.BorderBrushProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BorderThicknessProperty, CalendarButton.BorderThicknessProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.FontSizeProperty, CalendarButton.FontSizeProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentProperty, CalendarButton.ContentProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentTemplateProperty, CalendarButton.ContentTemplateProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.HorizontalAlignmentProperty, CalendarButton.HorizontalAlignmentProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.VerticalAlignmentProperty, CalendarButton.VerticalAlignmentProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.HorizontalContentAlignmentProperty, CalendarButton.HorizontalContentAlignmentProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.VerticalContentAlignmentProperty, CalendarButton.VerticalContentAlignmentProperty);
return contentPresenter;
});
}
protected override void BuildStyles()
{
var commonStyle = new Style(selector => selector.Nesting());
commonStyle.Add(CalendarButton.ClickModeProperty, ClickMode.Release);
commonStyle.Add(CalendarButton.CursorProperty, new Cursor(StandardCursorType.Hand));
commonStyle.Add(CalendarButton.BackgroundProperty, GlobalTokenResourceKey.ColorTransparent);
commonStyle.Add(CalendarButton.ForegroundProperty, GlobalTokenResourceKey.ColorTextLabel);
commonStyle.Add(CalendarButton.CornerRadiusProperty, GlobalTokenResourceKey.BorderRadiusSM);
commonStyle.Add(CalendarButton.BorderBrushProperty, GlobalTokenResourceKey.ColorTransparent);
commonStyle.Add(CalendarButton.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
commonStyle.Add(CalendarButton.VerticalAlignmentProperty, VerticalAlignment.Stretch);
commonStyle.Add(CalendarButton.HorizontalContentAlignmentProperty, HorizontalAlignment.Center);
commonStyle.Add(CalendarButton.VerticalContentAlignmentProperty, VerticalAlignment.Center);
commonStyle.Add(CalendarButton.FontSizeProperty, GlobalTokenResourceKey.FontSize);
commonStyle.Add(CalendarButton.HeightProperty, CalendarTokenResourceKey.CellHeight);
commonStyle.Add(CalendarButton.MarginProperty, CalendarTokenResourceKey.CellMargin);
var contentStyle = new Style(selector => selector.Nesting().Template().Name(ContentPart));
contentStyle.Add(ContentPresenter.LineHeightProperty, CalendarTokenResourceKey.CellLineHeight);
commonStyle.Add(contentStyle);
var hoverStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.PointerOver));
hoverStyle.Add(CalendarButton.BackgroundProperty, CalendarTokenResourceKey.CellHoverBg);
commonStyle.Add(hoverStyle);
var inactiveStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.InActive));
inactiveStyle.Add(CalendarButton.ForegroundProperty, GlobalTokenResourceKey.ColorTextDisabled);
commonStyle.Add(inactiveStyle);
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
selectedStyle.Add(CalendarButton.BackgroundProperty, GlobalTokenResourceKey.ColorPrimary);
selectedStyle.Add(CalendarButton.ForegroundProperty, GlobalTokenResourceKey.ColorWhite);
selectedStyle.Add(CalendarButton.BorderThicknessProperty, new Thickness(0));
commonStyle.Add(selectedStyle);
Add(commonStyle);
}
}
@@ -1,20 +1,28 @@
using System.Globalization;
using AtomUI.Media;
using AtomUI.Theme.Data;
using AtomUI.Theme.Styling;
using AtomUI.Theme.Utils;
using AtomUI.Utils;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Input;
using AvaloniaButton = Avalonia.Controls.Button;
namespace AtomUI.Controls;
[PseudoClasses(StdPseudoClass.Pressed, StdPseudoClass.Disabled, StdPseudoClass.Selected, InactivePC, TodayPC, BlackoutPC, DayfocusedPC)]
[PseudoClasses(StdPseudoClass.Pressed, StdPseudoClass.Disabled, StdPseudoClass.Selected, StdPseudoClass.InActive,
TodayPC, BlackoutPC, DayfocusedPC)]
internal sealed class CalendarDayButton : AvaloniaButton
{
private const string InactivePC = ":inactive";
private const string TodayPC = ":today";
private const string BlackoutPC = ":blackout";
private const string DayfocusedPC = ":dayfocused";
internal const string TodayPC = ":today";
internal const string BlackoutPC = ":blackout";
internal const string DayfocusedPC = ":dayfocused";
/// <summary>
/// Default content for the CalendarDayButton.
/// </summary>
@@ -152,6 +160,12 @@ internal sealed class CalendarDayButton : AvaloniaButton
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
SetPseudoClasses();
if (Transitions is null) {
Transitions = new Transitions()
{
AnimationUtils.CreateTransition<SolidColorBrushTransition>(BackgroundProperty, GlobalTokenResourceKey.MotionDurationFast)
};
}
}
private void SetPseudoClasses()
@@ -162,7 +176,7 @@ internal sealed class CalendarDayButton : AvaloniaButton
}
PseudoClasses.Set(StdPseudoClass.Selected, IsSelected);
PseudoClasses.Set(InactivePC, IsInactive);
PseudoClasses.Set(StdPseudoClass.InActive, IsInactive);
PseudoClasses.Set(TodayPC, IsToday);
PseudoClasses.Set(BlackoutPC, IsBlackout);
PseudoClasses.Set(DayfocusedPC, IsCurrent && IsEnabled);
@@ -230,4 +244,11 @@ internal sealed class CalendarDayButton : AvaloniaButton
if (e.InitialPressMouseButton == MouseButton.Left) CalendarDayButtonMouseUp?.Invoke(this, e);
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
TokenResourceBinder.CreateGlobalTokenBinding(this, BorderThicknessProperty, GlobalTokenResourceKey.BorderThickness, BindingPriority.Template,
new RenderScaleAwareThicknessConfigure(this));
}
}
@@ -0,0 +1,93 @@
using AtomUI.Theme;
using AtomUI.Theme.Styling;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Styling;
namespace AtomUI.Controls;
[ControlThemeProvider]
internal class CalendarDayButtonTheme : BaseControlTheme
{
private const string ContentPart = "PART_Content";
public CalendarDayButtonTheme()
: base(typeof(CalendarDayButton))
{
}
protected override IControlTemplate BuildControlTemplate()
{
return new FuncControlTemplate<CalendarDayButton>((calendarDayButton, scope) =>
{
var contentPresenter = new ContentPresenter()
{
Name = ContentPart,
};
CreateTemplateParentBinding(contentPresenter, ContentPresenter.PaddingProperty, CalendarDayButton.PaddingProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ForegroundProperty, CalendarDayButton.ForegroundProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BackgroundProperty, CalendarDayButton.BackgroundProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.CornerRadiusProperty, CalendarDayButton.CornerRadiusProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BorderBrushProperty, CalendarDayButton.BorderBrushProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BorderThicknessProperty, CalendarDayButton.BorderThicknessProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.FontSizeProperty, CalendarDayButton.FontSizeProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentProperty, CalendarDayButton.ContentProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentTemplateProperty, CalendarDayButton.ContentTemplateProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.HorizontalAlignmentProperty, CalendarDayButton.HorizontalAlignmentProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.VerticalAlignmentProperty, CalendarDayButton.VerticalAlignmentProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.HorizontalContentAlignmentProperty, CalendarDayButton.HorizontalContentAlignmentProperty);
CreateTemplateParentBinding(contentPresenter, ContentPresenter.VerticalContentAlignmentProperty, CalendarDayButton.VerticalContentAlignmentProperty);
return contentPresenter;
});
}
protected override void BuildStyles()
{
var commonStyle = new Style(selector => selector.Nesting());
commonStyle.Add(CalendarDayButton.ClickModeProperty, ClickMode.Release);
commonStyle.Add(CalendarDayButton.CursorProperty, new Cursor(StandardCursorType.Hand));
commonStyle.Add(CalendarDayButton.BackgroundProperty, GlobalTokenResourceKey.ColorTransparent);
commonStyle.Add(CalendarDayButton.ForegroundProperty, GlobalTokenResourceKey.ColorTextLabel);
commonStyle.Add(CalendarDayButton.CornerRadiusProperty, GlobalTokenResourceKey.BorderRadiusSM);
commonStyle.Add(CalendarDayButton.BorderBrushProperty, GlobalTokenResourceKey.ColorTransparent);
commonStyle.Add(CalendarDayButton.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
commonStyle.Add(CalendarDayButton.VerticalAlignmentProperty, VerticalAlignment.Stretch);
commonStyle.Add(CalendarDayButton.HorizontalContentAlignmentProperty, HorizontalAlignment.Center);
commonStyle.Add(CalendarDayButton.VerticalContentAlignmentProperty, VerticalAlignment.Center);
commonStyle.Add(CalendarDayButton.FontSizeProperty, GlobalTokenResourceKey.FontSize);
commonStyle.Add(CalendarDayButton.WidthProperty, CalendarTokenResourceKey.CellWidth);
commonStyle.Add(CalendarDayButton.HeightProperty, CalendarTokenResourceKey.CellHeight);
commonStyle.Add(CalendarDayButton.MarginProperty, CalendarTokenResourceKey.CellMargin);
var contentStyle = new Style(selector => selector.Nesting().Template().Name(ContentPart));
contentStyle.Add(ContentPresenter.LineHeightProperty, CalendarTokenResourceKey.CellLineHeight);
commonStyle.Add(contentStyle);
var hoverStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.PointerOver));
hoverStyle.Add(CalendarDayButton.BackgroundProperty, CalendarTokenResourceKey.CellHoverBg);
commonStyle.Add(hoverStyle);
var inactiveStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.InActive));
inactiveStyle.Add(CalendarDayButton.ForegroundProperty, GlobalTokenResourceKey.ColorTextDisabled);
commonStyle.Add(inactiveStyle);
var todayStyle = new Style(selector => selector.Nesting().Class(CalendarDayButton.TodayPC));
todayStyle.Add(CalendarDayButton.BorderBrushProperty, GlobalTokenResourceKey.ColorPrimary);
commonStyle.Add(todayStyle);
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
selectedStyle.Add(CalendarDayButton.BackgroundProperty, GlobalTokenResourceKey.ColorPrimary);
selectedStyle.Add(CalendarDayButton.ForegroundProperty, GlobalTokenResourceKey.ColorWhite);
selectedStyle.Add(CalendarDayButton.BorderThicknessProperty, new Thickness(0));
commonStyle.Add(selectedStyle);
Add(commonStyle);
}
}
+9 -9
View File
@@ -31,9 +31,9 @@ internal sealed class CalendarItem : TemplatedControl
/// </summary>
private const int NumberOfDaysPerWeek = 7;
private AvaloniaButton? _headerButton;
private AvaloniaButton? _nextButton;
private AvaloniaButton? _previousButton;
private HeadTextButton? _headerButton;
private IconButton? _nextButton;
private IconButton? _previousButton;
private DateTime _currentMonth;
private bool _isMouseLeftButtonDown;
@@ -69,7 +69,7 @@ internal sealed class CalendarItem : TemplatedControl
/// Gets the button that allows switching between month mode, year mode,
/// and decade mode.
/// </summary>
internal AvaloniaButton? HeaderButton
internal HeadTextButton? HeaderButton
{
get => _headerButton;
private set
@@ -89,7 +89,7 @@ internal sealed class CalendarItem : TemplatedControl
/// Gets the button that displays the next page of the calendar when it
/// is clicked.
/// </summary>
internal AvaloniaButton? NextButton
internal IconButton? NextButton
{
get => _nextButton;
private set
@@ -118,7 +118,7 @@ internal sealed class CalendarItem : TemplatedControl
/// Gets the button that displays the previous page of the calendar when
/// it is clicked.
/// </summary>
internal AvaloniaButton? PreviousButton
internal IconButton? PreviousButton
{
get => _previousButton;
private set
@@ -230,9 +230,9 @@ internal sealed class CalendarItem : TemplatedControl
/// </summary>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
HeaderButton = e.NameScope.Find<AvaloniaButton>(CalendarItemTheme.HeaderButtonPart);
PreviousButton = e.NameScope.Find<AvaloniaButton>(CalendarItemTheme.PreviousButtonPart);
NextButton = e.NameScope.Find<AvaloniaButton>(CalendarItemTheme.NextButtonPart);
HeaderButton = e.NameScope.Find<HeadTextButton>(CalendarItemTheme.HeaderButtonPart);
PreviousButton = e.NameScope.Find<IconButton>(CalendarItemTheme.PreviousButtonPart);
NextButton = e.NameScope.Find<IconButton>(CalendarItemTheme.NextButtonPart);
MonthView = e.NameScope.Find<Grid>(CalendarItemTheme.MonthViewPart);
YearView = e.NameScope.Find<Grid>(CalendarItemTheme.YearViewPart);
@@ -1,10 +1,11 @@
using AtomUI.Theme;
using AtomUI.Theme.Styling;
using AtomUI.Utils;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Layout;
using Avalonia.Styling;
using AvaloniaButton = Avalonia.Controls.Button;
namespace AtomUI.Controls;
@@ -15,6 +16,7 @@ internal class CalendarItemTheme : BaseControlTheme
public const string ItemRootLayoutPart = "PART_ItemRootLayout";
public const string MonthViewPart = "PART_MonthView";
public const string YearViewPart = "PART_YearView";
public const string HeaderLayoutPart = "PART_HeaderLayout";
public const string PreviousButtonPart = "PART_PreviousButton";
public const string HeaderButtonPart = "PART_HeaderButton";
@@ -33,11 +35,6 @@ internal class CalendarItemTheme : BaseControlTheme
{
Name = ItemFramePart
};
CreateTemplateParentBinding(frame, Border.BorderBrushProperty, CalendarItem.BorderBrushProperty);
CreateTemplateParentBinding(frame, Border.BorderThicknessProperty, CalendarItem.BorderThicknessProperty);
CreateTemplateParentBinding(frame, Border.CornerRadiusProperty, CalendarItem.CornerRadiusProperty);
CreateTemplateParentBinding(frame, Border.BackgroundProperty, CalendarItem.BackgroundProperty);
var rootLayout = new DockPanel()
{
@@ -63,6 +60,7 @@ internal class CalendarItemTheme : BaseControlTheme
{
var headerLayout = new Grid()
{
Name = HeaderLayoutPart,
ColumnDefinitions = new ColumnDefinitions()
{
new ColumnDefinition(GridLength.Auto),
@@ -70,15 +68,29 @@ internal class CalendarItemTheme : BaseControlTheme
new ColumnDefinition(GridLength.Auto),
}
};
var previousButton = new AvaloniaButton()
var previousButtonIcon = new PathIcon()
{
Name = PreviousButtonPart
Kind = "LeftOutlined"
};
TokenResourceBinder.CreateGlobalTokenBinding(previousButtonIcon, PathIcon.NormalFilledBrushProperty, GlobalTokenResourceKey.ColorTextDescription);
TokenResourceBinder.CreateGlobalTokenBinding(previousButtonIcon, PathIcon.ActiveFilledBrushProperty, GlobalTokenResourceKey.ColorText);
TokenResourceBinder.CreateGlobalTokenBinding(previousButtonIcon, PathIcon.SelectedFilledBrushProperty, GlobalTokenResourceKey.ColorText);
var previousButton = new IconButton()
{
Name = PreviousButtonPart,
Icon = previousButtonIcon
};
TokenResourceBinder.CreateGlobalTokenBinding(previousButton, IconButton.IconWidthProperty, GlobalTokenResourceKey.IconSize);
TokenResourceBinder.CreateGlobalTokenBinding(previousButton, IconButton.IconHeightProperty, GlobalTokenResourceKey.IconSize);
previousButton.RegisterInNameScope(scope);
Grid.SetColumn(previousButton, 0);
headerLayout.Children.Add(previousButton);
var headerButton = new AvaloniaButton()
var headerButton = new HeadTextButton()
{
Name = HeaderButtonPart
};
@@ -86,10 +98,22 @@ internal class CalendarItemTheme : BaseControlTheme
headerButton.RegisterInNameScope(scope);
headerLayout.Children.Add(headerButton);
var nextButton = new AvaloniaButton()
var nextButtonIcon = new PathIcon()
{
Name = NextButtonPart
Kind = "RightOutlined"
};
TokenResourceBinder.CreateGlobalTokenBinding(nextButtonIcon, PathIcon.NormalFilledBrushProperty, GlobalTokenResourceKey.ColorTextDescription);
TokenResourceBinder.CreateGlobalTokenBinding(nextButtonIcon, PathIcon.ActiveFilledBrushProperty, GlobalTokenResourceKey.ColorText);
TokenResourceBinder.CreateGlobalTokenBinding(nextButtonIcon, PathIcon.SelectedFilledBrushProperty, GlobalTokenResourceKey.ColorText);
var nextButton = new IconButton()
{
Name = NextButtonPart,
Icon = nextButtonIcon
};
TokenResourceBinder.CreateGlobalTokenBinding(nextButton, IconButton.IconWidthProperty, GlobalTokenResourceKey.IconSize);
TokenResourceBinder.CreateGlobalTokenBinding(nextButton, IconButton.IconHeightProperty, GlobalTokenResourceKey.IconSize);
Grid.SetColumn(nextButton, 2);
nextButton.RegisterInNameScope(scope);
headerLayout.Children.Add(nextButton);
@@ -99,6 +123,9 @@ internal class CalendarItemTheme : BaseControlTheme
private void BuildContentView(DockPanel layout, INameScope scope)
{
var dayTitleRowDef = new RowDefinition();
TokenResourceBinder.CreateTokenBinding(dayTitleRowDef, RowDefinition.HeightProperty, CalendarTokenResourceKey.DayTitleHeight);
var monthView = new Grid()
{
Name = MonthViewPart,
@@ -106,7 +133,7 @@ internal class CalendarItemTheme : BaseControlTheme
IsVisible = false,
RowDefinitions = new RowDefinitions()
{
new RowDefinition(30, GridUnitType.Pixel),
dayTitleRowDef,
new RowDefinition(GridLength.Star),
new RowDefinition(GridLength.Star),
new RowDefinition(GridLength.Star),
@@ -153,9 +180,15 @@ internal class CalendarItemTheme : BaseControlTheme
protected override void BuildStyles()
{
var commonStyle = new Style(selector => selector.Nesting());
commonStyle.Add(CalendarItem.BorderBrushProperty, GlobalTokenResourceKey.ColorBorder);
commonStyle.Add(CalendarItem.CornerRadiusProperty, GlobalTokenResourceKey.BorderRadius);
commonStyle.Add(CalendarItem.BackgroundProperty, GlobalTokenResourceKey.ColorBgContainer);
commonStyle.Add(CalendarItem.MinWidthProperty, CalendarTokenResourceKey.ItemPanelMinWidth);
commonStyle.Add(CalendarItem.MinHeightProperty, CalendarTokenResourceKey.ItemPanelMinHeight);
var headerLayoutStyle = new Style(selector => selector.Nesting().Template().Name(HeaderLayoutPart));
headerLayoutStyle.Add(Grid.MarginProperty, CalendarTokenResourceKey.HeaderMargin);
commonStyle.Add(headerLayoutStyle);
Add(commonStyle);
}
}
@@ -164,7 +197,13 @@ internal class DayTitleTemplate : ITemplate<Control>
{
public Control Build()
{
return new TextBlock();
var textBlock = new TextBlock()
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
};
textBlock.Bind(TextBlock.TextProperty, new Binding());
return textBlock;
}
object? ITemplate.Build()
+22 -8
View File
@@ -2,6 +2,7 @@
using AtomUI.Theme.Styling;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Layout;
using Avalonia.Styling;
namespace AtomUI.Controls;
@@ -11,6 +12,7 @@ internal class CalendarTheme : BaseControlTheme
{
public const string RootPart = "PART_Root";
public const string CalendarItemPart = "PART_CalendarItem";
public const string FramePart = "PART_Frame";
public CalendarTheme()
: base(typeof(Calendar))
@@ -22,6 +24,17 @@ internal class CalendarTheme : BaseControlTheme
{
return new FuncControlTemplate<Calendar>((calendar, scope) =>
{
var frame = new Border()
{
Name = FramePart
};
CreateTemplateParentBinding(frame, Border.BorderBrushProperty, Calendar.BorderBrushProperty);
CreateTemplateParentBinding(frame, Border.BorderThicknessProperty, Calendar.BorderThicknessProperty);
CreateTemplateParentBinding(frame, Border.CornerRadiusProperty, Calendar.CornerRadiusProperty);
CreateTemplateParentBinding(frame, Border.BackgroundProperty, Calendar.BackgroundProperty);
CreateTemplateParentBinding(frame, Border.PaddingProperty, Calendar.PaddingProperty);
var rootLayout = new StackPanel()
{
Name = RootPart,
@@ -31,16 +44,16 @@ internal class CalendarTheme : BaseControlTheme
var calendarItem = new CalendarItem()
{
Name = CalendarItemPart
Name = CalendarItemPart,
HorizontalAlignment = HorizontalAlignment.Center
};
calendarItem.RegisterInNameScope(scope);
CreateTemplateParentBinding(calendarItem, CalendarItem.BorderBrushProperty, Calendar.BorderBrushProperty);
CreateTemplateParentBinding(calendarItem, CalendarItem.BorderThicknessProperty, Calendar.BorderThicknessProperty);
CreateTemplateParentBinding(calendarItem, CalendarItem.CornerRadiusProperty, Calendar.CornerRadiusProperty);
CreateTemplateParentBinding(calendarItem, CalendarItem.BackgroundProperty, Calendar.BackgroundProperty);
rootLayout.Children.Add(calendarItem);
return rootLayout;
calendarItem.RegisterInNameScope(scope);
rootLayout.Children.Add(calendarItem);
frame.Child = rootLayout;
return frame;
});
}
@@ -50,6 +63,7 @@ internal class CalendarTheme : BaseControlTheme
commonStyle.Add(Calendar.BorderBrushProperty, GlobalTokenResourceKey.ColorBorder);
commonStyle.Add(Calendar.CornerRadiusProperty, GlobalTokenResourceKey.BorderRadius);
commonStyle.Add(Calendar.BackgroundProperty, GlobalTokenResourceKey.ColorBgContainer);
commonStyle.Add(Calendar.PaddingProperty, CalendarTokenResourceKey.PanelContentPadding);
Add(commonStyle);
}
}
+45 -1
View File
@@ -1,5 +1,7 @@
using AtomUI.Media;
using AtomUI.Theme.TokenSystem;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
namespace AtomUI.Controls;
@@ -49,16 +51,51 @@ internal class CalendarToken : AbstractControlDesignToken
/// </summary>
public double CellWidth { get; set; }
/// <summary>
/// 单元格行高
/// </summary>
public double CellLineHeight { get; set; }
/// <summary>
/// 单元格外边距
/// </summary>
public Thickness CellMargin { get; set; }
/// <summary>
/// 日历项最小宽度
/// </summary>
public double ItemPanelMinWidth { get; set; }
/// <summary>
/// 日历项最小高度
/// </summary>
public double ItemPanelMinHeight { get; set; }
/// <summary>
/// 单元格文本高度
/// </summary>
public double TextHeight { get; set; }
/// <summary>
/// 面板内容内边距
/// </summary>
public Thickness PanelContentPadding { get; set; }
/// <summary>
/// 十年/年/季/月/周单元格高度
/// </summary>
public double WithoutTimeCellHeight { get; set; }
/// <summary>
/// 星期的高度
/// </summary>
public GridLength DayTitleHeight { get; set; }
/// <summary>
/// Header 头外边距
/// </summary>
public Thickness HeaderMargin { get; set; }
internal override void CalculateFromAlias()
{
base.CalculateFromAlias();
@@ -70,9 +107,16 @@ internal class CalendarToken : AbstractControlDesignToken
CellHoverWithRangeBg = colorPrimary.Lighten(35);
CellRangeBorderColor = colorPrimary.Lighten(20);
CellBgDisabled = _globalToken.ColorBgContainerDisabled;
CellWidth = _globalToken.HeightToken.ControlHeightSM * 1.5;
CellWidth = _globalToken.HeightToken.ControlHeightSM;
CellHeight = _globalToken.HeightToken.ControlHeightSM;
TextHeight = _globalToken.HeightToken.ControlHeightLG;
WithoutTimeCellHeight = _globalToken.HeightToken.ControlHeightLG * 1.65;
CellMargin = new Thickness(_globalToken.MarginXXS);
PanelContentPadding = new Thickness(_globalToken.PaddingSM);
ItemPanelMinWidth = 230;
ItemPanelMinHeight = 260;
DayTitleHeight = new GridLength(40, GridUnitType.Pixel);
HeaderMargin = new Thickness(0, 0, 0, _globalToken.MarginXS);
CellLineHeight = CellHeight - 2; // 不知道为啥设置成一样,或者不设置文字有些靠下
}
}
@@ -1,5 +1,6 @@
using System.Diagnostics;
using System.Globalization;
using AtomUI.Theme;
namespace AtomUI.Controls;
@@ -67,14 +68,15 @@ internal static class DateTimeHelper
public static DateTimeFormatInfo GetCurrentDateFormat()
{
if (CultureInfo.CurrentCulture.Calendar is GregorianCalendar) {
return CultureInfo.CurrentCulture.DateTimeFormat;
var culture = ThemeManager.Current.CultureInfo ?? CultureInfo.CurrentCulture;
if (culture.Calendar is GregorianCalendar) {
return culture.DateTimeFormat;
} else {
foreach (System.Globalization.Calendar cal in CultureInfo.CurrentCulture.OptionalCalendars) {
foreach (System.Globalization.Calendar cal in culture.OptionalCalendars) {
if (cal is GregorianCalendar) {
// if the default calendar is not Gregorian, return the
// first supported GregorianCalendar dtfi
DateTimeFormatInfo dtfi = new CultureInfo(CultureInfo.CurrentCulture.Name).DateTimeFormat;
DateTimeFormatInfo dtfi = new CultureInfo(culture.Name).DateTimeFormat;
dtfi.Calendar = cal;
return dtfi;
}
@@ -0,0 +1,24 @@
using AtomUI.Media;
using AtomUI.Theme.Styling;
using AtomUI.Theme.Utils;
using Avalonia.Animation;
using Avalonia.Controls.Primitives;
namespace AtomUI.Controls;
using AvaloniaButton = Avalonia.Controls.Button;
internal class HeadTextButton : AvaloniaButton
{
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
if (Transitions is null) {
Transitions = new Transitions()
{
AnimationUtils.CreateTransition<SolidColorBrushTransition>(ForegroundProperty, GlobalTokenResourceKey.MotionDurationFast)
};
}
}
}
@@ -0,0 +1,51 @@
using AtomUI.Theme;
using AtomUI.Theme.Styling;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Styling;
namespace AtomUI.Controls;
[ControlThemeProvider]
internal class HeadTextButtonTheme : BaseControlTheme
{
private const string ContentPart = "PART_Content";
public HeadTextButtonTheme() : base(typeof(HeadTextButton)) {}
protected override IControlTemplate BuildControlTemplate()
{
return new FuncControlTemplate<HeadTextButton>((headTextButton, scope) =>
{
var content = new ContentPresenter()
{
Name = ContentPart,
HorizontalContentAlignment = HorizontalAlignment.Center,
VerticalContentAlignment = VerticalAlignment.Center
};
CreateTemplateParentBinding(content, ContentPresenter.ContentProperty, HeadTextButton.ContentProperty);
CreateTemplateParentBinding(content, ContentPresenter.ContentTemplateProperty, HeadTextButton.ContentTemplateProperty);
CreateTemplateParentBinding(content, ContentPresenter.BackgroundProperty, HeadTextButton.BackgroundProperty);
return content;
});
}
protected override void BuildStyles()
{
var commonStyle = new Style(selector => selector.Nesting());
commonStyle.Add(HeadTextButton.HorizontalAlignmentProperty, HorizontalAlignment.Center);
commonStyle.Add(HeadTextButton.BackgroundProperty, GlobalTokenResourceKey.ColorTransparent);
commonStyle.Add(HeadTextButton.FontWeightProperty, FontWeight.SemiBold);
commonStyle.Add(HeadTextButton.FontSizeProperty, GlobalTokenResourceKey.FontSize);
commonStyle.Add(HeadTextButton.CursorProperty, new Cursor(StandardCursorType.Hand));
var hoverStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.PointerOver));
hoverStyle.Add(HeadTextButton.ForegroundProperty, GlobalTokenResourceKey.ColorPrimary);
commonStyle.Add(hoverStyle);
Add(commonStyle);
}
}
@@ -18,8 +18,11 @@
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.SplitButtonTheme());
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.TextButtonTheme());
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.ToggleIconButtonTheme());
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CalendarButtonTheme());
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CalendarDayButtonTheme());
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CalendarItemTheme());
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CalendarTheme());
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.HeadTextButtonTheme());
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CheckBoxTheme());
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CollapseItemTheme());
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CollapseTheme());
@@ -137,8 +137,15 @@ namespace AtomUI.Theme.Styling
public static readonly TokenResourceKey CellRangeBorderColor = new TokenResourceKey("Calendar.CellRangeBorderColor", "AtomUI.Token");
public static readonly TokenResourceKey CellHeight = new TokenResourceKey("Calendar.CellHeight", "AtomUI.Token");
public static readonly TokenResourceKey CellWidth = new TokenResourceKey("Calendar.CellWidth", "AtomUI.Token");
public static readonly TokenResourceKey CellLineHeight = new TokenResourceKey("Calendar.CellLineHeight", "AtomUI.Token");
public static readonly TokenResourceKey CellMargin = new TokenResourceKey("Calendar.CellMargin", "AtomUI.Token");
public static readonly TokenResourceKey ItemPanelMinWidth = new TokenResourceKey("Calendar.ItemPanelMinWidth", "AtomUI.Token");
public static readonly TokenResourceKey ItemPanelMinHeight = new TokenResourceKey("Calendar.ItemPanelMinHeight", "AtomUI.Token");
public static readonly TokenResourceKey TextHeight = new TokenResourceKey("Calendar.TextHeight", "AtomUI.Token");
public static readonly TokenResourceKey PanelContentPadding = new TokenResourceKey("Calendar.PanelContentPadding", "AtomUI.Token");
public static readonly TokenResourceKey WithoutTimeCellHeight = new TokenResourceKey("Calendar.WithoutTimeCellHeight", "AtomUI.Token");
public static readonly TokenResourceKey DayTitleHeight = new TokenResourceKey("Calendar.DayTitleHeight", "AtomUI.Token");
public static readonly TokenResourceKey HeaderMargin = new TokenResourceKey("Calendar.HeaderMargin", "AtomUI.Token");
}
public static class CheckBoxTokenResourceKey
+17 -16
View File
@@ -2,20 +2,21 @@
public static class StdPseudoClass
{
public const string Disabled = ":disabled";
public const string Focus = ":focus";
public const string FocusWithIn = ":focus-within";
public const string PointerOver = ":pointerover";
public const string Checked = ":checked";
public const string UnChecked = ":unchecked";
public const string Pressed = ":pressed";
public const string Selected = ":selected";
public const string Indeterminate = ":indeterminate";
public const string Dragging = ":dragging";
public const string Empty = ":empty";
public const string FlyoutOpen = ":flyout-open";
public const string Expanded = ":expanded";
public const string Open = ":open";
public const string Horizontal = ":horizontal";
public const string Vertical = ":vertical";
public const string Disabled = ":disabled";
public const string Focus = ":focus";
public const string FocusWithIn = ":focus-within";
public const string PointerOver = ":pointerover";
public const string Checked = ":checked";
public const string UnChecked = ":unchecked";
public const string Pressed = ":pressed";
public const string Selected = ":selected";
public const string Indeterminate = ":indeterminate";
public const string Dragging = ":dragging";
public const string Empty = ":empty";
public const string FlyoutOpen = ":flyout-open";
public const string Expanded = ":expanded";
public const string Open = ":open";
public const string Horizontal = ":horizontal";
public const string Vertical = ":vertical";
public const string InActive = ":inactive";
}