Browse Source

Filtering and sorting changes

Krzysztof Krysiński 3 years ago
parent
commit
abf198568e

+ 20 - 2
PixiEditor/Helpers/Behaviours/TextBoxFocusBehavior.cs

@@ -1,4 +1,5 @@
-using System.Windows;
+using System.Linq;
+using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Input;
 using System.Windows.Interactivity;
 using System.Windows.Interactivity;
@@ -45,6 +46,15 @@ namespace PixiEditor.Helpers.Behaviours
             set => SetValue(DeselectOnFocusLossProperty, value);
             set => SetValue(DeselectOnFocusLossProperty, value);
         }
         }
 
 
+        public static readonly DependencyProperty FocusNextProperty = DependencyProperty.Register(
+            "FocusNext", typeof(bool), typeof(TextBoxFocusBehavior), new PropertyMetadata(false));
+
+        public bool FocusNext
+        {
+            get { return (bool)GetValue(FocusNextProperty); }
+            set { SetValue(FocusNextProperty, value); }
+        }
+
         protected override void OnAttached()
         protected override void OnAttached()
         {
         {
             base.OnAttached();
             base.OnAttached();
@@ -76,7 +86,15 @@ namespace PixiEditor.Helpers.Behaviours
 
 
         private void RemoveFocus()
         private void RemoveFocus()
         {
         {
-            MainWindow.Current.mainGrid.Focus();
+            if (!FocusNext)
+            {
+                MainWindow.Current.mainGrid.Focus();
+            }
+            else
+            {
+                AssociatedObject.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
+            }
+
         }
         }
 
 
         private void AssociatedObjectGotKeyboardFocus(
         private void AssociatedObjectGotKeyboardFocus(

BIN
PixiEditor/Images/ChevronsDown.png


+ 49 - 0
PixiEditor/Models/DataHolders/Palettes/FilteringSettings.cs

@@ -0,0 +1,49 @@
+using PixiEditor.Models.Enums;
+using System;
+using System.Linq;
+
+namespace PixiEditor.Models.DataHolders.Palettes
+{
+    public class FilteringSettings
+    {
+        public ColorsNumberMode ColorsNumberMode { get; set; }
+        public int ColorsCount { get; set; }
+        public string[] Tags { get; set; }
+
+        public FilteringSettings(ColorsNumberMode colorsNumberMode, int colorsCount, string[] tags)
+        {
+            ColorsNumberMode = colorsNumberMode;
+            ColorsCount = colorsCount;
+            Tags = tags;
+        }
+
+        public bool Filter(Palette palette)
+        {
+            bool result = true;
+
+            switch (ColorsNumberMode)
+            {
+                case ColorsNumberMode.Any:
+                    break;
+                case ColorsNumberMode.Max:
+                    result = palette.Colors.Count <= ColorsCount;
+                    break;
+                case ColorsNumberMode.Min:
+                    result = palette.Colors.Count >= ColorsCount;
+                    break;
+                case ColorsNumberMode.Exact:
+                    result = palette.Colors.Count == ColorsCount;
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException();
+            }
+
+            if (Tags.Length > 0)
+            {
+                result = Tags.All(tag => palette.Tags.Contains(tag));
+            }
+
+            return result;
+        }
+    }
+}

+ 9 - 0
PixiEditor/Models/DataHolders/Palettes/SortingType.cs

@@ -0,0 +1,9 @@
+namespace PixiEditor.Models.DataHolders.Palettes
+{
+    public enum SortingType
+    {
+        Default,
+        Alphabetical,
+        ColorCount
+    }
+}

+ 28 - 9
PixiEditor/Models/DataProviders/LocalPalettesFetcher.cs

@@ -17,31 +17,50 @@ namespace PixiEditor.Models.DataProviders
             Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
             Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
             "PixiEditor", "Palettes");
             "PixiEditor", "Palettes");
 
 
-        public override async Task<PaletteList> FetchPaletteList(int startIndex, int count)
+        private List<Palette> _cachedPalettes;
+
+        public override async Task<PaletteList> FetchPaletteList(int startIndex, int count, FilteringSettings filtering)
         {
         {
             string[] files = DirectoryExtensions.GetFiles(PathToPalettesFolder, string.Join("|", AvailableParsers.SelectMany(x => x.SupportedFileExtensions)), SearchOption.TopDirectoryOnly);
             string[] files = DirectoryExtensions.GetFiles(PathToPalettesFolder, string.Join("|", AvailableParsers.SelectMany(x => x.SupportedFileExtensions)), SearchOption.TopDirectoryOnly);
 
 
+            if(_cachedPalettes == null)
+            {
+                _cachedPalettes = await ParseAll(files);
+            }
+
             PaletteList result = new PaletteList
             PaletteList result = new PaletteList
             {
             {
                 Palettes = new WpfObservableRangeCollection<Palette>()
                 Palettes = new WpfObservableRangeCollection<Palette>()
             };
             };
 
 
-            if (startIndex >= files.Length) return result;
+            var filteredPalettes = _cachedPalettes.Where(filtering.Filter).ToArray();
+
+            if (startIndex >= filteredPalettes.Length) return result;
 
 
             for (int i = 0; i < count; i++)
             for (int i = 0; i < count; i++)
             {
             {
-                if (startIndex + i >= files.Length) break;
-                string filePath = files[i + startIndex];
-                string extension = Path.GetExtension(filePath);
+                if (startIndex + i >= filteredPalettes.Length) break;
+                Palette palette = filteredPalettes[startIndex + i];
+                result.Palettes.Add(palette);
+            }
+
+            result.FetchedCorrectly = true;
+            return result;
+        }
+
+        private async Task<List<Palette>> ParseAll(string[] files)
+        {
+            List<Palette> result = new List<Palette>();
+            foreach (var file in files)
+            {
+                string extension = Path.GetExtension(file);
                 var foundParser = AvailableParsers.First(x => x.SupportedFileExtensions.Contains(extension));
                 var foundParser = AvailableParsers.First(x => x.SupportedFileExtensions.Contains(extension));
-                if (foundParser != null)
                 {
                 {
-                    PaletteFileData fileData = await foundParser.Parse(filePath);
-                    result.Palettes.Add(new Palette(fileData.Title, new List<string>(fileData.GetHexColors()), fileData.Tags));
+                    PaletteFileData fileData = await foundParser.Parse(file);
+                    result.Add(new Palette(fileData.Title, new List<string>(fileData.GetHexColors()), fileData.Tags));
                 }
                 }
             }
             }
 
 
-            result.FetchedCorrectly = true;
             return result;
             return result;
         }
         }
 
 

+ 1 - 1
PixiEditor/Models/DataProviders/PaletteListDataSource.cs

@@ -8,7 +8,7 @@ namespace PixiEditor.Models.DataProviders
     public abstract class PaletteListDataSource
     public abstract class PaletteListDataSource
     {
     {
         public virtual void Initialize() { }
         public virtual void Initialize() { }
-        public abstract Task<PaletteList> FetchPaletteList(int startIndex, int items);
+        public abstract Task<PaletteList> FetchPaletteList(int startIndex, int items, FilteringSettings filtering);
         public List<PaletteFileParser> AvailableParsers { get; set; }
         public List<PaletteFileParser> AvailableParsers { get; set; }
 
 
     }
     }

+ 2 - 0
PixiEditor/PixiEditor.csproj

@@ -136,6 +136,7 @@
 		<None Remove="Images\AnchorDot.png" />
 		<None Remove="Images\AnchorDot.png" />
 		<None Remove="Images\CheckerTile.png" />
 		<None Remove="Images\CheckerTile.png" />
 		<None Remove="Images\ChevronDown.png" />
 		<None Remove="Images\ChevronDown.png" />
+		<None Remove="Images\ChevronsDown.png" />
 		<None Remove="Images\DiagonalRed.png" />
 		<None Remove="Images\DiagonalRed.png" />
 		<None Remove="Images\Download.png" />
 		<None Remove="Images\Download.png" />
 		<None Remove="Images\Eye-off.png" />
 		<None Remove="Images\Eye-off.png" />
@@ -214,6 +215,7 @@
 		<Resource Include="Images\AnchorDot.png" />
 		<Resource Include="Images\AnchorDot.png" />
 		<Resource Include="Images\CheckerTile.png" />
 		<Resource Include="Images\CheckerTile.png" />
 		<Resource Include="Images\ChevronDown.png" />
 		<Resource Include="Images\ChevronDown.png" />
+		<Resource Include="Images\ChevronsDown.png" />
 		<Resource Include="Images\DiagonalRed.png" />
 		<Resource Include="Images\DiagonalRed.png" />
 		<Resource Include="Images\Download.png" />
 		<Resource Include="Images\Download.png" />
 		<Resource Include="Images\Eye-off.png" />
 		<Resource Include="Images\Eye-off.png" />

+ 35 - 9
PixiEditor/Views/Dialogs/PalettesBrowser.xaml

@@ -6,8 +6,9 @@
              xmlns:local="clr-namespace:PixiEditor.Views.UserControls.Palettes" xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              xmlns:local="clr-namespace:PixiEditor.Views.UserControls.Palettes" xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              mc:Ignorable="d" 
              mc:Ignorable="d" 
              xmlns:gif="http://wpfanimatedgif.codeplex.com" xmlns:usercontrols="clr-namespace:PixiEditor.Views.UserControls" xmlns:views="clr-namespace:PixiEditor.Views"
              xmlns:gif="http://wpfanimatedgif.codeplex.com" xmlns:usercontrols="clr-namespace:PixiEditor.Views.UserControls" xmlns:views="clr-namespace:PixiEditor.Views"
-        Title="Palettes Browser" WindowStartupLocation="CenterScreen" MinWidth="200" Height="600" Width="800" WindowStyle="None"
-             Name="lospecPalettesBrowser">
+             xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours"
+             Title="Palettes Browser" WindowStartupLocation="CenterScreen" MinWidth="200" Height="600" Width="800" WindowStyle="None"
+             Name="palettesBrowser">
     <Window.Resources>
     <Window.Resources>
         <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
         <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
     </Window.Resources>
     </Window.Resources>
@@ -40,8 +41,32 @@
                 <ComboBox Name="sortingComboBox" FontSize="16" VerticalAlignment="Center" SelectionChanged="SortingComboBox_SelectionChanged">
                 <ComboBox Name="sortingComboBox" FontSize="16" VerticalAlignment="Center" SelectionChanged="SortingComboBox_SelectionChanged">
                     <ComboBoxItem IsSelected="True">Default</ComboBoxItem>
                     <ComboBoxItem IsSelected="True">Default</ComboBoxItem>
                     <ComboBoxItem>Alphabetical</ComboBoxItem>
                     <ComboBoxItem>Alphabetical</ComboBoxItem>
-                    <ComboBoxItem>Newest</ComboBoxItem>
+                    <ComboBoxItem>Color Count</ComboBoxItem>
                 </ComboBox>
                 </ComboBox>
+                <ToggleButton Margin="10 0 0 0" Name="toggleBtn"
+                              IsChecked="{Binding ElementName=palettesBrowser, Path=SortAscending}"
+                              Focusable="False"
+                              Style="{StaticResource PixiEditorDockThemeToolButtonStyle}">
+                    <Image Width="24" Height="24" Source="/Images/ChevronsDown.png">
+                        <Image.Style>
+                            <Style TargetType="{x:Type Image}">
+                                <Style.Triggers>
+                                    <DataTrigger Binding="{Binding ElementName=toggleBtn, Path=IsChecked}" Value="true">
+                                        <Setter Property="RenderTransform">
+                                            <Setter.Value>
+                                                <RotateTransform Angle="180" CenterX="11.5" CenterY="11.5"/>
+                                            </Setter.Value>
+                                        </Setter>
+                                        <Setter Property="ToolTip" Value="Ascending"/>
+                                    </DataTrigger>
+                                    <DataTrigger Binding="{Binding ElementName=toggleBtn, Path=IsChecked}" Value="false">
+                                        <Setter Property="ToolTip" Value="Descending"/>
+                                    </DataTrigger>
+                                </Style.Triggers>
+                            </Style>
+                        </Image.Style>
+                    </Image>
+                </ToggleButton>
                 <Label Margin="10 0 0 0" Content="Tags:" Style="{StaticResource BaseLabel}" VerticalAlignment="Center" FontSize="16"/>
                 <Label Margin="10 0 0 0" Content="Tags:" Style="{StaticResource BaseLabel}" VerticalAlignment="Center" FontSize="16"/>
                 <usercontrols:InputBox OnSubmit="TagsInput_OnSubmit" FontSize="16" VerticalAlignment="Center" 
                 <usercontrols:InputBox OnSubmit="TagsInput_OnSubmit" FontSize="16" VerticalAlignment="Center" 
                                        Style="{StaticResource DarkTextBoxStyle}" Width="250" />
                                        Style="{StaticResource DarkTextBoxStyle}" Width="250" />
@@ -52,8 +77,9 @@
                     <ComboBoxItem>Min</ComboBoxItem>
                     <ComboBoxItem>Min</ComboBoxItem>
                     <ComboBoxItem>Exact</ComboBoxItem>
                     <ComboBoxItem>Exact</ComboBoxItem>
                 </ComboBox>
                 </ComboBox>
-                <views:NumberInput Width="50" FontSize="16" VerticalAlignment="Center" Margin="10 0 0 0" 
-                                   Value="{Binding ElementName=lospecPalettesBrowser, Path=ColorsNumber, Mode=TwoWay}"/>
+                <views:NumberInput Width="50" FontSize="16" VerticalAlignment="Center" Margin="10 0 0 0"
+                                   FocusNext="True"
+                                   Value="{Binding ElementName=palettesBrowser, Path=ColorsNumber, Mode=TwoWay}"/>
             </StackPanel>
             </StackPanel>
         </StackPanel>
         </StackPanel>
         <Grid Grid.Row="2" Margin="10">
         <Grid Grid.Row="2" Margin="10">
@@ -61,19 +87,19 @@
                        VerticalAlignment="Center" Visibility="{Binding ElementName=itemsControl, 
                        VerticalAlignment="Center" Visibility="{Binding ElementName=itemsControl, 
                 Path=Visibility, Converter={converters:OppositeVisibilityConverter}}"/>
                 Path=Visibility, Converter={converters:OppositeVisibilityConverter}}"/>
             <ScrollViewer Name="scrollViewer" Margin="5" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" ScrollChanged="ScrollViewer_ScrollChanged">
             <ScrollViewer Name="scrollViewer" Margin="5" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" ScrollChanged="ScrollViewer_ScrollChanged">
