浏览代码

Palettes rework wip

Krzysztof Krysiński 2 年之前
父节点
当前提交
aec78ef157
共有 53 个文件被更改,包括 375 次插入181 次删除
  1. 1 0
      src/PixiEditor.Extensions/Palettes/ExtensionPalette.cs
  2. 2 1
      src/PixiEditor.Extensions/Palettes/IPalette.cs
  3. 34 0
      src/PixiEditor.Extensions/Palettes/PaletteColor.cs
  4. 20 0
      src/PixiEditor.Extensions/Palettes/PaletteListDataSource.cs
  5. 9 10
      src/PixiEditor.Extensions/Palettes/Parsers/PaletteFileData.cs
  6. 3 2
      src/PixiEditor.Extensions/Palettes/Parsers/PaletteFileParser.cs
  7. 11 1
      src/PixiEditor/Helpers/Converters/BackendColorToMediaColorConverter.cs
  8. 7 6
      src/PixiEditor/Helpers/DocumentViewModelBuilder.cs
  9. 6 0
      src/PixiEditor/Helpers/Extensions/ColorHelpers.cs
  10. 3 2
      src/PixiEditor/Helpers/Extensions/PixiParserDocumentEx.cs
  11. 3 2
      src/PixiEditor/Helpers/Extensions/SerializableDocumentEx.cs
  12. 1 0
      src/PixiEditor/Helpers/Extensions/ServiceCollectionHelpers.cs
  13. 2 1
      src/PixiEditor/Helpers/PaletteHelpers.cs
  14. 二进制
      src/PixiEditor/Images/SupperterPack.png
  15. 2 2
      src/PixiEditor/Models/AppExtensions/Services/PaletteProvider.cs
  16. 3 1
      src/PixiEditor/Models/Commands/Search/ColorSearchResult.cs
  17. 2 0
      src/PixiEditor/Models/DataHolders/Palettes/Palette.cs
  18. 2 1
      src/PixiEditor/Models/DataHolders/Palettes/PaletteList.cs
  19. 7 9
      src/PixiEditor/Models/DataProviders/LocalPalettesFetcher.cs
  20. 0 13
      src/PixiEditor/Models/DataProviders/PaletteListDataSource.cs
  21. 4 3
      src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs
  22. 2 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EraserToolExecutor.cs
  23. 2 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/FloodFillToolExecutor.cs
  24. 2 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/LineToolExecutor.cs
  25. 2 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PenToolExecutor.cs
  26. 2 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ShapeToolExecutor.cs
  27. 4 2
      src/PixiEditor/Models/IO/PaletteParsers/ClsFileParser.cs
  28. 4 2
      src/PixiEditor/Models/IO/PaletteParsers/GimpGplParser.cs
  29. 4 2
      src/PixiEditor/Models/IO/PaletteParsers/HexPaletteParser.cs
  30. 4 2
      src/PixiEditor/Models/IO/PaletteParsers/JascPalFile/JascFileParser.cs
  31. 6 4
      src/PixiEditor/Models/IO/PaletteParsers/PaintNetTxtParser.cs
  32. 3 1
      src/PixiEditor/Models/IO/PaletteParsers/PixiPaletteParser.cs
  33. 14 12
      src/PixiEditor/Models/IO/PaletteParsers/PngPaletteParser.cs
  34. 2 0
      src/PixiEditor/PixiEditor.csproj
  35. 3 2
      src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.Serialization.cs
  36. 5 4
      src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs
  37. 18 11
      src/PixiEditor/ViewModels/SubViewModels/Main/ColorsViewModel.cs
  38. 25 8
      src/PixiEditor/Views/Dialogs/PalettesBrowser.xaml.cs
  39. 2 2
      src/PixiEditor/Views/MainWindow.xaml
  40. 15 0
      src/PixiEditor/Views/UserControls/Chip.xaml
  41. 33 0
      src/PixiEditor/Views/UserControls/Chip.xaml.cs
  42. 4 3
      src/PixiEditor/Views/UserControls/EditableTextBlock.xaml
  43. 9 0
      src/PixiEditor/Views/UserControls/EditableTextBlock.xaml.cs
  44. 1 1
      src/PixiEditor/Views/UserControls/Palettes/ColorReplacer.xaml
  45. 15 10
      src/PixiEditor/Views/UserControls/Palettes/ColorReplacer.xaml.cs
  46. 2 2
      src/PixiEditor/Views/UserControls/Palettes/CompactPaletteViewer.xaml
  47. 2 2
      src/PixiEditor/Views/UserControls/Palettes/PaletteColorControl.xaml
  48. 12 13
      src/PixiEditor/Views/UserControls/Palettes/PaletteColorControl.xaml.cs
  49. 18 7
      src/PixiEditor/Views/UserControls/Palettes/PaletteItem.xaml
  50. 4 4
      src/PixiEditor/Views/UserControls/Palettes/PaletteViewer.xaml
  51. 28 22
      src/PixiEditor/Views/UserControls/Palettes/PaletteViewer.xaml.cs
  52. 4 4
      src/PixiEditor/Views/UserControls/SwatchesView.xaml
  53. 2 2
      src/SampleExtension/SampleExtension.cs

+ 1 - 0
src/PixiEditor.Extensions/Palettes/ExtensionPalette.cs

@@ -5,6 +5,7 @@ public class ExtensionPalette : IPalette
     public string Name { get; }
     public List<PaletteColor> Colors { get; }
     public bool IsFavourite { get; set; }
