feat: work around .net standard 2.0 formatting to H

This commit is contained in:
rabbitism
2024-04-26 17:57:53 +08:00
parent 68545dbf54
commit 41b530b7bf
2 changed files with 172 additions and 40 deletions

View File

@@ -4,7 +4,7 @@
xmlns:u="https://irihi.tech/ursa"> xmlns:u="https://irihi.tech/ursa">
<!-- Add Resources Here --> <!-- Add Resources Here -->
<Design.PreviewWith> <Design.PreviewWith>
<u:TimePickerPresenter Width="300" Height="300" /> <u:TimePickerPresenter Height="300" />
</Design.PreviewWith> </Design.PreviewWith>
<ControlTheme x:Key="{x:Type u:TimePickerPresenter}" TargetType="u:TimePickerPresenter"> <ControlTheme x:Key="{x:Type u:TimePickerPresenter}" TargetType="u:TimePickerPresenter">
<Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="HorizontalAlignment" Value="Left" />
@@ -12,32 +12,39 @@
<Setter Property="MaxHeight" Value="300" /> <Setter Property="MaxHeight" Value="300" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate TargetType="u:TimePickerPresenter"> <ControlTemplate TargetType="u:TimePickerPresenter">
<Grid <Grid Name="{x:Static u:TimePickerPresenter.PART_PickerContainer}" ColumnDefinitions="*, Auto, *, Auto, *, Auto, *">
Name="{x:Static u:TimePickerPresenter.PART_PickerContainer}"
ColumnDefinitions="*, *, *, *, Auto">
<Grid.Styles> <Grid.Styles>
<Style Selector="u|UrsaDateTimeScrollPanel > ListBoxItem"> <Style Selector="u|UrsaDateTimeScrollPanel &gt; ListBoxItem">
<Setter Property="Theme" Value="{DynamicResource DateTimePickerItem}" /> <Setter Property="Theme" Value="{DynamicResource DateTimePickerItem}" />
</Style> </Style>
</Grid.Styles> </Grid.Styles>
<ScrollViewer <ScrollViewer
Name="{x:Static u:TimePickerPresenter.PART_HourScrollPanel}"
Grid.Column="0" Grid.Column="0"
HorizontalContentAlignment="Left"
HorizontalAlignment="Left" HorizontalAlignment="Left"
HorizontalContentAlignment="Left"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden"> VerticalScrollBarVisibility="Hidden">
<u:UrsaDateTimeScrollPanel <u:UrsaDateTimeScrollPanel
Name="{x:Static u:TimePickerPresenter.PART_HourSelector}" Name="{x:Static u:TimePickerPresenter.PART_HourSelector}"
HorizontalAlignment="Left"
MinWidth="64" MinWidth="64"
HorizontalAlignment="Left"
ItemHeight="32" ItemHeight="32"
PanelType="Hour" PanelType="Hour"
ShouldLoop="True" /> ShouldLoop="True" />
</ScrollViewer> </ScrollViewer>
<ScrollViewer <Rectangle
Grid.Column="1" Grid.Column="1"
HorizontalContentAlignment="Left" Name="{x:Static u:TimePickerPresenter.PART_FirstSeparator}"
Width="1"
Margin="0,4"
Fill="{DynamicResource DateTimePickerSeparatorBackground}"
VerticalAlignment="Stretch" />
<ScrollViewer
Name="{x:Static u:TimePickerPresenter.PART_MinuteScrollPanel}"
Grid.Column="2"
HorizontalAlignment="Left" HorizontalAlignment="Left"
HorizontalContentAlignment="Left"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden"> VerticalScrollBarVisibility="Hidden">
<u:UrsaDateTimeScrollPanel <u:UrsaDateTimeScrollPanel
@@ -47,8 +54,16 @@
PanelType="Minute" PanelType="Minute"
ShouldLoop="True" /> ShouldLoop="True" />
</ScrollViewer> </ScrollViewer>
<Rectangle
Grid.Column="3"
Name="{x:Static u:TimePickerPresenter.PART_SecondSeparator}"
Width="1"
Margin="0,4"
Fill="{DynamicResource DateTimePickerSeparatorBackground}"
VerticalAlignment="Stretch" />
<ScrollViewer <ScrollViewer
Grid.Column="2" Name="{x:Static u:TimePickerPresenter.PART_SecondScrollPanel}"
Grid.Column="4"
HorizontalAlignment="Left" HorizontalAlignment="Left"
HorizontalContentAlignment="Left" HorizontalContentAlignment="Left"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled"
@@ -60,8 +75,16 @@
PanelType="Minute" PanelType="Minute"
ShouldLoop="True" /> ShouldLoop="True" />
</ScrollViewer> </ScrollViewer>
<Rectangle
Grid.Column="5"
Name="{x:Static u:TimePickerPresenter.PART_ThirdSeparator}"
Width="1"
Margin="0,4"
Fill="{DynamicResource DateTimePickerSeparatorBackground}"
VerticalAlignment="Stretch" />
<ScrollViewer <ScrollViewer
Grid.Column="3" Name="{x:Static u:TimePickerPresenter.PART_AmPmScrollPanel}"
Grid.Column="6"
HorizontalAlignment="Left" HorizontalAlignment="Left"
HorizontalContentAlignment="Left" HorizontalContentAlignment="Left"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled"