-                <ItemsControl Name="itemsControl" ItemsSource="{Binding ElementName=lospecPalettesBrowser, Path=FilteredPalettes}" 
-                          Visibility="{Binding ElementName=lospecPalettesBrowser, Path=PaletteList.FetchedCorrectly,
+                <ItemsControl Name="itemsControl" ItemsSource="{Binding ElementName=palettesBrowser, Path=SortedResults}"
+                          Visibility="{Binding ElementName=palettesBrowser, Path=PaletteList.FetchedCorrectly,
                 Converter={StaticResource BoolToVisibilityConverter}}">
                 Converter={StaticResource BoolToVisibilityConverter}}">
                     <ItemsControl.ItemTemplate>
                     <ItemsControl.ItemTemplate>
                         <DataTemplate>
                         <DataTemplate>
                             <local:PaletteItem Palette="{Binding}" 
                             <local:PaletteItem Palette="{Binding}" 
-                                               ImportPaletteCommand="{Binding ImportPaletteCommand, ElementName=lospecPalettesBrowser}"/>
+                                               ImportPaletteCommand="{Binding ImportPaletteCommand, ElementName=palettesBrowser}"/>
                         </DataTemplate>
                         </DataTemplate>
                     </ItemsControl.ItemTemplate>
                     </ItemsControl.ItemTemplate>
                 </ItemsControl>
                 </ItemsControl>
             </ScrollViewer>
             </ScrollViewer>
             <Image gif:ImageBehavior.AnimatedSource="/Images/Processing.gif" HorizontalAlignment="Center" VerticalAlignment="Center"
             <Image gif:ImageBehavior.AnimatedSource="/Images/Processing.gif" HorizontalAlignment="Center" VerticalAlignment="Center"
