feat: Add theme.

This commit is contained in:
rabbitism
2024-03-06 15:46:06 +08:00
parent 390b581cb8
commit eb14cf9e13
11 changed files with 181 additions and 57 deletions

View File

@@ -1,37 +0,0 @@
namespace Ursa.Demo;
public static class MenuKeys
{
public const string MenuKeyIntroduction = "Introduction";
public const string MenuKeyBadge = "Badge";
public const string MenuKeyBanner = "Banner";
public const string MenuKeyButtonGroup = "ButtonGroup";
public const string MenuKeyBreadcrumb = "Breadcrumb";
public const string MenuKeyClassInput = "Class Input";
public const string MenuKeyDialog = "Dialog";
public const string MenuKeyDivider = "Divider";
public const string MenuKeyDisableContainer = "DisableContainer";
public const string MenuKeyDrawer = "Drawer";
public const string MenuKeyDualBadge = "DualBadge";
public const string MenuKeyEnumSelector = "EnumSelector";
public const string MenuKeyForm = "Form";
public const string MenuKeyImageViewer = "ImageViewer";
public const string MenuKeyIpBox = "IPv4Box";
public const string MenuKeyIconButton = "IconButton";
public const string MenuKeyKeyGestureInput = "KeyGestureInput";
public const string MenuKeyLoading = "Loading";
public const string MenuKeyMessageBox = "MessageBox";
public const string MenuKeyNavMenu = "NavMenu";
public const string MenuKeyNumberDisplayer = "NumberDisplayer";
public const string MenuKeyNumericUpDown = "NumericUpDown";
public const string MenuKeyPagination = "Pagination";
public const string MenuKeyRangeSlider = "RangeSlider";
public const string MenuKeySelectionList = "SelectionList";
public const string MenuKeyTagInput = "TagInput";
public const string MenuKeySkeleton = "Skeleton";
public const string MenuKeyTimeline = "Timeline";
public const string MenuKeyTwoTonePathIcon = "TwoTonePathIcon";
public const string MenuKeyThemeToggler = "ThemeToggler";
public const string MenuKeyToolBar = "ToolBar";
}

View File

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

View File

@@ -0,0 +1,76 @@
<UserControl
x:Class="Ursa.Demo.Pages.ScrollToButtonDemo"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:u="https://irihi.tech/ursa"
xmlns:vm="clr-namespace:Ursa.Demo.ViewModels"
d:DesignHeight="450"
d:DesignWidth="800"
x:CompileBindings="True"
x:DataType="vm:ScrollToButtonDemoViewModel"
mc:Ignorable="d">
<UserControl.Styles>
<Style Selector="ScrollViewer">
<Setter Property="Margin" Value="8" />
</Style>
<Style Selector="ScrollViewer Border.Content">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0, 0" EndPoint="2000, 2000">
<GradientStop Color="{DynamicResource SemiPurple9Color}" Offset="0.0"></GradientStop>
<GradientStop Color="{DynamicResource SemiPurple5Color}" Offset="0.5"></GradientStop>
<GradientStop Color="{DynamicResource SemiPurple1Color}" Offset="1.0"></GradientStop>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</UserControl.Styles>
<Grid ColumnDefinitions="*, *, *, *, *" RowDefinitions="Auto, *">
<TextBlock Grid.Row="0" Grid.Column="0">Scroll To Top</TextBlock>
<TextBlock Grid.Row="0" Grid.Column="1">Scroll To Bottom</TextBlock>
<TextBlock Grid.Row="0" Grid.Column="2">Scroll To Left</TextBlock>
<TextBlock Grid.Row="0" Grid.Column="3">Scroll To Right</TextBlock>
<TextBlock Grid.Row="0" Grid.Column="4">Scroll To Top</TextBlock>
<ScrollViewer
Grid.Row="1"
Grid.Column="0"
u:ScrollTo.Direction="Top"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<Border Classes="Content" Height="2000" HorizontalAlignment="Stretch" />
</ScrollViewer>
<ScrollViewer
Grid.Row="1"
Grid.Column="1"
u:ScrollTo.Direction="Bottom"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<Border Classes="Content" Height="2000" HorizontalAlignment="Stretch" />
</ScrollViewer>
<ScrollViewer
Grid.Row="1"
Grid.Column="2"
u:ScrollTo.Direction="Left"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<Border Classes="Content" Width="2000" VerticalAlignment="Stretch" />
</ScrollViewer>
<ScrollViewer
Grid.Row="1"
Grid.Column="3"
u:ScrollTo.Direction="Right"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<Border Classes="Content" Width="2000" VerticalAlignment="Stretch" />
</ScrollViewer>
<ListBox
Grid.Row="1"
Grid.Column="4"
u:ScrollTo.Direction="Top"
ItemsSource="{Binding Items}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Ursa.Demo.Pages;
public partial class ScrollToButtonDemo : UserControl
{
public ScrollToButtonDemo()
{
InitializeComponent();
}
}

View File

