Browse Source

overengineered parsers wip

flabbet 3 years ago
parent
commit
d31c046111
31 changed files with 289 additions and 500 deletions
  1. 19 0
      PixiEditor/Helpers/Extensions/DirectoryExtensions.cs
  2. 4 5
      PixiEditor/Helpers/Extensions/ServiceCollectionHelpers.cs
  3. 0 9
      PixiEditor/Models/DataHolders/LospecPalette/LospecUser.cs
  4. 0 17
      PixiEditor/Models/DataHolders/LospecPalette/Palette.cs
  5. 17 0
      PixiEditor/Models/DataHolders/Palettes/Palette.cs
  6. 13 0
      PixiEditor/Models/DataHolders/Palettes/PaletteFileType.cs
  7. 1 1
      PixiEditor/Models/DataHolders/Palettes/PaletteList.cs
  8. 44 0
      PixiEditor/Models/DataProviders/LocalPalettesFetcher.cs
  9. 10 0
      PixiEditor/Models/DataProviders/PaletteListDataSource.cs
  10. 1 2
      PixiEditor/Models/ExternalServices/LospecPaletteFetcher.cs
  11. 0 14
      PixiEditor/Models/IO/JascPalFile/JascFileData.cs
  12. 15 6
      PixiEditor/Models/IO/JascPalFile/JascFileParser.cs
  13. 35 0
      PixiEditor/Models/IO/PaletteFileData.cs
  14. 12 0
      PixiEditor/Models/IO/PaletteFileParser.cs
  15. 12 11
      PixiEditor/Models/Tools/BitmapOperationTool.cs
  16. 29 346
      PixiEditor/Models/Undo/StorageBasedChange.cs
  17. 3 3
      PixiEditor/Models/Undo/UndoLayer.cs
  18. 13 1
      PixiEditor/ViewModels/SubViewModels/Main/ColorsViewModel.cs
  19. 2 0
      PixiEditor/ViewModels/ViewModelMain.cs
  20. 3 3
      PixiEditor/Views/Dialogs/PalettesBrowser.xaml
  21. 8 7
      PixiEditor/Views/Dialogs/PalettesBrowser.xaml.cs
  22. 2 2
      PixiEditor/Views/MainWindow.xaml
  23. 1 1
      PixiEditor/Views/UserControls/Palettes/PaletteColor.xaml
  24. 1 2
      PixiEditor/Views/UserControls/Palettes/PaletteColor.xaml.cs
  25. 1 1
      PixiEditor/Views/UserControls/Palettes/PaletteColorAdder.xaml
  26. 2 1
      PixiEditor/Views/UserControls/Palettes/PaletteColorAdder.xaml.cs
  27. 8 19
      PixiEditor/Views/UserControls/Palettes/PaletteItem.xaml
  28. 6 26
      PixiEditor/Views/UserControls/Palettes/PaletteItem.xaml.cs
  29. 8 8
      PixiEditor/Views/UserControls/Palettes/PaletteViewer.xaml
  30. 14 10
      PixiEditor/Views/UserControls/Palettes/PaletteViewer.xaml.cs
  31. 5 5
      PixiEditor/Views/UserControls/SwatchesView.xaml

+ 19 - 0
PixiEditor/Helpers/Extensions/DirectoryExtensions.cs

@@ -0,0 +1,19 @@
+using System.Linq;
+
+namespace PixiEditor.Helpers.Extensions
+{
+    public static class DirectoryExtensions
+    {
+        /// <summary>
+        ///     Gets files in directory with multiple filters.
+        /// </summary>
+        /// <param name="sourceFolder">Folder to get files from.</param>
+        /// <param name="filters">Filters separated by '|' character.</param>
+        /// <param name="searchOption">Search option for directory.</param>
+        /// <returns>List of file paths found.</returns>
+        public static string[] GetFiles(string sourceFolder, string filters, System.IO.SearchOption searchOption)
+        {
+            return filters.Split('|').SelectMany(filter => System.IO.Directory.GetFiles(sourceFolder, filter, searchOption)).ToArray();
+        }
+    }
+}

+ 4 - 5
PixiEditor/Helpers/Extensions/ServiceCollectionHelpers.cs

@@ -1,17 +1,14 @@
 using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Controllers.Shortcuts;
+using PixiEditor.Models.IO;
+using PixiEditor.Models.IO.JascPalFile;
 using PixiEditor.Models.Services;
 using PixiEditor.Models.Tools;
 using PixiEditor.Models.Tools.Tools;
 using PixiEditor.Models.UserPreferences;
 using PixiEditor.ViewModels;
 using PixiEditor.ViewModels.SubViewModels.Main;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 
 namespace PixiEditor.Helpers.Extensions
 {
@@ -57,6 +54,8 @@ namespace PixiEditor.Helpers.Extensions
                 .AddSingleton<Tool, ColorPickerTool>()
                 .AddSingleton<Tool, BrightnessTool>()
                 .AddSingleton<Tool, ZoomTool>()
+                // Palette Parsers
+                .AddSingleton<PaletteFileParser, JascFileParser>()
                 // Other
                 .AddSingleton<DocumentProvider>();
     }

+ 0 - 9
PixiEditor/Models/DataHolders/LospecPalette/LospecUser.cs

@@ -1,9 +0,0 @@
-namespace PixiEditor.Models.DataHolders.LospecPalette
-{
-    public class LospecUser
-    {
-        public string Name { get; set; }
-        public string Slug { get; set; }
-        public string Url => $"https://lospec.com/{Slug}";
-    }
-}

+ 0 - 17
PixiEditor/Models/DataHolders/LospecPalette/Palette.cs

@@ -1,17 +0,0 @@
-using PixiEditor.Models.DataHolders.LospecPalette;
-using SkiaSharp;
-using System.Collections.Generic;
-
-namespace PixiEditor.Models.DataHolders
-{
-    public class Palette
-    {
-        public string Title { get; set; }
-        public string Slug { get; set; }
-        public string Url => $"https://lospec.com/palette-list/{Slug}";
-        public LospecUser User { get; set; }
-        public ObservableCollection<string> Colors { get; set; }
-        public int Likes { get; set; }
-        public string[] Tags { get; set; }
-    }
-}

+ 17 - 0
PixiEditor/Models/DataHolders/Palettes/Palette.cs

@@ -0,0 +1,17 @@
+namespace PixiEditor.Models.DataHolders.Palettes
+{
+    public class Palette
+    {
+        public string Title { get; set; }
+        public ObservableCollection<string> Colors { get; set; }
+        public string[] Tags { get; set; }
+
+        public Palette() { }
+        public Palette(string title, ObservableCollection<string> colors, string[] tags)
+        {
+            Title = title;
+            Colors = colors;
+            Tags = tags;
+        }
+    }
+}

+ 13 - 0
PixiEditor/Models/DataHolders/Palettes/PaletteFileType.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PixiEditor.Models.DataHolders.Palettes
+{
+    public enum PaletteFileType
+    {
+        JascPal
+    }
+}

+ 1 - 1
PixiEditor/Models/DataHolders/LospecPalette/PaletteList.cs → PixiEditor/Models/DataHolders/Palettes/PaletteList.cs