-                   Visibility="{Binding ElementName=lospecPalettesBrowser, Path=IsFetching, Converter={StaticResource BoolToVisibilityConverter}}"
+                   Visibility="{Binding ElementName=palettesBrowser, Path=IsFetching, Converter={StaticResource BoolToVisibilityConverter}}"
                    Height="50" gif:ImageBehavior.AnimationSpeedRatio="1.5"/>
                    Height="50" gif:ImageBehavior.AnimationSpeedRatio="1.5"/>
         </Grid>
         </Grid>
     </Grid>
     </Grid>

+ 111 - 68
PixiEditor/Views/Dialogs/PalettesBrowser.xaml.cs

@@ -72,26 +72,41 @@ namespace PixiEditor.Views.Dialogs
         // Using a DependencyProperty as the backing store for PaletteListDataSources.  This enables animation, styling, binding, etc...
         // Using a DependencyProperty as the backing store for PaletteListDataSources.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty PaletteListDataSourcesProperty =
         public static readonly DependencyProperty PaletteListDataSourcesProperty =
             DependencyProperty.Register("PaletteListDataSources", typeof(WpfObservableRangeCollection<PaletteListDataSource>), typeof(PalettesBrowser), new PropertyMetadata(new WpfObservableRangeCollection<PaletteListDataSource>()));
             DependencyProperty.Register("PaletteListDataSources", typeof(WpfObservableRangeCollection<PaletteListDataSource>), typeof(PalettesBrowser), new PropertyMetadata(new WpfObservableRangeCollection<PaletteListDataSource>()));
