Kaynağa Gözat

Solved all compile time errors

Krzysztof Krysiński 2 yıl önce
ebeveyn
işleme
1b803e5b55
21 değiştirilmiş dosya ile 421 ekleme ve 32 silme
  1. 44 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/Converters/FileExtensionToColorConverter.cs
  2. 20 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/Converters/MarkupConverter.cs
  3. 20 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/Converters/SingleInstanceConverter.cs
  4. 34 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/Extensions/ColorHelpers.cs
  5. 0 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/MarkupExtensions/LocalizationExtension.cs
  6. 117 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/SupportedFilesHelper.cs
  7. 19 9
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Commands/Search/ColorSearchResult.cs
  8. 9 3
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Commands/Search/CommandSearchResult.cs
  9. 10 7
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Commands/Search/FileSearchResult.cs
  10. 6 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Files/FileType.cs
  11. 10 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/IColorsHandler.cs
  12. 9 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/IDocument.cs
  13. 11 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/IDocumentHandler.cs
  14. 1 1
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/ISearchHandler.cs
  15. 1 1
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/IToolHandler.cs
  16. 1 1
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/IToolsHandler.cs
  17. 55 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/IO/FileTypeDialogData.cs
  18. 52 0
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/IO/FileTypeDialogDataSet.cs
  19. 1 5
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/PixiEditor.Avalonia.csproj
  20. 0 3
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Views/Dialogs/NoticePopup.axaml
  21. 1 2
      src/PixiEditor.Avalonia/PixiEditor.Avalonia/Views/Dialogs/NoticePopup.axaml.cs

+ 44 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/Converters/FileExtensionToColorConverter.cs

@@ -0,0 +1,44 @@
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Windows.Media;
+using Avalonia.Media;
+using PixiEditor.Models.Enums;
+using PixiEditor.Models.Files;
+
+namespace PixiEditor.Helpers.Converters;
+
+internal class FileExtensionToColorConverter :
+    SingleInstanceConverter<FileExtensionToColorConverter>
+{
+    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);
+    }
+
+    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);
+    }
+
+    private static SolidColorBrush ColorBrush(byte r, byte g, byte b)
+    {
+        return new SolidColorBrush(Color.FromRgb(r, g, b));
+    }
+}

+ 20 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/Converters/MarkupConverter.cs

@@ -0,0 +1,20 @@
+using System.Globalization;
+using Avalonia.Data.Converters;
+using Avalonia.Markup.Xaml;
+
+namespace PixiEditor.Helpers.Converters;
+
+internal abstract class MarkupConverter : MarkupExtension, IValueConverter
+{
+    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 override object ProvideValue(IServiceProvider serviceProvider)
+    {
+        return this;
+    }
+}

+ 20 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/Converters/SingleInstanceConverter.cs

@@ -0,0 +1,20 @@
+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>
+internal abstract class SingleInstanceConverter<TThis> : MarkupConverter
+    where TThis : SingleInstanceConverter<TThis>
+{
+    private static SingleInstanceConverter<TThis> instance;
+
+    public override object ProvideValue(IServiceProvider serviceProvider)
+    {
+        if (instance is null)
+        {
+            instance = this;
+        }
+
+        return instance;
+    }
+}

+ 34 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/Extensions/ColorHelpers.cs

@@ -0,0 +1,34 @@
+using System.Windows.Media;
+using Avalonia.Media;
+using PixiEditor.Extensions.Palettes;
+using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
+
+namespace PixiEditor.Helpers.Extensions;
+
+internal static class ColorHelpers
+{
+    public static BackendColor ToOpaqueColor(this Color color) => new(color.R, color.G, color.B);
+    public static BackendColor ToColor(this Color color) => new(color.R, color.G, color.B, color.A);
+    public static BackendColor ToColor(this PaletteColor color) => new(color.R, color.G, color.B, 255);
+
+    public static PaletteColor ToPaletteColor(this Color color) => new(color.R, color.G, color.B);
+    public static PaletteColor ToPaletteColor(this BackendColor color) => new(color.R, color.G, color.B);
+
+    public static Color ToOpaqueMediaColor(this BackendColor color) => Color.FromRgb(color.R, color.G, color.B);
+    public static Color ToColor(this BackendColor color) => Color.FromArgb(color.A, color.R, color.G, color.B);
+    public static Color ToMediaColor(this PaletteColor color) => Color.FromRgb(color.R, color.G, color.B);
+    
+    public static BackendColor BlendColors(BackendColor bottomColor, BackendColor topColor)
+    {
+        if (topColor.A is < 255 and > 0)
+        {
+            byte r = (byte)((topColor.R * topColor.A / 255) + (bottomColor.R * bottomColor.A * (255 - topColor.A) / (255 * 255)));
+            byte g = (byte)((topColor.G * topColor.A / 255) + (bottomColor.G * bottomColor.A * (255 - topColor.A) / (255 * 255)));
+            byte b = (byte)((topColor.B * topColor.A / 255) + (bottomColor.B * bottomColor.A * (255 - topColor.A) / (255 * 255)));
+            byte a = (byte)(topColor.A + (bottomColor.A * (255 - topColor.A) / 255));
+            return new BackendColor(r, g, b, a);
+        }
+
+        return topColor.A == 255 ? topColor : bottomColor;
+    }
+}

