浏览代码

No more non UI related errors

Krzysztof Krysiński 2 年之前
父节点
当前提交
26e1811db5

+ 8 - 4
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Controllers/InputDevice/KeyboardInputFilter.cs

@@ -77,9 +77,11 @@ internal class KeyboardInputFilter
         /*if (key == Key.System) TODO: Validate if this is not needed
             key = args.SystemKey;*/
 
-        MaybeUpdateKeyState(key, args.IsRepeat, KeyStates.Down, keyboardState, OnAnyKeyDown);
+        bool isRepeat = keyboardState.TryGetValue(key, out KeyStates state) ? state == KeyStates.Down : false;
+
+        MaybeUpdateKeyState(key, isRepeat, KeyStates.Down, keyboardState, OnAnyKeyDown);
         key = ConvertRightKeys(key);
-        MaybeUpdateKeyState(key, args.IsRepeat, KeyStates.Down, converterdKeyboardState, OnConvertedKeyDown);
+        MaybeUpdateKeyState(key, isRepeat, KeyStates.Down, converterdKeyboardState, OnConvertedKeyDown);
     }
 
     public void KeyUpInlet(KeyEventArgs args)
@@ -88,9 +90,11 @@ internal class KeyboardInputFilter
         /*if (key == Key.System) TODO: Validate if this is not needed
             key = args.SystemKey;*/
 
-        MaybeUpdateKeyState(key, args.IsRepeat, KeyStates.None, keyboardState, OnAnyKeyUp);
+        bool isRepeat = keyboardState.TryGetValue(key, out KeyStates state) ? state == KeyStates.Down : false;
+
+        MaybeUpdateKeyState(key, isRepeat, KeyStates.None, keyboardState, OnAnyKeyUp);
         key = ConvertRightKeys(key);
-        MaybeUpdateKeyState(key, args.IsRepeat, KeyStates.None, converterdKeyboardState, OnConvertedKeyUp);
+        MaybeUpdateKeyState(key, isRepeat, KeyStates.None, converterdKeyboardState, OnConvertedKeyUp);
     }
 
     private void MaybeUpdateKeyState(

+ 2 - 1
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Handlers/IDocument.cs

@@ -8,6 +8,7 @@ using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface.Vector;
 using PixiEditor.Extensions.Palettes;
+using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.DocumentModels.Public;
 using PixiEditor.Models.Enums;
@@ -16,7 +17,7 @@ namespace PixiEditor.Models.Containers;
 
 internal interface IDocument : IHandler
 {
-    public ObservableCollection<PaletteColor> Palette { get; set; }
+    public ObservableRangeCollection<PaletteColor> Palette { get; set; }
     public VecI SizeBindable { get; }
     public IStructureMemberHandler? SelectedStructureMember { get; }
     public IReferenceLayerHandler ReferenceLayerHandler { get; }

+ 1 - 1
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/IO/Exporter.cs

@@ -185,7 +185,7 @@ internal class Exporter
                 bitmap.DrawingSurface.Canvas.DrawColor(Colors.White, DrawingApi.Core.Surface.BlendMode.Multiply);
 
             using var stream = new FileStream(savePath, FileMode.Create);
-            encoder.Save(stream, bitmap);
+            encoder.SaveAsync(stream, bitmap);
         }
         catch (SecurityException)
         {

+ 2 - 1
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/IO/FileEncoders/IFileEncoder.cs

@@ -7,5 +7,6 @@ namespace PixiEditor.Models.IO.FileEncoders;
 public interface IFileEncoder
 {
     public bool SupportsTransparency { get; }
-    public Task Save(Stream stream, Surface bitmap);
+    public Task SaveAsync(Stream stream, Surface bitmap);
+    public void Save(Stream stream, Surface bitmap);
 }

+ 6 - 1
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/IO/FileEncoders/UniversalFileEncoder.cs

@@ -17,11 +17,16 @@ public class UniversalFileEncoder : IFileEncoder
         SupportsTransparency = FormatSupportsTransparency(format);
     }
 
-    public async Task Save(Stream stream, Surface bitmap)
+    public async Task SaveAsync(Stream stream, Surface bitmap)
     {
         await bitmap.DrawingSurface.Snapshot().Encode(Format).AsStream().CopyToAsync(stream);
     }
 
+    public void Save(Stream stream, Surface bitmap)
+    {
+        bitmap.DrawingSurface.Snapshot().Encode(Format).AsStream().CopyTo(stream);
+    }
+
     private bool FormatSupportsTransparency(EncodedImageFormat format)
     {
         switch (format)

+ 38 - 0
src/PixiEditor.Avalonia/PixiEditor.Avalonia/Models/Structures/ObservableRangeCollection.cs

@@ -0,0 +1,38 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.Linq;
+
+namespace PixiEditor.Models.DataHolders;
+
+public class ObservableRangeCollection<T> : ObservableCollection<T>
+{
+    public ObservableRangeCollection()
+    {
+    }
+
+    public ObservableRangeCollection(IEnumerable<T> collection) : base(collection)
+    {
+    }
+
+    public void AddRange(IEnumerable<T> collection)
+    {
+        foreach (var i in collection)
+        {
+            Items.Add(i);
+        }
+
+        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, collection.ToList()));
+    }
+
+    public void ReplaceRange(IEnumerable<T> collection)
+    {
+        Items.Clear();
+        foreach (var i in collection)
+        {
+            Items.Add(i);
+        }
+
+        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+    }
+}