-
-        public WpfObservableRangeCollection<Palette> FilteredPalettes
+        public bool SortAscending
         {
         {
-            get { return (WpfObservableRangeCollection<Palette>)GetValue(FilteredPalettesProperty); }
-            set { SetValue(FilteredPalettesProperty, value); }
+            get { return (bool)GetValue(SortAscendingProperty); }
+            set { SetValue(SortAscendingProperty, value); }
         }
         }
 
 
-        // Using a DependencyProperty as the backing store for FilteredPalettes.  This enables animation, styling, binding, etc...
-        public static readonly DependencyProperty FilteredPalettesProperty =
-            DependencyProperty.Register("FilteredPalettes", typeof(WpfObservableRangeCollection<Palette>), typeof(PalettesBrowser));
-
+        // Using a DependencyProperty as the backing store for SortDescending.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty SortAscendingProperty =
+            DependencyProperty.Register("SortAscending", typeof(bool), typeof(PalettesBrowser), new PropertyMetadata(true, OnSortAscendingChanged));
 
 
 
 
+        public static readonly DependencyProperty SortedResultsProperty = DependencyProperty.Register(
+            "SortedResults", typeof(WpfObservableRangeCollection<Palette>), typeof(PalettesBrowser), new PropertyMetadata(default(WpfObservableRangeCollection<Palette>)));
 
 
+        public WpfObservableRangeCollection<Palette> SortedResults
+        {
+            get { return (WpfObservableRangeCollection<Palette>)GetValue(SortedResultsProperty); }
+            set { SetValue(SortedResultsProperty, value); }
+        }
         public string SortingType { get; set; } = "Default";
         public string SortingType { get; set; } = "Default";
         public ColorsNumberMode ColorsNumberMode { get; set; } = ColorsNumberMode.Any;
         public ColorsNumberMode ColorsNumberMode { get; set; } = ColorsNumberMode.Any;
         public string[] Tags { get; set; } = Array.Empty<string>();
         public string[] Tags { get; set; } = Array.Empty<string>();
 
 
