Browse Source

file-scoped namespaces

flabbet 3 years ago
parent
commit
9f08b57239
100 changed files with 3015 additions and 3115 deletions
  1. 6 7
      src/PixiEditor.UpdateInstaller/App.xaml.cs
  2. 14 15
      src/PixiEditor.UpdateInstaller/Extensions.cs
  3. 29 30
      src/PixiEditor.UpdateInstaller/MainWindow.xaml.cs
  4. 8 9
      src/PixiEditor.UpdateInstaller/ViewModelBase.cs
  5. 36 37
      src/PixiEditor.UpdateInstaller/ViewModelMain.cs
  6. 9 10
      src/PixiEditor.UpdateModule/Asset.cs
  7. 18 19
      src/PixiEditor.UpdateModule/ReleaseInfo.cs
  8. 16 17
      src/PixiEditor.UpdateModule/UpdateChannel.cs
  9. 68 69
      src/PixiEditor.UpdateModule/UpdateChecker.cs
  10. 39 40
      src/PixiEditor.UpdateModule/UpdateDownloader.cs
  11. 48 49
      src/PixiEditor.UpdateModule/UpdateInstaller.cs
  12. 7 8
      src/PixiEditor.UpdateModule/UpdateProgressChangedEventArgs.cs
  13. 89 90
      src/PixiEditor/App.xaml.cs
  14. 21 22
      src/PixiEditor/Exceptions/CorruptedFileException.cs
  15. 20 21
      src/PixiEditor/Helpers/Behaviours/ClearFocusOnClickBehavior.cs
  16. 21 22
      src/PixiEditor/Helpers/Behaviours/GlobalShortcutFocusBehavior.cs
  17. 19 20
      src/PixiEditor/Helpers/Behaviours/TextBlockExtensions.cs
  18. 107 108
      src/PixiEditor/Helpers/Behaviours/TextBoxFocusBehavior.cs
  19. 14 15
      src/PixiEditor/Helpers/BindingProxy.cs
  20. 31 32
      src/PixiEditor/Helpers/ClipboardHelper.cs
  21. 14 15
      src/PixiEditor/Helpers/Converters/BoolToIntConverter.cs
  22. 9 10
      src/PixiEditor/Helpers/Converters/CountToVisibilityConverter.cs
  23. 11 12
      src/PixiEditor/Helpers/Converters/DebugConverter.cs
  24. 11 12
      src/PixiEditor/Helpers/Converters/DoubleToIntConverter.cs
  25. 7 8
      src/PixiEditor/Helpers/Converters/EmptyStringToVisibilityConverter.cs
  26. 21 22
      src/PixiEditor/Helpers/Converters/EnumBooleanConverter.cs
  27. 17 18
      src/PixiEditor/Helpers/Converters/EnumToStringConverter.cs
  28. 17 18
      src/PixiEditor/Helpers/Converters/EqualityBoolToVisibilityConverter.cs
  29. 30 31
      src/PixiEditor/Helpers/Converters/FileExtensionToColorConverter.cs
  30. 10 11
      src/PixiEditor/Helpers/Converters/FloorConverter.cs
  31. 18 19
      src/PixiEditor/Helpers/Converters/FormattedColorConverter.cs
  32. 12 13
      src/PixiEditor/Helpers/Converters/IndentConverter.cs
  33. 11 12
      src/PixiEditor/Helpers/Converters/IndexOfConverter.cs
  34. 10 11
      src/PixiEditor/Helpers/Converters/IndexToAssociatedKeyConverter.cs
  35. 11 12
      src/PixiEditor/Helpers/Converters/IntToPickerTypeConverter.cs
  36. 8 9
      src/PixiEditor/Helpers/Converters/IntToViewportRectConverter.cs
  37. 9 10
      src/PixiEditor/Helpers/Converters/InverseBooleanConverter.cs
  38. 9 10
      src/PixiEditor/Helpers/Converters/IsSpecifiedTypeConverter.cs
  39. 16 17
      src/PixiEditor/Helpers/Converters/KeyToStringConverter.cs
  40. 29 30
      src/PixiEditor/Helpers/Converters/LayerStructureToGroupsConverter.cs
  41. 72 73
      src/PixiEditor/Helpers/Converters/LayersToStructuredLayersConverter.cs
  42. 12 13
      src/PixiEditor/Helpers/Converters/MarkupConverter.cs
  43. 10 11
      src/PixiEditor/Helpers/Converters/MultiValueMarkupConverter.cs
  44. 12 13
      src/PixiEditor/Helpers/Converters/NotNullToBoolConverter.cs
  45. 14 15
      src/PixiEditor/Helpers/Converters/NotNullToVisibilityConverter.cs
  46. 7 8
      src/PixiEditor/Helpers/Converters/NullToVisibilityConverter.cs
  47. 16 17
      src/PixiEditor/Helpers/Converters/OppositeVisibilityConverter.cs
  48. 9 10
      src/PixiEditor/Helpers/Converters/PaletteItemsToWidthConverter.cs
  49. 18 19
      src/PixiEditor/Helpers/Converters/SKColorToMediaColorConverter.cs
  50. 15 16
      src/PixiEditor/Helpers/Converters/SingleInstanceConverter.cs
  51. 12 13
      src/PixiEditor/Helpers/Converters/SingleInstanceMultiValueConverter.cs
  52. 12 13
      src/PixiEditor/Helpers/Converters/ThresholdVisibilityConverter.cs
  53. 20 21
      src/PixiEditor/Helpers/Converters/ToolSizeToIntConverter.cs
  54. 13 14
      src/PixiEditor/Helpers/Converters/ViewboxInverseTransformConverter.cs
  55. 17 18
      src/PixiEditor/Helpers/Converters/WidthToBitmapScalingModeConverter.cs
  56. 13 14
      src/PixiEditor/Helpers/Converters/ZoomLevelToBitmapScalingModeConverter.cs
  57. 11 12
      src/PixiEditor/Helpers/Converters/ZoomToViewportConverter.cs
  58. 62 63
      src/PixiEditor/Helpers/CoordinatesHelper.cs
  59. 71 72
      src/PixiEditor/Helpers/CrashHelper.cs
  60. 34 35
      src/PixiEditor/Helpers/DependencyInjectionHelper.cs
  61. 23 24
      src/PixiEditor/Helpers/DesignCommandHelpers.cs
  62. 127 128
      src/PixiEditor/Helpers/EllipseGenerator.cs
  63. 7 8
      src/PixiEditor/Helpers/ExecutionTrigger.cs
  64. 16 17
      src/PixiEditor/Helpers/Extensions/DictionaryHelper.cs
  65. 13 14
      src/PixiEditor/Helpers/Extensions/DirectoryExtensions.cs
  66. 19 20
      src/PixiEditor/Helpers/Extensions/EnumHelpers.cs
  67. 66 67
      src/PixiEditor/Helpers/Extensions/EnumerableHelpers.cs
  68. 38 39
      src/PixiEditor/Helpers/Extensions/Int32RectHelper.cs
  69. 113 114
      src/PixiEditor/Helpers/Extensions/ParserHelpers.cs
  70. 58 59
      src/PixiEditor/Helpers/Extensions/PixelFormatHelper.cs
  71. 6 7
      src/PixiEditor/Helpers/Extensions/SKRectIHelper.cs
  72. 53 54
      src/PixiEditor/Helpers/Extensions/ServiceCollectionHelpers.cs
  73. 8 9
      src/PixiEditor/Helpers/Extensions/SkiaWPFHelpers.cs
  74. 19 20
      src/PixiEditor/Helpers/Extensions/StringHelpers.cs
  75. 6 7
      src/PixiEditor/Helpers/Extensions/ToolbarHelpers.cs
  76. 103 104
      src/PixiEditor/Helpers/GlobalMouseHook.cs
  77. 67 68
      src/PixiEditor/Helpers/InputKeyHelpers.cs
  78. 19 20
      src/PixiEditor/Helpers/PaletteHelpers.cs
  79. 11 12
      src/PixiEditor/Helpers/ProcessHelpers.cs
  80. 47 48
      src/PixiEditor/Helpers/RelayCommand.cs
  81. 26 27
      src/PixiEditor/Helpers/SelectionHelpers.cs
  82. 13 14
      src/PixiEditor/Helpers/SizeCalculator.cs
  83. 5 6
      src/PixiEditor/Helpers/StringExtensions.cs
  84. 73 74
      src/PixiEditor/Helpers/SupportedFilesHelper.cs
  85. 12 13
      src/PixiEditor/Helpers/UI/DocumentsTemplateSelector.cs
  86. 9 10
      src/PixiEditor/Helpers/UI/PanelsStyleSelector.cs
  87. 29 30
      src/PixiEditor/Helpers/UI/ReversedOrderStackPanel.cs
  88. 13 14
      src/PixiEditor/Helpers/UI/TreeViewItemHelper.cs
  89. 28 29
      src/PixiEditor/Helpers/VersionHelpers.cs
  90. 75 76
      src/PixiEditor/Helpers/WindowSizeHelper.cs
  91. 119 120
      src/PixiEditor/Models/Colors/ExColor.cs
  92. 10 11
      src/PixiEditor/Models/Commands/Attributes/Commands/DebugAttribute.cs
  93. 15 16
      src/PixiEditor/Models/Commands/Attributes/Commands/GroupAttribute.cs
  94. 17 18
      src/PixiEditor/Models/Commands/Attributes/Commands/InternalAttribute.cs
  95. 57 58
      src/PixiEditor/Models/Commands/CommandCollection.cs
  96. 263 264
      src/PixiEditor/Models/Commands/CommandController.cs
  97. 36 37
      src/PixiEditor/Models/Commands/CommandGroup.cs
  98. 8 9
      src/PixiEditor/Models/Commands/Commands/BasicCommand.cs
  99. 29 30
      src/PixiEditor/Models/Commands/Commands/Command.cs
  100. 9 10
      src/PixiEditor/Models/Commands/Commands/ToolCommand.cs

+ 6 - 7
src/PixiEditor.UpdateInstaller/App.xaml.cs

@@ -1,11 +1,10 @@
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.UpdateInstaller
+namespace PixiEditor.UpdateInstaller;
+
+/// <summary>
+///     Interaction logic for App.xaml.
+/// </summary>
+public partial class App : Application
 {
 {
-    /// <summary>
-    ///     Interaction logic for App.xaml.
-    /// </summary>
-    public partial class App : Application
-    {
-    }
 }
 }

+ 14 - 15
src/PixiEditor.UpdateInstaller/Extensions.cs

@@ -3,25 +3,24 @@ using System.Diagnostics;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
 using System.Text;
 using System.Text;
 
 
-namespace PixiEditor.UpdateInstaller
+namespace PixiEditor.UpdateInstaller;
+
+public static class Extensions
 {
 {
-    public static class Extensions
-    {
-        private const int MaxPath = 255;
+    private const int MaxPath = 255;
 
 
-        public static string GetExecutablePath()
+    public static string GetExecutablePath()
+    {
+        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
         {
         {
-            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
-            {
-                StringBuilder sb = new StringBuilder(MaxPath);
-                GetModuleFileName(IntPtr.Zero, sb, MaxPath);
-                return sb.ToString();
-            }
-
-            return Process.GetCurrentProcess().MainModule?.FileName;
+            StringBuilder sb = new StringBuilder(MaxPath);
+            GetModuleFileName(IntPtr.Zero, sb, MaxPath);
+            return sb.ToString();
         }
         }
 
 
-        [DllImport("kernel32.dll")]
-        private static extern uint GetModuleFileName(IntPtr hModule, StringBuilder lpFilename, int nSize);
+        return Process.GetCurrentProcess().MainModule?.FileName;
     }
     }
+
+    [DllImport("kernel32.dll")]
+    private static extern uint GetModuleFileName(IntPtr hModule, StringBuilder lpFilename, int nSize);
 }
 }

+ 29 - 30
src/PixiEditor.UpdateInstaller/MainWindow.xaml.cs

@@ -4,40 +4,39 @@ using System.IO;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.UpdateInstaller
+namespace PixiEditor.UpdateInstaller;
+
+/// <summary>
+///     Interaction logic for MainWindow.xaml.
+/// </summary>
+public partial class MainWindow
 {
 {
-    /// <summary>
-    ///     Interaction logic for MainWindow.xaml.
-    /// </summary>
-    public partial class MainWindow
+    public MainWindow()
     {
     {
-        public MainWindow()
-        {
-            InitializeComponent();
-            DataContext = new ViewModelMain();
-        }
+        InitializeComponent();
+        DataContext = new ViewModelMain();
+    }
 
 
-        private async void Window_Loaded(object sender, RoutedEventArgs e)
+    private async void Window_Loaded(object sender, RoutedEventArgs e)
+    {
+        ViewModelMain vmm = (ViewModelMain)DataContext;
+        await Task.Run(() =>
         {
         {
-            ViewModelMain vmm = (ViewModelMain)DataContext;
-            await Task.Run(() =>
+            try
+            {
+                vmm.InstallUpdate();
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "Update error", MessageBoxButton.OK, MessageBoxImage.Error);
+                File.AppendAllText("ErrorLog.txt", $"Error PixiEditor.UpdateInstaller: {DateTime.Now}\n{ex.Message}\n{ex.StackTrace}\n-----\n");
+            }
+            finally
             {
             {
-                try
-                {
-                    vmm.InstallUpdate();
-                }
-                catch (Exception ex)
-                {
-                    MessageBox.Show(ex.Message, "Update error", MessageBoxButton.OK, MessageBoxImage.Error);
-                    File.AppendAllText("ErrorLog.txt", $"Error PixiEditor.UpdateInstaller: {DateTime.Now}\n{ex.Message}\n{ex.StackTrace}\n-----\n");
-                }
-                finally
-                {
-                    string pixiEditorExecutablePath = Directory.GetFiles(vmm.UpdateDirectory, "PixiEditor.exe")[0];
-                    Process.Start(pixiEditorExecutablePath);
-                }
-            });
-            Close();
-        }
+                string pixiEditorExecutablePath = Directory.GetFiles(vmm.UpdateDirectory, "PixiEditor.exe")[0];
+                Process.Start(pixiEditorExecutablePath);
+            }
+        });
+        Close();
     }
     }
 }
 }

+ 8 - 9
src/PixiEditor.UpdateInstaller/ViewModelBase.cs

@@ -1,17 +1,16 @@
 using System.ComponentModel;
 using System.ComponentModel;
 
 
-namespace PixiEditor.UpdateInstaller
+namespace PixiEditor.UpdateInstaller;
+
+public class ViewModelBase : INotifyPropertyChanged
 {
 {
-    public class ViewModelBase : INotifyPropertyChanged
-    {
-        public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
+    public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
 
 
-        protected void RaisePropertyChanged(string property)
+    protected void RaisePropertyChanged(string property)
+    {
+        if (property != null)
         {
         {
-            if (property != null)
-            {
-                PropertyChanged(this, new PropertyChangedEventArgs(property));
-            }
+            PropertyChanged(this, new PropertyChangedEventArgs(property));
         }
         }
     }
     }
 }
 }

+ 36 - 37
src/PixiEditor.UpdateInstaller/ViewModelMain.cs

@@ -2,59 +2,58 @@
 using System.IO;
 using System.IO;
 using PixiEditor.UpdateModule;
 using PixiEditor.UpdateModule;
 
 
-namespace PixiEditor.UpdateInstaller
+namespace PixiEditor.UpdateInstaller;
+
+public class ViewModelMain : ViewModelBase
 {
 {
-    public class ViewModelMain : ViewModelBase
-    {
-        private float progressValue;
+    private float progressValue;
 
 
-        public ViewModelMain()
-        {
-            Current = this;
+    public ViewModelMain()
+    {
+        Current = this;
 
 
-            string updateDirectory = Path.GetDirectoryName(Extensions.GetExecutablePath());
+        string updateDirectory = Path.GetDirectoryName(Extensions.GetExecutablePath());
 
 
 #if DEBUG
 #if DEBUG
-            updateDirectory = Environment.GetCommandLineArgs()[1];
+        updateDirectory = Environment.GetCommandLineArgs()[1];
 #endif
 #endif
-            UpdateDirectory = updateDirectory;
-        }
+        UpdateDirectory = updateDirectory;
+    }
 
 
-        public ViewModelMain Current { get; private set; }
+    public ViewModelMain Current { get; private set; }
 
 
-        public UpdateModule.UpdateInstaller Installer { get; set; }
+    public UpdateModule.UpdateInstaller Installer { get; set; }
 
 
-        public string UpdateDirectory { get; private set; }
+    public string UpdateDirectory { get; private set; }
 
 
-        public float ProgressValue
+    public float ProgressValue
+    {
+        get => progressValue;
+        set
         {
         {
-            get => progressValue;
-            set
-            {
-                progressValue = value;
-                RaisePropertyChanged(nameof(ProgressValue));
-            }
+            progressValue = value;
+            RaisePropertyChanged(nameof(ProgressValue));
         }
         }
+    }
+
+    public void InstallUpdate()
+    {
+        string[] files = Directory.GetFiles(UpdateDownloader.DownloadLocation, "update-*.zip");
 
 
-        public void InstallUpdate()
+        if (files.Length > 0)
         {
         {
-            string[] files = Directory.GetFiles(UpdateDownloader.DownloadLocation, "update-*.zip");
-
-            if (files.Length > 0)
-            {
-                Installer = new UpdateModule.UpdateInstaller(files[0], UpdateDirectory);
-                Installer.ProgressChanged += Installer_ProgressChanged;
-                Installer.Install();
-            }
-            else
-            {
-                ProgressValue = 100;
-            }
+            Installer = new UpdateModule.UpdateInstaller(files[0], UpdateDirectory);
+            Installer.ProgressChanged += Installer_ProgressChanged;
+            Installer.Install();
         }
         }
-
-        private void Installer_ProgressChanged(object sender, UpdateProgressChangedEventArgs e)
+        else
         {
         {
-            ProgressValue = e.Progress;
+            ProgressValue = 100;
         }
         }
     }
     }
+
+    private void Installer_ProgressChanged(object sender, UpdateProgressChangedEventArgs e)
+    {
+        ProgressValue = e.Progress;
+    }
 }
 }

+ 9 - 10
src/PixiEditor.UpdateModule/Asset.cs

@@ -1,16 +1,15 @@
 using System.Text.Json.Serialization;
 using System.Text.Json.Serialization;
 
 
-namespace PixiEditor.UpdateModule
+namespace PixiEditor.UpdateModule;
+
+public class Asset
 {
 {
-    public class Asset
-    {
-        [JsonPropertyName("url")]
-        public string Url { get; set; }
+    [JsonPropertyName("url")]
+    public string Url { get; set; }
 
 
-        [JsonPropertyName("name")]
-        public string Name { get; set; }
+    [JsonPropertyName("name")]
+    public string Name { get; set; }
 
 
-        [JsonPropertyName("content_type")]
-        public string ContentType { get; set; }
-    }
+    [JsonPropertyName("content_type")]
+    public string ContentType { get; set; }
 }
 }

+ 18 - 19
src/PixiEditor.UpdateModule/ReleaseInfo.cs

@@ -1,30 +1,29 @@
 using System.Text.Json.Serialization;
 using System.Text.Json.Serialization;
 
 
-namespace PixiEditor.UpdateModule
+namespace PixiEditor.UpdateModule;
+
+public class ReleaseInfo
 {
 {
-    public class ReleaseInfo
+    public ReleaseInfo()
     {
     {
-        public ReleaseInfo()
-        {
-        }
+    }
 
 
-        public ReleaseInfo(bool dataFetchSuccessful)
-        {
-            WasDataFetchSuccessful = dataFetchSuccessful;
-        }
+    public ReleaseInfo(bool dataFetchSuccessful)
+    {
+        WasDataFetchSuccessful = dataFetchSuccessful;
+    }
 
 
-        [JsonPropertyName("tag_name")]
-        public string TagName { get; set; }
+    [JsonPropertyName("tag_name")]
+    public string TagName { get; set; }
 
 
-        [JsonPropertyName("draft")]
-        public bool IsDraft { get; set; }
+    [JsonPropertyName("draft")]
+    public bool IsDraft { get; set; }
 
 
-        [JsonPropertyName("prerelease")]
-        public bool IsPrerelease { get; set; }
+    [JsonPropertyName("prerelease")]
+    public bool IsPrerelease { get; set; }
 
 
-        [JsonPropertyName("assets")]
-        public Asset[] Assets { get; set; }
+    [JsonPropertyName("assets")]
+    public Asset[] Assets { get; set; }
 
 
-        public bool WasDataFetchSuccessful { get; set; } = true;
-    }
+    public bool WasDataFetchSuccessful { get; set; } = true;
 }
 }

+ 16 - 17
src/PixiEditor.UpdateModule/UpdateChannel.cs

@@ -4,23 +4,22 @@ using System.Linq;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
-namespace PixiEditor.UpdateModule
+namespace PixiEditor.UpdateModule;
+
+public class UpdateChannel
 {
 {
-    public class UpdateChannel
-    {
-        public string Name { get; }
-        public string RepositoryOwner { get; }
-        public string RepositoryName { get; }
-        public string ApiUrl { get; } 
-        public string IncompatibleFileApiUrl { get; }
+    public string Name { get; }
+    public string RepositoryOwner { get; }
+    public string RepositoryName { get; }
+    public string ApiUrl { get; } 
+    public string IncompatibleFileApiUrl { get; }
 
 
-        public UpdateChannel(string name, string repositoryOwner, string repositoryName)
-        {
-            Name = name;
-            RepositoryOwner = repositoryOwner;
-            RepositoryName = repositoryName;
-            ApiUrl = $"https://api.github.com/repos/{repositoryOwner}/{repositoryName}/releases/latest";
-            IncompatibleFileApiUrl = "https://raw.githubusercontent.com/" + $"{repositoryOwner}/{repositoryName}/" + "{0}/incompatible.json";
-        }
+    public UpdateChannel(string name, string repositoryOwner, string repositoryName)
+    {
+        Name = name;
+        RepositoryOwner = repositoryOwner;
+        RepositoryName = repositoryName;
+        ApiUrl = $"https://api.github.com/repos/{repositoryOwner}/{repositoryName}/releases/latest";
+        IncompatibleFileApiUrl = "https://raw.githubusercontent.com/" + $"{repositoryOwner}/{repositoryName}/" + "{0}/incompatible.json";
     }
     }
-}
+}

+ 68 - 69
src/PixiEditor.UpdateModule/UpdateChecker.cs

@@ -6,100 +6,99 @@ using System.Net.Http;
 using System.Text.Json;
 using System.Text.Json;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
-namespace PixiEditor.UpdateModule
+namespace PixiEditor.UpdateModule;
+
+public class UpdateChecker
 {
 {
-    public class UpdateChecker
+    public UpdateChecker(string currentVersionTag, UpdateChannel channel)
     {
     {
-        public UpdateChecker(string currentVersionTag, UpdateChannel channel)
-        {
-            CurrentVersionTag = currentVersionTag;
-            Channel = channel;
-        }
+        CurrentVersionTag = currentVersionTag;
+        Channel = channel;
+    }
 
 
-        public ReleaseInfo LatestReleaseInfo { get; private set; }
+    public ReleaseInfo LatestReleaseInfo { get; private set; }
 
 
-        public UpdateChannel Channel { get; set; }
+    public UpdateChannel Channel { get; set; }
 
 
-        public string CurrentVersionTag { get; }
+    public string CurrentVersionTag { get; }
 
 
-        /// <summary>
-        ///     Compares version strings and returns true if newVer > originalVer.
-        /// </summary>
-        /// <param name="originalVer">Version to compare.</param>
-        /// <param name="newVer">Version to compare with.</param>
-        /// <returns>True if semantic version is higher.</returns>
-        public static bool VersionBigger(string originalVer, string newVer)
+    /// <summary>
+    ///     Compares version strings and returns true if newVer > originalVer.
+    /// </summary>
+    /// <param name="originalVer">Version to compare.</param>
+    /// <param name="newVer">Version to compare with.</param>
+    /// <returns>True if semantic version is higher.</returns>
+    public static bool VersionBigger(string originalVer, string newVer)
+    {
+        if (!ParseVersionString(originalVer, out float ver1))
         {
         {
-            if (!ParseVersionString(originalVer, out float ver1))
-            {
-                return false;
-            }
-
-            if (ParseVersionString(newVer, out float ver2))
-            {
-                return ver2 > ver1;
-            }
-
             return false;
             return false;
         }
         }
 
 
-        public async Task<bool> CheckUpdateAvailable()
+        if (ParseVersionString(newVer, out float ver2))
         {
         {
-            LatestReleaseInfo = await GetLatestReleaseInfoAsync(Channel.ApiUrl);
-            return CheckUpdateAvailable(LatestReleaseInfo);
+            return ver2 > ver1;
         }
         }
 
 
-        public bool CheckUpdateAvailable(ReleaseInfo latestRelease)
-        {
-            return latestRelease.WasDataFetchSuccessful && VersionBigger(CurrentVersionTag, latestRelease.TagName);
-        }
+        return false;
+    }
 
 
-        public bool IsUpdateCompatible(string[] incompatibleVersions)
-        {
-            return !incompatibleVersions.Select(x => x.Trim()).Contains(CurrentVersionTag[..7].Trim());
-        }
+    public async Task<bool> CheckUpdateAvailable()
+    {
+        LatestReleaseInfo = await GetLatestReleaseInfoAsync(Channel.ApiUrl);
+        return CheckUpdateAvailable(LatestReleaseInfo);
+    }
 
 
-        public async Task<bool> IsUpdateCompatible()
-        {
-            string[] incompatibleVersions = await GetUpdateIncompatibleVersionsAsync(LatestReleaseInfo.TagName);
-            return IsUpdateCompatible(incompatibleVersions);
-        }
+    public bool CheckUpdateAvailable(ReleaseInfo latestRelease)
+    {
+        return latestRelease.WasDataFetchSuccessful && VersionBigger(CurrentVersionTag, latestRelease.TagName);
+    }
+
+    public bool IsUpdateCompatible(string[] incompatibleVersions)
+    {
+        return !incompatibleVersions.Select(x => x.Trim()).Contains(CurrentVersionTag[..7].Trim());
+    }
 
 
-        public async Task<string[]> GetUpdateIncompatibleVersionsAsync(string tag)
+    public async Task<bool> IsUpdateCompatible()
+    {
+        string[] incompatibleVersions = await GetUpdateIncompatibleVersionsAsync(LatestReleaseInfo.TagName);
+        return IsUpdateCompatible(incompatibleVersions);
+    }
+
+    public async Task<string[]> GetUpdateIncompatibleVersionsAsync(string tag)
+    {
+        using (HttpClient client = new HttpClient())
         {
         {
-            using (HttpClient client = new HttpClient())
+            client.DefaultRequestHeaders.Add("User-Agent", "PixiEditor");
+            HttpResponseMessage response = await client.GetAsync(string.Format(Channel.IncompatibleFileApiUrl, tag));
+            if (response.StatusCode == HttpStatusCode.OK)
             {
             {
-                client.DefaultRequestHeaders.Add("User-Agent", "PixiEditor");
-                HttpResponseMessage response = await client.GetAsync(string.Format(Channel.IncompatibleFileApiUrl, tag));
-                if (response.StatusCode == HttpStatusCode.OK)
-                {
-                    string content = await response.Content.ReadAsStringAsync();
-                    return JsonSerializer.Deserialize<string[]>(content);
-                }
+                string content = await response.Content.ReadAsStringAsync();
+                return JsonSerializer.Deserialize<string[]>(content);
             }
             }
-
-            return Array.Empty<string>();
         }
         }
 
 
-        private static async Task<ReleaseInfo> GetLatestReleaseInfoAsync(string apiUrl)
+        return Array.Empty<string>();
+    }
+
+    private static async Task<ReleaseInfo> GetLatestReleaseInfoAsync(string apiUrl)
+    {
+        using (HttpClient client = new HttpClient())
         {
         {
-            using (HttpClient client = new HttpClient())
+            client.DefaultRequestHeaders.Add("User-Agent", "PixiEditor");
+            HttpResponseMessage response = await client.GetAsync(apiUrl);
+            if (response.StatusCode == HttpStatusCode.OK)
             {
             {
-                client.DefaultRequestHeaders.Add("User-Agent", "PixiEditor");
-                HttpResponseMessage response = await client.GetAsync(apiUrl);
-                if (response.StatusCode == HttpStatusCode.OK)
-                {
-                    string content = await response.Content.ReadAsStringAsync();
-                    return JsonSerializer.Deserialize<ReleaseInfo>(content);
-                }
+                string content = await response.Content.ReadAsStringAsync();
+                return JsonSerializer.Deserialize<ReleaseInfo>(content);
             }
             }
-
-            return new ReleaseInfo(false);
         }
         }
 
 
-        private static bool ParseVersionString(string versionString, out float version)
-        {
-            return float.TryParse(versionString[..7].Replace(".", string.Empty).Insert(1, "."), NumberStyles.Any, CultureInfo.InvariantCulture, out version);
-        }
+        return new ReleaseInfo(false);
+    }
+
+    private static bool ParseVersionString(string versionString, out float version)
+    {
+        return float.TryParse(versionString[..7].Replace(".", string.Empty).Insert(1, "."), NumberStyles.Any, CultureInfo.InvariantCulture, out version);
     }
     }
 }
 }

+ 39 - 40
src/PixiEditor.UpdateModule/UpdateDownloader.cs

@@ -5,61 +5,60 @@ using System.Net;
 using System.Net.Http;
 using System.Net.Http;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
-namespace PixiEditor.UpdateModule
+namespace PixiEditor.UpdateModule;
+
+public static class UpdateDownloader
 {
 {
-    public static class UpdateDownloader
+    public static string DownloadLocation { get; } = Path.Join(Path.GetTempPath(), "PixiEditor");
+
+    public static async Task DownloadReleaseZip(ReleaseInfo release)
     {
     {
-        public static string DownloadLocation { get; } = Path.Join(Path.GetTempPath(), "PixiEditor");
+        Asset matchingAsset = GetMatchingAsset(release);
 
 
-        public static async Task DownloadReleaseZip(ReleaseInfo release)
+        using (HttpClient client = new HttpClient())
         {
         {
-            Asset matchingAsset = GetMatchingAsset(release);
-
-            using (HttpClient client = new HttpClient())
+            client.DefaultRequestHeaders.Add("User-Agent", "PixiEditor");
+            client.DefaultRequestHeaders.Add("Accept", "application/octet-stream");
+            var response = await client.GetAsync(matchingAsset.Url);
+            if (response.StatusCode == HttpStatusCode.OK)
             {
             {
-                client.DefaultRequestHeaders.Add("User-Agent", "PixiEditor");
-                client.DefaultRequestHeaders.Add("Accept", "application/octet-stream");
-                var response = await client.GetAsync(matchingAsset.Url);
-                if (response.StatusCode == HttpStatusCode.OK)
-                {
-                    byte[] bytes = await response.Content.ReadAsByteArrayAsync();
-                    CreateTempDirectory();
-                    File.WriteAllBytes(Path.Join(DownloadLocation, $"update-{release.TagName}.zip"), bytes);
-                }
+                byte[] bytes = await response.Content.ReadAsByteArrayAsync();
+                CreateTempDirectory();
+                File.WriteAllBytes(Path.Join(DownloadLocation, $"update-{release.TagName}.zip"), bytes);
             }
             }
         }
         }
+    }
 
 
-        public static async Task DownloadInstaller(ReleaseInfo info)
-        {
-            Asset matchingAsset = GetMatchingAsset(info, "application/x-msdownload");
-
-            using (HttpClient client = new HttpClient())
-            {
-                client.DefaultRequestHeaders.Add("User-Agent", "PixiEditor");
-                client.DefaultRequestHeaders.Add("Accept", "application/octet-stream");
-                var response = await client.GetAsync(matchingAsset.Url);
-                if (response.StatusCode == HttpStatusCode.OK)
-                {
-                    byte[] bytes = await response.Content.ReadAsByteArrayAsync();
-                    CreateTempDirectory();
-                    File.WriteAllBytes(Path.Join(DownloadLocation, $"update-{info.TagName}.exe"), bytes);
-                }
-            }
-        }
+    public static async Task DownloadInstaller(ReleaseInfo info)
+    {
+        Asset matchingAsset = GetMatchingAsset(info, "application/x-msdownload");
 
 
-        public static void CreateTempDirectory()
+        using (HttpClient client = new HttpClient())
         {
         {
-            if (!Directory.Exists(DownloadLocation))
+            client.DefaultRequestHeaders.Add("User-Agent", "PixiEditor");
+            client.DefaultRequestHeaders.Add("Accept", "application/octet-stream");
+            var response = await client.GetAsync(matchingAsset.Url);
+            if (response.StatusCode == HttpStatusCode.OK)
             {
             {
-                Directory.CreateDirectory(DownloadLocation);
+                byte[] bytes = await response.Content.ReadAsByteArrayAsync();
+                CreateTempDirectory();
+                File.WriteAllBytes(Path.Join(DownloadLocation, $"update-{info.TagName}.exe"), bytes);
             }
             }
         }
         }
+    }
 
 
-        private static Asset GetMatchingAsset(ReleaseInfo release, string assetType = "zip")
+    public static void CreateTempDirectory()
+    {
+        if (!Directory.Exists(DownloadLocation))
         {
         {
-            string arch = IntPtr.Size == 8 ? "x64" : "x86";
-            return release.Assets.First(x => x.ContentType.Contains(assetType)
-            && x.Name.Contains(arch));
+            Directory.CreateDirectory(DownloadLocation);
         }
         }
     }
     }
+
+    private static Asset GetMatchingAsset(ReleaseInfo release, string assetType = "zip")
+    {
+        string arch = IntPtr.Size == 8 ? "x64" : "x86";
+        return release.Assets.First(x => x.ContentType.Contains(assetType)
+                                         && x.Name.Contains(arch));
+    }
 }
 }

+ 48 - 49
src/PixiEditor.UpdateModule/UpdateInstaller.cs

@@ -3,71 +3,70 @@ using System.Diagnostics;
 using System.IO;
 using System.IO;
 using System.IO.Compression;
 using System.IO.Compression;
 
 
