Sfoglia il codice sorgente

Fixed duplicate event subscribing

Krzysztof Krysiński 3 mesi fa
parent
commit
ebff1cabc1

+ 1 - 0
src/PixiEditor.Desktop/Program.cs

@@ -2,6 +2,7 @@
 using Avalonia;
 using Avalonia.Logging;
 using Drawie.Interop.Avalonia;
+using Drawie.Interop.VulkanAvalonia;
 
 namespace PixiEditor.Desktop;
 

+ 1 - 0
src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ElementEventArgs.cs

@@ -18,6 +18,7 @@ public class ElementEventArgs
             nameof(ToggleEventArgs) => new ToggleEventArgs(reader.ReadBool()),
             nameof(TextEventArgs) => new TextEventArgs(reader.ReadString()),
             nameof(NumberEventArgs) => new NumberEventArgs(reader.ReadDouble()),
+            nameof(ElementEventArgs) => new ElementEventArgs(),
             _ => throw new NotSupportedException($"Event type '{eventType}' is not supported.")
         };
 

+ 4 - 1
src/PixiEditor.Extensions.Sdk/Api/FlyUI/CheckBox.cs

@@ -13,9 +13,10 @@ public class CheckBox : SingleChildLayoutElement
 
     public bool IsChecked { get; set; }
 
-    public CheckBox(ILayoutElement<ControlDefinition> child = null, ElementEventHandler onCheckedChanged = null, Cursor? cursor = null) : base(cursor)
+    public CheckBox(ILayoutElement<ControlDefinition> child = null, bool isChecked = false, ElementEventHandler onCheckedChanged = null, Cursor? cursor = null) : base(cursor)
     {
         Child = child;
+        IsChecked = isChecked;
         
         if (onCheckedChanged != null)
         {
@@ -38,6 +39,8 @@ public class CheckBox : SingleChildLayoutElement
         if (Child != null)
             checkbox.AddChild(Child.BuildNative());
 
+        checkbox.AddProperty(IsChecked);
+
         return checkbox;
     }
 }

BIN
src/PixiEditor.Extensions.Sdk/build/PixiEditor.Api.CGlueMSBuild.dll


BIN
src/PixiEditor.Extensions.Sdk/build/PixiEditor.Extensions.MSPackageBuilder.dll


+ 4 - 2
src/PixiEditor.Extensions.WasmRuntime/WasmExtensionInstance.cs

@@ -77,12 +77,14 @@ public partial class WasmExtensionInstance : Extension
 
     private void OnAsyncCallCompleted(int handle, int result)
     {
-        Instance.GetAction<int, int>("async_call_completed").Invoke(handle, result);
+        Dispatcher.UIThread.Invoke(() =>
+            Instance.GetAction<int, int>("async_call_completed").Invoke(handle, result));
     }
 
     private void OnAsyncCallFaulted(int handle, string exceptionMessage)
     {
-        Instance.GetAction<int, string>("async_call_faulted").Invoke(handle, exceptionMessage);
+        Dispatcher.UIThread.Invoke(() =>
+            Instance.GetAction<int, string>("async_call_faulted").Invoke(handle, exceptionMessage));
     }
 
     private void SetElementMap()

+ 1 - 1
src/PixiEditor.Extensions/FlyUI/Elements/Border.cs

@@ -106,9 +106,9 @@ public class Border : SingleChildLayoutElement
         yield return CornerRadius;
         yield return Padding;
         yield return Margin;
-        yield return BackgroundColor;
         yield return Width;
         yield return Height;
+        yield return BackgroundColor;
     }
 
     protected override void DeserializeControlProperties(List<object> values)

+ 20 - 1
src/PixiEditor.Extensions/FlyUI/Elements/CheckBox.cs