+        private FilteringSettings _filteringSettings;
+
+        public FilteringSettings Filtering
+        {
+            get => _filteringSettings ??= new FilteringSettings(ColorsNumberMode, ColorsNumber, Tags);
+            set => _filteringSettings = value;
+        }
+
         private char[] _separators = new char[] { ' ', ',' };
         private char[] _separators = new char[] { ' ', ',' };
 
 
+        private SortingType _sortingType => (SortingType)Enum.Parse(typeof(SortingType), SortingType.Replace(" ", ""));
+
         public PalettesBrowser()
         public PalettesBrowser()
         {
         {
             InitializeComponent();
             InitializeComponent();
@@ -107,121 +122,102 @@ namespace PixiEditor.Views.Dialogs
             SystemCommands.CloseWindow(this);
             SystemCommands.CloseWindow(this);
         }
         }
 
 
-        private static void ColorsNumberChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        private static async void ColorsNumberChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        {
+            PalettesBrowser browser = (PalettesBrowser)d;
+            browser.Filtering.ColorsCount = (int)e.NewValue;
+            await browser.UpdatePaletteList();
+        }
+
+        private static void OnSortAscendingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
         {
         {
             PalettesBrowser browser = (PalettesBrowser)d;
             PalettesBrowser browser = (PalettesBrowser)d;
-            browser.FilterPalettes();
+            browser.Sort();
         }
         }
 
 
 
 