-namespace PixiEditor.UpdateModule
+namespace PixiEditor.UpdateModule;
+
+public class UpdateInstaller
 {
 {
-    public class UpdateInstaller
-    {
-        public const string TargetDirectoryName = "UpdateFiles";
+    public const string TargetDirectoryName = "UpdateFiles";
 
 
-        private float progress = 0;
+    private float progress = 0;
 
 
-        public UpdateInstaller(string archiveFileName, string targetDirectory)
-        {
-            ArchiveFileName = archiveFileName;
-            TargetDirectory = targetDirectory;
-        }
+    public UpdateInstaller(string archiveFileName, string targetDirectory)
+    {
+        ArchiveFileName = archiveFileName;
+        TargetDirectory = targetDirectory;
+    }
 
 
-        public event EventHandler<UpdateProgressChangedEventArgs> ProgressChanged;
+    public event EventHandler<UpdateProgressChangedEventArgs> ProgressChanged;
 
 
-        public static string UpdateFilesPath { get; set; } = Path.Join(UpdateDownloader.DownloadLocation, TargetDirectoryName);
+    public static string UpdateFilesPath { get; set; } = Path.Join(UpdateDownloader.DownloadLocation, TargetDirectoryName);
 
 
-        public float Progress
+    public float Progress
+    {
+        get => progress;
+        set
         {
         {
-            get => progress;
-            set
-            {
-                progress = value;
-                ProgressChanged?.Invoke(this, new UpdateProgressChangedEventArgs(value));
-            }
+            progress = value;
+            ProgressChanged?.Invoke(this, new UpdateProgressChangedEventArgs(value));
         }
         }
+    }
 
 
-        public string ArchiveFileName { get; set; }
+    public string ArchiveFileName { get; set; }
 
 
-        public string TargetDirectory { get; set; }
+    public string TargetDirectory { get; set; }
 
 
-        public void Install()
+    public void Install()
+    {
+        var processes = Process.GetProcessesByName("PixiEditor");
+        if (processes.Length > 0)
         {
         {
-            var processes = Process.GetProcessesByName("PixiEditor");
-            if (processes.Length > 0)
-            {
-                processes[0].WaitForExit();
-            }
-
-            ZipFile.ExtractToDirectory(ArchiveFileName, UpdateFilesPath, true);
-            Progress = 25; // 25% for unzip
-            string dirWithFiles = Directory.GetDirectories(UpdateFilesPath)[0];
-            string[] files = Directory.GetFiles(dirWithFiles);
-            CopyFilesToDestination(files);
-            DeleteArchive();
-            Progress = 100;
+            processes[0].WaitForExit();
         }
         }
 
 
-        private void DeleteArchive()
-        {
-            File.Delete(ArchiveFileName);
-            Directory.Delete(UpdateFilesPath, true);
-        }
+        ZipFile.ExtractToDirectory(ArchiveFileName, UpdateFilesPath, true);
+        Progress = 25; // 25% for unzip
+        string dirWithFiles = Directory.GetDirectories(UpdateFilesPath)[0];
+        string[] files = Directory.GetFiles(dirWithFiles);
+        CopyFilesToDestination(files);
+        DeleteArchive();
+        Progress = 100;
+    }
 
 
-        private void CopyFilesToDestination(string[] files)
+    private void DeleteArchive()
+    {
+        File.Delete(ArchiveFileName);
+        Directory.Delete(UpdateFilesPath, true);
+    }
+
+    private void CopyFilesToDestination(string[] files)
+    {
+        float fileCopiedVal = 74f / files.Length; // 74% is reserved for copying
+        string destinationDir = TargetDirectory;
+        foreach (string file in files)
         {
         {
-            float fileCopiedVal = 74f / files.Length; // 74% is reserved for copying
-            string destinationDir = TargetDirectory;
-            foreach (string file in files)
-            {
-                string targetFileName = Path.GetFileName(file);
-                File.Copy(file, Path.Join(destinationDir, targetFileName), true);
-                Progress += fileCopiedVal;
-            }
+            string targetFileName = Path.GetFileName(file);
+            File.Copy(file, Path.Join(destinationDir, targetFileName), true);
+            Progress += fileCopiedVal;
         }
         }
     }
     }
 }
 }

+ 7 - 8
src/PixiEditor.UpdateModule/UpdateProgressChangedEventArgs.cs

@@ -1,14 +1,13 @@
 using System;
 using System;
 
 
-namespace PixiEditor.UpdateModule
+namespace PixiEditor.UpdateModule;
+
+public class UpdateProgressChangedEventArgs : EventArgs
 {
 {
-    public class UpdateProgressChangedEventArgs : EventArgs
+    public UpdateProgressChangedEventArgs(float progress)
     {
     {
-        public UpdateProgressChangedEventArgs(float progress)
-        {
-            Progress = progress;
-        }
-
-        public float Progress { get; set; }
+        Progress = progress;
     }
     }
+
+    public float Progress { get; set; }
 }
 }

+ 89 - 90
src/PixiEditor/App.xaml.cs

@@ -14,118 +14,117 @@ using System.Windows;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.UserPreferences;
 using PixiEditor.Models.UserPreferences;
 
 
-namespace PixiEditor
+namespace PixiEditor;
+
+/// <summary>
+///     Interaction logic for App.xaml.
+/// </summary>
+public partial class App : Application
 {
 {
-    /// <summary>
-    ///     Interaction logic for App.xaml.
-    /// </summary>
-    public partial class App : Application
-    {
-        /// <summary>The event mutex name.</summary>
-        private const string UniqueEventName = "33f1410b-2ad7-412a-a468-34fe0a85747c";
+    /// <summary>The event mutex name.</summary>
+    private const string UniqueEventName = "33f1410b-2ad7-412a-a468-34fe0a85747c";
 
 
-        /// <summary>The unique mutex name.</summary>
-        private const string UniqueMutexName = "ab2afe27-b9ee-4f03-a1e4-c18da16a349c";
+    /// <summary>The unique mutex name.</summary>
+    private const string UniqueMutexName = "ab2afe27-b9ee-4f03-a1e4-c18da16a349c";
 
 
-        /// <summary>The event wait handle.</summary>
-        private EventWaitHandle _eventWaitHandle;
+    /// <summary>The event wait handle.</summary>
+    private EventWaitHandle _eventWaitHandle;
 
 
-        private string passedArgsFile = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "PixiEditor", ".passedArgs");
+    private string passedArgsFile = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "PixiEditor", ".passedArgs");
 
 
-        /// <summary>The mutex.</summary>
-        private Mutex _mutex;
+    /// <summary>The mutex.</summary>
+    private Mutex _mutex;
 
 
-        protected override void OnStartup(StartupEventArgs e)
+    protected override void OnStartup(StartupEventArgs e)
+    {
+        if (HandleNewInstance())
         {
         {
-            if (HandleNewInstance())
-            {
-                StartupArgs.Args = e.Args.ToList();
-                string arguments = string.Join(' ', e.Args);
+            StartupArgs.Args = e.Args.ToList();
+            string arguments = string.Join(' ', e.Args);
 
 
-                if (ParseArgument("--crash (\"?)([A-z0-9:\\/\\ -_.]+)\\1", arguments, out Group[] groups))
-                {
-                    CrashReport report = CrashReport.Parse(groups[2].Value);
-                    MainWindow = new CrashReportDialog(report);
-                }
-                else
-                {
-                    MainWindow = new MainWindow();
-                }
-
-                MainWindow.Show();
+            if (ParseArgument("--crash (\"?)([A-z0-9:\\/\\ -_.]+)\\1", arguments, out Group[] groups))
+            {
+                CrashReport report = CrashReport.Parse(groups[2].Value);
+                MainWindow = new CrashReportDialog(report);
+            }
+            else
+            {
+                MainWindow = new MainWindow();
             }
             }
+
+            MainWindow.Show();
         }
         }
+    }
 
 
-        private bool HandleNewInstance()
-        {
-            bool isOwned;
-            _mutex = new Mutex(true, UniqueMutexName, out isOwned);
-            _eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, UniqueEventName);
+    private bool HandleNewInstance()
+    {
+        bool isOwned;
+        _mutex = new Mutex(true, UniqueMutexName, out isOwned);
+        _eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, UniqueEventName);
 
 
-            GC.KeepAlive(_mutex);
+        GC.KeepAlive(_mutex);
 
 
-            if (isOwned)
-            {
-                var thread = new Thread(
-                    () =>
+        if (isOwned)
+        {
+            var thread = new Thread(
+                () =>
+                {
+                    while (_eventWaitHandle.WaitOne())
                     {
                     {
-                        while (_eventWaitHandle.WaitOne())
-                        {
-                            Current.Dispatcher.BeginInvoke(
-                                (Action)(() =>
+                        Current.Dispatcher.BeginInvoke(
+                            (Action)(() =>
+                            {
+                                MainWindow mainWindow = ((MainWindow)Current.MainWindow);
+                                if (mainWindow != null)
                                 {
                                 {
-                                    MainWindow mainWindow = ((MainWindow)Current.MainWindow);
-                                    if (mainWindow != null)
-                                    {
-                                        mainWindow.BringToForeground();
-                                        StartupArgs.Args = File.ReadAllText(passedArgsFile).Split(' ').ToList();
-                                        File.Delete(passedArgsFile);
-                                        StartupArgs.Args.Add("--openedInExisting");
-                                        mainWindow.DataContext.OnStartupCommand.Execute(null);
-                                    }
-                                }));
-                        }
-                    })
-                {
-                    // It is important mark it as background otherwise it will prevent app from exiting.
-                    IsBackground = true
-                };
-
-                thread.Start();
-                return true;
-            }
-
-            // Notify other instance so it could bring itself to foreground.
-            File.WriteAllText(passedArgsFile, string.Join(' ', Environment.GetCommandLineArgs()));
-            _eventWaitHandle.Set();
+                                    mainWindow.BringToForeground();
+                                    StartupArgs.Args = File.ReadAllText(passedArgsFile).Split(' ').ToList();
+                                    File.Delete(passedArgsFile);
+                                    StartupArgs.Args.Add("--openedInExisting");
+                                    mainWindow.DataContext.OnStartupCommand.Execute(null);
+                                }
+                            }));
+                    }
+                })
+            {
+                // It is important mark it as background otherwise it will prevent app from exiting.
+                IsBackground = true
+            };
 
 
-            // Terminate this instance.
-            Shutdown();
-            return false;
+            thread.Start();
+            return true;
         }
         }
 
 
-        protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
-        {
-            base.OnSessionEnding(e);
+        // Notify other instance so it could bring itself to foreground.
+        File.WriteAllText(passedArgsFile, string.Join(' ', Environment.GetCommandLineArgs()));
+        _eventWaitHandle.Set();
 
 
-            if (ViewModelMain.Current.BitmapManager.Documents.Any(x => !x.ChangesSaved))
-            {
-                ConfirmationType confirmation = ConfirmationDialog.Show($"{e.ReasonSessionEnding} with unsaved data. Are you sure?", $"{e.ReasonSessionEnding}");
-                e.Cancel = confirmation != ConfirmationType.Yes;
-            }
-        }
+        // Terminate this instance.
+        Shutdown();
+        return false;
+    }
 
 
-        private bool ParseArgument(string pattern, string args, out Group[] groups)
+    protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
+    {
+        base.OnSessionEnding(e);
+
+        if (ViewModelMain.Current.BitmapManager.Documents.Any(x => !x.ChangesSaved))
         {
         {
-            Match match = Regex.Match(args, pattern, RegexOptions.IgnoreCase);
-            groups = null;
+            ConfirmationType confirmation = ConfirmationDialog.Show($"{e.ReasonSessionEnding} with unsaved data. Are you sure?", $"{e.ReasonSessionEnding}");
+            e.Cancel = confirmation != ConfirmationType.Yes;
+        }
+    }
 
 
-            if (match.Success)
-            {
-                groups = match.Groups.Values.ToArray();
-            }
+    private bool ParseArgument(string pattern, string args, out Group[] groups)
+    {
+        Match match = Regex.Match(args, pattern, RegexOptions.IgnoreCase);
+        groups = null;
 
 
-            return match.Success;
+        if (match.Success)
+        {
+            groups = match.Groups.Values.ToArray();
         }
         }
+
+        return match.Success;
     }
     }
-}
+}

+ 21 - 22
src/PixiEditor/Exceptions/CorruptedFileException.cs

@@ -1,30 +1,29 @@
 using System;
 using System;
 
 
-namespace PixiEditor.Exceptions
+namespace PixiEditor.Exceptions;
+
+[Serializable]
+public class CorruptedFileException : Exception
 {
 {
-    [Serializable]
-    public class CorruptedFileException : Exception
+    public CorruptedFileException()
+        : base("The file you've chosen might be corrupted.")
     {
     {
-        public CorruptedFileException()
-            : base("The file you've chosen might be corrupted.")
-        {
-        }
+    }
 
 
-        public CorruptedFileException(string message)
-            : base(message)
-        {
-        }
+    public CorruptedFileException(string message)
+        : base(message)
+    {
+    }
 
 
-        public CorruptedFileException(string message, Exception inner)
-            : base(message, inner)
-        {
-        }
+    public CorruptedFileException(string message, Exception inner)
+        : base(message, inner)
+    {
+    }
 
 
-        protected CorruptedFileException(
-          System.Runtime.Serialization.SerializationInfo info,
-          System.Runtime.Serialization.StreamingContext context)
-            : base(info, context)
-        {
-        }
+    protected CorruptedFileException(
+        System.Runtime.Serialization.SerializationInfo info,
+        System.Runtime.Serialization.StreamingContext context)
+        : base(info, context)
+    {
     }
     }
-}
+}

+ 20 - 21
src/PixiEditor/Helpers/Behaviours/ClearFocusOnClickBehavior.cs

@@ -3,31 +3,30 @@ using System.Windows;
 using System.Windows.Input;
 using System.Windows.Input;
 using System.Windows.Interactivity;
 using System.Windows.Interactivity;
 
 
-namespace PixiEditor.Helpers.Behaviours
+namespace PixiEditor.Helpers.Behaviours;
+
+public class ClearFocusOnClickBehavior : Behavior<FrameworkElement>
 {
 {
-    public class ClearFocusOnClickBehavior : Behavior<FrameworkElement>
+    protected override void OnAttached()
     {
     {
-        protected override void OnAttached()
-        {
-            base.OnAttached();
-            AssociatedObject.MouseDown += AssociatedObject_MouseDown;
-            AssociatedObject.LostKeyboardFocus += AssociatedObject_LostKeyboardFocus;
-        }
+        base.OnAttached();
+        AssociatedObject.MouseDown += AssociatedObject_MouseDown;
+        AssociatedObject.LostKeyboardFocus += AssociatedObject_LostKeyboardFocus;
+    }
 
 
-        private void AssociatedObject_LostKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
-        {
+    private void AssociatedObject_LostKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
+    {
             
             
-        }
+    }
 
 
-        protected override void OnDetaching()
-        {
-            AssociatedObject.MouseDown -= AssociatedObject_MouseDown;
-        }
+    protected override void OnDetaching()
+    {
+        AssociatedObject.MouseDown -= AssociatedObject_MouseDown;
+    }
 
 
-        private void AssociatedObject_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
-        {
-            AssociatedObject.Focus();
-            ShortcutController.UnblockShortcutExecutionAll();
-        }
+    private void AssociatedObject_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
+    {
+        AssociatedObject.Focus();
+        ShortcutController.UnblockShortcutExecutionAll();
     }
     }
-}
+}

+ 21 - 22
src/PixiEditor/Helpers/Behaviours/GlobalShortcutFocusBehavior.cs

@@ -7,32 +7,31 @@ using System.Windows;
 using System.Windows.Interactivity;
 using System.Windows.Interactivity;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Controllers;
 
 
-namespace PixiEditor.Helpers.Behaviours
+namespace PixiEditor.Helpers.Behaviours;
+
+public class GlobalShortcutFocusBehavior : Behavior<FrameworkElement>
 {
 {
-    public class GlobalShortcutFocusBehavior : Behavior<FrameworkElement>
+    protected override void OnAttached()
     {
     {
-        protected override void OnAttached()
-        {
-            base.OnAttached();
-            AssociatedObject.GotKeyboardFocus += AssociatedObject_GotKeyboardFocus;
-            AssociatedObject.LostKeyboardFocus += AssociatedObject_LostKeyboardFocus;
-        }
+        base.OnAttached();
+        AssociatedObject.GotKeyboardFocus += AssociatedObject_GotKeyboardFocus;
+        AssociatedObject.LostKeyboardFocus += AssociatedObject_LostKeyboardFocus;
+    }
 
 
-        protected override void OnDetaching()
-        {
-            base.OnDetaching();
-            AssociatedObject.GotKeyboardFocus -= AssociatedObject_GotKeyboardFocus;
-            AssociatedObject.LostKeyboardFocus -= AssociatedObject_LostKeyboardFocus;
-        }
+    protected override void OnDetaching()
+    {
+        base.OnDetaching();
+        AssociatedObject.GotKeyboardFocus -= AssociatedObject_GotKeyboardFocus;
+        AssociatedObject.LostKeyboardFocus -= AssociatedObject_LostKeyboardFocus;
+    }
 
 
-        private void AssociatedObject_LostKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
-        {
-            ShortcutController.UnblockShortcutExecution("GlobalShortcutFocusBehavior");
-        }
+    private void AssociatedObject_LostKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
+    {
+        ShortcutController.UnblockShortcutExecution("GlobalShortcutFocusBehavior");
+    }
 
 
-        private void AssociatedObject_GotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
-        {
-            ShortcutController.BlockShortcutExection("GlobalShortcutFocusBehavior");
-        }
+    private void AssociatedObject_GotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
+    {
+        ShortcutController.BlockShortcutExection("GlobalShortcutFocusBehavior");
     }
     }
 }
 }

+ 19 - 20
src/PixiEditor/Helpers/Behaviours/TextBlockExtensions.cs

@@ -2,32 +2,31 @@
 using System.Windows.Controls;
 using System.Windows.Controls;
 using System.Windows.Documents;
 using System.Windows.Documents;
 
 
-namespace PixiEditor.Helpers.Behaviours
+namespace PixiEditor.Helpers.Behaviours;
+
+public static class TextBlockExtensions
 {
 {
-    public static class TextBlockExtensions
+    public static IEnumerable<Inline> GetBindableInlines(DependencyObject obj)
     {
     {
-        public static IEnumerable<Inline> GetBindableInlines(DependencyObject obj)
-        {
-            return (IEnumerable<Inline>)obj.GetValue(BindableInlinesProperty);
-        }
+        return (IEnumerable<Inline>)obj.GetValue(BindableInlinesProperty);
+    }
 
 
-        public static void SetBindableInlines(DependencyObject obj, IEnumerable<Inline> value)
-        {
-            obj.SetValue(BindableInlinesProperty, value);
-        }
+    public static void SetBindableInlines(DependencyObject obj, IEnumerable<Inline> value)
+    {
+        obj.SetValue(BindableInlinesProperty, value);
+    }
 
 
-        public static readonly DependencyProperty BindableInlinesProperty =
-            DependencyProperty.RegisterAttached("BindableInlines", typeof(IEnumerable<Inline>), typeof(TextBlockExtensions), new PropertyMetadata(null, OnBindableInlinesChanged));
+    public static readonly DependencyProperty BindableInlinesProperty =
+        DependencyProperty.RegisterAttached("BindableInlines", typeof(IEnumerable<Inline>), typeof(TextBlockExtensions), new PropertyMetadata(null, OnBindableInlinesChanged));
 
 
-        private static void OnBindableInlinesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    private static void OnBindableInlinesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not TextBlock target)
         {
         {
-            if (d is not TextBlock target)
-            {
-                return;
-            }
-
-            target.Inlines.Clear();
-            target.Inlines.AddRange((System.Collections.IEnumerable)e.NewValue);
+            return;
         }
         }
+
+        target.Inlines.Clear();
+        target.Inlines.AddRange((System.Collections.IEnumerable)e.NewValue);
     }
     }
 }
 }

+ 107 - 108
src/PixiEditor/Helpers/Behaviours/TextBoxFocusBehavior.cs

@@ -3,131 +3,130 @@ using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Input;
 using System.Windows.Interactivity;
 using System.Windows.Interactivity;
 
 
-namespace PixiEditor.Helpers.Behaviours
+namespace PixiEditor.Helpers.Behaviours;
+
+internal class TextBoxFocusBehavior : Behavior<TextBox>
 {
 {
-    internal class TextBoxFocusBehavior : Behavior<TextBox>
+    public static readonly DependencyProperty SelectOnMouseClickProperty =
+        DependencyProperty.Register(
+            nameof(SelectOnMouseClick),
+            typeof(bool),
+            typeof(TextBoxFocusBehavior),
+            new PropertyMetadata(false));
+
+    public static readonly DependencyProperty ConfirmOnEnterProperty =
+        DependencyProperty.Register(
+            nameof(ConfirmOnEnter),
+            typeof(bool),
+            typeof(TextBoxFocusBehavior),
+            new PropertyMetadata(false));
+
+    public static readonly DependencyProperty DeselectOnFocusLossProperty =
+        DependencyProperty.Register(
+            nameof(DeselectOnFocusLoss),
+            typeof(bool),
+            typeof(TextBoxFocusBehavior),
+            new PropertyMetadata(false));
+
+    public bool SelectOnMouseClick
     {
     {
-        public static readonly DependencyProperty SelectOnMouseClickProperty =
-            DependencyProperty.Register(
-                nameof(SelectOnMouseClick),
-                typeof(bool),
-                typeof(TextBoxFocusBehavior),
-                new PropertyMetadata(false));
-
-        public static readonly DependencyProperty ConfirmOnEnterProperty =
-            DependencyProperty.Register(
-                nameof(ConfirmOnEnter),
-                typeof(bool),
-                typeof(TextBoxFocusBehavior),
-                new PropertyMetadata(false));
-
-        public static readonly DependencyProperty DeselectOnFocusLossProperty =
-            DependencyProperty.Register(
-                nameof(DeselectOnFocusLoss),
-                typeof(bool),
-                typeof(TextBoxFocusBehavior),
-                new PropertyMetadata(false));
-
-        public bool SelectOnMouseClick
-        {
-            get => (bool)GetValue(SelectOnMouseClickProperty);
-            set => SetValue(SelectOnMouseClickProperty, value);
-        }
+        get => (bool)GetValue(SelectOnMouseClickProperty);
+        set => SetValue(SelectOnMouseClickProperty, value);
+    }
 
 
-        public bool ConfirmOnEnter
-        {
-            get => (bool)GetValue(ConfirmOnEnterProperty);
-            set => SetValue(ConfirmOnEnterProperty, value);
-        }
-        public bool DeselectOnFocusLoss
-        {
-            get => (bool)GetValue(DeselectOnFocusLossProperty);
-            set => SetValue(DeselectOnFocusLossProperty, value);
-        }
+    public bool ConfirmOnEnter
+    {
+        get => (bool)GetValue(ConfirmOnEnterProperty);
+        set => SetValue(ConfirmOnEnterProperty, value);
+    }
+    public bool DeselectOnFocusLoss
+    {
+        get => (bool)GetValue(DeselectOnFocusLossProperty);
+        set => SetValue(DeselectOnFocusLossProperty, value);
+    }
 
 
-        public static readonly DependencyProperty FocusNextProperty = DependencyProperty.Register(nameof(FocusNext), typeof(bool), typeof(TextBoxFocusBehavior), new PropertyMetadata(false));
+    public static readonly DependencyProperty FocusNextProperty = DependencyProperty.Register(nameof(FocusNext), typeof(bool), typeof(TextBoxFocusBehavior), new PropertyMetadata(false));
 
 
-        public bool FocusNext
-        {
-            get { return (bool)GetValue(FocusNextProperty); }
-            set { SetValue(FocusNextProperty, value); }
-        }
+    public bool FocusNext
+    {
+        get { return (bool)GetValue(FocusNextProperty); }
+        set { SetValue(FocusNextProperty, value); }
+    }
 
 
-        protected override void OnAttached()
-        {
-            base.OnAttached();
-            AssociatedObject.GotKeyboardFocus += AssociatedObjectGotKeyboardFocus;
-            AssociatedObject.GotMouseCapture += AssociatedObjectGotMouseCapture;
-            AssociatedObject.LostFocus += AssociatedObject_LostFocus;
-            AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObjectPreviewMouseLeftButtonDown;
-            AssociatedObject.KeyUp += AssociatedObject_KeyUp;
-        }
+    protected override void OnAttached()
+    {
+        base.OnAttached();
+        AssociatedObject.GotKeyboardFocus += AssociatedObjectGotKeyboardFocus;
+        AssociatedObject.GotMouseCapture += AssociatedObjectGotMouseCapture;
+        AssociatedObject.LostFocus += AssociatedObject_LostFocus;
+        AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObjectPreviewMouseLeftButtonDown;
+        AssociatedObject.KeyUp += AssociatedObject_KeyUp;
+    }
 
 
-        protected override void OnDetaching()
-        {
-            base.OnDetaching();
-            AssociatedObject.GotKeyboardFocus -= AssociatedObjectGotKeyboardFocus;
-            AssociatedObject.GotMouseCapture -= AssociatedObjectGotMouseCapture;
-            AssociatedObject.LostFocus -= AssociatedObject_LostFocus;
-            AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObjectPreviewMouseLeftButtonDown;
-            AssociatedObject.KeyUp -= AssociatedObject_KeyUp;
-        }
+    protected override void OnDetaching()
+    {
+        base.OnDetaching();
+        AssociatedObject.GotKeyboardFocus -= AssociatedObjectGotKeyboardFocus;
+        AssociatedObject.GotMouseCapture -= AssociatedObjectGotMouseCapture;
+        AssociatedObject.LostFocus -= AssociatedObject_LostFocus;
+        AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObjectPreviewMouseLeftButtonDown;
+        AssociatedObject.KeyUp -= AssociatedObject_KeyUp;
+    }
 
 
-        // Converts number to proper format if enter is clicked and moves focus to next object
-        private void AssociatedObject_KeyUp(object sender, KeyEventArgs e)
-        {
-            if (e.Key != Key.Enter || !ConfirmOnEnter)
-                return;
+    // Converts number to proper format if enter is clicked and moves focus to next object
+    private void AssociatedObject_KeyUp(object sender, KeyEventArgs e)
+    {
+        if (e.Key != Key.Enter || !ConfirmOnEnter)
+            return;
 
 
-            RemoveFocus();
-        }
+        RemoveFocus();
+    }
 
 
-        private void RemoveFocus()
+    private void RemoveFocus()
+    {
+        if (!FocusNext)
         {
         {
-            if (!FocusNext)
-            {
-                MainWindow.Current.mainGrid.Focus();
-            }
-            else
-            {
-                AssociatedObject.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
-            }
-
+            MainWindow.Current.mainGrid.Focus();
         }
         }
-
-        private void AssociatedObjectGotKeyboardFocus(
-            object sender,
-            KeyboardFocusChangedEventArgs e)
+        else
         {
         {
-            if (SelectOnMouseClick || e.KeyboardDevice.IsKeyDown(Key.Tab))
-                AssociatedObject.SelectAll();
+            AssociatedObject.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
         }
         }
 
 
-        private void AssociatedObjectGotMouseCapture(
-            object sender,
-            MouseEventArgs e)
-        {
-            if (SelectOnMouseClick)
-                AssociatedObject.SelectAll();
-        }
+    }
 
 
-        private void AssociatedObject_LostFocus(object sender, RoutedEventArgs e)
-        {
-            if (DeselectOnFocusLoss)
-                AssociatedObject.Select(0, 0);
-            RemoveFocus();
-        }
+    private void AssociatedObjectGotKeyboardFocus(
+        object sender,
+        KeyboardFocusChangedEventArgs e)
+    {
+        if (SelectOnMouseClick || e.KeyboardDevice.IsKeyDown(Key.Tab))
+            AssociatedObject.SelectAll();
+    }
+
+    private void AssociatedObjectGotMouseCapture(
+        object sender,
+        MouseEventArgs e)
+    {
+        if (SelectOnMouseClick)
+            AssociatedObject.SelectAll();
+    }
+
+    private void AssociatedObject_LostFocus(object sender, RoutedEventArgs e)
+    {
+        if (DeselectOnFocusLoss)
+            AssociatedObject.Select(0, 0);
+        RemoveFocus();
+    }
+
+    private void AssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+    {
+        if (!SelectOnMouseClick)
+            return;
 
 
-        private void AssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+        if (!AssociatedObject.IsKeyboardFocusWithin)
         {
         {
-            if (!SelectOnMouseClick)
-                return;
-
-            if (!AssociatedObject.IsKeyboardFocusWithin)
-            {
-                AssociatedObject.Focus();
-                e.Handled = true;
-            }
+            AssociatedObject.Focus();
+            e.Handled = true;
         }
         }
     }
     }
-}
+}

+ 14 - 15
src/PixiEditor/Helpers/BindingProxy.cs

@@ -1,21 +1,20 @@
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+public class BindingProxy : Freezable
 {
 {
-    public class BindingProxy : Freezable
+    protected override Freezable CreateInstanceCore()
     {
     {
-        protected override Freezable CreateInstanceCore()
-        {
-            return new BindingProxy();
-        }
-
-        public object Data
-        {
-            get { return (object)GetValue(DataProperty); }
-            set { SetValue(DataProperty, value); }
-        }
+        return new BindingProxy();
+    }
 
 
-        public static readonly DependencyProperty DataProperty =
-            DependencyProperty.Register(nameof(Data), typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
+    public object Data
+    {
+        get { return (object)GetValue(DataProperty); }
+        set { SetValue(DataProperty, value); }
     }
     }
-}
+
+    public static readonly DependencyProperty DataProperty =
+        DependencyProperty.Register(nameof(Data), typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
+}

+ 31 - 32
src/PixiEditor/Helpers/ClipboardHelper.cs

@@ -1,45 +1,44 @@
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+class ClipboardHelper
 {
 {
-    class ClipboardHelper
+    public static bool TrySetDataObject(DataObject obj, bool copy)
     {
     {
-        public static bool TrySetDataObject(DataObject obj, bool copy)
+        try
+        {
+            Clipboard.SetDataObject(obj, copy);
+            return true;
+        }
+        catch
         {
         {
-            try
-            {
-                Clipboard.SetDataObject(obj, copy);
-                return true;
-            }
-            catch
-            {
-                return false;
-            }
+            return false;
         }
         }
+    }
 
 
-        public static DataObject TryGetDataObject()
+    public static DataObject TryGetDataObject()
+    {
+        try
         {
         {
-            try
-            {
-                return (DataObject)Clipboard.GetDataObject();
-            }
-            catch
-            {
-                return null;
-            }
+            return (DataObject)Clipboard.GetDataObject();
         }
         }
+        catch
+        {
+            return null;
+        }
+    }
 
 
-        public static bool TryClear()
+    public static bool TryClear()
+    {
+        try
+        {
+            Clipboard.Clear();
+            return true;
+        }
+        catch
         {
         {
-            try
-            {
-                Clipboard.Clear();
-                return true;
-            }
-            catch
-            {
-                return false;
-            }
+            return false;
         }
         }
     }
     }
-}
+}

+ 14 - 15
src/PixiEditor/Helpers/Converters/BoolToIntConverter.cs

@@ -1,27 +1,26 @@
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class BoolToIntConverter
+    : SingleInstanceConverter<BoolToIntConverter>
 {
 {
-    public class BoolToIntConverter
-        : SingleInstanceConverter<BoolToIntConverter>
+    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return value.ToString() == "0";
-        }
+        return value.ToString() == "0";
+    }
 
 
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        if (value is bool boolean)
         {
         {
-            if (value is bool boolean)
+            if (boolean == false)
             {
             {
-                if (boolean == false)
-                {
-                    return 0;
-                }
+                return 0;
             }
             }
-
-            return 1;
         }
         }
+
+        return 1;
     }
     }
 }
 }

+ 9 - 10
src/PixiEditor/Helpers/Converters/CountToVisibilityConverter.cs

@@ -7,18 +7,17 @@ using System.Threading.Tasks;
 using System.Windows;
 using System.Windows;
 using System.Windows.Data;
 using System.Windows.Data;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class CountToVisibilityConverter : SingleInstanceConverter<CountToVisibilityConverter>
 {
 {
-    public class CountToVisibilityConverter : SingleInstanceConverter<CountToVisibilityConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        if (value is int intVal)
         {
         {
-            if (value is int intVal)
-            {
-                return intVal == 0 ? Visibility.Visible : Visibility.Collapsed;
-            }
-
-            return Visibility.Visible;
+            return intVal == 0 ? Visibility.Visible : Visibility.Collapsed;
         }
         }
+
+        return Visibility.Visible;
     }
     }
-}
+}

+ 11 - 12
src/PixiEditor/Helpers/Converters/DebugConverter.cs

@@ -1,19 +1,18 @@
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class DebugConverter
+    : SingleInstanceConverter<DebugConverter>
 {
 {
-    public class DebugConverter
-        : SingleInstanceConverter<DebugConverter>
+    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return value;
-        }
+        return value;
+    }
 
 
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return value;
-        }
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        return value;
     }
     }
-}
+}

+ 11 - 12
src/PixiEditor/Helpers/Converters/DoubleToIntConverter.cs

@@ -1,20 +1,19 @@
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class DoubleToIntConverter :
+    SingleInstanceConverter<DoubleToIntConverter>
 {
 {
-    public class DoubleToIntConverter :
-        SingleInstanceConverter<DoubleToIntConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        if (value is double or float)
         {
         {
-            if (value is double or float)
-            {
-                double val = (double)value;
-                return (int)val;
-            }
-
-            return value;
+            double val = (double)value;
+            return (int)val;
         }
         }
+
+        return value;
     }
     }
-}
+}

+ 7 - 8
src/PixiEditor/Helpers/Converters/EmptyStringToVisibilityConverter.cs

@@ -2,17 +2,16 @@
 using System.Globalization;
 using System.Globalization;
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class EmptyStringToVisibilityConverter :
+    SingleInstanceConverter<EmptyStringToVisibilityConverter>
 {
 {
-    public class EmptyStringToVisibilityConverter :
-        SingleInstanceConverter<EmptyStringToVisibilityConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return
-                string.IsNullOrEmpty((string)value)
+        return
+            string.IsNullOrEmpty((string)value)
                 ? Visibility.Collapsed
                 ? Visibility.Collapsed
                 : Visibility.Visible;
                 : Visibility.Visible;
-        }
     }
     }
 }
 }

+ 21 - 22
src/PixiEditor/Helpers/Converters/EnumBooleanConverter.cs

@@ -5,33 +5,32 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class EnumBooleanConverter : SingleInstanceConverter<EnumBooleanConverter>
 {
 {
-    public class EnumBooleanConverter : SingleInstanceConverter<EnumBooleanConverter>
+    #region IValueConverter Members
+    public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
     {
     {
-        #region IValueConverter Members
-        public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
-        {
-            string parameterString = parameter as string;
-            if (parameterString == null)
-                return DependencyProperty.UnsetValue;
+        string parameterString = parameter as string;
+        if (parameterString == null)
+            return DependencyProperty.UnsetValue;
 
 
-            if (Enum.IsDefined(value.GetType(), value) == false)
-                return DependencyProperty.UnsetValue;
+        if (Enum.IsDefined(value.GetType(), value) == false)
+            return DependencyProperty.UnsetValue;
 
 
-            object parameterValue = Enum.Parse(value.GetType(), parameterString);
+        object parameterValue = Enum.Parse(value.GetType(), parameterString);
 
 
-            return parameterValue.Equals(value);
-        }
+        return parameterValue.Equals(value);
+    }
 
 
-        public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
-        {
-            string parameterString = parameter as string;
-            if (parameterString == null)
-                return DependencyProperty.UnsetValue;
+    public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+    {
+        string parameterString = parameter as string;
+        if (parameterString == null)
+            return DependencyProperty.UnsetValue;
 
 
-            return Enum.Parse(targetType, parameterString);
-        }
-        #endregion
+        return Enum.Parse(targetType, parameterString);
     }
     }
-}
+    #endregion
+}

+ 17 - 18
src/PixiEditor/Helpers/Converters/EnumToStringConverter.cs