@@ -32,4 +32,8 @@
<DependentUpon>SkeletonDemo.axaml</DependentUpon> <DependentUpon>SkeletonDemo.axaml</DependentUpon>
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Models\" />
</ItemGroup>
</Project> </Project>

View File

@@ -48,6 +48,7 @@ public class MainViewViewModel : ViewModelBase
MenuKeys.MenuKeyNumericUpDown => new NumericUpDownDemoViewModel(), MenuKeys.MenuKeyNumericUpDown => new NumericUpDownDemoViewModel(),
MenuKeys.MenuKeyPagination => new PaginationDemoViewModel(), MenuKeys.MenuKeyPagination => new PaginationDemoViewModel(),
MenuKeys.MenuKeyRangeSlider => new RangeSliderDemoViewModel(), MenuKeys.MenuKeyRangeSlider => new RangeSliderDemoViewModel(),
MenuKeys.MenuKeyScrollToButton => new ScrollToButtonDemoViewModel(),
MenuKeys.MenuKeySelectionList => new SelectionListDemoViewModel(), MenuKeys.MenuKeySelectionList => new SelectionListDemoViewModel(),
MenuKeys.MenuKeySkeleton => new SkeletonDemoViewModel(), MenuKeys.MenuKeySkeleton => new SkeletonDemoViewModel(),
MenuKeys.MenuKeyTagInput => new TagInputDemoViewModel(), MenuKeys.MenuKeyTagInput => new TagInputDemoViewModel(),

View File

@@ -35,6 +35,7 @@ public class MenuViewModel: ViewModelBase
new() { MenuHeader = "Numeric UpDown", Key = MenuKeys.MenuKeyNumericUpDown }, new() { MenuHeader = "Numeric UpDown", Key = MenuKeys.MenuKeyNumericUpDown },
new() { MenuHeader = "Pagination", Key = MenuKeys.MenuKeyPagination }, new() { MenuHeader = "Pagination", Key = MenuKeys.MenuKeyPagination },
new() { MenuHeader = "RangeSlider", Key = MenuKeys.MenuKeyRangeSlider }, new() { MenuHeader = "RangeSlider", Key = MenuKeys.MenuKeyRangeSlider },
new() { MenuHeader = "ScrollToButton", Key = MenuKeys.MenuKeyScrollToButton, Status = "New" },
new() { MenuHeader = "Selection List", Key = MenuKeys.MenuKeySelectionList, Status = "New" }, new() { MenuHeader = "Selection List", Key = MenuKeys.MenuKeySelectionList, Status = "New" },
new() { MenuHeader = "Skeleton", Key = MenuKeys.MenuKeySkeleton, Status = "New" }, new() { MenuHeader = "Skeleton", Key = MenuKeys.MenuKeySkeleton, Status = "New" },
new() { MenuHeader = "TagInput", Key = MenuKeys.MenuKeyTagInput }, new() { MenuHeader = "TagInput", Key = MenuKeys.MenuKeyTagInput },
@@ -45,3 +46,40 @@ public class MenuViewModel: ViewModelBase
}; };
} }
} }
public static class MenuKeys
{
public const string MenuKeyIntroduction = "Introduction";
public const string MenuKeyBadge = "Badge";
public const string MenuKeyBanner = "Banner";
public const string MenuKeyButtonGroup = "ButtonGroup";
public const string MenuKeyBreadcrumb= "Breadcrumb";
public const string MenuKeyClassInput = "Class Input";
public const string MenuKeyDialog = "Dialog";
public const string MenuKeyDivider = "Divider";
public const string MenuKeyDisableContainer = "DisableContainer";
public const string MenuKeyDrawer = "Drawer";
public const string MenuKeyDualBadge = "DualBadge";
public const string MenuKeyEnumSelector = "EnumSelector";
public const string MenuKeyForm = "Form";
public const string MenuKeyImageViewer = "ImageViewer";
public const string MenuKeyIpBox = "IPv4Box";
public const string MenuKeyIconButton = "IconButton";
public const string MenuKeyKeyGestureInput = "KeyGestureInput";
public const string MenuKeyLoading = "Loading";
public const string MenuKeyMessageBox = "MessageBox";
public const string MenuKeyNavMenu = "NavMenu";
public const string MenuKeyNumberDisplayer = "NumberDisplayer";
public const string MenuKeyNumericUpDown = "NumericUpDown";
public const string MenuKeyPagination = "Pagination";
public const string MenuKeyRangeSlider = "RangeSlider";
public const string MenuKeyScrollToButton = "ScrollToButton";
public const string MenuKeySelectionList = "SelectionList";
public const string MenuKeyTagInput = "TagInput";
public const string MenuKeySkeleton = "Skeleton";
public const string MenuKeyTimeline = "Timeline";
public const string MenuKeyTwoTonePathIcon = "TwoTonePathIcon";
public const string MenuKeyThemeToggler = "ThemeToggler";
public const string MenuKeyToolBar = "ToolBar";
}

View File

