Browse Source

Added filtering and sorting to brush picker

Krzysztof Krysiński 3 weeks ago
parent
commit
775df30447

+ 1 - 1
src/PixiEditor/Models/Palettes/SortingType.cs → src/PixiEditor/Models/Palettes/PaletteSortingType.cs

@@ -1,6 +1,6 @@
 namespace PixiEditor.Models.Palettes;
 namespace PixiEditor.Models.Palettes;
 
 
-public enum SortingType
+public enum PaletteSortingType
 {
 {
     Default,
     Default,
     Alphabetical,
     Alphabetical,

+ 13 - 4
src/PixiEditor/Views/Input/BrushPicker.axaml

@@ -6,6 +6,7 @@
              xmlns:localization="clr-namespace:PixiEditor.UI.Common.Localization;assembly=PixiEditor.UI.Common"
              xmlns:localization="clr-namespace:PixiEditor.UI.Common.Localization;assembly=PixiEditor.UI.Common"
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              xmlns:controls="clr-namespace:Drawie.Interop.Avalonia.Core.Controls;assembly=Drawie.Interop.Avalonia.Core"
              xmlns:controls="clr-namespace:Drawie.Interop.Avalonia.Core.Controls;assembly=Drawie.Interop.Avalonia.Core"
+             xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              x:ClassModifier="internal"
              x:ClassModifier="internal"
              x:Class="PixiEditor.Views.Input.BrushPicker">
              x:Class="PixiEditor.Views.Input.BrushPicker">
@@ -43,7 +44,7 @@
                                 <RowDefinition Height="Auto" />
                                 <RowDefinition Height="Auto" />
                             </Grid.RowDefinitions>
                             </Grid.RowDefinitions>
 
 
-                            <TextBox Watermark="{localization:Translate Key=SEARCH}">
+                            <TextBox Watermark="{localization:Translate Key=SEARCH}" Text="{Binding $parent[input:BrushPicker].SearchText}">
                                 <TextBox.InnerLeftContent>
                                 <TextBox.InnerLeftContent>
                                     <TextBlock Classes="pixi-icon" Text="{DynamicResource icon-search}"
                                     <TextBlock Classes="pixi-icon" Text="{DynamicResource icon-search}"
                                                Margin="0, 0, 5, 0" />
                                                Margin="0, 0, 5, 0" />
@@ -63,8 +64,10 @@
                                         HorizontalAlignment="Right" Margin="0,5,5,0" Spacing="5"
                                         HorizontalAlignment="Right" Margin="0,5,5,0" Spacing="5"
                                         IsVisible="{Binding IsChecked, ElementName=SortButton}">
                                         IsVisible="{Binding IsChecked, ElementName=SortButton}">
                                 <TextBlock Text="{localization:Translate Key=SORT_BY}" />
                                 <TextBlock Text="{localization:Translate Key=SORT_BY}" />
-                                <ComboBox SelectedIndex="0">
-                                    <ComboBoxItem Content="{localization:Translate Key=ALPHABETICAL}" />
+                                <ComboBox SelectedIndex="{Binding $parent[input:BrushPicker].SelectedSortingIndex,
+                                                         Mode=TwoWay}"
+                                          ItemsSource="{Binding $parent[input:BrushPicker].SortingOptions}">
+
                                 </ComboBox>
                                 </ComboBox>
                             </StackPanel>
                             </StackPanel>
 
 
@@ -73,10 +76,16 @@
                                 <ToggleButton
                                 <ToggleButton
                                     IsVisible="{Binding IsChecked, ElementName=SortButton}"
                                     IsVisible="{Binding IsChecked, ElementName=SortButton}"
                                     Content="{DynamicResource icon-arrow-up}"
                                     Content="{DynamicResource icon-arrow-up}"
+                                    behaviours:ToggleGroupBehavior.GroupName="SORTING_DIRECTION"
+                                    behaviours:ToggleGroupBehavior.Value="ascending"
+                                    behaviours:ToggleGroupBehavior.SelectedValue="{Binding $parent[input:BrushPicker].SortingDirection, Mode=TwoWay}"
                                     Classes="pixi-icon" />
                                     Classes="pixi-icon" />
                                 <ToggleButton
                                 <ToggleButton
                                     IsVisible="{Binding IsChecked, ElementName=SortButton}"
                                     IsVisible="{Binding IsChecked, ElementName=SortButton}"
                                     Content="{DynamicResource icon-arrow-down}"
                                     Content="{DynamicResource icon-arrow-down}"
+                                    behaviours:ToggleGroupBehavior.GroupName="SORTING_DIRECTION"
+                                    behaviours:ToggleGroupBehavior.Value="descending"
+                                    behaviours:ToggleGroupBehavior.SelectedValue="{Binding $parent[input:BrushPicker].SortingDirection, Mode=TwoWay}"
                                     Classes="pixi-icon" />
                                     Classes="pixi-icon" />
                             </StackPanel>
                             </StackPanel>
                         </Grid>
                         </Grid>
@@ -84,7 +93,7 @@
                         <ScrollViewer Grid.Row="1" Margin="0,10,0,0" HorizontalScrollBarVisibility="Disabled"
                         <ScrollViewer Grid.Row="1" Margin="0,10,0,0" HorizontalScrollBarVisibility="Disabled"
                                       VerticalScrollBarVisibility="Auto">
                                       VerticalScrollBarVisibility="Auto">
                             <ItemsControl
                             <ItemsControl
-                                ItemsSource="{Binding $parent[input:BrushPicker].Brushes}">
+                                ItemsSource="{Binding $parent[input:BrushPicker].FilteredBrushes}">
                                 <ItemsControl.Styles>
                                 <ItemsControl.Styles>
                                     <Style Selector="ContentPresenter > Border">
                                     <Style Selector="ContentPresenter > Border">
                                         <Setter Property="Background" Value="Transparent" />
                                         <Setter Property="Background" Value="Transparent" />

+ 106 - 0
src/PixiEditor/Views/Input/BrushPicker.axaml.cs

@@ -5,6 +5,7 @@ using Avalonia.Markup.Xaml;
 using Avalonia.Media;
 using Avalonia.Media;
 using Avalonia.VisualTree;
 using Avalonia.VisualTree;
 using CommunityToolkit.Mvvm.Input;
 using CommunityToolkit.Mvvm.Input;
+using PixiEditor.Models.Palettes;
 using Brush = PixiEditor.Models.BrushEngine.Brush;
 using Brush = PixiEditor.Models.BrushEngine.Brush;
 
 
 namespace PixiEditor.Views.Input;
 namespace PixiEditor.Views.Input;
@@ -15,6 +16,45 @@ internal partial class BrushPicker : UserControl
         AvaloniaProperty.Register<BrushPicker, ObservableCollection<Brush>>(
         AvaloniaProperty.Register<BrushPicker, ObservableCollection<Brush>>(
             nameof(Brushes));
             nameof(Brushes));
 
 
+    public static readonly StyledProperty<ObservableCollection<Brush>> FilteredBrushesProperty =
+        AvaloniaProperty.Register<BrushPicker, ObservableCollection<Brush>>(
+            nameof(FilteredBrushes));
+
+    public static readonly StyledProperty<string> SearchTextProperty = AvaloniaProperty.Register<BrushPicker, string>(
+        nameof(SearchText));
+
+    public static readonly StyledProperty<int> SelectedSortingProperty = AvaloniaProperty.Register<BrushPicker, int>(
+        nameof(SelectedSortingIndex));
+
+    public static readonly StyledProperty<string> SortingDirectionProperty = AvaloniaProperty.Register<BrushPicker, string>(
+        nameof(SortingDirection), "ascending");
+
+    public string SortingDirection
+    {
+        get => GetValue(SortingDirectionProperty);
+        set => SetValue(SortingDirectionProperty, value);
+    }
+
+    public int SelectedSortingIndex
+    {
+        get => GetValue(SelectedSortingProperty);
+        set => SetValue(SelectedSortingProperty, value);
+    }
+
+    public BrushSorting[] SortingOptions { get; } = (BrushSorting[])System.Enum.GetValues(typeof(BrushSorting));
+
+    public string SearchText
+    {
+        get => GetValue(SearchTextProperty);
+        set => SetValue(SearchTextProperty, value);
+    }
+
+    public ObservableCollection<Brush> FilteredBrushes
+    {
+        get => GetValue(FilteredBrushesProperty);
+        set => SetValue(FilteredBrushesProperty, value);
+    }
+
     public ObservableCollection<Brush> Brushes
     public ObservableCollection<Brush> Brushes
     {
     {
         get => GetValue(BrushesProperty);
         get => GetValue(BrushesProperty);
@@ -39,6 +79,23 @@ internal partial class BrushPicker : UserControl
             {
             {
                 x.SelectedBrush = x.Brushes[0];
                 x.SelectedBrush = x.Brushes[0];
             }
             }
+
+            x.UpdateResults();
+        });
+
+        SearchTextProperty.Changed.AddClassHandler<BrushPicker>((x, e) =>
+        {
+            x.UpdateResults();
+        });
+
+        SelectedSortingProperty.Changed.AddClassHandler<BrushPicker>((x, e) =>
+        {
+            x.UpdateResults();
+        });
+
+        SortingDirectionProperty.Changed.AddClassHandler<BrushPicker>((x, e) =>
+        {
+            x.UpdateResults();
         });
         });
     }
     }
 
 
