mirror of
https://gitee.com/chinware/atomui.git
synced 2024-11-29 18:38:16 +08:00
Add AtomUI.Controls.CalendarPresenter.Calendar
This commit is contained in:
parent
8b03543524
commit
5ecbaa81f1
@ -23,9 +23,9 @@ public static class AtomUIExtensions
|
||||
builder.AfterSetup(builder =>
|
||||
{
|
||||
var themeManager = ThemeManager.Current;
|
||||
themeManager.CultureInfo = new CultureInfo(LanguageCode.en_US);
|
||||
themeManager.LoadTheme(ThemeManager.DEFAULT_THEME_ID);
|
||||
themeManager.SetActiveTheme(ThemeManager.DEFAULT_THEME_ID);
|
||||
themeManager.CultureInfo = new CultureInfo(LanguageCode.en_US);
|
||||
builder.Instance!.Styles.Add(themeManager);
|
||||
});
|
||||
return builder;
|
||||
|
@ -36,6 +36,9 @@ internal class Program
|
||||
catch (Exception ex)
|
||||
{
|
||||
File.WriteAllText("error.log", ex.ToString());
|
||||
#if DEBUG
|
||||
throw;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,5 +3,7 @@
|
||||
<assembly fullname="AtomUI.Theme" preserve="All"/>
|
||||
<assembly fullname="Avalonia.Base" preserve="All"/>
|
||||
<assembly fullname="AtomUI.Controls" preserve="All"/>
|
||||
<assembly fullname="AtomUI.Icon" preserve="All"/>
|
||||
<assembly fullname="AtomUI.Icon.AntDesign" preserve="All"/>
|
||||
<assembly fullname="Avalonia.Remote.Protocol" preserve="All"/>
|
||||
</linker>
|
@ -12,8 +12,5 @@
|
||||
<atom:Calendar />
|
||||
</desktop:ShowCaseItem>
|
||||
|
||||
<desktop:ShowCaseItem Description="The simplest usage for Calendar." Title="Range Calendar">
|
||||
<atom:RangeCalendar FixedRangeStart="True" SelectedRangeStartDate="2024-9-10" SelectedRangeEndDate="2024-9-12"/>
|
||||
</desktop:ShowCaseItem>
|
||||
</desktop:ShowCasePanel>
|
||||
</UserControl>
|
@ -5,12 +5,20 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:desktop="clr-namespace:AtomUI.Demo.Desktop"
|
||||
xmlns:calendarpresenter="clr-namespace:AtomUI.Controls.CalendarPresenter;assembly=AtomUI.Controls"
|
||||
xmlns:atom="https://atomui.net"
|
||||
mc:Ignorable="d">
|
||||
<desktop:ShowCasePanel>
|
||||
<desktop:ShowCaseItem
|
||||
Title="Basic"
|
||||
Description="Click TimePicker, and then we could select or input a time in panel.">
|
||||
Description="Click DatePicker, and then we could select or input a date in panel.">
|
||||
<atom:DatePicker Watermark="Select date"/>
|
||||
</desktop:ShowCaseItem>
|
||||
|
||||
<desktop:ShowCaseItem
|
||||
Title="Basic"
|
||||
Description="Click DatePicker, and then we could select or input a date in panel.">
|
||||
<calendarpresenter:Calendar />
|
||||
</desktop:ShowCaseItem>
|
||||
</desktop:ShowCasePanel>
|
||||
</UserControl>
|
1400
src/AtomUI.Controls/DatePicker/CalendarPresenter/Calendar.cs
Normal file
1400
src/AtomUI.Controls/DatePicker/CalendarPresenter/Calendar.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,206 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
public sealed class CalendarBlackoutDatesCollection : ObservableCollection<CalendarDateRange>
|
||||
{
|
||||
/// <summary>
|
||||
/// The Calendar whose dates this object represents.
|
||||
/// </summary>
|
||||
private readonly Calendar _owner;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the
|
||||
/// <see cref="T:Avalonia.Controls.Primitives.CalendarBlackoutDatesCollection" />
|
||||
/// class.
|
||||
/// </summary>
|
||||
/// <param name="owner">
|
||||
/// The <see cref="T:Avalonia.Controls.Calendar" /> whose dates
|
||||
/// this object represents.
|
||||
/// </param>
|
||||
public CalendarBlackoutDatesCollection(Calendar owner)
|
||||
{
|
||||
_owner = owner ?? throw new ArgumentNullException(nameof(owner));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all dates before <see cref="P:System.DateTime.Today" /> to the
|
||||
/// collection.
|
||||
/// </summary>
|
||||
public void AddDatesInPast()
|
||||
{
|
||||
Add(new CalendarDateRange(DateTime.MinValue, DateTime.Today.AddDays(-1)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value that represents whether this collection contains the
|
||||
/// specified date.
|
||||
/// </summary>
|
||||
/// <param name="date">The date to search for.</param>
|
||||
/// <returns>
|
||||
/// True if the collection contains the specified date; otherwise,
|
||||
/// false.
|
||||
/// </returns>
|
||||
public bool Contains(DateTime date)
|
||||
{
|
||||
var count = Count;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if (DateTimeHelper.InRange(date, this[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value that represents whether this collection contains the
|
||||
/// specified range of dates.
|
||||
/// </summary>
|
||||
/// <param name="start">The start of the date range.</param>
|
||||
/// <param name="end">The end of the date range.</param>
|
||||
/// <returns>
|
||||
/// True if all dates in the range are contained in the collection;
|
||||
/// otherwise, false.
|
||||
/// </returns>
|
||||
public bool Contains(DateTime start, DateTime end)
|
||||
{
|
||||
DateTime rangeStart;
|
||||
DateTime rangeEnd;
|
||||
|
||||
if (DateTime.Compare(end, start) > -1)
|
||||
{
|
||||
rangeStart = DateTimeHelper.DiscardTime(start);
|
||||
rangeEnd = DateTimeHelper.DiscardTime(end);
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeStart = DateTimeHelper.DiscardTime(end);
|
||||
rangeEnd = DateTimeHelper.DiscardTime(start);
|
||||
}
|
||||
|
||||
var count = Count;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var range = this[i];
|
||||
if (DateTime.Compare(range.Start, rangeStart) == 0 && DateTime.Compare(range.End, rangeEnd) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value that represents whether this collection contains any
|
||||
/// date in the specified range.
|
||||
/// </summary>
|
||||
/// <param name="range">The range of dates to search for.</param>
|
||||
/// <returns>
|
||||
/// True if any date in the range is contained in the collection;
|
||||
/// otherwise, false.
|
||||
/// </returns>
|
||||
public bool ContainsAny(CalendarDateRange range)
|
||||
{
|
||||
return this.Any(r => r.ContainsAny(range));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all items from the collection.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This implementation raises the CollectionChanged event.
|
||||
/// </remarks>
|
||||
protected override void ClearItems()
|
||||
{
|
||||
EnsureValidThread();
|
||||
|
||||
base.ClearItems();
|
||||
_owner.UpdateMonths();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the collection at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">
|
||||
/// The zero-based index at which item should be inserted.
|
||||
/// </param>
|
||||
/// <param name="item">The object to insert.</param>
|
||||
/// <remarks>
|
||||
/// This implementation raises the CollectionChanged event.
|
||||
/// </remarks>
|
||||
protected override void InsertItem(int index, CalendarDateRange item)
|
||||
{
|
||||
EnsureValidThread();
|
||||
|
||||
if (!IsValid(item))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(item), "Value is not valid.");
|
||||
}
|
||||
|
||||
base.InsertItem(index, item);
|
||||
_owner.UpdateMonths();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the item at the specified index of the collection.
|
||||
/// </summary>
|
||||
/// <param name="index">
|
||||
/// The zero-based index of the element to remove.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// This implementation raises the CollectionChanged event.
|
||||
/// </remarks>
|
||||
protected override void RemoveItem(int index)
|
||||
{
|
||||
EnsureValidThread();
|
||||
|
||||
base.RemoveItem(index);
|
||||
_owner.UpdateMonths();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the element at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">
|
||||
/// The zero-based index of the element to replace.
|
||||
/// </param>
|
||||
/// <param name="item">
|
||||
/// The new value for the element at the specified index.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// This implementation raises the CollectionChanged event.
|
||||
/// </remarks>
|
||||
protected override void SetItem(int index, CalendarDateRange item)
|
||||
{
|
||||
EnsureValidThread();
|
||||
|
||||
if (!IsValid(item))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(item), "Value is not valid.");
|
||||
}
|
||||
|
||||
base.SetItem(index, item);
|
||||
_owner.UpdateMonths();
|
||||
}
|
||||
|
||||
private bool IsValid(CalendarDateRange item)
|
||||
{
|
||||
if (_owner.SelectedDate is not null &&
|
||||
DateTimeHelper.InRange(_owner.SelectedDate.Value, item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void EnsureValidThread()
|
||||
{
|
||||
Dispatcher.UIThread.VerifyAccess();
|
||||
}
|
||||
}
|
@ -0,0 +1,198 @@
|
||||
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;
|
||||
using AvaloniaButton = Avalonia.Controls.Button;
|
||||
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a button on a
|
||||
/// <see cref="T:Avalonia.Controls.Calendar" />.
|
||||
/// </summary>
|
||||
[PseudoClasses(StdPseudoClass.Selected, StdPseudoClass.InActive, BtnFocusedPC)]
|
||||
internal sealed class CalendarButton : AvaloniaButton
|
||||
{
|
||||
internal const string BtnFocusedPC = ":btnfocused";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Calendar associated with this button.
|
||||
/// </summary>
|
||||
internal Calendar? Owner { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A value indicating whether the button is focused.
|
||||
/// </summary>
|
||||
private bool _isCalendarButtonFocused;
|
||||
|
||||
/// <summary>
|
||||
/// A value indicating whether the button is inactive.
|
||||
/// </summary>
|
||||
private bool _isInactive;
|
||||
|
||||
/// <summary>
|
||||
/// A value indicating whether the button is selected.
|
||||
/// </summary>
|
||||
private bool _isSelected;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the
|
||||
/// <see cref="T:Avalonia.Controls.Primitives.CalendarButton" />
|
||||
/// class.
|
||||
/// </summary>
|
||||
public CalendarButton()
|
||||
{
|
||||
SetCurrentValue(ContentProperty, DateTimeHelper.GetCurrentDateFormat().AbbreviatedMonthNames[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the button is focused.
|
||||
/// </summary>
|
||||
internal bool IsCalendarButtonFocused
|
||||
{
|
||||
get => _isCalendarButtonFocused;
|
||||
|
||||
set
|
||||
{
|
||||
if (_isCalendarButtonFocused != value)
|
||||
{
|
||||
_isCalendarButtonFocused = value;
|
||||
SetPseudoClasses();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the button is inactive.
|
||||
/// </summary>
|
||||
internal bool IsInactive
|
||||
{
|
||||
get => _isInactive;
|
||||
|
||||
set
|
||||
{
|
||||
if (_isInactive != value)
|
||||
{
|
||||
_isInactive = value;
|
||||
SetPseudoClasses();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the button is selected.
|
||||
/// </summary>
|
||||
internal bool IsSelected
|
||||
{
|
||||
get => _isSelected;
|
||||
|
||||
set
|
||||
{
|
||||
if (_isSelected != value)
|
||||
{
|
||||
_isSelected = value;
|
||||
SetPseudoClasses();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the visual tree for the
|
||||
/// <see cref="T:System.Windows.Controls.Primitives.CalendarButton" />
|
||||
/// when a new template is applied.
|
||||
/// </summary>
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
SetPseudoClasses();
|
||||
if (Transitions is null)
|
||||
{
|
||||
Transitions = new Transitions
|
||||
{
|
||||
AnimationUtils.CreateTransition<SolidColorBrushTransition>(BackgroundProperty,
|
||||
GlobalTokenResourceKey.MotionDurationFast)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets PseudoClasses based on current state.
|
||||
/// </summary>
|
||||
private void SetPseudoClasses()
|
||||
{
|
||||
PseudoClasses.Set(StdPseudoClass.Selected, IsSelected);
|
||||
PseudoClasses.Set(StdPseudoClass.InActive, IsInactive);
|
||||
PseudoClasses.Set(BtnFocusedPC, IsCalendarButtonFocused && IsEnabled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the left mouse button is pressed (or when the tip of the
|
||||
/// stylus touches the tablet PC) while the mouse pointer is over a
|
||||
/// UIElement.
|
||||
/// </summary>
|
||||
public event EventHandler<PointerPressedEventArgs>? CalendarLeftMouseButtonDown;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the left mouse button is released (or the tip of the
|
||||
/// stylus is removed from the tablet PC) while the mouse (or the
|
||||
/// stylus) is over a UIElement (or while a UIElement holds mouse
|
||||
/// capture).
|
||||
/// </summary>
|
||||
public event EventHandler<PointerReleasedEventArgs>? CalendarLeftMouseButtonUp;
|
||||
|
||||
/// <summary>
|
||||
/// Provides class handling for the MouseLeftButtonDown event that
|
||||
/// occurs when the left mouse button is pressed while the mouse pointer
|
||||
/// is over this control.
|
||||
/// </summary>
|
||||
/// <param name="e">The event data. </param>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// e is a null reference (Nothing in Visual Basic).
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This method marks the MouseLeftButtonDown event as handled by
|
||||
/// setting the MouseButtonEventArgs.Handled property of the event data
|
||||
/// to true when the button is enabled and its ClickMode is not set to
|
||||
/// Hover. Since this method marks the MouseLeftButtonDown event as
|
||||
/// handled in some situations, you should use the Click event instead
|
||||
/// to detect a button click.
|
||||
/// </remarks>
|
||||
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
||||
{
|
||||
base.OnPointerPressed(e);
|
||||
|
||||
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
{
|
||||
CalendarLeftMouseButtonDown?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides handling for the MouseLeftButtonUp event that occurs when
|
||||
/// the left mouse button is released while the mouse pointer is over
|
||||
/// this control.
|
||||
/// </summary>
|
||||
/// <param name="e">The event data.</param>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// e is a null reference (Nothing in Visual Basic).
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This method marks the MouseLeftButtonUp event as handled by setting
|
||||
/// the MouseButtonEventArgs.Handled property of the event data to true
|
||||
/// when the button is enabled and its ClickMode is not set to Hover.
|
||||
/// Since this method marks the MouseLeftButtonUp event as handled in
|
||||
/// some situations, you should use the Click event instead to detect a
|
||||
/// button click.
|
||||
/// </remarks>
|
||||
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||
{
|
||||
base.OnPointerReleased(e);
|
||||
if (e.InitialPressMouseButton == MouseButton.Left)
|
||||
{
|
||||
CalendarLeftMouseButtonUp?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
[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,
|
||||
TemplatedControl.PaddingProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ForegroundProperty,
|
||||
TemplatedControl.ForegroundProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BackgroundProperty,
|
||||
TemplatedControl.BackgroundProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.CornerRadiusProperty,
|
||||
TemplatedControl.CornerRadiusProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BorderBrushProperty,
|
||||
TemplatedControl.BorderBrushProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BorderThicknessProperty,
|
||||
TemplatedControl.BorderThicknessProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.FontSizeProperty,
|
||||
TemplatedControl.FontSizeProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentProperty,
|
||||
ContentControl.ContentProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentTemplateProperty,
|
||||
ContentControl.ContentTemplateProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, Layoutable.HorizontalAlignmentProperty,
|
||||
Layoutable.HorizontalAlignmentProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, Layoutable.VerticalAlignmentProperty,
|
||||
Layoutable.VerticalAlignmentProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.HorizontalContentAlignmentProperty,
|
||||
ContentControl.HorizontalContentAlignmentProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.VerticalContentAlignmentProperty,
|
||||
ContentControl.VerticalContentAlignmentProperty);
|
||||
|
||||
return contentPresenter;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
var commonStyle = new Style(selector => selector.Nesting());
|
||||
|
||||
commonStyle.Add(Avalonia.Controls.Button.ClickModeProperty, ClickMode.Release);
|
||||
commonStyle.Add(InputElement.CursorProperty, new Cursor(StandardCursorType.Hand));
|
||||
commonStyle.Add(TemplatedControl.BackgroundProperty, GlobalTokenResourceKey.ColorTransparent);
|
||||
commonStyle.Add(TemplatedControl.ForegroundProperty, GlobalTokenResourceKey.ColorTextLabel);
|
||||
commonStyle.Add(TemplatedControl.CornerRadiusProperty, GlobalTokenResourceKey.BorderRadiusSM);
|
||||
commonStyle.Add(TemplatedControl.BorderBrushProperty, GlobalTokenResourceKey.ColorTransparent);
|
||||
commonStyle.Add(Layoutable.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
|
||||
commonStyle.Add(Layoutable.VerticalAlignmentProperty, VerticalAlignment.Stretch);
|
||||
commonStyle.Add(ContentControl.HorizontalContentAlignmentProperty, HorizontalAlignment.Center);
|
||||
commonStyle.Add(ContentControl.VerticalContentAlignmentProperty, VerticalAlignment.Center);
|
||||
commonStyle.Add(TemplatedControl.FontSizeProperty, GlobalTokenResourceKey.FontSize);
|
||||
commonStyle.Add(Layoutable.HeightProperty, DatePickerTokenResourceKey.CellHeight);
|
||||
commonStyle.Add(Layoutable.MarginProperty, DatePickerTokenResourceKey.CellMargin);
|
||||
|
||||
var contentStyle = new Style(selector => selector.Nesting().Template().Name(ContentPart));
|
||||
contentStyle.Add(ContentPresenter.LineHeightProperty, DatePickerTokenResourceKey.CellLineHeight);
|
||||
commonStyle.Add(contentStyle);
|
||||
|
||||
var hoverStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.PointerOver));
|
||||
hoverStyle.Add(TemplatedControl.BackgroundProperty, DatePickerTokenResourceKey.CellHoverBg);
|
||||
commonStyle.Add(hoverStyle);
|
||||
|
||||
var inactiveStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.InActive));
|
||||
inactiveStyle.Add(TemplatedControl.ForegroundProperty, GlobalTokenResourceKey.ColorTextDisabled);
|
||||
commonStyle.Add(inactiveStyle);
|
||||
|
||||
var selectedStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.Selected));
|
||||
selectedStyle.Add(TemplatedControl.BackgroundProperty, GlobalTokenResourceKey.ColorPrimary);
|
||||
selectedStyle.Add(TemplatedControl.ForegroundProperty, GlobalTokenResourceKey.ColorWhite);
|
||||
selectedStyle.Add(TemplatedControl.BorderThicknessProperty, new Thickness(0));
|
||||
commonStyle.Add(selectedStyle);
|
||||
|
||||
Add(commonStyle);
|
||||
}
|
||||
}
|
@ -0,0 +1,281 @@
|
||||
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.CalendarPresenter;
|
||||
|
||||
[PseudoClasses(StdPseudoClass.Pressed,
|
||||
StdPseudoClass.Disabled,
|
||||
StdPseudoClass.Selected,
|
||||
StdPseudoClass.InActive,
|
||||
TodayPC,
|
||||
BlackoutPC,
|
||||
DayfocusedPC)]
|
||||
internal sealed class CalendarDayButton : AvaloniaButton
|
||||
{
|
||||
internal const string TodayPC = ":today";
|
||||
internal const string BlackoutPC = ":blackout";
|
||||
internal const string DayfocusedPC = ":dayfocused";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Calendar associated with this button.
|
||||
/// </summary>
|
||||
internal Calendar? Owner { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default content for the CalendarDayButton.
|
||||
/// </summary>
|
||||
private const int DefaultContent = 1;
|
||||
|
||||
private bool _ignoringMouseOverState;
|
||||
private bool _isBlackout;
|
||||
|
||||
private bool _isCurrent;
|
||||
private bool _isInactive;
|
||||
private bool _isSelected;
|
||||
private bool _isToday;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the
|
||||
/// <see cref="T:Avalonia.Controls.Primitives.CalendarDayButton" />
|
||||
/// class.
|
||||
/// </summary>
|
||||
public CalendarDayButton()
|
||||
{
|
||||
//Focusable = false;
|
||||
SetCurrentValue(ContentProperty, DefaultContent.ToString(CultureInfo.CurrentCulture));
|
||||
}
|
||||
|
||||
internal int Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the button is the focused
|
||||
/// element on the Calendar control.
|
||||
/// </summary>
|
||||
internal bool IsCurrent
|
||||
{
|
||||
get => _isCurrent;
|
||||
|
||||
set
|
||||
{
|
||||
if (_isCurrent != value)
|
||||
{
|
||||
_isCurrent = value;
|
||||
SetPseudoClasses();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this is a blackout date.
|
||||
/// </summary>
|
||||
internal bool IsBlackout
|
||||
{
|
||||
get => _isBlackout;
|
||||
|
||||
set
|
||||
{
|
||||
if (_isBlackout != value)
|
||||
{
|
||||
_isBlackout = value;
|
||||
SetPseudoClasses();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this button represents
|
||||
/// today.
|
||||
/// </summary>
|
||||
internal bool IsToday
|
||||
{
|
||||
get => _isToday;
|
||||
|
||||
set
|
||||
{
|
||||
if (_isToday != value)
|
||||
{
|
||||
_isToday = value;
|
||||
SetPseudoClasses();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the button is inactive.
|
||||
/// </summary>
|
||||
internal bool IsInactive
|
||||
{
|
||||
get => _isInactive;
|
||||
|
||||
set
|
||||
{
|
||||
if (_isInactive != value)
|
||||
{
|
||||
_isInactive = value;
|
||||
SetPseudoClasses();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the button is selected.
|
||||
/// </summary>
|
||||
internal bool IsSelected
|
||||
{
|
||||
get => _isSelected;
|
||||
|
||||
set
|
||||
{
|
||||
if (_isSelected != value)
|
||||
{
|
||||
_isSelected = value;
|
||||
SetPseudoClasses();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure the button is not in the MouseOver state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If a button is in the MouseOver state when a Popup is closed (as is
|
||||
/// the case when you select a date in the DatePicker control), it will
|
||||
/// continue to think it's in the mouse over state even when the Popup
|
||||
/// opens again and it's not. This method is used to forcibly clear the
|
||||
/// state by changing the CommonStates state group.
|
||||
/// </remarks>
|
||||
internal void IgnoreMouseOverState()
|
||||
{
|
||||
// TODO: Investigate whether this needs to be done by changing the
|
||||
// state everytime we change any state, or if it can be done once
|
||||
// to properly reset the control.
|
||||
|
||||
_ignoringMouseOverState = false;
|
||||
|
||||
// If the button thinks it's in the MouseOver state (which can
|
||||
// happen when a Popup is closed before the button can change state)
|
||||
// we will override the state so it shows up as normal.
|
||||
if (IsPointerOver)
|
||||
{
|
||||
_ignoringMouseOverState = true;
|
||||
SetPseudoClasses();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
SetPseudoClasses();
|
||||
if (Transitions is null)
|
||||
{
|
||||
Transitions = new Transitions
|
||||
{
|
||||
AnimationUtils.CreateTransition<SolidColorBrushTransition>(BackgroundProperty,
|
||||
GlobalTokenResourceKey.MotionDurationFast)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void SetPseudoClasses()
|
||||
{
|
||||
if (_ignoringMouseOverState)
|
||||
{
|
||||
PseudoClasses.Set(StdPseudoClass.Pressed, IsPressed);
|
||||
PseudoClasses.Set(StdPseudoClass.Disabled, !IsEnabled);
|
||||
}
|
||||
|
||||
PseudoClasses.Set(StdPseudoClass.Selected, IsSelected);
|
||||
PseudoClasses.Set(StdPseudoClass.InActive, IsInactive);
|
||||
PseudoClasses.Set(TodayPC, IsToday);
|
||||
PseudoClasses.Set(BlackoutPC, IsBlackout);
|
||||
PseudoClasses.Set(DayfocusedPC, IsCurrent && IsEnabled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the left mouse button is pressed (or when the tip of the
|
||||
/// stylus touches the tablet PC) while the mouse pointer is over a
|
||||
/// UIElement.
|
||||
/// </summary>
|
||||
public event EventHandler<PointerPressedEventArgs>? CalendarDayButtonMouseDown;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the left mouse button is released (or the tip of the
|
||||
/// stylus is removed from the tablet PC) while the mouse (or the
|
||||
/// stylus) is over a UIElement (or while a UIElement holds mouse
|
||||
/// capture).
|
||||
/// </summary>
|
||||
public event EventHandler<PointerReleasedEventArgs>? CalendarDayButtonMouseUp;
|
||||
|
||||
/// <summary>
|
||||
/// Provides class handling for the MouseLeftButtonDown event that
|
||||
/// occurs when the left mouse button is pressed while the mouse pointer
|
||||
/// is over this control.
|
||||
/// </summary>
|
||||
/// <param name="e">The event data. </param>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// e is a null reference (Nothing in Visual Basic).
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This method marks the MouseLeftButtonDown event as handled by
|
||||
/// setting the MouseButtonEventArgs.Handled property of the event data
|
||||
/// to true when the button is enabled and its ClickMode is not set to
|
||||
/// Hover. Since this method marks the MouseLeftButtonDown event as
|
||||
/// handled in some situations, you should use the Click event instead
|
||||
/// to detect a button click.
|
||||
/// </remarks>
|
||||
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
||||
{
|
||||
base.OnPointerPressed(e);
|
||||
|
||||
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
{
|
||||
CalendarDayButtonMouseDown?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides handling for the MouseLeftButtonUp event that occurs when
|
||||
/// the left mouse button is released while the mouse pointer is over
|
||||
/// this control.
|
||||
/// </summary>
|
||||
/// <param name="e">The event data.</param>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// e is a null reference (Nothing in Visual Basic).
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This method marks the MouseLeftButtonUp event as handled by setting
|
||||
/// the MouseButtonEventArgs.Handled property of the event data to true
|
||||
/// when the button is enabled and its ClickMode is not set to Hover.
|
||||
/// Since this method marks the MouseLeftButtonUp event as handled in
|
||||
/// some situations, you should use the Click event instead to detect a
|
||||
/// button click.
|
||||
/// </remarks>
|
||||
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||
{
|
||||
base.OnPointerReleased(e);
|
||||
|
||||
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,109 @@
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
[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,
|
||||
TemplatedControl.PaddingProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ForegroundProperty,
|
||||
TemplatedControl.ForegroundProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BackgroundProperty,
|
||||
TemplatedControl.BackgroundProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.CornerRadiusProperty,
|
||||
TemplatedControl.CornerRadiusProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BorderBrushProperty,
|
||||
TemplatedControl.BorderBrushProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.BorderThicknessProperty,
|
||||
TemplatedControl.BorderThicknessProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.FontSizeProperty,
|
||||
TemplatedControl.FontSizeProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentProperty,
|
||||
ContentControl.ContentProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.ContentTemplateProperty,
|
||||
ContentControl.ContentTemplateProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, Layoutable.HorizontalAlignmentProperty,
|
||||
Layoutable.HorizontalAlignmentProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, Layoutable.VerticalAlignmentProperty,
|
||||
Layoutable.VerticalAlignmentProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.HorizontalContentAlignmentProperty,
|
||||
ContentControl.HorizontalContentAlignmentProperty);
|
||||
CreateTemplateParentBinding(contentPresenter, ContentPresenter.VerticalContentAlignmentProperty,
|
||||
ContentControl.VerticalContentAlignmentProperty);
|
||||
|
||||
return contentPresenter;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
var commonStyle = new Style(selector => selector.Nesting());
|
||||
|
||||
commonStyle.Add(Avalonia.Controls.Button.ClickModeProperty, ClickMode.Release);
|
||||
commonStyle.Add(InputElement.CursorProperty, new Cursor(StandardCursorType.Hand));
|
||||
commonStyle.Add(TemplatedControl.BackgroundProperty, GlobalTokenResourceKey.ColorTransparent);
|
||||
commonStyle.Add(TemplatedControl.ForegroundProperty, GlobalTokenResourceKey.ColorTextLabel);
|
||||
commonStyle.Add(TemplatedControl.CornerRadiusProperty, GlobalTokenResourceKey.BorderRadiusSM);
|
||||
commonStyle.Add(TemplatedControl.BorderBrushProperty, GlobalTokenResourceKey.ColorTransparent);
|
||||
commonStyle.Add(Layoutable.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
|
||||
commonStyle.Add(Layoutable.VerticalAlignmentProperty, VerticalAlignment.Stretch);
|
||||
commonStyle.Add(ContentControl.HorizontalContentAlignmentProperty, HorizontalAlignment.Center);
|
||||
commonStyle.Add(ContentControl.VerticalContentAlignmentProperty, VerticalAlignment.Center);
|
||||
commonStyle.Add(TemplatedControl.FontSizeProperty, GlobalTokenResourceKey.FontSize);
|
||||
commonStyle.Add(Layoutable.WidthProperty, DatePickerTokenResourceKey.CellWidth);
|
||||
commonStyle.Add(Layoutable.HeightProperty, DatePickerTokenResourceKey.CellHeight);
|
||||
commonStyle.Add(Layoutable.MarginProperty, DatePickerTokenResourceKey.CellMargin);
|
||||
|
||||
var contentStyle = new Style(selector => selector.Nesting().Template().Name(ContentPart));
|
||||
contentStyle.Add(ContentPresenter.LineHeightProperty, DatePickerTokenResourceKey.CellLineHeight);
|
||||
commonStyle.Add(contentStyle);
|
||||
|
||||
var hoverStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.PointerOver));
|
||||
hoverStyle.Add(TemplatedControl.BackgroundProperty, DatePickerTokenResourceKey.CellHoverBg);
|
||||
commonStyle.Add(hoverStyle);
|
||||
|
||||
var inactiveStyle = new Style(selector => selector.Nesting().Class(StdPseudoClass.InActive));
|
||||
inactiveStyle.Add(TemplatedControl.ForegroundProperty, GlobalTokenResourceKey.ColorTextDisabled);
|
||||
commonStyle.Add(inactiveStyle);
|
||||
|
||||
var todayStyle = new Style(selector => selector.Nesting().Class(BaseCalendarDayButton.TodayPC));
|
||||
todayStyle.Add(TemplatedControl.BorderBrushProperty, GlobalTokenResourceKey.ColorPrimary);
|
||||
commonStyle.Add(todayStyle);
|
||||
|
||||
var selectedStyle = new Style(selector =>
|
||||
selector.Nesting().Class(StdPseudoClass.Selected)
|
||||
.Not(selector1 => selector1.Nesting().Class(StdPseudoClass.InActive)));
|
||||
selectedStyle.Add(TemplatedControl.BackgroundProperty, GlobalTokenResourceKey.ColorPrimary);
|
||||
selectedStyle.Add(TemplatedControl.ForegroundProperty, GlobalTokenResourceKey.ColorWhite);
|
||||
selectedStyle.Add(TemplatedControl.BorderThicknessProperty, new Thickness(0));
|
||||
commonStyle.Add(selectedStyle);
|
||||
|
||||
Add(commonStyle);
|
||||
}
|
||||
}
|
1115
src/AtomUI.Controls/DatePicker/CalendarPresenter/CalendarItem.cs
Normal file
1115
src/AtomUI.Controls/DatePicker/CalendarPresenter/CalendarItem.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,319 @@
|
||||
using AtomUI.Data;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using AtomUI.Utils;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class CalendarItemTheme : BaseControlTheme
|
||||
{
|
||||
public const string ItemFramePart = "PART_ItemFrame";
|
||||
public const string ItemRootLayoutPart = "PART_ItemRootLayout";
|
||||
public const string MonthViewLayoutPart = "PART_MonthViewLayout";
|
||||
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 PreviousMonthButtonPart = "PART_PreviousMonthButton";
|
||||
public const string HeaderButtonPart = "PART_HeaderButton";
|
||||
public const string NextMonthButtonPart = "PART_NextMonthButton";
|
||||
public const string NextButtonPart = "PART_NextButton";
|
||||
|
||||
public CalendarItemTheme()
|
||||
: base(typeof(CalendarItem))
|
||||
{
|
||||
}
|
||||
|
||||
protected override IControlTemplate BuildControlTemplate()
|
||||
{
|
||||
return new FuncControlTemplate<CalendarItem>((calendarItem, scope) =>
|
||||
{
|
||||
var frame = new Border
|
||||
{
|
||||
Name = ItemFramePart
|
||||
};
|
||||
|
||||
CreateTemplateParentBinding(frame, Border.MinWidthProperty, CalendarItem.MinWidthProperty);
|
||||
CreateTemplateParentBinding(frame, Border.MinHeightProperty, CalendarItem.MinHeightProperty);
|
||||
|
||||
var rootLayout = new DockPanel
|
||||
{
|
||||
Name = ItemRootLayoutPart,
|
||||
LastChildFill = true
|
||||
};
|
||||
BuildHeader(rootLayout, scope);
|
||||
BuildContentView(rootLayout, scope);
|
||||
|
||||
BuildDayTitleTemplate(calendarItem);
|
||||
frame.Child = rootLayout;
|
||||
|
||||
return frame;
|
||||
});
|
||||
}
|
||||
|
||||
private void BuildDayTitleTemplate(CalendarItem calendarItem)
|
||||
{
|
||||
calendarItem.DayTitleTemplate = new DayTitleTemplate();
|
||||
}
|
||||
|
||||
protected virtual void BuildHeader(DockPanel layout, INameScope scope)
|
||||
{
|
||||
var headerLayout = new UniformGrid
|
||||
{
|
||||
Name = HeaderLayoutPart,
|
||||
Columns = 1
|
||||
};
|
||||
|
||||
headerLayout.RegisterInNameScope(scope);
|
||||
BuildHeaderItem(headerLayout, scope);
|
||||
|
||||
DockPanel.SetDock(headerLayout, Dock.Top);
|
||||
layout.Children.Add(headerLayout);
|
||||
}
|
||||
|
||||
private void BuildHeaderItem(UniformGrid layout, INameScope scope)
|
||||
{
|
||||
var headerLayout = new Grid
|
||||
{
|
||||
ColumnDefinitions = new ColumnDefinitions
|
||||
{
|
||||
new(GridLength.Auto),
|
||||
new(GridLength.Auto),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Auto),
|
||||
new(GridLength.Auto)
|
||||
}
|
||||
};
|
||||
|
||||
var previousButton = BuildPreviousButton(PreviousButtonPart);
|
||||
previousButton.RegisterInNameScope(scope);
|
||||
Grid.SetColumn(previousButton, 0);
|
||||
headerLayout.Children.Add(previousButton);
|
||||
|
||||
var previousMonthButton = BuildPreviousMonthButton(PreviousMonthButtonPart);
|
||||
CreateTemplateParentBinding(previousMonthButton, Visual.IsVisibleProperty,
|
||||
CalendarItem.IsMonthViewModeProperty);
|
||||
previousMonthButton.RegisterInNameScope(scope);
|
||||
Grid.SetColumn(previousMonthButton, 1);
|
||||
headerLayout.Children.Add(previousMonthButton);
|
||||
|
||||
var headerButton = new HeadTextButton
|
||||
{
|
||||
Name = HeaderButtonPart
|
||||
};
|
||||
Grid.SetColumn(headerButton, 2);
|
||||
headerButton.RegisterInNameScope(scope);
|
||||
headerLayout.Children.Add(headerButton);
|
||||
|
||||
var nextMonthButton = BuildNextMonthButton(NextMonthButtonPart);
|
||||
CreateTemplateParentBinding(nextMonthButton, Visual.IsVisibleProperty, CalendarItem.IsMonthViewModeProperty);
|
||||
nextMonthButton.IsVisible = false;
|
||||
nextMonthButton.RegisterInNameScope(scope);
|
||||
Grid.SetColumn(nextMonthButton, 3);
|
||||
headerLayout.Children.Add(nextMonthButton);
|
||||
|
||||
var nextButton = BuildNextButton(NextButtonPart);
|
||||
nextButton.RegisterInNameScope(scope);
|
||||
Grid.SetColumn(nextButton, 4);
|
||||
headerLayout.Children.Add(nextButton);
|
||||
|
||||
layout.Children.Add(headerLayout);
|
||||
}
|
||||
|
||||
protected virtual IconButton BuildPreviousButton(string name)
|
||||
{
|
||||
var previousButtonIcon = new PathIcon
|
||||
{
|
||||
Kind = "DoubleLeftOutlined"
|
||||
};
|
||||
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 = name,
|
||||
Icon = previousButtonIcon
|
||||
};
|
||||
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(previousButton, IconButton.IconWidthProperty,
|
||||
GlobalTokenResourceKey.IconSizeSM);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(previousButton, IconButton.IconHeightProperty,
|
||||
GlobalTokenResourceKey.IconSizeSM);
|
||||
return previousButton;
|
||||
}
|
||||
|
||||
protected virtual IconButton BuildPreviousMonthButton(string name)
|
||||
{
|
||||
var previousMonthButtonIcon = new PathIcon
|
||||
{
|
||||
Kind = "LeftOutlined"
|
||||
};
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(previousMonthButtonIcon, PathIcon.NormalFilledBrushProperty,
|
||||
GlobalTokenResourceKey.ColorTextDescription);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(previousMonthButtonIcon, PathIcon.ActiveFilledBrushProperty,
|
||||
GlobalTokenResourceKey.ColorText);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(previousMonthButtonIcon, PathIcon.SelectedFilledBrushProperty,
|
||||
GlobalTokenResourceKey.ColorText);
|
||||
|
||||
var previousMonthButton = new IconButton
|
||||
{
|
||||
Name = name,
|
||||
Icon = previousMonthButtonIcon
|
||||
};
|
||||
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(previousMonthButton, IconButton.IconWidthProperty,
|
||||
GlobalTokenResourceKey.IconSizeSM);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(previousMonthButton, IconButton.IconHeightProperty,
|
||||
GlobalTokenResourceKey.IconSizeSM);
|
||||
return previousMonthButton;
|
||||
}
|
||||
|
||||
protected virtual IconButton BuildNextButton(string name)
|
||||
{
|
||||
var nextButtonIcon = new PathIcon
|
||||
{
|
||||
Kind = "DoubleRightOutlined"
|
||||
};
|
||||
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 = name,
|
||||
Icon = nextButtonIcon
|
||||
};
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(nextButton, IconButton.IconWidthProperty,
|
||||
GlobalTokenResourceKey.IconSizeSM);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(nextButton, IconButton.IconHeightProperty,
|
||||
GlobalTokenResourceKey.IconSizeSM);
|
||||
return nextButton;
|
||||
}
|
||||
|
||||
protected virtual IconButton BuildNextMonthButton(string name)
|
||||
{
|
||||
var nextMonthButtonIcon = new PathIcon
|
||||
{
|
||||
Kind = "RightOutlined"
|
||||
};
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(nextMonthButtonIcon, PathIcon.NormalFilledBrushProperty,
|
||||
GlobalTokenResourceKey.ColorTextDescription);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(nextMonthButtonIcon, PathIcon.ActiveFilledBrushProperty,
|
||||
GlobalTokenResourceKey.ColorText);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(nextMonthButtonIcon, PathIcon.SelectedFilledBrushProperty,
|
||||
GlobalTokenResourceKey.ColorText);
|
||||
var nextMonthButton = new IconButton
|
||||
{
|
||||
Name = name,
|
||||
Icon = nextMonthButtonIcon
|
||||
};
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(nextMonthButton, IconButton.IconWidthProperty,
|
||||
GlobalTokenResourceKey.IconSizeSM);
|
||||
TokenResourceBinder.CreateGlobalTokenBinding(nextMonthButton, IconButton.IconHeightProperty,
|
||||
GlobalTokenResourceKey.IconSizeSM);
|
||||
return nextMonthButton;
|
||||
}
|
||||
|
||||
private void BuildContentView(DockPanel layout, INameScope scope)
|
||||
{
|
||||
var monthViewLayout = new UniformGrid
|
||||
{
|
||||
Name = MonthViewLayoutPart,
|
||||
Columns = 1,
|
||||
IsVisible = false
|
||||
};
|
||||
|
||||
var monthView = BuildMonthViewItem(MonthViewPart);
|
||||
monthView.RegisterInNameScope(scope);
|
||||
monthViewLayout.Children.Add(monthView);
|
||||
|
||||
BindUtils.RelayBind(monthViewLayout, Visual.IsVisibleProperty, monthView, Visual.IsVisibleProperty);
|
||||
|
||||
monthViewLayout.RegisterInNameScope(scope);
|
||||
layout.Children.Add(monthViewLayout);
|
||||
|
||||
var yearView = new Grid
|
||||
{
|
||||
Name = YearViewPart,
|
||||
IsVisible = false,
|
||||
RowDefinitions = new RowDefinitions
|
||||
{
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star)
|
||||
},
|
||||
ColumnDefinitions = new ColumnDefinitions
|
||||
{
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star)
|
||||
}
|
||||
};
|
||||
yearView.RegisterInNameScope(scope);
|
||||
layout.Children.Add(yearView);
|
||||
}
|
||||
|
||||
private Grid BuildMonthViewItem(string name)
|
||||
{
|
||||
var dayTitleRowDef = new RowDefinition();
|
||||
TokenResourceBinder.CreateTokenBinding(dayTitleRowDef, RowDefinition.HeightProperty,
|
||||
DatePickerTokenResourceKey.DayTitleHeight);
|
||||
var monthViewLayout = new Grid
|
||||
{
|
||||
Name = name,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
IsVisible = false,
|
||||
RowDefinitions = new RowDefinitions
|
||||
{
|
||||
dayTitleRowDef,
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star)
|
||||
},
|
||||
ColumnDefinitions = new ColumnDefinitions
|
||||
{
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star),
|
||||
new(GridLength.Star)
|
||||
}
|
||||
};
|
||||
return monthViewLayout;
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
var commonStyle = new Style(selector => selector.Nesting());
|
||||
|
||||
commonStyle.Add(CalendarItem.MinHeightProperty, DatePickerTokenResourceKey.ItemPanelMinHeight);
|
||||
commonStyle.Add(CalendarItem.MinWidthProperty, DatePickerTokenResourceKey.ItemPanelMinWidth);
|
||||
var headerLayoutStyle = new Style(selector => selector.Nesting().Template().Name(HeaderLayoutPart));
|
||||
headerLayoutStyle.Add(Layoutable.MarginProperty, DatePickerTokenResourceKey.HeaderMargin);
|
||||
|
||||
commonStyle.Add(headerLayoutStyle);
|
||||
|
||||
Add(commonStyle);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class CalendarTheme : BaseControlTheme
|
||||
{
|
||||
public const string CalendarItemPart = "PART_CalendarItem";
|
||||
public const string FramePart = "PART_Frame";
|
||||
|
||||
public CalendarTheme()
|
||||
: this(typeof(Calendar))
|
||||
{
|
||||
}
|
||||
|
||||
public CalendarTheme(Type targetType) : base(targetType)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IControlTemplate BuildControlTemplate()
|
||||
{
|
||||
return new FuncControlTemplate<Calendar>((calendar, scope) =>
|
||||
{
|
||||
var frame = new Border
|
||||
{
|
||||
Name = FramePart,
|
||||
ClipToBounds = true
|
||||
};
|
||||
|
||||
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);
|
||||
CreateTemplateParentBinding(frame, Border.MinWidthProperty, Calendar.MinWidthProperty);
|
||||
CreateTemplateParentBinding(frame, Border.MinHeightProperty, Calendar.MinHeightProperty);
|
||||
|
||||
var calendarItem = new CalendarItem
|
||||
{
|
||||
Name = CalendarItemPart,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch
|
||||
};
|
||||
|
||||
calendarItem.RegisterInNameScope(scope);
|
||||
|
||||
frame.Child = calendarItem;
|
||||
|
||||
return frame;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
base.BuildStyles();
|
||||
|
||||
var commonStyle = new Style(selector => selector.Nesting());
|
||||
commonStyle.Add(Calendar.BorderBrushProperty, GlobalTokenResourceKey.ColorBorder);
|
||||
commonStyle.Add(Calendar.CornerRadiusProperty, GlobalTokenResourceKey.BorderRadius);
|
||||
commonStyle.Add(Calendar.BackgroundProperty, GlobalTokenResourceKey.ColorBgContainer);
|
||||
commonStyle.Add(Calendar.PaddingProperty, DatePickerTokenResourceKey.PanelContentPadding);
|
||||
commonStyle.Add(Calendar.HorizontalAlignmentProperty, HorizontalAlignment.Left);
|
||||
commonStyle.Add(Calendar.VerticalAlignmentProperty, VerticalAlignment.Top);
|
||||
Add(commonStyle);
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ using Avalonia.Interactivity;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
public class RangeDateSelectedEventArgs : RoutedEventArgs
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
public sealed class RangeCalendarBlackoutDatesCollection : ObservableCollection<CalendarDateRange>
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace AtomUI.Controls;
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
internal sealed class RangeCalendarButton : BaseCalendarButton
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace AtomUI.Controls;
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
internal sealed class RangeCalendarDayButton : BaseCalendarDayButton
|
||||
{
|
@ -11,7 +11,7 @@ using Avalonia.Input.Raw;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
[TemplatePart(RangeCalendarItemTheme.PrimaryHeaderButtonPart, typeof(HeadTextButton))]
|
||||
[TemplatePart(RangeCalendarItemTheme.SecondaryHeaderButtonPart, typeof(HeadTextButton))]
|
||||
@ -37,7 +37,7 @@ internal class RangeCalendarItem : TemplatedControl
|
||||
|
||||
protected readonly System.Globalization.Calendar _calendar = new GregorianCalendar();
|
||||
|
||||
#region 公共属性定义
|
||||
#region 公共属性定义
|
||||
|
||||
public static readonly StyledProperty<IBrush?> HeaderBackgroundProperty =
|
||||
RangeCalendar.HeaderBackgroundProperty.AddOwner<RangeCalendarItem>();
|
||||
@ -1200,21 +1200,28 @@ internal class RangeCalendarItem : TemplatedControl
|
||||
|
||||
internal void HandleCellMouseLeftButtonDown(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (Owner != null) {
|
||||
if (!Owner.HasFocusInternal) {
|
||||
if (Owner != null)
|
||||
{
|
||||
if (!Owner.HasFocusInternal)
|
||||
{
|
||||
Owner.Focus();
|
||||
}
|
||||
|
||||
if (sender is RangeCalendarDayButton b) {
|
||||
if (b.IsEnabled && !b.IsBlackout && b.DataContext is DateTime selectedDate) {
|
||||
if (sender is RangeCalendarDayButton b)
|
||||
{
|
||||
if (b.IsEnabled && !b.IsBlackout && b.DataContext is DateTime selectedDate)
|
||||
{
|
||||
// Set the start or end of the selection
|
||||
// range
|
||||
if (Owner.FixedRangeStart)
|
||||
{
|
||||
Owner.SelectedRangeStartDate = selectedDate;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Owner.SelectedRangeEndDate = selectedDate;
|
||||
}
|
||||
|
||||
Owner.UpdateHighlightDays();
|
||||
if (Owner.SelectedRangeStartDate is not null && Owner.SelectedRangeEndDate is not null)
|
||||
{
|
||||
@ -1227,18 +1234,23 @@ internal class RangeCalendarItem : TemplatedControl
|
||||
|
||||
internal void HandleCellMouseLeftButtonUp(object? sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
if (Owner != null) {
|
||||
RangeCalendarDayButton? b = sender as RangeCalendarDayButton;
|
||||
if (b != null && !b.IsBlackout) {
|
||||
Owner.OnDayButtonMouseUp(e);
|
||||
}
|
||||
if (b != null && b.DataContext is DateTime selectedDate) {
|
||||
// If the day is Disabled but a trailing day we should
|
||||
// be able to switch months
|
||||
if (b.IsInactive) {
|
||||
Owner.OnDayClick(selectedDate);
|
||||
}
|
||||
}
|
||||
if (Owner != null)
|
||||
{
|
||||
RangeCalendarDayButton? b = sender as RangeCalendarDayButton;
|
||||
if (b != null && !b.IsBlackout)
|
||||
{
|
||||
Owner.OnDayButtonMouseUp(e);
|
||||
}
|
||||
|
||||
if (b != null && b.DataContext is DateTime selectedDate)
|
||||
{
|
||||
// If the day is Disabled but a trailing day we should
|
||||
// be able to switch months
|
||||
if (b.IsInactive)
|
||||
{
|
||||
Owner.OnDayClick(selectedDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1303,9 +1315,11 @@ internal class RangeCalendarItem : TemplatedControl
|
||||
|
||||
private void DetectRestoreHoverPosition(RawInputEventArgs args)
|
||||
{
|
||||
if (Owner is null) {
|
||||
if (Owner is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (args is RawPointerEventArgs pointerEventArgs)
|
||||
{
|
||||
if (!IsPointerInMonthView(pointerEventArgs.Position))
|
||||
@ -1335,10 +1349,13 @@ internal class RangeCalendarItem : TemplatedControl
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Owner.DisplayMode == CalendarMode.Month)
|
||||
{
|
||||
return GetMonthViewRect(PrimaryMonthView!).Contains(position) || GetMonthViewRect(SecondaryMonthView!).Contains(position);
|
||||
return GetMonthViewRect(PrimaryMonthView!).Contains(position) ||
|
||||
GetMonthViewRect(SecondaryMonthView!).Contains(position);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1347,6 +1364,7 @@ internal class RangeCalendarItem : TemplatedControl
|
||||
var firstDay = (monthView.Children[7] as RangeCalendarDayButton)!;
|
||||
var firstDayPos = firstDay.TranslatePoint(new Point(0, 0), TopLevel.GetTopLevel(monthView)!) ?? default;
|
||||
var monthViewPos = monthView.TranslatePoint(new Point(0, 0), TopLevel.GetTopLevel(monthView)!) ?? default;
|
||||
return new Rect(firstDayPos, new Size(monthView.Bounds.Width, monthViewPos.Y + monthView.Bounds.Height - firstDayPos.Y ));
|
||||
return new Rect(firstDayPos,
|
||||
new Size(monthView.Bounds.Width, monthViewPos.Y + monthView.Bounds.Height - firstDayPos.Y));
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ using Avalonia.Data.Converters;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class RangeCalendarItemTheme : BaseControlTheme
|
@ -8,10 +8,10 @@ using Avalonia.Controls.Templates;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
namespace AtomUI.Controls.CalendarPresenter;
|
||||
|
||||
[ControlThemeProvider]
|
||||
public class RangeCalendarTheme : BaseControlTheme
|
||||
internal class RangeCalendarTheme : BaseControlTheme
|
||||
{
|
||||
public const string RootPart = "PART_Root";
|
||||
public const string CalendarItemPart = "PART_CalendarItem";
|
||||
@ -69,8 +69,6 @@ public class RangeCalendarTheme : BaseControlTheme
|
||||
commonStyle.Add(TemplatedControl.CornerRadiusProperty, GlobalTokenResourceKey.BorderRadius);
|
||||
commonStyle.Add(TemplatedControl.BackgroundProperty, GlobalTokenResourceKey.ColorBgContainer);
|
||||
commonStyle.Add(TemplatedControl.PaddingProperty, DatePickerTokenResourceKey.PanelContentPadding);
|
||||
commonStyle.Add(Layoutable.MinWidthProperty, DatePickerTokenResourceKey.ItemPanelMinWidth);
|
||||
commonStyle.Add(Layoutable.MinHeightProperty, DatePickerTokenResourceKey.ItemPanelMinHeight);
|
||||
Add(commonStyle);
|
||||
}
|
||||
}
|
11
src/AtomUI.Controls/DatePicker/DatePicker.cs
Normal file
11
src/AtomUI.Controls/DatePicker/DatePicker.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using AtomUI.Controls.Internal;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
public class DatePicker : InfoPickerInput
|
||||
{
|
||||
protected override Flyout CreatePickerFlyout()
|
||||
{
|
||||
return new Flyout();
|
||||
}
|
||||
}
|
6
src/AtomUI.Controls/DatePicker/DatePickerPresenter.cs
Normal file
6
src/AtomUI.Controls/DatePicker/DatePickerPresenter.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
public class DatePickerPresenter
|
||||
{
|
||||
|
||||
}
|
16
src/AtomUI.Controls/DatePicker/DatePickerPresenterTheme.cs
Normal file
16
src/AtomUI.Controls/DatePicker/DatePickerPresenterTheme.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Styling;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class DatePickerPresenterTheme : BaseControlTheme
|
||||
{
|
||||
public DatePickerPresenterTheme() : this(typeof(DatePickerPresenter))
|
||||
{
|
||||
}
|
||||
|
||||
public DatePickerPresenterTheme(Type targetType) : base(targetType)
|
||||
{
|
||||
}
|
||||
}
|
30
src/AtomUI.Controls/DatePicker/DatePickerTheme.cs
Normal file
30
src/AtomUI.Controls/DatePicker/DatePickerTheme.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using AtomUI.Controls.Internal;
|
||||
using AtomUI.Theme.Styling;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
[ControlThemeProvider]
|
||||
internal class DatePickerTheme : InfoPickerInputTheme
|
||||
{
|
||||
public DatePickerTheme() : base(typeof(DatePicker))
|
||||
{
|
||||
}
|
||||
|
||||
protected override PathIcon BuildInfoIcon(InfoPickerInput infoPickerInput, INameScope scope)
|
||||
{
|
||||
return new PathIcon()
|
||||
{
|
||||
Kind = "CalendarOutlined"
|
||||
};
|
||||
}
|
||||
|
||||
protected override void BuildStyles()
|
||||
{
|
||||
base.BuildStyles();
|
||||
var commonStyle = new Style(selector => selector.Nesting());
|
||||
commonStyle.Add(DatePicker.MinWidthProperty, DatePickerTokenResourceKey.PickerInputMinWidth);
|
||||
Add(commonStyle);
|
||||
}
|
||||
}
|
@ -66,6 +66,11 @@ internal class DatePickerToken : AbstractControlDesignToken
|
||||
/// </summary>
|
||||
public double ItemPanelMinWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 两个月日历项最小宽度
|
||||
/// </summary>
|
||||
public double RangeItemPanelMinWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日历项最小高度
|
||||
/// </summary>
|
||||
@ -101,28 +106,35 @@ internal class DatePickerToken : AbstractControlDesignToken
|
||||
/// </summary>
|
||||
public double RangeCalendarSpacing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日期选择器最小的宽度
|
||||
/// </summary>
|
||||
public double PickerInputMinWidth { get; set; }
|
||||
|
||||
internal override void CalculateFromAlias()
|
||||
{
|
||||
base.CalculateFromAlias();
|
||||
|
||||
var colorPrimary = _globalToken.ColorToken.ColorPrimaryToken.ColorPrimary;
|
||||
|
||||
CellHoverBg = _globalToken.ControlItemBgHover;
|
||||
CellActiveWithRangeBg = _globalToken.ControlItemBgActive;
|
||||
CellHoverWithRangeBg = colorPrimary.Lighten(35);
|
||||
CellRangeBorderColor = colorPrimary.Lighten(20);
|
||||
CellBgDisabled = _globalToken.ColorBgContainerDisabled;
|
||||
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 = 260;
|
||||
ItemPanelMinHeight = 290;
|
||||
DayTitleHeight = new GridLength(40, GridUnitType.Pixel);
|
||||
HeaderMargin = new Thickness(0, 0, 0, _globalToken.MarginXS);
|
||||
CellLineHeight = CellHeight - 2; // 不知道为啥设置成一样,或者不设置文字有些靠下
|
||||
RangeCalendarSpacing = 20;
|
||||
CellHoverBg = _globalToken.ControlItemBgHover;
|
||||
CellActiveWithRangeBg = _globalToken.ControlItemBgActive;
|
||||
CellHoverWithRangeBg = colorPrimary.Lighten(35);
|
||||
CellRangeBorderColor = colorPrimary.Lighten(20);
|
||||
CellBgDisabled = _globalToken.ColorBgContainerDisabled;
|
||||
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 = 225;
|
||||
RangeItemPanelMinWidth = 260;
|
||||
ItemPanelMinHeight = 240;
|
||||
DayTitleHeight = new GridLength(40, GridUnitType.Pixel);
|
||||
HeaderMargin = new Thickness(0, 0, 0, _globalToken.MarginSM);
|
||||
CellLineHeight = CellHeight - 2; // 不知道为啥设置成一样,或者不设置文字有些靠下
|
||||
RangeCalendarSpacing = 20;
|
||||
PickerInputMinWidth = 150;
|
||||
}
|
||||
}
|
10
src/AtomUI.Controls/DatePicker/Localization/en_US.cs
Normal file
10
src/AtomUI.Controls/DatePicker/Localization/en_US.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Utils;
|
||||
|
||||
namespace AtomUI.Controls.DatePickerLang;
|
||||
|
||||
[LanguageProvider(LanguageCode.en_US, DatePickerToken.ID)]
|
||||
internal class en_US : AbstractLanguageProvider
|
||||
{
|
||||
public const string Today = "Today";
|
||||
}
|
10
src/AtomUI.Controls/DatePicker/Localization/zh_CN.cs
Normal file
10
src/AtomUI.Controls/DatePicker/Localization/zh_CN.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Utils;
|
||||
|
||||
namespace AtomUI.Controls.DatePickerLang;
|
||||
|
||||
[LanguageProvider(LanguageCode.zh_CN, DatePickerToken.ID)]
|
||||
internal class zh_CN : AbstractLanguageProvider
|
||||
{
|
||||
public const string Today = "今天";
|
||||
}
|
@ -29,8 +29,14 @@
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.ComboBoxItemTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.ComboBoxSpinnerInnerBoxTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.ComboBoxTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.RangeCalendarItemTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.RangeCalendarTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CalendarPresenter.CalendarButtonTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CalendarPresenter.CalendarDayButtonTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CalendarPresenter.CalendarItemTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CalendarPresenter.CalendarTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CalendarPresenter.RangeCalendarItemTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.CalendarPresenter.RangeCalendarTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.DatePickerPresenterTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.DatePickerTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.EmptyIndicatorTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.ExpanderTheme());
|
||||
ThemeManager.Current.RegisterControlTheme(new AtomUI.Controls.MenuFlyoutPresenterTheme());
|
||||
|
@ -4,6 +4,8 @@
|
||||
{
|
||||
internal static void Register()
|
||||
{
|
||||
ThemeManager.Current.RegisterLanguageProvider(new AtomUI.Controls.DatePickerLang.en_US());
|
||||
ThemeManager.Current.RegisterLanguageProvider(new AtomUI.Controls.DatePickerLang.zh_CN());
|
||||
ThemeManager.Current.RegisterLanguageProvider(new AtomUI.Controls.Localization.en_US());
|
||||
ThemeManager.Current.RegisterLanguageProvider(new AtomUI.Controls.Localization.zh_CN());
|
||||
ThemeManager.Current.RegisterLanguageProvider(new AtomUI.Controls.PopupConfirmLang.en_US());
|
||||
|
@ -1,5 +1,13 @@
|
||||
using AtomUI.Theme;
|
||||
|
||||
namespace AtomUI.Controls.DatePickerLang
|
||||
{
|
||||
public static class DatePickerLangResourceKey
|
||||
{
|
||||
public static readonly LanguageResourceKey Today = new LanguageResourceKey("DatePicker.Today", "AtomUI.Lang");
|
||||
}
|
||||
}
|
||||
|
||||
namespace AtomUI.Controls.Localization
|
||||
{
|
||||
public static class CommonLangResourceKey
|
||||
|
@ -200,6 +200,7 @@ namespace AtomUI.Theme.Styling
|
||||
public static readonly TokenResourceKey CellLineHeight = new TokenResourceKey("DatePicker.CellLineHeight", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey CellMargin = new TokenResourceKey("DatePicker.CellMargin", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ItemPanelMinWidth = new TokenResourceKey("DatePicker.ItemPanelMinWidth", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey RangeItemPanelMinWidth = new TokenResourceKey("DatePicker.RangeItemPanelMinWidth", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey ItemPanelMinHeight = new TokenResourceKey("DatePicker.ItemPanelMinHeight", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey TextHeight = new TokenResourceKey("DatePicker.TextHeight", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey PanelContentPadding = new TokenResourceKey("DatePicker.PanelContentPadding", "AtomUI.Token");
|
||||
@ -207,6 +208,7 @@ namespace AtomUI.Theme.Styling
|
||||
public static readonly TokenResourceKey DayTitleHeight = new TokenResourceKey("DatePicker.DayTitleHeight", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey HeaderMargin = new TokenResourceKey("DatePicker.HeaderMargin", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey RangeCalendarSpacing = new TokenResourceKey("DatePicker.RangeCalendarSpacing", "AtomUI.Token");
|
||||
public static readonly TokenResourceKey PickerInputMinWidth = new TokenResourceKey("DatePicker.PickerInputMinWidth", "AtomUI.Token");
|
||||
}
|
||||
|
||||
public static class EmptyIndicatorTokenResourceKey
|
||||
|
@ -47,13 +47,13 @@ internal class InfoPickerInputTheme : BaseControlTheme
|
||||
};
|
||||
pickerInnerBox.RegisterInNameScope(scope);
|
||||
CreateTemplateParentBinding(pickerInnerBox, AddOnDecoratedInnerBox.LeftAddOnContentProperty,
|
||||
RangeTimePicker.InnerLeftContentProperty);
|
||||
InfoPickerInput.InnerLeftContentProperty);
|
||||
CreateTemplateParentBinding(pickerInnerBox, AddOnDecoratedInnerBox.StyleVariantProperty,
|
||||
RangeTimePicker.StyleVariantProperty);
|
||||
InfoPickerInput.StyleVariantProperty);
|
||||
CreateTemplateParentBinding(pickerInnerBox, AddOnDecoratedInnerBox.StatusProperty,
|
||||
RangeTimePicker.StatusProperty);
|
||||
InfoPickerInput.StatusProperty);
|
||||
CreateTemplateParentBinding(pickerInnerBox, AddOnDecoratedInnerBox.SizeTypeProperty,
|
||||
RangeTimePicker.SizeTypeProperty);
|
||||
InfoPickerInput.SizeTypeProperty);
|
||||
|
||||
var clearUpButton = new PickerClearUpButton()
|
||||
{
|
||||
@ -89,14 +89,16 @@ internal class InfoPickerInputTheme : BaseControlTheme
|
||||
Name = DecoratedBoxPart,
|
||||
Focusable = true
|
||||
};
|
||||
CreateTemplateParentBinding(decoratedBox, AddOnDecoratedBox.MinWidthProperty,
|
||||
InfoPickerInput.MinWidthProperty);
|
||||
CreateTemplateParentBinding(decoratedBox, AddOnDecoratedBox.StyleVariantProperty,
|
||||
RangeTimePicker.StyleVariantProperty);
|
||||
CreateTemplateParentBinding(decoratedBox, AddOnDecoratedBox.SizeTypeProperty, RangeTimePicker.SizeTypeProperty);
|
||||
CreateTemplateParentBinding(decoratedBox, AddOnDecoratedBox.StatusProperty, RangeTimePicker.StatusProperty);
|
||||
InfoPickerInput.StyleVariantProperty);
|
||||
CreateTemplateParentBinding(decoratedBox, AddOnDecoratedBox.SizeTypeProperty, InfoPickerInput.SizeTypeProperty);
|
||||
CreateTemplateParentBinding(decoratedBox, AddOnDecoratedBox.StatusProperty, InfoPickerInput.StatusProperty);
|
||||
CreateTemplateParentBinding(decoratedBox, AddOnDecoratedBox.LeftAddOnProperty,
|
||||
RangeTimePicker.LeftAddOnProperty);
|
||||
InfoPickerInput.LeftAddOnProperty);
|
||||
CreateTemplateParentBinding(decoratedBox, AddOnDecoratedBox.RightAddOnProperty,
|
||||
RangeTimePicker.RightAddOnProperty);
|
||||
InfoPickerInput.RightAddOnProperty);
|
||||
decoratedBox.RegisterInNameScope(scope);
|
||||
return decoratedBox;
|
||||
}
|
||||
|
@ -51,12 +51,12 @@ internal class RangeInfoPickerInputTheme : InfoPickerInputTheme
|
||||
var rangeStartTextBox = BuildPickerTextBox(InfoInputBoxPart);
|
||||
CreateTemplateParentBinding(rangeStartTextBox, TextBox.TextProperty, RangeInfoPickerInput.TextProperty);
|
||||
CreateTemplateParentBinding(rangeStartTextBox, TextBox.WatermarkProperty,
|
||||
RangeTimePicker.WatermarkProperty);
|
||||
RangeInfoPickerInput.WatermarkProperty);
|
||||
|
||||
var rangeEndTextBox = BuildPickerTextBox(SecondaryInfoInputBoxPart);
|
||||
CreateTemplateParentBinding(rangeEndTextBox, TextBox.TextProperty, RangeInfoPickerInput.SecondaryTextProperty);
|
||||
CreateTemplateParentBinding(rangeEndTextBox, TextBox.WatermarkProperty,
|
||||
RangeTimePicker.SecondaryWatermarkProperty);
|
||||
RangeInfoPickerInput.SecondaryWatermarkProperty);
|
||||
|
||||
rangeStartTextBox.RegisterInNameScope(scope);
|
||||
rangeEndTextBox.RegisterInNameScope(scope);
|
||||
@ -108,7 +108,7 @@ internal class RangeInfoPickerInputTheme : InfoPickerInputTheme
|
||||
{
|
||||
{
|
||||
var indicatorStyle = new Style(selector => selector.Nesting().Template().Name(RangePickerIndicatorPart));
|
||||
indicatorStyle.Add(Layoutable.HeightProperty, TimePickerTokenResourceKey.RangePickerIndicatorThickness);
|
||||
indicatorStyle.Add(Layoutable.HeightProperty, InfoPickerInputTokenResourceKey.RangePickerIndicatorThickness);
|
||||
commonStyle.Add(indicatorStyle);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user