+    public string FileName { get; set; }
 
     public ExtensionPalette(string name, List<PaletteColor> colors)
     {

+ 2 - 1
src/PixiEditor.Extensions/Palettes/IPalette.cs

@@ -4,5 +4,6 @@ public interface IPalette
 {
     public string Name { get; }
     public List<PaletteColor> Colors { get; }
-    public bool IsFavourite { get; set; }
+    public bool IsFavourite { get; }
+    public string FileName { get; set; }
 }

+ 34 - 0
src/PixiEditor.Extensions/Palettes/PaletteColor.cs

@@ -2,6 +2,9 @@
 
 public struct PaletteColor
 {
+    public static PaletteColor Empty => new(0, 0, 0);
+    public static PaletteColor Black => new(0, 0, 0);
+    public static PaletteColor White => new(255, 255, 255);
     public byte R { get; set; }
     public byte G { get; set; }
     public byte B { get; set; }
@@ -19,4 +22,35 @@ public struct PaletteColor
     {
         return Hex;
     }
+
+    public static bool operator ==(PaletteColor left, PaletteColor right)
+    {
+        return left.R == right.R && left.G == right.G && left.B == right.B;
+    }
+
+    public static bool operator !=(PaletteColor left, PaletteColor right)
+    {
+        return !(left == right);
+    }
+
+    public static PaletteColor Parse(string hexString)
+    {
+        string hex = hexString.Replace("#", string.Empty);
+
+        if (hex.Length == 3)
+        {
+            hex = $"{hex[0]}{hex[0]}{hex[1]}{hex[1]}{hex[2]}{hex[2]}";
+        }
+
+        if (hex.Length != 6)
+        {
+            throw new ArgumentException("Invalid hex string. Expected format: RRGGBB");
+        }
+
+        byte r = Convert.ToByte(hex.Substring(0, 2), 16);
+        byte g = Convert.ToByte(hex.Substring(2, 2), 16);
+        byte b = Convert.ToByte(hex.Substring(4, 2), 16);
+
+        return new PaletteColor(r, g, b);
+    }
 }

+ 20 - 0
src/PixiEditor.Extensions/Palettes/PaletteListDataSource.cs

@@ -0,0 +1,20 @@
+using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
+using PixiEditor.Models.IO;
+
+namespace PixiEditor.Models.DataProviders;
+
+public abstract class PaletteListDataSource
+{
+    public virtual void Initialize() { }
+
+    /// <summary>
+    ///     Fetches palettes from the provider.
+    /// </summary>
+    /// <param name="startIndex">Starting fetch index. Palettes before said index won't be fetched.</param>
+    /// <param name="items">Max amount of palettes to fetch.</param>
+    /// <param name="filtering">Filtering settings for fetching.</param>
+    /// <returns>A List of palettes. Null if fetch wasn't successful.</returns>
+    public abstract Task<List<IPalette>> FetchPaletteList(int startIndex, int items, FilteringSettings filtering);
+    public List<PaletteFileParser> AvailableParsers { get; set; }
+}

+ 9 - 10
src/PixiEditor/Models/IO/PaletteFileData.cs → src/PixiEditor.Extensions/Palettes/Parsers/PaletteFileData.cs

@@ -1,16 +1,15 @@
-using PixiEditor.DrawingApi.Core.ColorsImpl;
-using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes;
 
 namespace PixiEditor.Models.IO;
 
-internal class PaletteFileData
+public class PaletteFileData
 {
     public string Title { get; set; }
-    public Color[] Colors { get; set; }
+    public PaletteColor[] Colors { get; set; }
     public bool IsCorrupted { get; set; } = false;
-    public static PaletteFileData Corrupted => new ("Corrupted", Array.Empty<Color>()) { IsCorrupted = true };
+    public static PaletteFileData Corrupted => new ("Corrupted", Array.Empty<PaletteColor>()) { IsCorrupted = true };
 
-    public PaletteFileData(Color[] colors)
+    public PaletteFileData(PaletteColor[] colors)
     {
         Colors = colors;
         Title = "";
@@ -18,16 +17,16 @@ internal class PaletteFileData
 
     public PaletteFileData(List<string> colors)
     {
-        Colors = new Color[colors.Count];
+        Colors = new PaletteColor[colors.Count];
         for (int i = 0; i < colors.Count; i++)
         {
-            Colors[i] = Color.Parse(colors[i]);
+            Colors[i] = PaletteColor.Parse(colors[i]);
         }
 
         Title = "";
     }
 
-    public PaletteFileData(string title, Color[] colors)
+    public PaletteFileData(string title, PaletteColor[] colors)
     {
         Title = title;
         Colors = colors;
@@ -38,7 +37,7 @@ internal class PaletteFileData
         PaletteColor[] colors = new PaletteColor[Colors.Length];
         for (int i = 0; i < Colors.Length; i++)
         {
-            Color color = Colors[i];
+            PaletteColor color = Colors[i];
             colors[i] = new PaletteColor(color.R, color.G, color.B);
         }
 

+ 3 - 2
src/PixiEditor/Models/IO/PaletteFileParser.cs → src/PixiEditor.Extensions/Palettes/Parsers/PaletteFileParser.cs

@@ -1,8 +1,9 @@
 using System.IO;
+using PixiEditor.Models.IO;
 
-namespace PixiEditor.Models.IO;
+namespace PixiEditor.Extensions.Palettes.Parsers;
 
-internal abstract class PaletteFileParser
+public abstract class PaletteFileParser
 {
     public abstract Task<PaletteFileData> Parse(string path);
     public abstract Task<bool> Save(string path, PaletteFileData data);

+ 11 - 1
src/PixiEditor/Helpers/Converters/BackendColorToMediaColorConverter.cs

@@ -1,5 +1,6 @@
 using System.Globalization;
 using System.Windows.Media;
+using PixiEditor.Extensions.Palettes;
 using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 
 namespace PixiEditor.Helpers.Converters;
@@ -8,7 +9,16 @@ internal class BackendColorToMediaColorConverter : SingleInstanceConverter<Backe
 {
     public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
-        var backendColor = (BackendColor)value;
+        BackendColor backendColor = default;
+        if (value is BackendColor)
+        {
+            backendColor = (BackendColor)value;
+        }
+        else if (value is PaletteColor paletteColor)
+        {
+            backendColor = paletteColor.ToColor();
+        }
+
         var color = Color.FromArgb(backendColor.A, backendColor.R, backendColor.G, backendColor.B);
 
         if (targetType == typeof(Brush))

+ 7 - 6
src/PixiEditor/Helpers/DocumentViewModelBuilder.cs

@@ -5,6 +5,7 @@ using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.Extensions.Palettes;
 using PixiEditor.Parser;
 using BlendMode = PixiEditor.ChangeableDocument.Enums.BlendMode;
 
@@ -15,8 +16,8 @@ internal class DocumentViewModelBuilder : ChildrenBuilder
     public int Width { get; set; }
     public int Height { get; set; }
     
-    public List<Color> Swatches { get; set; } = new List<Color>();
-    public List<Color> Palette { get; set; } = new List<Color>();
+    public List<PaletteColor> Swatches { get; set; } = new List<PaletteColor>();
+    public List<PaletteColor> Palette { get; set; } = new List<PaletteColor>();
     
     public ReferenceLayerBuilder ReferenceLayer { get; set; }
 
@@ -28,22 +29,22 @@ internal class DocumentViewModelBuilder : ChildrenBuilder
         return this;
     }
     
-    public DocumentViewModelBuilder WithSwatches(IEnumerable<Color> swatches)
+    public DocumentViewModelBuilder WithSwatches(IEnumerable<PaletteColor> swatches)
     {
         Swatches = new (swatches);
         return this;
     }
 
-    public DocumentViewModelBuilder WithSwatches<T>(IEnumerable<T> swatches, Func<T, Color> toColor) =>
+    public DocumentViewModelBuilder WithSwatches<T>(IEnumerable<T> swatches, Func<T, PaletteColor> toColor) =>
         WithSwatches(swatches.Select(toColor));
     
-    public DocumentViewModelBuilder WithPalette(IEnumerable<Color> palette)
+    public DocumentViewModelBuilder WithPalette(IEnumerable<PaletteColor> palette)
     {
         Palette = new(palette);
         return this;
     }
 
-    public DocumentViewModelBuilder WithPalette<T>(IEnumerable<T> pallet, Func<T, Color> toColor) =>
+    public DocumentViewModelBuilder WithPalette<T>(IEnumerable<T> pallet, Func<T, PaletteColor> toColor) =>
         WithPalette(pallet.Select(toColor));
 
     public DocumentViewModelBuilder WithReferenceLayer<T>(T reference, Action<T, ReferenceLayerBuilder> builder)

+ 6 - 0
src/PixiEditor/Helpers/Extensions/ColorHelpers.cs

@@ -1,4 +1,5 @@
 using System.Windows.Media;
+using PixiEditor.Extensions.Palettes;
 using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 
 namespace PixiEditor.Helpers.Extensions;
@@ -7,9 +8,14 @@ internal static class ColorHelpers
 {
     public static BackendColor ToOpaqueColor(this Color color) => new(color.R, color.G, color.B);
     public static BackendColor ToColor(this Color color) => new(color.R, color.G, color.B, color.A);
+    public static BackendColor ToColor(this PaletteColor color) => new(color.R, color.G, color.B, 255);
+
+    public static PaletteColor ToPaletteColor(this Color color) => new(color.R, color.G, color.B);
+    public static PaletteColor ToPaletteColor(this BackendColor color) => new(color.R, color.G, color.B);
 
     public static Color ToOpaqueMediaColor(this BackendColor color) => Color.FromRgb(color.R, color.G, color.B);
     public static Color ToColor(this BackendColor color) => Color.FromArgb(color.A, color.R, color.G, color.B);
+    public static Color ToMediaColor(this PaletteColor color) => Color.FromRgb(color.R, color.G, color.B);
     
     public static BackendColor BlendColors(BackendColor bottomColor, BackendColor topColor)
     {

+ 3 - 2
src/PixiEditor/Helpers/Extensions/PixiParserDocumentEx.cs

@@ -1,6 +1,7 @@
 using ChunkyImageLib;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.Extensions.Palettes;
 using PixiEditor.Parser;
 using PixiEditor.Parser.Deprecated;
 using PixiEditor.ViewModels.SubViewModels.Document;
@@ -19,8 +20,8 @@ internal static class PixiParserDocumentEx
         return DocumentViewModel.Build(b =>
         {
             b.WithSize(document.Width, document.Height)
-                .WithPalette(document.Palette, x => new Color(x.R, x.G, x.B, x.A))
-                .WithSwatches(document.Swatches, x => new(x.R, x.G, x.B, x.A))
+                .WithPalette(document.Palette, x => new PaletteColor(x.R, x.G, x.B))
+                .WithSwatches(document.Swatches, x => new(x.R, x.G, x.B))
                 .WithReferenceLayer(document.ReferenceLayer, (r, builder) => builder
                     .WithIsVisible(r.Enabled)
                     .WithShape(r.Corners)

+ 3 - 2
src/PixiEditor/Helpers/Extensions/SerializableDocumentEx.cs

@@ -2,6 +2,7 @@
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
+using PixiEditor.Extensions.Palettes;
 using PixiEditor.Parser;
 using PixiEditor.Parser.Collections.Deprecated;
 using PixiEditor.Parser.Deprecated;
@@ -32,8 +33,8 @@ internal static class SerializableDocumentEx
         {
             builder
                 .WithSize(serializableDocument.Width, serializableDocument.Height)
-                .WithPalette(serializableDocument.Palette.Select(x => new Color(x.R, x.G, x.B, x.A)).ToList())
-                .WithSwatches(serializableDocument.Swatches.Select(x => new Color(x.R, x.G, x.B, x.A)).ToList());
+                .WithPalette(serializableDocument.Palette.Select(x => new PaletteColor(x.R, x.G, x.B)).ToList())
+                .WithSwatches(serializableDocument.Swatches.Select(x => new PaletteColor(x.R, x.G, x.B)).ToList());
 
             if (serializableDocument.Groups != null)
             {

+ 1 - 0
src/PixiEditor/Helpers/Extensions/ServiceCollectionHelpers.cs

@@ -1,6 +1,7 @@
 using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.Extensions;
 using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 using PixiEditor.Extensions.Windowing;
 using PixiEditor.Models.AppExtensions.Services;
 using PixiEditor.Models.Commands;

+ 2 - 1
src/PixiEditor/Helpers/PaletteHelpers.cs

@@ -1,4 +1,5 @@
-using PixiEditor.Models.IO;
+using PixiEditor.Extensions.Palettes.Parsers;
+using PixiEditor.Models.IO;
 
 namespace PixiEditor.Helpers;
 

二进制
src/PixiEditor/Images/SupperterPack.png


+ 2 - 2
src/PixiEditor/Models/AppExtensions/Services/PaletteProvider.cs

@@ -20,7 +20,7 @@ internal sealed class PaletteProvider : IPaletteProvider
         foreach (PaletteListDataSource dataSource in dataSources)
         {
             var palettes = await dataSource.FetchPaletteList(startIndex, items, filtering);
-            allPalettes.AddRange(palettes.Palettes);
+            allPalettes.AddRange(palettes);
         }
 
         return allPalettes;
@@ -51,7 +51,7 @@ internal sealed class PaletteProvider : IPaletteProvider
 
         await localPalettesFetcher.SavePalette(
             finalName,
-            palette.Colors.Select(x => new Color(x.R, x.G, x.B)).ToArray());
+            palette.Colors.ToArray());
 
         return true;
     }

+ 3 - 1
src/PixiEditor/Models/Commands/Search/ColorSearchResult.cs

@@ -2,6 +2,7 @@
 using System.Windows.Controls;
 using System.Windows.Documents;
 using System.Windows.Media;
+using PixiEditor.Extensions.Palettes;
 
 namespace PixiEditor.Models.Commands.Search;
 
@@ -44,7 +45,8 @@ internal class ColorSearchResult : SearchResult
     public static ColorSearchResult PastePalette(DrawingApi.Core.ColorsImpl.Color color, string searchTerm = null)
     {
         //var result = new ColorSearchResult(color, x => ViewModelMain.Current.BitmapManager.ActiveDocument.Palette.Add(x))
-        var result = new ColorSearchResult(color, x => ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument!.Palette.Add(x))
+        var result = new ColorSearchResult(color, x =>
+            ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument!.Palette.Add(new PaletteColor(x.R, x.G, x.B)))
         {
             SearchTerm = searchTerm,
             isPalettePaste = true

+ 2 - 0
src/PixiEditor/Models/DataHolders/Palettes/Palette.cs

@@ -29,6 +29,8 @@ internal class Palette : NotifyableObject, IPalette
 
     public bool IsFavourite { get; set; }
 
+    public bool IsFromSupporterPack { get; }
+
     public Palette(string name, List<PaletteColor> colors, string? fileName)
     {
         Name = name;

+ 2 - 1
src/PixiEditor/Models/DataHolders/Palettes/PaletteList.cs

@@ -1,4 +1,5 @@
-using PixiEditor.Helpers;
+using PixiEditor.Extensions.Palettes;
+using PixiEditor.Helpers;
 
 namespace PixiEditor.Models.DataHolders.Palettes;
 

+ 7 - 9
src/PixiEditor/Models/DataProviders/LocalPalettesFetcher.cs

@@ -1,6 +1,7 @@
 using System.IO;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders.Palettes;
 using PixiEditor.Models.IO;
@@ -37,22 +38,20 @@ internal class LocalPalettesFetcher : PaletteListDataSource
         IPreferences.Current.AddCallback(PreferencesConstants.FavouritePalettes, updated =>
         {
             cachedFavoritePalettes = (List<string>)updated;
+            cachedPalettes.ForEach(x => x.IsFavourite = cachedFavoritePalettes.Contains(x.Name));
         });
     }
 
-    public override async Task<PaletteList> FetchPaletteList(int startIndex, int count, FilteringSettings filtering)
+    public override async Task<List<IPalette>> FetchPaletteList(int startIndex, int count, FilteringSettings filtering)
     {
         if (cachedPalettes == null)
         {
             await RefreshCacheAll();
         }
 
-        PaletteList result = new PaletteList
-        {
-            Palettes = new WpfObservableRangeCollection<Palette>()
-        };
+        var filteredPalettes = cachedPalettes.Where(filtering.Filter).OrderByDescending(x => x.IsFavourite).ToArray();
 
-        var filteredPalettes = cachedPalettes.Where(filtering.Filter).ToArray();
+        List<IPalette> result = new List<IPalette>();
 
         if (startIndex >= filteredPalettes.Length) return result;
 
@@ -60,10 +59,9 @@ internal class LocalPalettesFetcher : PaletteListDataSource
         {
             if (startIndex + i >= filteredPalettes.Length) break;
             Palette palette = filteredPalettes[startIndex + i];
-            result.Palettes.Add(palette);
+            result.Add(palette);
         }
 
-        result.FetchedCorrectly = true;
         return result;
     }
 
@@ -102,7 +100,7 @@ internal class LocalPalettesFetcher : PaletteListDataSource
         return newName;
     }
 
-    public async Task SavePalette(string fileName, Color[] colors)
+    public async Task SavePalette(string fileName, PaletteColor[] colors)
     {
         watcher.EnableRaisingEvents = false;
         string path = Path.Join(Paths.PathToPalettesFolder, fileName);

+ 0 - 13
src/PixiEditor/Models/DataProviders/PaletteListDataSource.cs

@@ -1,13 +0,0 @@
-using PixiEditor.Extensions.Palettes;
-using PixiEditor.Models.DataHolders.Palettes;
-using PixiEditor.Models.IO;
-
-namespace PixiEditor.Models.DataProviders;
-
-internal abstract class PaletteListDataSource
-{
-    public virtual void Initialize() { }
-    public abstract Task<PaletteList> FetchPaletteList(int startIndex, int items, FilteringSettings filtering);
-    public List<PaletteFileParser> AvailableParsers { get; set; }
-
-}

+ 4 - 3
src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs

@@ -7,6 +7,7 @@ using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface.Vector;
+using PixiEditor.Extensions.Palettes;
 using PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 using PixiEditor.Models.DocumentPassthroughActions;
 using PixiEditor.Models.Enums;
@@ -232,16 +233,16 @@ internal class DocumentOperationsModule
     /// </summary>
     /// <param name="oldColor">The color to replace</param>
     /// <param name="newColor">The new color</param>
-    public void ReplaceColor(Color oldColor, Color newColor)
+    public void ReplaceColor(PaletteColor oldColor, PaletteColor newColor)
     {
         if (Internals.ChangeController.IsChangeActive || oldColor == newColor)
             return;
         
-        Internals.ActionAccumulator.AddFinishedActions(new ReplaceColor_Action(oldColor, newColor));
+        Internals.ActionAccumulator.AddFinishedActions(new ReplaceColor_Action(oldColor.ToColor(), newColor.ToColor()));
         ReplaceInPalette(oldColor, newColor);
     }
 
-    private void ReplaceInPalette(Color oldColor, Color newColor)
+    private void ReplaceInPalette(PaletteColor oldColor, PaletteColor newColor)
     {
         int indexOfOldColor = Document.Palette.IndexOf(oldColor);
         if(indexOfOldColor == -1)

+ 2 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EraserToolExecutor.cs

@@ -2,6 +2,7 @@
 using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.Extensions.Palettes;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Tools.Tools;
@@ -34,7 +35,7 @@ internal class EraserToolExecutor : UpdateableChangeExecutor
         color = vm.ColorsSubViewModel.PrimaryColor;
         toolSize = toolbar.ToolSize;
 
-        vm.ColorsSubViewModel.AddSwatch(color);
+        vm.ColorsSubViewModel.AddSwatch(new PaletteColor(color.R, color.G, color.B));
         IAction? action = new LineBasedPen_Action(guidValue, DrawingApi.Core.ColorsImpl.Colors.Transparent, controller!.LastPixelPosition, toolSize, true,
             drawOnMask);
         internals!.ActionAccumulator.AddActions(action);

+ 2 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/FloodFillToolExecutor.cs

@@ -1,6 +1,7 @@
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.Extensions.Palettes;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Tools.Tools;
@@ -28,7 +29,7 @@ internal class FloodFillToolExecutor : UpdateableChangeExecutor
         if (!drawOnMask && member is not LayerViewModel)
             return ExecutionState.Error;
 
-        colorsVM.AddSwatch(color);
+        colorsVM.AddSwatch(new PaletteColor(color.R, color.G, color.B));
         memberGuid = member.GuidValue;
         considerAllLayers = fillTool.ConsiderAllLayers;
         color = colorsVM.PrimaryColor;

+ 2 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/LineToolExecutor.cs

@@ -3,6 +3,7 @@ using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.Extensions.Palettes;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Tools;
@@ -45,7 +46,7 @@ internal class LineToolExecutor : UpdateableChangeExecutor
         strokeWidth = toolViewModel.ToolSize;
         memberGuid = member.GuidValue;
 
-        colorsVM.AddSwatch(strokeColor);
+        colorsVM.AddSwatch(new PaletteColor(strokeColor.R, strokeColor.G, strokeColor.B));
 
         return ExecutionState.Success;
     }

+ 2 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PenToolExecutor.cs

@@ -2,6 +2,7 @@
 using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.Extensions.Palettes;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Tools.Tools;
@@ -35,7 +36,7 @@ internal class PenToolExecutor : UpdateableChangeExecutor
         toolSize = toolbar.ToolSize;
         pixelPerfect = penTool.PixelPerfectEnabled;
 
-        vm.ColorsSubViewModel.AddSwatch(color);
+        vm.ColorsSubViewModel.AddSwatch(new PaletteColor(color.R, color.G, color.B));
         IAction? action = pixelPerfect switch
         {
             false => new LineBasedPen_Action(guidValue, color, controller!.LastPixelPosition, toolSize, false, drawOnMask),

+ 2 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ShapeToolExecutor.cs

@@ -2,6 +2,7 @@
 using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.Extensions.Palettes;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Tools;
@@ -46,7 +47,7 @@ internal abstract class ShapeToolExecutor<T> : UpdateableChangeExecutor where T
         strokeWidth = toolbar.ToolSize;
         memberGuid = member.GuidValue;
 
-        colorsVM.AddSwatch(strokeColor);
+        colorsVM.AddSwatch(new PaletteColor(strokeColor.R, strokeColor.G, strokeColor.B));
         DrawShape(startPos, true);
         return ExecutionState.Success;
     }

+ 4 - 2
src/PixiEditor/Models/IO/PaletteParsers/ClsFileParser.cs

@@ -1,6 +1,8 @@
 using System.IO;
 using CLSEncoderDecoder;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 
 namespace PixiEditor.Models.IO.PaletteParsers;
 
@@ -28,7 +30,7 @@ internal class ClsFileParser : PaletteFileParser
                 set.Utf8Name,
                 set.Colors
                     .Where(static color => color.Alpha > 0)
-                    .Select(static color => new Color(color.Red, color.Green, color.Blue, 255))
+                    .Select(static color => new PaletteColor(color.Red, color.Green, color.Blue))
                     .ToArray()
             );
             return data;
@@ -41,7 +43,7 @@ internal class ClsFileParser : PaletteFileParser
 
         string name = data.Title;
         List<ClsColor> colors = data.Colors
-            .Select(color => new ClsColor(color.R, color.G, color.B, color.A)).ToList();
+            .Select(color => new ClsColor(color.R, color.G, color.B, 255)).ToList();
         await Task.Run(() =>
         {
             if (name.Length == 0)

+ 4 - 2
src/PixiEditor/Models/IO/PaletteParsers/GimpGplParser.cs

@@ -1,6 +1,8 @@
 using System.IO;
 using System.Text;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 
 namespace PixiEditor.Models.IO.PaletteParsers;
 
@@ -30,7 +32,7 @@ internal class GimpGplParser : PaletteFileParser
 
         if(lines.Length == 0) return PaletteFileData.Corrupted;
 
-        List<Color> colors = new();
+        List<PaletteColor> colors = new();
         char[] separators = new[] { '\t', ' ' };
         foreach (var colorLine in lines)
         {
@@ -54,7 +56,7 @@ internal class GimpGplParser : PaletteFileParser
             parsed = byte.TryParse(colorParts[2], out byte b);
             if(!parsed) continue;
 
-            var color = new Color(r, g, b, 255); // alpha is ignored in PixiEditor
+            var color = new PaletteColor(r, g, b); // alpha is ignored in PixiEditor
             if (colors.Contains(color)) continue;
 
             colors.Add(color);

+ 4 - 2
src/PixiEditor/Models/IO/PaletteParsers/HexPaletteParser.cs

@@ -2,6 +2,8 @@
 using System.IO;
 using System.Text;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 
 namespace PixiEditor.Models.IO.PaletteParsers;
 
@@ -26,7 +28,7 @@ internal class HexPaletteParser : PaletteFileParser
         var lines = await ReadTextLines(path);
         string name = Path.GetFileNameWithoutExtension(path);
 
-        List<Color> colors = new();
+        List<PaletteColor> colors = new();
         foreach (var colorLine in lines)
         {
             if (colorLine.Length < 6)
@@ -35,7 +37,7 @@ internal class HexPaletteParser : PaletteFileParser
             byte r = byte.Parse(colorLine.Substring(0, 2), NumberStyles.HexNumber);
             byte g = byte.Parse(colorLine.Substring(2, 2), NumberStyles.HexNumber);
             byte b = byte.Parse(colorLine.Substring(4, 2), NumberStyles.HexNumber);
-            var color = new Color(r, g, b, 255); // alpha is ignored in PixiEditor
+            var color = new PaletteColor(r, g, b); // alpha is ignored in PixiEditor
             if (colors.Contains(color)) continue;
 
             colors.Add(color);

+ 4 - 2
src/PixiEditor/Models/IO/PaletteParsers/JascPalFile/JascFileParser.cs

@@ -1,5 +1,7 @@
 using System.IO;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 
 namespace PixiEditor.Models.IO.PaletteParsers.JascPalFile;
 
@@ -21,11 +23,11 @@ internal class JascFileParser : PaletteFileParser
         if (ValidateFile(fileType, magicBytes))
         {
             int colorCount = int.Parse(lines[2]);
-            Color[] colors = new Color[colorCount];
+            PaletteColor[] colors = new PaletteColor[colorCount];
             for (int i = 0; i < colorCount; i++)
             {
                 string[] colorData = lines[i + 3].Split(' ');
-                colors[i] = new Color(byte.Parse(colorData[0]), byte.Parse(colorData[1]), byte.Parse(colorData[2]));
+                colors[i] = new PaletteColor(byte.Parse(colorData[0]), byte.Parse(colorData[1]), byte.Parse(colorData[2]));
             }
 
             return new PaletteFileData(name, colors);

+ 6 - 4
src/PixiEditor/Models/IO/PaletteParsers/PaintNetTxtParser.cs

@@ -2,6 +2,8 @@
 using System.IO;
 using System.Text;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 using PixiEditor.Helpers;
 
 namespace PixiEditor.Models.IO.PaletteParsers;
@@ -31,7 +33,7 @@ internal class PaintNetTxtParser : PaletteFileParser
 
         lines = lines.Where(x => !x.StartsWith(";")).ToArray();
 
-        List<Color> colors = new();
+        List<PaletteColor> colors = new();
         for (int i = 0; i < lines.Length; i++)
         {
             // Color format aarrggbb
@@ -43,7 +45,7 @@ internal class PaintNetTxtParser : PaletteFileParser
             byte r = byte.Parse(colorLine.Substring(2, 2), NumberStyles.HexNumber);
             byte g = byte.Parse(colorLine.Substring(4, 2), NumberStyles.HexNumber);
             byte b = byte.Parse(colorLine.Substring(6, 2), NumberStyles.HexNumber);
-            var color = new Color(r, g, b, 255); // alpha is ignored in PixiEditor
+            var color = new PaletteColor(r, g, b); // alpha is ignored in PixiEditor
             if(colors.Contains(color)) continue;
 
             colors.Add(color);
@@ -58,9 +60,9 @@ internal class PaintNetTxtParser : PaletteFileParser
         sb.AppendLine("; Paint.NET Palette File");
         sb.AppendLine($"; Made using PixiEditor {VersionHelpers.GetCurrentAssemblyVersion().ToString()}");
         sb.AppendLine($"; {data.Colors.Length} colors");
-        foreach (Color color in data.Colors)
+        foreach (PaletteColor color in data.Colors)
         {
-            sb.AppendLine(color.ToHex());
+            sb.AppendLine(color.Hex);
         }
 
         try

+ 3 - 1
src/PixiEditor/Models/IO/PaletteParsers/PixiPaletteParser.cs

@@ -1,5 +1,7 @@
 using System.IO;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 using PixiEditor.Parser;
 
 namespace PixiEditor.Models.IO.PaletteParsers;
@@ -27,7 +29,7 @@ internal class PixiPaletteParser : PaletteFileParser
 
         string name = Path.GetFileNameWithoutExtension(path);
 
-        return new PaletteFileData(name, file.Palette.Select(x => new Color(x.R, x.G, x.B, x.A)).ToArray());
+        return new PaletteFileData(name, file.Palette.Select(x => new PaletteColor(x.R, x.G, x.B)).ToArray());
     }
 
     public override bool CanSave => false;

+ 14 - 12
src/PixiEditor/Models/IO/PaletteParsers/PngPaletteParser.cs

@@ -1,6 +1,8 @@
 using System.IO;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
+using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 using Color = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 
 namespace PixiEditor.Models.IO.PaletteParsers;
@@ -30,7 +32,7 @@ internal class PngPaletteParser : PaletteFileParser
 
             BitmapFrame frame = decoder.Frames[0];
 
-            Color[] colors = ExtractFromBitmap(frame);
+            PaletteColor[] colors = ExtractFromBitmap(frame);
 
             PaletteFileData data = new(
                 Path.GetFileNameWithoutExtension(path), colors);
@@ -39,7 +41,7 @@ internal class PngPaletteParser : PaletteFileParser
         });
     }
 
-    private Color[] ExtractFromBitmap(BitmapFrame frame)
+    private PaletteColor[] ExtractFromBitmap(BitmapFrame frame)
     {
         if (frame.Palette is not null && frame.Palette.Colors.Count > 0)
         {
@@ -49,14 +51,14 @@ internal class PngPaletteParser : PaletteFileParser
         return ExtractFromBitmapSource(frame);
     }
 
-    private Color[] ExtractFromBitmapSource(BitmapFrame frame)
+    private PaletteColor[] ExtractFromBitmapSource(BitmapFrame frame)
     {
         if (frame.PixelWidth == 0 || frame.PixelHeight == 0)
         {
-            return Array.Empty<Color>();
+            return Array.Empty<PaletteColor>();
         }
 
-        List<Color> colors = new();
+        List<PaletteColor> colors = new();
 
         byte[] pixels = new byte[frame.PixelWidth * frame.PixelHeight * 4];
         frame.CopyPixels(pixels, frame.PixelWidth * 4, 0);
@@ -73,19 +75,19 @@ internal class PngPaletteParser : PaletteFileParser
         return colors.ToArray();
     }
 
-    private Color GetColorFromBytes(byte[] pixels, int i)
+    private PaletteColor GetColorFromBytes(byte[] pixels, int i)
     {
-        return new Color(pixels[i * 4 + 2], pixels[i * 4 + 1], pixels[i * 4]);
+        return new PaletteColor(pixels[i * 4 + 2], pixels[i * 4 + 1], pixels[i * 4]);
     }
 
-    private Color[] ExtractFromBitmapPalette(BitmapPalette palette)
+    private PaletteColor[] ExtractFromBitmapPalette(BitmapPalette palette)
     {
         if (palette.Colors == null || palette.Colors.Count == 0)
         {
-            return Array.Empty<Color>();
+            return Array.Empty<PaletteColor>();
         }
 
-        return palette.Colors.Select(color => color.ToColor()).ToArray();
+        return palette.Colors.Select(color => new PaletteColor(color.R, color.G, color.B)).ToArray();
     }
 
     public override async Task<bool> Save(string path, PaletteFileData data)
@@ -109,8 +111,8 @@ internal class PngPaletteParser : PaletteFileParser
             bitmap.Lock();
             for (int i = 0; i < data.Colors.Length; i++)
             {
-                Color color = data.Colors[i];
-                bitmap.SetPixel(i, 0, color.ToOpaqueMediaColor());
+                PaletteColor color = data.Colors[i];
+                bitmap.SetPixel(i, 0, new System.Windows.Media.Color { R = color.R, G = color.G, B = color.B, A = 255 });
             }
 
             bitmap.Unlock();

+ 2 - 0
src/PixiEditor/PixiEditor.csproj

@@ -432,6 +432,8 @@
 		<Resource Include="Images\Commands\PixiEditor\Selection\InvertSelection.png" />
 		<None Remove="Images\LanguageFlags\zh.png" />
 		<Resource Include="Images\LanguageFlags\zh.png" />
+		<None Remove="Images\SupperterPack.png" />
+		<Resource Include="Images\SupperterPack.png" />
 	</ItemGroup>
 	<ItemGroup>
 		<None Include="..\LICENSE">

+ 3 - 2
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.Serialization.cs

@@ -8,6 +8,7 @@ using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
+using PixiEditor.Extensions.Palettes;
 using PixiEditor.Helpers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.IO;
@@ -158,6 +159,6 @@ internal partial class DocumentViewModel
         };
     }
 
-    private ColorCollection ToCollection(WpfObservableRangeCollection<PixiColor> collection) =>
-        new(collection.Select(x => Color.FromArgb(x.A, x.R, x.G, x.B)));
+    private ColorCollection ToCollection(WpfObservableRangeCollection<PaletteColor> collection) =>
+        new(collection.Select(x => Color.FromArgb(255, x.R, x.G, x.B)));
 }

+ 5 - 4
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs

@@ -15,6 +15,7 @@ using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using PixiEditor.DrawingApi.Core.Surface.Vector;
+using PixiEditor.Extensions.Palettes;
 using PixiEditor.Helpers;
 using PixiEditor.Helpers.Collections;
 using PixiEditor.Models.Controllers;
@@ -142,8 +143,8 @@ internal partial class DocumentViewModel : NotifyableObject
     private VectorPath selectionPath = new VectorPath();
     public VectorPath SelectionPathBindable => selectionPath;
 
-    public WpfObservableRangeCollection<Color> Swatches { get; set; } = new WpfObservableRangeCollection<Color>();
-    public WpfObservableRangeCollection<Color> Palette { get; set; } = new WpfObservableRangeCollection<Color>();
+    public WpfObservableRangeCollection<PaletteColor> Swatches { get; set; } = new WpfObservableRangeCollection<PaletteColor>();
+    public WpfObservableRangeCollection<PaletteColor> Palette { get; set; } = new WpfObservableRangeCollection<PaletteColor>();
 
     public DocumentTransformViewModel TransformViewModel { get; }
     public ReferenceLayerViewModel ReferenceLayerViewModel { get; }
@@ -211,8 +212,8 @@ internal partial class DocumentViewModel : NotifyableObject
                 .AddActions(new SetReferenceLayer_Action(refLayer.Shape, refLayer.ImagePbgra32Bytes.ToImmutableArray(), refLayer.ImageSize));
         }
         
-        viewModel.Swatches = new WpfObservableRangeCollection<Color>(builderInstance.Swatches);
-        viewModel.Palette = new WpfObservableRangeCollection<Color>(builderInstance.Palette);
+        viewModel.Swatches = new WpfObservableRangeCollection<PaletteColor>(builderInstance.Swatches);
+        viewModel.Palette = new WpfObservableRangeCollection<PaletteColor>(builderInstance.Palette);
 
         AddMembers(viewModel.StructureRoot.GuidValue, builderInstance.Children);
 

+ 18 - 11
src/PixiEditor/ViewModels/SubViewModels/Main/ColorsViewModel.cs

@@ -3,6 +3,7 @@ using System.Windows.Input;
 using System.Windows.Media;
 using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Commands.XAML;
 using PixiEditor.Models.Controllers;
@@ -77,7 +78,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
     }
 
     [Command.Internal("PixiEditor.Colors.ReplaceColors")]
-    public void ReplaceColors((Color oldColor, Color newColor) colors)
+    public void ReplaceColors((PaletteColor oldColor, PaletteColor newColor) colors)
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null || colors.oldColor == colors.newColor)
@@ -89,8 +90,8 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
     [Command.Basic("PixiEditor.Colors.ReplacePrimaryBySecondaryColor", true, "REPLACE_PRIMARY_BY_SECONDARY", "REPLACE_PRIMARY_BY_SECONDARY_DESCRIPTIVE", IconEvaluator = "PixiEditor.Colors.ReplaceColorIcon")]
     public void ReplaceColors(bool replacePrimary)
     {
-        var oldColor = replacePrimary ? PrimaryColor : SecondaryColor;
-        var newColor = replacePrimary ? SecondaryColor : PrimaryColor;
+        PaletteColor oldColor = replacePrimary ? PrimaryColor.ToPaletteColor() : SecondaryColor.ToPaletteColor();
+        PaletteColor newColor = replacePrimary ? SecondaryColor.ToPaletteColor() : PrimaryColor.ToPaletteColor();
         
         ReplaceColors((oldColor, newColor));
     }
@@ -149,7 +150,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
         if (lospecPaletteArg != null)
         {
             var browser = PalettesBrowser.Open(PaletteDataSources, ImportPaletteCommand,
-                new WpfObservableRangeCollection<Color>());
+                new WpfObservableRangeCollection<PaletteColor>());
 
             browser.IsFetching = true;
             var palette = await LospecPaletteFetcher.FetchPalette(lospecPaletteArg.Split(@"://")[1].Replace("/", ""));
@@ -186,7 +187,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
 
         await LocalPaletteFetcher.SavePalette(
             palette.FileName,
-            palette.Colors.Select(x => new Color(x.R, x.G, x.B)).ToArray());
+            palette.Colors.Select(x => new PaletteColor(x.R, x.G, x.B)).ToArray());
 
         await browser.UpdatePaletteList();
         if (browser.SortedResults.Any(x => x.FileName == palette.FileName))
@@ -218,10 +219,10 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
         {
             if (doc.Palette is null)
             {
-                doc.Palette = new WpfObservableRangeCollection<DrawingApi.Core.ColorsImpl.Color>();
+                doc.Palette = new WpfObservableRangeCollection<PaletteColor>();
             }
 
-            doc.Palette.ReplaceRange(palette.Select(x => new Color(x.R, x.G, x.B)));
+            doc.Palette.ReplaceRange(palette.Select(x => new PaletteColor(x.R, x.G, x.B)));
         }
     }
 
@@ -260,9 +261,14 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
 
         Color color;
         if (document?.Palette is null || document.Palette.Count <= index)
+        {
             color = Colors.Gray;
+        }
         else
-            color = document.Palette[index];
+        {
+            PaletteColor paletteColor = document.Palette[index];
+            color = new Color(paletteColor.R, paletteColor.G, paletteColor.B);
+        }
 
         return ColorSearchResult.GetIcon(color);
     }
@@ -282,7 +288,8 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
         var document = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (document?.Palette is not null && document.Palette.Count > index)
         {
-            PrimaryColor = document.Palette[index];
+            PaletteColor paletteColor = document.Palette[index];
+            PrimaryColor = new Color(paletteColor.R, paletteColor.G, paletteColor.B);
         }
     }
 
@@ -292,7 +299,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
         (PrimaryColor, SecondaryColor) = (SecondaryColor, PrimaryColor);
     }
 
-    public void AddSwatch(Color color)
+    public void AddSwatch(PaletteColor color)
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null)
@@ -304,7 +311,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
     }
 
     [Command.Internal("PixiEditor.Colors.RemoveSwatch")]
-    public void RemoveSwatch(Color color)
+    public void RemoveSwatch(PaletteColor color)
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null)

