浏览代码

More windowing functions

Krzysztof Krysiński 1 年之前
父节点
当前提交
5888d489f9

+ 2 - 1
src/PixiEditor.AvaloniaUI/Models/ExtensionServices/WindowProvider.cs

@@ -2,6 +2,7 @@
 using System.Linq;
 using System.Linq;
 using System.Reflection;
 using System.Reflection;
 using PixiEditor.AvaloniaUI.Views.Dialogs;
 using PixiEditor.AvaloniaUI.Views.Dialogs;
+using PixiEditor.Extensions.Common.Localization;
 using PixiEditor.Extensions.CommonApi.Windowing;
 using PixiEditor.Extensions.CommonApi.Windowing;
 using PixiEditor.Extensions.Helpers;
 using PixiEditor.Extensions.Helpers;
 using PixiEditor.Extensions.Runtime;
 using PixiEditor.Extensions.Runtime;
@@ -40,7 +41,7 @@ public class WindowProvider : IWindowProvider
 
 
     public IPopupWindow CreatePopupWindow(string title, object body)
     public IPopupWindow CreatePopupWindow(string title, object body)
     {
     {
-        return new PopupWindow(new PixiEditorPopup { Title = title, Content = body });
+        return new PopupWindow(new PixiEditorPopup { Title = new LocalizedString(title), Content = body });
     }
     }
 
 
     public IPopupWindow GetWindow(WindowType type)
     public IPopupWindow GetWindow(WindowType type)

+ 15 - 3
src/PixiEditor.Extensions.Wasm/Api/Window/PopupWindow.cs

@@ -4,15 +4,27 @@ namespace PixiEditor.Extensions.Wasm.Api.Window;
 
 
 public class PopupWindow : IPopupWindow
 public class PopupWindow : IPopupWindow
 {
 {
-    public string Title { get; set; }
+    private int windowHandle;
+
+    internal PopupWindow(int handle)
+    {
+        windowHandle = handle;
+    }
+
+    public string Title
+    {
+        get => Interop.GetWindowTitle(windowHandle);
+        set => Interop.SetWindowTitle(windowHandle, value);
+    }
+
     public void Show()
     public void Show()
     {
     {
-        throw new NotImplementedException();
+        Interop.ShowWindow(windowHandle);
     }
     }
 
 
     public void Close()
     public void Close()
     {
     {
-        throw new NotImplementedException();
+        Interop.CloseWindow(windowHandle);
     }
     }
 
 
     public Task<bool?> ShowDialog()
     public Task<bool?> ShowDialog()

+ 2 - 2
src/PixiEditor.Extensions.Wasm/Api/Window/WindowProvider.cs

@@ -12,12 +12,12 @@ public class WindowProvider : IWindowProvider
         byte[] bytes = compiledControl.Serialize().ToArray();
         byte[] bytes = compiledControl.Serialize().ToArray();
         IntPtr ptr = Marshal.AllocHGlobal(bytes.Length);
         IntPtr ptr = Marshal.AllocHGlobal(bytes.Length);
         Marshal.Copy(bytes, 0, ptr, bytes.Length);
         Marshal.Copy(bytes, 0, ptr, bytes.Length);
-        Interop.CreatePopupWindow(title, ptr, bytes.Length);
+        int handle = Interop.CreatePopupWindow(title, ptr, bytes.Length);
         Marshal.FreeHGlobal(ptr);
         Marshal.FreeHGlobal(ptr);
 
 
         SubscribeToEvents(compiledControl);
         SubscribeToEvents(compiledControl);
 
 
-        return new PopupWindow(); // TODO: Implement
+        return new PopupWindow(handle) { Title = title };
     }
     }
 
 
     internal void LayoutStateChanged(int uniqueId, CompiledControl newLayout)
     internal void LayoutStateChanged(int uniqueId, CompiledControl newLayout)

+ 21 - 0
src/PixiEditor.Extensions.Wasm/Interop.Windowing.cs

@@ -0,0 +1,21 @@
+using System.Runtime.CompilerServices;
+
+namespace PixiEditor.Extensions.Wasm;
+
+internal static partial class Interop
+{
+    [MethodImpl(MethodImplOptions.InternalCall)]
+    internal static extern int CreatePopupWindow(string title, IntPtr data, int length);
+
+    [MethodImpl(MethodImplOptions.InternalCall)]
+    internal static extern void SetWindowTitle(int windowHandle, string title);
+
+    [MethodImpl(MethodImplOptions.InternalCall)]
+    internal static extern string GetWindowTitle(int windowHandle);
+
+    [MethodImpl(MethodImplOptions.InternalCall)]
+    internal static extern void ShowWindow(int windowHandle);
+
+    [MethodImpl(MethodImplOptions.InternalCall)]
+    internal static extern void CloseWindow(int windowHandle);
+}