-        public async Task UpdatePaletteList(bool refetch = false)
+        public async Task UpdatePaletteList()
         {
         {
             IsFetching = true;
             IsFetching = true;
-            if (PaletteList == null || refetch)
+            if(PaletteList?.Palettes != null)
+            {
+                PaletteList.Palettes.Clear();
+            }
+
+            for (int i = 0; i < PaletteListDataSources.Count; i++)
             {
             {
-                for (int i = 0; i < PaletteListDataSources.Count; i++)
+                PaletteList src = await FetchPaletteList(i, Filtering);
+                if (!src.FetchedCorrectly) continue;
+                if (PaletteList == null)
                 {
                 {
-                    PaletteList src = await FetchPaletteList(i);
-                    if (!src.FetchedCorrectly) continue;
-                    if (PaletteList == null)
-                    {
-                        PaletteList = src;
-                    }
-                    else
-                    {
-                        PaletteList.Palettes.AddRange(src.Palettes);
-                    }
+                    PaletteList = src;
                 }
                 }
-
-                if (FilteredPalettes == null)
+                else
                 {
                 {
-                    FilteredPalettes = new WpfObservableRangeCollection<Palette>(PaletteList.Palettes);
+                    PaletteList.Palettes?.AddRange(src.Palettes);
                 }
                 }
-
-                FilterPalettes();
-                OnListFetched.Invoke(PaletteList);
             }
             }
 
 
+            Sort();
+            OnListFetched?.Invoke(PaletteList);
+
             IsFetching = false;
             IsFetching = false;
         }
         }
 
 
-        private async Task<PaletteList> FetchPaletteList(int index)
+        private async Task<PaletteList> FetchPaletteList(int index, FilteringSettings filtering)
         {
         {
             int startIndex = PaletteList != null ? PaletteList.Palettes.Count : 0;
             int startIndex = PaletteList != null ? PaletteList.Palettes.Count : 0;
-            var src = await PaletteListDataSources[index].FetchPaletteList(startIndex, ItemsPerLoad);
+            var src = await PaletteListDataSources[index].FetchPaletteList(startIndex, ItemsPerLoad, filtering);
             return src;
             return src;
         }
         }
 
 
         private async void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
         private async void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
         {
         {
-            if (PaletteList == null || PaletteList.Palettes == null) return;
+            if (PaletteList?.Palettes == null) return;
             var scrollViewer = (ScrollViewer)sender;
             var scrollViewer = (ScrollViewer)sender;
             if (scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight)
             if (scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight)
             {
             {
                 IsFetching = true;
                 IsFetching = true;
-                var newPalettes = await FetchPaletteList(0);
-                if (newPalettes == null || !newPalettes.FetchedCorrectly || newPalettes.Palettes == null)
+                var newPalettes = await FetchPaletteList(0, Filtering);
+                if (newPalettes is not { FetchedCorrectly: true } || newPalettes.Palettes == null)
                 {
                 {
                     IsFetching = false;
                     IsFetching = false;
                     return;
                     return;
                 }
                 }
 
 
                 PaletteList.Palettes.AddRange(newPalettes.Palettes);
                 PaletteList.Palettes.AddRange(newPalettes.Palettes);
-                FilterPalettes();
-                OnListFetched.Invoke(PaletteList);
+                Sort();
+                OnListFetched?.Invoke(PaletteList);
                 IsFetching = false;
                 IsFetching = false;
             }
             }
         }
         }
 
 
         private void SortingComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
         private void SortingComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
         {
         {
-            if (e.AddedItems != null && e.AddedItems.Count > 0 && e.AddedItems[0] is ComboBoxItem item && item.Content is string value)
+            if (e.AddedItems is { Count: > 0 } && e.AddedItems[0] is ComboBoxItem { Content: string value })
             {
             {
                 SortingType = value;
                 SortingType = value;
-                FilterPalettes();
+                Sort();
                 scrollViewer.ScrollToHome();
                 scrollViewer.ScrollToHome();
             }
             }
         }
         }
 
 