View File

@@ -2,6 +2,7 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Irihi.Avalonia.Shared.Helpers;
namespace Ursa.Controls; namespace Ursa.Controls;
@@ -10,6 +11,13 @@ namespace Ursa.Controls;
[TemplatePart(PART_MinuteSelector, typeof(DateTimePickerPanel))] [TemplatePart(PART_MinuteSelector, typeof(DateTimePickerPanel))]
[TemplatePart(PART_SecondSelector, typeof(DateTimePickerPanel))] [TemplatePart(PART_SecondSelector, typeof(DateTimePickerPanel))]
[TemplatePart(PART_AmPmSelector, typeof(DateTimePickerPanel))] [TemplatePart(PART_AmPmSelector, typeof(DateTimePickerPanel))]
[TemplatePart(PART_HourScrollPanel, typeof(Control))]
[TemplatePart(PART_MinuteScrollPanel, typeof(Control))]
[TemplatePart(PART_SecondScrollPanel, typeof(Control))]
[TemplatePart(PART_AmPmScrollPanel, typeof(Control))]
[TemplatePart(PART_FirstSeparator, typeof(Control))]
[TemplatePart(PART_SecondSeparator, typeof(Control))]
[TemplatePart(PART_ThirdSeparator, typeof(Control))]
public class TimePickerPresenter: TemplatedControl public class TimePickerPresenter: TemplatedControl
{ {
public const string PART_HourSelector = "PART_HourSelector"; public const string PART_HourSelector = "PART_HourSelector";
@@ -18,11 +26,29 @@ public class TimePickerPresenter: TemplatedControl
public const string PART_AmPmSelector = "PART_AmPmSelector"; public const string PART_AmPmSelector = "PART_AmPmSelector";
public const string PART_PickerContainer = "PART_PickerContainer"; public const string PART_PickerContainer = "PART_PickerContainer";
public const string PART_HourScrollPanel = "PART_HourScrollPanel";
public const string PART_MinuteScrollPanel = "PART_MinuteScrollPanel";
public const string PART_SecondScrollPanel = "PART_SecondScrollPanel";
public const string PART_AmPmScrollPanel = "PART_AmPmScrollPanel";
public const string PART_FirstSeparator = "PART_FirstSeparator";
public const string PART_SecondSeparator = "PART_SecondSeparator";
public const string PART_ThirdSeparator = "PART_ThirdSeparator";
private DateTimePickerPanel? _hourSelector; private DateTimePickerPanel? _hourSelector;
private DateTimePickerPanel? _minuteSelector; private DateTimePickerPanel? _minuteSelector;
private DateTimePickerPanel? _secondSelector; private DateTimePickerPanel? _secondSelector;
private DateTimePickerPanel? _ampmSelector; private DateTimePickerPanel? _ampmSelector;
private Grid? _pickerContainer; private Grid? _pickerContainer;
private Control? _hourScrollPanel;
private Control? _minuteScrollPanel;
private Control? _secondScrollPanel;
private Control? _ampmScrollPanel;
private Control? _firstSeparator;
private Control? _secondSeparator;
private Control? _thirdSeparator;
private bool _use12Clock;
public static readonly StyledProperty<bool> NeedsConfirmationProperty = AvaloniaProperty.Register<TimePickerPresenter, bool>( public static readonly StyledProperty<bool> NeedsConfirmationProperty = AvaloniaProperty.Register<TimePickerPresenter, bool>(
nameof(NeedsConfirmation)); nameof(NeedsConfirmation));
@@ -51,17 +77,8 @@ public class TimePickerPresenter: TemplatedControl
set => SetValue(TimeProperty, value); set => SetValue(TimeProperty, value);
} }
public static readonly StyledProperty<bool> Use12HoursProperty = AvaloniaProperty.Register<TimePickerPresenter, bool>(
nameof(Use12Hours));
public bool Use12Hours
{
get => GetValue(Use12HoursProperty);
set => SetValue(Use12HoursProperty, value);
}
public static readonly StyledProperty<string> PanelFormatProperty = AvaloniaProperty.Register<TimePickerPresenter, string>( public static readonly StyledProperty<string> PanelFormatProperty = AvaloniaProperty.Register<TimePickerPresenter, string>(
nameof(PanelFormat)); nameof(PanelFormat), defaultValue: "hh mm ss t");
public string PanelFormat public string PanelFormat
{ {
@@ -69,6 +86,72 @@ public class TimePickerPresenter: TemplatedControl
set => SetValue(PanelFormatProperty, value); set => SetValue(PanelFormatProperty, value);
} }
static TimePickerPresenter()
{
PanelFormatProperty.Changed.AddClassHandler<TimePickerPresenter, string>((presenter, args) => presenter.OnPanelFormatChanged(args));
}
private void OnPanelFormatChanged(AvaloniaPropertyChangedEventArgs<string> args)
{
var format = args.NewValue.Value;
UpdatePanelLayout(format);
}
private void UpdatePanelLayout(string panelFormat)
{
var parts = panelFormat.Split(' ', '-', ':');
var panels = new List<Control?>();
foreach (var part in parts)
{
if (part.Length < 1) continue;
if ((part.Contains('h') || part.Contains('H')) && !panels.Contains(_hourScrollPanel))
{
panels.Add(_hourScrollPanel);
_use12Clock = part.Contains('h');
_hourSelector?.SetValue(DateTimePickerPanel.ItemFormatProperty, part.ToLower());
if (_hourSelector is not null)
{
_hourSelector.MaximumValue = _use12Clock ? 12 : 23;
_hourSelector.MinimumValue = _use12Clock ? 1 : 0;
}
}
else if (part[0] == 'm' && !panels.Contains(_minuteSelector))
{
panels.Add(_minuteScrollPanel);
_minuteSelector?.SetValue(DateTimePickerPanel.ItemFormatProperty, part);
}
else if (part[0] == 's' && !panels.Contains(_secondScrollPanel))
{
panels.Add(_secondScrollPanel);
_secondSelector?.SetValue(DateTimePickerPanel.ItemFormatProperty, part.Replace('s', 'm'));
}
else if (part[0] == 't' && !panels.Contains(_ampmScrollPanel))
{
panels.Add(_ampmScrollPanel);
_ampmSelector?.SetValue(DateTimePickerPanel.ItemFormatProperty, part);
}
}
if (panels.Count < 1) return;
IsVisibleProperty.SetValue(false, _hourScrollPanel, _minuteScrollPanel, _secondScrollPanel, _ampmScrollPanel,
_firstSeparator, _secondSeparator, _thirdSeparator);
for(var i = 0; i< panels.Count; i++)
{
var panel = panels[i];
if (panel is null) continue;
panel.IsVisible = true;
Grid.SetColumn(panel, 2 * i);
var separator = i switch
{
0 => _firstSeparator,
1 => _secondSeparator,
2 => _thirdSeparator,
_ => null,
};
IsVisibleProperty.SetValue(true, separator);
}
}
public TimePickerPresenter() public TimePickerPresenter()
{ {
SetCurrentValue(TimeProperty, DateTime.Now.TimeOfDay); SetCurrentValue(TimeProperty, DateTime.Now.TimeOfDay);
@@ -82,48 +165,74 @@ public class TimePickerPresenter: TemplatedControl
_secondSelector = e.NameScope.Find<DateTimePickerPanel>(PART_SecondSelector); _secondSelector = e.NameScope.Find<DateTimePickerPanel>(PART_SecondSelector);
_ampmSelector = e.NameScope.Find<DateTimePickerPanel>(PART_AmPmSelector); _ampmSelector = e.NameScope.Find<DateTimePickerPanel>(PART_AmPmSelector);
_pickerContainer = e.NameScope.Find<Grid>(PART_PickerContainer); _pickerContainer = e.NameScope.Find<Grid>(PART_PickerContainer);
_hourScrollPanel = e.NameScope.Find<Control>(PART_HourScrollPanel);
_minuteScrollPanel = e.NameScope.Find<Control>(PART_MinuteScrollPanel);
_secondScrollPanel = e.NameScope.Find<Control>(PART_SecondScrollPanel);
_ampmScrollPanel = e.NameScope.Find<Control>(PART_AmPmScrollPanel);
_firstSeparator = e.NameScope.Find<Control>(PART_FirstSeparator);
_secondSeparator = e.NameScope.Find<Control>(PART_SecondSeparator);
_thirdSeparator = e.NameScope.Find<Control>(PART_ThirdSeparator);
Initialize(); Initialize();
UpdatePanelLayout(PanelFormat);
UpdatePanelsFromSelectedTime();
}
private void UpdatePanelsFromSelectedTime()
{
if (Time is null) return;
var time = Time ?? DateTime.Now.TimeOfDay;
if (_hourSelector is not null)
{
_hourSelector.SelectedValue = _use12Clock ? time.Hours % 12 : time.Hours;
}
if (_minuteSelector is not null)
{
_minuteSelector.SelectedValue = time.Minutes;
}
if (_secondSelector is not null)
{
_secondSelector.SelectedValue = time.Seconds;
}
if (_ampmSelector is not null)
{
_ampmSelector.SelectedValue = time.Hours switch
{
>= 12 => 1,
_ => 0
};
}
} }
private void Initialize() private void Initialize()
{ {
if (_pickerContainer is null) return; if (_pickerContainer is null) return;
var use12Clock = Use12Hours;
if (_hourSelector is not null) if (_hourSelector is not null)
{ {
_hourSelector.MaximumValue = use12Clock ? 12 : 23;
_hourSelector.MinimumValue = use12Clock ? 1 : 0;
_hourSelector.ItemFormat = "%h"; _hourSelector.ItemFormat = "%h";
var hour = Time?.Hours; _hourSelector.MaximumValue = _use12Clock ? 12 : 23;
_hourSelector.SelectedValue = hour ?? 0; _hourSelector.MinimumValue = _use12Clock ? 1 : 0;
} }
if(_minuteSelector is not null) if(_minuteSelector is not null)
{ {
_minuteSelector.ItemFormat = "mm";
_minuteSelector.MaximumValue = 59; _minuteSelector.MaximumValue = 59;
_minuteSelector.MinimumValue = 0; _minuteSelector.MinimumValue = 0;
_minuteSelector.ItemFormat = "mm";
var minute = Time?.Minutes;
_minuteSelector.SelectedValue = minute ?? 0;
} }
if(_secondSelector is not null) if(_secondSelector is not null)
{ {
_secondSelector.ItemFormat = "mm";
_secondSelector.MaximumValue = 59; _secondSelector.MaximumValue = 59;
_secondSelector.MinimumValue = 0; _secondSelector.MinimumValue = 0;
_secondSelector.ItemFormat = "mm";
var second = Time?.Seconds;
_secondSelector.SelectedValue = second ?? 0;
} }
if(_ampmSelector is not null) if(_ampmSelector is not null)
{ {
_ampmSelector.ItemFormat = "t";
_ampmSelector.MaximumValue = 1; _ampmSelector.MaximumValue = 1;
_ampmSelector.MinimumValue = 0; _ampmSelector.MinimumValue = 0;
_ampmSelector.ItemFormat = "%t";
var ampm = Time?.Hours switch
{
>= 12 => 1,
_ => 0
};
_ampmSelector.SelectedValue = ampm;
} }
} }
} }