+ 0 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/MarkupExtensions/LocalizationExtension.cs → src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/MarkupExtensions/LocalizationExtension.cs


+ 117 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Helpers/SupportedFilesHelper.cs

@@ -0,0 +1,117 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using PixiEditor.Models.Enums;
+using PixiEditor.Models.Files;
+using PixiEditor.Models.IO;
+
+namespace PixiEditor.Helpers;
+
+internal 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; }
+
+    static SupportedFilesHelper()
+    {
+        fileTypeDialogsData = new Dictionary<FileType, FileTypeDialogData>();
+        allFileTypeDialogsData = new List<FileTypeDialogData>();
+
+        var allFormats = Enum.GetValues(typeof(FileType)).Cast<FileType>().ToList();
+
+        foreach (var format in allFormats)
+        {
+            var fileTypeDialogData = new FileTypeDialogData(format);
+            if (format != FileType.Unset)
+                fileTypeDialogsData[format] = fileTypeDialogData;
+
+            allFileTypeDialogsData.Add(fileTypeDialogData);
+        }
+
+        AllSupportedExtensions = fileTypeDialogsData.SelectMany(i => i.Value.Extensions).ToArray();
+        PrimaryExtensions = fileTypeDialogsData.Select(i => i.Value.PrimaryExtension).ToArray();
+    }
+
+    public static FileTypeDialogData GetFileTypeDialogData(FileType type)
+    {
+        return allFileTypeDialogsData.Where(i => i.FileType == type).Single();
+    }
+
+    public static string FixFileExtension(string pathWithOrWithoutExtension, FileType requestedType)
+    {
+        if (requestedType == FileType.Unset)
+            throw new ArgumentException("A valid filetype is required", nameof(requestedType));
+
+        var typeFromPath = SupportedFilesHelper.ParseImageFormat(Path.GetExtension(pathWithOrWithoutExtension));
+        if (typeFromPath != FileType.Unset && typeFromPath == requestedType)
+            return pathWithOrWithoutExtension;
+        return AppendExtension(pathWithOrWithoutExtension, SupportedFilesHelper.GetFileTypeDialogData(requestedType));
+    }
+
+    public static string AppendExtension(string path, FileTypeDialogData data)
+    {
+        string ext = data.Extensions.First();
+        string filename = Path.GetFileName(path);
+        if (filename.Length + ext.Length > 255)
+            filename = filename.Substring(0, 255 - ext.Length);
+        filename += ext;
+        return Path.Combine(Path.GetDirectoryName(path), filename);
+    }
+
+    public static bool IsSupportedFile(string path)
+    {
+        var ext = Path.GetExtension(path.ToLower());
+        return IsExtensionSupported(ext);
+    }
+
+    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 List<FileTypeDialogData> GetAllSupportedFileTypes(bool includePixi)
+    {
+        var allExts = fileTypeDialogsData.Values.ToList();
+        if (!includePixi)
+            allExts.RemoveAll(item => item.FileType == FileType.Pixi);
+        return allExts;
+    }
+
+    public static string BuildSaveFilter(bool includePixi)
+    {
+        var allSupportedExtensions = GetAllSupportedFileTypes(includePixi);
+        var filter = string.Join("|", allSupportedExtensions.Select(i => i.SaveFilter));
+
+        return filter;
+    }
+
+    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;
+    }
+
+    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;
+    }
+}

+ 19 - 9
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Commands/Search/ColorSearchResult.cs

@@ -3,6 +3,8 @@ using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Media;
 using PixiEditor.Extensions.Palettes;
+using PixiEditor.Helpers.Extensions;
+using PixiEditor.Models.Containers;
 
 namespace PixiEditor.Models.Commands.Search;
 
@@ -17,15 +19,15 @@ internal class ColorSearchResult : SearchResult
 
     public override string Text => text;
 