@@ -47,6 +104,49 @@ internal partial class BrushPicker : UserControl
         InitializeComponent();
         InitializeComponent();
     }
     }
 
 
+    protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+    {
+        if(SelectedSortingIndex < 0 || SelectedSortingIndex >= SortingOptions.Length)
+        {
+            SelectedSortingIndex = 0;
+        }
+    }
+
+    private void UpdateResults()
+    {
+        var filtered = new ObservableCollection<Brush>();
+        if (string.IsNullOrWhiteSpace(SearchText))
+        {
+            filtered = new ObservableCollection<Brush>(Brushes);
+        }
+        else
+        {
+            var lowerSearch = SearchText?.ToLowerInvariant();
+            foreach (var brush in Brushes)
+            {
+                if (lowerSearch == null || brush.Name.ToLowerInvariant().Contains(lowerSearch))
+                {
+                    filtered.Add(brush);
+                }
+            }
+        }
+
+        filtered = SelectedSortingIndex switch
+        {
+            (int)BrushSorting.Alphabetical => new ObservableCollection<Brush>(filtered.OrderBy(b => b.Name)),
+            _ => filtered
+        };
+
+
+        bool descending = SortingDirection == "descending";
+        if (descending)
+        {
+            filtered = new ObservableCollection<Brush>(filtered.Reverse());
+        }
+
+        FilteredBrushes = filtered;
+    }
+
     [RelayCommand]
     [RelayCommand]
     public void SelectBrush(Brush brush)
     public void SelectBrush(Brush brush)
     {
     {
@@ -55,3 +155,9 @@ internal partial class BrushPicker : UserControl
         PopupToggle.Flyout.Hide();
         PopupToggle.Flyout.Hide();
     }
     }
 }
 }