-        private void FilterPalettes()
-        {
-            FilteredPalettes.Clear();
-            switch (ColorsNumberMode)
-            {
-                case ColorsNumberMode.Any:
-                    FilteredPalettes.AddRange(PaletteList.Palettes);
-                    break;
-                case ColorsNumberMode.Max:
-                    FilteredPalettes.AddRange(PaletteList.Palettes.Where(x => x.Colors.Count <= ColorsNumber));
-                    break;
-                case ColorsNumberMode.Min:
-                    FilteredPalettes.AddRange(PaletteList.Palettes.Where(x => x.Colors.Count >= ColorsNumber));
-                    break;
-                case ColorsNumberMode.Exact:
-                    FilteredPalettes.AddRange(PaletteList.Palettes.Where(x => x.Colors.Count == ColorsNumber));
-                    break;
-                default:
-                    break;
-            }
-
-            
-            FilteredPalettes.OrderBy()
-        }
-
-        private void TagsInput_OnSubmit(object sender, InputBoxEventArgs e)
+        private async void TagsInput_OnSubmit(object sender, InputBoxEventArgs e)
         {
         {
             Tags = e.Input.Split(_separators, options: StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
             Tags = e.Input.Split(_separators, options: StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
-            FilterPalettes();
+            Filtering.Tags = Tags;
+            await UpdatePaletteList();
             scrollViewer.ScrollToHome();
             scrollViewer.ScrollToHome();
         }
         }
 
 
 
 
-        private void ColorsComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        private async void ColorsComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
         {
         {
-            if (e.AddedItems != null && e.AddedItems.Count > 0 && e.AddedItems[0] is ComboBoxItem item && item.Content is string value)
+            if (e.AddedItems is { Count: > 0 } && e.AddedItems[0] is ComboBoxItem item && item.Content is string value)
             {
             {
                 ColorsNumberMode = Enum.Parse<ColorsNumberMode>(value);
                 ColorsNumberMode = Enum.Parse<ColorsNumberMode>(value);
-                FilterPalettes();
+                Filtering.ColorsNumberMode = ColorsNumberMode;
+                await UpdatePaletteList();
                 scrollViewer.ScrollToHome();
                 scrollViewer.ScrollToHome();
             }
             }
         }
         }
@@ -230,5 +226,52 @@ namespace PixiEditor.Views.Dialogs
         {
         {
             ((Grid)sender).Focus();
             ((Grid)sender).Focus();
         }
         }
+
+        private void Sort()
+        {
+            Sort(!SortAscending);
+        }
+
+        private void Sort(bool descending)
+        {
+            if(PaletteList?.Palettes == null) return;
+
+            IOrderedEnumerable<Palette> sorted = null;
+            if (!descending)
+            {
+                switch (_sortingType)
+                {
+                    case Models.DataHolders.Palettes.SortingType.Default:
+                        sorted = PaletteList.Palettes.OrderBy(x => PaletteList.Palettes.IndexOf(x));
+                        break;
+                    case Models.DataHolders.Palettes.SortingType.Alphabetical:
+                        sorted = PaletteList.Palettes.OrderBy(x => x.Title);
+                        break;
+                    case Models.DataHolders.Palettes.SortingType.ColorCount:
+                        sorted = PaletteList.Palettes.OrderBy(x => x.Colors.Count);
+                        break;
+                }
+            }
+            else
+            {
+                switch (_sortingType)
+                {
+                    case Models.DataHolders.Palettes.SortingType.Default:
+                        sorted = PaletteList.Palettes.OrderByDescending(x => PaletteList.Palettes.IndexOf(x));
+                        break;
+                    case Models.DataHolders.Palettes.SortingType.Alphabetical:
+                        sorted = PaletteList.Palettes.OrderByDescending(x => x.Title);
+                        break;
+                    case Models.DataHolders.Palettes.SortingType.ColorCount:
+                        sorted = PaletteList.Palettes.OrderByDescending(x => x.Colors.Count);
+                        break;
+                }
+            }
+
+            if(sorted != null)
+            {
+                SortedResults = new WpfObservableRangeCollection<Palette>(sorted);
+            }
+        }
     }
     }
 }
 }