-    public override AvaloniaObject Description => new TextBlock(
+    public override AvaloniaObject Description => new TextBlock()
     {
         Text = $"{color} rgba({color.R}, {color.G}, {color.B}, {color.A})",
         FontSize = 16,
-        TextDecorations = GetDecoration(new Pen(new SolidColorBrush(color.ToOpaqueMediaColor()), 1))
+        TextDecorations = GetDecoration(1, new SolidColorBrush(color.ToOpaqueMediaColor()))
     };
 
     //public override bool CanExecute => !requiresDocument || (requiresDocument && ViewModelMain.Current.BitmapManager.ActiveDocument != null);
-    public override bool CanExecute => !isPalettePaste || ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument != null;
+    public override bool CanExecute => !isPalettePaste || (IDocumentHandler.Instance != null && IDocumentHandler.Instance.HasActiveDocument);
 
     public override IImage Icon => icon;
 
@@ -42,7 +44,7 @@ internal class ColorSearchResult : SearchResult
         this.target = target;
     }
 
-    public ColorSearchResult(DrawingApi.Core.ColorsImpl.Color color) : this(color, x => ViewModelMain.Current.ColorsSubViewModel.PrimaryColor = x)
+    public ColorSearchResult(DrawingApi.Core.ColorsImpl.Color color) : this(color, x => IColorsHandler.Instance.PrimaryColor = x)
     {
         text = $"Set color to {color}";
     }
@@ -50,7 +52,7 @@ internal class ColorSearchResult : SearchResult
     public static ColorSearchResult PastePalette(DrawingApi.Core.ColorsImpl.Color color, string searchTerm = null)
     {
         var result = new ColorSearchResult(color, x =>
-            ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument!.Palette.Add(new PaletteColor(x.R, x.G, x.B)))
+            IDocumentHandler.Instance.ActiveDocument.Palette.Add(new PaletteColor(x.R, x.G, x.B)))
         {
             SearchTerm = searchTerm,
             isPalettePaste = true
@@ -63,14 +65,22 @@ internal class ColorSearchResult : SearchResult
 
     public static DrawingImage GetIcon(DrawingApi.Core.ColorsImpl.Color color)
     {
-        var drawing = new GeometryDrawing() { Brush = new SolidColorBrush(color.ToOpaqueMediaColor()), Pen = new(Brushes.White, 1) };
-        var geometry = new EllipseGeometry(new(5, 5), 5, 5) { };
+        var drawing = new GeometryDrawing() { Brush = new SolidColorBrush(color.ToOpaqueMediaColor()), Pen = new Pen(Brushes.White, 1) };
+        var geometry = new EllipseGeometry(new Rect(5, 5,5, 5));
         drawing.Geometry = geometry;
         return new DrawingImage(drawing);
     }
     
-    private static TextDecorationCollection GetDecoration(Pen pen) => new()
+    private static TextDecorationCollection GetDecoration(double strokeThickness, SolidColorBrush solidColorBrush) => new()
     {
-        new TextDecoration(TextDecorationLocation.Underline, pen, 0, TextDecorationUnit.Pixel, TextDecorationUnit.Pixel)
+        new TextDecoration()
+        {
+            Location = TextDecorationLocation.Underline,
+            StrokeThicknessUnit = TextDecorationUnit.Pixel,
+            StrokeOffsetUnit = TextDecorationUnit.Pixel,
+            StrokeThickness = strokeThickness,
+            Stroke = solidColorBrush,
+            StrokeOffset = 0,
+        },
     };
 }

+ 9 - 3
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Commands/Search/CommandSearchResult.cs

@@ -1,4 +1,6 @@
-using System.Windows.Media;
+using System.Threading.Tasks;
+using System.Windows.Media;
+using Avalonia.Media;
 using PixiEditor.Models.Commands.Commands;
 using PixiEditor.Models.DataHolders;
 
@@ -12,11 +14,15 @@ internal class CommandSearchResult : SearchResult
 
     public override bool CanExecute => Command.CanExecute();
 
-    public override ImageSource Icon => Command.IconEvaluator.CallEvaluate(Command, this);
+    public override IImage Icon => Command.IconEvaluator.CallEvaluate(Command, this);
 
     public override KeyCombination Shortcut => Command.Shortcut;
 
     public CommandSearchResult(Command command) => Command = command;
 
-    public override void Execute() => Command.Execute();
+    public override Task Execute()
+    {
+        Command.Execute();
+        return Task.CompletedTask;
+    }
 }

+ 10 - 7
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Commands/Search/FileSearchResult.cs

