From 2b6eb84cbb544b32a1a296fd522513613efed802 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Tue, 2 Sep 2025 19:04:36 +0200 Subject: [PATCH] add new menu API --- .../main/java/de/unixwork/ui/Application.java | 4 ++ .../src/main/java/de/unixwork/ui/Menu.java | 48 +++++++++++++ .../main/java/de/unixwork/ui/MenuElement.java | 18 +++++ .../main/java/de/unixwork/ui/MenuFuncs.java | 9 +++ .../main/java/de/unixwork/ui/MenuItem.java | 68 +++++++++++++++++++ .../test/java/de/unixwork/ui/demo/Main.java | 13 ++++ 6 files changed, 160 insertions(+) create mode 100644 ui-java/src/main/java/de/unixwork/ui/Menu.java create mode 100644 ui-java/src/main/java/de/unixwork/ui/MenuElement.java create mode 100644 ui-java/src/main/java/de/unixwork/ui/MenuItem.java diff --git a/ui-java/src/main/java/de/unixwork/ui/Application.java b/ui-java/src/main/java/de/unixwork/ui/Application.java index f2e31f3..50598d3 100644 --- a/ui-java/src/main/java/de/unixwork/ui/Application.java +++ b/ui-java/src/main/java/de/unixwork/ui/Application.java @@ -7,4 +7,8 @@ public interface Application { default void shutdown() { } + + public static void setAppMenu(Menu appmenu) { + appmenu.create(); + } } diff --git a/ui-java/src/main/java/de/unixwork/ui/Menu.java b/ui-java/src/main/java/de/unixwork/ui/Menu.java new file mode 100644 index 0000000..a18dcd2 --- /dev/null +++ b/ui-java/src/main/java/de/unixwork/ui/Menu.java @@ -0,0 +1,48 @@ +package de.unixwork.ui; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.LinkedList; + +public class Menu extends MenuElement { + private LinkedList items = new LinkedList<>(); + private String title; + + public Menu() { + + } + + public Menu(String title) { + this.title = title; + } + + public void add(MenuElement item) { + items.add(item); + item.setParent(this); + } + + @Override + protected void create() { + if(parent != null) { + MenuFuncs ui = MenuFuncs.getInstance(); + try (Arena arena = Arena.ofConfined()) { + MemorySegment label = MemorySegment.NULL; + if(title != null) { + label = arena.allocateFrom(title); + } + ui.menu_create.invoke(label); + for(var item : items) { + item.create(); + } + ui.menu_end.invoke(); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } else { + for(var item : items) { + item.create(); + } + } + } +} + diff --git a/ui-java/src/main/java/de/unixwork/ui/MenuElement.java b/ui-java/src/main/java/de/unixwork/ui/MenuElement.java new file mode 100644 index 0000000..ac2b3a3 --- /dev/null +++ b/ui-java/src/main/java/de/unixwork/ui/MenuElement.java @@ -0,0 +1,18 @@ +package de.unixwork.ui; + +public abstract class MenuElement { + Menu parent; + + public void setParent(Menu parent) { + if(this.parent != null) { + throw new RuntimeException("Cannot set parent twice"); + } + this.parent = parent; + } + + public MenuElement getParent() { + return parent; + } + + protected abstract void create(); +} diff --git a/ui-java/src/main/java/de/unixwork/ui/MenuFuncs.java b/ui-java/src/main/java/de/unixwork/ui/MenuFuncs.java index 0894ed4..a4e1b95 100644 --- a/ui-java/src/main/java/de/unixwork/ui/MenuFuncs.java +++ b/ui-java/src/main/java/de/unixwork/ui/MenuFuncs.java @@ -17,6 +17,9 @@ public class MenuFuncs { public MethodHandle menu_separator; public MethodHandle menu_itemlist_create; + public MethodHandle contextmenu_builder; + public MethodHandle menubuilder_free; + public MethodHandle toolbar_item_create; public MethodHandle toolbar_toggleitem_create; public MethodHandle toolbar_menu_create; @@ -45,6 +48,9 @@ public class MenuFuncs { MemorySegment ui_menu_separator_addr = lib.find("ui_menuseparator").orElseThrow(); MemorySegment ui_menu_itemlist_create_addr = lib.find("ui_menu_itemlist_create").orElseThrow(); + MemorySegment ui_contextmenu_builder_addr = lib.find("ui_contextmenu_builder").orElseThrow(); + MemorySegment ui_menubuilder_free_addr = lib.find("ui_menubuilder_free").orElseThrow(); + MemorySegment ui_toolbar_item_create_addr = lib.find("ui_toolbar_item_create").orElseThrow(); MemorySegment ui_toolbar_toggleitem_create_addr = lib.find("ui_toolbar_toggleitem_create").orElseThrow(); MemorySegment ui_toolbar_menu_create_addr = lib.find("ui_toolbar_menu_create").orElseThrow(); @@ -61,6 +67,9 @@ public class MenuFuncs { menu_separator = linker.downcallHandle(ui_menu_separator_addr, sigv); menu_itemlist_create = linker.downcallHandle(ui_menu_itemlist_create_addr, sigv_m); + contextmenu_builder = linker.downcallHandle(ui_contextmenu_builder_addr, sigv_mm); + menubuilder_free = linker.downcallHandle(ui_menubuilder_free_addr, sigv_m); + toolbar_item_create = linker.downcallHandle(ui_toolbar_item_create_addr, sigv_mm); toolbar_toggleitem_create = linker.downcallHandle(ui_toolbar_toggleitem_create_addr, sigv_mm); toolbar_menu_create = linker.downcallHandle(ui_toolbar_menu_create_addr, sigv_mm); diff --git a/ui-java/src/main/java/de/unixwork/ui/MenuItem.java b/ui-java/src/main/java/de/unixwork/ui/MenuItem.java new file mode 100644 index 0000000..862f4b9 --- /dev/null +++ b/ui-java/src/main/java/de/unixwork/ui/MenuItem.java @@ -0,0 +1,68 @@ +package de.unixwork.ui; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; + +public class MenuItem extends MenuElement { + private String label; + private String icon; + private EventHandler onClick; + + public MenuItem(String label, EventHandler onClick) { + this.label = label; + this.onClick = onClick; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public EventHandler getOnClick() { + return onClick; + } + + public void setOnClick(EventHandler onClick) { + this.onClick = onClick; + } + + @Override + protected void create() { + MenuFuncs ui = MenuFuncs.getInstance(); + ArgFuncs a = ArgFuncs.getInstance(); + Toolkit toolkit = Toolkit.getInstance(); + try (Arena arena = Arena.ofConfined()) { + MemorySegment args = (MemorySegment) a.menuitem_args_new.invoke(); + if(label != null) { + MemorySegment cstr = arena.allocateFrom(label); + a.menuitem_args_set_label.invoke(args, cstr); + } + if(icon != null) { + MemorySegment cstr = arena.allocateFrom(icon); + a.menuitem_args_set_icon.invoke(args, cstr); + } + if(onClick != null) { + EventWrapper event = new EventWrapper(onClick); + + // set toolkit args + a.menuitem_args_set_onclick.invoke(args, event.getCallback()); + a.menuitem_args_set_onclickdata.invoke(args, event.getUserData()); + } + ui.menuitem_create.invoke(args); + a.menuitem_args_free.invoke(args); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } +} diff --git a/ui-java/src/test/java/de/unixwork/ui/demo/Main.java b/ui-java/src/test/java/de/unixwork/ui/demo/Main.java index 9210823..9c7b959 100644 --- a/ui-java/src/test/java/de/unixwork/ui/demo/Main.java +++ b/ui-java/src/test/java/de/unixwork/ui/demo/Main.java @@ -70,6 +70,7 @@ public class Main implements Application{ System.out.println("UI Demo"); Toolkit.init("testapp"); + /* AppMenu.menu("File", () -> { AppMenu.menuItem("Open", event -> { System.out.println("Open"); @@ -79,6 +80,18 @@ public class Main implements Application{ System.exit(0); }); }); + */ + Menu appmenu = new Menu(); + Menu fileMenu = new Menu("File"); + appmenu.add(fileMenu); + fileMenu.add(new MenuItem("Open", event -> { + System.out.println("Open"); + })); + fileMenu.add(new MenuItem("Exit", event -> { + System.out.println("Exit"); + System.exit(0); + })); + Application.setAppMenu(appmenu); Toolbar.item("open", "Open", event -> { System.out.println("Toolbar Open"); -- 2.47.3