+ 6 - 4
src/PixiEditor.Avalonia/PixiEditor.Avalonia/ViewModels/Document/DocumentViewModel.Serialization.cs

@@ -3,15 +3,18 @@ using System.Collections.ObjectModel;
 using System.Drawing;
 using System.IO;
 using System.Linq;
+using System.Threading.Tasks;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using PixiEditor.Extensions.Palettes;
 using PixiEditor.Helpers;
 using PixiEditor.Helpers.Extensions;
+using PixiEditor.Models.IO.FileEncoders;
 using PixiEditor.Parser;
 using PixiEditor.Parser.Collections;
 using BlendMode = PixiEditor.Parser.BlendMode;
@@ -41,7 +44,7 @@ internal partial class DocumentViewModel
         return document;
     }
 
-    private static ReferenceLayer GetReferenceLayer(IReadOnlyDocument document)
+    private static ReferenceLayer? GetReferenceLayer(IReadOnlyDocument document)
     {
         if (document.ReferenceLayer == null)
         {
@@ -54,12 +57,11 @@ internal partial class DocumentViewModel
         
         surface.DrawBytes(surface.Size, layer.ImagePbgra32Bytes.ToArray(), ColorType.Bgra8888, AlphaType.Premul);
 
-        var encoder = new PngBitmapEncoder();
+        var encoder = new UniversalFileEncoder(EncodedImageFormat.Png);
 
         using var stream = new MemoryStream();
         
-        encoder.Frames.Add(BitmapFrame.Create(surface.ToWriteableBitmap()));
-        encoder.Save(stream);
+        encoder.Save(stream, surface);
 
         stream.Position = 0;
 

+ 2 - 2
src/PixiEditor.Avalonia/PixiEditor.Avalonia/ViewModels/Document/DocumentViewModel.cs

@@ -151,7 +151,7 @@ internal partial class DocumentViewModel : ObservableObject, IDocument
     private VectorPath selectionPath = new VectorPath();
     public VectorPath SelectionPathBindable => selectionPath;
     public ObservableCollection<PaletteColor> Swatches { get; set; } = new(); // TODO: Replaced WPFObservableCollection, make sure it works
-    public ObservableCollection<PaletteColor> Palette { get; set; } = new(); // TODO: Same
+    public ObservableRangeCollection<PaletteColor> Palette { get; set; } = new(); // TODO: Same
     public DocumentTransformViewModel TransformViewModel { get; }
     public ReferenceLayerViewModel ReferenceLayerViewModel { get; }
     public LineToolOverlayViewModel LineToolOverlayViewModel { get; }
@@ -227,7 +227,7 @@ internal partial class DocumentViewModel : ObservableObject, IDocument
         }
 
         viewModel.Swatches = new ObservableCollection<PaletteColor>(builderInstance.Swatches);
-        viewModel.Palette = new ObservableCollection<PaletteColor>(builderInstance.Palette);
+        viewModel.Palette = new ObservableRangeCollection<PaletteColor>(builderInstance.Palette);
 
         AddMembers(viewModel.StructureRoot.GuidValue, builderInstance.Children);
 

+ 1 - 1
src/PixiEditor.Avalonia/PixiEditor.Avalonia/ViewModels/SubViewModels/ColorsViewModel.cs

@@ -165,7 +165,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
         if (lospecPaletteArg != null)
         {
             var browser = PalettesBrowser.Open(PaletteProvider, ImportPaletteCommand,
-                new WpfObservableRangeCollection<PaletteColor>());
+                new ObservableRangeCollection<PaletteColor>());
 
             browser.IsFetching = true;
             var palette = await LospecPaletteFetcher.FetchPalette(lospecPaletteArg.Split(@"://")[1].Replace("/", ""));

+ 9 - 8
src/PixiEditor.Avalonia/PixiEditor.Avalonia/ViewModels/ViewModelMain.cs

@@ -1,5 +1,6 @@
 using System.ComponentModel;
 using System.Linq;
+using System.Threading.Tasks;
 using CommunityToolkit.Mvvm.Input;
 using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.Avalonia.ViewModels;
@@ -164,14 +165,14 @@ internal partial class ViewModelMain : ViewModelBase
     }
 
     [RelayCommand]