+
+public enum BrushSorting
+{
+    Default = 0,
+    Alphabetical,
+}

+ 7 - 7
src/PixiEditor/Views/Windows/PalettesBrowser.axaml.cs

@@ -157,7 +157,7 @@ internal partial class PalettesBrowser : PixiEditorPopup, IPopupWindow
 
 
     private char[] separators = new char[] { ' ', ',' };
     private char[] separators = new char[] { ' ', ',' };
 
 
-    private SortingType InternalSortingType => (SortingType)SortingIndex;
+    private PaletteSortingType InternalSortingType => (PaletteSortingType)SortingIndex;
     public ObservableRangeCollection<PaletteColor> CurrentEditingPalette { get; set; }
     public ObservableRangeCollection<PaletteColor> CurrentEditingPalette { get; set; }
     public static PalettesBrowser Instance { get; internal set; }
     public static PalettesBrowser Instance { get; internal set; }
 
 
@@ -563,13 +563,13 @@ internal partial class PalettesBrowser : PixiEditorPopup, IPopupWindow
         {
         {
             switch (InternalSortingType)
             switch (InternalSortingType)
             {
             {
-                case SortingType.Default:
+                case PaletteSortingType.Default:
                     sorted = PaletteList.Palettes.OrderByDescending(x => x.IsFavourite).ThenBy(x => PaletteList.Palettes.IndexOf(x));
                     sorted = PaletteList.Palettes.OrderByDescending(x => x.IsFavourite).ThenBy(x => PaletteList.Palettes.IndexOf(x));
                     break;
                     break;
-                case SortingType.Alphabetical:
+                case PaletteSortingType.Alphabetical:
                     sorted = PaletteList.Palettes.OrderBy(x => x.Name);
                     sorted = PaletteList.Palettes.OrderBy(x => x.Name);
                     break;
                     break;
-                case SortingType.ColorCount:
+                case PaletteSortingType.ColorCount:
                     sorted = PaletteList.Palettes.OrderBy(x => x.Colors.Count);
                     sorted = PaletteList.Palettes.OrderBy(x => x.Colors.Count);
                     break;
                     break;
             }
             }
@@ -578,13 +578,13 @@ internal partial class PalettesBrowser : PixiEditorPopup, IPopupWindow
         {
         {
             switch (InternalSortingType)
             switch (InternalSortingType)
             {
             {
-                case SortingType.Default:
+                case PaletteSortingType.Default:
                     sorted = PaletteList.Palettes.OrderByDescending(x => PaletteList.Palettes.IndexOf(x));
                     sorted = PaletteList.Palettes.OrderByDescending(x => PaletteList.Palettes.IndexOf(x));
                     break;
                     break;
-                case SortingType.Alphabetical:
+                case PaletteSortingType.Alphabetical:
                     sorted = PaletteList.Palettes.OrderByDescending(x => x.Name);
                     sorted = PaletteList.Palettes.OrderByDescending(x => x.Name);
                     break;
                     break;
-                case SortingType.ColorCount:
+                case PaletteSortingType.ColorCount:
                     sorted = PaletteList.Palettes.OrderByDescending(x => x.Colors.Count);
                     sorted = PaletteList.Palettes.OrderByDescending(x => x.Colors.Count);
                     break;
                     break;
             }
             }