feat: logical scrollable.

This commit is contained in:
rabbitism
2024-04-25 19:29:39 +08:00
parent 294d066bbd
commit 0fc5cc5637
5 changed files with 176 additions and 72 deletions

View File

@@ -0,0 +1,110 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Irihi.Avalonia.Shared.Contracts;
namespace Ursa.Controls.TimePicker;
public class TimePicker: TemplatedControl, IClearControl
{
private TimeSpan? _selectedTimeHolder;
public static readonly StyledProperty<string> DisplayFormatProperty = AvaloniaProperty.Register<TimePicker, string>(
nameof(DisplayFormat), defaultValue: "HH:mm:ss");
public string DisplayFormat
{
get => GetValue(DisplayFormatProperty);
set => SetValue(DisplayFormatProperty, value);
}
public static readonly StyledProperty<string> PanelFormatProperty = AvaloniaProperty.Register<TimePicker, string>(
nameof(PanelFormat), defaultValue: "HH mm ss");
public string PanelFormat
{
get => GetValue(PanelFormatProperty);
set => SetValue(PanelFormatProperty, value);
}
public static readonly StyledProperty<TimeSpan?> SelectedTimeProperty = AvaloniaProperty.Register<TimePicker, TimeSpan?>(
nameof(SelectedTime));
public TimeSpan? SelectedTime
{
get => GetValue(SelectedTimeProperty);
set => SetValue(SelectedTimeProperty, value);
}
public static readonly StyledProperty<bool> NeedConfirmationProperty = AvaloniaProperty.Register<TimePicker, bool>(
nameof(NeedConfirmation));
public bool NeedConfirmation
{
get => GetValue(NeedConfirmationProperty);
set => SetValue(NeedConfirmationProperty, value);
}
public static readonly StyledProperty<bool> IsLoopingProperty = AvaloniaProperty.Register<TimePicker, bool>(
nameof(IsLooping));
public bool IsLooping
{
get => GetValue(IsLoopingProperty);
set => SetValue(IsLoopingProperty, value);
}
static TimePicker()
{
PanelFormatProperty.Changed.AddClassHandler<TimePicker, string>((picker, args)=> picker.OnPanelFormatChanged(args));
}
private void OnPanelFormatChanged(AvaloniaPropertyChangedEventArgs<string> args)
{
var format = args.NewValue.Value;
string[] parts = format.Split(new char[] { ' ', '-', ':' });
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
}
private void OnSelectionChanged()
{
if (NeedConfirmation)
{
_selectedTimeHolder = new TimeSpan();
}
else
{
SelectedTime = new TimeSpan();
}
}
public void Clear()
{
SetCurrentValue(SelectedTimeProperty, null);
}
public void Confirm()
{
if (NeedConfirmation)
{
// TODO: close popup.
SetCurrentValue(SelectedTimeProperty, _selectedTimeHolder);
}
}
protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error)
{
base.UpdateDataValidation(property, state, error);
if (property == SelectedTimeProperty)
{
DataValidationErrors.SetError(this, error);
}
}
}

View File