@@ -1,4 +1,4 @@
-namespace PixiEditor.Models.DataHolders
+namespace PixiEditor.Models.DataHolders.Palettes
 {
     public class PaletteList
     {

+ 44 - 0
PixiEditor/Models/DataProviders/LocalPalettesFetcher.cs

@@ -0,0 +1,44 @@
+using PixiEditor.Helpers.Extensions;
+using PixiEditor.Models.DataHolders;
+using PixiEditor.Models.DataHolders.Palettes;
+using PixiEditor.Models.IO;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace PixiEditor.Models.DataProviders
+{
+    public class LocalPalettesFetcher : PaletteListDataSource
+    {
+        public string PathToPalettesFolder { get; private set; } = Path.Join(
+            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+            "PixiEditor", "Palettes");
+
+        public IEnumerable<PaletteFileParser> AvailableParsers { get; private set; }
+
+        public override async Task<PaletteList> FetchPaletteList()
+        {
+            string[] files = DirectoryExtensions.GetFiles(PathToPalettesFolder, string.Join("|", AvailableParsers.SelectMany(x => x.SupportedFileExtensions)), SearchOption.TopDirectoryOnly);
+
+            PaletteList result = new PaletteList();
+            result.Palettes = new ObservableCollection<Palette>();
+            for (int i = 0; i < files.Length; i++)
+            {
+                string filePath = files[i];
+                string extension = Path.GetExtension(filePath);
+                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 ObservableCollection<string>(fileData.GetHexColors()), fileData.Tags));
+                }
+            }
+
+            result.FetchedCorrectly = true;
+            return result;
+        }
+    }
+}

+ 10 - 0
PixiEditor/Models/DataProviders/PaletteListDataSource.cs

@@ -0,0 +1,10 @@
+using PixiEditor.Models.DataHolders.Palettes;
+using System.Threading.Tasks;
+
+namespace PixiEditor.Models.DataProviders
+{
+    public abstract class PaletteListDataSource
+    {
+        public abstract Task<PaletteList> FetchPaletteList();
+    }
+}

+ 1 - 2
PixiEditor/Models/ExternalServices/LospecPaletteFetcher.cs

@@ -1,8 +1,7 @@
 using Newtonsoft.Json;
 using PixiEditor.Models.DataHolders;
+using PixiEditor.Models.DataHolders.Palettes;
 using PixiEditor.Models.Enums;
-using System;
-using System.Linq;
 using System.Net;
 using System.Net.Http;
 using System.Threading.Tasks;

+ 0 - 14
PixiEditor/Models/IO/JascPalFile/JascFileData.cs

@@ -1,14 +0,0 @@
-using SkiaSharp;
-
-namespace PixiEditor.Models.IO.JascPalFile;
-
-public class JascFileData
-{
-    public SKColor[] Colors { get; set; }
-
-    public JascFileData(SKColor[] colors)
-    {
-        Colors = colors;
-    }
-
-}

+ 15 - 6
PixiEditor/Models/IO/JascPalFile/JascFileParser.cs

@@ -1,4 +1,5 @@
 using System.IO;
+using System.Threading.Tasks;
 using SkiaSharp;
 
 namespace PixiEditor.Models.IO.JascPalFile;
@@ -6,11 +7,15 @@ namespace PixiEditor.Models.IO.JascPalFile;
 /// <summary>
 ///     This class is responsible for parsing JASC-PAL files. Which holds the color palette data.
 /// </summary>
-public static class JascFileParser
+public class JascFileParser : PaletteFileParser
 {
-    public static JascFileData Parse(string path)
+    private static readonly string[] _supportedFileExtensions = new string[] { ".pal" };
+    public override string[] SupportedFileExtensions => _supportedFileExtensions;
+    public override string FileName => "Jasc Palette";
+
+    public static async Task<PaletteFileData> ParseFile(string path)
     {
-        string fileContent = File.ReadAllText(path);
+        string fileContent = await File.ReadAllTextAsync(path);
         string[] lines = fileContent.Split('\n');
         string fileType = lines[0];
         string magicBytes = lines[1];
@@ -24,13 +29,13 @@ public static class JascFileParser
                 colors[i] = new SKColor(byte.Parse(colorData[0]), byte.Parse(colorData[1]), byte.Parse(colorData[2]));
             }
 
-            return new JascFileData(colors);
+            return new PaletteFileData(colors);
         }
 
         throw new JascFileException("Invalid JASC-PAL file.");
     }
 
-    public static void Save(string path, JascFileData data)
+    public static async Task SaveFile(string path, PaletteFileData data)
     {
         string fileContent = "JASC-PAL\n0100\n" + data.Colors.Length;
         for (int i = 0; i < data.Colors.Length; i++)
@@ -38,9 +43,13 @@ public static class JascFileParser
             fileContent += "\n" + data.Colors[i].Red + " " + data.Colors[i].Green + " " + data.Colors[i].Blue;
         }
 
-        File.WriteAllText(path, fileContent);
+        await File.WriteAllTextAsync(path, fileContent);
     }
 
+    public override async Task<PaletteFileData> Parse(string path) => await ParseFile(path);
+
+    public override async Task Save(string path, PaletteFileData data) => await SaveFile(path, data);
+
     private static bool ValidateFile(string fileType, string magicBytes)
     {
         return fileType.Length > 7 && fileType[..8].ToUpper() == "JASC-PAL" && magicBytes.Length > 3 && magicBytes[..4] == "0100";

+ 35 - 0
PixiEditor/Models/IO/PaletteFileData.cs

@@ -0,0 +1,35 @@
+using SkiaSharp;
+using System;
+using System.Collections.Generic;
+
+namespace PixiEditor.Models.IO
+{
+    public class PaletteFileData
+    {
+        public string Title { get; set; }
+        public SKColor[] Colors { get; set; }
+        public string[] Tags { get; set; }
+
+        public PaletteFileData(SKColor[] colors)
+        {
+            Colors = colors;
+        }
+
+        public PaletteFileData(string title, SKColor[] colors, string[] tags)
+        {
+            Title = title;
+            Colors = colors;
+            Tags = tags;
+        }
+
+        public string[] GetHexColors()
+        {
+            string[] colors = new string[Colors.Length];
+            for (int i = 0; i < Colors.Length; i++)
+            {
+                colors[i] = Colors[i].ToString();
+            }
+            return colors;
+        }
+    }
+}

+ 12 - 0
PixiEditor/Models/IO/PaletteFileParser.cs

@@ -0,0 +1,12 @@
+using System.Threading.Tasks;
+
+namespace PixiEditor.Models.IO
+{
+    public abstract class PaletteFileParser
+    {
+        public abstract Task<PaletteFileData> Parse(string path);
+        public abstract Task Save(string path, PaletteFileData data);
+        public abstract string FileName { get; }
+        public abstract string[] SupportedFileExtensions { get; }
+    }
+}

+ 12 - 11
PixiEditor/Models/Tools/BitmapOperationTool.cs

@@ -1,9 +1,11 @@
-using PixiEditor.Models.DataHolders;
+using System;
+using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.Undo;
 using SkiaSharp;
 using System.Collections.Generic;
+using PixiEditor.Models.Tools.ToolSettings.Settings;
 
 namespace PixiEditor.Models.Tools
 {
@@ -69,16 +71,15 @@ namespace PixiEditor.Models.Tools
                 finalRect.Inflate(halfSize, halfSize);
             }
 
-            //if (toolSessionRect.IsEmpty)
-            //{
-            //    finalRect = SKRectI.Create(doc.ActiveLayer.OffsetX, doc.ActiveLayer.OffsetY, doc.ActiveLayer.Width, doc.ActiveLayer.Height);
-            //}
+            if (toolSessionRect.IsEmpty)
+            {
+                finalRect = SKRectI.Create(doc.ActiveLayer.OffsetX, doc.ActiveLayer.OffsetY, doc.ActiveLayer.Width, doc.ActiveLayer.Height);
+            }
 
-            //Commented, because rect based undo is still a little buggy
-            //if (UseDocumentRectForUndo)
-            //{
-            //    finalRect = SKRectI.Create(0, 0, doc.Width, doc.Height);
-            //}
+            if (UseDocumentRectForUndo)
+            {
+                finalRect = SKRectI.Create(0, 0, doc.Width, doc.Height);
+            }
 
             if (_customRectReported)
             {
@@ -90,4 +91,4 @@ namespace PixiEditor.Models.Tools
             _change = new StorageBasedChange(doc, new[] { new LayerChunk(doc.ActiveLayer, finalRect) });
         }
     }
