diff --git a/samples/PixiEditorExtensionSamples.sln b/samples/PixiEditorExtensionSamples.sln
index 1f4c38cc1..b62328642 100644
--- a/samples/PixiEditorExtensionSamples.sln
+++ b/samples/PixiEditorExtensionSamples.sln
@@ -25,6 +25,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample8_Commands", "Sample8
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample8_CommandLibrary", "Sample8_CommandLibrary\Sample8_CommandLibrary.csproj", "{3559A288-DF82-4429-B23C-CFF9E55B372E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample9_Document", "Sample9_Document\Sample9_Document.csproj", "{E018D2C3-2DD7-4BC7-AAAF-91DA949789E4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -74,6 +76,10 @@ Global
{3559A288-DF82-4429-B23C-CFF9E55B372E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3559A288-DF82-4429-B23C-CFF9E55B372E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3559A288-DF82-4429-B23C-CFF9E55B372E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E018D2C3-2DD7-4BC7-AAAF-91DA949789E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E018D2C3-2DD7-4BC7-AAAF-91DA949789E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E018D2C3-2DD7-4BC7-AAAF-91DA949789E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E018D2C3-2DD7-4BC7-AAAF-91DA949789E4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{FD9B4C32-4D2E-410E-BC6B-787779BEB6E2} = {7CC35BC4-829F-4EF4-8EB6-E1D46206E7DC}
diff --git a/samples/Sample7_FlyUI/WindowContentElement.cs b/samples/Sample7_FlyUI/WindowContentElement.cs
index 985ab2275..eec1be6a9 100644
--- a/samples/Sample7_FlyUI/WindowContentElement.cs
+++ b/samples/Sample7_FlyUI/WindowContentElement.cs
@@ -7,13 +7,20 @@ using PixiEditor.Extensions.Sdk.Api.Window;
namespace FlyUISample;
-[SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1118:Parameter should not span multiple lines", Justification = "FlyUI style")]
+[SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1118:Parameter should not span multiple lines",
+ Justification = "FlyUI style")]
public class WindowContentElement : StatelessElement
{
public PopupWindow Window { get; set; }
public override ControlDefinition BuildNative()
{
+ SizeInputField field = new SizeInputField();
+ field.SizeChanged += args =>
+ {
+ PixiEditorExtension.Api.Logger.Log(field.Value.ToString());
+ };
+
Layout layout = new Layout(body:
new Container(margin: Edges.All(25), child:
new Column(
@@ -29,7 +36,8 @@ public class WindowContentElement : StatelessElement
),
new Align(
alignment: Alignment.CenterRight,
- child: new Text("- Paulo Coelho, The Alchemist (1233)", textStyle: new TextStyle(fontStyle: FontStyle.Italic))
+ child: new Text("- Paulo Coelho, The Alchemist (1233)",
+ textStyle: new TextStyle(fontStyle: FontStyle.Italic))
),
new Container(
margin: Edges.Symmetric(25, 0),
@@ -47,6 +55,7 @@ public class WindowContentElement : StatelessElement
? "Checked"
: "Unchecked");
}),
+ field,
new Center(
new Button(
child: new Text("Close"), onClick: _ => { Window.Close(); }))
@@ -57,5 +66,4 @@ public class WindowContentElement : StatelessElement
return layout.BuildNative();
}
-
}
\ No newline at end of file
diff --git a/samples/Sample9_Document/CommandsSampleExtension.cs b/samples/Sample9_Document/CommandsSampleExtension.cs
new file mode 100644
index 000000000..91d900d64
--- /dev/null
+++ b/samples/Sample9_Document/CommandsSampleExtension.cs
@@ -0,0 +1,24 @@
+using PixiEditor.Extensions.CommonApi.Commands;
+using PixiEditor.Extensions.Sdk;
+
+namespace Sample9_Commands;
+
+public class CommandsSampleExtension : PixiEditorExtension
+{
+ ///
+ /// This method is called when extension is loaded.
+ /// All extensions are first loaded and then initialized. This method is called before .
+ ///
+ public override void OnLoaded()
+ {
+ }
+
+ ///
+ /// This method is called when extension is initialized. After this method is called, you can use Api property to access PixiEditor API.
+ ///
+ public override void OnInitialized()
+ {
+ var doc = Api.Documents.ImportFile("Resources/cs.png", true); // Open file from the extension resources
+ doc?.Resize(128, 128); // Resizes whole document
+ }
+}
\ No newline at end of file
diff --git a/samples/Sample9_Document/Program.cs b/samples/Sample9_Document/Program.cs
new file mode 100644
index 000000000..24b96b2e0
--- /dev/null
+++ b/samples/Sample9_Document/Program.cs
@@ -0,0 +1,8 @@
+namespace Sample9_Commands;
+
+public static class Program
+{
+ public static void Main()
+ {
+ }
+}
\ No newline at end of file
diff --git a/samples/Sample9_Document/Resources/cs.png b/samples/Sample9_Document/Resources/cs.png
new file mode 100644
index 000000000..518a64bc0
Binary files /dev/null and b/samples/Sample9_Document/Resources/cs.png differ
diff --git a/samples/Sample9_Document/Sample9_Document.csproj b/samples/Sample9_Document/Sample9_Document.csproj
new file mode 100644
index 000000000..171adb632
--- /dev/null
+++ b/samples/Sample9_Document/Sample9_Document.csproj
@@ -0,0 +1,45 @@
+
+
+
+ net8.0
+ wasi-wasm
+ Exe
+ true
+ true
+ true
+ ..\..\src\PixiEditor.Desktop\bin\Debug\net8.0\Extensions
+ false
+ false
+ Sample9_Commands
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
diff --git a/samples/Sample9_Document/extension.json b/samples/Sample9_Document/extension.json
new file mode 100644
index 000000000..6433016c0
--- /dev/null
+++ b/samples/Sample9_Document/extension.json
@@ -0,0 +1,44 @@
+{
+ "displayName": "Sample Extension - Document",
+ "uniqueName": "yourCompany.Samples.Document",
+ "description": "Sample Document extension for PixiEditor",
+ "version": "1.0.0",
+ "localization": {
+ "languages": [
+ {
+ "name": "English",
+ "code": "en",
+ "localeFileName": "Localization/en.json"
+ },
+ {
+ "name": "Polish",
+ "code": "pl",
+ "localeFileName": "Localization/pl.json"
+ }
+ ]
+ },
+ "author": {
+ "name": "PixiEditor",
+ "email": "info@pixieditor.net",
+ "website": "https://pixieditor.net"
+ },
+ "publisher": {
+ "name": "PixiEditor",
+ "email": "info@pixieditor.net",
+ "website": "https://pixieditor.net"
+ },
+ "contributors": [
+ {
+ "name": "flabbet",
+ "email": "some@mail.com",
+ "website": "https://github.com/flabbet"
+ }
+ ],
+ "license": "MIT",
+ "categories": [
+ "Extension"
+ ],
+ "permissions": [
+ "OpenDocuments"
+ ]
+}
\ No newline at end of file
diff --git a/src/PixiEditor.Browser/Program.cs b/src/PixiEditor.Browser/Program.cs
index c467359ac..d5cf3031d 100644
--- a/src/PixiEditor.Browser/Program.cs
+++ b/src/PixiEditor.Browser/Program.cs
@@ -2,10 +2,11 @@
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Browser;
-using PixiEditor;
[assembly: SupportedOSPlatform("browser")]
+namespace PixiEditor.Avalonia.Browser;
+
internal sealed partial class Program
{
private static Task Main(string[] args) => BuildAvaloniaApp()
@@ -13,4 +14,4 @@ internal sealed partial class Program
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure();
-}
+}
\ No newline at end of file
diff --git a/src/PixiEditor.ChangeableDocument/ChangeInfos/Root/ReferenceLayerChangeInfos/SetReferenceLayer_ChangeInfo.cs b/src/PixiEditor.ChangeableDocument/ChangeInfos/Root/ReferenceLayerChangeInfos/SetReferenceLayer_ChangeInfo.cs
index 5b41c6ec2..693d21140 100644
--- a/src/PixiEditor.ChangeableDocument/ChangeInfos/Root/ReferenceLayerChangeInfos/SetReferenceLayer_ChangeInfo.cs
+++ b/src/PixiEditor.ChangeableDocument/ChangeInfos/Root/ReferenceLayerChangeInfos/SetReferenceLayer_ChangeInfo.cs
@@ -2,6 +2,6 @@
using Drawie.Backend.Core.Numerics;
using Drawie.Numerics;
-namespace PixiEditor.ChangeableDocument.ChangeInfos.Structure;
+namespace PixiEditor.ChangeableDocument.ChangeInfos.Root.ReferenceLayerChangeInfos;
public record class SetReferenceLayer_ChangeInfo(ImmutableArray ImagePbgra8888Bytes, VecI ImageSize, ShapeCorners Shape) : IChangeInfo;
diff --git a/src/PixiEditor.Desktop/Program.cs b/src/PixiEditor.Desktop/Program.cs
index 276205095..03ac8c942 100644
--- a/src/PixiEditor.Desktop/Program.cs
+++ b/src/PixiEditor.Desktop/Program.cs
@@ -1,7 +1,7 @@
using System;
using Avalonia;
using Avalonia.Logging;
-using Drawie.Interop.VulkanAvalonia;
+using Drawie.Interop.Avalonia;
namespace PixiEditor.Desktop;
diff --git a/src/PixiEditor.Extensions.CommonApi/Documents/IDocument.cs b/src/PixiEditor.Extensions.CommonApi/Documents/IDocument.cs
new file mode 100644
index 000000000..1ac1ca77e
--- /dev/null
+++ b/src/PixiEditor.Extensions.CommonApi/Documents/IDocument.cs
@@ -0,0 +1,7 @@
+namespace PixiEditor.Extensions.CommonApi.Documents;
+
+public interface IDocument
+{
+ public Guid Id { get; }
+ public void Resize(int width, int height);
+}
diff --git a/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ElementEventArgs.cs b/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ElementEventArgs.cs
index 9c3ab33ba..d91aa32f2 100644
--- a/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ElementEventArgs.cs
+++ b/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ElementEventArgs.cs
@@ -1,12 +1,44 @@
-namespace PixiEditor.Extensions.CommonApi.FlyUI.Events;
+using System.Collections;
+using PixiEditor.Extensions.CommonApi.Utilities;
+
+namespace PixiEditor.Extensions.CommonApi.FlyUI.Events;
public class ElementEventArgs
{
- public object Sender { get; set; }
- public static ElementEventArgs Empty { get; } = new ElementEventArgs();
+ public object Sender { get; set; }
+
+ public static ElementEventArgs Deserialize(byte[] data)
+ {
+ if (data == null) return new ElementEventArgs();
+
+ ByteReader reader = new ByteReader(data);
+ string eventType = reader.ReadString();
+ ElementEventArgs eventArgs = eventType switch // TODO: more generic implementation
+ {
+ nameof(ToggleEventArgs) => new ToggleEventArgs(reader.ReadBool()),
+ nameof(TextEventArgs) => new TextEventArgs(reader.ReadString()),
+ nameof(NumberEventArgs) => new NumberEventArgs(reader.ReadDouble()),
+ _ => throw new NotSupportedException($"Event type '{eventType}' is not supported.")
+ };
+
+ return eventArgs;
+ }
+
+ public byte[] Serialize()
+ {
+ ByteWriter writer = new ByteWriter();
+ writer.WriteString(GetType().Name);
+ SerializeArgs(writer);
+
+ return writer.ToArray();
+ }
+
+ protected virtual void SerializeArgs(ByteWriter writer)
+ {
+ // Default implementation does nothing. Override in derived classes to serialize specific properties.
+ }
}
public class ElementEventArgs : ElementEventArgs where TEventArgs : ElementEventArgs
{
- public static new ElementEventArgs Empty { get; } = new ElementEventArgs();
}
diff --git a/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ElementEventHandler.cs b/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ElementEventHandler.cs
index ac141ea6a..bf5dbfe88 100644
--- a/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ElementEventHandler.cs
+++ b/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ElementEventHandler.cs
@@ -1,4 +1,6 @@
namespace PixiEditor.Extensions.CommonApi.FlyUI.Events;
public delegate void ElementEventHandler(ElementEventArgs args);
-public delegate void ElementEventHandler(TEventArgs args) where TEventArgs : ElementEventArgs;
+
+public delegate void ElementEventHandler(TEventArgs args)
+ where TEventArgs : ElementEventArgs;
diff --git a/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/NumberEventArgs.cs b/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/NumberEventArgs.cs
new file mode 100644
index 000000000..698aca09f
--- /dev/null
+++ b/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/NumberEventArgs.cs
@@ -0,0 +1,19 @@
+using System.Numerics;
+using PixiEditor.Extensions.CommonApi.Utilities;
+
+namespace PixiEditor.Extensions.CommonApi.FlyUI.Events;
+
+public class NumberEventArgs : ElementEventArgs
+{
+ public double Value { get; }
+
+ public NumberEventArgs(double value)
+ {
+ Value = value;
+ }
+
+ protected override void SerializeArgs(ByteWriter writer)
+ {
+ writer.WriteDouble(Value);
+ }
+}
diff --git a/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/TextEventArgs.cs b/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/TextEventArgs.cs
new file mode 100644
index 000000000..67137a693
--- /dev/null
+++ b/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/TextEventArgs.cs
@@ -0,0 +1,19 @@
+using System.Collections;
+using PixiEditor.Extensions.CommonApi.Utilities;
+
+namespace PixiEditor.Extensions.CommonApi.FlyUI.Events;
+
+public class TextEventArgs : ElementEventArgs
+{
+ public string Text { get; set; }
+
+ public TextEventArgs(string newText)
+ {
+ Text = newText;
+ }
+
+ protected override void SerializeArgs(ByteWriter writer)
+ {
+ writer.WriteString(Text);
+ }
+}
diff --git a/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ToggleEventArgs.cs b/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ToggleEventArgs.cs
index 2d7ac49c4..02f985cf8 100644
--- a/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ToggleEventArgs.cs
+++ b/src/PixiEditor.Extensions.CommonApi/FlyUI/Events/ToggleEventArgs.cs
@@ -1,4 +1,7 @@
-namespace PixiEditor.Extensions.CommonApi.FlyUI.Events;
+using System.Collections;
+using PixiEditor.Extensions.CommonApi.Utilities;
+
+namespace PixiEditor.Extensions.CommonApi.FlyUI.Events;
public class ToggleEventArgs : ElementEventArgs
{
@@ -8,4 +11,9 @@ public class ToggleEventArgs : ElementEventArgs
{
IsToggled = isToggled;
}
+
+ protected override void SerializeArgs(ByteWriter writer)
+ {
+ writer.WriteBool(IsToggled);
+ }
}
diff --git a/src/PixiEditor.Extensions.CommonApi/IO/IDocumentProvider.cs b/src/PixiEditor.Extensions.CommonApi/IO/IDocumentProvider.cs
index 9013d9788..8fd31f7c7 100644
--- a/src/PixiEditor.Extensions.CommonApi/IO/IDocumentProvider.cs
+++ b/src/PixiEditor.Extensions.CommonApi/IO/IDocumentProvider.cs
@@ -1,6 +1,10 @@
+using PixiEditor.Extensions.CommonApi.Documents;
+
namespace PixiEditor.Extensions.CommonApi.IO;
public interface IDocumentProvider
{
- public void ImportFile(string path, bool associatePath = true);
+ public IDocument? ActiveDocument { get; }
+ public IDocument? ImportFile(string path, bool associatePath = true);
+ public IDocument? GetDocument(Guid id);
}
diff --git a/src/PixiEditor.Extensions.CommonApi/Utilities/ByteReader.cs b/src/PixiEditor.Extensions.CommonApi/Utilities/ByteReader.cs
new file mode 100644
index 000000000..ac5dcb726
--- /dev/null
+++ b/src/PixiEditor.Extensions.CommonApi/Utilities/ByteReader.cs
@@ -0,0 +1,62 @@
+namespace PixiEditor.Extensions.CommonApi.Utilities;
+
+public class ByteReader
+{
+ private byte[] _buffer;
+ private int _position;
+
+ public ByteReader(byte[] buffer)
+ {
+ _buffer = buffer;
+ _position = 0;
+ }
+
+ public byte ReadByte()
+ {
+ return _buffer[_position++];
+ }
+
+ public string ReadString()
+ {
+ int length = ReadInt();
+ string result = System.Text.Encoding.UTF8.GetString(_buffer, _position, length);
+ _position += length;
+ return result;
+ }
+
+ public int ReadInt()
+ {
+ int result = BitConverter.ToInt32(_buffer, _position);
+ _position += sizeof(int);
+ return result;
+ }
+
+ public float ReadFloat()
+ {
+ float result = BitConverter.ToSingle(_buffer, _position);
+ _position += sizeof(float);
+ return result;
+ }
+
+ public bool ReadBool()
+ {
+ bool result = BitConverter.ToBoolean(_buffer, _position);
+ _position += sizeof(bool);
+ return result;
+ }
+
+ public byte[] ReadBytes(int length)
+ {
+ byte[] result = new byte[length];
+ Array.Copy(_buffer, _position, result, 0, length);
+ _position += length;
+ return result;
+ }
+
+ public double ReadDouble()
+ {
+ double result = BitConverter.ToDouble(_buffer, _position);
+ _position += sizeof(double);
+ return result;
+ }
+}
diff --git a/src/PixiEditor.Extensions.CommonApi/Utilities/ByteWriter.cs b/src/PixiEditor.Extensions.CommonApi/Utilities/ByteWriter.cs
new file mode 100644
index 000000000..6e5aee0a3
--- /dev/null
+++ b/src/PixiEditor.Extensions.CommonApi/Utilities/ByteWriter.cs
@@ -0,0 +1,60 @@
+namespace PixiEditor.Extensions.CommonApi.Utilities;
+
+public class ByteWriter
+{
+ private List _buffer;
+ private int _position;
+
+ public ByteWriter()
+ {
+ _buffer = new List();
+ _position = 0;
+ }
+
+ public void WriteByte(byte value)
+ {
+ _buffer.Add(value);
+ _position++;
+ }
+
+ public void WriteString(string value)
+ {
+ byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes(value);
+ WriteInt(stringBytes.Length);
+ _buffer.AddRange(stringBytes);
+ }
+
+ public void WriteInt(int value)
+ {
+ byte[] intBytes = BitConverter.GetBytes(value);
+ _buffer.AddRange(intBytes);
+ }
+
+ public void WriteFloat(float value)
+ {
+ byte[] floatBytes = BitConverter.GetBytes(value);
+ _buffer.AddRange(floatBytes);
+ }
+
+ public void WriteDouble(double value)
+ {
+ byte[] doubleBytes = BitConverter.GetBytes(value);
+ _buffer.AddRange(doubleBytes);
+ }
+
+ public void WriteBool(bool value)
+ {
+ byte[] boolBytes = BitConverter.GetBytes(value);
+ _buffer.AddRange(boolBytes);
+ }
+
+ public void WriteBytes(byte[] value)
+ {
+ _buffer.AddRange(value);
+ }
+
+ public byte[] ToArray()
+ {
+ return _buffer.ToArray();
+ }
+}
diff --git a/src/PixiEditor.Extensions.Runtime/ExtensionException.cs b/src/PixiEditor.Extensions.Runtime/ExtensionException.cs
index 2251294c6..1ece4578b 100644
--- a/src/PixiEditor.Extensions.Runtime/ExtensionException.cs
+++ b/src/PixiEditor.Extensions.Runtime/ExtensionException.cs
@@ -1,5 +1,5 @@
-using PixiEditor.Extensions.Common.Localization;
-using PixiEditor.Extensions.Exceptions;
+using PixiEditor.Extensions.Exceptions;
+using PixiEditor.UI.Common.Localization;
namespace PixiEditor.Extensions.Runtime;
diff --git a/src/PixiEditor.Extensions.Sdk/Api/Documents/Document.cs b/src/PixiEditor.Extensions.Sdk/Api/Documents/Document.cs
new file mode 100644
index 000000000..f85a29b97
--- /dev/null
+++ b/src/PixiEditor.Extensions.Sdk/Api/Documents/Document.cs
@@ -0,0 +1,21 @@
+using PixiEditor.Extensions.CommonApi.Documents;
+using PixiEditor.Extensions.Sdk.Bridge;
+
+namespace PixiEditor.Extensions.Sdk.Api.Documents;
+
+public class Document : IDocument
+{
+ public Guid Id => documentId;
+ private Guid documentId;
+
+ internal Document(Guid documentId)
+ {
+ this.documentId = documentId;
+ }
+
+
+ public void Resize(int width, int height)
+ {
+ Native.resize_document(documentId.ToString(), width, height);
+ }
+}
diff --git a/src/PixiEditor.Extensions.Sdk/Api/FlyUI/LayoutElement.cs b/src/PixiEditor.Extensions.Sdk/Api/FlyUI/LayoutElement.cs
index 060fd98a8..9a4200db5 100644
--- a/src/PixiEditor.Extensions.Sdk/Api/FlyUI/LayoutElement.cs
+++ b/src/PixiEditor.Extensions.Sdk/Api/FlyUI/LayoutElement.cs
@@ -6,6 +6,8 @@ namespace PixiEditor.Extensions.Sdk.Api.FlyUI;
public abstract class LayoutElement : ILayoutElement
{
private Dictionary> _events;
+ private Dictionary<(string, Delegate), ElementEventHandler> _wrappedHandlers = new();
+
public List BuildQueuedEvents = new List();
public int UniqueId { get; set; }
@@ -74,7 +76,7 @@ public abstract class LayoutElement : ILayoutElement
BuildQueuedEvents.Add(eventName);
}
- /*public void AddEvent(string eventName, ElementEventHandler eventHandler) where TEventArgs : ElementEventArgs
+ public void AddEvent(string eventName, ElementEventHandler eventHandler) where T : ElementEventArgs
{
if (_events == null)
{
@@ -86,9 +88,12 @@ public abstract class LayoutElement : ILayoutElement
_events.Add(eventName, new List());
}
- _events[eventName].Add((args => eventHandler((TEventArgs)args)));
+ ElementEventHandler wrapped = x => eventHandler(x as T);
+
+ _wrappedHandlers.Add((eventName, eventHandler), wrapped);
+ _events[eventName].Add(wrapped);
BuildQueuedEvents.Add(eventName);
- }*/
+ }
public void RemoveEvent(string eventName, ElementEventHandler eventHandler)
{
@@ -105,7 +110,7 @@ public abstract class LayoutElement : ILayoutElement
_events[eventName].Remove(eventHandler);
}
- /*public void RemoveEvent(string eventName, ElementEventHandler eventHandler) where TEventArgs : ElementEventArgs
+ public void RemoveEvent(string eventName, ElementEventHandler eventHandler) where T : ElementEventArgs
{
if (_events == null)
{
@@ -117,8 +122,12 @@ public abstract class LayoutElement : ILayoutElement
return;
}
- _events[eventName].Remove((args => eventHandler((TEventArgs)args)));
- }*/
+ if (_wrappedHandlers.TryGetValue((eventName, eventHandler), out ElementEventHandler wrapped))
+ {
+ _wrappedHandlers.Remove((eventName, eventHandler));
+ _events[eventName].Remove(wrapped);
+ }
+ }
public void RaiseEvent(string eventName, ElementEventArgs args)
{
diff --git a/src/PixiEditor.Extensions.Sdk/Api/FlyUI/SizeInputField.cs b/src/PixiEditor.Extensions.Sdk/Api/FlyUI/SizeInputField.cs
new file mode 100644
index 000000000..437f90628
--- /dev/null
+++ b/src/PixiEditor.Extensions.Sdk/Api/FlyUI/SizeInputField.cs
@@ -0,0 +1,39 @@
+using PixiEditor.Extensions.CommonApi.FlyUI;
+using PixiEditor.Extensions.CommonApi.FlyUI.Events;
+
+namespace PixiEditor.Extensions.Sdk.Api.FlyUI;
+
+public class SizeInputField : LayoutElement
+{
+ public event ElementEventHandler SizeChanged
+ {
+ add => AddEvent(nameof(SizeChanged), value);
+ remove => RemoveEvent(nameof(SizeChanged), value);
+ }
+ public double Value { get; set; }
+ public double Min { get; set; }
+ public double Max { get; set; }
+ public int Decimals { get; set; }
+ public string Unit { get; set; }
+
+ public SizeInputField(double value = 0, double min = 1, double max = double.MaxValue, int decimals = 0, string unit = "px", Cursor? cursor = null) : base(cursor)
+ {
+ Value = value;
+ Min = min;
+ Max = max;
+ Decimals = decimals;
+ Unit = unit;
+ SizeChanged += e => Value = e.Value;
+ }
+
+ protected override ControlDefinition CreateControl()
+ {
+ ControlDefinition field = new ControlDefinition(UniqueId, "SizeInputField");
+ field.AddProperty(Value);
+ field.AddProperty(Min);
+ field.AddProperty(Max);
+ field.AddProperty(Decimals);
+ field.AddProperty(Unit);
+ return field;
+ }
+}
diff --git a/src/PixiEditor.Extensions.Sdk/Api/FlyUI/StatelessElement.cs b/src/PixiEditor.Extensions.Sdk/Api/FlyUI/StatelessElement.cs
index 576a2a71d..8ad0b3a2c 100644
--- a/src/PixiEditor.Extensions.Sdk/Api/FlyUI/StatelessElement.cs
+++ b/src/PixiEditor.Extensions.Sdk/Api/FlyUI/StatelessElement.cs
@@ -9,6 +9,10 @@ public abstract class StatelessElement : LayoutElement, IStatelessElement Build()
{
return this;
diff --git a/src/PixiEditor.Extensions.Sdk/Api/FlyUI/TextField.cs b/src/PixiEditor.Extensions.Sdk/Api/FlyUI/TextField.cs
new file mode 100644
index 000000000..f5105dc4f
--- /dev/null
+++ b/src/PixiEditor.Extensions.Sdk/Api/FlyUI/TextField.cs
@@ -0,0 +1,27 @@
+using PixiEditor.Extensions.CommonApi.FlyUI;
+using PixiEditor.Extensions.CommonApi.FlyUI.Events;
+
+namespace PixiEditor.Extensions.Sdk.Api.FlyUI;
+
+public class TextField : LayoutElement
+{
+ public event ElementEventHandler TextChanged
+ {
+ add => AddEvent(nameof(TextChanged), value);
+ remove => RemoveEvent(nameof(TextChanged), value);
+ }
+ public string Text { get; set; }
+
+ public TextField(string? text = null, Cursor? cursor = null) : base(cursor)
+ {
+ Text = text ?? string.Empty;
+ TextChanged += e => Text = e.Text;
+ }
+
+ protected override ControlDefinition CreateControl()
+ {
+ ControlDefinition textField = new ControlDefinition(UniqueId, "TextField");
+ textField.AddProperty(Text);
+ return textField;
+ }
+}
diff --git a/src/PixiEditor.Extensions.Sdk/Api/IO/DocumentProvider.cs b/src/PixiEditor.Extensions.Sdk/Api/IO/DocumentProvider.cs
index 7c39070e3..fb8c658bd 100644
--- a/src/PixiEditor.Extensions.Sdk/Api/IO/DocumentProvider.cs
+++ b/src/PixiEditor.Extensions.Sdk/Api/IO/DocumentProvider.cs
@@ -1,12 +1,24 @@
+using PixiEditor.Extensions.CommonApi.Documents;
using PixiEditor.Extensions.CommonApi.IO;
+using PixiEditor.Extensions.Sdk.Api.Documents;
using PixiEditor.Extensions.Sdk.Bridge;
namespace PixiEditor.Extensions.Sdk.Api.IO;
public class DocumentProvider : IDocumentProvider
{
- public void ImportFile(string path, bool associatePath = true)
+ public IDocument ActiveDocument => Interop.GetActiveDocument();
+
+ public IDocument? ImportFile(string path, bool associatePath = true)
{
- Native.import_file(path, associatePath);
+ return Interop.ImportFile(path, associatePath);
+ }
+
+ public IDocument? GetDocument(Guid id)
+ {
+ if (id == Guid.Empty)
+ throw new ArgumentException("Invalid document ID");
+
+ return new Document(id);
}
}
diff --git a/src/PixiEditor.Extensions.Sdk/Bridge/Interop.Document.cs b/src/PixiEditor.Extensions.Sdk/Bridge/Interop.Document.cs
new file mode 100644
index 000000000..2daa31adc
--- /dev/null
+++ b/src/PixiEditor.Extensions.Sdk/Bridge/Interop.Document.cs
@@ -0,0 +1,25 @@
+using PixiEditor.Extensions.CommonApi.Documents;
+using PixiEditor.Extensions.Sdk.Api.Documents;
+
+namespace PixiEditor.Extensions.Sdk.Bridge;
+
+internal static partial class Interop
+{
+ public static IDocument GetActiveDocument()
+ {
+ string document = Native.get_active_document();
+ if (document == null || !Guid.TryParse(document, out Guid id))
+ return null;
+
+ return new Document(id);
+ }
+
+ public static IDocument? ImportFile(string path, bool associatePath)
+ {
+ string document = Native.import_file(path, associatePath);
+ if (document == null || !Guid.TryParse(document, out Guid id))
+ return null;
+
+ return new Document(id);
+ }
+}
diff --git a/src/PixiEditor.Extensions.Sdk/Bridge/Native.Document.cs b/src/PixiEditor.Extensions.Sdk/Bridge/Native.Document.cs
index 6c1bedaa1..48baa3ed7 100644
--- a/src/PixiEditor.Extensions.Sdk/Bridge/Native.Document.cs
+++ b/src/PixiEditor.Extensions.Sdk/Bridge/Native.Document.cs
@@ -5,5 +5,11 @@ namespace PixiEditor.Extensions.Sdk.Bridge;
internal partial class Native
{
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void import_file(string path, bool associatePath);
+ internal static extern string import_file(string path, bool associatePath);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal static extern string get_active_document();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal static extern void resize_document(string documentId, int width, int height);
}
diff --git a/src/PixiEditor.Extensions.Sdk/Bridge/Native.cs b/src/PixiEditor.Extensions.Sdk/Bridge/Native.cs
index 3df16649c..8893d1b99 100644
--- a/src/PixiEditor.Extensions.Sdk/Bridge/Native.cs
+++ b/src/PixiEditor.Extensions.Sdk/Bridge/Native.cs
@@ -5,6 +5,8 @@ using System.Runtime.CompilerServices;
using PixiEditor.Extensions.CommonApi.FlyUI;
using PixiEditor.Extensions.CommonApi.FlyUI.Events;
using PixiEditor.Extensions.Sdk.Api.FlyUI;
+using PixiEditor.Extensions.Sdk.Utilities;
+using ProtoBuf;
namespace PixiEditor.Extensions.Sdk.Bridge;
@@ -50,11 +52,23 @@ internal static partial class Native
}
[ApiExport("raise_element_event")]
- internal static void EventRaised(int internalControlId, string eventName) //TOOD: Args
+ internal static void EventRaised(int internalControlId, string eventName, IntPtr eventData, int dataLength)
{
if (LayoutElementsStore.LayoutElements.TryGetValue((int)internalControlId, out ILayoutElement element))
{
- element.RaiseEvent(eventName ?? "", new ElementEventArgs { Sender = element });
+ byte[] data = InteropUtility.IntPtrToByteArray(eventData, dataLength);
+ ElementEventArgs args = ElementEventArgs.Deserialize(data);
+ args.Sender = element;
+ element.RaiseEvent(eventName ?? "", args);
+ }
+ }
+
+ [ApiExport("raise_element_text_event")]
+ internal static void TextEventRaised(int internalControlId, string eventName, string text)
+ {
+ if (LayoutElementsStore.LayoutElements.TryGetValue((int)internalControlId, out ILayoutElement element))
+ {
+ element.RaiseEvent(eventName ?? "", new TextEventArgs(text) { Sender = element });
}
}
diff --git a/src/PixiEditor.Extensions.Sdk/build/PixiEditor.Api.CGlueMSBuild.dll b/src/PixiEditor.Extensions.Sdk/build/PixiEditor.Api.CGlueMSBuild.dll
index 23e67fcdc..866c5311f 100644
Binary files a/src/PixiEditor.Extensions.Sdk/build/PixiEditor.Api.CGlueMSBuild.dll and b/src/PixiEditor.Extensions.Sdk/build/PixiEditor.Api.CGlueMSBuild.dll differ
diff --git a/src/PixiEditor.Extensions.Sdk/build/PixiEditor.Extensions.MSPackageBuilder.dll b/src/PixiEditor.Extensions.Sdk/build/PixiEditor.Extensions.MSPackageBuilder.dll
index 3232fb255..63aafd6b7 100644
Binary files a/src/PixiEditor.Extensions.Sdk/build/PixiEditor.Extensions.MSPackageBuilder.dll and b/src/PixiEditor.Extensions.Sdk/build/PixiEditor.Extensions.MSPackageBuilder.dll differ
diff --git a/src/PixiEditor.Extensions.WasmRuntime/Api/DocumentsApi.cs b/src/PixiEditor.Extensions.WasmRuntime/Api/DocumentsApi.cs
index 0efcad8e8..8d5cb5d48 100644
--- a/src/PixiEditor.Extensions.WasmRuntime/Api/DocumentsApi.cs
+++ b/src/PixiEditor.Extensions.WasmRuntime/Api/DocumentsApi.cs
@@ -6,17 +6,43 @@ namespace PixiEditor.Extensions.WasmRuntime.Api;
internal class DocumentsApi : ApiGroupHandler
{
[ApiFunction("import_file")]
- public void ImportFile(string path, bool associatePath = false)
+ public string ImportFile(string path, bool associatePath = false)
{
PermissionUtility.ThrowIfLacksPermissions(Extension.Metadata, ExtensionPermissions.OpenDocuments, "ImportFile");
string fullPath = ResourcesUtility.ToResourcesFullPath(Extension, path);
- if (!File.Exists(fullPath))
+ string id = string.Empty;
+ if (File.Exists(fullPath))
{
- return;
+ id = Api.Documents.ImportFile(fullPath, associatePath)?.Id.ToString() ?? string.Empty;
}
- Api.Documents.ImportFile(fullPath, associatePath);
+ return id;
+ }
+
+ [ApiFunction("get_active_document")]
+ public string GetActiveDocument()
+ {
+ var activeDocument = Api.Documents.ActiveDocument;
+ string id = activeDocument?.Id.ToString() ?? string.Empty;
+ return id;
+ }
+
+ [ApiFunction("resize_document")]
+ public void ResizeDocument(string documentId, int width, int height)
+ {
+ if (!Guid.TryParse(documentId, out Guid id))
+ {
+ throw new ArgumentException("Invalid document ID");
+ }
+
+ var document = Api.Documents.GetDocument(id);
+ if (document == null)
+ {
+ throw new ArgumentException("Document not found");
+ }
+
+ document.Resize(width, height);
}
}
diff --git a/src/PixiEditor.Extensions.WasmRuntime/Api/FlyUiApi.cs b/src/PixiEditor.Extensions.WasmRuntime/Api/FlyUiApi.cs
index 09fbc2909..97f7fa11f 100644
--- a/src/PixiEditor.Extensions.WasmRuntime/Api/FlyUiApi.cs
+++ b/src/PixiEditor.Extensions.WasmRuntime/Api/FlyUiApi.cs
@@ -13,11 +13,16 @@ internal class FlyUIApi : ApiGroupHandler
LayoutBuilder.ManagedElements[controlId].AddEvent(eventName, (args) =>
{
- var action = Instance.GetAction("raise_element_event");
+ var action = Instance.GetAction("raise_element_event");
var ptr = WasmMemoryUtility.WriteString(eventName);
- action.Invoke(controlId, ptr);
+ var data = args.Serialize();
+ var dataPtr = WasmMemoryUtility.WriteBytes(data);
+ int dataSize = data.Length;
+
+ action.Invoke(controlId, ptr, dataPtr, dataSize);
WasmMemoryUtility.Free(ptr);
+ WasmMemoryUtility.Free(dataPtr);
});
}
diff --git a/src/PixiEditor.Extensions.WasmRuntime/Api/LocalizationApi.cs b/src/PixiEditor.Extensions.WasmRuntime/Api/LocalizationApi.cs
index ee556bfe2..4f0e0cc66 100644
--- a/src/PixiEditor.Extensions.WasmRuntime/Api/LocalizationApi.cs
+++ b/src/PixiEditor.Extensions.WasmRuntime/Api/LocalizationApi.cs
@@ -1,4 +1,4 @@
-using PixiEditor.Extensions.Common.Localization;
+using PixiEditor.UI.Common.Localization;
namespace PixiEditor.Extensions.WasmRuntime.Api;
diff --git a/src/PixiEditor.Extensions.WasmRuntime/Api/Palettes/PalettesApi.cs b/src/PixiEditor.Extensions.WasmRuntime/Api/Palettes/PalettesApi.cs
index f83334000..8446d7ec2 100644
--- a/src/PixiEditor.Extensions.WasmRuntime/Api/Palettes/PalettesApi.cs
+++ b/src/PixiEditor.Extensions.WasmRuntime/Api/Palettes/PalettesApi.cs
@@ -1,9 +1,7 @@
-using CommunityToolkit.HighPerformance;
-using PixiEditor.Extensions.CommonApi.Palettes;
-using PixiEditor.Extensions.WasmRuntime.Api.Palettes;
+using PixiEditor.Extensions.CommonApi.Palettes;
using ProtoBuf;
-namespace PixiEditor.Extensions.WasmRuntime.Api;
+namespace PixiEditor.Extensions.WasmRuntime.Api.Palettes;
internal class PalettesApi : ApiGroupHandler
{
diff --git a/src/PixiEditor.Extensions.WasmRuntime/Api/WindowingApi.cs b/src/PixiEditor.Extensions.WasmRuntime/Api/WindowingApi.cs
index ab7de6f6c..1614ef47d 100644
--- a/src/PixiEditor.Extensions.WasmRuntime/Api/WindowingApi.cs
+++ b/src/PixiEditor.Extensions.WasmRuntime/Api/WindowingApi.cs
@@ -1,10 +1,8 @@
-using PixiEditor.Extensions.Common.Localization;
-using PixiEditor.Extensions.CommonApi.Async;
-using PixiEditor.Extensions.CommonApi.Utilities;
-using PixiEditor.Extensions.CommonApi.Windowing;
+using PixiEditor.Extensions.CommonApi.Windowing;
using PixiEditor.Extensions.FlyUI.Elements;
using PixiEditor.Extensions.WasmRuntime.Utilities;
using PixiEditor.Extensions.Windowing;
+using PixiEditor.UI.Common.Localization;
namespace PixiEditor.Extensions.WasmRuntime.Api;
diff --git a/src/PixiEditor.Extensions.WasmRuntime/WasmExtensionInstance.cs b/src/PixiEditor.Extensions.WasmRuntime/WasmExtensionInstance.cs
index 4c47f9997..a8ad89a11 100644
--- a/src/PixiEditor.Extensions.WasmRuntime/WasmExtensionInstance.cs
+++ b/src/PixiEditor.Extensions.WasmRuntime/WasmExtensionInstance.cs
@@ -21,7 +21,7 @@ public partial class WasmExtensionInstance : Extension
private Linker Linker { get; }
private Store Store { get; }
private Module Module { get; }
-
+
private LayoutBuilder LayoutBuilder { get; set; }
internal ObjectManager NativeObjectManager { get; set; }
internal AsyncCallsManager AsyncHandleManager { get; set; }
@@ -30,7 +30,7 @@ public partial class WasmExtensionInstance : Extension
private string modulePath;
private List modules = new();
-
+
public override string Location => modulePath;
partial void LinkApiFunctions();
@@ -49,7 +49,7 @@ public partial class WasmExtensionInstance : Extension
AsyncHandleManager = new AsyncCallsManager();
AsyncHandleManager.OnAsyncCallCompleted += OnAsyncCallCompleted;
AsyncHandleManager.OnAsyncCallFaulted += OnAsyncCallFaulted;
-
+
LinkApiFunctions();
Linker.DefineModule(Store, Module);
@@ -66,19 +66,20 @@ public partial class WasmExtensionInstance : Extension
protected override void OnInitialized()
{
modules.Add(new PreferencesModule(this, Api.Preferences));
- modules.Add(new CommandModule(this, Api.Commands, (ICommandSupervisor)Api.Services.GetService(typeof(ICommandSupervisor))));
+ modules.Add(new CommandModule(this, Api.Commands,
+ (ICommandSupervisor)Api.Services.GetService(typeof(ICommandSupervisor))));
LayoutBuilder = new LayoutBuilder((ElementMap)Api.Services.GetService(typeof(ElementMap)));
//SetElementMap();
Instance.GetAction("initialize").Invoke();
base.OnInitialized();
}
-
+
private void OnAsyncCallCompleted(int handle, int result)
{
Instance.GetAction("async_call_completed").Invoke(handle, result);
}
-
+
private void OnAsyncCallFaulted(int handle, string exceptionMessage)
{
Instance.GetAction("async_call_faulted").Invoke(handle, exceptionMessage);
diff --git a/src/PixiEditor.Extensions/Exceptions/RecoverableException.cs b/src/PixiEditor.Extensions/Exceptions/RecoverableException.cs
index 103080899..4521dc03a 100644
--- a/src/PixiEditor.Extensions/Exceptions/RecoverableException.cs
+++ b/src/PixiEditor.Extensions/Exceptions/RecoverableException.cs
@@ -1,5 +1,5 @@
using System.Runtime.Serialization;
-using PixiEditor.Extensions.Common.Localization;
+using PixiEditor.UI.Common.Localization;
namespace PixiEditor.Extensions.Exceptions;
diff --git a/src/PixiEditor.Extensions/FlyUI/Elements/SizeInputField.cs b/src/PixiEditor.Extensions/FlyUI/Elements/SizeInputField.cs
new file mode 100644
index 000000000..8db29401e
--- /dev/null
+++ b/src/PixiEditor.Extensions/FlyUI/Elements/SizeInputField.cs
@@ -0,0 +1,49 @@
+using Avalonia.Controls;
+using Avalonia.Data;
+using PixiEditor.Extensions.CommonApi.FlyUI.Events;
+using PixiEditor.UI.Common.Controls;
+
+namespace PixiEditor.Extensions.FlyUI.Elements;
+
+public class SizeInputField : LayoutElement
+{
+ public event ElementEventHandler 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; }
+
+ protected override Control CreateNativeControl()
+ {
+ SizeInput sizeInput = new SizeInput { MinSize = Min, MaxSize = Max, Decimals = Decimals, Unit = Unit };
+
+ Binding binding = new Binding { Source = this, Path = nameof(Value), Mode = BindingMode.TwoWay, };
+
+ sizeInput.Bind(SizeInput.SizeProperty, binding);
+
+ sizeInput.PropertyChanged += (sender, args) =>
+ {
+ if (args.Property != SizeInput.SizeProperty) return;
+
+ Value = sizeInput.Size;
+ RaiseEvent(nameof(SizeChanged), new NumberEventArgs(Value));
+ };
+
+ return sizeInput;
+ }
+
+ protected override void DeserializeControlProperties(List