-    public void CloseWindow(object property)
+    public async Task CloseWindow(object property)
     {
         if (!(property is CancelEventArgs))
         {
             throw new ArgumentException();
         }
 
-        ((CancelEventArgs)property).Cancel = !DisposeAllDocumentsWithSaveConfirmation();
+        ((CancelEventArgs)property).Cancel = !await DisposeAllDocumentsWithSaveConfirmation();
     }
 
     private void ToolsSubViewModel_SelectedToolChanged(object sender, SelectedToolEventArgs e)
@@ -200,13 +201,13 @@ internal partial class ViewModelMain : ViewModelBase
     /// Closes documents with unsaved changes confirmation dialog.
     /// </summary>
     /// <returns>If documents was removed successfully.</returns>
-    private bool DisposeAllDocumentsWithSaveConfirmation()
+    private async Task<bool> DisposeAllDocumentsWithSaveConfirmation()
     {
         int docCount = DocumentManagerSubViewModel.Documents.Count;
         for (int i = 0; i < docCount; i++)
         {
             WindowSubViewModel.MakeDocumentViewportActive(DocumentManagerSubViewModel.Documents.First());
-            bool canceled = !DisposeActiveDocumentWithSaveConfirmation();
+            bool canceled = !await DisposeActiveDocumentWithSaveConfirmation();
             if (canceled)
             {
                 return false;
@@ -220,14 +221,14 @@ internal partial class ViewModelMain : ViewModelBase
     /// Disposes the active document after showing the unsaved changes confirmation dialog.
     /// </summary>
     /// <returns>If the document was closed successfully.</returns>
-    public bool DisposeActiveDocumentWithSaveConfirmation()
+    public async Task<bool> DisposeActiveDocumentWithSaveConfirmation()
     {
         if (DocumentManagerSubViewModel.ActiveDocument is null)
             return false;
-        return DisposeDocumentWithSaveConfirmation(DocumentManagerSubViewModel.ActiveDocument);
+        return await DisposeDocumentWithSaveConfirmation(DocumentManagerSubViewModel.ActiveDocument);
     }
 
-    public bool DisposeDocumentWithSaveConfirmation(DocumentViewModel document)
+    public async Task<bool> DisposeDocumentWithSaveConfirmation(DocumentViewModel document)
     {
         const string ConfirmationDialogTitle = "UNSAVED_CHANGES";
         const string ConfirmationDialogMessage = "DOCUMENT_MODIFIED_SAVE";
@@ -238,7 +239,7 @@ internal partial class ViewModelMain : ViewModelBase
             result = ConfirmationDialog.Show(ConfirmationDialogMessage, ConfirmationDialogTitle);
             if (result == ConfirmationType.Yes)
             {
-                if (!FileSubViewModel.SaveDocument(document, false))
+                if (!await FileSubViewModel.SaveDocument(document, false))
                     return false;
             }
         }