-}
+}

+ 29 - 346
PixiEditor/Models/Undo/StorageBasedChange.cs

@@ -2,12 +2,14 @@
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.IO;
 using PixiEditor.Models.Layers;
+using SkiaSharp;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Text;
+using System.Windows;
 
 namespace PixiEditor.Models.Undo
 {
@@ -16,13 +18,13 @@ namespace PixiEditor.Models.Undo
     /// </summary>
     public class StorageBasedChange : IDisposable
     {
-        public static string DefaultUndoChangeLocation => Path.Join(Path.GetTempPath(), "PixiEditor", "UndoStack");
+        public static string DefaultUndoChangeLocation { get; } = Path.Join(Path.GetTempPath(), "PixiEditor", Guid.NewGuid().ToString(), "UndoStack");
 
         public string UndoChangeLocation { get; set; }
 
         public UndoLayer[] StoredLayers { get; set; }
 
-        private List<Guid> layersToStore;
+        private List<Guid> layersToStore = new List<Guid>();
         public Document Document { get; }
 
         public StorageBasedChange(Document doc, IEnumerable<Layer> layers, bool saveOnStartup = true)
@@ -56,7 +58,7 @@ namespace PixiEditor.Models.Undo
             }
 
             UndoChangeLocation = DefaultUndoChangeLocation;
-            GenerateUndoLayers();
+            GenerateUndoLayers(layerChunks);
             if (saveOnStartup)
             {
                 SaveLayersOnDevice();
@@ -87,19 +89,14 @@ namespace PixiEditor.Models.Undo
                 layersToStore.Add(layer.GuidValue);
             }
 
+            UndoChangeLocation = undoChangeLocation;
+            GenerateUndoLayers(layerChunks);
             if (saveOnStartup)
             {
                 SaveLayersOnDevice();
             }
         }
 
-        public void Dispose()
-        {
-            var layers = LoadLayersFromDevice();
-            foreach (var layer in layers)
-                layer.LayerBitmap.Dispose();
-        }
-
         public void SaveLayersOnDevice()
         {
             int i = 0;
@@ -158,14 +155,15 @@ namespace PixiEditor.Models.Undo
                 var bitmap = Importer.LoadFromGZippedBytes(storedLayer.StoredPngLayerName);
                 layers[i] = new Layer(storedLayer.Name, bitmap, storedLayer.MaxWidth, storedLayer.MaxHeight)
                 {
-                    Offset = new System.Windows.Thickness(storedLayer.OffsetX, storedLayer.OffsetY, 0, 0),
+                    Width = storedLayer.Width,
+                    Height = storedLayer.Height,
+                    Offset = new Thickness(storedLayer.OffsetX, storedLayer.OffsetY, 0, 0),
                     Opacity = storedLayer.Opacity,
                     IsVisible = storedLayer.IsVisible,
                     IsActive = storedLayer.IsActive,
-                    Width = storedLayer.Width,
-                    Height = storedLayer.Height,
                     LayerHighlightColor = storedLayer.LayerHighlightColor
                 };
+
                 layers[i].ChangeGuid(storedLayer.LayerGuid);
 
                 File.Delete(StoredLayers[i].StoredPngLayerName);
@@ -209,14 +207,19 @@ namespace PixiEditor.Models.Undo
         /// <param name="undoRedoProcess">Process that is invoked on redo and undo.</param>
         /// <param name="processArgs">Custom parameters for undo and redo process.</param>
         /// <param name="description">Undo change description.</param>
-        /// <returns>UndoManager ready Change instance.</returns>
+        /// <returns>UndoManager ready 'Change' instance.</returns>
         public Change ToChange(Action<Layer[], UndoLayer[], object[]> undoRedoProcess, object[] processArgs, string description = "")
         {
             Action<object[]> finalProcess = processParameters =>
             {
-
                 Layer[] layers = LoadLayersFromDevice();
-                GenerateUndoLayers();
+                LayerChunk[] chunks = new LayerChunk[layers.Length];
+                for (int i = 0; i < layers.Length; i++)
+                {
+                    chunks[i] = new LayerChunk(layers[i], StoredLayers[i].SerializedRect);
+                }
+
+                GenerateUndoLayers(chunks);
 
                 SaveLayersOnDevice();
 
@@ -313,7 +316,7 @@ namespace PixiEditor.Models.Undo
         /// <summary>
         /// Generates UndoLayer[] StoredLayers data.
         /// </summary>
-        private void GenerateUndoLayers()
+        private void GenerateUndoLayers(LayerChunk[] chunks)
         {
             StoredLayers = new UndoLayer[layersToStore.Count];
             int i = 0;
@@ -325,16 +328,15 @@ namespace PixiEditor.Models.Undo
                     throw new ArgumentException("Provided document doesn't contain selected layer");
                 }
 
-                layer.ClipCanvas();
-
                 int index = Document.Layers.IndexOf(layer);
-                string pngName = layer.Name + Guid.NewGuid().ToString();
+                string fileName = layer.Name + Guid.NewGuid();
                 StoredLayers[i] = new UndoLayer(
                     Path.Join(
                         UndoChangeLocation,
-                        Convert.ToBase64String(Encoding.UTF8.GetBytes(pngName)) + ".png"),
+                        Convert.ToBase64String(Encoding.UTF8.GetBytes(fileName)) + ".undoimg"),
                     layer,
-                    index);
+                    index,
+                    chunks[i].AbsoluteChunkRect);
                 i++;
             }
         }
@@ -343,11 +345,11 @@ namespace PixiEditor.Models.Undo
         {
             if (args.Length > 0 && args[0] is Document document)
             {
-                var ls = document.LayerStructure.CloneGroups();
-
                 for (int i = 0; i < layers.Length; i++)
                 {
                     Layer layer = layers[i];
+                    UndoLayer layerData = data[i];
+                    var foundLayer = document.Layers.FirstOrDefault(x => x.GuidValue == layerData.LayerGuid);
 
                     if (foundLayer != null)
                     {
@@ -359,17 +361,13 @@ namespace PixiEditor.Models.Undo
                         document.Layers.Insert(layerData.LayerIndex, layer);
                     }
 
-                    if (data[i].IsActive)
+                    if (layerData.IsActive)
                     {
-                        document.SetMainActiveLayer(data[i].LayerIndex);
+                        document.SetMainActiveLayer(layerData.LayerIndex);
                     }
                 }
-
-                document.BuildLayerStructureProcess(new object[] { ls });
             }
         }
-    }
-}
 
         private static void ApplyChunkToLayer(Layer layer, SKRectI rect, Surface chunk)
         {
@@ -388,319 +386,4 @@ namespace PixiEditor.Models.Undo
             }
         }
     }
