feat: add theme and function.

This commit is contained in:
rabbitism
2024-03-05 21:07:15 +08:00
parent 47f3bd759e
commit 390b581cb8
8 changed files with 227 additions and 23 deletions

View File

@@ -8,7 +8,7 @@
d:DesignHeight="850"
d:DesignWidth="850"
mc:Ignorable="d">
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<ScrollViewer HorizontalScrollBarVisibility="Auto" u:ScrollTo.Direction="Top">
<StackPanel
Margin="24"
HorizontalAlignment="Left"

View File

@@ -0,0 +1,39 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa">
<!-- Add Resources Here -->
<ControlTheme x:Key="{x:Type u:ScrollToButton}" TargetType="u:ScrollToButton">
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="Cursor" Value="Hand"></Setter>
<Setter Property="Margin" Value="0, 0, 32, 32" />
<Setter Property="Template">
<ControlTemplate TargetType="u:ScrollToButton">
<Border
Name="PART_Background"
Background="{DynamicResource ButtonDefaultBackground}"
CornerRadius="{DynamicResource ButtonCornerRadius}">
<PathIcon
Name="PART_Icon"
Margin="8"
Width="16"
Height="16"
Data="{DynamicResource ScrollToButtonIconGlyph}"
Foreground="{DynamicResource ButtonDefaultPrimaryForeground}" />
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pressed">
<Setter Property="RenderTransform" Value="scale(0.98)" />
</Style>
<Style Selector="^:pointerover /template/ Border#PART_Background">
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultPointeroverBorderBrush}" />
<Setter Property="Background" Value="{DynamicResource ButtonDefaultPointeroverBackground}" />
</Style>
<Style Selector="^:pressed /template/ Border#PART_Background">
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultPressedBorderBrush}" />
<Setter Property="Background" Value="{DynamicResource ButtonDefaultPressedBackground}" />
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -25,6 +25,7 @@
<ResourceInclude Source="NumberDisplayer.axaml" />
<ResourceInclude Source="Pagination.axaml" />
<ResourceInclude Source="RangeSlider.axaml" />
<ResourceInclude Source="ScrollToButton.axaml" />
<ResourceInclude Source="SelectionList.axaml" />
<ResourceInclude Source="TagInput.axaml" />
<ResourceInclude Source="ThemeSelector.axaml" />

View File

@@ -0,0 +1,5 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<StreamGeometry x:Key="ScrollToButtonIconGlyph">M19.637 16.4369C19.0513 17.0227 18.1015 17.0227 17.5157 16.4369L11.8589 10.7801L6.20202 16.4369C5.61623 17.0227 4.66648 17.0227 4.0807 16.4369C3.49491 15.8511 3.49491 14.9014 4.0807 14.3156L10.7982 7.59809C11.384 7.01231 12.3337 7.01231 12.9195 7.59809L19.637 14.3156C20.2228 14.9014 20.2228 15.8511 19.637 16.4369Z</StreamGeometry>
</ResourceDictionary>

View File

@@ -13,6 +13,7 @@
<MergeResourceInclude Source="MessageBox.axaml" />
<MergeResourceInclude Source="NavigationMenu.axaml" />
<MergeResourceInclude Source="Pagination.axaml" />
<MergeResourceInclude Source="ScrollToButton.axaml" />
<MergeResourceInclude Source="TagInput.axaml" />
<MergeResourceInclude Source="Skeleton.axaml" />
<MergeResourceInclude Source="ThemeSelector.axaml" />

View File

@@ -1,22 +0,0 @@
using Avalonia;
using Avalonia.Controls;
namespace Ursa.Controls;
public class BackTopButton: Button
{
public static readonly StyledProperty<Control> TargetProperty = AvaloniaProperty.Register<BackTopButton, Control>(
nameof(Target));
public Control Target
{
get => GetValue(TargetProperty);
set => SetValue(TargetProperty, value);
}
protected override void OnClick()
{
base.OnClick();
}
}

View File