@@ -1,7 +1,8 @@
 using System.IO;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Media;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Media;
 using PixiEditor.Helpers.Converters;
 
 namespace PixiEditor.Models.Commands.Search;
@@ -15,24 +16,24 @@ internal class FileSearchResult : SearchResult
 
     public override string Text => asReferenceLayer ? $"As reference: ...\\{Path.GetFileName(FilePath)}" : $"...\\{Path.GetFileName(FilePath)}";
 
-    public override FrameworkElement Description => new TextBlock { Text = FilePath, FontSize = 16 };
+    public override AvaloniaObject Description => new TextBlock { Text = FilePath, FontSize = 16 };
 
     public override bool CanExecute => !asReferenceLayer ||
                 CommandController.Current.Commands["PixiEditor.Clipboard.PasteReferenceLayerFromPath"].Methods.CanExecute(FilePath);
 
-    public override ImageSource Icon => icon;
+    public override IImage Icon => icon;
 
     public FileSearchResult(string path, bool asReferenceLayer = false)
     {
         FilePath = path;
         var drawing = new GeometryDrawing() { Brush = FileExtensionToColorConverter.GetBrush(FilePath) };
-        var geometry = new RectangleGeometry(new(0, 0, 10, 10), 3, 3) { };
+        var geometry = new RectangleGeometry(new Rect(0, 0, 10, 10)) { };
         drawing.Geometry = geometry;
         icon = new DrawingImage(drawing);
         this.asReferenceLayer = asReferenceLayer;
     }
 
-    public override void Execute()
+    public override Task Execute()
     {
         if (!asReferenceLayer)
         {
@@ -47,5 +48,7 @@ internal class FileSearchResult : SearchResult
                     .Execute(FilePath);
             }
         }
+
+        return Task.CompletedTask;
     }
 }

+ 6 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Files/FileType.cs

@@ -0,0 +1,6 @@
+namespace PixiEditor.Models.Files;
+
+public enum FileType
+{
+    Unset, Pixi, Png, Jpeg, Bmp, Gif
+}

+ 10 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/IColorsHandler.cs

@@ -0,0 +1,10 @@
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+
+namespace PixiEditor.Models.Containers;
+
+internal interface IColorsHandler
+{
+    public static IColorsHandler? Instance { get; }
+    public Color PrimaryColor { get; set; }
+    public Color SecondaryColor { get; set; }
+}

+ 9 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/IDocument.cs

@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+using PixiEditor.Extensions.Palettes;
+
+namespace PixiEditor.Models.Containers;
+
+public interface IDocument
+{
+    public List<PaletteColor> Palette { get; set; }
+}

+ 11 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/IDocumentHandler.cs

@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using PixiEditor.Extensions.Palettes;
+
+namespace PixiEditor.Models.Containers;
+
+internal interface IDocumentHandler
+{
+    public static IDocumentHandler? Instance { get; }
+    public bool HasActiveDocument { get; }
+    public IDocument? ActiveDocument { get; set; }
+}

+ 1 - 1
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/ISearchHandler.cs

@@ -1,6 +1,6 @@
 namespace PixiEditor.Models.Containers;
 
-public interface ISearchHandler
+internal  interface ISearchHandler
 {
     public void OpenSearchWindow(string searchQuery);
 }

+ 1 - 1
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/IToolHandler.cs

@@ -4,7 +4,7 @@ using PixiEditor.Extensions.Common.Localization;
 
 namespace PixiEditor.Models.Containers;
 