+ 25 - 8
src/PixiEditor/Views/Dialogs/PalettesBrowser.xaml.cs

@@ -2,11 +2,13 @@ using System.Diagnostics;
 using System.IO;
 using System.Windows;
 using System.Windows.Controls;
+using System.Windows.Documents;
 using System.Windows.Input;
 using System.Windows.Navigation;
 using Microsoft.Win32;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 using PixiEditor.Helpers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders.Palettes;
@@ -18,6 +20,7 @@ using PixiEditor.Models.Localization;
 using PixiEditor.Models.UserPreferences;
 using PixiEditor.Views.UserControls;
 using PixiEditor.Views.UserControls.Palettes;
+using PaletteColor = PixiEditor.Extensions.Palettes.PaletteColor;
 
 namespace PixiEditor.Views.Dialogs;
 
@@ -139,7 +142,7 @@ internal partial class PalettesBrowser : Window
     private char[] separators = new char[] { ' ', ',' };
 
     private SortingType InternalSortingType => (SortingType)SortingIndex;
-    public WpfObservableRangeCollection<Color> CurrentEditingPalette { get; set; }
+    public WpfObservableRangeCollection<PaletteColor> CurrentEditingPalette { get; set; }
     public static PalettesBrowser Instance { get; internal set; }
 
     private LocalPalettesFetcher LocalPalettesFetcher