-}
-
-//            UndoChangeLocation = undoChangeLocation;
-//            GenerateUndoLayers(layerChunks);
-//            if (saveOnStartup)
-//            {
-//                SaveLayersOnDevice();
-//            }
-//        }
-
-//        public void SaveLayersOnDevice()
-//        {
-//            int i = 0;
-//            foreach (var layerGuid in layersToStore)
-//            {
-//                Layer layer = Document.Layers.First(x => x.GuidValue == layerGuid);
-//                UndoLayer storedLayer = StoredLayers[i];
-//                if (Directory.Exists(Path.GetDirectoryName(storedLayer.StoredPngLayerName)))
-//                {
-//                    // Calculate absolute rect to relative rect
-//                    SKRectI finalRect = SKRectI.Create(
-//                        storedLayer.SerializedRect.Left - layer.OffsetX,
-//                        storedLayer.SerializedRect.Top - layer.OffsetY,
-//                        storedLayer.SerializedRect.Width,
-//                        storedLayer.SerializedRect.Height);
-
-//                    using var image = layer.LayerBitmap.SkiaSurface.Snapshot();
-//                    Surface targetSizeSurface = new Surface(finalRect.Width, finalRect.Height);
-
-//                    targetSizeSurface.SkiaSurface.Canvas.DrawImage(image, finalRect, SKRect.Create(0, 0, finalRect.Width, finalRect.Height), Surface.ReplacingPaint);
-
-//                    Exporter.SaveAsGZippedBytes(storedLayer.StoredPngLayerName, targetSizeSurface);
-//                }
-
-//                i++;
-//            }
-
-//            layersToStore = new List<Guid>();
-//        }
-
-//        /// <summary>
-//        /// Loads saved layers from disk.
-//        /// </summary>
-//        /// <returns>Array of saved layers.</returns>
-//        public Layer[] LoadLayersFromDevice()
-//        {
-//            Layer[] layers = new Layer[StoredLayers.Length];
-//            for (int i = 0; i < StoredLayers.Length; i++)
-//            {
-//                UndoLayer storedLayer = StoredLayers[i];
-//                var bitmap = Importer.LoadFromGZippedBytes(storedLayer.StoredPngLayerName);
-//                layers[i] = new Layer(storedLayer.Name, bitmap)
-//                {
-//                    Width = storedLayer.Width,
-//                    Height = storedLayer.Height,
-//                    Offset = new Thickness(storedLayer.OffsetX, storedLayer.OffsetY, 0, 0),
-//                    Opacity = storedLayer.Opacity,
-//                    MaxWidth = storedLayer.MaxWidth,
-//                    MaxHeight = storedLayer.MaxHeight,
-//                    IsVisible = storedLayer.IsVisible,
-//                    IsActive = storedLayer.IsActive,
-//                    LayerHighlightColor = storedLayer.LayerHighlightColor
-//                };
-
-//                layers[i].ChangeGuid(storedLayer.LayerGuid);
-
-//                File.Delete(StoredLayers[i].StoredPngLayerName);
-//            }
-
-//            layersToStore = layers.Select(x => x.GuidValue).ToList();
-//            return layers;
-//        }
-
-//        /// <summary>
-//        ///     Creates UndoManager ready Change instance, where undo process loads layers from device, and redo saves them.
-//        /// </summary>
-//        /// <param name="undoProcess">Method that is invoked on undo, with loaded layers parameter and UndoLayer array data.</param>
-//        /// <param name="processArgs">Custom parameters for undo process.</param>
-//        /// <param name="redoProcess">Method that is invoked on redo with custom object array parameters.</param>
-//        /// <param name="redoProcessParameters">Parameters for redo process.</param>
-//        /// <param name="description">Undo change description.</param>
-//        /// <returns>UndoManager ready Change instance.</returns>
-//        public Change ToChange(Action<Layer[], UndoLayer[], object[]> undoProcess, object[] processArgs, Action<object[]> redoProcess, object[] redoProcessParameters, string description = "")
-//        {
-//            Action<object[]> finalUndoProcess = processParameters =>
-//            {
-//                Layer[] layers = LoadLayersFromDevice();
-//                undoProcess(layers, StoredLayers, processParameters);
-//            };
-
-//            Action<object[]> finalRedoProcess = parameters =>
-//            {
-//                SaveLayersOnDevice();
-//                redoProcess(parameters);
-//            };
-
-//            var change = new Change(finalUndoProcess, processArgs, finalRedoProcess, redoProcessParameters, description);
-//            change.DisposeProcess = (_, _) => Dispose();
-//            return change;
-//        }
-
-//        /// <summary>
-//        ///     Creates UndoManager ready Change instance, where undo and redo is the same, before process images are loaded from disk and current ones are saved.
-//        /// </summary>
-//        /// <param name="undoRedoProcess">Process that is invoked on redo and undo.</param>
-//        /// <param name="processArgs">Custom parameters for undo and redo process.</param>
-//        /// <param name="description">Undo change description.</param>
-//        /// <returns>UndoManager ready 'Change' instance.</returns>
-//        public Change ToChange(Action<Layer[], UndoLayer[], object[]> undoRedoProcess, object[] processArgs, string description = "")
-//        {
-//            Action<object[]> finalProcess = processParameters =>
-//            {
-//                Layer[] layers = LoadLayersFromDevice();
-//                LayerChunk[] chunks = new LayerChunk[layers.Length];
-//                for (int i = 0; i < layers.Length; i++)
-//                {
-//                    chunks[i] = new LayerChunk(layers[i], StoredLayers[i].SerializedRect);
-//                }
-
-//                GenerateUndoLayers(chunks);
-
-//                SaveLayersOnDevice();
-
-//                undoRedoProcess(layers, StoredLayers, processParameters);
-//            };
-
-//            var change = new Change(finalProcess, processArgs, finalProcess, processArgs, description);
-//            change.DisposeProcess = (_, _) => Dispose();
-//            return change;
-//        }
-
-//        /// <summary>
-//        ///     Creates UndoManager ready Change instance, where undo process loads layers from device, and redo saves them.
-//        /// </summary>
-//        /// <param name="undoProcess">Method that is invoked on undo, with loaded layers parameter and UndoLayer array data.</param>
-//        /// <param name="redoProcess">Method that is invoked on redo with custom object array parameters.</param>
-//        /// <param name="redoProcessParameters">Parameters for redo process.</param>
-//        /// <param name="description">Undo change description.</param>
-//        /// <returns>UndoManager ready Change instance.</returns>
-//        public Change ToChange(Action<Layer[], UndoLayer[]> undoProcess, Action<object[]> redoProcess, object[] redoProcessParameters, string description = "")
-//        {
-//            Action<object[]> finalUndoProcess = _ =>
-//            {
-//                Layer[] layers = LoadLayersFromDevice();
-//                undoProcess(layers, StoredLayers);
-//            };
-
-//            Action<object[]> finalRedoProcess = parameters =>
-//            {
-//                SaveLayersOnDevice();
-//                redoProcess(parameters);
-//            };
-
-//            var change = new Change(finalUndoProcess, null, finalRedoProcess, redoProcessParameters, description);
-//            change.DisposeProcess = (_, _) => Dispose();
-//            return change;
-//        }
-
-//        /// <summary>
-//        ///     Creates UndoManager ready Change instance, where undo process saves layers on device, and redo loads them.
-//        /// </summary>
-//        /// <param name="undoProcess">Method that is invoked on undo, with loaded layers parameter and UndoLayer array data.</param>
-//        /// <param name="undoProcessParameters">Parameters for undo process.</param>
-//        /// <param name="redoProcess">Method that is invoked on redo with custom object array parameters.</param>
-//        /// <param name="description">Undo change description.</param>
-//        /// <returns>UndoManager ready Change instance.</returns>
-//        public Change ToChange(Action<object[]> undoProcess, object[] undoProcessParameters, Action<Layer[], UndoLayer[]> redoProcess, string description = "")
-//        {
-//            Action<object[]> finalUndoProcess = parameters =>
-//            {
-//                SaveLayersOnDevice();
-//                undoProcess(parameters);
-//            };
-
-//            Action<object[]> finalRedoProcess = parameters =>
-//            {
-//                Layer[] layers = LoadLayersFromDevice();
-//                redoProcess(layers, StoredLayers);
-//            };
-
-//            var change = new Change(finalUndoProcess, undoProcessParameters, finalRedoProcess, null, description);
-//            change.DisposeProcess = (_, _) => Dispose();
-//            return change;
-//        }
-
-//        /// <summary>
-//        ///     Creates UndoManager ready Change instance, where undo process saves layers on device, and redo loads them.
-//        /// </summary>
-//        /// <param name="undoProcess">Method that is invoked on undo, with loaded layers parameter and UndoLayer array data.</param>
-//        /// <param name="undoProcessParameters">Parameters for undo process.</param>
-//        /// <param name="redoProcess">Method that is invoked on redo with custom object array parameters.</param>
-//        /// <param name="redoProcessArgs">Parameters for redo process.</param>
-//        /// <param name="description">Undo change description.</param>
-//        /// <returns>UndoManager ready Change instance.</returns>
-//        public Change ToChange(Action<object[]> undoProcess, object[] undoProcessParameters, Action<Layer[], UndoLayer[], object[]> redoProcess, object[] redoProcessArgs, string description = "")
-//        {
-//            Action<object[]> finalUndoProcess = parameters =>
-//            {
-//                SaveLayersOnDevice();
-//                undoProcess(parameters);
-//            };
-
-//            Action<object[]> finalRedoProcess = parameters =>
-//            {
-//                Layer[] layers = LoadLayersFromDevice();
-//                redoProcess(layers, StoredLayers, parameters);
-//            };
-
-//            var change = new Change(finalUndoProcess, undoProcessParameters, finalRedoProcess, redoProcessArgs, description);
-//            change.DisposeProcess = (_, _) => Dispose();
-//            return change;
-//        }
-
-//        /// <summary>
-//        /// Generates UndoLayer[] StoredLayers data.
-//        /// </summary>
-//        private void GenerateUndoLayers(LayerChunk[] chunks)
-//        {
-//            StoredLayers = new UndoLayer[layersToStore.Count];
-//            int i = 0;
-//            foreach (var layerGuid in layersToStore)
-//            {
-//                Layer layer = Document.Layers.First(x => x.GuidValue == layerGuid);
-//                if (!Document.Layers.Contains(layer))
-//                {
-//                    throw new ArgumentException("Provided document doesn't contain selected layer");
-//                }
-
-//                int index = Document.Layers.IndexOf(layer);
-//                string fileName = layer.Name + Guid.NewGuid();
-//                StoredLayers[i] = new UndoLayer(
-//                    Path.Join(
-//                        UndoChangeLocation,
-//                        Convert.ToBase64String(Encoding.UTF8.GetBytes(fileName)) + ".undoimg"),
-//                    layer,
-//                    index,
-//                    chunks[i].AbsoluteChunkRect);
-//                i++;
-//            }
-//        }
-
-//        public static void BasicUndoProcess(Layer[] layers, UndoLayer[] data, object[] args)
-//        {
-//            if (args.Length > 0 && args[0] is Document document)
-//            {
-//                for (int i = 0; i < layers.Length; i++)
-//                {
-//                    Layer layer = layers[i];
-//                    UndoLayer layerData = data[i];
-//                    var foundLayer = document.Layers.FirstOrDefault(x => x.GuidValue == layerData.LayerGuid);
-
-//                    if (foundLayer != null)
-//                    {
-//                        ApplyChunkToLayer(foundLayer, layerData, layer.LayerBitmap);
-//                    }
-//                    else
-//                    {
-//                        document.RemoveLayer(layerData.LayerIndex, false);
-//                        document.Layers.Insert(layerData.LayerIndex, layer);
-//                    }
-
-//                    if (layerData.IsActive)
-//                    {
-//                        document.SetMainActiveLayer(layerData.LayerIndex);
-//                    }
-//                }
-//            }
-//        }
-
-//        private static void ApplyChunkToLayer(Layer layer, UndoLayer layerData, Surface chunk)
-//        {
-//            bool widthBigger = layer.Width < chunk.Width;
-//            bool heightBigger = layer.Height < chunk.Height;
-//            int targetWidth = widthBigger ? chunk.Width : layer.Width;
-//            int targetHeight = heightBigger ? chunk.Height : layer.Height;
-
-//            int offsetDiffX = layerData.OffsetX - layer.OffsetX;
-//            int offsetDiffY = layerData.OffsetY - layer.OffsetY;
-
-//            int targetOffsetX = layerData.OffsetX == 0 && widthBigger ? layerData.SerializedRect.Left : layerData.OffsetX;
-//            int targetOffsetY = layerData.OffsetY == 0 && heightBigger ? layerData.SerializedRect.Top : layerData.OffsetY;
-
-//            Surface targetSizeSurface = new Surface(targetWidth, targetHeight);
-//            using var foundLayerSnapshot = layer.LayerBitmap.SkiaSurface.Snapshot();
-//            targetSizeSurface.SkiaSurface.Canvas.DrawImage(
-//                foundLayerSnapshot,
-//                SKRect.Create(offsetDiffX, offsetDiffY, layer.Width, layer.Height),
-//                SKRect.Create(0, 0, targetWidth, targetHeight),
-//                Surface.ReplacingPaint);
-
-//            layer.Offset = new Thickness(targetOffsetX, targetOffsetY, 0, 0);
-
-//            SKRect finalRect = SKRect.Create(
-//                layerData.SerializedRect.Left - layer.OffsetX,
-//                layerData.SerializedRect.Top - layer.OffsetY,
-//                layerData.SerializedRect.Width,
-//                layerData.SerializedRect.Height);
-
-//            using var snapshot = chunk.SkiaSurface.Snapshot();
-
-//            targetSizeSurface.SkiaSurface.Canvas.DrawImage(
-//                snapshot,
-//                finalRect,
-//                Surface.ReplacingPaint);
-
-//            layer.LayerBitmap = targetSizeSurface;
-//        }
-
-//        public void Dispose()
-//        {
-//            var layers = LoadLayersFromDevice();
-//            foreach (var layer in layers)
-//                layer.LayerBitmap.Dispose();
-//        }
-//    }
-//}
+}