-public interface IToolHandler
+internal  interface IToolHandler
 {
     public bool IsTransient { get; set; }
     public LocalizedString DisplayName => new LocalizedString(ToolNameLocalizationKey);

+ 1 - 1
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/IToolsHandler.cs

@@ -1,6 +1,6 @@
 namespace PixiEditor.Models.Containers;
 
-public interface IToolsHandler
+internal  interface IToolsHandler
 {
     public void SetTool(object parameter);
 }

+ 55 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/IO/FileTypeDialogData.cs

@@ -0,0 +1,55 @@
+using System.Collections.Generic;
+using System.Linq;
+using PixiEditor.Models.Enums;
+using PixiEditor.Models.Files;
+
+namespace PixiEditor.Models.IO;
+
+internal class FileTypeDialogData
+{
+    public FileType FileType { get; set; }
+
+    /// <summary>
+    /// Gets or sets file type extensions e.g. {jpg,jpeg}
+    /// </summary>
+    public List<string> Extensions { get; set; }
+
+    /// <summary>
+    /// Gets file type's main extensions e.g. jpeg
+    /// </summary>
+    public string PrimaryExtension { get => Extensions.FirstOrDefault(); }
+
+    /// <summary>
+    /// Gets or sets name displayed before extension e.g. JPEG Files
+    /// </summary>
+    public string DisplayName { get; set; }
+
+    public FileTypeDialogData(FileType fileType)
+    {
+        FileType = fileType;
+        Extensions = new List<string>();
+        Extensions.Add("." + FileType.ToString().ToLower());
+        if (FileType == FileType.Jpeg)
+            Extensions.Add(".jpg");
+
+        if (fileType == FileType.Pixi)
+            DisplayName = "PixiEditor Files";
+        else
+            DisplayName = FileType.ToString() + " Images";
+    }
+
+    public string SaveFilter
+    {
+        get { return DisplayName + "|" + GetExtensionFormattedForDialog(PrimaryExtension); }
+    }
+
+    public string ExtensionsFormattedForDialog
+    {
+        get { return string.Join(";", Extensions.Select(i => GetExtensionFormattedForDialog(i))); }
+    }
+
+    string GetExtensionFormattedForDialog(string extension)
+    {
+        return "*" + extension;
+    }
+}

+ 52 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/IO/FileTypeDialogDataSet.cs

@@ -0,0 +1,52 @@
+using System.Collections.Generic;
+using System.Linq;
+using PixiEditor.Helpers;
+using PixiEditor.Models.Enums;
+using PixiEditor.Models.Files;
+
+namespace PixiEditor.Models.IO;
+
+internal class FileTypeDialogDataSet
+{
+    public enum SetKind { Any, Pixi, Images }
+    IEnumerable<FileTypeDialogData> fileTypes;
+    string displayName;
+
+    public FileTypeDialogDataSet(SetKind kind, IEnumerable<FileTypeDialogData> fileTypes = null)
+    {
+        if (fileTypes == null)
+            fileTypes = SupportedFilesHelper.GetAllSupportedFileTypes(true);
+        var allSupportedExtensions = fileTypes;
+        if (kind == SetKind.Any)
+        {
+            Init("Any", allSupportedExtensions);
+        }
+        else if (kind == SetKind.Pixi)
+        {
+            Init("PixiEditor Files", new[] { new FileTypeDialogData(FileType.Pixi) });
+        }
+        else if (kind == SetKind.Images)
+        {
+            Init("Image Files", allSupportedExtensions, FileType.Pixi);
+        }
+    }
+    public FileTypeDialogDataSet(string displayName, IEnumerable<FileTypeDialogData> fileTypes, FileType? fileTypeToSkip = null)
+    {
+        Init(displayName, fileTypes, fileTypeToSkip);
+    }
+
+    private void Init(string displayName, IEnumerable<FileTypeDialogData> fileTypes, FileType? fileTypeToSkip = null)
+    {
+        var copy = fileTypes.ToList();
+        if (fileTypeToSkip.HasValue)
+            copy.RemoveAll(i => i.FileType == fileTypeToSkip.Value);
+        this.fileTypes = copy;
+
+        this.displayName = displayName;
+    }
+
+    public string GetFormattedTypes()
+    {
+        return displayName + " |" + string.Join(";", this.fileTypes.Select(i => i.ExtensionsFormattedForDialog));
+    }
+}

+ 1 - 5
src/PixiEditor.Avalonia/PixiEditor.Avalonia/PixiEditor.Avalonia.csproj

@@ -50,10 +50,6 @@
     </ItemGroup>
   
     <ItemGroup>
-      <AvaloniaXaml Include="Views\Dialogs\NoticePopup.axaml">
-        <Generator>MSBuild:Compile</Generator>
-        <XamlRuntime>Wpf</XamlRuntime>
-        <SubType>Designer</SubType>
-      </AvaloniaXaml>
+
     </ItemGroup>
 </Project>

+ 0 - 3
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Views/Dialogs/NoticePopup.axaml

@@ -4,9 +4,6 @@
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-        xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
-        xmlns:dial="clr-namespace:PixiEditor.Views.Dialogs"
-        xmlns:views="clr-namespace:PixiEditor.Views"
         xmlns:helpers="clr-namespace:PixiEditor.Helpers"
         xmlns:ui="clr-namespace:PixiEditor.Extensions.UI;assembly=PixiEditor.Extensions"
         xmlns:controls="https://github.com/avaloniaui"

+ 1 - 2
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Views/Dialogs/NoticePopup.axaml.cs

@@ -1,5 +1,4 @@
-using System.Windows;
-using Avalonia;
+using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Interactivity;