@@ -0,0 +1,62 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Ursa.Controls.Panels;
/// <summary>
/// The panel to display items for time selection
/// </summary>
public class UrsaTimePickerPanel: Panel, ILogicalScrollable
{
public static readonly StyledProperty<double> ItemHeightProperty =
AvaloniaProperty.Register<UrsaTimePickerPanel, double>(
nameof(ItemHeight), defaultValue: 32);
public double ItemHeight
{
get => GetValue(ItemHeightProperty);
set => SetValue(ItemHeightProperty, value);
}
public static readonly StyledProperty<bool> ShouldLoopProperty = AvaloniaProperty.Register<UrsaTimePickerPanel, bool>(
nameof(ShouldLoop));
public bool ShouldLoop
{
get => GetValue(ShouldLoopProperty);
set => SetValue(ShouldLoopProperty, value);
}
static UrsaTimePickerPanel()
{
ItemHeightProperty.Changed.AddClassHandler<UrsaTimePickerPanel, double>((panel, args) => panel.OnItemHeightChanged(args));
AffectsArrange<UrsaTimePickerPanel>(ItemHeightProperty);
AffectsMeasure<UrsaTimePickerPanel>(ItemHeightProperty);
}
private Size _scrollSize;
private Size _pageScrollSize;
private void OnItemHeightChanged(AvaloniaPropertyChangedEventArgs<double> args)
{
var newValue = args.NewValue.Value;
_scrollSize = new Size(0, newValue);
_pageScrollSize = new Size(0, newValue * 3);
}
public event EventHandler? OnSelectionChanged;
public Size Extent { get; private set; }
public Vector Offset { get; set; }
public Size Viewport => Bounds.Size;
public bool BringIntoView(Control target, Rect targetRect) => false;
public Control? GetControlInDirection(NavigationDirection direction, Control? from) => null;
public void RaiseScrollInvalidated(System.EventArgs e) => ScrollInvalidated?.Invoke(this, e);
public bool CanHorizontallyScroll { get => false; set { } }
public bool CanVerticallyScroll { get => false; set {} }
public bool IsLogicalScrollEnabled => true;
public Size ScrollSize => _scrollSize;
public Size PageScrollSize => _pageScrollSize;
public event EventHandler? ScrollInvalidated;
}

View File

@@ -1,28 +0,0 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
namespace Ursa.Controls.Panels;
/// <summary>
/// The panel to display items for time selection
/// </summary>
public class UrsaTimePickerPanel: Panel
{
/// <summary>
/// Defines whether the panel is looping.
/// This is ont applicable for columns like year and AM/PM designation.
/// </summary>
public static readonly StyledProperty<bool> IsLoopingProperty = AvaloniaProperty.Register<UrsaTimePickerPanel, bool>(
nameof(IsLooping));
/// <summary>
/// Gets or sets the value of <see cref="IsLoopingProperty"/>.
/// </summary>
public bool IsLooping
{
get => GetValue(IsLoopingProperty);
set => SetValue(IsLoopingProperty, value);
}
}

View File

@@ -1,44 +0,0 @@
using Avalonia;
using Avalonia.Controls.Primitives;
namespace Ursa.Controls.TimePicker;
public class TimePicker: TemplatedControl
{
public static readonly StyledProperty<string> DisplayFormatProperty = AvaloniaProperty.Register<TimePicker, string>(
nameof(DisplayFormat), defaultValue:"HH:mm:ss");
public string DisplayFormat
{
get => GetValue(DisplayFormatProperty);
set => SetValue(DisplayFormatProperty, value);
}
public static readonly StyledProperty<string> PanelPlacementProperty =
AvaloniaProperty.Register<TimePicker, string>(
nameof(PanelPlacement), defaultValue: "HH mm ss");
public string PanelPlacement
{
get => GetValue(PanelPlacementProperty);
set => SetValue(PanelPlacementProperty, value);
}
public static readonly StyledProperty<TimeSpan?> SelectedTimeProperty = AvaloniaProperty.Register<TimePicker, TimeSpan?>(
nameof(SelectedTime));
public TimeSpan? SelectedTime
{
get => GetValue(SelectedTimeProperty);
set => SetValue(SelectedTimeProperty, value);
}
public static readonly StyledProperty<bool> NeedConfirmProperty = AvaloniaProperty.Register<TimePicker, bool>(
nameof(NeedConfirm));
public bool NeedConfirm
{
get => GetValue(NeedConfirmProperty);
set => SetValue(NeedConfirmProperty, value);
}
}

View File

@@ -24,4 +24,8 @@
<None Include="irihi.png" Pack="true" PackagePath=""/>
</ItemGroup>
<ItemGroup>
<Folder Include="Controls\Panels\" />
</ItemGroup>
</Project>