+ 2 - 1
PixiEditor/Views/UserControls/NumberInput.xaml

@@ -11,7 +11,8 @@
              InputScope="Number" MouseWheel="TextBox_MouseWheel"
              InputScope="Number" MouseWheel="TextBox_MouseWheel"
              PreviewTextInput="TextBox_PreviewTextInput" Text="{Binding ElementName=numberInput, Path=Value}" Padding="0" VerticalContentAlignment="Center">
              PreviewTextInput="TextBox_PreviewTextInput" Text="{Binding ElementName=numberInput, Path=Value}" Padding="0" VerticalContentAlignment="Center">
         <i:Interaction.Behaviors>
         <i:Interaction.Behaviors>
-            <behaviours:TextBoxFocusBehavior SelectOnMouseClick="True" ConfirmOnEnter="True"/>
+            <behaviours:TextBoxFocusBehavior SelectOnMouseClick="True" ConfirmOnEnter="True"
+                                             FocusNext="{Binding ElementName=numberInput, Path=FocusNext}"/>
             <behaviours:GlobalShortcutFocusBehavior/>
             <behaviours:GlobalShortcutFocusBehavior/>
         </i:Interaction.Behaviors>
         </i:Interaction.Behaviors>
     </TextBox>
     </TextBox>

+ 9 - 1
PixiEditor/Views/UserControls/NumberInput.xaml.cs

@@ -61,7 +61,6 @@ namespace PixiEditor.Views
             DependencyProperty.Register("OnScrollAction", typeof(Action), typeof(NumberInput), new PropertyMetadata(null));
             DependencyProperty.Register("OnScrollAction", typeof(Action), typeof(NumberInput), new PropertyMetadata(null));
 
 
 
 
-
         public NumberInput()
         public NumberInput()
         {
         {
             InitializeComponent();
             InitializeComponent();
@@ -85,6 +84,15 @@ namespace PixiEditor.Views
             set => SetValue(MaxProperty, value);
             set => SetValue(MaxProperty, value);
         }
         }
 
 
+        public static readonly DependencyProperty FocusNextProperty = DependencyProperty.Register(
+            "FocusNext", typeof(bool), typeof(NumberInput), new PropertyMetadata(false));
+
+        public bool FocusNext
+        {
+            get { return (bool)GetValue(FocusNextProperty); }
+            set { SetValue(FocusNextProperty, value); }
+        }
+
         private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
         private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
         {
         {
             NumberInput input = (NumberInput)d;
             NumberInput input = (NumberInput)d;

+ 1 - 1
PixiEditor/Views/UserControls/Palettes/PaletteViewer.xaml

@@ -22,7 +22,7 @@
                 <Button Margin="0, 0, 5, 0" Style="{StaticResource ToolButtonStyle}" Click="BrowsePalettes_Click"
                 <Button Margin="0, 0, 5, 0" Style="{StaticResource ToolButtonStyle}" Click="BrowsePalettes_Click"
                 Cursor="Hand" Height="24" Width="24" ToolTip="Browse Palettes">
                 Cursor="Hand" Height="24" Width="24" ToolTip="Browse Palettes">
                         <Button.Background>
                         <Button.Background>
-                            <ImageBrush ImageSource="/Images/Globe.png"/>
+                            <ImageBrush ImageSource="/Images/Folder.png"/>
                         </Button.Background>
                         </Button.Background>
                     </Button>
                     </Button>
                     <Button Margin="0, 0, 5, 0" Style="{StaticResource ToolButtonStyle}" 
                     <Button Margin="0, 0, 5, 0" Style="{StaticResource ToolButtonStyle}"