Browse Source

Serialization Improvements

Krzysztof Krysiński 1 year ago
parent
commit
8c85d17ee1

+ 13 - 10
src/PixiEditor.DevTools/Layouts/LivePreviewWindowState.cs

@@ -21,15 +21,17 @@ public class LivePreviewWindowState : State
 
     public override LayoutElement BuildElement()
     {
-        return new Align(
-            alignment: Alignment.TopLeft,
-            child: new Column(
-                new Button(
-                    child: SelectedProjectFile != null ? new Text($"Selected extension: {SelectedProjectFile}") : new Text("Select extension"),
-                    onClick: OnClick),
-                _element ?? new Text("No layout element selected")
-                )
-            );
+        return new Column(
+            new Align(
+                alignment: Alignment.TopLeft,
+                child: new Button(
+                    child: SelectedProjectFile != null
+                        ? new Text($"Selected extension: {SelectedProjectFile}")
+                        : new Text("Select extension"),
+                    onClick: OnClick)),
+            new Center(
+                child: _element ?? new Text("No layout element selected"))
+        );
     }
 
     private void OnFileChanged(string obj)
@@ -47,7 +49,8 @@ public class LivePreviewWindowState : State
 
     private void OnClick(ElementEventArgs args)
     {
-        if (DevToolsExtension.PixiEditorApi.FileSystem.OpenFileDialog(new FileFilter().AddFilter("Layout file", "*.layout"), out string? path))
+        if (DevToolsExtension.PixiEditorApi.FileSystem.OpenFileDialog(
+                new FileFilter().AddFilter("Layout file", "*.layout"), out string? path))
         {
             SetState(() =>
             {

+ 22 - 3
src/PixiEditor.Extensions.MSBuildLayoutCompiler/Program.cs

@@ -8,7 +8,7 @@ Console.WriteLine($"Building layouts from path: {Path.GetFullPath(assemblyPath)}
 Assembly assembly = Assembly.LoadFrom(assemblyPath);
 var exportedTypes = assembly.GetExportedTypes();
 
-exportedTypes.Where(x => IsLayoutElement(x)).ToList().ForEach(x =>
+exportedTypes.Where(IsLayoutElement).ToList().ForEach(x =>
 {
     string path = Path.Combine(outputPath, x.Name + ".layout");
     if(Directory.Exists(outputPath) == false)
@@ -22,7 +22,8 @@ exportedTypes.Where(x => IsLayoutElement(x)).ToList().ForEach(x =>
 
 byte[] GenerateLayoutFile(Type type)
 {
-    object instance = Activator.CreateInstance(type);
+    Console.WriteLine($"Generating layout for {type.Name}");
+    object instance = Activator.CreateInstance(type, TryGetConstructorArgs(type));
     MethodInfo buildNativeMethod = type.GetMethod("BuildNative");
     var compiled = buildNativeMethod.Invoke(instance, null);
     object bytesArray = compiled.GetType().GetMethod("SerializeBytes").Invoke(compiled, null);
@@ -33,7 +34,25 @@ byte[] GenerateLayoutFile(Type type)
 bool IsLayoutElement(Type type)
 {
     if(type.BaseType == null) return false;
-    if(type.BaseType.Name.Contains("LayoutElement")) return true;
+    if(type.BaseType.Name.Contains("StatefulElement") || type.BaseType.Name.Contains("StatelessElement")) return true;
 
     return IsLayoutElement(type.BaseType);
 }
+
+object?[] TryGetConstructorArgs(Type handler)
+{
+    ConstructorInfo[] constructors = handler.GetConstructors();
+    if (constructors.Length == 0)
+    {
+        return Array.Empty<object>();
+    }
+
+    ConstructorInfo constructor = constructors[0];
+    ParameterInfo[] parameters = constructor.GetParameters();
+    if (parameters.Length == 0)
+    {
+        return Array.Empty<object>();
+    }
+
+    return parameters.Select(x => x.ParameterType.IsValueType ? Activator.CreateInstance(x.ParameterType) : null).ToArray();
+}

+ 3 - 3
src/PixiEditor.Extensions.Wasm.Tests/NativeControlSerializationTest.cs

@@ -10,7 +10,7 @@ public class NativeControlSerializationTest
     public void TestThatNoChildLayoutSerializesCorrectBytes()
     {
         CompiledControl layout = new CompiledControl(0, "Layout");
-        layout.AddProperty("Title");
+        layout.AddProperty("Title", typeof(string));
 
         int uniqueId = 0;
         byte[] uniqueIdBytes = BitConverter.GetBytes(uniqueId);
@@ -93,7 +93,7 @@ public class NativeControlSerializationTest
         CompiledControl layout = new CompiledControl(0, "Layout");
         CompiledControl center = new CompiledControl(1, "Center");
         CompiledControl text = new CompiledControl(2, "Text");
-        text.AddProperty("Hello world");
+        text.AddProperty("Hello world", typeof(string));
         center.AddChild(text);
         layout.AddChild(center);
 
@@ -182,7 +182,7 @@ public class NativeControlSerializationTest
 
         Assert.Equal("Text", compiledControl.Children[0].Children[0].ControlTypeId);
         Assert.Single(compiledControl.Children[0].Children[0].Properties);
-        Assert.Equal("hello sexy.", compiledControl.Children[0].Children[0].Properties[0]);
+        Assert.Equal("hello sexy.", compiledControl.Children[0].Children[0].Properties[0].value);
     }
 
     [Fact]

+ 1 - 1
src/PixiEditor.Extensions.Wasm/Api/LayoutBuilding/Column.cs

@@ -5,7 +5,7 @@ public class Column : MultiChildLayoutElement
     public override CompiledControl BuildNative()
     {
         CompiledControl control = new CompiledControl(UniqueId, "Column");
-        control.Children.AddRange(Children.Select(x => x.BuildNative()));
+        control.Children.AddRange(Children.Where(x => x != null).Select(x => x.BuildNative()));
 
         return control;
     }

+ 10 - 9
src/PixiEditor.Extensions.Wasm/Api/LayoutBuilding/CompiledControl.cs

@@ -6,7 +6,7 @@ namespace PixiEditor.Extensions.Wasm.Api.LayoutBuilding;
 public class CompiledControl
 {
     public string ControlTypeId { get; set; }
-    public List<object> Properties { get; set; } = new();
+    public List<(object value, Type type)> Properties { get; set; } = new();
     public List<CompiledControl> Children { get; set; } = new();
     public int UniqueId { get; set; }
     internal List<string> QueuedEvents => _buildQueuedEvents;
@@ -20,12 +20,12 @@ public class CompiledControl
 
     public void AddProperty<T>(T value) where T : unmanaged
     {
-        Properties.Add(value);
+        Properties.Add((value, typeof(T)));
     }
 
-    public void AddProperty(string value)
+    public void AddProperty(string value, Type type)
     {
-        Properties.Add(value);
+        Properties.Add((value, type));
     }
 
     public void AddChild(CompiledControl child)
@@ -73,13 +73,13 @@ public class CompiledControl
         var result = new List<byte>();
         foreach (var property in Properties)
         {
-            result.Add(ByteMap.GetTypeByteId(property.GetType()));
-            if (property is string str)
+            result.Add(ByteMap.GetTypeByteId(property.type));
+            if (property.type == typeof(string))
             {
-                result.AddRange(BitConverter.GetBytes(str.Length));
+                result.AddRange(BitConverter.GetBytes(property.value is string s ? s.Length : 0));
             }
 
-            result.AddRange(property switch
+            result.AddRange(property.value switch
             {
                 int i => BitConverter.GetBytes(i),
                 float f => BitConverter.GetBytes(f),
@@ -90,7 +90,8 @@ public class CompiledControl
                 byte b => new byte[] { b },
                 char c => BitConverter.GetBytes(c),
                 string s => Encoding.UTF8.GetBytes(s),
-                _ => throw new Exception($"Unknown unmanaged type: {property.GetType()}")
+                null => Array.Empty<byte>(),
+                _ => throw new Exception($"Unknown unmanaged type: {property.value.GetType()}")
             });
         }
 

+ 1 - 1
src/PixiEditor.Extensions.Wasm/Api/LayoutBuilding/Text.cs

@@ -9,7 +9,7 @@ public class Text(string value) : StatelessElement
     public override CompiledControl BuildNative()
     {
         CompiledControl text = new CompiledControl(UniqueId, "Text");
-        text.AddProperty(Value);
+        text.AddProperty(Value, typeof(string));
 
         BuildPendingEvents(text);
         return text;

+ 1 - 1
src/PixiEditor.Extensions.Wasm/build/PixiEditor.Extensions.Wasm.targets

@@ -5,7 +5,7 @@
   </ItemGroup>
 
   <Target Name="GenerateLayouts" AfterTargets="Build" Inputs="bin\Debug\$(TargetFramework)\PixiEditor.Extensions.Wasm.dll" Outputs="$(RootFolder)\Layouts\">
-    <Exec ConsoleToMSBuild="true"
+    <Exec  ConsoleToMSBuild="true"
           Command="..\PixiEditor.Extensions.MSBuildLayoutCompiler\bin\Debug\net8.0\PixiEditor.Extensions.MSBuildLayoutCompiler.exe $(OutputPath)\$(MSBuildProjectName).dll $(OutputPath)\Layouts\"/>
   </Target>
 

+ 1 - 1
src/PixiEditor.Extensions/LayoutBuilding/Elements/Center.cs

@@ -42,7 +42,7 @@ public class Center : SingleChildLayoutElement
         panel = new Panel()
         {
             HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
-            VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center
+            VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
         };
 
         if (Child != null)