From 2e4e4de2a1a9e235fc4abdf1f54574fa69936a48 Mon Sep 17 00:00:00 2001 From: polarboy Date: Fri, 6 Sep 2024 22:52:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=9F=BA=E6=9C=AC=E7=9A=84?= =?UTF-8?q?=E6=97=A5=E5=8E=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Calendar/CalendarButton.cs | 22 +++-- .../Calendar/CalendarButtonTheme.cs | 88 ++++++++++++++++++ .../Calendar/CalendarDayButton.cs | 35 +++++-- .../Calendar/CalendarDayButtonTheme.cs | 93 +++++++++++++++++++ src/AtomUI.Controls/Calendar/CalendarItem.cs | 18 ++-- .../Calendar/CalendarItemTheme.cs | 71 ++++++++++---- src/AtomUI.Controls/Calendar/CalendarTheme.cs | 30 ++++-- src/AtomUI.Controls/Calendar/CalendarToken.cs | 46 ++++++++- .../Calendar/DateTimeHelper.cs | 10 +- .../Calendar/HeadTextButton.cs | 24 +++++ .../Calendar/HeadTextButtonTheme.cs | 51 ++++++++++ .../ControlThemeRegister.g.cs | 3 + .../TokenResourceConst.g.cs | 7 ++ src/AtomUI.Controls/StdPseudoClass.cs | 33 +++---- 14 files changed, 464 insertions(+), 67 deletions(-) create mode 100644 src/AtomUI.Controls/Calendar/CalendarButtonTheme.cs create mode 100644 src/AtomUI.Controls/Calendar/CalendarDayButtonTheme.cs create mode 100644 src/AtomUI.Controls/Calendar/HeadTextButton.cs create mode 100644 src/AtomUI.Controls/Calendar/HeadTextButtonTheme.cs diff --git a/src/AtomUI.Controls/Calendar/CalendarButton.cs b/src/AtomUI.Controls/Calendar/CalendarButton.cs index 57cf27513..18834664a 100644 --- a/src/AtomUI.Controls/Calendar/CalendarButton.cs +++ b/src/AtomUI.Controls/Calendar/CalendarButton.cs @@ -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 /// . /// -[PseudoClasses(":selected", ":inactive", ":btnfocused")] +[PseudoClasses(StdPseudoClass.Selected, StdPseudoClass.InActive, BtnFocusedPC)] internal sealed class CalendarButton : AvaloniaButton { + private const string BtnFocusedPC = ":btnfocused"; /// /// A value indicating whether the button is focused. /// @@ -34,7 +39,6 @@ internal sealed class CalendarButton : AvaloniaButton /// class. /// 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(BackgroundProperty, GlobalTokenResourceKey.MotionDurationFast) + }; + } } /// @@ -104,9 +114,9 @@ internal sealed class CalendarButton : AvaloniaButton /// 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); } /// diff --git a/src/AtomUI.Controls/Calendar/CalendarButtonTheme.cs b/src/AtomUI.Controls/Calendar/CalendarButtonTheme.cs new file mode 100644 index 000000000..f0aa89da1 --- /dev/null +++ b/src/AtomUI.Controls/Calendar/CalendarButtonTheme.cs @@ -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, 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); + } +} \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/CalendarDayButton.cs b/src/AtomUI.Controls/Calendar/CalendarDayButton.cs index 5d5caf288..fa9bb998a 100644 --- a/src/AtomUI.Controls/Calendar/CalendarDayButton.cs +++ b/src/AtomUI.Controls/Calendar/CalendarDayButton.cs @@ -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"; + /// /// Default content for the CalendarDayButton. /// @@ -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(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)); + } } \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/CalendarDayButtonTheme.cs b/src/AtomUI.Controls/Calendar/CalendarDayButtonTheme.cs new file mode 100644 index 000000000..9aa3b8cc0 --- /dev/null +++ b/src/AtomUI.Controls/Calendar/CalendarDayButtonTheme.cs @@ -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, 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); + } +} \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/CalendarItem.cs b/src/AtomUI.Controls/Calendar/CalendarItem.cs index ad5f45477..8ed8c0690 100644 --- a/src/AtomUI.Controls/Calendar/CalendarItem.cs +++ b/src/AtomUI.Controls/Calendar/CalendarItem.cs @@ -31,9 +31,9 @@ internal sealed class CalendarItem : TemplatedControl /// 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. /// - 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. /// - 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. /// - internal AvaloniaButton? PreviousButton + internal IconButton? PreviousButton { get => _previousButton; private set @@ -230,9 +230,9 @@ internal sealed class CalendarItem : TemplatedControl /// protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { - HeaderButton = e.NameScope.Find(CalendarItemTheme.HeaderButtonPart); - PreviousButton = e.NameScope.Find(CalendarItemTheme.PreviousButtonPart); - NextButton = e.NameScope.Find(CalendarItemTheme.NextButtonPart); + HeaderButton = e.NameScope.Find(CalendarItemTheme.HeaderButtonPart); + PreviousButton = e.NameScope.Find(CalendarItemTheme.PreviousButtonPart); + NextButton = e.NameScope.Find(CalendarItemTheme.NextButtonPart); MonthView = e.NameScope.Find(CalendarItemTheme.MonthViewPart); YearView = e.NameScope.Find(CalendarItemTheme.YearViewPart); diff --git a/src/AtomUI.Controls/Calendar/CalendarItemTheme.cs b/src/AtomUI.Controls/Calendar/CalendarItemTheme.cs index 6345cf944..6d94c497b 100644 --- a/src/AtomUI.Controls/Calendar/CalendarItemTheme.cs +++ b/src/AtomUI.Controls/Calendar/CalendarItemTheme.cs @@ -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 { 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() diff --git a/src/AtomUI.Controls/Calendar/CalendarTheme.cs b/src/AtomUI.Controls/Calendar/CalendarTheme.cs index ce7c7d4bc..352f5b7de 100644 --- a/src/AtomUI.Controls/Calendar/CalendarTheme.cs +++ b/src/AtomUI.Controls/Calendar/CalendarTheme.cs @@ -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, 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); } } \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/CalendarToken.cs b/src/AtomUI.Controls/Calendar/CalendarToken.cs index d8a13d510..e63effa31 100644 --- a/src/AtomUI.Controls/Calendar/CalendarToken.cs +++ b/src/AtomUI.Controls/Calendar/CalendarToken.cs @@ -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 /// public double CellWidth { get; set; } + /// + /// 单元格行高 + /// + public double CellLineHeight { get; set; } + + /// + /// 单元格外边距 + /// + public Thickness CellMargin { get; set; } + + /// + /// 日历项最小宽度 + /// + public double ItemPanelMinWidth { get; set; } + + /// + /// 日历项最小高度 + /// + public double ItemPanelMinHeight { get; set; } + /// /// 单元格文本高度 /// public double TextHeight { get; set; } + /// + /// 面板内容内边距 + /// + public Thickness PanelContentPadding { get; set; } + /// /// 十年/年/季/月/周单元格高度 /// public double WithoutTimeCellHeight { get; set; } + /// + /// 星期的高度 + /// + public GridLength DayTitleHeight { get; set; } + + /// + /// Header 头外边距 + /// + 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; // 不知道为啥设置成一样,或者不设置文字有些靠下 } } \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/DateTimeHelper.cs b/src/AtomUI.Controls/Calendar/DateTimeHelper.cs index 80ca7823e..217b40c4c 100644 --- a/src/AtomUI.Controls/Calendar/DateTimeHelper.cs +++ b/src/AtomUI.Controls/Calendar/DateTimeHelper.cs @@ -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; } diff --git a/src/AtomUI.Controls/Calendar/HeadTextButton.cs b/src/AtomUI.Controls/Calendar/HeadTextButton.cs new file mode 100644 index 000000000..ad162b5a4 --- /dev/null +++ b/src/AtomUI.Controls/Calendar/HeadTextButton.cs @@ -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(ForegroundProperty, GlobalTokenResourceKey.MotionDurationFast) + }; + } + } + +} \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/HeadTextButtonTheme.cs b/src/AtomUI.Controls/Calendar/HeadTextButtonTheme.cs new file mode 100644 index 000000000..6049a103e --- /dev/null +++ b/src/AtomUI.Controls/Calendar/HeadTextButtonTheme.cs @@ -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, 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); + } +} \ No newline at end of file diff --git a/src/AtomUI.Controls/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.ControlThemeRegisterGenerator/ControlThemeRegister.g.cs b/src/AtomUI.Controls/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.ControlThemeRegisterGenerator/ControlThemeRegister.g.cs index 44ee95c92..ca07e8f1d 100644 --- a/src/AtomUI.Controls/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.ControlThemeRegisterGenerator/ControlThemeRegister.g.cs +++ b/src/AtomUI.Controls/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.ControlThemeRegisterGenerator/ControlThemeRegister.g.cs @@ -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()); diff --git a/src/AtomUI.Controls/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.TokenResourceKeyGenerator/TokenResourceConst.g.cs b/src/AtomUI.Controls/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.TokenResourceKeyGenerator/TokenResourceConst.g.cs index 01d649c64..fcfc969c5 100644 --- a/src/AtomUI.Controls/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.TokenResourceKeyGenerator/TokenResourceConst.g.cs +++ b/src/AtomUI.Controls/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.TokenResourceKeyGenerator/TokenResourceConst.g.cs @@ -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 diff --git a/src/AtomUI.Controls/StdPseudoClass.cs b/src/AtomUI.Controls/StdPseudoClass.cs index 5b4444776..ad56960cc 100644 --- a/src/AtomUI.Controls/StdPseudoClass.cs +++ b/src/AtomUI.Controls/StdPseudoClass.cs @@ -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"; } \ No newline at end of file