@@ -1,29 +1,28 @@
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.Enums;
 using System;
 using System;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+internal class EnumToStringConverter : SingleInstanceConverter<EnumToStringConverter>
 {
 {
-    internal class EnumToStringConverter : SingleInstanceConverter<EnumToStringConverter>
+    public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        try
         {
         {
-            try
+            var type = value.GetType();
+            if (type == typeof(SizeUnit))
             {
             {
-                var type = value.GetType();
-                if (type == typeof(SizeUnit))
-                {
-                    var valueCasted = (SizeUnit)value;
-                    if (valueCasted == SizeUnit.Percentage)
-                        return "%";
+                var valueCasted = (SizeUnit)value;
+                if (valueCasted == SizeUnit.Percentage)
+                    return "%";
 
 
-                    return "px";
-                }
-                return Enum.GetName((value.GetType()), value);
-            }
-            catch
-            {
-                return string.Empty;
+                return "px";
             }
             }
+            return Enum.GetName((value.GetType()), value);
+        }
+        catch
+        {
+            return string.Empty;
         }
         }
     }
     }
-}
+}

+ 17 - 18
src/PixiEditor/Helpers/Converters/EqualityBoolToVisibilityConverter.cs

@@ -1,27 +1,26 @@
 using System.Globalization;
 using System.Globalization;
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class EqualityBoolToVisibilityConverter : MarkupConverter
 {
 {
-    public class EqualityBoolToVisibilityConverter : MarkupConverter
+    public bool Invert { get; set; }
+
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public bool Invert { get; set; }
+        if (value == null)
+            return Invert;
 
 
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        if (value.GetType().IsAssignableTo(typeof(Enum)) && parameter is string s)
         {
         {
-            if (value == null)
-                return Invert;
-
-            if (value.GetType().IsAssignableTo(typeof(Enum)) && parameter is string s)
-            {
-                parameter = Enum.Parse(value.GetType(), s);
-            }
-            else
-            {
-                parameter = System.Convert.ChangeType(parameter, value.GetType());
-            }
-
-            return value.Equals(parameter) != Invert ? Visibility.Visible : Visibility.Collapsed;
+            parameter = Enum.Parse(value.GetType(), s);
         }
         }
+        else
+        {
+            parameter = System.Convert.ChangeType(parameter, value.GetType());
+        }
+
+        return value.Equals(parameter) != Invert ? Visibility.Visible : Visibility.Collapsed;
     }
     }
-}
+}

+ 30 - 31
src/PixiEditor/Helpers/Converters/FileExtensionToColorConverter.cs

@@ -3,40 +3,39 @@ using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Windows.Media;
 using System.Windows.Media;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class FileExtensionToColorConverter :
+    SingleInstanceConverter<FileExtensionToColorConverter>
 {
 {
-    public class FileExtensionToColorConverter :
-        SingleInstanceConverter<FileExtensionToColorConverter>
-    {
-        private static readonly Dictionary<string, SolidColorBrush> extensionsToBrushes;
-        public static readonly SolidColorBrush UnknownBrush = ColorBrush(100, 100, 100);
+    private static readonly Dictionary<string, SolidColorBrush> extensionsToBrushes;
+    public static readonly SolidColorBrush UnknownBrush = ColorBrush(100, 100, 100);
 
 
-        static FileExtensionToColorConverter()
-        {
-            extensionsToBrushes = new Dictionary<string, SolidColorBrush>();
-            AssignFormatToBrush(FileType.Unset, UnknownBrush);
-            AssignFormatToBrush(FileType.Pixi, ColorBrush(226, 1, 45));
-            AssignFormatToBrush(FileType.Png, ColorBrush(56, 108, 254));
-            AssignFormatToBrush(FileType.Jpeg, ColorBrush(36, 179, 66));
-            AssignFormatToBrush(FileType.Bmp, ColorBrush(255, 140, 0));
-            AssignFormatToBrush(FileType.Gif, ColorBrush(180, 0, 255));
-        }
-        static void AssignFormatToBrush(FileType format, SolidColorBrush brush)
-        {
-            SupportedFilesHelper.GetFileTypeDialogData(format).Extensions.ForEach(i => extensionsToBrushes[i] = brush);
-        }
+    static FileExtensionToColorConverter()
+    {
+        extensionsToBrushes = new Dictionary<string, SolidColorBrush>();
+        AssignFormatToBrush(FileType.Unset, UnknownBrush);
+        AssignFormatToBrush(FileType.Pixi, ColorBrush(226, 1, 45));
+        AssignFormatToBrush(FileType.Png, ColorBrush(56, 108, 254));
+        AssignFormatToBrush(FileType.Jpeg, ColorBrush(36, 179, 66));
+        AssignFormatToBrush(FileType.Bmp, ColorBrush(255, 140, 0));
+        AssignFormatToBrush(FileType.Gif, ColorBrush(180, 0, 255));
+    }
+    static void AssignFormatToBrush(FileType format, SolidColorBrush brush)
+    {
+        SupportedFilesHelper.GetFileTypeDialogData(format).Extensions.ForEach(i => extensionsToBrushes[i] = brush);
+    }
 
 
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
-            GetBrush((string)value);
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
+        GetBrush((string)value);
 
 
-        public static Brush GetBrush(string path)
-        {
-            return extensionsToBrushes.GetValueOrDefault(Path.GetExtension(path).ToLower(), UnknownBrush);
-        }
+    public static Brush GetBrush(string path)
+    {
+        return extensionsToBrushes.GetValueOrDefault(Path.GetExtension(path).ToLower(), UnknownBrush);
+    }
 
 
-        private static SolidColorBrush ColorBrush(byte r, byte g, byte b)
-        {
-            return new SolidColorBrush(Color.FromRgb(r, g, b));
-        }
+    private static SolidColorBrush ColorBrush(byte r, byte g, byte b)
+    {
+        return new SolidColorBrush(Color.FromRgb(r, g, b));
     }
     }
-}
+}

+ 10 - 11
src/PixiEditor/Helpers/Converters/FloorConverter.cs

@@ -1,18 +1,17 @@
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class FloorConverter : SingleInstanceConverter<FloorConverter>
 {
 {
-    public class FloorConverter : SingleInstanceConverter<FloorConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return Math.Floor((double)value);
-        }
+        return Math.Floor((double)value);
+    }
 
 
-        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return value;
-        }
+    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        return value;
     }
     }
-}
+}

+ 18 - 19
src/PixiEditor/Helpers/Converters/FormattedColorConverter.cs

@@ -2,27 +2,26 @@
 using System.Globalization;
 using System.Globalization;
 using System.Windows.Media;
 using System.Windows.Media;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class FormattedColorConverter
+    : SingleInstanceMultiValueConverter<FormattedColorConverter>
 {
 {
-    public class FormattedColorConverter
-        : SingleInstanceMultiValueConverter<FormattedColorConverter>
+    public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+        if (values == null ||
+            values.Length <= 1 ||
+            values[0] is not Color color ||
+            values[1] is not string format)
         {
         {
-            if (values == null ||
-                values.Length <= 1 ||
-                values[0] is not Color color ||
-                values[1] is not string format)
-            {
-                return "";
-            }
-
-            return format.ToLowerInvariant() switch
-            {
-                "hex" => color.ToString(),
-                "rgba" => $"({color.R}, {color.G}, {color.B}, {color.A})",
-                _ => "",
-            };
+            return "";
         }
         }
+
+        return format.ToLowerInvariant() switch
+        {
+            "hex" => color.ToString(),
+            "rgba" => $"({color.R}, {color.G}, {color.B}, {color.A})",
+            _ => "",
+        };
     }
     }
-}
+}

+ 12 - 13
src/PixiEditor/Helpers/Converters/IndentConverter.cs

@@ -3,21 +3,20 @@ using System.Globalization;
 using System.Windows;
 using System.Windows;
 using System.Windows.Data;
 using System.Windows.Data;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class IndentConverter
+    : SingleInstanceConverter<IndentConverter>
 {
 {
-    public class IndentConverter
-        : SingleInstanceConverter<IndentConverter>
-    {
-        private const int IndentSize = 20;
+    private const int IndentSize = 20;
 
 
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return new GridLength(((GridLength)value).Value + IndentSize);
-        }
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        return new GridLength(((GridLength)value).Value + IndentSize);
+    }
 
 
-        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return Binding.DoNothing;
-        }
+    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        return Binding.DoNothing;
     }
     }
 }
 }

+ 11 - 12
src/PixiEditor/Helpers/Converters/IndexOfConverter.cs

@@ -4,20 +4,19 @@ using System;
 using System.Globalization;
 using System.Globalization;
 using System.Windows.Data;
 using System.Windows.Data;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class IndexOfConverter
+    : SingleInstanceConverter<IndexOfConverter>
 {
 {
-    public class IndexOfConverter
-        : SingleInstanceConverter<IndexOfConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        if (value is Layer layer && ViewModelMain.Current.BitmapManager.ActiveDocument != null)
         {
         {
-            if (value is Layer layer && ViewModelMain.Current.BitmapManager.ActiveDocument != null)
-            {
-                int index = ViewModelMain.Current.BitmapManager.ActiveDocument.Layers.IndexOf(layer);
-                return index;
-            }
-
-            return Binding.DoNothing;
+            int index = ViewModelMain.Current.BitmapManager.ActiveDocument.Layers.IndexOf(layer);
+            return index;
         }
         }
+
+        return Binding.DoNothing;
     }
     }
-}
+}

+ 10 - 11
src/PixiEditor/Helpers/Converters/IndexToAssociatedKeyConverter.cs

@@ -5,19 +5,18 @@ using System.Linq;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class IndexToAssociatedKeyConverter : SingleInstanceConverter<IndexToAssociatedKeyConverter>
 {
 {
-    public class IndexToAssociatedKeyConverter : SingleInstanceConverter<IndexToAssociatedKeyConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        if(value is int index && index < 10)
         {
         {
-            if(value is int index && index < 10)
-            {
-                if (index == 9) return 0;
-                return (int?)index + 1;
-            }
-
-            return (int?)null;
+            if (index == 9) return 0;
+            return (int?)index + 1;
         }
         }
+
+        return (int?)null;
     }
     }
-}
+}

+ 11 - 12
src/PixiEditor/Helpers/Converters/IntToPickerTypeConverter.cs

@@ -2,19 +2,18 @@
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class IntToPickerTypeConverter
+    : SingleInstanceConverter<IntToPickerTypeConverter>
 {
 {
-    public class IntToPickerTypeConverter
-        : SingleInstanceConverter<IntToPickerTypeConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return (PickerType)value;
-        }
+        return (PickerType)value;
+    }
 
 
-        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return (int)value;
-        }
+    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        return (int)value;
     }
     }
-}
+}

+ 8 - 9
src/PixiEditor/Helpers/Converters/IntToViewportRectConverter.cs

@@ -3,16 +3,15 @@ using System.Globalization;
 using System.Windows;
 using System.Windows;
 using System.Windows.Data;
 using System.Windows.Data;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class IntToViewportRectConverter
+    : SingleInstanceConverter<IntToViewportRectConverter>
 {
 {
-    public class IntToViewportRectConverter
-        : SingleInstanceConverter<IntToViewportRectConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return parameter is string and "vertical"
-                   ? new Rect(0, 0, 1d / (int)value, 1d)
-                   : (object)new Rect(0, 0, 1d, 1d / (int)value);
-        }
+        return parameter is string and "vertical"
+            ? new Rect(0, 0, 1d / (int)value, 1d)
+            : (object)new Rect(0, 0, 1d, 1d / (int)value);
     }
     }
 }
 }

+ 9 - 10
src/PixiEditor/Helpers/Converters/InverseBooleanConverter.cs

@@ -1,17 +1,16 @@
 using System;
 using System;
 using System.Windows.Data;
 using System.Windows.Data;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+[ValueConversion(typeof(bool), typeof(bool))]
+public class InverseBooleanConverter
+    : SingleInstanceConverter<InverseBooleanConverter>
 {
 {
-    [ValueConversion(typeof(bool), typeof(bool))]
-    public class InverseBooleanConverter
-        : SingleInstanceConverter<InverseBooleanConverter>
+    public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
-        {
-            return targetType != typeof(bool)
-                   ? throw new InvalidOperationException("The target must be a boolean")
-                   : !(bool)value;
-        }
+        return targetType != typeof(bool)
+            ? throw new InvalidOperationException("The target must be a boolean")
+            : !(bool)value;
     }
     }
 }
 }

+ 9 - 10
src/PixiEditor/Helpers/Converters/IsSpecifiedTypeConverter.cs

@@ -2,16 +2,15 @@
 using System.Globalization;
 using System.Globalization;
 using System.Windows.Data;
 using System.Windows.Data;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+[ValueConversion(typeof(object), typeof(bool))]
+public class IsSpecifiedTypeConverter : MarkupConverter
 {
 {
-    [ValueConversion(typeof(object), typeof(bool))]
-    public class IsSpecifiedTypeConverter : MarkupConverter
-    {
-        public Type SpecifiedType { get; set; }
+    public Type SpecifiedType { get; set; }
 
 
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return value != null && value.GetType() == SpecifiedType;
-        }
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        return value != null && value.GetType() == SpecifiedType;
     }
     }
-}
+}

+ 16 - 17
src/PixiEditor/Helpers/Converters/KeyToStringConverter.cs

@@ -2,25 +2,24 @@
 using System.Globalization;
 using System.Globalization;
 using System.Windows.Input;
 using System.Windows.Input;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class KeyToStringConverter
+    : SingleInstanceConverter<KeyToStringConverter>
 {
 {
-    public class KeyToStringConverter
-        : SingleInstanceConverter<KeyToStringConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        if (value is Key key)
+        {
+            return InputKeyHelpers.GetKeyboardKey(key);
+        }
+        else if (value is ModifierKeys)
+        {
+            return value.ToString();
+        }
+        else
         {
         {
-            if (value is Key key)
-            {
-                return InputKeyHelpers.GetKeyboardKey(key);
-            }
-            else if (value is ModifierKeys)
-            {
-                return value.ToString();
-            }
-            else
-            {
-                return string.Empty;
-            }
+            return string.Empty;
         }
         }
     }
     }
-}
+}

+ 29 - 30
src/PixiEditor/Helpers/Converters/LayerStructureToGroupsConverter.cs

@@ -8,46 +8,45 @@ using System.Linq;
 using System.Windows.Data;
 using System.Windows.Data;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class LayerStructureToGroupsConverter
+    : SingleInstanceMultiValueConverter<LayerStructureToGroupsConverter>
 {
 {
-    public class LayerStructureToGroupsConverter
-        : SingleInstanceMultiValueConverter<LayerStructureToGroupsConverter>
+    public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+        if (values[0] is not LayerStructure structure)
         {
         {
-            if (values[0] is not LayerStructure structure)
-            {
-                return Binding.DoNothing;
-            }
-
-            return GetSubGroups(structure.Groups);
+            return Binding.DoNothing;
         }
         }
 
 
-        private System.Collections.ObjectModel.ObservableCollection<GuidStructureItem> GetSubGroups(IEnumerable<GuidStructureItem> groups)
-        {
-            WpfObservableRangeCollection<GuidStructureItem> finalGroups = new WpfObservableRangeCollection<GuidStructureItem>();
-            foreach (var group in groups)
-            {
-                finalGroups.AddRange(GetSubGroups(group));
-            }
+        return GetSubGroups(structure.Groups);
+    }
 
 
-            return finalGroups;
+    private System.Collections.ObjectModel.ObservableCollection<GuidStructureItem> GetSubGroups(IEnumerable<GuidStructureItem> groups)
+    {
+        WpfObservableRangeCollection<GuidStructureItem> finalGroups = new WpfObservableRangeCollection<GuidStructureItem>();
+        foreach (var group in groups)
+        {
+            finalGroups.AddRange(GetSubGroups(group));
         }
         }
 
 
-        private IEnumerable<GuidStructureItem> GetSubGroups(GuidStructureItem group)
-        {
-            List<GuidStructureItem> groups = new List<GuidStructureItem>() { group };
+        return finalGroups;
+    }
+
+    private IEnumerable<GuidStructureItem> GetSubGroups(GuidStructureItem group)
+    {
+        List<GuidStructureItem> groups = new List<GuidStructureItem>() { group };
 
 
-            foreach (var subGroup in group.Subgroups)
+        foreach (var subGroup in group.Subgroups)
+        {
+            groups.Add(subGroup);
+            if (subGroup.Subgroups.Count > 0)
             {
             {
-                groups.Add(subGroup);
-                if (subGroup.Subgroups.Count > 0)
-                {
-                    groups.AddRange(GetSubGroups(subGroup));
-                }
+                groups.AddRange(GetSubGroups(subGroup));
             }
             }
-
-            return groups.Distinct();
         }
         }
+
+        return groups.Distinct();
     }
     }
-}
+}

+ 72 - 73
src/PixiEditor/Helpers/Converters/LayersToStructuredLayersConverter.cs

@@ -6,107 +6,106 @@ using System.Globalization;
 using System.Linq;
 using System.Linq;
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+// TODO: Implement rebuilding only changed items instead whole tree
+public class LayersToStructuredLayersConverter
+    : MultiValueMarkupConverter
 {
 {
-    // TODO: Implement rebuilding only changed items instead whole tree
-    public class LayersToStructuredLayersConverter
-        : MultiValueMarkupConverter
-    {
-        private static StructuredLayerTree cachedTree;
-        private List<Guid> lastLayerGuids = new List<Guid>();
-        private IList<Layer> lastLayers = new List<Layer>();
-        private WpfObservableRangeCollection<GuidStructureItem> lastStructure = new WpfObservableRangeCollection<GuidStructureItem>();
+    private static StructuredLayerTree cachedTree;
+    private List<Guid> lastLayerGuids = new List<Guid>();
+    private IList<Layer> lastLayers = new List<Layer>();
+    private WpfObservableRangeCollection<GuidStructureItem> lastStructure = new WpfObservableRangeCollection<GuidStructureItem>();
 
 
-        public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+    public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+    {
+        if (values[0] is WpfObservableRangeCollection<Layer> layers && values[1] is LayerStructure structure)
         {
         {
-            if (values[0] is WpfObservableRangeCollection<Layer> layers && values[1] is LayerStructure structure)
+            if (cachedTree == null)
             {
             {
-                if (cachedTree == null)
-                {
-                    cachedTree = new StructuredLayerTree(layers, structure);
-                }
-
-                if (TryFindStructureDifferences(structure) ||
-                    lastLayerGuids.Count != layers.Count ||
-                    LayerOrderIsDifferent(layers) ||
-                    LayersAreDifferentObjects(layers, lastLayers))
-                {
-                    cachedTree = new StructuredLayerTree(layers, structure);
-                    lastLayers = layers;
-                    lastLayerGuids = layers.Select(x => x.GuidValue).ToList();
-                    lastStructure = structure.CloneGroups();
-                }
+                cachedTree = new StructuredLayerTree(layers, structure);
+            }
 
 
-                return cachedTree.RootDirectoryItems;
+            if (TryFindStructureDifferences(structure) ||
+                lastLayerGuids.Count != layers.Count ||
+                LayerOrderIsDifferent(layers) ||
+                LayersAreDifferentObjects(layers, lastLayers))
+            {
+                cachedTree = new StructuredLayerTree(layers, structure);
+                lastLayers = layers;
+                lastLayerGuids = layers.Select(x => x.GuidValue).ToList();
+                lastStructure = structure.CloneGroups();
             }
             }
 
 
-            return DependencyProperty.UnsetValue;
+            return cachedTree.RootDirectoryItems;
         }
         }
 
 
-        public override object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
-        {
-            throw new ArgumentException("Value is not a StructuredLayerTree");
-        }
+        return DependencyProperty.UnsetValue;
+    }
+
+    public override object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+    {
+        throw new ArgumentException("Value is not a StructuredLayerTree");
+    }
 
 
-        private bool LayerOrderIsDifferent(IList<Layer> layers)
+    private bool LayerOrderIsDifferent(IList<Layer> layers)
+    {
+        var guids = layers.Select(x => x.GuidValue).ToArray();
+        return !guids.SequenceEqual(lastLayerGuids);
+    }
+
+    /// <summary>
+    /// This should trigger if you open and close the same files twice.
+    /// Even though the layers are technically the same, having two different objects screws things up down the line.
+    /// </summary>
+    private bool LayersAreDifferentObjects(IList<Layer> layers, IList<Layer> lastLayers)
+    {
+        for (int i = 0; i < layers.Count; i++)
         {
         {
-            var guids = layers.Select(x => x.GuidValue).ToArray();
-            return !guids.SequenceEqual(lastLayerGuids);
+            if (layers[i] != lastLayers[i])
+                return true;
         }
         }
+        return false;
+    }
+
+    private bool TryFindStructureDifferences(LayerStructure structure)
+    {
+        bool structureModified = false;
 
 
-        /// <summary>
-        /// This should trigger if you open and close the same files twice.
-        /// Even though the layers are technically the same, having two different objects screws things up down the line.
-        /// </summary>
-        private bool LayersAreDifferentObjects(IList<Layer> layers, IList<Layer> lastLayers)
+        if (lastStructure.Count != structure.Groups.Count)
         {
         {
-            for (int i = 0; i < layers.Count; i++)
-            {
-                if (layers[i] != lastLayers[i])
-                    return true;
-            }
-            return false;
+            return true;
         }
         }
 
 
-        private bool TryFindStructureDifferences(LayerStructure structure)
-        {
-            bool structureModified = false;
 
 
-            if (lastStructure.Count != structure.Groups.Count)
+        foreach (GuidStructureItem treeItem in lastStructure)
+        {
+            var matchingGroup = structure.Groups.FirstOrDefault(x => x.GroupGuid == treeItem.GroupGuid);
+            List<GuidStructureItem> changedGroups = new List<GuidStructureItem>();
+            if (matchingGroup == null || StructureMismatch(treeItem, matchingGroup))
             {
             {
-                return true;
+                structureModified = true;
             }
             }
 
 
+        }
 
 
-            foreach (GuidStructureItem treeItem in lastStructure)
-            {
-                var matchingGroup = structure.Groups.FirstOrDefault(x => x.GroupGuid == treeItem.GroupGuid);
-                List<GuidStructureItem> changedGroups = new List<GuidStructureItem>();
-                if (matchingGroup == null || StructureMismatch(treeItem, matchingGroup))
-                {
-                    structureModified = true;
-                }
-
-            }
+        return structureModified;
+    }
 
 
-            return structureModified;
-        }
+    private bool StructureMismatch(GuidStructureItem first, GuidStructureItem second)
+    {
+        bool rootMismatch = first.EndLayerGuid != second.EndLayerGuid || first.StartLayerGuid != second.StartLayerGuid || first.IsVisible != second.IsVisible || first.IsExpanded != second.IsExpanded || first.Opacity != second.Opacity || first.Subgroups.Count != second.Subgroups.Count || second.Name != first.Name;
 
 
-        private bool StructureMismatch(GuidStructureItem first, GuidStructureItem second)
+        if (!rootMismatch && first.Subgroups.Count > 0)
         {
         {
-            bool rootMismatch = first.EndLayerGuid != second.EndLayerGuid || first.StartLayerGuid != second.StartLayerGuid || first.IsVisible != second.IsVisible || first.IsExpanded != second.IsExpanded || first.Opacity != second.Opacity || first.Subgroups.Count != second.Subgroups.Count || second.Name != first.Name;
-
-            if (!rootMismatch && first.Subgroups.Count > 0)
+            for (int i = 0; i < first.Subgroups.Count; i++)
             {
             {
-                for (int i = 0; i < first.Subgroups.Count; i++)
+                if (StructureMismatch(first.Subgroups[i], second.Subgroups[i]))
                 {
                 {
-                    if (StructureMismatch(first.Subgroups[i], second.Subgroups[i]))
-                    {
-                        return true;
-                    }
+                    return true;
                 }
                 }
             }
             }
-            return rootMismatch;
         }
         }
+        return rootMismatch;
     }
     }
 }
 }

+ 12 - 13
src/PixiEditor/Helpers/Converters/MarkupConverter.cs

@@ -7,20 +7,19 @@ using System.Threading.Tasks;
 using System.Windows.Data;
 using System.Windows.Data;
 using System.Windows.Markup;
 using System.Windows.Markup;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public abstract class MarkupConverter : MarkupExtension, IValueConverter
 {
 {
-    public abstract class MarkupConverter : MarkupExtension, IValueConverter
-    {
-        public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
+    public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
 
 
-        public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
+    public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        throw new NotImplementedException();
+    }
 
 
-        public override object ProvideValue(IServiceProvider serviceProvider)
-        {
-            return this;
-        }
+    public override object ProvideValue(IServiceProvider serviceProvider)
+    {
+        return this;
     }
     }
-}
+}

+ 10 - 11
src/PixiEditor/Helpers/Converters/MultiValueMarkupConverter.cs

@@ -3,17 +3,16 @@ using System.Globalization;
 using System.Windows.Data;
 using System.Windows.Data;
 using System.Windows.Markup;
 using System.Windows.Markup;
 
 
-namespace PixiEditor.Helpers.Converters
-{
-    public abstract class MultiValueMarkupConverter : MarkupExtension, IMultiValueConverter
-    {
-        public abstract object Convert(object[] values, Type targetType, object parameter, CultureInfo culture);
+namespace PixiEditor.Helpers.Converters;
 
 
-        public virtual object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
+public abstract class MultiValueMarkupConverter : MarkupExtension, IMultiValueConverter
+{
+    public abstract object Convert(object[] values, Type targetType, object parameter, CultureInfo culture);
 
 
-        public override object ProvideValue(IServiceProvider serviceProvider) => this;
+    public virtual object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+    {
+        throw new NotImplementedException();
     }
     }
-}
+
+    public override object ProvideValue(IServiceProvider serviceProvider) => this;
+}

+ 12 - 13
src/PixiEditor/Helpers/Converters/NotNullToBoolConverter.cs

@@ -2,22 +2,21 @@
 using System.Globalization;
 using System.Globalization;
 using System.Windows.Data;
 using System.Windows.Data;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+[ValueConversion(typeof(object), typeof(bool))]
+public class NotNullToBoolConverter
+    : SingleInstanceConverter<NotNullToBoolConverter>
 {
 {
-    [ValueConversion(typeof(object), typeof(bool))]
-    public class NotNullToBoolConverter
-        : SingleInstanceConverter<NotNullToBoolConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            bool result = value is not null;
+        bool result = value is not null;
 
 
-            return parameter is null ? result : !result;
-        }
+        return parameter is null ? result : !result;
+    }
 
 
-        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return value;
-        }
+    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        return value;
     }
     }
 }
 }

+ 14 - 15
src/PixiEditor/Helpers/Converters/NotNullToVisibilityConverter.cs

@@ -3,24 +3,23 @@ using System.Globalization;
 using System.Windows;
 using System.Windows;
 using System.Windows.Data;
 using System.Windows.Data;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+[ValueConversion(typeof(object), typeof(Visibility))]
+public class NotNullToVisibilityConverter
+    : MarkupConverter
 {
 {
-    [ValueConversion(typeof(object), typeof(Visibility))]
-    public class NotNullToVisibilityConverter
-        : MarkupConverter
+    public bool Inverted { get; set; }
+
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public bool Inverted { get; set; }
+        bool isNull = value is not null;
 
 
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        if (Inverted)
         {
         {
-            bool isNull = value is not null;
-
-            if (Inverted)
-            {
-                isNull = !isNull;
-            }
-
-            return isNull ? Visibility.Visible : Visibility.Collapsed;
+            isNull = !isNull;
         }
         }
+
+        return isNull ? Visibility.Visible : Visibility.Collapsed;
     }
     }
-}
+}

+ 7 - 8
src/PixiEditor/Helpers/Converters/NullToVisibilityConverter.cs

@@ -2,14 +2,13 @@
 using System.Globalization;
 using System.Globalization;
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class NullToVisibilityConverter
+    : SingleInstanceConverter<NullToVisibilityConverter>
 {
 {
-    public class NullToVisibilityConverter
-        : SingleInstanceConverter<NullToVisibilityConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return value is null ? Visibility.Visible : Visibility.Collapsed;
-        }
+        return value is null ? Visibility.Visible : Visibility.Collapsed;
     }
     }
-}
+}

+ 16 - 17
src/PixiEditor/Helpers/Converters/OppositeVisibilityConverter.cs

@@ -3,29 +3,28 @@ using System.Globalization;
 using System.Windows;
 using System.Windows;
 using System.Windows.Data;
 using System.Windows.Data;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class OppositeVisibilityConverter
+    : SingleInstanceConverter<OppositeVisibilityConverter>
 {
 {
-    public class OppositeVisibilityConverter
-        : SingleInstanceConverter<OppositeVisibilityConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        if (value.ToString().ToLower() == "visible")
         {
         {
-            if (value.ToString().ToLower() == "visible")
-            {
-                return Visibility.Hidden;
-            }
-
-            return Visibility.Visible;
+            return Visibility.Hidden;
         }
         }
 
 
-        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            if (value is Visibility visibility)
-            {
-                return visibility == Visibility.Visible ? "Hidden" : "Visible";
-            }
+        return Visibility.Visible;
+    }
 
 
-            return null;
+    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        if (value is Visibility visibility)
+        {
+            return visibility == Visibility.Visible ? "Hidden" : "Visible";
         }
         }
+
+        return null;
     }
     }
 }
 }

+ 9 - 10
src/PixiEditor/Helpers/Converters/PaletteItemsToWidthConverter.cs

@@ -6,18 +6,17 @@ using System.Linq;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class PaletteItemsToWidthConverter : SingleInstanceConverter<PaletteItemsToWidthConverter>
 {
 {
-    public class PaletteItemsToWidthConverter : SingleInstanceConverter<PaletteItemsToWidthConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        if(value is IList<SKColor> colors && colors.Count == 0)
         {
         {
-            if(value is IList<SKColor> colors && colors.Count == 0)
-            {
-                return 0;
-            }
-
-            return 120;
+            return 0;
         }
         }
+
+        return 120;
     }
     }
-}
+}

+ 18 - 19
src/PixiEditor/Helpers/Converters/SKColorToMediaColorConverter.cs

@@ -4,29 +4,28 @@ using System.Globalization;
 using System.Windows.Data;
 using System.Windows.Data;
 using System.Windows.Media;
 using System.Windows.Media;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class SKColorToMediaColorConverter : SingleInstanceConverter<SKColorToMediaColorConverter>
 {
 {
-    public class SKColorToMediaColorConverter : SingleInstanceConverter<SKColorToMediaColorConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            var skcolor = (SKColor)value;
-            var color = Color.FromArgb(skcolor.Alpha, skcolor.Red, skcolor.Green, skcolor.Blue);
+        var skcolor = (SKColor)value;
+        var color = Color.FromArgb(skcolor.Alpha, skcolor.Red, skcolor.Green, skcolor.Blue);
 
 
-            if (targetType == typeof(Brush))
-            {
-                return new SolidColorBrush(color);
-            }
-            else
-            {
-                return color;
-            }
+        if (targetType == typeof(Brush))
+        {
+            return new SolidColorBrush(color);
         }
         }
-
-        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        else
         {
         {
-            var color = (Color)value;
-            return new SKColor(color.R, color.G, color.B, color.A);
+            return color;
         }
         }
     }
     }
-}
+
+    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        var color = (Color)value;
+        return new SKColor(color.R, color.G, color.B, color.A);
+    }
+}

+ 15 - 16
src/PixiEditor/Helpers/Converters/SingleInstanceConverter.cs

@@ -1,23 +1,22 @@
 using System;
 using System;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+/// <summary>
+/// Use this if you want to share the same converter over the whole application. <para/> Do not use this if your converter has properties.
+/// </summary>
+public abstract class SingleInstanceConverter<TThis> : MarkupConverter
+    where TThis : SingleInstanceConverter<TThis>
 {
 {
-    /// <summary>
-    /// Use this if you want to share the same converter over the whole application. <para/> Do not use this if your converter has properties.
-    /// </summary>
-    public abstract class SingleInstanceConverter<TThis> : MarkupConverter
-        where TThis : SingleInstanceConverter<TThis>
-    {
-        private static SingleInstanceConverter<TThis> instance;
+    private static SingleInstanceConverter<TThis> instance;
 
 
-        public override object ProvideValue(IServiceProvider serviceProvider)
+    public override object ProvideValue(IServiceProvider serviceProvider)
+    {
+        if (instance is null)
         {
         {
-            if (instance is null)
-            {
-                instance = this;
-            }
-
-            return instance;
+            instance = this;
         }
         }
+
+        return instance;
     }
     }
-}
+}

+ 12 - 13
src/PixiEditor/Helpers/Converters/SingleInstanceMultiValueConverter.cs

@@ -1,20 +1,19 @@
 using System;
 using System;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public abstract class SingleInstanceMultiValueConverter<TThis> : MultiValueMarkupConverter
+    where TThis : SingleInstanceMultiValueConverter<TThis>
 {
 {
-    public abstract class SingleInstanceMultiValueConverter<TThis> : MultiValueMarkupConverter
-        where TThis : SingleInstanceMultiValueConverter<TThis>
-    {
-        private static SingleInstanceMultiValueConverter<TThis> instance;
+    private static SingleInstanceMultiValueConverter<TThis> instance;
 
 
-        public override object ProvideValue(IServiceProvider serviceProvider)
+    public override object ProvideValue(IServiceProvider serviceProvider)
+    {
+        if (instance is null)
         {
         {
-            if (instance is null)
-            {
-                instance = this;
-            }
-
-            return instance;
+            instance = this;
         }
         }
+
+        return instance;
     }
     }
-}
+}

+ 12 - 13
src/PixiEditor/Helpers/Converters/ThresholdVisibilityConverter.cs

@@ -2,19 +2,18 @@
 using System.Globalization;
 using System.Globalization;
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class ThresholdVisibilityConverter
+    : MarkupConverter
 {
 {
-    public class ThresholdVisibilityConverter
-        : MarkupConverter
-    {
-        public double Threshold { get; set; } = 100;
-        public bool CheckIfLess { get; set; } = false;
+    public double Threshold { get; set; } = 100;
+    public bool CheckIfLess { get; set; } = false;
 
 
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return CheckIfLess
-                   ? (double)value < Threshold ? Visibility.Visible : Visibility.Hidden
-                   : (double)value >= Threshold ? Visibility.Visible : Visibility.Hidden;
-        }
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        return CheckIfLess
+            ? (double)value < Threshold ? Visibility.Visible : Visibility.Hidden
+            : (double)value >= Threshold ? Visibility.Visible : Visibility.Hidden;
     }
     }
-}
+}

+ 20 - 21
src/PixiEditor/Helpers/Converters/ToolSizeToIntConverter.cs

@@ -3,32 +3,31 @@ using System.Globalization;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
 using System.Windows.Data;
 using System.Windows.Data;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+[ValueConversion(typeof(string), typeof(int))]