+ 3 - 3
PixiEditor/Models/Undo/UndoLayer.cs

@@ -36,9 +36,9 @@ namespace PixiEditor.Models.Undo
 
         public float Opacity { get; set; }
 
-        //public SKRectI SerializedRect { get; set; }
+        public SKRectI SerializedRect { get; set; }
 
-        public UndoLayer(string storedPngLayerName, Layer layer, int layerIndex/*, SKRectI serializedRect*/)
+        public UndoLayer(string storedPngLayerName, Layer layer, int layerIndex, SKRectI serializedRect)
         {
             StoredPngLayerName = storedPngLayerName;
             LayerIndex = layerIndex;
@@ -54,7 +54,7 @@ namespace PixiEditor.Models.Undo
             IsActive = layer.IsActive;
             LayerGuid = layer.GuidValue;
             LayerHighlightColor = layer.LayerHighlightColor;
-            //SerializedRect = serializedRect;
+            SerializedRect = serializedRect;
         }
     }
 }

+ 13 - 1
PixiEditor/ViewModels/SubViewModels/Main/ColorsViewModel.cs

@@ -1,8 +1,12 @@
-using PixiEditor.Helpers;
+using Microsoft.Extensions.DependencyInjection;
+using PixiEditor.Helpers;
 using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.Enums;
+using PixiEditor.Models.IO;
 using SkiaSharp;
 using System;
+using System.Collections;
+using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
 
@@ -21,6 +25,8 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
 
         public RelayCommand<int> SelectPaletteColorCommand { get; set; }
 
+        public IEnumerable<PaletteFileParser> PaletteParsers { get; private set; }
+
         private SKColor primaryColor = SKColors.Black;
 
         public SKColor PrimaryColor // Primary color, hooked with left mouse button
@@ -55,6 +61,7 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
         public ColorsViewModel(ViewModelMain owner)
             : base(owner)
         {
+
             SelectColorCommand = new RelayCommand(SelectColor);
             RemoveSwatchCommand = new RelayCommand(RemoveSwatch);
             SwapColorsCommand = new RelayCommand(SwapColors);
@@ -120,5 +127,10 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
         {
             PrimaryColor = parameter as SKColor? ?? throw new ArgumentException();
         }
+
+        public void SetupPaletteParsers(IServiceProvider services)
+        {
+            PaletteParsers = services.GetServices<PaletteFileParser>();
+        }
     }
 }

