diff --git a/demo/Ursa.Demo/Pages/SelectionBoxDemo.axaml b/demo/Ursa.Demo/Pages/SelectionBoxDemo.axaml index 5ef2092..18068cf 100644 --- a/demo/Ursa.Demo/Pages/SelectionBoxDemo.axaml +++ b/demo/Ursa.Demo/Pages/SelectionBoxDemo.axaml @@ -1,15 +1,55 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/Ursa.Demo/ViewModels/SelectionListDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/SelectionListDemoViewModel.cs index c69a4bc..3711edd 100644 --- a/demo/Ursa.Demo/ViewModels/SelectionListDemoViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/SelectionListDemoViewModel.cs @@ -3,9 +3,10 @@ using CommunityToolkit.Mvvm.ComponentModel; namespace Ursa.Demo.ViewModels; -public class SelectionListDemoViewModel: ObservableObject +public partial class SelectionListDemoViewModel: ObservableObject { public ObservableCollection Items { get; set; } + [ObservableProperty] private string? _selectedItem; public SelectionListDemoViewModel() { @@ -14,4 +15,9 @@ public class SelectionListDemoViewModel: ObservableObject "Ding", "Otter", "Husky", "Mr. 17", "Cass" }; } + + public void Clear() + { + SelectedItem = null; + } } \ No newline at end of file diff --git a/src/Ursa.Themes.Semi/Controls/SelectionList.axaml b/src/Ursa.Themes.Semi/Controls/SelectionList.axaml index 2123272..8306ddc 100644 --- a/src/Ursa.Themes.Semi/Controls/SelectionList.axaml +++ b/src/Ursa.Themes.Semi/Controls/SelectionList.axaml @@ -3,9 +3,19 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:u="https://irihi.tech/ursa"> - + + + + - + - + + + + FontWeight="{TemplateBinding FontWeight}" + ContentTemplate="{TemplateBinding ContentTemplate}" + Foreground="{TemplateBinding Foreground}" /> diff --git a/src/Ursa/Controls/SelectionList/SelectionList.cs b/src/Ursa/Controls/SelectionList/SelectionList.cs index e530179..240d809 100644 --- a/src/Ursa/Controls/SelectionList/SelectionList.cs +++ b/src/Ursa/Controls/SelectionList/SelectionList.cs @@ -1,6 +1,8 @@ +using System.Runtime.CompilerServices; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; +using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives; using Avalonia.Controls.Selection; using Avalonia.Controls.Templates; @@ -11,14 +13,23 @@ using Irihi.Avalonia.Shared.Helpers; namespace Ursa.Controls; -[TemplatePart(PART_Indicator, typeof(Control))] +[TemplatePart(PART_Indicator, typeof(ContentPresenter))] public class SelectionList: SelectingItemsControl { public const string PART_Indicator = "PART_Indicator"; private static readonly FuncTemplate DefaultPanel = new(() => new StackPanel()); - private Control? _indicator; private ImplicitAnimationCollection? _implicitAnimations; + private ContentPresenter? _indicator; + + public static readonly StyledProperty IndicatorProperty = AvaloniaProperty.Register( + nameof(Indicator)); + + public Control? Indicator + { + get => GetValue(IndicatorProperty); + set => SetValue(IndicatorProperty, value); + } static SelectionList() { @@ -75,25 +86,23 @@ public class SelectionList: SelectingItemsControl protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); - _indicator = e.NameScope.Find(PART_Indicator); - _indicator?.Arrange(new Rect()); + _indicator= e.NameScope.Find(PART_Indicator); + EnsureIndicatorAnimation(); + } + + private void EnsureIndicatorAnimation() + { if (_indicator is not null) { _indicator.Opacity = 0; SetUpAnimation(); if (ElementComposition.GetElementVisual(_indicator) is { } v) { - v.ImplicitAnimations = _implicitAnimations; + v.ImplicitAnimations = _implicitAnimations; } - _indicator.SizeChanged += OnIndicatorSizeChanged; } } - private void OnIndicatorSizeChanged(object sender, SizeChangedEventArgs e) - { - - } - internal void SelectByIndex(int index) { using var operation = Selection.BatchUpdate(); @@ -103,13 +112,16 @@ public class SelectionList: SelectingItemsControl private void SetUpAnimation() { + if (_implicitAnimations != null) return; + var compositorVisual = ElementComposition.GetElementVisual(this); + if (compositorVisual is null) return; var compositor = ElementComposition.GetElementVisual(this)!.Compositor; var offsetAnimation = compositor.CreateVector3KeyFrameAnimation(); - offsetAnimation.Target = "Offset"; + offsetAnimation.Target = nameof(CompositionVisual.Offset); offsetAnimation.InsertExpressionKeyFrame(1.0f, "this.FinalValue"); offsetAnimation.Duration = TimeSpan.FromSeconds(0.3); var sizeAnimation = compositor.CreateVector2KeyFrameAnimation(); - sizeAnimation.Target = "Size"; + sizeAnimation.Target = nameof(CompositionVisual.Size); sizeAnimation.InsertExpressionKeyFrame(1.0f, "this.FinalValue"); sizeAnimation.Duration = TimeSpan.FromSeconds(0.3); var opacityAnimation = compositor.CreateScalarKeyFrameAnimation(); @@ -118,9 +130,19 @@ public class SelectionList: SelectingItemsControl opacityAnimation.Duration = TimeSpan.FromSeconds(0.3); _implicitAnimations = compositor.CreateImplicitAnimationCollection(); - _implicitAnimations["Offset"] = offsetAnimation; - _implicitAnimations["Size"] = sizeAnimation; - _implicitAnimations["Opacity"] = opacityAnimation; + _implicitAnimations[nameof(CompositionVisual.Offset)] = offsetAnimation; + _implicitAnimations[nameof(CompositionVisual.Size)] = sizeAnimation; + _implicitAnimations[nameof(CompositionVisual.Opacity)] = opacityAnimation; } -} \ No newline at end of file + protected override void OnKeyDown(KeyEventArgs e) + { + var hotkeys = Application.Current!.PlatformSettings?.HotkeyConfiguration; + + if (e.Key.ToNavigationDirection() is { } direction && direction.IsDirectional()) + { + e.Handled |= MoveSelection(direction, WrapSelection); + } + base.OnKeyDown(e); + } +}