+internal class ToolSizeToIntConverter
+    : SingleInstanceConverter<ToolSizeToIntConverter>
 {
 {
-    [ValueConversion(typeof(string), typeof(int))]
-    internal class ToolSizeToIntConverter
-        : SingleInstanceConverter<ToolSizeToIntConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return value.ToString();
-        }
+        return value.ToString();
+    }
 
 
-        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        if (value is not string s)
         {
         {
-            if (value is not string s)
-            {
-                return null;
-            }
-
-            Match match = Regex.Match(s, @"\d+");
+            return null;
+        }
 
 
-            if (!match.Success)
-            {
-                return null;
-            }
+        Match match = Regex.Match(s, @"\d+");
 
 
-            return int.Parse(match.Groups[0].ValueSpan);
+        if (!match.Success)
+        {
+            return null;
         }
         }
+
+        return int.Parse(match.Groups[0].ValueSpan);
     }
     }
-}
+}

+ 13 - 14
src/PixiEditor/Helpers/Converters/ViewboxInverseTransformConverter.cs

@@ -3,21 +3,20 @@ using System.Globalization;
 using System.Windows;
 using System.Windows;
 using System.Windows.Media;
 using System.Windows.Media;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+class ViewboxInverseTransformConverter : MultiValueMarkupConverter
 {
 {
-    class ViewboxInverseTransformConverter : MultiValueMarkupConverter
+    public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
-        {
-            var transform = ((ContainerVisual)VisualTreeHelper.GetChild((DependencyObject)values[0], 0)).Transform;
-            if (transform == null)
-                return DependencyProperty.UnsetValue;
-            return transform.Inverse;
-        }
+        var transform = ((ContainerVisual)VisualTreeHelper.GetChild((DependencyObject)values[0], 0)).Transform;
+        if (transform == null)
+            return DependencyProperty.UnsetValue;
+        return transform.Inverse;
+    }
 
 
-        public override object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
+    public override object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+    {
+        throw new NotImplementedException();
     }
     }
-}
+}

+ 17 - 18
src/PixiEditor/Helpers/Converters/WidthToBitmapScalingModeConverter.cs

@@ -3,25 +3,24 @@ using System.Globalization;
 using System.Windows;
 using System.Windows;
 using System.Windows.Media;
 using System.Windows.Media;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+internal class WidthToBitmapScalingModeConverter : SingleInstanceMultiValueConverter<WidthToBitmapScalingModeConverter>
 {
 {
-    internal class WidthToBitmapScalingModeConverter : SingleInstanceMultiValueConverter<WidthToBitmapScalingModeConverter>
+    public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
-        {
-            int? pixelWidth = values[0] as int?;
-            double? actualWidth = values[1] as double?;
-            if (pixelWidth == null || actualWidth == null)
-                return DependencyProperty.UnsetValue;
-            double zoomLevel = actualWidth.Value / pixelWidth.Value;
-            if (zoomLevel < 1)
-                return BitmapScalingMode.HighQuality;
-            return BitmapScalingMode.NearestNeighbor;
-        }
+        int? pixelWidth = values[0] as int?;
+        double? actualWidth = values[1] as double?;
+        if (pixelWidth == null || actualWidth == null)
+            return DependencyProperty.UnsetValue;
+        double zoomLevel = actualWidth.Value / pixelWidth.Value;
+        if (zoomLevel < 1)
+            return BitmapScalingMode.HighQuality;
+        return BitmapScalingMode.NearestNeighbor;
+    }
 
 
-        public override object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
+    public override object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+    {
+        throw new NotImplementedException();
     }
     }
-}
+}

+ 13 - 14
src/PixiEditor/Helpers/Converters/ZoomLevelToBitmapScalingModeConverter.cs

@@ -2,21 +2,20 @@
 using System.Globalization;
 using System.Globalization;
 using System.Windows.Media;
 using System.Windows.Media;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+internal class ZoomLevelToBitmapScalingModeConverter : SingleInstanceConverter<ZoomLevelToBitmapScalingModeConverter>
 {
 {
-    internal class ZoomLevelToBitmapScalingModeConverter : SingleInstanceConverter<ZoomLevelToBitmapScalingModeConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            double zoomLevel = (double)value;
-            if (zoomLevel < 1)
-                return BitmapScalingMode.HighQuality;
-            return BitmapScalingMode.NearestNeighbor;
-        }
+        double zoomLevel = (double)value;
+        if (zoomLevel < 1)
+            return BitmapScalingMode.HighQuality;
+        return BitmapScalingMode.NearestNeighbor;
+    }
 
 
-        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
+    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        throw new NotImplementedException();
     }
     }
-}
+}

+ 11 - 12
src/PixiEditor/Helpers/Converters/ZoomToViewportConverter.cs

@@ -3,20 +3,19 @@ using System.Globalization;
 using System.Windows;
 using System.Windows;
 using System.Windows.Data;
 using System.Windows.Data;
 
 
-namespace PixiEditor.Helpers.Converters
+namespace PixiEditor.Helpers.Converters;
+
+public class ZoomToViewportConverter
+    : SingleInstanceConverter<ZoomToViewportConverter>
 {
 {
-    public class ZoomToViewportConverter
-        : SingleInstanceConverter<ZoomToViewportConverter>
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
     {
-        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        if (value is double scale)
         {
         {
-            if (value is double scale)
-            {
-                double newSize = Math.Clamp((double)parameter / scale, 1, 9999);
-                return new Rect(0, 0, newSize, newSize);
-            }
-
-            return Binding.DoNothing;
+            double newSize = Math.Clamp((double)parameter / scale, 1, 9999);
+            return new Rect(0, 0, newSize, newSize);
         }
         }
+
+        return Binding.DoNothing;
     }
     }
-}
+}

+ 62 - 63
src/PixiEditor/Helpers/CoordinatesHelper.cs

@@ -2,84 +2,83 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+internal class CoordinatesHelper
 {
 {
-    internal class CoordinatesHelper
+    public static (Coordinates, Coordinates) GetSquareOrLineCoordinates(IReadOnlyList<Coordinates> coords)
     {
     {
-        public static (Coordinates, Coordinates) GetSquareOrLineCoordinates(IReadOnlyList<Coordinates> coords)
+        if (DoCoordsFormLine(coords))
         {
         {
-            if (DoCoordsFormLine(coords))
-            {
-                return GetLineCoordinates(coords);
-            }
-            return GetSquareCoordiantes(coords);
+            return GetLineCoordinates(coords);
         }
         }
+        return GetSquareCoordiantes(coords);
+    }
 
 
-        private static bool DoCoordsFormLine(IReadOnlyList<Coordinates> coords)
-        {
-            var p1 = coords[0];
-            var p2 = coords[^1];
-            //find delta and mirror to first quadrant
-            float dX = Math.Abs(p2.X - p1.X);
-            float dY = Math.Abs(p2.Y - p1.Y);
+    private static bool DoCoordsFormLine(IReadOnlyList<Coordinates> coords)
+    {
+        var p1 = coords[0];
+        var p2 = coords[^1];
+        //find delta and mirror to first quadrant
+        float dX = Math.Abs(p2.X - p1.X);
+        float dY = Math.Abs(p2.Y - p1.Y);
 
 
-            //normalize
-            float length = (float)Math.Sqrt(dX * dX + dY * dY);
-            if (length == 0)
-                return false;
-            dX = dX / length;
-            dY = dY / length;
+        //normalize
+        float length = (float)Math.Sqrt(dX * dX + dY * dY);
+        if (length == 0)
+            return false;
+        dX = dX / length;
+        dY = dY / length;
 
 
-            return dX < 0.25f || dY < 0.25f; //angle < 15 deg or angle > 75 deg (sin 15 ~= 0.25)
-        }
+        return dX < 0.25f || dY < 0.25f; //angle < 15 deg or angle > 75 deg (sin 15 ~= 0.25)
+    }
 
 
-        public static (Coordinates, Coordinates) GetLineCoordinates(IReadOnlyList<Coordinates> mouseMoveCords)
-        {
-            int xStart = mouseMoveCords[0].X;
-            int yStart = mouseMoveCords[0].Y;
+    public static (Coordinates, Coordinates) GetLineCoordinates(IReadOnlyList<Coordinates> mouseMoveCords)
+    {
+        int xStart = mouseMoveCords[0].X;
+        int yStart = mouseMoveCords[0].Y;
 
 
-            int xEnd = mouseMoveCords[^1].X;
-            int yEnd = mouseMoveCords[^1].Y;
+        int xEnd = mouseMoveCords[^1].X;
+        int yEnd = mouseMoveCords[^1].Y;
 
 
 
 
-            if (Math.Abs(xStart - xEnd) > Math.Abs(yStart - yEnd))
-            {
-                yEnd = yStart;
-            }
-            else
-            {
-                xEnd = xStart;
-            }
-            return (new(xStart, yStart), new(xEnd, yEnd));
+        if (Math.Abs(xStart - xEnd) > Math.Abs(yStart - yEnd))
+        {
+            yEnd = yStart;
         }
         }
-
-        /// <summary>
-        ///     Extracts square from rectangle mouse drag, used to draw symmetric shapes.
-        /// </summary>
-        public static (Coordinates, Coordinates) GetSquareCoordiantes(IReadOnlyList<Coordinates> mouseMoveCords)
+        else
         {
         {
-            var end = mouseMoveCords[^1];
-            var start = mouseMoveCords[0];
+            xEnd = xStart;
+        }
+        return (new(xStart, yStart), new(xEnd, yEnd));
+    }
 
 
-            //find delta and mirror to first quadrant
-            var dX = Math.Abs(start.X - end.X);
-            var dY = Math.Abs(start.Y - end.Y);
+    /// <summary>
+    ///     Extracts square from rectangle mouse drag, used to draw symmetric shapes.
+    /// </summary>
+    public static (Coordinates, Coordinates) GetSquareCoordiantes(IReadOnlyList<Coordinates> mouseMoveCords)
+    {
+        var end = mouseMoveCords[^1];
+        var start = mouseMoveCords[0];
 
 
-            float sqrt2 = (float)Math.Sqrt(2);
-            //vector of length 1 at 45 degrees;
-            float diagX, diagY;
-            diagX = diagY = 1 / sqrt2;
+        //find delta and mirror to first quadrant
+        var dX = Math.Abs(start.X - end.X);
+        var dY = Math.Abs(start.Y - end.Y);
 
 
-            //dot product of delta and diag, returns length of [delta projected onto diag]
-            float projectedLength = diagX * dX + diagY * dY;
-            //project above onto axes
-            float axisLength = projectedLength / sqrt2;
+        float sqrt2 = (float)Math.Sqrt(2);
+        //vector of length 1 at 45 degrees;
+        float diagX, diagY;
+        diagX = diagY = 1 / sqrt2;
 
 
-            //final coords
-            float x = -Math.Sign(start.X - end.X) * axisLength;
-            float y = -Math.Sign(start.Y - end.Y) * axisLength;
-            end = new Coordinates((int)x + start.X, (int)y + start.Y);
-            return (start, end);
-        }
+        //dot product of delta and diag, returns length of [delta projected onto diag]
+        float projectedLength = diagX * dX + diagY * dY;
+        //project above onto axes
+        float axisLength = projectedLength / sqrt2;
+
+        //final coords
+        float x = -Math.Sign(start.X - end.X) * axisLength;
+        float y = -Math.Sign(start.Y - end.Y) * axisLength;
+        end = new Coordinates((int)x + start.X, (int)y + start.Y);
+        return (start, end);
     }
     }
-}
+}

+ 71 - 72
src/PixiEditor/Helpers/CrashHelper.cs

@@ -5,97 +5,96 @@ using System;
 using System.Globalization;
 using System.Globalization;
 using System.Text;
 using System.Text;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+public class CrashHelper
 {
 {
-    public class CrashHelper
+    private readonly IHardwareInfo hwInfo;
+
+    public static void SaveCrashInfo(Exception exception)
     {
     {
-        private readonly IHardwareInfo hwInfo;
+        CrashReport report = CrashReport.Generate(exception);
+        report.TrySave();
+        report.RestartToCrashReport();
+    }
 
 
-        public static void SaveCrashInfo(Exception exception)
-        {
-            CrashReport report = CrashReport.Generate(exception);
-            report.TrySave();
-            report.RestartToCrashReport();
-        }
+    public CrashHelper()
+    {
+        hwInfo = new HardwareInfo();
+    }
 
 
-        public CrashHelper()
-        {
-            hwInfo = new HardwareInfo();
-        }
+    public void GetCPUInformation(StringBuilder builder)
+    {
+        builder.AppendLine("CPU:");
+        hwInfo.RefreshCPUList(false);
 
 
-        public void GetCPUInformation(StringBuilder builder)
+        foreach (var processor in hwInfo.CpuList)
         {
         {
-            builder.AppendLine("CPU:");
-            hwInfo.RefreshCPUList(false);
-
-            foreach (var processor in hwInfo.CpuList)
-            {
-                builder
-                    .AppendLine($"  Name: {processor.Name}")
-                    .AppendLine($"  Speed: {(processor.CurrentClockSpeed / 1000f).ToString("F2", CultureInfo.InvariantCulture)} GHz")
-                    .AppendLine($"  Max Speed: {(processor.MaxClockSpeed / 1000f).ToString("F2", CultureInfo.InvariantCulture)} GHz")
-                    .AppendLine();
-            }
+            builder
+                .AppendLine($"  Name: {processor.Name}")
+                .AppendLine($"  Speed: {(processor.CurrentClockSpeed / 1000f).ToString("F2", CultureInfo.InvariantCulture)} GHz")
+                .AppendLine($"  Max Speed: {(processor.MaxClockSpeed / 1000f).ToString("F2", CultureInfo.InvariantCulture)} GHz")
+                .AppendLine();
         }
         }
+    }
 
 
-        public void GetGPUInformation(StringBuilder builder)
-        {
-            builder.AppendLine("GPU:");
-            hwInfo.RefreshVideoControllerList();
+    public void GetGPUInformation(StringBuilder builder)
+    {
+        builder.AppendLine("GPU:");
+        hwInfo.RefreshVideoControllerList();
 
 
-            foreach (var gpu in hwInfo.VideoControllerList)
-            {
-                builder
-                    .AppendLine($"  Name: {gpu.Name}")
-                    .AppendLine($"  Driver: {gpu.DriverVersion}")
-                    .AppendLine();
-            }
+        foreach (var gpu in hwInfo.VideoControllerList)
+        {
+            builder
+                .AppendLine($"  Name: {gpu.Name}")
+                .AppendLine($"  Driver: {gpu.DriverVersion}")
+                .AppendLine();
         }
         }
+    }
 
 
-        public void GetMemoryInformation(StringBuilder builder)
-        {
-            builder.AppendLine("Memory:");
-            hwInfo.RefreshMemoryStatus();
+    public void GetMemoryInformation(StringBuilder builder)
+    {
+        builder.AppendLine("Memory:");
+        hwInfo.RefreshMemoryStatus();
 
 
-            var memInfo = hwInfo.MemoryStatus;
+        var memInfo = hwInfo.MemoryStatus;
 
 
-            builder
-                .AppendLine($"  Available: {new ByteSize(memInfo.AvailablePhysical).ToString("", CultureInfo.InvariantCulture)}")
-                .AppendLine($"  Total: {new ByteSize(memInfo.TotalPhysical).ToString("", CultureInfo.InvariantCulture)}");
-        }
+        builder
+            .AppendLine($"  Available: {new ByteSize(memInfo.AvailablePhysical).ToString("", CultureInfo.InvariantCulture)}")
+            .AppendLine($"  Total: {new ByteSize(memInfo.TotalPhysical).ToString("", CultureInfo.InvariantCulture)}");
+    }
 
 
-        public static void AddExceptionMessage(StringBuilder builder, Exception e)
+    public static void AddExceptionMessage(StringBuilder builder, Exception e)
+    {
+        builder
+            .AppendLine("\n-------Crash message-------")
+            .Append(e.GetType().ToString())
+            .Append(": ")
+            .AppendLine(e.Message);
         {
         {
-            builder
-                .AppendLine("\n-------Crash message-------")
-                .Append(e.GetType().ToString())
-                .Append(": ")
-                .AppendLine(e.Message);
+            var innerException = e.InnerException;
+            while (innerException != null)
             {
             {
-                var innerException = e.InnerException;
-                while (innerException != null)
-                {
-                    builder
-                        .Append("\n-----Inner exception-----\n")
-                        .Append(innerException.GetType().ToString())
-                        .Append(": ")
-                        .Append(innerException.Message);
-                    innerException = innerException.InnerException;
-                }
+                builder
+                    .Append("\n-----Inner exception-----\n")
+                    .Append(innerException.GetType().ToString())
+                    .Append(": ")
+                    .Append(innerException.Message);
+                innerException = innerException.InnerException;
             }
             }
+        }
 
 
-            builder
-                .Append("\n\n-------Stack trace-------\n")
-                .Append(e.StackTrace);
+        builder
+            .Append("\n\n-------Stack trace-------\n")
+            .Append(e.StackTrace);
+        {
+            var innerException = e.InnerException;
+            while (innerException != null)
             {
             {
-                var innerException = e.InnerException;
-                while (innerException != null)
-                {
-                    builder
-                        .Append("\n-----Inner exception-----\n")
-                        .Append(innerException.StackTrace);
-                    innerException = innerException.InnerException;
-                }
+                builder
+                    .Append("\n-----Inner exception-----\n")
+                    .Append(innerException.StackTrace);
+                innerException = innerException.InnerException;
             }
             }
         }
         }
     }
     }

+ 34 - 35
src/PixiEditor/Helpers/DependencyInjectionHelper.cs

@@ -4,58 +4,57 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Reflection;
 using System.Reflection;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+public static class DependencyInjectionHelper
 {
 {
-    public static class DependencyInjectionHelper
-    {
-        public static T Inject<T>(this IServiceProvider provider)
-            => (T)Inject(provider, typeof(T));
+    public static T Inject<T>(this IServiceProvider provider)
+        => (T)Inject(provider, typeof(T));
 
 
 #nullable enable
 #nullable enable
 
 
-        public static object Inject(this IServiceProvider provider, Type type)
-        {
-            ConstructorInfo constructor = FindConstructorOrDefault(provider, type);
-
-            List<object?> parameters = new List<object?>();
+    public static object Inject(this IServiceProvider provider, Type type)
+    {
+        ConstructorInfo constructor = FindConstructorOrDefault(provider, type);
 
 
-            foreach (Type argumentType in constructor.GetParameters().Select(x => x.ParameterType))
-            {
-                parameters.Add(provider.GetRequiredService(argumentType));
-            }
+        List<object?> parameters = new List<object?>();
 
 
-            return constructor.Invoke(parameters.ToArray());
+        foreach (Type argumentType in constructor.GetParameters().Select(x => x.ParameterType))
+        {
+            parameters.Add(provider.GetRequiredService(argumentType));
         }
         }
 
 
+        return constructor.Invoke(parameters.ToArray());
+    }
+
 #nullable disable
 #nullable disable
 
 
-        private static ConstructorInfo FindConstructorOrDefault(IServiceProvider provider, Type type)
-        {
-            ConstructorInfo foundConstructor = default;
+    private static ConstructorInfo FindConstructorOrDefault(IServiceProvider provider, Type type)
+    {
+        ConstructorInfo foundConstructor = default;
 
 
-            foreach (ConstructorInfo info in type.GetConstructors())
+        foreach (ConstructorInfo info in type.GetConstructors())
+        {
+            if (HasParameters(provider, info.GetParameters()))
             {
             {
-                if (HasParameters(provider, info.GetParameters()))
-                {
-                    foundConstructor = info;
-                    break;
-                }
+                foundConstructor = info;
+                break;
             }
             }
-
-            return foundConstructor;
         }
         }
 
 
-        private static bool HasParameters(IServiceProvider provider, IEnumerable<ParameterInfo> parameters)
+        return foundConstructor;
+    }
+
+    private static bool HasParameters(IServiceProvider provider, IEnumerable<ParameterInfo> parameters)
+    {
+        foreach (ParameterInfo parameter in parameters)
         {
         {
-            foreach (ParameterInfo parameter in parameters)
+            if (provider.GetService(parameter.ParameterType) is null)
             {
             {
-                if (provider.GetService(parameter.ParameterType) is null)
-                {
-                    return false;
-                }
+                return false;
             }
             }
-
-            return true;
         }
         }
+
+        return true;
     }
     }
-}
+}

+ 23 - 24
src/PixiEditor/Helpers/DesignCommandHelpers.cs

@@ -3,34 +3,33 @@ using CommandAttribute = PixiEditor.Models.Commands.Attributes.Command;
 using System.Reflection;
 using System.Reflection;
 using PixiEditor.Models.Commands.Exceptions;
 using PixiEditor.Models.Commands.Exceptions;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+/// <summary>
+/// Helps with debugging when using XAML
+/// </summary>
+public static class DesignCommandHelpers
 {
 {
-    /// <summary>
-    /// Helps with debugging when using XAML
-    /// </summary>
-    public static class DesignCommandHelpers
-    {
-        private static IEnumerable<CommandAttribute.CommandAttribute> _commands;
+    private static IEnumerable<CommandAttribute.CommandAttribute> _commands;
 
 
-        public static CommandAttribute.CommandAttribute GetCommandAttribute(string name)
+    public static CommandAttribute.CommandAttribute GetCommandAttribute(string name)
+    {
+        if (_commands == null)
         {
         {
-            if (_commands == null)
-            {
-                _commands = Assembly
-                    .GetAssembly(typeof(CommandController))
-                    .GetTypes()
-                    .SelectMany(x => x.GetMethods())
-                    .SelectMany(x => x.GetCustomAttributes<CommandAttribute.CommandAttribute>());
-            }
-
-            var command = _commands.SingleOrDefault(x => x.InternalName == name || x.InternalName == $"#DEBUG#{name}");
+            _commands = Assembly
+                .GetAssembly(typeof(CommandController))
+                .GetTypes()
+                .SelectMany(x => x.GetMethods())
+                .SelectMany(x => x.GetCustomAttributes<CommandAttribute.CommandAttribute>());
+        }
 
 
-            if (command == null)
-            {
-                throw new CommandNotFoundException(name);
-            }
+        var command = _commands.SingleOrDefault(x => x.InternalName == name || x.InternalName == $"#DEBUG#{name}");
 
 
-            return command;
+        if (command == null)
+        {
+            throw new CommandNotFoundException(name);
         }
         }
+
+        return command;
     }
     }
-}
+}

+ 127 - 128
src/PixiEditor/Helpers/EllipseGenerator.cs

@@ -6,163 +6,162 @@ using System.Linq;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+internal static class EllipseGenerator
 {
 {
-    internal static class EllipseGenerator
+    public static List<DoubleCoords> SplitEllipseIntoLines(List<Coordinates> ellipse)
     {
     {
-        public static List<DoubleCoords> SplitEllipseIntoLines(List<Coordinates> ellipse)
+        List<DoubleCoords> lines = new();
+        var sorted = ellipse.OrderBy(
+            a => a,
+            Comparer<Coordinates>.Create((a, b) => a.Y != b.Y ? a.Y - b.Y : a.X - b.X)
+        );
+
+        int minX = int.MaxValue;
+        int maxX = int.MinValue;
+        Coordinates? prev = null;
+        foreach (var point in sorted)
         {
         {
-            List<DoubleCoords> lines = new();
-            var sorted = ellipse.OrderBy(
-                a => a,
-                Comparer<Coordinates>.Create((a, b) => a.Y != b.Y ? a.Y - b.Y : a.X - b.X)
-                );
-
-            int minX = int.MaxValue;
-            int maxX = int.MinValue;
-            Coordinates? prev = null;
-            foreach (var point in sorted)
+            if (prev.HasValue && point.Y != prev.Value.Y)
             {
             {
-                if (prev.HasValue && point.Y != prev.Value.Y)
-                {
-                    int prevY = prev.Value.Y;
-                    lines.Add(new DoubleCoords(new(minX, prevY), new(maxX, prevY)));
-                    minX = int.MaxValue;
-                    maxX = int.MinValue;
-                }
-                minX = Math.Min(point.X, minX);
-                maxX = Math.Max(point.X, maxX);
-                prev = point;
+                int prevY = prev.Value.Y;
+                lines.Add(new DoubleCoords(new(minX, prevY), new(maxX, prevY)));
+                minX = int.MaxValue;
+                maxX = int.MinValue;
             }
             }
-            lines.Add(new DoubleCoords(new(minX, prev.Value.Y), new(maxX, prev.Value.Y)));
-            return lines;
-        }
-        public static List<Coordinates> GenerateEllipseFromRect(DoubleCoords rect, List<Coordinates> listToFill = null)
-        {
-            float radiusX = (rect.Coords2.X - rect.Coords1.X) / 2.0f;
-            float radiusY = (rect.Coords2.Y - rect.Coords1.Y) / 2.0f;
-            float centerX = (rect.Coords1.X + rect.Coords2.X + 1) / 2.0f;
-            float centerY = (rect.Coords1.Y + rect.Coords2.Y + 1) / 2.0f;
-            return GenerateMidpointEllipse(radiusX, radiusY, centerX, centerY, listToFill);
+            minX = Math.Min(point.X, minX);
+            maxX = Math.Max(point.X, maxX);
+            prev = point;
         }
         }
+        lines.Add(new DoubleCoords(new(minX, prev.Value.Y), new(maxX, prev.Value.Y)));
+        return lines;
+    }
+    public static List<Coordinates> GenerateEllipseFromRect(DoubleCoords rect, List<Coordinates> listToFill = null)
+    {
+        float radiusX = (rect.Coords2.X - rect.Coords1.X) / 2.0f;
+        float radiusY = (rect.Coords2.Y - rect.Coords1.Y) / 2.0f;
+        float centerX = (rect.Coords1.X + rect.Coords2.X + 1) / 2.0f;
+        float centerY = (rect.Coords1.Y + rect.Coords2.Y + 1) / 2.0f;
+        return GenerateMidpointEllipse(radiusX, radiusY, centerX, centerY, listToFill);
+    }
 
 
-        /// <summary>
-        /// Draws an ellipse using it's center and radii
-        ///
-        /// Here is a usage example:
-        /// Let's say you want an ellipse that's 3 pixels wide and 3 pixels tall located in the top right corner of the canvas
-        /// It's center is at (1.5; 1.5). That's in the middle of a pixel
-        /// The radii are both equal to 1. Notice that it's 1 and not 1.5, since we want the ellipse to land in the middle of the pixel, not outside of it.
-        /// See desmos (note the inverted y axis): https://www.desmos.com/calculator/tq9uqg0hcq
-        ///
-        /// Another example:
-        /// 4x4 ellipse in the top right corner of the canvas
-        /// Center is at (2; 2). It's a place where 4 pixels meet
-        /// Both radii are 1.5. Making them 2 would make the ellipse touch the edges of pixels, whereas we want it to stay in the middle
-        /// </summary>
-        public static List<Coordinates> GenerateMidpointEllipse(
-            double halfWidth,
-            double halfHeight,
-            double centerX,
-            double centerY,
-            List<Coordinates> listToFill = null)
+    /// <summary>
+    /// Draws an ellipse using it's center and radii
+    ///
+    /// Here is a usage example:
+    /// Let's say you want an ellipse that's 3 pixels wide and 3 pixels tall located in the top right corner of the canvas
+    /// It's center is at (1.5; 1.5). That's in the middle of a pixel
+    /// The radii are both equal to 1. Notice that it's 1 and not 1.5, since we want the ellipse to land in the middle of the pixel, not outside of it.
+    /// See desmos (note the inverted y axis): https://www.desmos.com/calculator/tq9uqg0hcq
+    ///
+    /// Another example:
+    /// 4x4 ellipse in the top right corner of the canvas
+    /// Center is at (2; 2). It's a place where 4 pixels meet
+    /// Both radii are 1.5. Making them 2 would make the ellipse touch the edges of pixels, whereas we want it to stay in the middle
+    /// </summary>
+    public static List<Coordinates> GenerateMidpointEllipse(
+        double halfWidth,
+        double halfHeight,
+        double centerX,
+        double centerY,
+        List<Coordinates> listToFill = null)
+    {
+        listToFill ??= new List<Coordinates>();
+        if (halfWidth < 1 || halfHeight < 1)
         {
         {
-            listToFill ??= new List<Coordinates>();
-            if (halfWidth < 1 || halfHeight < 1)
-            {
-                AddFallbackRectangle(halfWidth, halfHeight, centerX, centerY, listToFill);
-                return listToFill;
-            }
-
-            // ellipse formula: halfHeight^2 * x^2 + halfWidth^2 * y^2 - halfHeight^2 * halfWidth^2 = 0
+            AddFallbackRectangle(halfWidth, halfHeight, centerX, centerY, listToFill);
+            return listToFill;
+        }
 
 
-            // Make sure we are always at the center of a pixel
-            double currentX = Math.Ceiling(centerX - 0.5) + 0.5;
-            double currentY = centerY + halfHeight;
+        // ellipse formula: halfHeight^2 * x^2 + halfWidth^2 * y^2 - halfHeight^2 * halfWidth^2 = 0
 
 
+        // Make sure we are always at the center of a pixel
+        double currentX = Math.Ceiling(centerX - 0.5) + 0.5;
+        double currentY = centerY + halfHeight;
 
 
-            double currentSlope;
 
 
-            // from PI/2 to PI/4
-            do
-            {
-                AddRegionPoints(listToFill, currentX, centerX, currentY, centerY);
+        double currentSlope;
 
 
-                // calculate next pixel coords
-                currentX++;
+        // from PI/2 to PI/4
+        do
+        {
+            AddRegionPoints(listToFill, currentX, centerX, currentY, centerY);
 
 
-                if ((Math.Pow(halfHeight, 2) * Math.Pow(currentX - centerX, 2)) +
-                    (Math.Pow(halfWidth, 2) * Math.Pow(currentY - centerY - 0.5, 2)) -
-                    (Math.Pow(halfWidth, 2) * Math.Pow(halfHeight, 2)) >= 0)
-                {
-                    currentY--;
-                }
-
-                // calculate how far we've advanced
-                double derivativeX = 2 * Math.Pow(halfHeight, 2) * (currentX - centerX);
-                double derivativeY = 2 * Math.Pow(halfWidth, 2) * (currentY - centerY);
-                currentSlope = -(derivativeX / derivativeY);
-            }
-            while (currentSlope > -1 && currentY - centerY > 0.5);
+            // calculate next pixel coords
+            currentX++;
 
 
-            // from PI/4 to 0
-            while (currentY - centerY >= 0)
+            if ((Math.Pow(halfHeight, 2) * Math.Pow(currentX - centerX, 2)) +
+                (Math.Pow(halfWidth, 2) * Math.Pow(currentY - centerY - 0.5, 2)) -
+                (Math.Pow(halfWidth, 2) * Math.Pow(halfHeight, 2)) >= 0)
             {
             {
-                AddRegionPoints(listToFill, currentX, centerX, currentY, centerY);
-
                 currentY--;
                 currentY--;
-                if ((Math.Pow(halfHeight, 2) * Math.Pow(currentX - centerX + 0.5, 2)) +
-                    (Math.Pow(halfWidth, 2) * Math.Pow(currentY - centerY, 2)) -
-                    (Math.Pow(halfWidth, 2) * Math.Pow(halfHeight, 2)) < 0)
-                {
-                    currentX++;
-                }
             }
             }
 
 
-            return listToFill;
+            // calculate how far we've advanced
+            double derivativeX = 2 * Math.Pow(halfHeight, 2) * (currentX - centerX);
+            double derivativeY = 2 * Math.Pow(halfWidth, 2) * (currentY - centerY);
+            currentSlope = -(derivativeX / derivativeY);
         }
         }
+        while (currentSlope > -1 && currentY - centerY > 0.5);
 
 
-        private static void AddFallbackRectangle(double halfWidth, double halfHeight, double centerX, double centerY, List<Coordinates> coordinates)
+        // from PI/4 to 0
+        while (currentY - centerY >= 0)
         {
         {
-            int left = (int)Math.Floor(centerX - halfWidth);
-            int top = (int)Math.Floor(centerY - halfHeight);
-            int right = (int)Math.Floor(centerX + halfWidth);
-            int bottom = (int)Math.Floor(centerY + halfHeight);
+            AddRegionPoints(listToFill, currentX, centerX, currentY, centerY);
 
 
-            for (int x = left; x <= right; x++)
+            currentY--;
+            if ((Math.Pow(halfHeight, 2) * Math.Pow(currentX - centerX + 0.5, 2)) +
+                (Math.Pow(halfWidth, 2) * Math.Pow(currentY - centerY, 2)) -
+                (Math.Pow(halfWidth, 2) * Math.Pow(halfHeight, 2)) < 0)
             {
             {
-                coordinates.Add(new Coordinates(x, top));
-                coordinates.Add(new Coordinates(x, bottom));
+                currentX++;
             }
             }
+        }
 
 
-            for (int y = top; y <= bottom; y++)
-            {
-                coordinates.Add(new Coordinates(left, y));
-                coordinates.Add(new Coordinates(right, y));
-            }
+        return listToFill;
+    }
+
+    private static void AddFallbackRectangle(double halfWidth, double halfHeight, double centerX, double centerY, List<Coordinates> coordinates)
+    {
+        int left = (int)Math.Floor(centerX - halfWidth);
+        int top = (int)Math.Floor(centerY - halfHeight);
+        int right = (int)Math.Floor(centerX + halfWidth);
+        int bottom = (int)Math.Floor(centerY + halfHeight);
+
+        for (int x = left; x <= right; x++)
+        {
+            coordinates.Add(new Coordinates(x, top));
+            coordinates.Add(new Coordinates(x, bottom));
         }
         }
 
 
-        private static void AddRegionPoints(List<Coordinates> coordinates, double x, double xc, double y, double yc)
+        for (int y = top; y <= bottom; y++)
         {
         {
-            int xFloor = (int)Math.Floor(x);
-            int yFloor = (int)Math.Floor(y);
-            int xFloorInv = (int)Math.Floor(-x + 2 * xc);
-            int yFloorInv = (int)Math.Floor(-y + 2 * yc);
+            coordinates.Add(new Coordinates(left, y));
+            coordinates.Add(new Coordinates(right, y));
+        }
+    }
 
 
-            //top and bottom or left and right
-            if (xFloor == xFloorInv || yFloor == yFloorInv)
-            {
-                coordinates.Add(new Coordinates(xFloor, yFloor));
-                coordinates.Add(new Coordinates(xFloorInv, yFloorInv));
-            }
-            //part of the arc
-            else
-            {
-                coordinates.Add(new Coordinates(xFloor, yFloor));
-                coordinates.Add(new Coordinates(xFloorInv, yFloorInv));
-                coordinates.Add(new Coordinates(xFloorInv, yFloor));
-                coordinates.Add(new Coordinates(xFloor, yFloorInv));
-            }
+    private static void AddRegionPoints(List<Coordinates> coordinates, double x, double xc, double y, double yc)
+    {
+        int xFloor = (int)Math.Floor(x);
+        int yFloor = (int)Math.Floor(y);
+        int xFloorInv = (int)Math.Floor(-x + 2 * xc);
+        int yFloorInv = (int)Math.Floor(-y + 2 * yc);
+
+        //top and bottom or left and right
+        if (xFloor == xFloorInv || yFloor == yFloorInv)
+        {
+            coordinates.Add(new Coordinates(xFloor, yFloor));
+            coordinates.Add(new Coordinates(xFloorInv, yFloorInv));
+        }
+        //part of the arc
+        else
+        {
+            coordinates.Add(new Coordinates(xFloor, yFloor));
+            coordinates.Add(new Coordinates(xFloorInv, yFloorInv));
+            coordinates.Add(new Coordinates(xFloorInv, yFloor));
+            coordinates.Add(new Coordinates(xFloor, yFloorInv));
         }
         }
     }
     }
-}
+}

+ 7 - 8
src/PixiEditor/Helpers/ExecutionTrigger.cs

@@ -1,13 +1,12 @@
 using System;
 using System;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+public class ExecutionTrigger<T>
 {
 {
-    public class ExecutionTrigger<T>
+    public event EventHandler<T> Triggered;
+    public void Execute(object sender, T args)
     {
     {
-        public event EventHandler<T> Triggered;
-        public void Execute(object sender, T args)
-        {
-            Triggered?.Invoke(sender, args);
-        }
+        Triggered?.Invoke(sender, args);
     }
     }
-}
+}

+ 16 - 17
src/PixiEditor/Helpers/Extensions/DictionaryHelper.cs

@@ -1,29 +1,28 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class DictionaryHelper
 {
 {
-    public static class DictionaryHelper
+    public static void AddRangeOverride<TKey, TValue>(
+        this IDictionary<TKey, TValue> dict,
+        IDictionary<TKey, TValue> dictToAdd)
     {
     {
-        public static void AddRangeOverride<TKey, TValue>(
-            this IDictionary<TKey, TValue> dict,
-            IDictionary<TKey, TValue> dictToAdd)
+        foreach (KeyValuePair<TKey, TValue> item in dictToAdd)
         {
         {
-            foreach (KeyValuePair<TKey, TValue> item in dictToAdd)
-            {
-                dict[item.Key] = item.Value;
-            }
+            dict[item.Key] = item.Value;
         }
         }
+    }
 
 
-        public static void AddRangeNewOnly<TKey, TValue>(
-            this IDictionary<TKey, TValue> dict,
-            IDictionary<TKey, TValue> dictToAdd)
+    public static void AddRangeNewOnly<TKey, TValue>(
+        this IDictionary<TKey, TValue> dict,
+        IDictionary<TKey, TValue> dictToAdd)
+    {
+        foreach (KeyValuePair<TKey, TValue> item in dictToAdd)
         {
         {
-            foreach (KeyValuePair<TKey, TValue> item in dictToAdd)
+            if (!dict.ContainsKey(item.Key))
             {
             {
-                if (!dict.ContainsKey(item.Key))
-                {
-                    dict.Add(item.Key, item.Value);
-                }
+                dict.Add(item.Key, item.Value);
             }
             }
         }
         }
     }
     }

+ 13 - 14
src/PixiEditor/Helpers/Extensions/DirectoryExtensions.cs

@@ -1,19 +1,18 @@
 using System.Linq;
 using System.Linq;
 
 
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class DirectoryExtensions
 {
 {
-    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)
     {
     {
-        /// <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();
-        }
+        return filters.Split('|').SelectMany(filter => System.IO.Directory.GetFiles(sourceFolder, $"*{filter}", searchOption)).ToArray();
     }
     }
-}
+}

+ 19 - 20
src/PixiEditor/Helpers/Extensions/EnumHelpers.cs

@@ -5,32 +5,31 @@ using System.Linq;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class EnumHelpers
 {
 {
-    public static class EnumHelpers
+    public static IEnumerable<T> GetFlags<T>(this T e)
+        where T : Enum
     {
     {
-        public static IEnumerable<T> GetFlags<T>(this T e)
-               where T : Enum
-        {
-            return Enum.GetValues(e.GetType()).Cast<T>().Where(x => e.HasFlag(x));
-        }
+        return Enum.GetValues(e.GetType()).Cast<T>().Where(x => e.HasFlag(x));
+    }
 
 
-        public static string GetDescription<T>(this T enumValue)
-            where T : struct, Enum
-        {
-            var description = enumValue.ToString();
-            var fieldInfo = enumValue.GetType().GetField(enumValue.ToString());
+    public static string GetDescription<T>(this T enumValue)
+        where T : struct, Enum
+    {
+        var description = enumValue.ToString();
+        var fieldInfo = enumValue.GetType().GetField(enumValue.ToString());
 
 
-            if (fieldInfo != null)
+        if (fieldInfo != null)
+        {
+            var attrs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), true);
+            if (attrs != null && attrs.Length > 0)
             {
             {
-                var attrs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), true);
-                if (attrs != null && attrs.Length > 0)
-                {
-                    description = ((DescriptionAttribute)attrs[0]).Description;
-                }
+                description = ((DescriptionAttribute)attrs[0]).Description;
             }
             }
-
-            return description;
         }
         }
+
+        return description;
     }
     }
 }
 }