+ 2 - 0
PixiEditor/ViewModels/ViewModelMain.cs

@@ -150,6 +150,8 @@ namespace PixiEditor.ViewModels
             UndoSubViewModel = services.GetService<UndoViewModel>();
             ViewportSubViewModel = services.GetService<ViewportViewModel>();
             ColorsSubViewModel = services.GetService<ColorsViewModel>();
+            ColorsSubViewModel?.SetupPaletteParsers(services);
+
             DocumentSubViewModel = services.GetService<DocumentViewModel>();
             DiscordViewModel = services.GetService<DiscordViewModel>();
             UpdateSubViewModel = services.GetService<UpdateViewModel>();

+ 3 - 3
PixiEditor/Views/Dialogs/LospecPalettesBrowser.xaml → PixiEditor/Views/Dialogs/PalettesBrowser.xaml

@@ -1,9 +1,9 @@
-<Window x:Class="PixiEditor.Views.Dialogs.LospecPalettesBrowser"
+<Window x:Class="PixiEditor.Views.Dialogs.PalettesBrowser"
              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.Lospec" 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" 
              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"
@@ -67,7 +67,7 @@
                 Converter={StaticResource BoolToVisibilityConverter}}">
                     <ItemsControl.ItemTemplate>
                         <DataTemplate>
-                            <local:LospecPaletteItem Palette="{Binding}" 
+                            <local:PaletteItem Palette="{Binding}" 
                                                      ImportPaletteCommand="{Binding ImportPaletteCommand, ElementName=lospecPalettesBrowser}"/>
                         </DataTemplate>
                     </ItemsControl.ItemTemplate>

+ 8 - 7
PixiEditor/Views/Dialogs/LospecPalettesBrowser.xaml.cs → PixiEditor/Views/Dialogs/PalettesBrowser.xaml.cs

@@ -1,4 +1,5 @@
 using PixiEditor.Models.DataHolders;
+using PixiEditor.Models.DataHolders.Palettes;
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.Events;
 using PixiEditor.Models.ExternalServices;
@@ -24,7 +25,7 @@ namespace PixiEditor.Views.Dialogs
     /// <summary>
     /// Interaction logic for LospecPalettesBrowser.xaml
     /// </summary>