@@ -152,6 +155,8 @@ internal partial class PalettesBrowser : Window
 
     private LocalPalettesFetcher localPalettesFetcher;
 
+    private double _lastScrolledOffset = -1;
+
     public PalettesBrowser()
     {
         InitializeComponent();
@@ -161,8 +166,8 @@ internal partial class PalettesBrowser : Window
         ToggleFavouriteCommand = new RelayCommand<Palette>(ToggleFavourite, CanToggleFavourite);
         Loaded += async (_, _) =>
         {
-            LocalPalettesFetcher.CacheUpdated += LocalCacheRefreshed;
             await LocalPalettesFetcher.RefreshCacheAll();
+            LocalPalettesFetcher.CacheUpdated += LocalCacheRefreshed;
         };
         Closed += (_, _) =>
         {
@@ -171,7 +176,7 @@ internal partial class PalettesBrowser : Window
         };
     }
 
-    public static PalettesBrowser Open(WpfObservableRangeCollection<PaletteListDataSource> dataSources, ICommand importPaletteCommand, WpfObservableRangeCollection<Color> currentEditingPalette)
+    public static PalettesBrowser Open(WpfObservableRangeCollection<PaletteListDataSource> dataSources, ICommand importPaletteCommand, WpfObservableRangeCollection<PaletteColor> currentEditingPalette)
     {
         if (Instance != null) return Instance;
         PalettesBrowser browser = new PalettesBrowser
@@ -263,13 +268,13 @@ internal partial class PalettesBrowser : Window
         palette.IsFavourite = !palette.IsFavourite;
         var favouritePalettes = IPreferences.Current.GetLocalPreference(PreferencesConstants.FavouritePalettes, new List<string>());
 
-        if (palette.IsFavourite)
+        if (palette.IsFavourite && !favouritePalettes.Contains(palette.Name))
         {
             favouritePalettes.Add(palette.Name);
         }
         else
         {
-            favouritePalettes.Remove(palette.Name);
+            favouritePalettes.RemoveAll(x => x == palette.Name);
         }
 
         IPreferences.Current.UpdateLocalPreference(PreferencesConstants.FavouritePalettes, favouritePalettes);
@@ -335,8 +340,8 @@ internal partial class PalettesBrowser : Window
     public async Task UpdatePaletteList()
     {
         IsFetching = true;
+        _lastScrolledOffset = -1;
         PaletteList?.Palettes?.Clear();
-
         for (int i = 0; i < PaletteListDataSources.Count; i++)
         {
             PaletteList src = await FetchPaletteList(i, Filtering);
@@ -360,7 +365,17 @@ internal partial class PalettesBrowser : Window
     {
         int startIndex = PaletteList != null ? PaletteList.Palettes.Count : 0;
         var src = await PaletteListDataSources[index].FetchPaletteList(startIndex, ItemsPerLoad, filtering);
-        return src;
+        WpfObservableRangeCollection<Palette> palettes = new WpfObservableRangeCollection<Palette>();
+        if (src != null)
+        {
+            foreach (var pal in src)
+            {
+                palettes.Add(new Palette(pal.Name, pal.Colors, pal.FileName) { IsFavourite = pal.IsFavourite});
+            }
+        }
+
+        PaletteList list = new PaletteList { Palettes = palettes, FetchedCorrectly = src != null };
+        return list;
     }
 
     private static async void OnNameFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
@@ -375,7 +390,7 @@ internal partial class PalettesBrowser : Window
     {
         if (PaletteList?.Palettes == null) return;
         var viewer = (ScrollViewer)sender;
-        if (viewer.VerticalOffset == viewer.ScrollableHeight)
+        if (viewer.VerticalOffset == viewer.ScrollableHeight && _lastScrolledOffset != viewer.VerticalOffset)
         {
             IsFetching = true;
             var newPalettes = await FetchPaletteList(0, Filtering);
@@ -388,6 +403,8 @@ internal partial class PalettesBrowser : Window
             PaletteList.Palettes.AddRange(newPalettes.Palettes);
             Sort();
             IsFetching = false;
+
+            _lastScrolledOffset = viewer.VerticalOffset;
         }
     }
 

+ 2 - 2
src/PixiEditor/Views/MainWindow.xaml

@@ -673,7 +673,7 @@
                                                                             </ItemsControl.ItemsPanel>
                                                                             <ItemsControl.ItemTemplate>
                                                                                 <DataTemplate>
-                                                                                    <palettes:PaletteColor Cursor="Hand" CornerRadius="0"
+                                                                                    <palettes:PaletteColorControl Cursor="Hand" CornerRadius="0"
                                                                                         views:Translator.TooltipKey="CLICK_SELECT_PRIMARY"
                                                                                         Width="22" Height="22" Color="{Binding}">
                                                                                         <b:Interaction.Triggers>
@@ -689,7 +689,7 @@
                                                                                                      AncestorType={x:Type ContextMenu}}}" />
                                                                                             </b:EventTrigger>
                                                                                         </b:Interaction.Triggers>
-                                                                                    </palettes:PaletteColor>
+                                                                                    </palettes:PaletteColorControl>
                                                                                 </DataTemplate>
                                                                             </ItemsControl.ItemTemplate>
                                                                         </ItemsControl>

+ 15 - 0
src/PixiEditor/Views/UserControls/Chip.xaml

@@ -0,0 +1,15 @@
+<UserControl x:Class="PixiEditor.Views.UserControls.Chip"
+             x:ClassModifier="internal"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:local="clr-namespace:PixiEditor.Views.UserControls"
+             mc:Ignorable="d" x:Name="chip"
+             d:DesignHeight="30" d:DesignWidth="60">
+    <Border VerticalAlignment="Center" Background="{StaticResource GlyphBrush}" BorderThickness="1"
+            BorderBrush="{Binding ElementName=chip, Path=OutlineColor}"
+            Padding="10 5" CornerRadius="2.5">
+        <TextBlock Text="{Binding ElementName=chip, Path=Text}" Foreground="White"/>
+    </Border>
+</UserControl>

+ 33 - 0
src/PixiEditor/Views/UserControls/Chip.xaml.cs

@@ -0,0 +1,33 @@
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using PixiEditor.Platform;
+using Brush = System.Drawing.Brush;
+
+namespace PixiEditor.Views.UserControls;
+
+internal partial class Chip : UserControl
+{
+    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
+        nameof(Text), typeof(string), typeof(Chip), new PropertyMetadata(default(string)));
+
+    public string Text
+    {
+        get { return (string)GetValue(TextProperty); }
+        set { SetValue(TextProperty, value); }
+    }
+
+    public static readonly DependencyProperty OutlineColorProperty = DependencyProperty.Register(
+        nameof(OutlineColor), typeof(SolidColorBrush), typeof(Chip), new PropertyMetadata(default(SolidColorBrush)));
+
+    public SolidColorBrush OutlineColor
+    {
+        get { return (SolidColorBrush)GetValue(OutlineColorProperty); }
+        set { SetValue(OutlineColorProperty, value); }
+    }
+    public Chip()
+    {
+        InitializeComponent();
+    }
+}
+