+ 66 - 67
src/PixiEditor/Helpers/Extensions/EnumerableHelpers.cs

@@ -1,97 +1,96 @@
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class EnumerableHelpers
 {
 {
-    public static class EnumerableHelpers
+    /// <summary>
+    /// Get's the item at the <paramref name="index"/> if it matches the <paramref name="predicate"/> or the first that matches after the <paramref name="index"/>.
+    /// </summary>
+    /// <param name="overrun">Should the enumerator start from the bottom if it can't find the first item in the higher part</param>
+    /// <returns>The first item or null if no item can be found.</returns>
+    public static T IndexOrNext<T>(this IEnumerable<T> collection, Predicate<T> predicate, int index, bool overrun = true)
     {
     {
-        /// <summary>
-        /// Get's the item at the <paramref name="index"/> if it matches the <paramref name="predicate"/> or the first that matches after the <paramref name="index"/>.
-        /// </summary>
-        /// <param name="overrun">Should the enumerator start from the bottom if it can't find the first item in the higher part</param>
-        /// <returns>The first item or null if no item can be found.</returns>
-        public static T IndexOrNext<T>(this IEnumerable<T> collection, Predicate<T> predicate, int index, bool overrun = true)
+        if (index < 0)
         {
         {
-            if (index < 0)
-            {
-                throw new ArgumentOutOfRangeException(nameof(index));
-            }
+            throw new ArgumentOutOfRangeException(nameof(index));
+        }
 
 
-            var enumerator = collection.GetEnumerator();
+        var enumerator = collection.GetEnumerator();
 
 
-            // Iterate to the target index
-            for (int i = 0; i < index; i++)
-            {
-                if (!enumerator.MoveNext())
-                {
-                    return default;
-                }
-            }
-
-            while (enumerator.MoveNext())
-            {
-                if (predicate(enumerator.Current))
-                {
-                    return enumerator.Current;
-                }
-            }
-
-            if (!overrun)
+        // Iterate to the target index
+        for (int i = 0; i < index; i++)
+        {
+            if (!enumerator.MoveNext())
             {
             {
                 return default;
                 return default;
             }
             }
+        }
 
 
-            enumerator.Reset();
-
-            for (int i = 0; i < index; i++)
+        while (enumerator.MoveNext())
+        {
+            if (predicate(enumerator.Current))
             {
             {
-                enumerator.MoveNext();
-                if (predicate(enumerator.Current))
-                {
-                    return enumerator.Current;
-                }
+                return enumerator.Current;
             }
             }
+        }
 
 
+        if (!overrun)
+        {
             return default;
             return default;
         }
         }
 
 
-        /// <summary>
-        /// Get's the item at the <paramref name="index"/> if it matches the <paramref name="predicate"/> or the first item that matches before the <paramref name="index"/>.
-        /// </summary>
-        /// <param name="underrun">Should the enumerator start from the top if it can't find the first item in the lower part</param>
-        /// <returns>The first item or null if no item can be found.</returns>
-        public static T IndexOrPrevious<T>(this IEnumerable<T> collection, Predicate<T> predicate, int index, bool underrun = true)
+        enumerator.Reset();
+
+        for (int i = 0; i < index; i++)
         {
         {
-            if (index < 0)
+            enumerator.MoveNext();
+            if (predicate(enumerator.Current))
             {
             {
-                throw new ArgumentOutOfRangeException(nameof(index));
+                return enumerator.Current;
             }
             }
+        }
 
 
-            var enumerator = collection.GetEnumerator();
-            T[] previousItems = new T[index + 1];
+        return default;
+    }
 
 
-            // Iterate to the target index
-            for (int i = 0; i <= index; i++)
-            {
-                if (!enumerator.MoveNext())
-                {
-                    return default;
-                }
+    /// <summary>
+    /// Get's the item at the <paramref name="index"/> if it matches the <paramref name="predicate"/> or the first item that matches before the <paramref name="index"/>.
+    /// </summary>
+    /// <param name="underrun">Should the enumerator start from the top if it can't find the first item in the lower part</param>
+    /// <returns>The first item or null if no item can be found.</returns>
+    public static T IndexOrPrevious<T>(this IEnumerable<T> collection, Predicate<T> predicate, int index, bool underrun = true)
+    {
+        if (index < 0)
+        {
+            throw new ArgumentOutOfRangeException(nameof(index));
+        }
 
 
-                previousItems[i] = enumerator.Current;
-            }
+        var enumerator = collection.GetEnumerator();
+        T[] previousItems = new T[index + 1];
 
 
-            for (int i = index; i >= 0; i--)
+        // Iterate to the target index
+        for (int i = 0; i <= index; i++)
+        {
+            if (!enumerator.MoveNext())
             {
             {
-                if (predicate(previousItems[i]))
-                {
-                    return previousItems[i];
-                }
+                return default;
             }
             }
 
 
-            if (!underrun)
+            previousItems[i] = enumerator.Current;
+        }
+
+        for (int i = index; i >= 0; i--)
+        {
+            if (predicate(previousItems[i]))
             {
             {
-                return default;
+                return previousItems[i];
             }
             }
+        }
 
 
-            return IndexOrNext(collection, predicate, index, false);
+        if (!underrun)
+        {
+            return default;
         }
         }
+
+        return IndexOrNext(collection, predicate, index, false);
     }
     }
-}
+}

+ 38 - 39
src/PixiEditor/Helpers/Extensions/Int32RectHelper.cs