@@ -0,0 +1,64 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Notifications;
using Avalonia.Controls.Primitives;
using Avalonia.Layout;
using Avalonia.LogicalTree;
using Avalonia.Styling;
using Ursa.Common;
namespace Ursa.Controls;
public class ScrollTo
{
public static readonly AttachedProperty<Position> DirectionProperty =
AvaloniaProperty.RegisterAttached<ScrollTo, Control, Position>("Direction");
public static void SetDirection(Control obj, Position value) => obj.SetValue(DirectionProperty, value);
public static Position GetDirection(Control obj) => obj.GetValue(DirectionProperty);
public static readonly AttachedProperty<ControlTheme?> ButtonThemeProperty =
AvaloniaProperty.RegisterAttached<ScrollTo, Control, ControlTheme?>("ButtonTheme");
public static void SetButtonTheme(Control obj, ControlTheme? value) => obj.SetValue(ButtonThemeProperty, value);
public static ControlTheme? GetButtonTheme(Control obj) => obj.GetValue(ButtonThemeProperty);
static ScrollTo()
{
DirectionProperty.Changed.AddClassHandler<Control, Position>(OnDirectionChanged);
ButtonThemeProperty.Changed.AddClassHandler<Control, ControlTheme?>(OnButtonThemeChanged);
}
private static void OnButtonThemeChanged(Control arg1, AvaloniaPropertyChangedEventArgs<ControlTheme?> arg2)
{
var button = EnsureButtonInAdorner(arg1);
if (button is null) return;
button.SetCurrentValue(StyledElement.ThemeProperty, arg2.NewValue.Value);
}
private static void OnDirectionChanged(Control control, AvaloniaPropertyChangedEventArgs<Position> args)
{
var button = EnsureButtonInAdorner(control);
if (button is null) return;
button.SetCurrentValue(ScrollToButton.DirectionProperty, args.NewValue.Value);
}
private static ScrollToButton? EnsureButtonInAdorner(Control control)
{
var scroll = control.GetSelfAndLogicalDescendants().OfType<ScrollViewer>().FirstOrDefault();
if (scroll is null) return null;
var adorner = AdornerLayer.GetAdorner(scroll);
if (adorner is not ScrollToButton button)
{
button = new ScrollToButton();
AdornerLayer.SetAdorner(control, button);
}
button.SetCurrentValue(ScrollToButton.TargetProperty, scroll);
button.SetCurrentValue(ScrollToButton.DirectionProperty, GetDirection(control));
if ( GetButtonTheme(control) is { } theme)
{
button.SetCurrentValue(StyledElement.ThemeProperty, theme);
}
return button;
}
}

View File

@@ -0,0 +1,116 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using Irihi.Avalonia.Shared.Helpers;
using Ursa.Common;
namespace Ursa.Controls;
public class ScrollToButton: Button
{
private ScrollViewer? _scroll;
private IDisposable? _disposable;
public static readonly StyledProperty<Control> TargetProperty = AvaloniaProperty.Register<ScrollToButton, Control>(
nameof(Target));
public Control Target
{
get => GetValue(TargetProperty);
set => SetValue(TargetProperty, value);
}
public static readonly StyledProperty<Position> DirectionProperty = AvaloniaProperty.Register<ScrollToButton, Position>(
nameof(Direction));
public Position Direction
{
get => GetValue(DirectionProperty);
set => SetValue(DirectionProperty, value);
}
static ScrollToButton()
{
TargetProperty.Changed.AddClassHandler<ScrollToButton, Control>((o,e)=>o.OnTargetChanged(e));
DirectionProperty.Changed.AddClassHandler<ScrollToButton, Position>((o,e)=>o.OnDirectionChanged(e));
}
private void OnDirectionChanged(AvaloniaPropertyChangedEventArgs<Position> avaloniaPropertyChangedEventArgs)
{
if (_scroll is null) return;
SetVisibility(avaloniaPropertyChangedEventArgs.NewValue.Value, _scroll.Offset);
}
private void OnTargetChanged(AvaloniaPropertyChangedEventArgs<Control> arg2)
{
_disposable?.Dispose();
if (arg2.NewValue.Value is { } newValue)
{
var scroll = newValue.GetSelfAndLogicalDescendants().OfType<ScrollViewer>().FirstOrDefault();
if (_scroll is not null)
{
_disposable?.Dispose();
}
_scroll = scroll;
_disposable = ScrollViewer.OffsetProperty.Changed.AddClassHandler<ScrollViewer, Vector>(OnScrollChanged);
SetVisibility(Direction, _scroll?.Offset);
}
}
protected override void OnClick()
{
var vector = Direction switch
{
Position.Top => new Vector(0, double.NegativeInfinity),
Position.Bottom => new Vector(0, double.PositiveInfinity),
Position.Left => new Vector(double.NegativeInfinity, 0),
Position.Right => new Vector(double.PositiveInfinity, 0),
_ => new Vector(0, 0)
};
_scroll?.SetCurrentValue(ScrollViewer.OffsetProperty, vector);
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
var scroll = Target.GetSelfAndLogicalDescendants().OfType<ScrollViewer>().FirstOrDefault();
if (_scroll is not null)
{
_disposable?.Dispose();
}
_scroll = scroll;
_disposable = ScrollViewer.OffsetProperty.Changed.AddClassHandler<ScrollViewer, Vector>(OnScrollChanged);
SetVisibility(Direction, _scroll?.Offset);
}
private void OnScrollChanged(ScrollViewer arg1, AvaloniaPropertyChangedEventArgs<Vector> arg2)
{
if (arg1 != _scroll) return;
SetVisibility(Direction, arg2.NewValue.Value);
}
private void SetVisibility(Position direction, Vector? vector)
{
if (vector is null) return;
if (direction == Position.Bottom && vector.Value.Y < 0)
{
IsVisible = true;
}
else if (direction == Position.Top && vector.Value.Y > 0)
{
IsVisible = true;
}
else if (direction == Position.Left && vector.Value.X < 0)
{
IsVisible = true;
}
else if (direction == Position.Right && vector.Value.X > 0)
{
IsVisible = true;
}
else
{
IsVisible = false;
}
}
}