+ 4 - 3
src/PixiEditor/Views/UserControls/EditableTextBlock.xaml

@@ -7,14 +7,15 @@
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters" 
              xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
              xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours"
-             mc:Ignorable="d"
+             mc:Ignorable="d" x:Name="etb"
              d:DesignHeight="60" d:DesignWidth="100" Focusable="True">
     <Grid>
-        <TextBlock Foreground="Snow" MouseLeftButtonDown="TextBlock_MouseDown"
+        <TextBlock Foreground="{Binding ElementName=etb, Path=Foreground}" MouseLeftButtonDown="TextBlock_MouseDown"
                    TextTrimming="CharacterEllipsis" Name="textBlock"
                    Visibility="{Binding Path=TextBlockVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
                    Text="{Binding Path=Text, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Mode=TwoWay}" />
-        <TextBox MaxLength="{Binding Path=MaxChars, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Mode=TwoWay}" Style="{StaticResource DarkTextBoxStyle}"
+        <TextBox Foreground="{Binding ElementName=etb, Path=Foreground}"
+                 MaxLength="{Binding Path=MaxChars, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Mode=TwoWay}" Style="{StaticResource DarkTextBoxStyle}"
                  LostFocus="TextBox_LostFocus"
                  Text="{Binding Path=Text, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Mode=TwoWay}"
                  KeyDown="TextBox_KeyDown"