@@ -2,59 +2,58 @@
 using System;
 using System;
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class Int32RectHelper
 {
 {
-    public static class Int32RectHelper
+    public static Int32Rect Intersect(this Int32Rect rect, Int32Rect other)
     {
     {
-        public static Int32Rect Intersect(this Int32Rect rect, Int32Rect other)
-        {
-            int rectX2 = rect.X + rect.Width;
-            int rectY2 = rect.Y + rect.Height;
+        int rectX2 = rect.X + rect.Width;
+        int rectY2 = rect.Y + rect.Height;
 
 
-            int otherX2 = other.X + other.Width;
-            int otherY2 = other.Y + other.Height;
+        int otherX2 = other.X + other.Width;
+        int otherY2 = other.Y + other.Height;
 
 
-            int maxX1 = Math.Max(rect.X, other.X);
-            int maxY1 = Math.Max(rect.Y, other.Y);
+        int maxX1 = Math.Max(rect.X, other.X);
+        int maxY1 = Math.Max(rect.Y, other.Y);
 
 
-            int minX2 = Math.Min(rectX2, otherX2);
-            int minY2 = Math.Min(rectY2, otherY2);
+        int minX2 = Math.Min(rectX2, otherX2);
+        int minY2 = Math.Min(rectY2, otherY2);
 
 
-            int width = minX2 - maxX1;
-            int height = minY2 - maxY1;
+        int width = minX2 - maxX1;
+        int height = minY2 - maxY1;
 
 
-            if (width <= 0 || height <= 0)
-                return Int32Rect.Empty;
+        if (width <= 0 || height <= 0)
+            return Int32Rect.Empty;
 
 
-            return new Int32Rect(maxX1, maxY1, width, height);
-        }
+        return new Int32Rect(maxX1, maxY1, width, height);
+    }
 
 
-        public static Int32Rect Expand(this Int32Rect rect, Int32Rect other)
-        {
-            int rectX2 = rect.X + rect.Width;
-            int rectY2 = rect.Y + rect.Height;
+    public static Int32Rect Expand(this Int32Rect rect, Int32Rect other)
+    {
+        int rectX2 = rect.X + rect.Width;
+        int rectY2 = rect.Y + rect.Height;
 
 
-            int otherX2 = other.X + other.Width;
-            int otherY2 = other.Y + other.Height;
+        int otherX2 = other.X + other.Width;
+        int otherY2 = other.Y + other.Height;
 
 
-            int minX1 = Math.Min(rect.X, other.X);
-            int minY1 = Math.Min(rect.Y, other.Y);
+        int minX1 = Math.Min(rect.X, other.X);
+        int minY1 = Math.Min(rect.Y, other.Y);
 
 
-            int maxX2 = Math.Max(rectX2, otherX2);
-            int maxY2 = Math.Max(rectY2, otherY2);
+        int maxX2 = Math.Max(rectX2, otherX2);
+        int maxY2 = Math.Max(rectY2, otherY2);
 
 
-            int width = maxX2 - minX1;
-            int height = maxY2 - minY1;
+        int width = maxX2 - minX1;
+        int height = maxY2 - minY1;
 
 
-            if (width <= 0 || height <= 0)
-                return Int32Rect.Empty;
+        if (width <= 0 || height <= 0)
+            return Int32Rect.Empty;
 
 
-            return new Int32Rect(minX1, minY1, width, height);
-        }
+        return new Int32Rect(minX1, minY1, width, height);
+    }
 
 
-        public static SKRectI ToSKRectI(this Int32Rect rect)
-        {
-            return new SKRectI(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
-        }
+    public static SKRectI ToSKRectI(this Int32Rect rect)
+    {
+        return new SKRectI(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
     }
     }
-}
+}

+ 113 - 114
src/PixiEditor/Helpers/Extensions/ParserHelpers.cs

@@ -7,161 +7,160 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Collections.ObjectModel;
 
 
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class ParserHelpers
 {
 {
-    public static class ParserHelpers
+    public static Document ToDocument(this SerializableDocument serializableDocument)
     {
     {
-        public static Document ToDocument(this SerializableDocument serializableDocument)
+        Document document = new Document(serializableDocument.Width, serializableDocument.Height)
         {
         {
-            Document document = new Document(serializableDocument.Width, serializableDocument.Height)
-            {
-                Layers = serializableDocument.ToLayers(),
-                Swatches = new WpfObservableRangeCollection<SKColor>(serializableDocument.Swatches.ToSKColors()),
-                Palette = new WpfObservableRangeCollection<SKColor>(serializableDocument.Palette.ToSKColors())
-            };
-
-            document.LayerStructure.Groups = serializableDocument.ToGroups(document);
+            Layers = serializableDocument.ToLayers(),
+            Swatches = new WpfObservableRangeCollection<SKColor>(serializableDocument.Swatches.ToSKColors()),
+            Palette = new WpfObservableRangeCollection<SKColor>(serializableDocument.Palette.ToSKColors())
+        };
 
 
-            if (document.Layers.Count > 0)
-            {
-                document.SetMainActiveLayer(0);
-            }
-            document.Renderer.ForceRerender();
+        document.LayerStructure.Groups = serializableDocument.ToGroups(document);
 
 
-            return document;
-        }
-
-        public static WpfObservableRangeCollection<Layer> ToLayers(this SerializableDocument document)
+        if (document.Layers.Count > 0)
         {
         {
-            WpfObservableRangeCollection<Layer> layers = new();
-            foreach (SerializableLayer slayer in document)
-            {
-                layers.Add(slayer.ToLayer(document.Width, document.Height));
-            }
-
-            return layers;
+            document.SetMainActiveLayer(0);
         }
         }
+        document.Renderer.ForceRerender();
+
+        return document;
+    }
 
 
-        public static Layer ToLayer(this SerializableLayer layer, int maxWidth, int maxHeight)
+    public static WpfObservableRangeCollection<Layer> ToLayers(this SerializableDocument document)
+    {
+        WpfObservableRangeCollection<Layer> layers = new();
+        foreach (SerializableLayer slayer in document)
         {
         {
-            return new Layer(layer.Name, new Surface(layer.ToSKImage()), maxWidth, maxHeight)
-            {
-                Opacity = layer.Opacity,
-                IsVisible = layer.IsVisible,
-                Offset = new(layer.OffsetX, layer.OffsetY, 0, 0),
-            };
+            layers.Add(slayer.ToLayer(document.Width, document.Height));
         }
         }
 
 
-        public static WpfObservableRangeCollection<GuidStructureItem> ToGroups(this SerializableDocument sdocument, Document document)
-        {
-            WpfObservableRangeCollection<GuidStructureItem> groups = new();
+        return layers;
+    }
 
 
-            if (sdocument.Groups == null)
-            {
-                return groups;
-            }
+    public static Layer ToLayer(this SerializableLayer layer, int maxWidth, int maxHeight)
+    {
+        return new Layer(layer.Name, new Surface(layer.ToSKImage()), maxWidth, maxHeight)
+        {
+            Opacity = layer.Opacity,
+            IsVisible = layer.IsVisible,
+            Offset = new(layer.OffsetX, layer.OffsetY, 0, 0),
+        };
+    }
 
 
-            foreach (SerializableGroup sgroup in sdocument.Groups)
-            {
-                groups.Add(sgroup.ToGroup(null, document));
-            }
+    public static WpfObservableRangeCollection<GuidStructureItem> ToGroups(this SerializableDocument sdocument, Document document)
+    {
+        WpfObservableRangeCollection<GuidStructureItem> groups = new();
 
 
+        if (sdocument.Groups == null)
+        {
             return groups;
             return groups;
         }
         }
 
 
-        public static GuidStructureItem ToGroup(this SerializableGroup sgroup, GuidStructureItem parent, Document document)
+        foreach (SerializableGroup sgroup in sdocument.Groups)
         {
         {
-            GuidStructureItem group = new GuidStructureItem(sgroup.Name, Guid.Empty)
-            {
-                Opacity = sgroup.Opacity,
-                IsVisible = sgroup.IsVisible,
-                Parent = parent,
-                StartLayerGuid = document.Layers[sgroup.StartLayer].GuidValue,
-                EndLayerGuid = document.Layers[sgroup.EndLayer].GuidValue
-            };
-
-            group.Subgroups = new(sgroup.Subgroups.ToGroups(document, group));
-
-            return group;
+            groups.Add(sgroup.ToGroup(null, document));
         }
         }
 
 
-        public static SerializableDocument ToSerializable(this Document document)
+        return groups;
+    }
+
+    public static GuidStructureItem ToGroup(this SerializableGroup sgroup, GuidStructureItem parent, Document document)
+    {
+        GuidStructureItem group = new GuidStructureItem(sgroup.Name, Guid.Empty)
         {
         {
-            return new SerializableDocument(document.Width, document.Height,
-                                            document.LayerStructure.Groups.ToSerializable(document),
-                                            document.Layers.ToSerializable())
-                .AddSwatches(document.Swatches)
-                .AddPalette(document.Palette);
-        }
+            Opacity = sgroup.Opacity,
+            IsVisible = sgroup.IsVisible,
+            Parent = parent,
+            StartLayerGuid = document.Layers[sgroup.StartLayer].GuidValue,
+            EndLayerGuid = document.Layers[sgroup.EndLayer].GuidValue
+        };
+
+        group.Subgroups = new(sgroup.Subgroups.ToGroups(document, group));
 
 
-        public static IEnumerable<SerializableLayer> ToSerializable(this IEnumerable<Layer> layers)
+        return group;
+    }
+
+    public static SerializableDocument ToSerializable(this Document document)
+    {
+        return new SerializableDocument(document.Width, document.Height,
+                document.LayerStructure.Groups.ToSerializable(document),
+                document.Layers.ToSerializable())
+            .AddSwatches(document.Swatches)
+            .AddPalette(document.Palette);
+    }
+
+    public static IEnumerable<SerializableLayer> ToSerializable(this IEnumerable<Layer> layers)
+    {
+        foreach (Layer layer in layers)
         {
         {
-            foreach (Layer layer in layers)
-            {
-                yield return layer.ToSerializable();
-            }
+            yield return layer.ToSerializable();
         }
         }
+    }
 
 
-        public static SerializableLayer ToSerializable(this Layer layer)
+    public static SerializableLayer ToSerializable(this Layer layer)
+    {
+        return new SerializableLayer(layer.Width, layer.Height, layer.OffsetX, layer.OffsetY)
         {
         {
-            return new SerializableLayer(layer.Width, layer.Height, layer.OffsetX, layer.OffsetY)
-            {
-                IsVisible = layer.IsVisible,
-                Opacity = layer.Opacity,
-                Name = layer.Name
-            }.FromSKImage(layer.LayerBitmap.SkiaSurface.Snapshot());
-        }
+            IsVisible = layer.IsVisible,
+            Opacity = layer.Opacity,
+            Name = layer.Name
+        }.FromSKImage(layer.LayerBitmap.SkiaSurface.Snapshot());
+    }
 
 
-        public static IEnumerable<SerializableGroup> ToSerializable(this IEnumerable<GuidStructureItem> groups, Document document)
+    public static IEnumerable<SerializableGroup> ToSerializable(this IEnumerable<GuidStructureItem> groups, Document document)
+    {
+        foreach (GuidStructureItem group in groups)
         {
         {
-            foreach (GuidStructureItem group in groups)
-            {
-                yield return group.ToSerializable(document);
-            }
+            yield return group.ToSerializable(document);
         }
         }
+    }
 
 
-        public static SerializableGroup ToSerializable(this GuidStructureItem group, Document document)
+    public static SerializableGroup ToSerializable(this GuidStructureItem group, Document document)
+    {
+        SerializableGroup serializable = new SerializableGroup(group.Name, group.Subgroups.ToSerializable(document))
         {
         {
-            SerializableGroup serializable = new SerializableGroup(group.Name, group.Subgroups.ToSerializable(document))
-            {
-                Opacity = group.Opacity,
-                IsVisible = group.IsVisible
-            };
+            Opacity = group.Opacity,
+            IsVisible = group.IsVisible
+        };
 
 
-            for (int i = 0; i < document.Layers.Count; i++)
+        for (int i = 0; i < document.Layers.Count; i++)
+        {
+            if (group.StartLayerGuid == document.Layers[i].GuidValue)
             {
             {
-                if (group.StartLayerGuid == document.Layers[i].GuidValue)
-                {
-                    serializable.StartLayer = i;
-                }
-
-                if (group.EndLayerGuid == document.Layers[i].GuidValue)
-                {
-                    serializable.EndLayer = i;
-                }
+                serializable.StartLayer = i;
             }
             }
 
 
-            return serializable;
-        }
-
-        private static IEnumerable<GuidStructureItem> ToGroups(this IEnumerable<SerializableGroup> groups, Document document, GuidStructureItem parent)
-        {
-            foreach (SerializableGroup sgroup in groups)
+            if (group.EndLayerGuid == document.Layers[i].GuidValue)
             {
             {
-                yield return sgroup.ToGroup(parent, document);
+                serializable.EndLayer = i;
             }
             }
         }
         }
 
 
-        private static SerializableDocument AddSwatches(this SerializableDocument document, IEnumerable<SKColor> colors)
-        {
-            document.Swatches.AddRange(colors);
-            return document;
-        }
+        return serializable;
+    }
 
 
-        private static SerializableDocument AddPalette(this SerializableDocument document, IEnumerable<SKColor> palette)
+    private static IEnumerable<GuidStructureItem> ToGroups(this IEnumerable<SerializableGroup> groups, Document document, GuidStructureItem parent)
+    {
+        foreach (SerializableGroup sgroup in groups)
         {
         {
-            document.Palette.AddRange(palette);
-            return document;
+            yield return sgroup.ToGroup(parent, document);
         }
         }
     }
     }
+
+    private static SerializableDocument AddSwatches(this SerializableDocument document, IEnumerable<SKColor> colors)
+    {
+        document.Swatches.AddRange(colors);
+        return document;
+    }
+
+    private static SerializableDocument AddPalette(this SerializableDocument document, IEnumerable<SKColor> palette)
+    {
+        document.Palette.AddRange(palette);
+        return document;
+    }
 }
 }

+ 58 - 59
src/PixiEditor/Helpers/Extensions/PixelFormatHelper.cs

@@ -2,72 +2,71 @@
 using System;
 using System;
 using System.Windows.Media;
 using System.Windows.Media;
 
 
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class PixelFormatHelper
 {
 {
-    public static class PixelFormatHelper
+    public static SKColorType ToSkia(this PixelFormat format, out SKAlphaType alphaType)
     {
     {
-        public static SKColorType ToSkia(this PixelFormat format, out SKAlphaType alphaType)
+        if (TryToSkia(format, out SKColorType color, out alphaType))
         {
         {
-            if (TryToSkia(format, out SKColorType color, out alphaType))
-            {
-                return color;
-            }
-            else
-            {
-                throw new NotImplementedException($"Skia does not support the '{format}' format");
-            }
+            return color;
         }
         }
-
-        public static bool TryToSkia(this PixelFormat format, out SKColorType colorType, out SKAlphaType alphaType)
+        else
         {
         {
-            if (format == PixelFormats.Rgba64)
-            {
-                alphaType = SKAlphaType.Unpremul;
-                colorType = SKColorType.Rgba16161616;
-                return true;
-            }
-            else if (format == PixelFormats.Bgra32)
-            {
-                alphaType = SKAlphaType.Unpremul;
-                colorType = SKColorType.Bgra8888;
-                return true;
-            }
-            else if (format == PixelFormats.Default)
-            {
-                alphaType = SKAlphaType.Unpremul;
-                colorType = SKColorType.RgbaF16;
-                return true;
-            }
-            else if (format == PixelFormats.Gray8)
-            {
-                alphaType = SKAlphaType.Opaque;
-                colorType = SKColorType.Gray8;
-                return true;
-            }
-            else if (format == PixelFormats.Pbgra32)
-            {
-                alphaType = SKAlphaType.Premul;
-                colorType = SKColorType.Bgra8888;
-                return true;
-            }
-            else if (format == PixelFormats.Bgr101010 || format == PixelFormats.Bgr24 || format == PixelFormats.Bgr32 || format == PixelFormats.Bgr555 ||
-                     format == PixelFormats.Bgr565 || format == PixelFormats.BlackWhite || format == PixelFormats.Cmyk32 || format == PixelFormats.Gray16 ||
-                     format == PixelFormats.Gray2 || format == PixelFormats.Gray32Float || format == PixelFormats.Gray4 || format == PixelFormats.Indexed1 ||
-                     format == PixelFormats.Indexed2 || format == PixelFormats.Indexed4 || format == PixelFormats.Indexed8 || format == PixelFormats.Prgba128Float ||
-                     format == PixelFormats.Prgba64 || format == PixelFormats.Rgb128Float || format == PixelFormats.Rgb24 || format == PixelFormats.Rgb48 ||
-                     format == PixelFormats.Rgba128Float)
-            {
-                alphaType = SKAlphaType.Unknown;
-                colorType = SKColorType.Unknown;
-                return false;
-            }
-
-            throw new NotImplementedException($"'{format}' has not been implemented by {nameof(PixelFormatHelper)}.{nameof(TryToSkia)}()");
+            throw new NotImplementedException($"Skia does not support the '{format}' format");
         }
         }
+    }
 
 
-        public static bool IsSkiaSupported(this PixelFormat format)
+    public static bool TryToSkia(this PixelFormat format, out SKColorType colorType, out SKAlphaType alphaType)
+    {
+        if (format == PixelFormats.Rgba64)
         {
         {
-            return TryToSkia(format, out _, out _);
+            alphaType = SKAlphaType.Unpremul;
+            colorType = SKColorType.Rgba16161616;
+            return true;
         }
         }
+        else if (format == PixelFormats.Bgra32)
+        {
+            alphaType = SKAlphaType.Unpremul;
+            colorType = SKColorType.Bgra8888;
+            return true;
+        }
+        else if (format == PixelFormats.Default)
+        {
+            alphaType = SKAlphaType.Unpremul;
+            colorType = SKColorType.RgbaF16;
+            return true;
+        }
+        else if (format == PixelFormats.Gray8)
+        {
+            alphaType = SKAlphaType.Opaque;
+            colorType = SKColorType.Gray8;
+            return true;
+        }
+        else if (format == PixelFormats.Pbgra32)
+        {
+            alphaType = SKAlphaType.Premul;
+            colorType = SKColorType.Bgra8888;
+            return true;
+        }
+        else if (format == PixelFormats.Bgr101010 || format == PixelFormats.Bgr24 || format == PixelFormats.Bgr32 || format == PixelFormats.Bgr555 ||
+                 format == PixelFormats.Bgr565 || format == PixelFormats.BlackWhite || format == PixelFormats.Cmyk32 || format == PixelFormats.Gray16 ||
+                 format == PixelFormats.Gray2 || format == PixelFormats.Gray32Float || format == PixelFormats.Gray4 || format == PixelFormats.Indexed1 ||
+                 format == PixelFormats.Indexed2 || format == PixelFormats.Indexed4 || format == PixelFormats.Indexed8 || format == PixelFormats.Prgba128Float ||
+                 format == PixelFormats.Prgba64 || format == PixelFormats.Rgb128Float || format == PixelFormats.Rgb24 || format == PixelFormats.Rgb48 ||
+                 format == PixelFormats.Rgba128Float)
+        {
+            alphaType = SKAlphaType.Unknown;
+            colorType = SKColorType.Unknown;
+            return false;
+        }
+
+        throw new NotImplementedException($"'{format}' has not been implemented by {nameof(PixelFormatHelper)}.{nameof(TryToSkia)}()");
+    }
+
+    public static bool IsSkiaSupported(this PixelFormat format)
+    {
+        return TryToSkia(format, out _, out _);
     }
     }
-}
+}

+ 6 - 7
src/PixiEditor/Helpers/Extensions/SKRectIHelper.cs

@@ -1,13 +1,12 @@
 using SkiaSharp;
 using SkiaSharp;
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class SKRectIHelper
 {
 {
-    public static class SKRectIHelper
+    public static Int32Rect ToInt32Rect(this SKRectI rect)
     {
     {
-        public static Int32Rect ToInt32Rect(this SKRectI rect)
-        {
-            return new Int32Rect(rect.Left, rect.Top, rect.Width, rect.Height);
-        }
+        return new Int32Rect(rect.Left, rect.Top, rect.Width, rect.Height);
     }
     }
-}
+}

+ 53 - 54
src/PixiEditor/Helpers/Extensions/ServiceCollectionHelpers.cs

@@ -12,58 +12,57 @@ using PixiEditor.Models.UserPreferences;
 using PixiEditor.ViewModels;
 using PixiEditor.ViewModels;
 using PixiEditor.ViewModels.SubViewModels.Main;
 using PixiEditor.ViewModels.SubViewModels.Main;
 
 
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class ServiceCollectionHelpers
 {
 {
-    public static class ServiceCollectionHelpers
-    {
-        /// <summary>
-        /// Add's all the services required to fully run PixiEditor's MainWindow
-        /// </summary>
-        public static IServiceCollection AddPixiEditor(this IServiceCollection collection) => collection
-                .AddSingleton<ViewModelMain>()
-                .AddSingleton<IPreferences, PreferencesSettings>()
-                // View Models
-                .AddSingleton<StylusViewModel>()
-                .AddSingleton<WindowViewModel>()
-                .AddSingleton<ToolsViewModel>()
-                .AddSingleton<FileViewModel>()
-                .AddSingleton<UpdateViewModel>()
-                .AddSingleton<IoViewModel>()
-                .AddSingleton<LayersViewModel>()
-                .AddSingleton<ClipboardViewModel>()
-                .AddSingleton<UndoViewModel>()
-                .AddSingleton<SelectionViewModel>()
-                .AddSingleton<ViewportViewModel>()
-                .AddSingleton<ColorsViewModel>()
-                .AddSingleton<DocumentViewModel>()
-                .AddSingleton<RegistryViewModel>()
-                .AddSingleton(static x => new DiscordViewModel(x.GetService<ViewModelMain>(), "764168193685979138"))
-                .AddSingleton<DebugViewModel>()
-                .AddSingleton<SearchViewModel>()
-                // Controllers
-                .AddSingleton<ShortcutController>()
-                .AddSingleton<CommandController>()
-                .AddSingleton<BitmapManager>()
-                // Tools
-                .AddSingleton<Tool, MoveViewportTool>()
-                .AddSingleton<Tool, MoveTool>()
-                .AddSingleton<Tool, PenTool>()
-                .AddSingleton<Tool, SelectTool>()
-                .AddSingleton<Tool, MagicWandTool>()
-                .AddSingleton<Tool, FloodFillTool>()
-                .AddSingleton<Tool, LineTool>()
-                .AddSingleton<Tool, CircleTool>()
-                .AddSingleton<Tool, RectangleTool>()
-                .AddSingleton<Tool, EraserTool>()
-                .AddSingleton<Tool, ColorPickerTool>()
-                .AddSingleton<Tool, BrightnessTool>()
-                .AddSingleton<Tool, ZoomTool>()
-                // Palette Parsers
-                .AddSingleton<PaletteFileParser, JascFileParser>()
-                .AddSingleton<PaletteFileParser, ClsFileParser>()
-                // Palette data sources
-                .AddSingleton<PaletteListDataSource, LocalPalettesFetcher>()
-                // Other
-                .AddSingleton<DocumentProvider>();
-    }
-}
+    /// <summary>
+    /// Add's all the services required to fully run PixiEditor's MainWindow
+    /// </summary>
+    public static IServiceCollection AddPixiEditor(this IServiceCollection collection) => collection
+        .AddSingleton<ViewModelMain>()
+        .AddSingleton<IPreferences, PreferencesSettings>()
+        // View Models
+        .AddSingleton<StylusViewModel>()
+        .AddSingleton<WindowViewModel>()
+        .AddSingleton<ToolsViewModel>()
+        .AddSingleton<FileViewModel>()
+        .AddSingleton<UpdateViewModel>()
+        .AddSingleton<IoViewModel>()
+        .AddSingleton<LayersViewModel>()
+        .AddSingleton<ClipboardViewModel>()
+        .AddSingleton<UndoViewModel>()
+        .AddSingleton<SelectionViewModel>()
+        .AddSingleton<ViewportViewModel>()
+        .AddSingleton<ColorsViewModel>()
+        .AddSingleton<DocumentViewModel>()
+        .AddSingleton<RegistryViewModel>()
+        .AddSingleton(static x => new DiscordViewModel(x.GetService<ViewModelMain>(), "764168193685979138"))
+        .AddSingleton<DebugViewModel>()
+        .AddSingleton<SearchViewModel>()
+        // Controllers
+        .AddSingleton<ShortcutController>()
+        .AddSingleton<CommandController>()
+        .AddSingleton<BitmapManager>()
+        // Tools
+        .AddSingleton<Tool, MoveViewportTool>()
+        .AddSingleton<Tool, MoveTool>()
+        .AddSingleton<Tool, PenTool>()
+        .AddSingleton<Tool, SelectTool>()
+        .AddSingleton<Tool, MagicWandTool>()
+        .AddSingleton<Tool, FloodFillTool>()
+        .AddSingleton<Tool, LineTool>()
+        .AddSingleton<Tool, CircleTool>()
+        .AddSingleton<Tool, RectangleTool>()
+        .AddSingleton<Tool, EraserTool>()
+        .AddSingleton<Tool, ColorPickerTool>()
+        .AddSingleton<Tool, BrightnessTool>()
+        .AddSingleton<Tool, ZoomTool>()
+        // Palette Parsers
+        .AddSingleton<PaletteFileParser, JascFileParser>()
+        .AddSingleton<PaletteFileParser, ClsFileParser>()
+        // Palette data sources
+        .AddSingleton<PaletteListDataSource, LocalPalettesFetcher>()
+        // Other
+        .AddSingleton<DocumentProvider>();
+}

+ 8 - 9
src/PixiEditor/Helpers/Extensions/SkiaWPFHelpers.cs

@@ -1,14 +1,13 @@
 using SkiaSharp;
 using SkiaSharp;
 using System.Windows.Media;
 using System.Windows.Media;
 
 
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class SkiaWPFHelpers
 {
 {
-    public static class SkiaWPFHelpers
-    {
-        public static SKColor ToOpaqueSKColor(this Color color) => new(color.R, color.G, color.B);
-        public static SKColor ToSKColor(this Color color) => new(color.R, color.G, color.B, color.A);
+    public static SKColor ToOpaqueSKColor(this Color color) => new(color.R, color.G, color.B);
+    public static SKColor ToSKColor(this Color color) => new(color.R, color.G, color.B, color.A);
 
 
-        public static Color ToOpaqueColor(this SKColor color) => Color.FromRgb(color.Red, color.Green, color.Blue);
-        public static Color ToColor(this SKColor color) => Color.FromArgb(color.Alpha, color.Red, color.Green, color.Blue);
-    }
-}
+    public static Color ToOpaqueColor(this SKColor color) => Color.FromRgb(color.Red, color.Green, color.Blue);
+    public static Color ToColor(this SKColor color) => Color.FromArgb(color.Alpha, color.Red, color.Green, color.Blue);
+}

+ 19 - 20
src/PixiEditor/Helpers/Extensions/StringHelpers.cs

@@ -4,29 +4,28 @@ using System.Linq;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class StringHelpers
 {
 {
-    public static class StringHelpers
+    public static string AddSpacesBeforeUppercaseLetters(this string text)
     {
     {
-        public static string AddSpacesBeforeUppercaseLetters(this string text)
-        {
-            if (string.IsNullOrWhiteSpace(text))
-                return "";
-
-            StringBuilder newText = new StringBuilder(text.Length * 2);
-            newText.Append(text[0]);
-            for (int i = 1; i < text.Length; i++)
-            {
-                if (char.IsUpper(text[i]) && text[i - 1] != ' ')
-                    newText.Append(' ');
-                newText.Append(text[i]);
-            }
-            return newText.ToString();
-        }
+        if (string.IsNullOrWhiteSpace(text))
+            return "";
 
 
-        public static string Limit(this string value, int maxLenght)
+        StringBuilder newText = new StringBuilder(text.Length * 2);
+        newText.Append(text[0]);
+        for (int i = 1; i < text.Length; i++)
         {
         {
-            return value.Length > maxLenght ? value.Substring(0, maxLenght) : value;
+            if (char.IsUpper(text[i]) && text[i - 1] != ' ')
+                newText.Append(' ');
+            newText.Append(text[i]);
         }
         }
+        return newText.ToString();
+    }
+
+    public static string Limit(this string value, int maxLenght)
+    {
+        return value.Length > maxLenght ? value.Substring(0, maxLenght) : value;
     }
     }
-}
+}

+ 6 - 7
src/PixiEditor/Helpers/Extensions/ToolbarHelpers.cs

@@ -2,14 +2,13 @@
 using PixiEditor.Models.Tools.ToolSettings.Settings;
 using PixiEditor.Models.Tools.ToolSettings.Settings;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
 
 
-namespace PixiEditor.Helpers.Extensions
+namespace PixiEditor.Helpers.Extensions;
+
+public static class ToolbarHelpers
 {
 {
-    public static class ToolbarHelpers
+    public static EnumSetting<TEnum> GetEnumSetting<TEnum>(this Toolbar toolbar, string name)
+        where TEnum : struct, Enum
     {
     {
-        public static EnumSetting<TEnum> GetEnumSetting<TEnum>(this Toolbar toolbar, string name)
-            where TEnum : struct, Enum
-        {
-            return toolbar.GetSetting<EnumSetting<TEnum>>(name);
-        }
+        return toolbar.GetSetting<EnumSetting<TEnum>>(name);
     }
     }
 }
 }

+ 103 - 104
src/PixiEditor/Helpers/GlobalMouseHook.cs

@@ -7,143 +7,142 @@ using System.Windows;
 using System.Windows.Input;
 using System.Windows.Input;
 using System.Windows.Threading;
 using System.Windows.Threading;
 
 
-namespace PixiEditor.Helpers
-{
-    public delegate void MouseUpEventHandler(object sender, Point p, MouseButton button);
+namespace PixiEditor.Helpers;
 
 
-    // see https://stackoverflow.com/questions/22659925/how-to-capture-mouseup-event-outside-the-wpf-window
-    [ExcludeFromCodeCoverage]
-    public static class GlobalMouseHook
-    {
-        private const int WH_MOUSE_LL = 14;
-        private const int WM_LBUTTONUP = 0x0202;
-        private const int WM_MBUTTONUP = 0x0208;
-        private const int WM_RBUTTONUP = 0x0205;
+public delegate void MouseUpEventHandler(object sender, Point p, MouseButton button);
 
 
-        private static int mouseHookHandle;
-        private static HookProc mouseDelegate;
+// see https://stackoverflow.com/questions/22659925/how-to-capture-mouseup-event-outside-the-wpf-window
+[ExcludeFromCodeCoverage]
+public static class GlobalMouseHook
+{
+    private const int WH_MOUSE_LL = 14;
+    private const int WM_LBUTTONUP = 0x0202;
+    private const int WM_MBUTTONUP = 0x0208;
+    private const int WM_RBUTTONUP = 0x0205;
 
 
-        private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
+    private static int mouseHookHandle;
+    private static HookProc mouseDelegate;
 
 
-        public static event MouseUpEventHandler OnMouseUp
-        {
-            add
-            { 
+    private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
+
+    public static event MouseUpEventHandler OnMouseUp
+    {
+        add
+        { 
 // disable low-level hook in debug to prevent mouse lag when pausing in debugger
 // disable low-level hook in debug to prevent mouse lag when pausing in debugger
 #if !DEBUG
 #if !DEBUG
                 Subscribe();
                 Subscribe();
 #endif
 #endif
-                MouseUp += value;
-            }
+            MouseUp += value;
+        }
 
 
-            remove
-            {
-                MouseUp -= value;
+        remove
+        {
+            MouseUp -= value;
 #if !DEBUG
 #if !DEBUG
                 Unsubscribe();
                 Unsubscribe();
 #endif
 #endif
-            }
         }
         }
+    }
 
 
-        private static event MouseUpEventHandler MouseUp;
+    private static event MouseUpEventHandler MouseUp;
 
 
-        public static void RaiseMouseUp()
-        {
-            MouseUp?.Invoke(default, default, default);
-        }
+    public static void RaiseMouseUp()
+    {
+        MouseUp?.Invoke(default, default, default);
+    }
 
 
-        private static void Unsubscribe()
+    private static void Unsubscribe()
+    {
+        if (mouseHookHandle != 0)
         {
         {
-            if (mouseHookHandle != 0)
+            int result = UnhookWindowsHookEx(mouseHookHandle);
+            mouseHookHandle = 0;
+            mouseDelegate = null;
+            if (result == 0)
             {
             {
-                int result = UnhookWindowsHookEx(mouseHookHandle);
-                mouseHookHandle = 0;
-                mouseDelegate = null;
-                if (result == 0)
-                {
-                    int errorCode = Marshal.GetLastWin32Error();
-                    throw new Win32Exception(errorCode);
-                }
+                int errorCode = Marshal.GetLastWin32Error();
+                throw new Win32Exception(errorCode);
             }
             }
         }
         }
+    }
 
 
-        private static void Subscribe()
+    private static void Subscribe()
+    {
+        if (mouseHookHandle == 0)
         {
         {
+            mouseDelegate = MouseHookProc;
+            mouseHookHandle = SetWindowsHookEx(
+                WH_MOUSE_LL,
+                mouseDelegate,
+                GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
+                0);
             if (mouseHookHandle == 0)
             if (mouseHookHandle == 0)
             {
             {
-                mouseDelegate = MouseHookProc;
-                mouseHookHandle = SetWindowsHookEx(
-                    WH_MOUSE_LL,
-                    mouseDelegate,
-                    GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
-                    0);
-                if (mouseHookHandle == 0)
-                {
-                    int errorCode = Marshal.GetLastWin32Error();
-                    throw new Win32Exception(errorCode);
-                }
+                int errorCode = Marshal.GetLastWin32Error();
+                throw new Win32Exception(errorCode);
             }
             }
         }
         }
+    }
 
 
-        private static int MouseHookProc(int nCode, int wParam, IntPtr lParam)
+    private static int MouseHookProc(int nCode, int wParam, IntPtr lParam)
+    {
+        if (nCode >= 0)
         {
         {
-            if (nCode >= 0)
+            MSLLHOOKSTRUCT mouseHookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
+            if (wParam == WM_LBUTTONUP || wParam == WM_MBUTTONUP || wParam == WM_RBUTTONUP)
             {
             {
-                MSLLHOOKSTRUCT mouseHookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
-                if (wParam == WM_LBUTTONUP || wParam == WM_MBUTTONUP || wParam == WM_RBUTTONUP)
+                if (MouseUp != null)
                 {
                 {
-                    if (MouseUp != null)
-                    {
-
-                        MouseButton button = wParam == WM_LBUTTONUP ? MouseButton.Left
-                            : wParam == WM_MBUTTONUP ? MouseButton.Middle : MouseButton.Right;
-                        Dispatcher.CurrentDispatcher.BeginInvoke(() =>
-                            MouseUp.Invoke(null, new Point(mouseHookStruct.Pt.X, mouseHookStruct.Pt.Y), button));
-                    }
+
+                    MouseButton button = wParam == WM_LBUTTONUP ? MouseButton.Left
+                        : wParam == WM_MBUTTONUP ? MouseButton.Middle : MouseButton.Right;
+                    Dispatcher.CurrentDispatcher.BeginInvoke(() =>
+                        MouseUp.Invoke(null, new Point(mouseHookStruct.Pt.X, mouseHookStruct.Pt.Y), button));
                 }
                 }
             }
             }
-
-            return CallNextHookEx(mouseHookHandle, nCode, wParam, lParam);
         }
         }
 
 
-        [DllImport(
-            "user32.dll",
-            CharSet = CharSet.Auto,
-            CallingConvention = CallingConvention.StdCall,
-            SetLastError = true)]
-        private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
-
-        [DllImport(
-            "user32.dll",
-            CharSet = CharSet.Auto,
-            CallingConvention = CallingConvention.StdCall,
-            SetLastError = true)]
-        private static extern int UnhookWindowsHookEx(int idHook);
-
-        [DllImport(
-            "user32.dll",
-            CharSet = CharSet.Auto,
-            CallingConvention = CallingConvention.StdCall)]
-        private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
-
-        [DllImport("kernel32.dll")]
-        private static extern IntPtr GetModuleHandle(string name);
-
-        [StructLayout(LayoutKind.Sequential)]
-        private struct POINT
-        {
-            public int X;
-            public int Y;
-        }
+        return CallNextHookEx(mouseHookHandle, nCode, wParam, lParam);
+    }
 
 
-        [StructLayout(LayoutKind.Sequential)]
-        private struct MSLLHOOKSTRUCT
-        {
-            public POINT Pt;
-            public uint MouseData;
-            public uint Flags;
-            public uint Time;
-            public IntPtr DwExtraInfo;
-        }
+    [DllImport(
+        "user32.dll",
+        CharSet = CharSet.Auto,
+        CallingConvention = CallingConvention.StdCall,
+        SetLastError = true)]
+    private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
+
+    [DllImport(
+        "user32.dll",
+        CharSet = CharSet.Auto,
+        CallingConvention = CallingConvention.StdCall,
+        SetLastError = true)]
+    private static extern int UnhookWindowsHookEx(int idHook);
+
+    [DllImport(
+        "user32.dll",
+        CharSet = CharSet.Auto,
+        CallingConvention = CallingConvention.StdCall)]
+    private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
+
+    [DllImport("kernel32.dll")]
+    private static extern IntPtr GetModuleHandle(string name);
+
+    [StructLayout(LayoutKind.Sequential)]
+    private struct POINT
+    {
+        public int X;
+        public int Y;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    private struct MSLLHOOKSTRUCT
+    {
+        public POINT Pt;
+        public uint MouseData;
+        public uint Flags;
+        public uint Time;
+        public IntPtr DwExtraInfo;
     }
     }
-}
+}

+ 67 - 68
src/PixiEditor/Helpers/InputKeyHelpers.cs

@@ -3,84 +3,83 @@ using System.Runtime.InteropServices;
 using System.Text;
 using System.Text;
 using System.Windows.Input;
 using System.Windows.Input;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+public static class InputKeyHelpers
 {
 {
-    public static class InputKeyHelpers
+    /// <summary>
+    /// Returns the charcter of the <paramref name="key"/> mapped to the users keyboard layout
+    /// </summary>
+    public static string GetKeyboardKey(Key key) => GetKeyboardKey(key, CultureInfo.CurrentCulture);
+
+    public static string GetKeyboardKey(Key key, CultureInfo culture) => key switch
     {
     {
-        /// <summary>
-        /// Returns the charcter of the <paramref name="key"/> mapped to the users keyboard layout
-        /// </summary>
-        public static string GetKeyboardKey(Key key) => GetKeyboardKey(key, CultureInfo.CurrentCulture);
+        >= Key.NumPad0 and <= Key.Divide => $"Num {GetMappedKey(key, culture)}",
+        Key.Space => nameof(Key.Space),
+        Key.Tab => nameof(Key.Tab),
+        Key.Back => "Backspace",
+        Key.Escape => "Esc",
+        _ => GetMappedKey(key, culture),
+    };
+
+    private static string GetMappedKey(Key key, CultureInfo culture)
+    {
+        int virtualKey = KeyInterop.VirtualKeyFromKey(key);
+        byte[] keyboardState = new byte[256];
 
 
-        public static string GetKeyboardKey(Key key, CultureInfo culture) => key switch
+        uint scanCode = MapVirtualKeyExW((uint)virtualKey, MapType.MAPVK_VK_TO_VSC, culture.KeyboardLayoutId);
+        StringBuilder stringBuilder = new(3);
+
+        int result = ToUnicode((uint)virtualKey, scanCode, keyboardState, stringBuilder, stringBuilder.Capacity, 0);
+
+        string stringResult;
+
+        stringResult = result switch
         {
         {
-            >= Key.NumPad0 and <= Key.Divide => $"Num {GetMappedKey(key, culture)}",
-            Key.Space => nameof(Key.Space),
-            Key.Tab => nameof(Key.Tab),
-            Key.Back => "Backspace",
-            Key.Escape => "Esc",
-            _ => GetMappedKey(key, culture),
+            0 => key.ToString(),
+            -1 => stringBuilder.ToString().ToUpper(),
+            _ => stringBuilder[result - 1].ToString().ToUpper()
         };
         };
 
 
-        private static string GetMappedKey(Key key, CultureInfo culture)
-        {
-            int virtualKey = KeyInterop.VirtualKeyFromKey(key);
-            byte[] keyboardState = new byte[256];
+        return stringResult;
+    }
+
+    private enum MapType : uint
+    {
+        /// <summary>
+        /// The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0.
+        /// </summary>
+        MAPVK_VK_TO_VSC = 0x0,
 
 
-            uint scanCode = MapVirtualKeyExW((uint)virtualKey, MapType.MAPVK_VK_TO_VSC, culture.KeyboardLayoutId);
-            StringBuilder stringBuilder = new(3);
+        /// <summary>
+        /// The uCode parameter is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0.
+        /// </summary>
+        MAPVK_VSC_TO_VK = 0x1,
 
 
-            int result = ToUnicode((uint)virtualKey, scanCode, keyboardState, stringBuilder, stringBuilder.Capacity, 0);
+        /// <summary>
+        /// The uCode parameter is a virtual-key code and is translated into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0.
+        /// </summary>
+        MAPVK_VK_TO_CHAR = 0x2,
 
 
-            string stringResult;
+        /// <summary>
+        /// The uCode parameter is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0.
+        /// </summary>
+        MAPVK_VSC_TO_VK_EX = 0x3,
+    }
 
 
-            stringResult = result switch
-            {
-                0 => key.ToString(),
-                -1 => stringBuilder.ToString().ToUpper(),
-                _ => stringBuilder[result - 1].ToString().ToUpper()
-            };
+    [DllImport("user32.dll")]
+    private static extern int ToUnicode(
+        uint wVirtKey,
+        uint wScanCode,
+        byte[] lpKeyState,
+        [Out, MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = 4)]
+        StringBuilder pwszBuff,
+        int cchBuff,
+        uint wFlags);
 
 
-            return stringResult;
-        }
+    [DllImport("user32.dll")]
+    private static extern bool GetKeyboardState(byte[] lpKeyState);
 
 
-        private enum MapType : uint
-        {
-            /// <summary>
-            /// The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0.
-            /// </summary>
-            MAPVK_VK_TO_VSC = 0x0,
-
-            /// <summary>
-            /// The uCode parameter is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0.
-            /// </summary>
-            MAPVK_VSC_TO_VK = 0x1,
-
-            /// <summary>
-            /// The uCode parameter is a virtual-key code and is translated into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0.
-            /// </summary>
-            MAPVK_VK_TO_CHAR = 0x2,
-
-            /// <summary>
-            /// The uCode parameter is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0.
-            /// </summary>
-            MAPVK_VSC_TO_VK_EX = 0x3,
-        }
-
-        [DllImport("user32.dll")]
-        private static extern int ToUnicode(
-            uint wVirtKey,
-            uint wScanCode,
-            byte[] lpKeyState,
-            [Out, MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = 4)]
-            StringBuilder pwszBuff,
-            int cchBuff,
-            uint wFlags);
-
-        [DllImport("user32.dll")]
-        private static extern bool GetKeyboardState(byte[] lpKeyState);
-
-        [DllImport("user32.dll")]
-        private static extern uint MapVirtualKeyExW(uint uCode, MapType uMapType, int hkl);
-    }
+    [DllImport("user32.dll")]
+    private static extern uint MapVirtualKeyExW(uint uCode, MapType uMapType, int hkl);
 }
 }

+ 19 - 20
src/PixiEditor/Helpers/PaletteHelpers.cs

@@ -1,31 +1,30 @@
 using PixiEditor.Models.IO;
 using PixiEditor.Models.IO;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+public static class PaletteHelpers
 {
 {
-    public static class PaletteHelpers
+    public static string GetFilter(IList<PaletteFileParser> parsers, bool includeCommon)
     {
     {
-        public static string GetFilter(IList<PaletteFileParser> parsers, bool includeCommon)
-        {
-            string filter = "";
-
-            if (includeCommon)
-            {
-                List<string> allSupportedFormats = new();
-                foreach (var parser in parsers)
-                {
-                    allSupportedFormats.AddRange(parser.SupportedFileExtensions);
-                }
-                string allSupportedFormatsString = string.Join(';', allSupportedFormats).Replace(".", "*.");
-                filter += $"Palette Files ({allSupportedFormatsString})|{allSupportedFormatsString}|";
-            }
+        string filter = "";
 
 
+        if (includeCommon)
+        {
+            List<string> allSupportedFormats = new();
             foreach (var parser in parsers)
             foreach (var parser in parsers)
             {
             {
-                string supportedFormats = string.Join(';', parser.SupportedFileExtensions).Replace(".", "*.");
-                filter += $"{parser.FileName} ({supportedFormats})|{supportedFormats}|";
+                allSupportedFormats.AddRange(parser.SupportedFileExtensions);
             }
             }
+            string allSupportedFormatsString = string.Join(';', allSupportedFormats).Replace(".", "*.");
+            filter += $"Palette Files ({allSupportedFormatsString})|{allSupportedFormatsString}|";
+        }
 
 
-            return filter.Remove(filter.Length - 1);
+        foreach (var parser in parsers)
+        {
+            string supportedFormats = string.Join(';', parser.SupportedFileExtensions).Replace(".", "*.");
+            filter += $"{parser.FileName} ({supportedFormats})|{supportedFormats}|";
         }
         }
+
+        return filter.Remove(filter.Length - 1);
     }
     }
-}
+}

+ 11 - 12
src/PixiEditor/Helpers/ProcessHelpers.cs

@@ -1,19 +1,18 @@
 using System;
 using System;
 using System.Diagnostics;
 using System.Diagnostics;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+public static class ProcessHelpers
 {
 {
-    public static class ProcessHelpers
+    public static void ShellExecute(string url)
     {
     {
-        public static void ShellExecute(string url)
+        Process.Start(new ProcessStartInfo
         {
         {
-            Process.Start(new ProcessStartInfo
-            {
-                FileName = url,
-                UseShellExecute = true
-            });
-        }
-
-        public static void ShellExecuteEV(string path) => ShellExecute(Environment.ExpandEnvironmentVariables(path));
+            FileName = url,
+            UseShellExecute = true
+        });
     }
     }
-}
+
+    public static void ShellExecuteEV(string path) => ShellExecute(Environment.ExpandEnvironmentVariables(path));
+}

+ 47 - 48
src/PixiEditor/Helpers/RelayCommand.cs

@@ -1,71 +1,70 @@
 using System;
 using System;
 using System.Windows.Input;
 using System.Windows.Input;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+public class RelayCommand<T> : ICommand
 {
 {
-    public class RelayCommand<T> : ICommand
+    private readonly Action<T> execute;
+    private readonly Predicate<T> canExecute;
+
+    public RelayCommand(Action<T> execute)
+        : this(execute, null)
     {
     {
-        private readonly Action<T> execute;
-        private readonly Predicate<T> canExecute;
+    }
 
 
-        public RelayCommand(Action<T> execute)
-            : this(execute, null)
+    public RelayCommand(Action<T> execute, Predicate<T> canExecute)
+    {
+        if (execute == null)
         {
         {
+            throw new ArgumentNullException("execute");
         }
         }
 
 
-        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
-        {
-            if (execute == null)
-            {
-                throw new ArgumentNullException("execute");
-            }
+        this.execute = execute;
+        this.canExecute = canExecute;
+    }
 
 
-            this.execute = execute;
-            this.canExecute = canExecute;
-        }
+    public event EventHandler CanExecuteChanged
+    {
+        add => CommandManager.RequerySuggested += value;
+        remove => CommandManager.RequerySuggested -= value;
+    }
 
 
-        public event EventHandler CanExecuteChanged
-        {
-            add => CommandManager.RequerySuggested += value;
-            remove => CommandManager.RequerySuggested -= value;
-        }
+    public bool CanExecute(T parameter)
+    {
+        return canExecute == null ? true : canExecute(parameter);
+    }
 
 
-        public bool CanExecute(T parameter)
+    public bool CanExecute(object parameter)
+    {
+        if (canExecute == null) return true;
+        if(parameter != null && parameter is not T)
         {
         {
-            return canExecute == null ? true : canExecute(parameter);
+            throw new ArgumentException("Provided parameter type does not match RelayCommand parameter type");
         }
         }
 
 
-        public bool CanExecute(object parameter)
-        {
-            if (canExecute == null) return true;
-            if(parameter != null && parameter is not T)
-            {
-                throw new ArgumentException("Provided parameter type does not match RelayCommand parameter type");
-            }
+        return CanExecute((T)parameter);
+    }
 
 
-            return CanExecute((T)parameter);
-        }
+    public void Execute(T parameter)
+    {
+        execute(parameter);
+    }
 
 
-        public void Execute(T parameter)
+    public void Execute(object parameter)
+    {
+        if (parameter != null && parameter is not T)
         {
         {
-            execute(parameter);
+            throw new ArgumentException("Provided parameter type does not match RelayCommand parameter type");
         }
         }
 
 
-        public void Execute(object parameter)
-        {
-            if (parameter != null && parameter is not T)
-            {
-                throw new ArgumentException("Provided parameter type does not match RelayCommand parameter type");
-            }
-
-            Execute((T)parameter);
-        }
+        Execute((T)parameter);
     }
     }
+}
 
 
-    public class RelayCommand : RelayCommand<object>
-    {
-        public RelayCommand(Action<object> execute, Predicate<object> canExecute) : base(execute, canExecute) { }
+public class RelayCommand : RelayCommand<object>
+{
+    public RelayCommand(Action<object> execute, Predicate<object> canExecute) : base(execute, canExecute) { }
 
 
-        public RelayCommand(Action<object> execute) : base(execute) { }
-    }
-}
+    public RelayCommand(Action<object> execute) : base(execute) { }
+}

+ 26 - 27
src/PixiEditor/Helpers/SelectionHelpers.cs

@@ -5,42 +5,41 @@ using PixiEditor.Models.Enums;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.Undo;
 using PixiEditor.Models.Undo;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+public static class SelectionHelpers
 {
 {
-    public static class SelectionHelpers
+    public static void AddSelectionUndoStep(Document document, IEnumerable<Coordinates> oldPoints, SelectionType mode)
     {
     {
-        public static void AddSelectionUndoStep(Document document, IEnumerable<Coordinates> oldPoints, SelectionType mode)
+        if (mode == SelectionType.New && document.ActiveSelection.SelectedPoints.Count != 0)
         {
         {
-            if (mode == SelectionType.New && document.ActiveSelection.SelectedPoints.Count != 0)
+            if (oldPoints.Any())
             {
             {
-                if (oldPoints.Any())
-                {
-                    // Add empty selection as the old one get's fully deleted first
-                    document.UndoManager.AddUndoChange(
-                        new Change(
-                            SetSelectionProcess, new object[] { document, new List<Coordinates>(oldPoints) },
-                            SetSelectionProcess, new object[] { document, new List<Coordinates>() }));
-                }
-
+                // Add empty selection as the old one get's fully deleted first
                 document.UndoManager.AddUndoChange(
                 document.UndoManager.AddUndoChange(
                     new Change(
                     new Change(
-                        SetSelectionProcess, new object[] { document, new List<Coordinates>() },
-                        SetSelectionProcess, new object[] { document, new List<Coordinates>(document.ActiveSelection.SelectedPoints) }));
+                        SetSelectionProcess, new object[] { document, new List<Coordinates>(oldPoints) },
+                        SetSelectionProcess, new object[] { document, new List<Coordinates>() }));
             }
             }
-            else
-            {
-                document.UndoManager.AddUndoChange(
-                    new Change(
-                        SetSelectionProcess, new object[] { document, oldPoints is null ? new List<Coordinates>() : new List<Coordinates>(oldPoints) },
-                        SetSelectionProcess, new object[] { document, new List<Coordinates>(document.ActiveSelection.SelectedPoints) }));
-            }
-        }
 
 
-        private static void SetSelectionProcess(object[] arguments)
+            document.UndoManager.AddUndoChange(
+                new Change(
+                    SetSelectionProcess, new object[] { document, new List<Coordinates>() },
+                    SetSelectionProcess, new object[] { document, new List<Coordinates>(document.ActiveSelection.SelectedPoints) }));
+        }
+        else
         {
         {
-            Document document = (Document)arguments[0];
-
-            document.ActiveSelection.SetSelection((IEnumerable<Coordinates>)arguments[1], SelectionType.New);
+            document.UndoManager.AddUndoChange(
+                new Change(
+                    SetSelectionProcess, new object[] { document, oldPoints is null ? new List<Coordinates>() : new List<Coordinates>(oldPoints) },
+                    SetSelectionProcess, new object[] { document, new List<Coordinates>(document.ActiveSelection.SelectedPoints) }));
         }
         }
     }
     }
+
+    private static void SetSelectionProcess(object[] arguments)
+    {
+        Document document = (Document)arguments[0];
+
+        document.ActiveSelection.SetSelection((IEnumerable<Coordinates>)arguments[1], SelectionType.New);
+    }
 }
 }

+ 13 - 14
src/PixiEditor/Helpers/SizeCalculator.cs

@@ -1,20 +1,19 @@
 using System;
 using System;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+public static class SizeCalculator
 {
 {
-    public static class SizeCalculator
+    public static System.Drawing.Size CalcAbsoluteFromPercentage(float percentage, System.Drawing.Size currentSize)
     {
     {
-        public static System.Drawing.Size CalcAbsoluteFromPercentage(float percentage, System.Drawing.Size currentSize)
-        {
-            float percFactor = percentage / 100f;
-            float newWidth = currentSize.Width * percFactor;
-            float newHeight = currentSize.Height * percFactor;
-            return new System.Drawing.Size((int)MathF.Round(newWidth), (int)MathF.Round(newHeight));
-        }
+        float percFactor = percentage / 100f;
+        float newWidth = currentSize.Width * percFactor;
+        float newHeight = currentSize.Height * percFactor;
+        return new System.Drawing.Size((int)MathF.Round(newWidth), (int)MathF.Round(newHeight));
+    }
 
 
-        public static int CalcPercentageFromAbsolute(int initAbsoluteSize, int currentAbsoluteSize)
-        {
-            return (int)((float)currentAbsoluteSize * 100) / initAbsoluteSize;
-        }
+    public static int CalcPercentageFromAbsolute(int initAbsoluteSize, int currentAbsoluteSize)
+    {
+        return (int)((float)currentAbsoluteSize * 100) / initAbsoluteSize;
     }
     }
-}
+}

+ 5 - 6
src/PixiEditor/Helpers/StringExtensions.cs

@@ -1,13 +1,12 @@
 using System;
 using System;
 using System.Linq;
 using System.Linq;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+public static class StringExtensions
 {
 {
-    public static class StringExtensions
+    public static string Reverse(this string s)
     {
     {
-        public static string Reverse(this string s)
-        {
-            return new string(s.Reverse<char>().ToArray());
-        }
+        return new string(s.Reverse<char>().ToArray());
     }
     }
 }
 }

+ 73 - 74
src/PixiEditor/Helpers/SupportedFilesHelper.cs

@@ -5,93 +5,92 @@ using System.Collections.Generic;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 
 
-namespace PixiEditor.Helpers
-{
-    public class SupportedFilesHelper
-    {
-        static Dictionary<FileType, FileTypeDialogData> fileTypeDialogsData;
-        static List<FileTypeDialogData> allFileTypeDialogsData;
-        public static string[] AllSupportedExtensions { get; private set; }
-        public static string[] PrimaryExtensions { get; private set; }
+namespace PixiEditor.Helpers;
 
 
-        static SupportedFilesHelper()
-        {
-            fileTypeDialogsData = new Dictionary<FileType, FileTypeDialogData>();
-            allFileTypeDialogsData = new List<FileTypeDialogData>();
+public class SupportedFilesHelper
+{
+    static Dictionary<FileType, FileTypeDialogData> fileTypeDialogsData;
+    static List<FileTypeDialogData> allFileTypeDialogsData;
+    public static string[] AllSupportedExtensions { get; private set; }
+    public static string[] PrimaryExtensions { get; private set; }
 
 
-            var allFormats = Enum.GetValues(typeof(FileType)).Cast<FileType>().ToList();
+    static SupportedFilesHelper()
+    {
+        fileTypeDialogsData = new Dictionary<FileType, FileTypeDialogData>();
+        allFileTypeDialogsData = new List<FileTypeDialogData>();
 
 
-            foreach (var format in allFormats)
-            {
-                var fileTypeDialogData = new FileTypeDialogData(format);
-                if (format != FileType.Unset)
-                    fileTypeDialogsData[format] = fileTypeDialogData;
+        var allFormats = Enum.GetValues(typeof(FileType)).Cast<FileType>().ToList();
 
 
-                allFileTypeDialogsData.Add(fileTypeDialogData);
-            }
+        foreach (var format in allFormats)
+        {
+            var fileTypeDialogData = new FileTypeDialogData(format);
+            if (format != FileType.Unset)
+                fileTypeDialogsData[format] = fileTypeDialogData;
 
 
-            AllSupportedExtensions = fileTypeDialogsData.SelectMany(i => i.Value.Extensions).ToArray();
-            PrimaryExtensions = fileTypeDialogsData.Select(i => i.Value.PrimaryExtension).ToArray();
+            allFileTypeDialogsData.Add(fileTypeDialogData);
         }
         }
 
 
-        public static FileTypeDialogData GetFileTypeDialogData(FileType type)
-        {
-            return allFileTypeDialogsData.Where(i => i.FileType == type).Single();
-        }
+        AllSupportedExtensions = fileTypeDialogsData.SelectMany(i => i.Value.Extensions).ToArray();
+        PrimaryExtensions = fileTypeDialogsData.Select(i => i.Value.PrimaryExtension).ToArray();
+    }
 
 
-        public static bool IsSupportedFile(string path)
-        {
-            var ext = Path.GetExtension(path.ToLower());
-            return IsExtensionSupported(ext);
-        }
+    public static FileTypeDialogData GetFileTypeDialogData(FileType type)
+    {
+        return allFileTypeDialogsData.Where(i => i.FileType == type).Single();
+    }
 
 
-        public static bool IsExtensionSupported(string fileExtension)
-        {
-            return AllSupportedExtensions.Contains(fileExtension);
-        }
-        public static FileType ParseImageFormat(string extension)
-        {
-            var allExts = fileTypeDialogsData.Values.ToList();
-            var fileData = allExts.Where(i => i.Extensions.Contains(extension)).SingleOrDefault();
-            if (fileData != null)
-                return fileData.FileType;
-            return FileType.Unset;
-        }
+    public static bool IsSupportedFile(string path)
+    {
+        var ext = Path.GetExtension(path.ToLower());
+        return IsExtensionSupported(ext);
+    }
 
 
-        public static List<FileTypeDialogData> GetAllSupportedFileTypes(bool includePixi)
-        {
-            var allExts = fileTypeDialogsData.Values.ToList();
-            if (!includePixi)
-                allExts.RemoveAll(item => item.FileType == FileType.Pixi);
-            return allExts;
-        }
+    public static bool IsExtensionSupported(string fileExtension)
+    {
+        return AllSupportedExtensions.Contains(fileExtension);
+    }
+    public static FileType ParseImageFormat(string extension)
+    {
+        var allExts = fileTypeDialogsData.Values.ToList();
+        var fileData = allExts.Where(i => i.Extensions.Contains(extension)).SingleOrDefault();
+        if (fileData != null)
+            return fileData.FileType;
+        return FileType.Unset;
+    }
 
 
-        public static string BuildSaveFilter(bool includePixi)
-        {
-            var allSupportedExtensions = GetAllSupportedFileTypes(includePixi);
-            var filter = string.Join("|", allSupportedExtensions.Select(i => i.SaveFilter));
+    public static List<FileTypeDialogData> GetAllSupportedFileTypes(bool includePixi)
+    {
+        var allExts = fileTypeDialogsData.Values.ToList();
+        if (!includePixi)
+            allExts.RemoveAll(item => item.FileType == FileType.Pixi);
+        return allExts;
+    }
 
 
-            return filter;
-        }
+    public static string BuildSaveFilter(bool includePixi)
+    {
+        var allSupportedExtensions = GetAllSupportedFileTypes(includePixi);
+        var filter = string.Join("|", allSupportedExtensions.Select(i => i.SaveFilter));
 
 
-        public static FileType GetSaveFileTypeFromFilterIndex(bool includePixi, int filterIndex)
-        {
-            var allSupportedExtensions = GetAllSupportedFileTypes(includePixi);
-            //filter index starts at 1 for some reason
-            int index = filterIndex - 1;
-            if (allSupportedExtensions.Count <= index)
-                return FileType.Unset;
-            return allSupportedExtensions[index].FileType;
-        }
+        return filter;
+    }
 
 
-        public static string BuildOpenFilter()
-        {
-            var any = new FileTypeDialogDataSet(FileTypeDialogDataSet.SetKind.Any).GetFormattedTypes();
-            var pixi = new FileTypeDialogDataSet(FileTypeDialogDataSet.SetKind.Pixi).GetFormattedTypes();
-            var images = new FileTypeDialogDataSet(FileTypeDialogDataSet.SetKind.Images).GetFormattedTypes();
+    public static FileType GetSaveFileTypeFromFilterIndex(bool includePixi, int filterIndex)
+    {
+        var allSupportedExtensions = GetAllSupportedFileTypes(includePixi);
+        //filter index starts at 1 for some reason
+        int index = filterIndex - 1;
+        if (allSupportedExtensions.Count <= index)
+            return FileType.Unset;
+        return allSupportedExtensions[index].FileType;
+    }
 
 
-            var filter = any + "|" + pixi + "|" + images;
-            return filter;
-        }
+    public static string BuildOpenFilter()
+    {
+        var any = new FileTypeDialogDataSet(FileTypeDialogDataSet.SetKind.Any).GetFormattedTypes();
+        var pixi = new FileTypeDialogDataSet(FileTypeDialogDataSet.SetKind.Pixi).GetFormattedTypes();
+        var images = new FileTypeDialogDataSet(FileTypeDialogDataSet.SetKind.Images).GetFormattedTypes();
+
+        var filter = any + "|" + pixi + "|" + images;
+        return filter;
     }
     }
-}
+}

+ 12 - 13
src/PixiEditor/Helpers/UI/DocumentsTemplateSelector.cs

@@ -4,25 +4,24 @@ using AvalonDock.Layout;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.ViewModels;
 using PixiEditor.ViewModels;
 
 
-namespace PixiEditor.Helpers.UI
+namespace PixiEditor.Helpers.UI;
+
+public class DocumentsTemplateSelector : DataTemplateSelector
 {
 {
-    public class DocumentsTemplateSelector : DataTemplateSelector
+    public DocumentsTemplateSelector()
     {
     {
-        public DocumentsTemplateSelector()
-        {
 
 
-        }
+    }
 
 
-        public DataTemplate DocumentsViewTemplate { get; set; }
+    public DataTemplate DocumentsViewTemplate { get; set; }
 
 
-        public override DataTemplate SelectTemplate(object item, DependencyObject container)
+    public override DataTemplate SelectTemplate(object item, DependencyObject container)
+    {
+        if (item is Document)
         {
         {
-            if (item is Document)
-            {
-                return DocumentsViewTemplate;
-            }
-
-            return base.SelectTemplate(item, container);
+            return DocumentsViewTemplate;
         }
         }
+
+        return base.SelectTemplate(item, container);
     }
     }
 }
 }

+ 9 - 10
src/PixiEditor/Helpers/UI/PanelsStyleSelector.cs

@@ -2,19 +2,18 @@
 using System.Windows.Controls;
 using System.Windows.Controls;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders;
 
 
-namespace PixiEditor.Helpers.UI
+namespace PixiEditor.Helpers.UI;
+
+public class PanelsStyleSelector : StyleSelector
 {
 {
-    public class PanelsStyleSelector : StyleSelector
-    {
-        public Style DocumentTabStyle { get; set; }
+    public Style DocumentTabStyle { get; set; }
 
 
-        public override Style SelectStyle(object item, DependencyObject container)
+    public override Style SelectStyle(object item, DependencyObject container)
+    {
+        if (item is Document)
         {
         {
-            if (item is Document)
-            {
-                return DocumentTabStyle;
-            }
-            return base.SelectStyle(item, container);
+            return DocumentTabStyle;
         }
         }
+        return base.SelectStyle(item, container);
     }
     }
 }
 }

+ 29 - 30
src/PixiEditor/Helpers/UI/ReversedOrderStackPanel.cs

@@ -3,43 +3,42 @@ using System.Linq;
 using System.Windows;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Controls;
 
 
-namespace PixiEditor.Helpers.UI
+namespace PixiEditor.Helpers.UI;
+
+public class ReversedOrderStackPanel : StackPanel
 {
 {
-    public class ReversedOrderStackPanel : StackPanel
+    protected override Size ArrangeOverride(Size arrangeSize)
     {
     {
-        protected override Size ArrangeOverride(Size arrangeSize)
-        {
-            bool fHorizontal = Orientation == Orientation.Horizontal;
-            Rect rcChild = new Rect(arrangeSize);
-            double previousChildSize = 0.0;
+        bool fHorizontal = Orientation == Orientation.Horizontal;
+        Rect rcChild = new Rect(arrangeSize);
+        double previousChildSize = 0.0;
 
 
-            System.Collections.Generic.IEnumerable<UIElement> children = InternalChildren.Cast<UIElement>().Reverse();
-            foreach (UIElement child in children)
+        System.Collections.Generic.IEnumerable<UIElement> children = InternalChildren.Cast<UIElement>().Reverse();
+        foreach (UIElement child in children)
+        {
+            if (child == null)
             {
             {
-                if (child == null)
-                {
-                    continue;
-                }
-
-                if (fHorizontal)
-                {
-                    rcChild.X += previousChildSize;
-                    previousChildSize = child.DesiredSize.Width;
-                    rcChild.Width = previousChildSize;
-                    rcChild.Height = Math.Max(arrangeSize.Height, child.DesiredSize.Height);
-                }
-                else
-                {
-                    rcChild.Y += previousChildSize;
-                    previousChildSize = child.DesiredSize.Height;
-                    rcChild.Height = previousChildSize;
-                    rcChild.Width = Math.Max(arrangeSize.Width, child.DesiredSize.Width);
-                }
+                continue;
+            }
 
 
-                child.Arrange(rcChild);
+            if (fHorizontal)
+            {
+                rcChild.X += previousChildSize;
+                previousChildSize = child.DesiredSize.Width;
+                rcChild.Width = previousChildSize;
+                rcChild.Height = Math.Max(arrangeSize.Height, child.DesiredSize.Height);
+            }
+            else
+            {
+                rcChild.Y += previousChildSize;
+                previousChildSize = child.DesiredSize.Height;
+                rcChild.Height = previousChildSize;
+                rcChild.Width = Math.Max(arrangeSize.Width, child.DesiredSize.Width);
             }
             }
 
 
-            return arrangeSize;
+            child.Arrange(rcChild);
         }
         }
+
+        return arrangeSize;
     }
     }
 }
 }

+ 13 - 14
src/PixiEditor/Helpers/UI/TreeViewItemHelper.cs

@@ -1,21 +1,20 @@
 using System.Windows;
 using System.Windows;
 
 
-namespace PixiEditor.Helpers.UI
+namespace PixiEditor.Helpers.UI;
+
+public static class TreeViewItemHelper
 {
 {
-    public static class TreeViewItemHelper
+    public static GridLength GetIndent(DependencyObject obj)
     {
     {
-        public static GridLength GetIndent(DependencyObject obj)
-        {
-            return (GridLength)obj.GetValue(IndentProperty);
-        }
+        return (GridLength)obj.GetValue(IndentProperty);
+    }
 
 
-        public static void SetIndent(DependencyObject obj, GridLength value)
-        {
-            obj.SetValue(IndentProperty, value);
-        }
+    public static void SetIndent(DependencyObject obj, GridLength value)
+    {
+        obj.SetValue(IndentProperty, value);
+    }
 
 
 
 
-        public static readonly DependencyProperty IndentProperty =
-            DependencyProperty.RegisterAttached("Indent", typeof(GridLength), typeof(TreeViewItemHelper), new PropertyMetadata(new GridLength(0)));
-    }
-}
+    public static readonly DependencyProperty IndentProperty =
+        DependencyProperty.RegisterAttached("Indent", typeof(GridLength), typeof(TreeViewItemHelper), new PropertyMetadata(new GridLength(0)));
+}

+ 28 - 29
src/PixiEditor/Helpers/VersionHelpers.cs

@@ -3,46 +3,45 @@ using System.Diagnostics;
 using System.Reflection;
 using System.Reflection;
 using System.Text;
 using System.Text;
 
 
-namespace PixiEditor.Helpers
-{
-    public static class VersionHelpers
-    {
-        public static Version GetCurrentAssemblyVersion() => Assembly.GetExecutingAssembly().GetName().Version;
-
-        public static string GetCurrentAssemblyVersion(Func<Version, string> toString) => toString(GetCurrentAssemblyVersion());
+namespace PixiEditor.Helpers;
 
 
-        public static string GetCurrentAssemblyVersionString()
-        {
-            StringBuilder builder = new(GetCurrentAssemblyVersion().ToString());
+public static class VersionHelpers
+{
+    public static Version GetCurrentAssemblyVersion() => Assembly.GetExecutingAssembly().GetName().Version;
 
 
-            bool isDone = false;
+    public static string GetCurrentAssemblyVersion(Func<Version, string> toString) => toString(GetCurrentAssemblyVersion());
 
 
-            AppendDevBuild(builder, ref isDone);
+    public static string GetCurrentAssemblyVersionString()
+    {
+        StringBuilder builder = new(GetCurrentAssemblyVersion().ToString());
 
 
-            if (isDone)
-            {
-                return builder.ToString();
-            }
+        bool isDone = false;
 
 
-            AppendDebugBuild(builder, ref isDone);
+        AppendDevBuild(builder, ref isDone);
 
 
+        if (isDone)
+        {
             return builder.ToString();
             return builder.ToString();
         }
         }
 
 
-        [Conditional("DEV_RELEASE")]
-        private static void AppendDevBuild(StringBuilder builder, ref bool done)
-        {
-            done = true;
+        AppendDebugBuild(builder, ref isDone);
 
 
-            builder.Append(" Dev Build");
-        }
+        return builder.ToString();
+    }
 
 
-        [Conditional("DEBUG")]
-        private static void AppendDebugBuild(StringBuilder builder, ref bool done)
-        {
-            done = true;
+    [Conditional("DEV_RELEASE")]
+    private static void AppendDevBuild(StringBuilder builder, ref bool done)
+    {
+        done = true;
 
 
-            builder.Append(" Debug Build");
-        }
+        builder.Append(" Dev Build");
+    }
+
+    [Conditional("DEBUG")]
+    private static void AppendDebugBuild(StringBuilder builder, ref bool done)
+    {
+        done = true;
+
+        builder.Append(" Debug Build");
     }
     }
 }
 }

+ 75 - 76
src/PixiEditor/Helpers/WindowSizeHelper.cs

@@ -1,101 +1,100 @@
 using System;
 using System;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
 
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers;
+
+static class WindowSizeHelper
 {
 {
-    static class WindowSizeHelper
+    public static IntPtr SetMaxSizeHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
     {
     {
-        public static IntPtr SetMaxSizeHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
+        // All windows messages (msg) can be found here
+        // https://docs.microsoft.com/de-de/windows/win32/winmsg/window-notifications
+        if (msg == WM_GETMINMAXINFO)
         {
         {
-            // All windows messages (msg) can be found here
-            // https://docs.microsoft.com/de-de/windows/win32/winmsg/window-notifications
-            if (msg == WM_GETMINMAXINFO)
+            // We need to tell the system what our size should be when maximized. Otherwise it will
+            // cover the whole screen, including the task bar.
+            MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
+
+            // Adjust the maximized size and position to fit the work area of the correct monitor
+            IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+
+            if (monitor != IntPtr.Zero)
             {
             {
-                // We need to tell the system what our size should be when maximized. Otherwise it will
-                // cover the whole screen, including the task bar.
-                MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
-
-                // Adjust the maximized size and position to fit the work area of the correct monitor
-                IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
-
-                if (monitor != IntPtr.Zero)
-                {
-                    MONITORINFO monitorInfo = default;
-                    monitorInfo.cbSize = Marshal.SizeOf(typeof(MONITORINFO));
-                    GetMonitorInfo(monitor, ref monitorInfo);
-                    RECT rcWorkArea = monitorInfo.rcWork;
-                    RECT rcMonitorArea = monitorInfo.rcMonitor;
-                    mmi.ptMaxPosition.X = Math.Abs(rcWorkArea.Left - rcMonitorArea.Left);
-                    mmi.ptMaxPosition.Y = Math.Abs(rcWorkArea.Top - rcMonitorArea.Top);
-                    mmi.ptMaxSize.X = Math.Abs(rcWorkArea.Right - rcWorkArea.Left);
-                    mmi.ptMaxSize.Y = Math.Abs(rcWorkArea.Bottom - rcWorkArea.Top);
-                }
-
-                Marshal.StructureToPtr(mmi, lParam, true);
+                MONITORINFO monitorInfo = default;
+                monitorInfo.cbSize = Marshal.SizeOf(typeof(MONITORINFO));
+                GetMonitorInfo(monitor, ref monitorInfo);
+                RECT rcWorkArea = monitorInfo.rcWork;
+                RECT rcMonitorArea = monitorInfo.rcMonitor;
+                mmi.ptMaxPosition.X = Math.Abs(rcWorkArea.Left - rcMonitorArea.Left);
+                mmi.ptMaxPosition.Y = Math.Abs(rcWorkArea.Top - rcMonitorArea.Top);
+                mmi.ptMaxSize.X = Math.Abs(rcWorkArea.Right - rcWorkArea.Left);
+                mmi.ptMaxSize.Y = Math.Abs(rcWorkArea.Bottom - rcWorkArea.Top);
             }
             }
 
 
-            return IntPtr.Zero;
+            Marshal.StructureToPtr(mmi, lParam, true);
         }
         }
 
 
-        private const int WM_GETMINMAXINFO = 0x0024;
+        return IntPtr.Zero;
+    }
 
 
-        private const uint MONITOR_DEFAULTTONEAREST = 0x00000002;
+    private const int WM_GETMINMAXINFO = 0x0024;
 
 
-        [DllImport("user32.dll")]
-        private static extern IntPtr MonitorFromWindow(IntPtr handle, uint flags);
+    private const uint MONITOR_DEFAULTTONEAREST = 0x00000002;
 
 
-        [DllImport("user32.dll")]
-        private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
+    [DllImport("user32.dll")]
+    private static extern IntPtr MonitorFromWindow(IntPtr handle, uint flags);
 
 
-        [Serializable]
-        [StructLayout(LayoutKind.Sequential)]
-        private struct RECT
-        {
-            public int Left;
-            public int Top;
-            public int Right;
-            public int Bottom;
+    [DllImport("user32.dll")]
+    private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
 
 
-            public RECT(int left, int top, int right, int bottom)
-            {
-                this.Left = left;
-                this.Top = top;
-                this.Right = right;
-                this.Bottom = bottom;
-            }
-        }
+    [Serializable]
+    [StructLayout(LayoutKind.Sequential)]
+    private struct RECT
+    {
+        public int Left;
+        public int Top;
+        public int Right;
+        public int Bottom;
 
 
-        [StructLayout(LayoutKind.Sequential)]
-        private struct MONITORINFO
+        public RECT(int left, int top, int right, int bottom)
         {
         {
-            public int cbSize;
-            public RECT rcMonitor;
-            public RECT rcWork;
-            public uint dwFlags;
+            this.Left = left;
+            this.Top = top;
+            this.Right = right;
+            this.Bottom = bottom;
         }
         }
+    }
 
 
-        [Serializable]
-        [StructLayout(LayoutKind.Sequential)]
-        private struct POINT
-        {
-            public int X;
-            public int Y;
+    [StructLayout(LayoutKind.Sequential)]
+    private struct MONITORINFO
+    {
+        public int cbSize;
+        public RECT rcMonitor;
+        public RECT rcWork;
+        public uint dwFlags;
+    }
 
 
-            public POINT(int x, int y)
-            {
-                this.X = x;
-                this.Y = y;
-            }
-        }
+    [Serializable]
+    [StructLayout(LayoutKind.Sequential)]
+    private struct POINT
+    {
+        public int X;
+        public int Y;
 
 
-        [StructLayout(LayoutKind.Sequential)]
-        private struct MINMAXINFO
+        public POINT(int x, int y)
         {
         {
-            public POINT ptReserved;
-            public POINT ptMaxSize;
-            public POINT ptMaxPosition;
-            public POINT ptMinTrackSize;
-            public POINT ptMaxTrackSize;
+            this.X = x;
+            this.Y = y;
         }
         }
     }
     }
-}
+
+    [StructLayout(LayoutKind.Sequential)]
+    private struct MINMAXINFO
+    {
+        public POINT ptReserved;
+        public POINT ptMaxSize;
+        public POINT ptMaxPosition;
+        public POINT ptMinTrackSize;
+        public POINT ptMaxTrackSize;
+    }
+}

+ 119 - 120
src/PixiEditor/Models/Colors/ExColor.cs

@@ -1,129 +1,79 @@
 using SkiaSharp;
 using SkiaSharp;
 using System;
 using System;
 
 
-namespace PixiEditor.Models.Colors
+namespace PixiEditor.Models.Colors;
+
+public static class ExColor
 {
 {
-    public static class ExColor
+    /// <summary>
+    ///     Creates color with corrected brightness.
+    /// </summary>
+    /// <param name="color">Color to correct.</param>
+    /// <param name="correctionFactor">
+    ///     The brightness correction factor. Must be between -1 and 1.
+    ///     Negative values produce darker colors.
+    /// </param>
+    /// <returns>
+    ///     Corrected <see cref="SKColor" /> structure.
+    /// </returns>
+    public static SKColor ChangeColorBrightness(SKColor color, float correctionFactor)
     {
     {
-        /// <summary>
-        ///     Creates color with corrected brightness.
-        /// </summary>
-        /// <param name="color">Color to correct.</param>
-        /// <param name="correctionFactor">
-        ///     The brightness correction factor. Must be between -1 and 1.
-        ///     Negative values produce darker colors.
-        /// </param>
-        /// <returns>
-        ///     Corrected <see cref="SKColor" /> structure.
-        /// </returns>
-        public static SKColor ChangeColorBrightness(SKColor color, float correctionFactor)
-        {
-            Tuple<int, float, float> hsl = RgbToHsl(color.Red, color.Green, color.Blue);
-            int h = hsl.Item1;
-            float s = hsl.Item2;
-            float l = hsl.Item3;
+        Tuple<int, float, float> hsl = RgbToHsl(color.Red, color.Green, color.Blue);
+        int h = hsl.Item1;
+        float s = hsl.Item2;
+        float l = hsl.Item3;
 
 
-            l = Math.Clamp(l + correctionFactor, 0, 100);
-            SKColor rgb = HslToRgb(h, s, l);
-
-            return new SKColor(rgb.Red, rgb.Green, rgb.Blue, color.Alpha);
-        }
+        l = Math.Clamp(l + correctionFactor, 0, 100);
+        SKColor rgb = HslToRgb(h, s, l);
 
 
-        /// <summary>
-        ///     Converts RGB to HSL.
-        /// </summary>
-        /// <param name="r">Red value.</param>
-        /// <param name="g">Green value.</param>
-        /// <param name="b">Blue value.</param>
-        /// <returns>Tuple with 3 values in order: h, s, l0.</returns>
-        public static Tuple<int, float, float> RgbToHsl(int r, int g, int b)
-        {
-            int h;
-            float s, l;
-            float dR = r / 255.0f;
-            float dG = g / 255.0f;
-            float dB = b / 255.0f;
+        return new SKColor(rgb.Red, rgb.Green, rgb.Blue, color.Alpha);
+    }
 
 
-            float min = Math.Min(Math.Min(dR, dG), dB);
-            float max = Math.Max(Math.Max(dR, dG), dB);
-            float delta = max - min;
+    /// <summary>
+    ///     Converts RGB to HSL.
+    /// </summary>
+    /// <param name="r">Red value.</param>
+    /// <param name="g">Green value.</param>
+    /// <param name="b">Blue value.</param>
+    /// <returns>Tuple with 3 values in order: h, s, l0.</returns>
+    public static Tuple<int, float, float> RgbToHsl(int r, int g, int b)
+    {
+        int h;
+        float s, l;
+        float dR = r / 255.0f;
+        float dG = g / 255.0f;
+        float dB = b / 255.0f;
 
 
-            l = (max + min) / 2;
+        float min = Math.Min(Math.Min(dR, dG), dB);
+        float max = Math.Max(Math.Max(dR, dG), dB);
+        float delta = max - min;
 
 
-            if (delta == 0)
-            {
-                h = 0;
-                s = 0.0f;
-            }
-            else
-            {
-                s = l <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
-
-                float hue;
-
-                if (dR == max)
-                {
-                    hue = (dG - dB) / 6 / delta;
-                }
-                else if (dG == max)
-                {
-                    hue = (1.0f / 3) + ((dB - dR) / 6 / delta);
-                }
-                else
-                {
-                    hue = (2.0f / 3) + ((dR - dG) / 6 / delta);
-                }
-
-                if (hue < 0)
-                {
-                    hue += 1;
-                }
-
-                if (hue > 1)
-                {
-                    hue -= 1;
-                }
-
-                h = (int)(hue * 360);
-            }
+        l = (max + min) / 2;
 
 
-            return new Tuple<int, float, float>(h, s * 100, l * 100);
+        if (delta == 0)
+        {
+            h = 0;
+            s = 0.0f;
         }
         }
-
-        /// <summary>
-        ///     Converts HSL color format to RGB.
-        /// </summary>
-        /// <returns>RGB Color.</returns>
-        public static SKColor HslToRgb(int h, float s, float l)
+        else
         {
         {
-            s /= 100;
-            l /= 100;
-            byte r = 0;
-            byte g = 0;
-            byte b = 0;
+            s = l <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
 
 
-            if (s == 0)
+            float hue;
+
+            if (dR == max)
+            {
+                hue = (dG - dB) / 6 / delta;
+            }
+            else if (dG == max)
             {
             {
-                r = g = b = (byte)(l * 255);
+                hue = (1.0f / 3) + ((dB - dR) / 6 / delta);
             }
             }
             else
             else
             {
             {
-                float v1, v2;
-                float hue = (float)h / 360;
-
-                v2 = l < 0.5 ? l * (1 + s) : l + s - (l * s);
-                v1 = (2 * l) - v2;
-
-                r = (byte)(255 * HueToRgb(v1, v2, hue + (1.0f / 3)));
-                g = (byte)(255 * HueToRgb(v1, v2, hue));
-                b = (byte)(255 * HueToRgb(v1, v2, hue - (1.0f / 3)));
+                hue = (2.0f / 3) + ((dR - dG) / 6 / delta);
             }
             }
 
 
-            return new SKColor(r, g, b);
-        }
-
-        private static float HueToRgb(float v1, float v2, float hue)
-        {
             if (hue < 0)
             if (hue < 0)
             {
             {
                 hue += 1;
                 hue += 1;
@@ -134,22 +84,71 @@ namespace PixiEditor.Models.Colors
                 hue -= 1;
                 hue -= 1;
             }
             }
 
 
-            if (6 * hue < 1)
-            {
-                return v1 + ((v2 - v1) * 6 * hue);
-            }
+            h = (int)(hue * 360);
+        }
 
 
-            if (2 * hue < 1)
-            {
-                return v2;
-            }
+        return new Tuple<int, float, float>(h, s * 100, l * 100);
+    }
 
 
-            if (3 * hue < 2)
-            {
-                return v1 + ((v2 - v1) * ((2.0f / 3) - hue) * 6);
-            }
+    /// <summary>
+    ///     Converts HSL color format to RGB.
+    /// </summary>
+    /// <returns>RGB Color.</returns>
+    public static SKColor HslToRgb(int h, float s, float l)
+    {
+        s /= 100;
+        l /= 100;
+        byte r = 0;
+        byte g = 0;
+        byte b = 0;
+
+        if (s == 0)
+        {
+            r = g = b = (byte)(l * 255);
+        }
+        else
+        {
+            float v1, v2;
+            float hue = (float)h / 360;
 
 
-            return v1;
+            v2 = l < 0.5 ? l * (1 + s) : l + s - (l * s);
+            v1 = (2 * l) - v2;
+
+            r = (byte)(255 * HueToRgb(v1, v2, hue + (1.0f / 3)));
+            g = (byte)(255 * HueToRgb(v1, v2, hue));
+            b = (byte)(255 * HueToRgb(v1, v2, hue - (1.0f / 3)));
+        }
+
+        return new SKColor(r, g, b);
+    }
+
+    private static float HueToRgb(float v1, float v2, float hue)
+    {
+        if (hue < 0)
+        {
+            hue += 1;
         }
         }
+
+        if (hue > 1)
+        {
+            hue -= 1;
+        }
+
+        if (6 * hue < 1)
+        {
+            return v1 + ((v2 - v1) * 6 * hue);
+        }
+
+        if (2 * hue < 1)
+        {
+            return v2;
+        }
+
+        if (3 * hue < 2)
+        {
+            return v1 + ((v2 - v1) * ((2.0f / 3) - hue) * 6);
+        }
+
+        return v1;
     }
     }
-}
+}

+ 10 - 11
src/PixiEditor/Models/Commands/Attributes/Commands/DebugAttribute.cs

@@ -1,17 +1,16 @@
-namespace PixiEditor.Models.Commands.Attributes
+namespace PixiEditor.Models.Commands.Attributes;
+
+public partial class Command
 {
 {
-    public partial class Command
+    public class DebugAttribute : BasicAttribute
     {
     {
-        public class DebugAttribute : BasicAttribute
+        public DebugAttribute(string internalName, string displayName, string description) : base($"#DEBUG#{internalName}", displayName, description)
         {
         {
-            public DebugAttribute(string internalName, string displayName, string description) : base($"#DEBUG#{internalName}", displayName, description)
-            {
-            }
+        }
 
 
-            public DebugAttribute(string internalName, object parameter, string displayName, string description)
-                : base($"#DEBUG#{internalName}", parameter, displayName, description)
-            {
-            }
+        public DebugAttribute(string internalName, object parameter, string displayName, string description)
+            : base($"#DEBUG#{internalName}", parameter, displayName, description)
+        {
         }
         }
     }
     }
-}
+}

+ 15 - 16
src/PixiEditor/Models/Commands/Attributes/Commands/GroupAttribute.cs

@@ -1,22 +1,21 @@
-namespace PixiEditor.Models.Commands.Attributes
+namespace PixiEditor.Models.Commands.Attributes;
+
+public partial class Command
 {
 {
-    public partial class Command
+    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+    public class GroupAttribute : Attribute
     {
     {
-        [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
-        public class GroupAttribute : Attribute
-        {
-            public string InternalName { get; }
+        public string InternalName { get; }
 
 
-            public string DisplayName { get; }
+        public string DisplayName { get; }
 
 
-            /// <summary>
-            /// Groups all commands that start with the name <paramref name="internalName"/>
-            /// </summary>
-            public GroupAttribute(string internalName, string displayName)
-            {
-                InternalName = internalName;
-                DisplayName = displayName;
-            }
+        /// <summary>
+        /// Groups all commands that start with the name <paramref name="internalName"/>
+        /// </summary>
+        public GroupAttribute(string internalName, string displayName)
+        {
+            InternalName = internalName;
+            DisplayName = displayName;
         }
         }
     }
     }
-}
+}

+ 17 - 18
src/PixiEditor/Models/Commands/Attributes/Commands/InternalAttribute.cs

@@ -1,27 +1,26 @@
-namespace PixiEditor.Models.Commands.Attributes
+namespace PixiEditor.Models.Commands.Attributes;
+
+public partial class Command
 {
 {
-    public partial class Command
+    /// <summary>
+    /// A command that is not shown in the UI
+    /// </summary>
+    public class InternalAttribute : BasicAttribute
     {
     {
         /// <summary>
         /// <summary>
         /// A command that is not shown in the UI
         /// A command that is not shown in the UI
         /// </summary>
         /// </summary>
-        public class InternalAttribute : BasicAttribute
+        public InternalAttribute(string name)
+            : base(name, string.Empty, string.Empty)
         {
         {
-            /// <summary>
-            /// A command that is not shown in the UI
-            /// </summary>
-            public InternalAttribute(string name)
-                : base(name, string.Empty, string.Empty)
-            {
-            }
+        }
 
 
-            /// <summary>
-            /// A command that is not shown in the UI
-            /// </summary>
-            public InternalAttribute(string name, object parameter)
-                : base(name, parameter, string.Empty, string.Empty)
-            {
-            }
+        /// <summary>
+        /// A command that is not shown in the UI
+        /// </summary>
+        public InternalAttribute(string name, object parameter)
+            : base(name, parameter, string.Empty, string.Empty)
+        {
         }
         }
     }
     }
-}
+}

+ 57 - 58
src/PixiEditor/Models/Commands/CommandCollection.cs

@@ -4,81 +4,80 @@ using System.Diagnostics;
 using System.Windows.Input;
 using System.Windows.Input;
 using OneOf.Types;
 using OneOf.Types;
 
 
-namespace PixiEditor.Models.Commands
+namespace PixiEditor.Models.Commands;
+
+[DebuggerDisplay("Count = {Count}")]
+public class CommandCollection : ICollection<Command>
 {
 {
-    [DebuggerDisplay("Count = {Count}")]
-    public class CommandCollection : ICollection<Command>
-    {
-        private readonly Dictionary<string, Command> _commandInternalNames;
-        private readonly OneToManyDictionary<KeyCombination, Command> _commandShortcuts;
+    private readonly Dictionary<string, Command> _commandInternalNames;
+    private readonly OneToManyDictionary<KeyCombination, Command> _commandShortcuts;
 
 
-        public int Count => _commandInternalNames.Count;
+    public int Count => _commandInternalNames.Count;
 
 
-        public bool IsReadOnly => false;
+    public bool IsReadOnly => false;
 
 
-        public Command this[string name] => _commandInternalNames[name];
+    public Command this[string name] => _commandInternalNames[name];
 
 
-        public IEnumerable<Command> this[KeyCombination shortcut] => _commandShortcuts[shortcut];
+    public IEnumerable<Command> this[KeyCombination shortcut] => _commandShortcuts[shortcut];
 
 
-        public CommandCollection()
-        {
-            _commandInternalNames = new();
-            _commandShortcuts = new();
-        }
+    public CommandCollection()
+    {
+        _commandInternalNames = new();
+        _commandShortcuts = new();
+    }
 
 
-        public void Add(Command item)
-        {
-            _commandInternalNames.Add(item.InternalName, item);
-            _commandShortcuts.Add(item.Shortcut, item);
-        }
+    public void Add(Command item)
+    {
+        _commandInternalNames.Add(item.InternalName, item);
+        _commandShortcuts.Add(item.Shortcut, item);
+    }
 
 
-        public void Clear()
-        {
-            _commandInternalNames.Clear();
-            _commandShortcuts.Clear();
-        }
+    public void Clear()
+    {
+        _commandInternalNames.Clear();
+        _commandShortcuts.Clear();
+    }
 
 
-        public void ClearShortcuts() => _commandShortcuts.Clear();
+    public void ClearShortcuts() => _commandShortcuts.Clear();
 
 
-        public bool Contains(Command item) => _commandInternalNames.ContainsKey(item.InternalName);
+    public bool Contains(Command item) => _commandInternalNames.ContainsKey(item.InternalName);
 
 
-        public void CopyTo(Command[] array, int arrayIndex) => _commandInternalNames.Values.CopyTo(array, arrayIndex);
+    public void CopyTo(Command[] array, int arrayIndex) => _commandInternalNames.Values.CopyTo(array, arrayIndex);
 
 
-        public IEnumerator<Command> GetEnumerator() => _commandInternalNames.Values.GetEnumerator();
+    public IEnumerator<Command> GetEnumerator() => _commandInternalNames.Values.GetEnumerator();
 
 
-        public bool Remove(Command item)
-        {
-            bool anyRemoved = false;
+    public bool Remove(Command item)
+    {
+        bool anyRemoved = false;
 
 
-            anyRemoved |= _commandInternalNames.Remove(item.InternalName);
-            anyRemoved |= _commandShortcuts.Remove(item);
+        anyRemoved |= _commandInternalNames.Remove(item.InternalName);
+        anyRemoved |= _commandShortcuts.Remove(item);
 
 
-            return anyRemoved;
-        }
+        return anyRemoved;
+    }
 
 
-        public void AddShortcut(Command command, KeyCombination shortcut)
-        {
-            _commandShortcuts.Remove(KeyCombination.None, command);
-            _commandShortcuts.Add(shortcut, command);
-        }
+    public void AddShortcut(Command command, KeyCombination shortcut)
+    {
+        _commandShortcuts.Remove(KeyCombination.None, command);
+        _commandShortcuts.Add(shortcut, command);
+    }
 
 
-        public void RemoveShortcut(Command command, KeyCombination shortcut)
-        {
-            _commandShortcuts.Remove(shortcut, command);
-            _commandShortcuts.Add(KeyCombination.None, command);
-        }
+    public void RemoveShortcut(Command command, KeyCombination shortcut)
+    {
+        _commandShortcuts.Remove(shortcut, command);
+        _commandShortcuts.Add(KeyCombination.None, command);
+    }
 
 
-        public void ClearShortcut(KeyCombination shortcut)
-        {
-            if (shortcut is { Key: Key.None, Modifiers: ModifierKeys.None })
-                return;
-            _commandShortcuts.AddRange(KeyCombination.None, _commandShortcuts[shortcut]);
-            _commandShortcuts.Clear(shortcut);      
-        }
+    public void ClearShortcut(KeyCombination shortcut)
+    {
+        if (shortcut is { Key: Key.None, Modifiers: ModifierKeys.None })
+            return;
+        _commandShortcuts.AddRange(KeyCombination.None, _commandShortcuts[shortcut]);
+        _commandShortcuts.Clear(shortcut);      
+    }
 
 
-        public IEnumerable<KeyValuePair<KeyCombination, IEnumerable<Command>>> GetShortcuts() =>
-            _commandShortcuts;
+    public IEnumerable<KeyValuePair<KeyCombination, IEnumerable<Command>>> GetShortcuts() =>
+        _commandShortcuts;
 
 
-        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-    }
-}
+    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+}

+ 263 - 264
src/PixiEditor/Models/Commands/CommandController.cs

@@ -8,351 +8,350 @@ using System.Reflection;
 using System.Windows.Media;
 using System.Windows.Media;
 using CommandAttribute = PixiEditor.Models.Commands.Attributes.Command;
 using CommandAttribute = PixiEditor.Models.Commands.Attributes.Command;
 
 
-namespace PixiEditor.Models.Commands
+namespace PixiEditor.Models.Commands;
+
+public class CommandController
 {
 {
-    public class CommandController
-    {
-        private readonly ShortcutFile shortcutFile;
+    private readonly ShortcutFile shortcutFile;
 
 
-        public static CommandController Current { get; private set; }
+    public static CommandController Current { get; private set; }
 
 
-        public static string ShortcutsPath { get; private set; }
+    public static string ShortcutsPath { get; private set; }
 
 
-        public CommandCollection Commands { get; }
+    public CommandCollection Commands { get; }
 
 
-        public List<CommandGroup> CommandGroups { get; }
+    public List<CommandGroup> CommandGroups { get; }
 
 
-        public Dictionary<string, CanExecuteEvaluator> CanExecuteEvaluators { get; }
+    public Dictionary<string, CanExecuteEvaluator> CanExecuteEvaluators { get; }
 
 
-        public Dictionary<string, IconEvaluator> IconEvaluators { get; }
+    public Dictionary<string, IconEvaluator> IconEvaluators { get; }
 
 
-        public CommandController(IServiceProvider services)
-        {
-            Current ??= this;
+    public CommandController(IServiceProvider services)
+    {
+        Current ??= this;
 
 
-            ShortcutsPath = Path.Join(
-                Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
-                "PixiEditor",
-                "shortcuts.json");
+        ShortcutsPath = Path.Join(
+            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+            "PixiEditor",
+            "shortcuts.json");
 
 
-            shortcutFile = new(ShortcutsPath, this);
+        shortcutFile = new(ShortcutsPath, this);
 
 
-            Commands = new();
-            CommandGroups = new();
-            CanExecuteEvaluators = new();
-            IconEvaluators = new();
-        }
+        Commands = new();
+        CommandGroups = new();
+        CanExecuteEvaluators = new();
+        IconEvaluators = new();
+    }
 
 
-        public void Import(IEnumerable<KeyValuePair<KeyCombination, IEnumerable<string>>> shortcuts, bool save = true)
+    public void Import(IEnumerable<KeyValuePair<KeyCombination, IEnumerable<string>>> shortcuts, bool save = true)
+    {
+        foreach (var shortcut in shortcuts)
         {
         {
-            foreach (var shortcut in shortcuts)
+            foreach (var command in shortcut.Value)
             {
             {
-                foreach (var command in shortcut.Value)
-                {
-                    ReplaceShortcut(Commands[command], shortcut.Key);
-                }
-            }
-
-            if (save)
-            {
-                shortcutFile.SaveShortcuts();
+                ReplaceShortcut(Commands[command], shortcut.Key);
             }
             }
         }
         }
 
 
-        private static List<(string internalName, string displayName)> FindCommandGroups(Type[] typesToSearchForAttributes)
+        if (save)
         {
         {
-            List<(string internalName, string displayName)> result = new();
+            shortcutFile.SaveShortcuts();
+        }
+    }
 
 
-            foreach (var type in typesToSearchForAttributes)
+    private static List<(string internalName, string displayName)> FindCommandGroups(Type[] typesToSearchForAttributes)
+    {
+        List<(string internalName, string displayName)> result = new();
+
+        foreach (var type in typesToSearchForAttributes)
+        {
+            foreach (var group in type.GetCustomAttributes<CommandAttribute.GroupAttribute>())
             {
             {
-                foreach (var group in type.GetCustomAttributes<CommandAttribute.GroupAttribute>())
-                {
-                    result.Add((group.InternalName, group.DisplayName));
-                }
+                result.Add((group.InternalName, group.DisplayName));
             }
             }
-
-            return result;
         }
         }
 
 
-        private static void ForEachMethod
-            (Type[] typesToSearchForMethods, IServiceProvider serviceProvider, Action<MethodInfo, object> action)
+        return result;
+    }
+
+    private static void ForEachMethod
+        (Type[] typesToSearchForMethods, IServiceProvider serviceProvider, Action<MethodInfo, object> action)
+    {
+        foreach (var type in typesToSearchForMethods)
         {
         {
-            foreach (var type in typesToSearchForMethods)
+            object serviceInstance = serviceProvider.GetService(type);
+            var methods = type.GetMethods();
+            foreach (var method in methods)
             {
             {
-                object serviceInstance = serviceProvider.GetService(type);
-                var methods = type.GetMethods();
-                foreach (var method in methods)
-                {
-                    action(method, serviceInstance);
-                }
+                action(method, serviceInstance);
             }
             }
         }
         }
+    }
 
 
-        public void Init(IServiceProvider serviceProvider)
-        {
-            KeyValuePair<KeyCombination, IEnumerable<string>>[] shortcuts = shortcutFile.LoadShortcuts()?.ToArray()
-                ?? Array.Empty<KeyValuePair<KeyCombination, IEnumerable<string>>>();
+    public void Init(IServiceProvider serviceProvider)
+    {
+        KeyValuePair<KeyCombination, IEnumerable<string>>[] shortcuts = shortcutFile.LoadShortcuts()?.ToArray()
+                                                                        ?? Array.Empty<KeyValuePair<KeyCombination, IEnumerable<string>>>();
 
 
-            Type[] allTypesInPixiEditorAssembly = typeof(CommandController).Assembly.GetTypes();
+        Type[] allTypesInPixiEditorAssembly = typeof(CommandController).Assembly.GetTypes();
 
 
-            List<(string internalName, string displayName)> commandGroupsData = FindCommandGroups(allTypesInPixiEditorAssembly);
-            OneToManyDictionary<string, Command> commands = new(); // internal name of the corr. group -> command in that group
+        List<(string internalName, string displayName)> commandGroupsData = FindCommandGroups(allTypesInPixiEditorAssembly);
+        OneToManyDictionary<string, Command> commands = new(); // internal name of the corr. group -> command in that group
 
 
-            // Find evaluators
-            ForEachMethod(allTypesInPixiEditorAssembly, serviceProvider, (methodInfo, maybeServiceInstance) =>
+        // Find evaluators
+        ForEachMethod(allTypesInPixiEditorAssembly, serviceProvider, (methodInfo, maybeServiceInstance) =>
+        {
+            var evaluatorAttrs = methodInfo.GetCustomAttributes<Evaluator.EvaluatorAttribute>();
+            foreach (var attribute in evaluatorAttrs)
             {
             {
-                var evaluatorAttrs = methodInfo.GetCustomAttributes<Evaluator.EvaluatorAttribute>();
-                foreach (var attribute in evaluatorAttrs)
+                switch (attribute)
                 {
                 {
-                    switch (attribute)
+                    case Evaluator.CanExecuteAttribute canExecuteAttribute:
                     {
                     {
-                        case Evaluator.CanExecuteAttribute canExecuteAttribute:
+                        var getRequiredEvaluatorsObjectsOfCurrentEvaluator =
+                            (CommandController controller) =>
+                                canExecuteAttribute.NamesOfRequiredCanExecuteEvaluators.Select(x => controller.CanExecuteEvaluators[x]);
+
+                        AddEvaluatorFactory<Evaluator.CanExecuteAttribute, CanExecuteEvaluator, bool>(
+                            methodInfo,
+                            maybeServiceInstance,
+                            canExecuteAttribute,
+                            CanExecuteEvaluators,
+                            evaluateFunction => new CanExecuteEvaluator()
                             {
                             {
-                                var getRequiredEvaluatorsObjectsOfCurrentEvaluator =
-                                    (CommandController controller) =>
-                                        canExecuteAttribute.NamesOfRequiredCanExecuteEvaluators.Select(x => controller.CanExecuteEvaluators[x]);
-
-                                AddEvaluatorFactory<Evaluator.CanExecuteAttribute, CanExecuteEvaluator, bool>(
-                                    methodInfo,
-                                    maybeServiceInstance,
-                                    canExecuteAttribute,
-                                    CanExecuteEvaluators,
-                                    evaluateFunction => new CanExecuteEvaluator()
-                                    {
-                                        Name = attribute.Name,
-                                        Evaluate = evaluateFunctionArgument =>
-                                            evaluateFunction.Invoke(evaluateFunctionArgument) &&
-                                            getRequiredEvaluatorsObjectsOfCurrentEvaluator.Invoke(this).All(requiredEvaluator =>
-                                                requiredEvaluator.CallEvaluate(null, evaluateFunctionArgument))
-                                    });
-                                break;
-                            }
-                        case Evaluator.IconAttribute icon:
-                            AddEvaluator<Evaluator.IconAttribute, IconEvaluator, ImageSource>(methodInfo, maybeServiceInstance, icon, IconEvaluators);
-                            break;
+                                Name = attribute.Name,
+                                Evaluate = evaluateFunctionArgument =>
+                                    evaluateFunction.Invoke(evaluateFunctionArgument) &&
+                                    getRequiredEvaluatorsObjectsOfCurrentEvaluator.Invoke(this).All(requiredEvaluator =>
+                                        requiredEvaluator.CallEvaluate(null, evaluateFunctionArgument))
+                            });
+                        break;
                     }
                     }
+                    case Evaluator.IconAttribute icon:
+                        AddEvaluator<Evaluator.IconAttribute, IconEvaluator, ImageSource>(methodInfo, maybeServiceInstance, icon, IconEvaluators);
+                        break;
                 }
                 }
-            });
+            }
+        });
 
 
-            // Find basic commands
-            ForEachMethod(allTypesInPixiEditorAssembly, serviceProvider, (methodInfo, maybeServiceInstance) =>
-            {
-                var commandAttrs = methodInfo.GetCustomAttributes<CommandAttribute.CommandAttribute>();
+        // Find basic commands
+        ForEachMethod(allTypesInPixiEditorAssembly, serviceProvider, (methodInfo, maybeServiceInstance) =>
+        {
+            var commandAttrs = methodInfo.GetCustomAttributes<CommandAttribute.CommandAttribute>();
 
 
-                foreach (var attribute in commandAttrs)
+            foreach (var attribute in commandAttrs)
+            {
+                if (attribute is CommandAttribute.BasicAttribute basic)
                 {
                 {
-                    if (attribute is CommandAttribute.BasicAttribute basic)
+                    AddCommand(methodInfo, maybeServiceInstance, attribute, (isDebug, name, x, xCan, xIcon) => new Command.BasicCommand(x, xCan)
                     {
                     {
-                        AddCommand(methodInfo, maybeServiceInstance, attribute, (isDebug, name, x, xCan, xIcon) => new Command.BasicCommand(x, xCan)
-                        {
-                            InternalName = name,
-                            IsDebug = isDebug,
-                            DisplayName = attribute.DisplayName,
-                            Description = attribute.Description,
-                            IconPath = attribute.IconPath,
-                            IconEvaluator = xIcon,
-                            DefaultShortcut = attribute.GetShortcut(),
-                            Shortcut = GetShortcut(name, attribute.GetShortcut()),
-                            Parameter = basic.Parameter,
-                        });
-                    }
+                        InternalName = name,
+                        IsDebug = isDebug,
+                        DisplayName = attribute.DisplayName,
+                        Description = attribute.Description,
+                        IconPath = attribute.IconPath,
+                        IconEvaluator = xIcon,
+                        DefaultShortcut = attribute.GetShortcut(),
+                        Shortcut = GetShortcut(name, attribute.GetShortcut()),
+                        Parameter = basic.Parameter,
+                    });
                 }
                 }
-            });
+            }
+        });
 
 
-            // Find tool commands
-            foreach (var type in allTypesInPixiEditorAssembly)
+        // Find tool commands
+        foreach (var type in allTypesInPixiEditorAssembly)
+        {
+            if (!type.IsAssignableTo(typeof(Tool)))
+                continue;
+
+            var toolAttr = type.GetCustomAttribute<CommandAttribute.ToolAttribute>();
+            if (toolAttr is null)
+                continue;
+
+            Tool toolInstance = serviceProvider.GetServices<Tool>().First(x => x.GetType() == type);
+            string internalName = $"PixiEditor.Tools.Select.{type.Name}";
+
+            var command = new Command.ToolCommand()
             {
             {
-                if (!type.IsAssignableTo(typeof(Tool)))
-                    continue;
+                InternalName = internalName,
+                DisplayName = $"Select {toolInstance.DisplayName} Tool",
+                Description = $"Select {toolInstance.DisplayName} Tool",
+                IconPath = $"@{toolInstance.ImagePath}",
+                IconEvaluator = IconEvaluator.Default,
+                TransientKey = toolAttr.Transient,
+                DefaultShortcut = toolAttr.GetShortcut(),
+                Shortcut = GetShortcut(internalName, toolAttr.GetShortcut()),
+                ToolType = type,
+            };
+
+            Commands.Add(command);
+            AddCommandToCommandsCollection(command);
+        }
+
+        // save all commands into CommandGroups
+        foreach (var (groupInternalName, storedCommands) in commands)
+        {
+            var groupData = commandGroupsData.Where(group => group.internalName == groupInternalName).FirstOrDefault();
+            string groupDisplayName;
+            if (groupData == default)
+                groupDisplayName = "Misc";
+            else
+                groupDisplayName = groupData.displayName;
+            CommandGroups.Add(new(groupDisplayName, storedCommands));
+        }
 
 
-                var toolAttr = type.GetCustomAttribute<CommandAttribute.ToolAttribute>();
-                if (toolAttr is null)
-                    continue;
+        KeyCombination GetShortcut(string internalName, KeyCombination defaultShortcut)
+            => shortcuts.FirstOrDefault(x => x.Value.Contains(internalName), new(defaultShortcut, null)).Key;
 
 
-                Tool toolInstance = serviceProvider.GetServices<Tool>().First(x => x.GetType() == type);
-                string internalName = $"PixiEditor.Tools.Select.{type.Name}";
+        void AddCommandToCommandsCollection(Command command)
+        {
+            (string internalName, string displayName) group = commandGroupsData.FirstOrDefault(x => command.InternalName.StartsWith(x.internalName));
+            if (group == default)
+                commands.Add("", command);
+            else
+                commands.Add(group.internalName, command);
+        }
 
 
-                var command = new Command.ToolCommand()
-                {
-                    InternalName = internalName,
-                    DisplayName = $"Select {toolInstance.DisplayName} Tool",
-                    Description = $"Select {toolInstance.DisplayName} Tool",
-                    IconPath = $"@{toolInstance.ImagePath}",
-                    IconEvaluator = IconEvaluator.Default,
-                    TransientKey = toolAttr.Transient,
-                    DefaultShortcut = toolAttr.GetShortcut(),
-                    Shortcut = GetShortcut(internalName, toolAttr.GetShortcut()),
-                    ToolType = type,
-                };
-
-                Commands.Add(command);
-                AddCommandToCommandsCollection(command);
-            }
+        void AddEvaluator<TAttr, T, TParameter>(MethodInfo method, object instance, TAttr attribute, IDictionary<string, T> evaluators)
+            where T : Evaluator<TParameter>, new()
+            where TAttr : Evaluator.EvaluatorAttribute
+            => AddEvaluatorFactory<TAttr, T, TParameter>(method, instance, attribute, evaluators, x => new T() { Name = attribute.Name, Evaluate = x });
 
 
-            // save all commands into CommandGroups
-            foreach (var (groupInternalName, storedCommands) in commands)
+        void AddEvaluatorFactory<TAttr, T, TParameter>(MethodInfo method, object serviceInstance, TAttr attribute, IDictionary<string, T> evaluators, Func<Func<object, TParameter>, T> factory)
+            where T : Evaluator<TParameter>, new()
+            where TAttr : Evaluator.EvaluatorAttribute
+        {
+            if (method.ReturnType != typeof(TParameter))
             {
             {
-                var groupData = commandGroupsData.Where(group => group.internalName == groupInternalName).FirstOrDefault();
-                string groupDisplayName;
-                if (groupData == default)
-                    groupDisplayName = "Misc";
-                else
-                    groupDisplayName = groupData.displayName;
-                CommandGroups.Add(new(groupDisplayName, storedCommands));
+                throw new Exception($"Invalid return type for the CanExecute evaluator '{attribute.Name}' at {method.ReflectedType.FullName}.{method.Name}\nExpected '{typeof(TParameter).FullName}'");
             }
             }
-
-            KeyCombination GetShortcut(string internalName, KeyCombination defaultShortcut)
-                => shortcuts.FirstOrDefault(x => x.Value.Contains(internalName), new(defaultShortcut, null)).Key;
-
-            void AddCommandToCommandsCollection(Command command)
+            else if (method.GetParameters().Length > 1)
             {
             {
-                (string internalName, string displayName) group = commandGroupsData.FirstOrDefault(x => command.InternalName.StartsWith(x.internalName));
-                if (group == default)
-                    commands.Add("", command);
-                else
-                    commands.Add(group.internalName, command);
+                throw new Exception($"Too many parameters for the CanExecute evaluator '{attribute.Name}' at {method.ReflectedType.FullName}.{method.Name}");
             }
             }
-
-            void AddEvaluator<TAttr, T, TParameter>(MethodInfo method, object instance, TAttr attribute, IDictionary<string, T> evaluators)
-                where T : Evaluator<TParameter>, new()
-                where TAttr : Evaluator.EvaluatorAttribute
-                => AddEvaluatorFactory<TAttr, T, TParameter>(method, instance, attribute, evaluators, x => new T() { Name = attribute.Name, Evaluate = x });
-
-            void AddEvaluatorFactory<TAttr, T, TParameter>(MethodInfo method, object serviceInstance, TAttr attribute, IDictionary<string, T> evaluators, Func<Func<object, TParameter>, T> factory)
-                where T : Evaluator<TParameter>, new()
-                where TAttr : Evaluator.EvaluatorAttribute
+            else if (!method.IsStatic && serviceInstance is null)
             {
             {
-                if (method.ReturnType != typeof(TParameter))
-                {
-                    throw new Exception($"Invalid return type for the CanExecute evaluator '{attribute.Name}' at {method.ReflectedType.FullName}.{method.Name}\nExpected '{typeof(TParameter).FullName}'");
-                }
-                else if (method.GetParameters().Length > 1)
-                {
-                    throw new Exception($"Too many parameters for the CanExecute evaluator '{attribute.Name}' at {method.ReflectedType.FullName}.{method.Name}");
-                }
-                else if (!method.IsStatic && serviceInstance is null)
-                {
-                    throw new Exception($"No type instance for the CanExecute evaluator '{attribute.Name}' at {method.ReflectedType.FullName}.{method.Name} found");
-                }
-
-                var parameters = method.GetParameters();
-
-                Func<object, TParameter> func;
+                throw new Exception($"No type instance for the CanExecute evaluator '{attribute.Name}' at {method.ReflectedType.FullName}.{method.Name} found");
+            }
 
 
-                if (parameters.Length == 1)
-                {
-                    func = x => (TParameter)method.Invoke(serviceInstance, new[] { CastParameter(x, parameters[0].ParameterType) });
-                }
-                else
-                {
-                    func = x => (TParameter)method.Invoke(serviceInstance, null);
-                }
+            var parameters = method.GetParameters();
 
 
-                T evaluator = factory(func);
+            Func<object, TParameter> func;
 
 
-                evaluators.Add(evaluator.Name, evaluator);
+            if (parameters.Length == 1)
+            {
+                func = x => (TParameter)method.Invoke(serviceInstance, new[] { CastParameter(x, parameters[0].ParameterType) });
             }
             }
-
-            object CastParameter(object input, Type target)
+            else
             {
             {
-                if (target == typeof(object) || target == input?.GetType())
-                    return input;
-                return Convert.ChangeType(input, target);
+                func = x => (TParameter)method.Invoke(serviceInstance, null);
             }
             }
 
 
-            TCommand AddCommand<TAttr, TCommand>(MethodInfo method, object instance, TAttr attribute, Func<bool, string, Action<object>, CanExecuteEvaluator, IconEvaluator, TCommand> commandFactory)
-                where TAttr : CommandAttribute.CommandAttribute
-                where TCommand : Command
-            {
-                if (method != null)
-                {
-                    if (method.GetParameters().Length > 1)
-                    {
-                        throw new Exception($"Too many parameters for the CanExecute evaluator '{attribute.InternalName}' at {method.ReflectedType.FullName}.{method.Name}");
-                    }
-                    else if (!method.IsStatic && instance is null)
-                    {
-                        throw new Exception($"No type instance for the CanExecute evaluator '{attribute.InternalName}' at {method.ReflectedType.FullName}.{method.Name} found");
-                    }
-                }
+            T evaluator = factory(func);
 
 
-                var parameters = method?.GetParameters();
+            evaluators.Add(evaluator.Name, evaluator);
+        }
 
 
-                Action<object> action;
+        object CastParameter(object input, Type target)
+        {
+            if (target == typeof(object) || target == input?.GetType())
+                return input;
+            return Convert.ChangeType(input, target);
+        }
 
 
-                if (parameters == null || parameters.Length != 1)
+        TCommand AddCommand<TAttr, TCommand>(MethodInfo method, object instance, TAttr attribute, Func<bool, string, Action<object>, CanExecuteEvaluator, IconEvaluator, TCommand> commandFactory)
+            where TAttr : CommandAttribute.CommandAttribute
+            where TCommand : Command
+        {
+            if (method != null)
+            {
+                if (method.GetParameters().Length > 1)
                 {
                 {
-                    action = x => method.Invoke(instance, null);
+                    throw new Exception($"Too many parameters for the CanExecute evaluator '{attribute.InternalName}' at {method.ReflectedType.FullName}.{method.Name}");
                 }
                 }
-                else
+                else if (!method.IsStatic && instance is null)
                 {
                 {
-                    action = x => method.Invoke(instance, new[] { x });
-                }
-
-                string name = attribute.InternalName;
-                bool isDebug = attribute.InternalName.StartsWith("#DEBUG#");
-
-                if (attribute.InternalName.StartsWith("#DEBUG#"))
-                {
-                    name = name["#DEBUG#".Length..];
+                    throw new Exception($"No type instance for the CanExecute evaluator '{attribute.InternalName}' at {method.ReflectedType.FullName}.{method.Name} found");
                 }
                 }
+            }
 
 
-                var command = commandFactory(
-                        isDebug,
-                        name,
-                        action,
-                        attribute.CanExecute != null ? CanExecuteEvaluators[attribute.CanExecute] : CanExecuteEvaluator.AlwaysTrue,
-                        attribute.IconEvaluator != null ? IconEvaluators[attribute.IconEvaluator] : IconEvaluator.Default);
+            var parameters = method?.GetParameters();
 
 
-                Commands.Add(command);
-                AddCommandToCommandsCollection(command);
+            Action<object> action;
 
 
-                return command;
+            if (parameters == null || parameters.Length != 1)
+            {
+                action = x => method.Invoke(instance, null);
+            }
+            else
+            {
+                action = x => method.Invoke(instance, new[] { x });
             }
             }
-        }
 
 
-        /// <summary>
-        /// Removes the old shortcut to this command and adds the new one
-        /// </summary>
-        public void UpdateShortcut(Command command, KeyCombination newShortcut)
-        {
-            Commands.RemoveShortcut(command, command.Shortcut);
-            Commands.AddShortcut(command, newShortcut);
-            command.Shortcut = newShortcut;
-            shortcutFile.SaveShortcuts();
-        }
+            string name = attribute.InternalName;
+            bool isDebug = attribute.InternalName.StartsWith("#DEBUG#");
 
 
-        /// <summary>
-        /// Deletes all shortcuts of <paramref name="newShortcut"/> and adds <paramref name="command"/>
-        /// </summary>
-        public void ReplaceShortcut(Command command, KeyCombination newShortcut)
-        {
-            foreach (Command other in Commands[newShortcut])
+            if (attribute.InternalName.StartsWith("#DEBUG#"))
             {
             {
-                other.Shortcut = KeyCombination.None;
+                name = name["#DEBUG#".Length..];
             }
             }
 
 
-            Commands.ClearShortcut(newShortcut);
-            Commands.RemoveShortcut(command, command.Shortcut);
-            Commands.AddShortcut(command, newShortcut);
-            command.Shortcut = newShortcut;
-            shortcutFile.SaveShortcuts();
+            var command = commandFactory(
+                isDebug,
+                name,
+                action,
+                attribute.CanExecute != null ? CanExecuteEvaluators[attribute.CanExecute] : CanExecuteEvaluator.AlwaysTrue,
+                attribute.IconEvaluator != null ? IconEvaluators[attribute.IconEvaluator] : IconEvaluator.Default);
+
+            Commands.Add(command);
+            AddCommandToCommandsCollection(command);
+
+            return command;
         }
         }
+    }
 
 
-        public void ResetShortcuts()
+    /// <summary>
+    /// Removes the old shortcut to this command and adds the new one
+    /// </summary>
+    public void UpdateShortcut(Command command, KeyCombination newShortcut)
+    {
+        Commands.RemoveShortcut(command, command.Shortcut);
+        Commands.AddShortcut(command, newShortcut);
+        command.Shortcut = newShortcut;
+        shortcutFile.SaveShortcuts();
+    }
+
+    /// <summary>
+    /// Deletes all shortcuts of <paramref name="newShortcut"/> and adds <paramref name="command"/>
+    /// </summary>
+    public void ReplaceShortcut(Command command, KeyCombination newShortcut)
+    {
+        foreach (Command other in Commands[newShortcut])
         {
         {
-            File.Copy(ShortcutsPath, Path.ChangeExtension(ShortcutsPath, ".json.bak"), true);
+            other.Shortcut = KeyCombination.None;
+        }
 
 
-            Commands.ClearShortcuts();
+        Commands.ClearShortcut(newShortcut);
+        Commands.RemoveShortcut(command, command.Shortcut);
+        Commands.AddShortcut(command, newShortcut);
+        command.Shortcut = newShortcut;
+        shortcutFile.SaveShortcuts();
+    }
 
 
-            foreach (var command in Commands)
-            {
-                Commands.RemoveShortcut(command, command.Shortcut);
-                Commands.AddShortcut(command, command.DefaultShortcut);
-                command.Shortcut = command.DefaultShortcut;
-            }
+    public void ResetShortcuts()
+    {
+        File.Copy(ShortcutsPath, Path.ChangeExtension(ShortcutsPath, ".json.bak"), true);
 
 
-            shortcutFile.SaveShortcuts();
+        Commands.ClearShortcuts();
+
+        foreach (var command in Commands)
+        {
+            Commands.RemoveShortcut(command, command.Shortcut);
+            Commands.AddShortcut(command, command.DefaultShortcut);
+            command.Shortcut = command.DefaultShortcut;
         }
         }
+
+        shortcutFile.SaveShortcuts();
     }
     }
-}
+}

+ 36 - 37
src/PixiEditor/Models/Commands/CommandGroup.cs

@@ -2,54 +2,53 @@
 using System.Collections;
 using System.Collections;
 using System.Windows.Input;
 using System.Windows.Input;
 
 
-namespace PixiEditor.Models.Commands
+namespace PixiEditor.Models.Commands;
+
+public class CommandGroup : IEnumerable<Command>
 {
 {
-    public class CommandGroup : IEnumerable<Command>
-    {
-        private readonly Command[] commands;
-        private readonly Command[] visibleCommands;
+    private readonly Command[] commands;
+    private readonly Command[] visibleCommands;
 
 
-        public string DisplayName { get; set; }
+    public string DisplayName { get; set; }
 
 
-        public bool HasAssignedShortcuts { get; set; }
+    public bool HasAssignedShortcuts { get; set; }
 
 
-        public IEnumerable<Command> Commands => commands;
+    public IEnumerable<Command> Commands => commands;
 
 
-        public IEnumerable<Command> VisibleCommands => visibleCommands;
+    public IEnumerable<Command> VisibleCommands => visibleCommands;
 
 
-        public CommandGroup(string displayName, IEnumerable<Command> commands)
+    public CommandGroup(string displayName, IEnumerable<Command> commands)
+    {
+        DisplayName = displayName;
+        this.commands = commands.ToArray();
+        visibleCommands = commands.Where(x => !string.IsNullOrEmpty(x.DisplayName)).ToArray();
+
+        foreach (var command in commands)
         {
         {
-            DisplayName = displayName;
-            this.commands = commands.ToArray();
-            visibleCommands = commands.Where(x => !string.IsNullOrEmpty(x.DisplayName)).ToArray();
-
-            foreach (var command in commands)
-            {
-                HasAssignedShortcuts |= command.Shortcut.Key != Key.None;
-                command.ShortcutChanged += Command_ShortcutChanged;
-            }
+            HasAssignedShortcuts |= command.Shortcut.Key != Key.None;
+            command.ShortcutChanged += Command_ShortcutChanged;
         }
         }
+    }
 
 
-        private void Command_ShortcutChanged(Command cmd, ShortcutChangedEventArgs args)
+    private void Command_ShortcutChanged(Command cmd, ShortcutChangedEventArgs args)
+    {
+        if ((args.NewShortcut != KeyCombination.None && HasAssignedShortcuts) ||
+            (args.NewShortcut == KeyCombination.None && !HasAssignedShortcuts))
         {
         {
-            if ((args.NewShortcut != KeyCombination.None && HasAssignedShortcuts) ||
-                (args.NewShortcut == KeyCombination.None && !HasAssignedShortcuts))
-            {
-                // If a shortcut is already assigned and the new shortcut is not none nothing can change
-                // If no shortcut is already assigned and the new shortcut is none nothing can change
-                return;
-            }
-
-            HasAssignedShortcuts = false;
-
-            foreach (var command in commands)
-            {
-                HasAssignedShortcuts |= command.Shortcut.Key != Key.None;
-            }
+            // If a shortcut is already assigned and the new shortcut is not none nothing can change
+            // If no shortcut is already assigned and the new shortcut is none nothing can change
+            return;
         }
         }
 
 
-        public IEnumerator<Command> GetEnumerator() => Commands.GetEnumerator();
+        HasAssignedShortcuts = false;
 
 
-        IEnumerator IEnumerable.GetEnumerator() => Commands.GetEnumerator();
+        foreach (var command in commands)
+        {
+            HasAssignedShortcuts |= command.Shortcut.Key != Key.None;
+        }
     }
     }
-}
+
+    public IEnumerator<Command> GetEnumerator() => Commands.GetEnumerator();
+
+    IEnumerator IEnumerable.GetEnumerator() => Commands.GetEnumerator();
+}

+ 8 - 9
src/PixiEditor/Models/Commands/Commands/BasicCommand.cs

@@ -1,16 +1,15 @@
 using PixiEditor.Models.Commands.Evaluators;
 using PixiEditor.Models.Commands.Evaluators;
 
 
-namespace PixiEditor.Models.Commands
+namespace PixiEditor.Models.Commands;
+
+public partial class Command
 {
 {
-    public partial class Command
+    public class BasicCommand : Command
     {
     {
-        public class BasicCommand : Command
-        {
-            public object Parameter { get; init; }
+        public object Parameter { get; init; }
 
 
-            protected override object GetParameter() => Parameter;
+        protected override object GetParameter() => Parameter;
 
 
-            public BasicCommand(Action<object> onExecute, CanExecuteEvaluator canExecute) : base(onExecute, canExecute) { }
-        }
+        public BasicCommand(Action<object> onExecute, CanExecuteEvaluator canExecute) : base(onExecute, canExecute) { }
     }
     }
-}
+}

+ 29 - 30
src/PixiEditor/Models/Commands/Commands/Command.cs

@@ -4,54 +4,53 @@ using PixiEditor.Models.DataHolders;
 using System.Diagnostics;
 using System.Diagnostics;
 using System.Windows.Media;
 using System.Windows.Media;
 
 
-namespace PixiEditor.Models.Commands
+namespace PixiEditor.Models.Commands;
+
+[DebuggerDisplay("{InternalName,nq} ('{DisplayName,nq}')")]
+public abstract partial class Command : NotifyableObject
 {
 {
-    [DebuggerDisplay("{InternalName,nq} ('{DisplayName,nq}')")]
-    public abstract partial class Command : NotifyableObject
-    {
-        private KeyCombination _shortcut;
+    private KeyCombination _shortcut;
 
 
-        public bool IsDebug { get; init; }
+    public bool IsDebug { get; init; }
 
 
-        public string InternalName { get; init; }
+    public string InternalName { get; init; }
 
 
-        public string IconPath { get; init; }
+    public string IconPath { get; init; }
 
 
-        public IconEvaluator IconEvaluator { get; init; }
+    public IconEvaluator IconEvaluator { get; init; }
 
 
-        public string DisplayName { get; init; }
+    public string DisplayName { get; init; }
 
 
-        public string Description { get; init; }
+    public string Description { get; init; }
 
 
-        public CommandMethods Methods { get; init; }
+    public CommandMethods Methods { get; init; }
 
 
-        public KeyCombination DefaultShortcut { get; init; }
+    public KeyCombination DefaultShortcut { get; init; }
 
 
-        public KeyCombination Shortcut
+    public KeyCombination Shortcut
+    {
+        get => _shortcut;
+        set
         {
         {
-            get => _shortcut;
-            set
+            if (SetProperty(ref _shortcut, value, out var oldValue))
             {
             {
-                if (SetProperty(ref _shortcut, value, out var oldValue))
-                {
-                    ShortcutChanged?.Invoke(this, new(oldValue, value));
-                }
+                ShortcutChanged?.Invoke(this, new(oldValue, value));
             }
             }
         }
         }
+    }
 
 
-        public event ShortcutChangedEventHandler ShortcutChanged;
+    public event ShortcutChangedEventHandler ShortcutChanged;
 
 
-        protected abstract object GetParameter();
+    protected abstract object GetParameter();
 
 
-        protected Command(Action<object> onExecute, CanExecuteEvaluator canExecute) =>
-            Methods = new(this, onExecute, canExecute);
+    protected Command(Action<object> onExecute, CanExecuteEvaluator canExecute) =>
+        Methods = new(this, onExecute, canExecute);
 
 
-        public void Execute() => Methods.Execute(GetParameter());
+    public void Execute() => Methods.Execute(GetParameter());
 
 
-        public bool CanExecute() => Methods.CanExecute(GetParameter());
+    public bool CanExecute() => Methods.CanExecute(GetParameter());
 
 
-        public ImageSource GetIcon() => IconEvaluator.CallEvaluate(this, GetParameter());
+    public ImageSource GetIcon() => IconEvaluator.CallEvaluate(this, GetParameter());
 
 
-        public delegate void ShortcutChangedEventHandler(Command command, ShortcutChangedEventArgs args);
-    }
-}
+    public delegate void ShortcutChangedEventHandler(Command command, ShortcutChangedEventArgs args);
+}

+ 9 - 10
src/PixiEditor/Models/Commands/Commands/ToolCommand.cs

@@ -1,19 +1,18 @@
 using PixiEditor.ViewModels;
 using PixiEditor.ViewModels;
 using System.Windows.Input;
 using System.Windows.Input;
 
 
-namespace PixiEditor.Models.Commands
+namespace PixiEditor.Models.Commands;
+
+public partial class Command
 {
 {
-    public partial class Command
+    public class ToolCommand : Command
     {
     {
-        public class ToolCommand : Command
-        {
-            public Type ToolType { get; init; }
+        public Type ToolType { get; init; }
 
 
-            public Key TransientKey { get; init; }
+        public Key TransientKey { get; init; }
 
 
-            protected override object GetParameter() => ToolType;
+        protected override object GetParameter() => ToolType;
 
 
-            public ToolCommand() : base(ViewModelMain.Current.ToolsSubViewModel.SetTool, CommandController.Current.CanExecuteEvaluators["PixiEditor.HasDocument"]) { }
-        }
+        public ToolCommand() : base(ViewModelMain.Current.ToolsSubViewModel.SetTool, CommandController.Current.CanExecuteEvaluators["PixiEditor.HasDocument"]) { }
     }
     }
-}
+}

Some files were not shown because too many files changed in this diff