@@ -6,20 +6,29 @@ namespace PixiEditor.Extensions.FlyUI.Elements;
 
 public class CheckBox : SingleChildLayoutElement
 {
-    private Avalonia.Controls.CheckBox checkbox;    
+    private bool isChecked;
+    private Avalonia.Controls.CheckBox checkbox;
+
     public event ElementEventHandler<ToggleEventArgs> CheckedChanged
     {
         add => AddEvent(nameof(CheckedChanged), value);
         remove => RemoveEvent(nameof(CheckedChanged), value);
     }
 
+    public bool IsChecked { get => isChecked; set => SetField(ref isChecked, value); }
     protected override Control CreateNativeControl()
     {
         checkbox = new Avalonia.Controls.CheckBox();
+
         Binding binding =
             new Binding(nameof(Child)) { Source = this, Converter = LayoutElementToNativeControlConverter.Instance };
         checkbox.Bind(ContentControl.ContentProperty, binding);
 
+        Binding isCheckedBinding =
+            new Binding(nameof(IsChecked)) { Source = this, Mode = BindingMode.TwoWay };
+
+        checkbox.Bind(Avalonia.Controls.CheckBox.IsCheckedProperty, isCheckedBinding);
+
         checkbox.IsCheckedChanged += (sender, args) => RaiseEvent(
             nameof(CheckedChanged),
             new ToggleEventArgs((sender as Avalonia.Controls.CheckBox).IsChecked.Value) { Sender = this });
@@ -36,4 +45,14 @@ public class CheckBox : SingleChildLayoutElement
     {
         checkbox.Content = null;
     }
+
+    protected override IEnumerable<object> GetControlProperties()
+    {
+        yield return IsChecked;
+    }
+
+    protected override void DeserializeControlProperties(List<object> values)
+    {
+        IsChecked = (bool)values[0];
+    }
 }

+ 20 - 1
src/PixiEditor.Extensions/FlyUI/Elements/LayoutElement.cs

@@ -56,7 +56,8 @@ public abstract class LayoutElement : ILayoutElement<Control>, INotifyPropertyCh
     {
         if (Cursor != null)
         {
-            control.Cursor = new Avalonia.Input.Cursor((StandardCursorType)(Cursor.Value.BuiltInCursor ?? BuiltInCursor.None));
+            control.Cursor =
+                new Avalonia.Input.Cursor((StandardCursorType)(Cursor.Value.BuiltInCursor ?? BuiltInCursor.None));
         }
 
         SubscribeBasicEvents(control);
@@ -88,6 +89,15 @@ public abstract class LayoutElement : ILayoutElement<Control>, INotifyPropertyCh
             _events.Add(eventName, new List<ElementEventHandler>());
         }
 
+        // I'm unsure if it's a correct solution, it prevents resubscription of the same event during
+        // state change. If event count for the same name is bigger than 1, the same event will be called
+        // twice in extension, it won't resolve correct handle within the extension.
+        // TODO: Research if it's a correct solution
+        if (_events[eventName].Count > 0)
+        {
+            _events[eventName].Clear();
+        }
+
         _events[eventName].Add(eventHandler);
     }
 
@@ -103,6 +113,15 @@ public abstract class LayoutElement : ILayoutElement<Control>, INotifyPropertyCh
             _events.Add(eventName, new List<ElementEventHandler>());
         }
 
+        // I'm unsure if it's a correct solution, it prevents resubscription of the same event during
+        // state change. If event count for the same name is bigger than 1, the same event will be called
+        // twice in extension, it won't resolve correct handle within the extension.
+        // TODO: Research if it's a correct solution
+        if (_events[eventName].Count > 0)
+        {
+            _events[eventName].Clear();
+        }
+
         _events[eventName].Add((args => eventHandler((T)args)));
     }
 

+ 29 - 6
src/PixiEditor.Extensions/FlyUI/Elements/SizeInputField.cs