+ 9 - 0
src/PixiEditor/Views/UserControls/EditableTextBlock.xaml.cs

@@ -1,6 +1,7 @@
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
+using System.Windows.Media;
 using System.Windows.Threading;
 using PixiEditor.Models.Controllers;
 
@@ -41,6 +42,14 @@ internal partial class EditableTextBlock : UserControl
     public static readonly DependencyProperty MaxCharsProperty =
         DependencyProperty.Register(nameof(MaxChars), typeof(int), typeof(EditableTextBlock), new PropertyMetadata(int.MaxValue));
 
+    public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
+        nameof(Foreground), typeof(SolidColorBrush), typeof(EditableTextBlock), new PropertyMetadata(new SolidColorBrush(Colors.White)));
+
+    public SolidColorBrush Foreground
+    {
+        get { return (SolidColorBrush)GetValue(ForegroundProperty); }
+        set { SetValue(ForegroundProperty, value); }
+    }
 
     public event EventHandler<TextChangedEventArgs> OnSubmit;
 

+ 1 - 1
src/PixiEditor/Views/UserControls/Palettes/ColorReplacer.xaml

@@ -29,7 +29,7 @@
                     <Grid Visibility="{Binding ElementName=VisibilityCheckbox, Path=IsChecked, Converter={InverseBoolToVisibilityConverter}}"  Background="Transparent"/>
                 </Grid>
                 <StackPanel Name="MiddleStackPanel" Height="40" Orientation="Horizontal" HorizontalAlignment="Center">
-                    <local:PaletteColor Color="{Binding ElementName=uc, Path=ColorToReplace}"
+                    <local:PaletteColorControl Color="{Binding ElementName=uc, Path=ColorToReplace}"
                             Height="35" 
                             Width="35" 
                             views:Translator.TooltipKey="REPLACER_TOOLTIP"

+ 15 - 10
src/PixiEditor/Views/UserControls/Palettes/ColorReplacer.xaml.cs

@@ -2,6 +2,7 @@
 using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Media;
+using PixiEditor.Extensions.Palettes;
 using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 using BackendColors = PixiEditor.DrawingApi.Core.ColorsImpl.Colors;
 