-    public partial class LospecPalettesBrowser : Window
+    public partial class PalettesBrowser : Window
     {
         public event ListFetched OnListFetched;
         private int _currentPage = 0;
@@ -37,7 +38,7 @@ namespace PixiEditor.Views.Dialogs
 
         // Using a DependencyProperty as the backing store for PaletteList.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty PaletteListProperty =
-            DependencyProperty.Register("PaletteList", typeof(PaletteList), typeof(LospecPalettesBrowser));
+            DependencyProperty.Register("PaletteList", typeof(PaletteList), typeof(PalettesBrowser));
 
         public ICommand ImportPaletteCommand
         {
@@ -47,7 +48,7 @@ namespace PixiEditor.Views.Dialogs
 
         // Using a DependencyProperty as the backing store for ImportPaletteCommand.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty ImportPaletteCommandProperty =
-            DependencyProperty.Register("ImportPaletteCommand", typeof(ICommand), typeof(LospecPalettesBrowser));
+            DependencyProperty.Register("ImportPaletteCommand", typeof(ICommand), typeof(PalettesBrowser));
 
         public bool IsFetching
         {
@@ -57,7 +58,7 @@ namespace PixiEditor.Views.Dialogs
 
         // Using a DependencyProperty as the backing store for IsFetching.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty IsFetchingProperty =
-            DependencyProperty.Register("IsFetching", typeof(bool), typeof(LospecPalettesBrowser), new PropertyMetadata(false));
+            DependencyProperty.Register("IsFetching", typeof(bool), typeof(PalettesBrowser), new PropertyMetadata(false));
 
         public int ColorsNumber
         {
@@ -67,7 +68,7 @@ namespace PixiEditor.Views.Dialogs
 
         // Using a DependencyProperty as the backing store for ColorsNumber.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty ColorsNumberProperty =
-            DependencyProperty.Register("ColorsNumber", typeof(int), typeof(LospecPalettesBrowser), 
+            DependencyProperty.Register("ColorsNumber", typeof(int), typeof(PalettesBrowser), 
                 new PropertyMetadata(8, ColorsNumberChanged));
 
         public string SortingType { get; set; } = "Default";
@@ -76,7 +77,7 @@ namespace PixiEditor.Views.Dialogs
 
         private char[] _separators = new char[] { ' ', ',' };
 
-        public LospecPalettesBrowser()
+        public PalettesBrowser()
         {
             InitializeComponent();
         }
@@ -93,7 +94,7 @@ namespace PixiEditor.Views.Dialogs
 
         private static async void ColorsNumberChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
         {
-            LospecPalettesBrowser browser = (LospecPalettesBrowser)d;
+            PalettesBrowser browser = (PalettesBrowser)d;
             await browser.UpdatePaletteList(true);
         }
 

+ 2 - 2
PixiEditor/Views/MainWindow.xaml

@@ -17,7 +17,7 @@
         xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours" 
         xmlns:avalonDockTheme="clr-namespace:PixiEditor.Styles.AvalonDock" 
         xmlns:layerUserControls="clr-namespace:PixiEditor.Views.UserControls.Layers" 
-        xmlns:sys="clr-namespace:System;assembly=System.Runtime" 
+        xmlns:sys="clr-namespace:System;assembly=System.Runtime" xmlns:palettes="clr-namespace:PixiEditor.Views.UserControls.Palettes"
         d:DataContext="{d:DesignInstance Type=vm:ViewModelMain}"
         mc:Ignorable="d" WindowStyle="None" Initialized="MainWindow_Initialized"
         Title="PixiEditor" Name="mainWindow" Height="1000" Width="1600" Background="{StaticResource MainColor}"
@@ -349,7 +349,7 @@
                                     <avalondock:LayoutAnchorable ContentId="palette" Title="Palette" CanHide="False"
                                                                  CanClose="False" CanAutoHide="False"
                                                                  CanDockAsTabbedDocument="False" CanFloat="True">
-                                        <usercontrols:PaletteViewer IsEnabled="{Binding DocumentSubViewModel.Owner.BitmapManager.ActiveDocument,
+                                        <palettes:PaletteViewer IsEnabled="{Binding DocumentSubViewModel.Owner.BitmapManager.ActiveDocument,
                                         Converter={converters:NotNullToBoolConverter}}" Colors="{Binding BitmapManager.ActiveDocument.Palette}"
                                                               SelectColorCommand="{Binding ColorsSubViewModel.SelectColorCommand}"
                                                                     ImportPaletteCommand="{Binding ColorsSubViewModel.ImportPaletteCommand}"/>

+ 1 - 1
PixiEditor/Views/UserControls/PaletteColor.xaml → PixiEditor/Views/UserControls/Palettes/PaletteColor.xaml

@@ -1,4 +1,4 @@
-<UserControl x:Class="PixiEditor.Views.UserControls.PaletteColor"
+<UserControl x:Class="PixiEditor.Views.UserControls.Palettes.PaletteColor"
              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"

+ 1 - 2
PixiEditor/Views/UserControls/PaletteColor.xaml.cs → PixiEditor/Views/UserControls/Palettes/PaletteColor.xaml.cs

@@ -2,7 +2,7 @@
 using System.Windows.Controls;
 using SkiaSharp;
 
-namespace PixiEditor.Views.UserControls;
+namespace PixiEditor.Views.UserControls.Palettes;
 
 public partial class PaletteColor : UserControl
 {
@@ -16,7 +16,6 @@ public partial class PaletteColor : UserControl
     }
 
 
-
     public int? AssociatedKey
     {
         get { return (int?)GetValue(AssociatedKeyProperty); }

+ 1 - 1
PixiEditor/Views/UserControls/PaletteColorAdder.xaml → PixiEditor/Views/UserControls/Palettes/PaletteColorAdder.xaml

@@ -1,4 +1,4 @@
-<UserControl x:Class="PixiEditor.Views.UserControls.PaletteColorAdder"
+<UserControl x:Class="PixiEditor.Views.UserControls.Palettes.PaletteColorAdder"
              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" 

+ 2 - 1
PixiEditor/Views/UserControls/PaletteColorAdder.xaml.cs → PixiEditor/Views/UserControls/Palettes/PaletteColorAdder.xaml.cs

@@ -15,7 +15,8 @@ using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
 
-namespace PixiEditor.Views.UserControls
+namespace PixiEditor.Views.UserControls.Palettes
+
 {
     /// <summary>
     /// Interaction logic for PaletteColorAdder.xaml

+ 8 - 19
PixiEditor/Views/UserControls/Lospec/LospecPaletteItem.xaml → PixiEditor/Views/UserControls/Palettes/PaletteItem.xaml

@@ -1,9 +1,9 @@
-<UserControl x:Class="PixiEditor.Views.UserControls.Lospec.LospecPaletteItem"
+<UserControl x:Class="PixiEditor.Views.UserControls.Palettes.PaletteItem"
              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.Lospec" 
+             xmlns:local="clr-namespace:PixiEditor.Views.UserControls.Palettes" 
              xmlns:controls="clr-namespace:PixiEditor.Views.UserControls"
              mc:Ignorable="d" 
              d:DesignHeight="200" d:DesignWidth="800" Name="paletteItem">
@@ -19,16 +19,9 @@
         </Grid.RowDefinitions>
         <StackPanel Orientation="Vertical" Grid.RowSpan="2" Grid.ColumnSpan="2">
             <Separator Background="{StaticResource MainColor}"/>
-            <TextBlock>
-                <Hyperlink NavigateUri="{Binding ElementName=paletteItem, Path=Palette.Url}"
-                           RequestNavigate="Hyperlink_RequestNavigate">                 
-                    <TextBlock Text="{Binding Palette.Title, ElementName=paletteItem}" Foreground="White" FontSize="20"/>
-                </Hyperlink>
-            </TextBlock>
+            <TextBlock Text="{Binding Palette.Title, ElementName=paletteItem}" Foreground="White" FontSize="20"/>
             <TextBlock Margin="0 5 0 0">
-                <Hyperlink RequestNavigate="Hyperlink_RequestNavigate" NavigateUri="{Binding ElementName=paletteItem, Path=Palette.User.Url}">
-                    <controls:PrependTextBlock PrependColor="Gray" Prepend="Author: " Text="{Binding Palette.User.Name, ElementName=paletteItem}" Foreground="White"/>
-                </Hyperlink>
+            <controls:PrependTextBlock PrependColor="Gray" Prepend="Author: " Text="{Binding Palette.User.Name, ElementName=paletteItem}" Foreground="White"/>
             </TextBlock>
         </StackPanel>
         <ItemsControl Margin="0 0 0 0" Grid.Row="1" Grid.Column="0" ItemsSource="{Binding ElementName=paletteItem, Path=Palette.Colors}">
@@ -48,14 +41,10 @@
                 Style="{StaticResource ToolButtonStyle}" Cursor="Hand" 
                     Command="{Binding ImportPaletteCommand, ElementName=paletteItem}"
                     CommandParameter="{Binding ElementName=paletteItem, Path=Palette.Colors}">
-                <Button.Background>
-                    <ImageBrush ImageSource="/Images/Download.png"/>
-                </Button.Background>
-            </Button>
-        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Grid.Row="2" Grid.Column="2">
-            <controls:PrependTextBlock AppendColor="Gray" Append=" likes" Text="{Binding ElementName=paletteItem, Path=Palette.Likes}" Foreground="Gray"/>
-            <Image Source="/Images/Heart.png" Height="16" Margin="2.5 0 0 0"/>
-        </StackPanel>
+            <Button.Background>
+                <ImageBrush ImageSource="/Images/Download.png"/>
+            </Button.Background>
+        </Button>
         <StackPanel Grid.Row="2" Margin="0 10 0 0" Orientation="Horizontal">
             <TextBlock Text="Tags: " Foreground="Gray"/>
             <ItemsControl  ItemsSource="{Binding ElementName=paletteItem, Path=Palette.Tags}">

+ 6 - 26
PixiEditor/Views/UserControls/Lospec/LospecPaletteItem.xaml.cs → PixiEditor/Views/UserControls/Palettes/PaletteItem.xaml.cs

@@ -1,28 +1,17 @@
 using PixiEditor.Models.DataHolders;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
+using PixiEditor.Models.DataHolders.Palettes;
 using System.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
 using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
-using System.Windows.Shapes;
 
-namespace PixiEditor.Views.UserControls.Lospec
+namespace PixiEditor.Views.UserControls.Palettes
 {
     /// <summary>
     /// Interaction logic for LospecPaletteItem.xaml
     /// </summary>
-    public partial class LospecPaletteItem : UserControl
+    public partial class PaletteItem : UserControl
     {
         public Palette Palette
         {
@@ -32,7 +21,7 @@ namespace PixiEditor.Views.UserControls.Lospec
 
         // Using a DependencyProperty as the backing store for Palette.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty PaletteProperty =
-            DependencyProperty.Register("Palette", typeof(Palette), typeof(LospecPaletteItem), new PropertyMetadata(null));
+            DependencyProperty.Register("Palette", typeof(Palette), typeof(PaletteItem), new PropertyMetadata(null));
 
         public ICommand ImportPaletteCommand
         {
@@ -42,21 +31,12 @@ namespace PixiEditor.Views.UserControls.Lospec
 
         // Using a DependencyProperty as the backing store for ImportPaletteCommand.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty ImportPaletteCommandProperty =
-            DependencyProperty.Register("ImportPaletteCommand", typeof(ICommand), typeof(LospecPaletteItem));
+            DependencyProperty.Register("ImportPaletteCommand", typeof(ICommand), typeof(PaletteItem));
 
 
-        public LospecPaletteItem()
+        public PaletteItem()
         {
             InitializeComponent();
         }
-
-        private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
-        {
-            using Process openProcess = new Process();
-
-            openProcess.StartInfo.UseShellExecute = true;
-            openProcess.StartInfo.FileName = e.Uri.AbsoluteUri;
-            openProcess.Start();
-        }
     }
 }

+ 8 - 8
PixiEditor/Views/UserControls/PaletteViewer.xaml → PixiEditor/Views/UserControls/Palettes/PaletteViewer.xaml

@@ -1,11 +1,11 @@
-<UserControl x:Class="PixiEditor.Views.UserControls.PaletteViewer"
+<UserControl x:Class="PixiEditor.Views.UserControls.Palettes.PaletteViewer"
              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"
              xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
-             xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
+             xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters" xmlns:palettes="clr-namespace:PixiEditor.Views.UserControls.Palettes"
              mc:Ignorable="d" 
              d:DesignHeight="450" d:DesignWidth="300" Name="paletteControl">
     <Grid AllowDrop="True" PreviewDragEnter="Grid_PreviewDragEnter" PreviewDragLeave="Grid_PreviewDragLeave"
@@ -17,7 +17,7 @@
         </Grid.RowDefinitions>
         <StackPanel Orientation="Vertical" Grid.Row="0" Background="{StaticResource MainColor}">
             <DockPanel VerticalAlignment="Center" Margin="0 5 0 0">
-                <local:PaletteColorAdder DockPanel.Dock="Left" Margin="5 0 0 0" Colors="{Binding ElementName=paletteControl, Path=Colors}"/>
+                <palettes:PaletteColorAdder DockPanel.Dock="Left" Margin="5 0 0 0" Colors="{Binding ElementName=paletteControl, Path=Colors}"/>
                 <StackPanel Margin="0, 0, 5, 0" HorizontalAlignment="Right" Width="85" VerticalAlignment="Center" Orientation="Horizontal">
                 <Button Margin="0, 0, 5, 0" Style="{StaticResource ToolButtonStyle}" Click="BrowsePalettes_Click"
                 Cursor="Hand" Height="24" Width="24" ToolTip="Browse Palettes">
@@ -65,25 +65,25 @@
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                     <DataTemplate>
-                        <local:PaletteColor ToolTip="Click to select as main color. Drag and drop onto another pallete color to swap them." AllowDrop="True" Color="{Binding}" Margin="0 5 5 5" MouseMove="PaletteColor_MouseMove"
+                        <palettes:PaletteColor ToolTip="Click to select as main color. Drag and drop onto another pallete color to swap them." AllowDrop="True" Color="{Binding}" Margin="0 5 5 5" MouseMove="PaletteColor_MouseMove"
                                             Drop="PaletteColor_Drop"
                                             AssociatedKey="{Binding Path=(ItemsControl.AlternationIndex), 
                 RelativeSource={RelativeSource TemplatedParent}, Converter={converters:IndexToAssociatedKeyConverter}}">
                             <b:Interaction.Triggers>
                                 <b:EventTrigger EventName="MouseUp">
                                     <b:InvokeCommandAction
-                                    Command="{Binding SelectColorCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:PaletteViewer}}}"
+                                    Command="{Binding SelectColorCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type palettes:PaletteViewer}}}"
                                     CommandParameter="{Binding}" />
                                 </b:EventTrigger>
                             </b:Interaction.Triggers>
-                            <local:PaletteColor.ContextMenu>
+                            <palettes:PaletteColor.ContextMenu>
                                         <ContextMenu>
                                             <MenuItem Header="Remove" Foreground="White"
                                               Click="RemoveColorMenuItem_OnClick"
                                               CommandParameter="{Binding}" />
                                         </ContextMenu>
-                                    </local:PaletteColor.ContextMenu>
-                                </local:PaletteColor>
+                                    </palettes:PaletteColor.ContextMenu>
+                                </palettes:PaletteColor>
                     </DataTemplate>
                </ItemsControl.ItemTemplate>
             </ItemsControl>

+ 14 - 10
PixiEditor/Views/UserControls/PaletteViewer.xaml.cs → PixiEditor/Views/UserControls/Palettes/PaletteViewer.xaml.cs

@@ -1,14 +1,17 @@
 using System.Linq;
+using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
 using Microsoft.Win32;
 using PixiEditor.Models.DataHolders;
+using PixiEditor.Models.DataHolders.Palettes;
+using PixiEditor.Models.IO;
 using PixiEditor.Models.IO.JascPalFile;
 using PixiEditor.Views.Dialogs;
 using SkiaSharp;
 
-namespace PixiEditor.Views.UserControls
+namespace PixiEditor.Views.UserControls.Palettes
 {
     /// <summary>
     /// Interaction logic for Palette.xaml
@@ -63,7 +66,7 @@ namespace PixiEditor.Views.UserControls
             }
         }
 
-        private void ImportPalette_OnClick(object sender, RoutedEventArgs e)
+        private async void ImportPalette_OnClick(object sender, RoutedEventArgs e)
         {
             OpenFileDialog openFileDialog = new OpenFileDialog
             {
@@ -71,27 +74,28 @@ namespace PixiEditor.Views.UserControls
             };
             if (openFileDialog.ShowDialog() == true)
             {
-                ImportPallete(openFileDialog.FileName);
+                await ImportPalette(openFileDialog.FileName);
             }
         }
 
-        private void ImportPallete(string fileName)
+        private async Task ImportPalette(string fileName)
         {
-            var jascData = JascFileParser.Parse(fileName);
+            var jascData = await JascFileParser.ParseFile(fileName);
             Colors.Clear();
             Colors.AddRange(jascData.Colors);
         }
 
-        private void SavePalette_OnClick(object sender, RoutedEventArgs e)
+        private async void SavePalette_OnClick(object sender, RoutedEventArgs e)
         {
             SaveFileDialog saveFileDialog = new SaveFileDialog
             {
                 Filter = "Palette (*.pal)|*.pal"
             };
+
             if (saveFileDialog.ShowDialog() == true)
             {
                 string fileName = saveFileDialog.FileName;
-                JascFileParser.Save(fileName, new JascFileData(Colors.ToArray()));
+                await JascFileParser.SaveFile(fileName, new PaletteFileData(Colors.ToArray()));
             }
         }
 
@@ -108,11 +112,11 @@ namespace PixiEditor.Views.UserControls
             dragDropGrid.Visibility = Visibility.Hidden;
         }
 
-        private void Grid_Drop(object sender, DragEventArgs e)
+        private async void Grid_Drop(object sender, DragEventArgs e)
         {
             if(IsPalFilePresent(e, out string filePath))
             {
-                ImportPallete(filePath);
+                await ImportPalette(filePath);
                 dragDropGrid.Visibility = Visibility.Hidden;
             }
         }
@@ -164,7 +168,7 @@ namespace PixiEditor.Views.UserControls
 
         private async void BrowsePalettes_Click(object sender, RoutedEventArgs e)
         {
-            LospecPalettesBrowser browser = new LospecPalettesBrowser
+            PalettesBrowser browser = new PalettesBrowser
             {
                 Owner = Application.Current.MainWindow,
                 ImportPaletteCommand = this.ImportPaletteCommand

+ 5 - 5
PixiEditor/Views/UserControls/SwatchesView.xaml

@@ -5,7 +5,7 @@
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:local="clr-namespace:PixiEditor.Views.UserControls" 
              xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
-             xmlns:conv="clr-namespace:PixiEditor.Helpers.Converters"
+             xmlns:conv="clr-namespace:PixiEditor.Helpers.Converters" xmlns:palettes="clr-namespace:PixiEditor.Views.UserControls.Palettes"
              mc:Ignorable="d" Name="swatchesView"
              d:DesignHeight="450" d:DesignWidth="300">
     <UserControl.Resources>
@@ -34,7 +34,7 @@
             </ItemsControl.ItemsPanel>
             <ItemsControl.ItemTemplate>
                 <DataTemplate>
-                    <local:PaletteColor Color="{Binding}" Margin="0 5 5 5">
+                    <palettes:PaletteColor Color="{Binding}" Margin="0 5 5 5">
                         <i:Interaction.Triggers>
                             <i:EventTrigger EventName="MouseDown">
                                 <i:InvokeCommandAction
@@ -42,14 +42,14 @@
                                     CommandParameter="{Binding}" />
                             </i:EventTrigger>
                         </i:Interaction.Triggers>
-                        <local:PaletteColor.ContextMenu>
+                        <palettes:PaletteColor.ContextMenu>
                             <ContextMenu>
                                 <MenuItem Header="Remove" Foreground="White"
                                           Command="{Binding Source={x:Reference Name=swatchesView}, Path=DataContext.ColorsSubViewModel.RemoveSwatchCommand}"
                                           CommandParameter="{Binding}" />
                             </ContextMenu>
-                        </local:PaletteColor.ContextMenu>
-                    </local:PaletteColor>
+                        </palettes:PaletteColor.ContextMenu>
+                    </palettes:PaletteColor>
                 </DataTemplate>
             </ItemsControl.ItemTemplate>
         </ItemsControl>