@@ -7,17 +7,29 @@ namespace PixiEditor.Extensions.FlyUI.Elements;
 
 public class SizeInputField : LayoutElement
 {
+    private double value;
+    private double min = 1;
+    private double max;
+    private int decimals;
+    private string unit;
+
     public event ElementEventHandler<NumberEventArgs> SizeChanged
     {
         add => AddEvent(nameof(SizeChanged), value);
         remove => RemoveEvent(nameof(SizeChanged), value);
     }
 
-    public double Value { get; set; }
-    public double Min { get; set; } = 1;
-    public double Max { get; set; }
-    public int Decimals { get; set; }
-    public string Unit { get; set; }
+    public double Value
+    {
+        get => value;
+        set => SetField(ref this.value, value, nameof(Value));
+    }
+    public double Min { get => min; set => SetField(ref min, value); }
+    public double Max { get => max; set => SetField(ref max, value); }
+    public int Decimals { get => decimals; set => SetField(ref decimals, value); }
+    public string Unit { get => unit; set => SetField(ref unit, value); }
+
+    private bool suppressSizeChanged;
 
     protected override Control CreateNativeControl()
     {
@@ -29,7 +41,7 @@ public class SizeInputField : LayoutElement
 
         sizeInput.PropertyChanged += (sender, args) =>
         {
-            if (args.Property != SizeInput.SizeProperty) return;
+            if (args.Property != SizeInput.SizeProperty || suppressSizeChanged) return;
 
             Value = sizeInput.Size;
             RaiseEvent(nameof(SizeChanged), new NumberEventArgs(Value));
@@ -38,12 +50,23 @@ public class SizeInputField : LayoutElement
         return sizeInput;
     }
 
+    protected override IEnumerable<object> GetControlProperties()
+    {
+        yield return Value;
+        yield return Min;
+        yield return Max;
+        yield return Decimals;
+        yield return Unit;
+    }
+
     protected override void DeserializeControlProperties(List<object> values)
     {
+        suppressSizeChanged = true;
         Value = (double)values[0];
         Min = (double)values[1];
         Max = (double)values[2];
         Decimals = (int)values[3];
         Unit = (string)values[4];
+        suppressSizeChanged = false;
     }
 }

+ 7 - 1
src/PixiEditor.Extensions/FlyUI/Elements/TextField.cs

@@ -6,13 +6,14 @@ namespace PixiEditor.Extensions.FlyUI.Elements;
 
 internal class TextField : LayoutElement
 {
+    private string text;
     public event ElementEventHandler TextChanged
     {
         add => AddEvent(nameof(TextChanged), value);
         remove => RemoveEvent(nameof(TextChanged), value);
     }
 
-    public string Text { get; set; }
+    public string Text { get => text; set => SetField(ref text, value); }
 
     public TextField(string text)
     {
@@ -35,6 +36,11 @@ internal class TextField : LayoutElement
         return textBox;
     }
 
+    protected override IEnumerable<object> GetControlProperties()
+    {
+        yield return Text;
+    }
+
     protected override void DeserializeControlProperties(List<object> values)
     {
         Text = (string)values[0];

+ 1 - 0
src/PixiEditor.Extensions/UI/Panels/ColumnPanel.cs

@@ -57,6 +57,7 @@ public class ColumnPanel : Panel
             or MainAxisAlignment.SpaceEvenly;
         double spaceBetween = 0;
         double spaceBeforeAfter = 0;
+
         if (stretchPlacement)
         {
             double freeSpace = finalSize.Height - totalYSpace;

+ 2 - 2
src/PixiEditor/App.axaml

@@ -3,7 +3,7 @@
              xmlns:themes="clr-namespace:PixiEditor.UI.Common.Themes;assembly=PixiEditor.UI.Common"
              xmlns:avaloniaUi="clr-namespace:PixiEditor"
              xmlns:avalonia="clr-namespace:PixiDocks.Avalonia;assembly=PixiDocks.Avalonia"
-             xmlns:templates="clr-namespace:ColorPicker.Templates;assembly=ColorPicker.AvaloniaUI"
+             xmlns:templates1="clr-namespace:ColorPicker.AvaloniaUI.Templates;assembly=ColorPicker.AvaloniaUI"
              x:Class="PixiEditor.App"
              Name="PixiEditor"
              RequestedThemeVariant="Dark">
@@ -14,7 +14,7 @@
     <Application.Styles>
         <themes:PixiEditorTheme />
         <avalonia:PixiDockSimpleTheme />
-        <templates:PixiPerfectColorPickerTheme />
+        <templates1:PixiPerfectColorPickerTheme />
         <StyleInclude Source="/Styles/PixiEditor.Controls.axaml" />
         <StyleInclude Source="/Styles/PixiEditor.Animators.axaml" />
         <StyleInclude Source="/Styles/PixiEditor.Handles.axaml" />

+ 1 - 0
src/PixiEditor/Models/ExtensionServices/DocumentProvider.cs

@@ -1,3 +1,4 @@
+using Avalonia.Threading;
 using PixiEditor.Extensions.CommonApi.Documents;
 using PixiEditor.Extensions.CommonApi.IO;
 using PixiEditor.Models.IO;

+ 1 - 1
tests/PixiEditor.Extensions.Tests/LayoutBuilderTests.cs

@@ -17,7 +17,7 @@ public class LayoutBuilderTests
         bool callbackFired = false;
 
         button.Click += (e) => callbackFired = true;
-        button.RaiseEvent(nameof(Button.Click), ElementEventArgs.Empty);
+        button.RaiseEvent(nameof(Button.Click), new ElementEventArgs());
 
         Assert.True(callbackFired);
     }