@@ -9,15 +10,14 @@ namespace PixiEditor.Views.UserControls.Palettes;
 
 internal partial class ColorReplacer : UserControl
 {
-    public BackendColor ColorToReplace
+    public PaletteColor ColorToReplace
     {
-        get { return (BackendColor)GetValue(ColorToReplaceProperty); }
+        get { return (PaletteColor)GetValue(ColorToReplaceProperty); }
         set { SetValue(ColorToReplaceProperty, value); }
     }
 
-
     public static readonly DependencyProperty ColorToReplaceProperty =
-        DependencyProperty.Register(nameof(ColorToReplace), typeof(BackendColor), typeof(ColorReplacer), new PropertyMetadata(BackendColors.White));
+        DependencyProperty.Register(nameof(ColorToReplace), typeof(PaletteColor), typeof(ColorReplacer), new PropertyMetadata(PaletteColor.White));
 
 
     public Color HintColor
@@ -57,10 +57,15 @@ internal partial class ColorReplacer : UserControl
 
     private void UIElement_OnDrop(object sender, DragEventArgs e)
     {
-        if (e.Data.GetDataPresent(PaletteColor.PaletteColorDaoFormat))
+        if (e.Data.GetDataPresent(PaletteColorControl.PaletteColorDaoFormat))
         {
-            string hex = (string)e.Data.GetData(PaletteColor.PaletteColorDaoFormat);
-            ColorToReplace = BackendColor.Parse(hex).WithAlpha(255);
+            string hex = (string)e.Data.GetData(PaletteColorControl.PaletteColorDaoFormat);
+            if (hex is null)
+            {
+                return;
+            }
+
+            ColorToReplace = PaletteColor.Parse(hex);
         }
     }
 
@@ -71,10 +76,10 @@ internal partial class ColorReplacer : UserControl
 
     private void ReplaceButton_OnClick(object sender, RoutedEventArgs e)
     {
-        BackendColor first = ColorToReplace.WithAlpha(255);
+        PaletteColor first = ColorToReplace;
         Color rawSecond = NewColor;
 
-        BackendColor second = new BackendColor(rawSecond.R, rawSecond.G, rawSecond.B, 255);
+        PaletteColor second = new PaletteColor(rawSecond.R, rawSecond.G, rawSecond.B);
 
         var pack = (first, second);
         if (ReplaceColorsCommand.CanExecute(pack))
@@ -83,6 +88,6 @@ internal partial class ColorReplacer : UserControl
         }
 
         ColorToReplace = second;
-        NewColor = first.ToOpaqueMediaColor();
+        NewColor = new Color { R = first.R, G = first.G, B = first.B, A = 255 };
     }
 }

+ 2 - 2
src/PixiEditor/Views/UserControls/Palettes/CompactPaletteViewer.xaml

@@ -32,7 +32,7 @@
                 </ItemsControl.ItemsPanel>
                 <ItemsControl.ItemTemplate>
                     <DataTemplate>
-                        <local:PaletteColor views:Translator.TooltipKey="PALETTE_COLOR_TOOLTIP"
+                        <local:PaletteColorControl views:Translator.TooltipKey="PALETTE_COLOR_TOOLTIP"
                                             Cursor="Hand"
                                             Color="{Binding}" Width="20" Height="20" CornerRadius="0">
                             <b:Interaction.Triggers>
@@ -42,7 +42,7 @@
                                     CommandParameter="{Binding}" />
                                 </b:EventTrigger>
                             </b:Interaction.Triggers>
-                        </local:PaletteColor>
+                        </local:PaletteColorControl>
                     </DataTemplate>
                 </ItemsControl.ItemTemplate>
             </ItemsControl>

+ 2 - 2
src/PixiEditor/Views/UserControls/Palettes/PaletteColor.xaml → src/PixiEditor/Views/UserControls/Palettes/PaletteColorControl.xaml

@@ -1,4 +1,4 @@
-<UserControl x:Class="PixiEditor.Views.UserControls.Palettes.PaletteColor"
+<UserControl x:Class="PixiEditor.Views.UserControls.Palettes.PaletteColorControl"
              x:ClassModifier="internal"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -17,7 +17,7 @@
         <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
     </UserControl.Resources>
     <UserControl.Style>
-        <Style TargetType="{x:Type palettes:PaletteColor}">
+        <Style TargetType="{x:Type palettes:PaletteColorControl}">
             <Setter Property="Width" Value="36"/>
             <Setter Property="Height" Value="36"/>
         </Style>

+ 12 - 13
src/PixiEditor/Views/UserControls/Palettes/PaletteColor.xaml.cs → src/PixiEditor/Views/UserControls/Palettes/PaletteColorControl.xaml.cs

@@ -2,31 +2,30 @@
 using System.Windows.Controls;
 using System.Windows.Input;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Extensions.Palettes;
 
 namespace PixiEditor.Views.UserControls.Palettes;
 
-internal partial class PaletteColor : UserControl
+internal partial class PaletteColorControl : UserControl
 {
     public const string PaletteColorDaoFormat = "PixiEditor.PaletteColor";
 
-    public static readonly DependencyProperty ColorProperty = DependencyProperty.Register(nameof(Color), typeof(Color), typeof(PaletteColor), new PropertyMetadata(default(Color)));
+    public static readonly DependencyProperty ColorProperty = DependencyProperty.Register(nameof(Color), typeof(PaletteColor), typeof(PaletteColorControl), new PropertyMetadata(default(PaletteColor)));
 
-    public Color Color
+    public PaletteColor Color
     {
-        get { return (Color)GetValue(ColorProperty); }
+        get { return (PaletteColor)GetValue(ColorProperty); }
         set { SetValue(ColorProperty, value); }
     }
 
-
     public int? AssociatedKey
     {
         get { return (int?)GetValue(AssociatedKeyProperty); }
         set { SetValue(AssociatedKeyProperty, value); }
     }
 
-
     public static readonly DependencyProperty AssociatedKeyProperty =
-        DependencyProperty.Register(nameof(AssociatedKey), typeof(int?), typeof(PaletteColor), new PropertyMetadata(null));
+        DependencyProperty.Register(nameof(AssociatedKey), typeof(int?), typeof(PaletteColorControl), new PropertyMetadata(null));
 
     public CornerRadius CornerRadius
     {
@@ -36,26 +35,26 @@ internal partial class PaletteColor : UserControl
 
 
     public static readonly DependencyProperty CornerRadiusProperty =
-        DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), typeof(PaletteColor), new PropertyMetadata(new CornerRadius(5f)));
+        DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), typeof(PaletteColorControl), new PropertyMetadata(new CornerRadius(5f)));
 
     private Point clickPoint;
 