+ 1 - 3
src/PixiEditor.Extensions.Wasm/Interop.cs

@@ -7,13 +7,11 @@ using PixiEditor.Extensions.Wasm.Api.FlyUI;
 
 
 namespace PixiEditor.Extensions.Wasm;
 namespace PixiEditor.Extensions.Wasm;
 
 
-internal class Interop
+internal static partial class Interop
 {
 {
     [MethodImpl(MethodImplOptions.InternalCall)]
     [MethodImpl(MethodImplOptions.InternalCall)]
     internal static extern void LogMessage(string message);
     internal static extern void LogMessage(string message);
 
 
-    [MethodImpl(MethodImplOptions.InternalCall)]
-    internal static extern void CreatePopupWindow(string title, IntPtr data, int length);
 
 
     [MethodImpl(MethodImplOptions.InternalCall)]
     [MethodImpl(MethodImplOptions.InternalCall)]
     internal static extern void SubscribeToEvent(int internalControlId, string eventName);
     internal static extern void SubscribeToEvent(int internalControlId, string eventName);

+ 40 - 3
src/PixiEditor.Extensions.Wasm/native/window_api.c

@@ -5,16 +5,53 @@
 #include "api.h"
 #include "api.h"
 
 
 __attribute__((import_name("create_popup_window")))
 __attribute__((import_name("create_popup_window")))
-void create_popup_window(const char* title, int32_t titleLength, uint8_t* data, int32_t length);
+int32_t create_popup_window(const char* title, int32_t titleLength, uint8_t* data, int32_t length);
 
 
 // content is byte[] from C#
 // content is byte[] from C#
-void internal_create_popup_window(MonoString* title, uint8_t* data, int32_t length)
+int32_t internal_create_popup_window(MonoString* title, uint8_t* data, int32_t length)
 {
 {
     char* title_utf8 = mono_wasm_string_get_utf8(title);
     char* title_utf8 = mono_wasm_string_get_utf8(title);
-    create_popup_window(title_utf8, strlen(title_utf8), data, length);
+    return create_popup_window(title_utf8, strlen(title_utf8), data, length);
+}
+
+__attribute__((import_name("set_window_title")))
+void set_window_title(int32_t windowHandle, const char* title, int32_t titleLength);
+
+void internal_set_window_title(int32_t windowHandle, MonoString* title)
+{
+    char* title_utf8 = mono_wasm_string_get_utf8(title);
+    set_window_title(windowHandle, title_utf8, strlen(title_utf8));
+}
+
+__attribute__((import_name("get_window_title")))
+char* get_window_title(int32_t windowHandle);
+
+MonoString* internal_get_window_title(int32_t windowHandle)
+{
+    return mono_wasm_string_from_js(get_window_title(windowHandle));
+}
+
+__attribute__((import_name("show_window")))
+void show_window(int32_t windowHandle);
+
+void internal_show_window(int32_t windowHandle)
+{
+    show_window(windowHandle);
+}
+
+__attribute__((import_name("close_window")))
+void close_window(int32_t windowHandle);
+
+void internal_close_window(int32_t windowHandle)
+{
+    close_window(windowHandle);
 }
 }
 
 
 void attach_window_calls()
 void attach_window_calls()
 {
 {
     mono_add_internal_call("PixiEditor.Extensions.Wasm.Interop::CreatePopupWindow", internal_create_popup_window);
     mono_add_internal_call("PixiEditor.Extensions.Wasm.Interop::CreatePopupWindow", internal_create_popup_window);
+    mono_add_internal_call("PixiEditor.Extensions.Wasm.Interop::SetWindowTitle", internal_set_window_title);
+    mono_add_internal_call("PixiEditor.Extensions.Wasm.Interop::GetWindowTitle", internal_get_window_title);
+    mono_add_internal_call("PixiEditor.Extensions.Wasm.Interop::ShowWindow", internal_show_window);
+    mono_add_internal_call("PixiEditor.Extensions.Wasm.Interop::CloseWindow", internal_close_window);
 }
 }

+ 29 - 0
src/PixiEditor.Extensions.WasmRuntime/Management/ObjectManager.cs

@@ -0,0 +1,29 @@
+namespace PixiEditor.Extensions.WasmRuntime.Management;
+
+internal class ObjectManager
+{
+    private Dictionary<int, object> ManagedObjects { get; } = new Dictionary<int, object>();
+
+    public int AddObject(object obj)
+    {
+        int id = ManagedObjects.Count + 1; // 0 is reserved for null
+        ManagedObjects.Add(id, obj);
+        return id;
+    }
+
+    public T GetObject<T>(int id)
+    {
+        object obj = ManagedObjects[id];
+        if (obj is not T)
+        {
+            throw new InvalidCastException($"Object with id {id} is not of type {typeof(T).Name}");
+        }
+
+        return (T)obj;
+    }
+
+    public void RemoveObject(int id)
+    {
+        ManagedObjects.Remove(id);
+    }
+}

+ 33 - 1
src/PixiEditor.Extensions.WasmRuntime/WasmExtensionInstance.cs

@@ -4,6 +4,8 @@ using Avalonia.Controls;
 using Avalonia.Threading;
 using Avalonia.Threading;
 using PixiEditor.Extensions.FlyUI;
 using PixiEditor.Extensions.FlyUI;
 using PixiEditor.Extensions.FlyUI.Elements;
 using PixiEditor.Extensions.FlyUI.Elements;
+using PixiEditor.Extensions.WasmRuntime.Management;
+using PixiEditor.Extensions.Windowing;
 using Wasmtime;
 using Wasmtime;
 
 
 namespace PixiEditor.Extensions.WasmRuntime;
 namespace PixiEditor.Extensions.WasmRuntime;
@@ -18,6 +20,7 @@ public class WasmExtensionInstance : Extension
 
 
     private Memory memory = null!;
     private Memory memory = null!;
     private LayoutBuilder LayoutBuilder { get; set; }
     private LayoutBuilder LayoutBuilder { get; set; }
+    private ObjectManager NativeObjectManager { get; set; }
     private WasmMemoryUtility WasmMemoryUtility { get; set; }
     private WasmMemoryUtility WasmMemoryUtility { get; set; }
 
 
     public WasmExtensionInstance(Linker linker, Store store, Module module)
     public WasmExtensionInstance(Linker linker, Store store, Module module)
@@ -29,6 +32,7 @@ public class WasmExtensionInstance : Extension
 
 
     public void Instantiate()
     public void Instantiate()
     {
     {
+        NativeObjectManager = new ObjectManager();
         DefinePixiEditorApi();
         DefinePixiEditorApi();
         Linker.DefineModule(Store, Module);
         Linker.DefineModule(Store, Module);
 
 
@@ -78,7 +82,35 @@ public class WasmExtensionInstance : Extension
 
 
             var body = LayoutBuilder.Deserialize(arr, DuplicateResolutionTactic.ThrowException);
             var body = LayoutBuilder.Deserialize(arr, DuplicateResolutionTactic.ThrowException);
 
 
-            Api.Windowing.CreatePopupWindow(title, body.BuildNative()).Show();
+            var popupWindow = Api.Windowing.CreatePopupWindow(title, body.BuildNative());
+
+            int handle = NativeObjectManager.AddObject(popupWindow);
+            return WasmMemoryUtility.WriteInt32(handle);
+        });
+
+        Linker.DefineFunction("env", "set_window_title", (int handle, int titleOffset, int titleLength) =>
+        {
+            string title = WasmMemoryUtility.GetString(titleOffset, titleLength);
+            var window = NativeObjectManager.GetObject<PopupWindow>(memory.ReadInt32(handle));
+            window.Title = title;
+        });
+
+        Linker.DefineFunction("env", "get_window_title", (int handle) =>
+        {
+            var window = NativeObjectManager.GetObject<PopupWindow>(memory.ReadInt32(handle));
+            return WasmMemoryUtility.WriteString(window.Title);
+        });
+
+        Linker.DefineFunction("env", "show_window", (int handle) =>
+        {
+            var window = NativeObjectManager.GetObject<PopupWindow>(memory.ReadInt32(handle));
+            window.Show();
+        });
+
+        Linker.DefineFunction("env", "close_window", (int handle) =>
+        {
+            var window = NativeObjectManager.GetObject<PopupWindow>(memory.ReadInt32(handle));
+            window.Close();
         });
         });
 
 
         Linker.DefineFunction("env", "subscribe_to_event", (int controlId, int eventNameOffset, int eventNameLengthOffset) =>
         Linker.DefineFunction("env", "subscribe_to_event", (int controlId, int eventNameOffset, int eventNameLengthOffset) =>

+ 9 - 1
src/PixiEditor.Platform.Standalone/StandaloneAdditionalContentProvider.cs

@@ -4,12 +4,20 @@ public sealed class StandaloneAdditionalContentProvider : IAdditionalContentProv
 {
 {
     public bool IsContentInstalled(AdditionalContentProduct product)
     public bool IsContentInstalled(AdditionalContentProduct product)
     {
     {
-        //if(!PlatformHasContent(product)) return false;
+        if(!PlatformHasContent(product)) return false;
+#if DEBUG
+        return true;
+#else
         return false;
         return false;
+#endif
     }
     }
 
 
     public bool PlatformHasContent(AdditionalContentProduct product)
     public bool PlatformHasContent(AdditionalContentProduct product)
     {
     {
+#if DEBUG
+        return true;
+#else
         return false;
         return false;
+#endif
     }
     }
 }
 }