@@ -0,0 +1,15 @@
using System.Collections.ObjectModel;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
namespace Ursa.Demo.ViewModels;
public class ScrollToButtonDemoViewModel: ObservableObject
{
public ObservableCollection<string> Items { get; set; }
public ScrollToButtonDemoViewModel()
{
Items = new ObservableCollection<string>(Enumerable.Range(0, 1000).Select(a => "Item " + a));
}
}

View File

@@ -7,7 +7,7 @@
<Setter Property="HorizontalAlignment" Value="Right" /> <Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Bottom" /> <Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="Cursor" Value="Hand"></Setter> <Setter Property="Cursor" Value="Hand"></Setter>
<Setter Property="Margin" Value="0, 0, 32, 32" /> <Setter Property="Margin" Value="0, 0, 16, 16" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate TargetType="u:ScrollToButton"> <ControlTemplate TargetType="u:ScrollToButton">
<Border <Border
@@ -35,5 +35,14 @@
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultPressedBorderBrush}" /> <Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultPressedBorderBrush}" />
<Setter Property="Background" Value="{DynamicResource ButtonDefaultPressedBackground}" /> <Setter Property="Background" Value="{DynamicResource ButtonDefaultPressedBackground}" />
</Style> </Style>
<Style Selector="^[Direction=Right] /template/ PathIcon#PART_Icon">
<Setter Property="RenderTransform" Value="rotate(90deg)"></Setter>
</Style>
<Style Selector="^[Direction=Bottom] /template/ PathIcon#PART_Icon">
<Setter Property="RenderTransform" Value="rotate(180deg)"></Setter>
</Style>
<Style Selector="^[Direction=Left] /template/ PathIcon#PART_Icon">
<Setter Property="RenderTransform" Value="rotate(270deg)"></Setter>
</Style>
</ControlTheme> </ControlTheme>
</ResourceDictionary> </ResourceDictionary>

View File

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

View File

@@ -1,6 +1,8 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.VisualTree;
using Irihi.Avalonia.Shared.Helpers; using Irihi.Avalonia.Shared.Helpers;
using Ursa.Common; using Ursa.Common;
@@ -46,10 +48,11 @@ public class ScrollToButton: Button
_disposable?.Dispose(); _disposable?.Dispose();
if (arg2.NewValue.Value is { } newValue) if (arg2.NewValue.Value is { } newValue)
{ {
var scroll = newValue.GetSelfAndLogicalDescendants().OfType<ScrollViewer>().FirstOrDefault(); var scroll = newValue.GetSelfAndVisualDescendants().OfType<ScrollViewer>().FirstOrDefault();
if (_scroll is not null) if (_scroll is not null)
{ {
_disposable?.Dispose(); _disposable?.Dispose();
_scroll = null;
} }
_scroll = scroll; _scroll = scroll;
_disposable = ScrollViewer.OffsetProperty.Changed.AddClassHandler<ScrollViewer, Vector>(OnScrollChanged); _disposable = ScrollViewer.OffsetProperty.Changed.AddClassHandler<ScrollViewer, Vector>(OnScrollChanged);
@@ -70,13 +73,14 @@ public class ScrollToButton: Button
_scroll?.SetCurrentValue(ScrollViewer.OffsetProperty, vector); _scroll?.SetCurrentValue(ScrollViewer.OffsetProperty, vector);
} }
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnLoaded(RoutedEventArgs e)
{ {
base.OnAttachedToVisualTree(e); base.OnLoaded(e);
var scroll = Target.GetSelfAndLogicalDescendants().OfType<ScrollViewer>().FirstOrDefault(); var scroll = Target.GetSelfAndVisualDescendants().OfType<ScrollViewer>().FirstOrDefault();
if (_scroll is not null) if (_scroll is not null)
{ {
_disposable?.Dispose(); _disposable?.Dispose();
_scroll = null;
} }
_scroll = scroll; _scroll = scroll;
_disposable = ScrollViewer.OffsetProperty.Changed.AddClassHandler<ScrollViewer, Vector>(OnScrollChanged); _disposable = ScrollViewer.OffsetProperty.Changed.AddClassHandler<ScrollViewer, Vector>(OnScrollChanged);
@@ -91,8 +95,8 @@ public class ScrollToButton: Button
private void SetVisibility(Position direction, Vector? vector) private void SetVisibility(Position direction, Vector? vector)
{ {
if (vector is null) return; if (vector is null || _scroll is null) return;
if (direction == Position.Bottom && vector.Value.Y < 0) if (direction == Position.Bottom && vector.Value.Y < _scroll.Extent.Height - _scroll.Bounds.Height)
{ {
IsVisible = true; IsVisible = true;
} }
@@ -100,11 +104,11 @@ public class ScrollToButton: Button
{ {
IsVisible = true; IsVisible = true;
} }
else if (direction == Position.Left && vector.Value.X < 0) else if (direction == Position.Left && vector.Value.X > 0)
{ {
IsVisible = true; IsVisible = true;
} }
else if (direction == Position.Right && vector.Value.X > 0) else if (direction == Position.Right && vector.Value.X < _scroll.Extent.Width - _scroll.Bounds.Width)
{ {
IsVisible = true; IsVisible = true;
} }