-    public PaletteColor()
+    public PaletteColorControl()
     {
         InitializeComponent();
     }
 
     private void PaletteColor_OnMouseMove(object sender, MouseEventArgs e)
     {
-        PaletteColor color = sender as PaletteColor;
-        if (color != null && e.LeftButton == MouseButtonState.Pressed && IsMouseCaptured)
+        PaletteColorControl colorControl = sender as PaletteColorControl;
+        if (colorControl != null && e.LeftButton == MouseButtonState.Pressed && IsMouseCaptured)
         {
             var movedDistance = (clickPoint - e.GetPosition(this)).Length;
             if (movedDistance > 10)
             {
                 DataObject data = new DataObject();
-                data.SetData(PaletteColor.PaletteColorDaoFormat, color.Color.ToString());
-                DragDrop.DoDragDrop(color, data, DragDropEffects.Move);
+                data.SetData(PaletteColorControl.PaletteColorDaoFormat, colorControl.Color.ToString());
+                DragDrop.DoDragDrop(colorControl, data, DragDropEffects.Move);
                 e.Handled = true;
             }
         }

+ 18 - 7
src/PixiEditor/Views/UserControls/Palettes/PaletteItem.xaml

@@ -14,27 +14,38 @@
     <UserControl.Resources>
         <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
     </UserControl.Resources>
-    <Grid Background="{StaticResource AccentColor}">
+    <Grid Background="{StaticResource AccentColor}" >
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="100*"/>
             <ColumnDefinition Width="95"/>
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
             <RowDefinition Height="60"/>
-            <RowDefinition Height="60*"/>
+            <RowDefinition Height="60*" MinHeight="45"/>
         </Grid.RowDefinitions>
         <StackPanel Orientation="Vertical" Grid.RowSpan="2" Grid.ColumnSpan="2">
-            <Separator Background="{StaticResource MainColor}"/>
-            <StackPanel Orientation="Horizontal">
-                <userControls:EditableTextBlock x:Name="titleTextBlock" OnSubmit="EditableTextBlock_OnSubmit" 
-                                         Text="{Binding Palette.Name, ElementName=paletteItem, Mode=TwoWay}" 
-                                         Foreground="White" FontSize="20" MaxChars="50"/>
+            <Separator Background="{StaticResource MainColor}" />
+            <DockPanel>
+                <StackPanel Orientation="Horizontal" DockPanel.Dock="Left">
+                    <Image Margin="0 5 5 0"
+                           Source="/Images/SupperterPack.png" Width="24"
+                           DockPanel.Dock="Right" HorizontalAlignment="Right"/>
+                    <userControls:EditableTextBlock x:Name="titleTextBlock" OnSubmit="EditableTextBlock_OnSubmit"
+                                                    Text="{Binding Palette.Name, ElementName=paletteItem, Mode=TwoWay}"
+                                                    FontSize="20" MaxChars="50"/>
                 <Button Visibility="{Binding ElementName=paletteItem, Path=IsMouseOver, Converter={StaticResource BoolToVisibilityConverter}}"
                         Click="RenameButton_Click"
                         Style="{StaticResource ImageButtonStyle}" Cursor="Hand" Width="20" Height="20">
                     <Image Source="/Images/Edit.png"/>
                 </Button>
             </StackPanel>
+                <!--<Image Margin="0 5 5 0"
+                       Source="/Images/SupperterPack.png" Width="24"
+                       DockPanel.Dock="Right" HorizontalAlignment="Right"/>-->
+                <!--<userControls:Chip OutlineColor="Gold" Margin="0 5 5 0"
+                                   Text="{Binding ElementName=paletteItem, Path=Palette.BundleName}"
+                                   DockPanel.Dock="Right" HorizontalAlignment="Right"/>-->
+            </DockPanel>
             <TextBlock Margin="0 5 0 0">
             </TextBlock>
         </StackPanel>

+ 4 - 4
src/PixiEditor/Views/UserControls/Palettes/PaletteViewer.xaml

@@ -83,7 +83,7 @@
                     </ItemsControl.ItemsPanel>
                     <ItemsControl.ItemTemplate>
                         <DataTemplate>
-                            <palettes:PaletteColor Cursor="Hand"
+                            <palettes:PaletteColorControl Cursor="Hand"
                                                    views:Translator.TooltipKey="PALETTE_COLOR_TOOLTIP"
                                                    AllowDrop="True" Color="{Binding}"
                                                Margin="2.5"
@@ -97,7 +97,7 @@
                                     CommandParameter="{Binding}" />
                                     </b:EventTrigger>
                                 </b:Interaction.Triggers>
-                                <palettes:PaletteColor.ContextMenu>
+                                <palettes:PaletteColorControl.ContextMenu>
                                     <ContextMenu>
                                         <MenuItem views:Translator.Key="CHOOSE" Foreground="White" Click="MenuItem_OnClick"
                                               CommandParameter="{Binding}"/>
@@ -108,8 +108,8 @@
                                                       CommandParameter="{Binding}"
                                                       Click="ReplaceColor_OnClick"/>
                                     </ContextMenu>
-                                </palettes:PaletteColor.ContextMenu>
-                            </palettes:PaletteColor>
+                                </palettes:PaletteColorControl.ContextMenu>
+                            </palettes:PaletteColorControl>
                         </DataTemplate>
                     </ItemsControl.ItemTemplate>
                 </ItemsControl>

+ 28 - 22
src/PixiEditor/Views/UserControls/Palettes/PaletteViewer.xaml.cs

@@ -4,6 +4,8 @@ using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Media;
 using Microsoft.Win32;
+using PixiEditor.Extensions.Palettes;
+using PixiEditor.Extensions.Palettes.Parsers;
 using PixiEditor.Helpers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataProviders;
@@ -11,7 +13,6 @@ using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.IO;
 using PixiEditor.Views.Dialogs;
-using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 
 namespace PixiEditor.Views.UserControls.Palettes;
 
@@ -20,18 +21,18 @@ namespace PixiEditor.Views.UserControls.Palettes;
 /// </summary>
 internal partial class PaletteViewer : UserControl
 {
-    public static readonly DependencyProperty SwatchesProperty = DependencyProperty.Register(nameof(Swatches), typeof(WpfObservableRangeCollection<BackendColor>), typeof(PaletteViewer), new PropertyMetadata(default(WpfObservableRangeCollection<BackendColor>)));
+    public static readonly DependencyProperty SwatchesProperty = DependencyProperty.Register(nameof(Swatches), typeof(WpfObservableRangeCollection<PaletteColorControl>), typeof(PaletteViewer), new PropertyMetadata(default(WpfObservableRangeCollection<PaletteColorControl>)));
 
-    public WpfObservableRangeCollection<BackendColor> Swatches
+    public WpfObservableRangeCollection<PaletteColor> Swatches
     {
-        get => (WpfObservableRangeCollection<BackendColor>)GetValue(SwatchesProperty);
+        get => (WpfObservableRangeCollection<PaletteColor>)GetValue(SwatchesProperty);
         set => SetValue(SwatchesProperty, value);
     }
-    public static readonly DependencyProperty ColorsProperty = DependencyProperty.Register(nameof(Colors), typeof(WpfObservableRangeCollection<BackendColor>), typeof(PaletteViewer));
+    public static readonly DependencyProperty ColorsProperty = DependencyProperty.Register(nameof(Colors), typeof(WpfObservableRangeCollection<PaletteColorControl>), typeof(PaletteViewer));
 
-    public WpfObservableRangeCollection<BackendColor> Colors
+    public WpfObservableRangeCollection<PaletteColor> Colors
     {
-        get { return (WpfObservableRangeCollection<BackendColor>)GetValue(ColorsProperty); }
+        get { return (WpfObservableRangeCollection<PaletteColor>)GetValue(ColorsProperty); }
         set { SetValue(ColorsProperty, value); }
     }
 
@@ -41,7 +42,6 @@ internal partial class PaletteViewer : UserControl
         set { SetValue(HintColorProperty, value); }
     }
 
-
     public static readonly DependencyProperty HintColorProperty =
         DependencyProperty.Register(nameof(HintColor), typeof(Color), typeof(PaletteViewer), new PropertyMetadata(System.Windows.Media.Colors.Transparent));
 
@@ -101,10 +101,10 @@ internal partial class PaletteViewer : UserControl
     private void RemoveColorMenuItem_OnClick(object sender, RoutedEventArgs e)
     {
         MenuItem menuItem = (MenuItem)sender;
-        BackendColor color = (BackendColor)menuItem.CommandParameter;
-        if (Colors.Contains(color))
+        PaletteColor colorControl = (PaletteColor)menuItem.CommandParameter;
+        if (Colors.Contains(colorControl))
         {
-            Colors.Remove(color);
+            Colors.Remove(colorControl);
         }
     }
 
@@ -184,9 +184,11 @@ internal partial class PaletteViewer : UserControl
             {
                 return;
             }
+
+            List<PaletteColor> paletteColors = colors.Select(x => new PaletteColor(x.R, x.G, x.B)).ToList();
             
             e.Effects = DragDropEffects.Copy;
-            Colors.AddRange(colors.Where(x => !Colors.Contains(x)).ToList());
+            Colors.AddRange(paletteColors.Where(x => !Colors.Contains(new PaletteColor(x.R, x.G, x.B))).ToList());
             e.Handled = true;
             return;
         }
@@ -219,17 +221,21 @@ internal partial class PaletteViewer : UserControl
 
     private void PaletteColor_Drop(object sender, DragEventArgs e)
     {
-        if (e.Data.GetDataPresent(PaletteColor.PaletteColorDaoFormat))
+        if (e.Data.GetDataPresent(PaletteColorControl.PaletteColorDaoFormat))
         {
-            string data = (string)e.Data.GetData(PaletteColor.PaletteColorDaoFormat);
-            BackendColor color = BackendColor.Parse(data);
-            if (Colors.Contains(color))
+            string data = (string)e.Data.GetData(PaletteColorControl.PaletteColorDaoFormat);
+
+            PaletteColor paletteColor = PaletteColor.Parse(data);
+            if (Colors.Contains(paletteColor))
             {
-                PaletteColor paletteColor = sender as PaletteColor;
-                int currIndex = Colors.IndexOf(color);
-                int newIndex = Colors.IndexOf(paletteColor.Color);
-                Colors.RemoveAt(currIndex);
-                Colors.Insert(newIndex, color);
+                PaletteColorControl paletteColorControl = sender as PaletteColorControl;
+                int currIndex = Colors.IndexOf(paletteColor);
+                if (paletteColorControl != null)
+                {
+                    int newIndex = Colors.IndexOf(paletteColorControl.Color);
+                    Colors.RemoveAt(currIndex);
+                    Colors.Insert(newIndex, paletteColor);
+                }
             }
         }
     }
@@ -243,7 +249,7 @@ internal partial class PaletteViewer : UserControl
     private void ReplaceColor_OnClick(object sender, RoutedEventArgs e)
     {
         MenuItem menuItem = (MenuItem)sender;
-        BackendColor color = (BackendColor)menuItem.CommandParameter;
+        PaletteColor color = (PaletteColor)menuItem.CommandParameter;
         Replacer.ColorToReplace = color;
         Replacer.VisibilityCheckbox.IsChecked = false;
     }

+ 4 - 4
src/PixiEditor/Views/UserControls/SwatchesView.xaml

@@ -37,7 +37,7 @@
             </ItemsControl.ItemsPanel>
             <ItemsControl.ItemTemplate>
                 <DataTemplate>
-                    <palettes:PaletteColor Cursor="Hand" Color="{Binding}" Margin="0 5 5 5">
+                    <palettes:PaletteColorControl Cursor="Hand" Color="{Binding}" Margin="0 5 5 5">
                         <i:Interaction.Triggers>
                             <i:EventTrigger EventName="MouseLeftButtonUp">
                                 <i:InvokeCommandAction
@@ -45,14 +45,14 @@
                                     CommandParameter="{Binding}" />
                             </i:EventTrigger>
                         </i:Interaction.Triggers>
-                        <palettes:PaletteColor.ContextMenu>
+                        <palettes:PaletteColorControl.ContextMenu>
                             <ContextMenu>
                                 <MenuItem Header="Remove" Foreground="White"
                                           Command="{cmds:Command PixiEditor.Colors.RemoveSwatch, UseProvided=True}"
                                           CommandParameter="{Binding}" />
                             </ContextMenu>
-                        </palettes:PaletteColor.ContextMenu>
-                    </palettes:PaletteColor>
+                        </palettes:PaletteColorControl.ContextMenu>
+                    </palettes:PaletteColorControl>
                 </DataTemplate>
             </ItemsControl.ItemTemplate>
         </ItemsControl>

+ 2 - 2
src/SampleExtension/SampleExtension.cs

@@ -13,8 +13,8 @@ public class SampleExtension : Extension
     protected override void OnInitialized()
     {
         var popup = Api.WindowProvider.CreatePopupWindow("Hello World!", new TextBlock { Text = "Hello World!" });
+        Api.PaletteProvider.AddPalette(new ExtensionPalette("Test Palette",
+            new List<PaletteColor>() { new PaletteColor(0, 0, 0) }));
         popup.ShowDialog();
-
-        Api.PaletteProvider.AddPalette(new ExtensionPalette("Sample Palette", new List<PaletteColor>(){new PaletteColor(255, 125, 75)}));
     }
 }