From 66d13ea703c38e63ea5daf10103ac1ea12fb25a5 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Tue, 30 Sep 2025 19:51:45 +0200 Subject: [PATCH] implement ListSaveHandler callback --- .../main/java/de/unixwork/ui/ArgFuncs.java | 6 ++ .../java/de/unixwork/ui/ListSaveHandler.java | 2 +- .../java/de/unixwork/ui/ListSaveWrapper.java | 58 +++++++++++++++++++ .../java/de/unixwork/ui/TableViewBuilder.java | 11 ++++ .../src/main/java/de/unixwork/ui/Toolkit.java | 17 ++++++ .../java/de/unixwork/ui/ToolkitFuncs.java | 16 +++++ .../main/java/de/unixwork/ui/UiObject.java | 10 ++++ 7 files changed, 119 insertions(+), 1 deletion(-) diff --git a/ui-java/src/main/java/de/unixwork/ui/ArgFuncs.java b/ui-java/src/main/java/de/unixwork/ui/ArgFuncs.java index cdc010b..ad2c1ab 100644 --- a/ui-java/src/main/java/de/unixwork/ui/ArgFuncs.java +++ b/ui-java/src/main/java/de/unixwork/ui/ArgFuncs.java @@ -326,6 +326,8 @@ class ArgFuncs { MethodHandle list_args_set_ondragcompletedata; MethodHandle list_args_set_ondrop; MethodHandle list_args_set_ondropdata; + MethodHandle list_args_set_onsave; + MethodHandle list_args_set_onsavedata; MethodHandle list_args_set_multiselection; MethodHandle list_args_set_contextmenu; MethodHandle list_args_set_groups; @@ -762,6 +764,8 @@ class ArgFuncs { MemorySegment ui_list_args_set_ondragcompletedata_addr = lib.find("ui_list_args_set_ondragcompletedata").orElseThrow(); MemorySegment ui_list_args_set_ondrop_addr = lib.find("ui_list_args_set_ondrop").orElseThrow(); MemorySegment ui_list_args_set_ondropdata_addr = lib.find("ui_list_args_set_ondropdata").orElseThrow(); + MemorySegment ui_list_args_set_onsave_addr = lib.find("ui_list_args_set_onsave").orElseThrow(); + MemorySegment ui_list_args_set_onsavedata_addr = lib.find("ui_list_args_set_onsavedata").orElseThrow(); MemorySegment ui_list_args_set_multiselection_addr = lib.find("ui_list_args_set_multiselection").orElseThrow(); MemorySegment ui_list_args_set_contextmenu_addr = lib.find("ui_list_args_set_contextmenu").orElseThrow(); MemorySegment ui_list_args_set_groups_addr = lib.find("ui_list_args_set_groups").orElseThrow(); @@ -1188,6 +1192,8 @@ class ArgFuncs { list_args_set_ondragcompletedata = linker.downcallHandle(ui_list_args_set_ondragcompletedata_addr, sigv_mm); list_args_set_ondrop = linker.downcallHandle(ui_list_args_set_ondrop_addr, sigv_mm); list_args_set_ondropdata = linker.downcallHandle(ui_list_args_set_ondropdata_addr, sigv_mm); + list_args_set_onsave = linker.downcallHandle(ui_list_args_set_onsave_addr, sigv_mm); + list_args_set_onsavedata = linker.downcallHandle(ui_list_args_set_onsavedata_addr, sigv_mm); list_args_set_multiselection = linker.downcallHandle(ui_list_args_set_multiselection_addr, sigv_mb); list_args_set_contextmenu = linker.downcallHandle(ui_list_args_set_contextmenu_addr, sigv_mm); list_args_set_groups = linker.downcallHandle(ui_list_args_set_groups_addr, sigv_mmi); diff --git a/ui-java/src/main/java/de/unixwork/ui/ListSaveHandler.java b/ui-java/src/main/java/de/unixwork/ui/ListSaveHandler.java index 421d222..d1ff160 100644 --- a/ui-java/src/main/java/de/unixwork/ui/ListSaveHandler.java +++ b/ui-java/src/main/java/de/unixwork/ui/ListSaveHandler.java @@ -1,6 +1,6 @@ package de.unixwork.ui; @FunctionalInterface -public interface ListSaveFunc { +public interface ListSaveHandler { public boolean save(UiList list, int row, int column, Object value); } diff --git a/ui-java/src/main/java/de/unixwork/ui/ListSaveWrapper.java b/ui-java/src/main/java/de/unixwork/ui/ListSaveWrapper.java index 45fe5a6..7b9bb10 100644 --- a/ui-java/src/main/java/de/unixwork/ui/ListSaveWrapper.java +++ b/ui-java/src/main/java/de/unixwork/ui/ListSaveWrapper.java @@ -1,4 +1,62 @@ package de.unixwork.ui; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; + public class ListSaveWrapper { + private MemorySegment callback; + private MemorySegment userdata; + + public ListSaveWrapper(UiObject obj, ListSaveHandler handler) { + Arena objArena = obj.getArena(); // very important to use the obj arena + callback = Toolkit.getInstance().eventHandler; + + long index = obj.addListSaveHandler(handler); + + userdata = objArena.allocate(ValueLayout.JAVA_LONG, 2); + userdata.setAtIndex(ValueLayout.JAVA_LONG, 0, obj.ptr.address()); + userdata.setAtIndex(ValueLayout.JAVA_LONG, 1, index); + } + + public static boolean onSaveHandler(MemorySegment list, int row, int col, MemorySegment value, MemorySegment userData) { + Toolkit tk = Toolkit.getInstance(); + ToolkitFuncs ui = ToolkitFuncs.getInstance(); + + userData = userData.reinterpret(16); + long objPtr = userData.getAtIndex(ValueLayout.JAVA_LONG, 0); + long handlerIndex = userData.getAtIndex(ValueLayout.JAVA_LONG, 1); + UiObject obj = tk.getToplevelObject(objPtr); + if(obj == null) { + return false; + } + ListSaveHandler handler = obj.getListSaveHandler((int)handlerIndex); + if(handler == null) { + return false; + } + + UiList uilist = Toolkit.listPtrToObject(list); + + Object valueObj = null; + try { + if((boolean) ui.cell_value_is_string.invoke(value)) { + MemorySegment cstr = (MemorySegment) ui.cell_value_get_string.invoke(value); + valueObj = (String)cstr.getString(0); + } else if((boolean) ui.cell_value_is_int.invoke(value)) { + valueObj = ui.cell_value_get_int.invoke(value); + } + } catch (Throwable e) { + throw new RuntimeException(e); + } + + return handler.save(uilist, row, col, valueObj); + } + + public MemorySegment getCallback() { + return callback; + } + + public MemorySegment getUserData() { + return userdata; + } } diff --git a/ui-java/src/main/java/de/unixwork/ui/TableViewBuilder.java b/ui-java/src/main/java/de/unixwork/ui/TableViewBuilder.java index ecbf9b2..71a1292 100644 --- a/ui-java/src/main/java/de/unixwork/ui/TableViewBuilder.java +++ b/ui-java/src/main/java/de/unixwork/ui/TableViewBuilder.java @@ -27,6 +27,7 @@ public class TableViewBuilder extends AbstractWidgetBuilder { private EventHandler onDragStart; private EventHandler onDragComplete; private EventHandler onDrop; + private ListSaveHandler onSave; private boolean multiselection; private Menu contextMenu; // TODO: contextmenu @@ -148,6 +149,11 @@ public class TableViewBuilder extends AbstractWidgetBuilder { return this; } + public TableViewBuilder onSave(ListSaveHandler onSave) { + this.onSave = onSave; + return this; + } + public TableViewBuilder states(int... states) { this.states = states; return this; @@ -242,6 +248,11 @@ public class TableViewBuilder extends AbstractWidgetBuilder { ui.list_args_set_ondrop.invoke(args, event.getCallback()); ui.list_args_set_ondropdata.invoke(args, event.getUserData()); } + if (onSave != null) { + ListSaveWrapper handler = new ListSaveWrapper(obj, onSave); + ui.list_args_set_onsave.invoke(args, handler.getCallback()); + ui.list_args_set_onsavedata.invoke(args, handler.getUserData()); + } if (contextMenu != null) { menuBuilder = contextMenu.createMenuBuilder(); ui.list_args_set_contextmenu.invoke(args, menuBuilder); diff --git a/ui-java/src/main/java/de/unixwork/ui/Toolkit.java b/ui-java/src/main/java/de/unixwork/ui/Toolkit.java index f6cc63e..bd2e9f8 100644 --- a/ui-java/src/main/java/de/unixwork/ui/Toolkit.java +++ b/ui-java/src/main/java/de/unixwork/ui/Toolkit.java @@ -50,6 +50,7 @@ public class Toolkit { protected MemorySegment eventHandler; protected MemorySegment globalEventHandler; protected MemorySegment oneshotEventHandler; + protected MemorySegment onSaveHandler; private HashMap threadCallbacks = new HashMap<>(); @@ -280,6 +281,22 @@ public class Toolkit { oneshotCallbackMethod, handlerSig, staticArena); + + try { + MethodHandle onSaveMethod = MethodHandles.lookup().findStatic( + ListSaveWrapper.class, + "onSaveHandler", + MethodType.methodType(boolean.class, MemorySegment.class, int.class, int.class, MemorySegment.class, MemorySegment.class)); + + onSaveHandler = linker.upcallStub( + onSaveMethod, + FunctionDescriptor.of(ValueLayout.JAVA_BOOLEAN, ValueLayout.ADDRESS, ValueLayout.JAVA_INT, ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.ADDRESS), + staticArena); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } } public static Toolkit getInstance() { diff --git a/ui-java/src/main/java/de/unixwork/ui/ToolkitFuncs.java b/ui-java/src/main/java/de/unixwork/ui/ToolkitFuncs.java index 84dd14f..5e21bc0 100644 --- a/ui-java/src/main/java/de/unixwork/ui/ToolkitFuncs.java +++ b/ui-java/src/main/java/de/unixwork/ui/ToolkitFuncs.java @@ -80,6 +80,11 @@ public class ToolkitFuncs { public MethodHandle textstyle_set_color; public MethodHandle textstyle_enable_color; + public MethodHandle cell_value_is_string; + public MethodHandle cell_value_is_int; + public MethodHandle cell_value_get_string; + public MethodHandle cell_value_get_int; + public MemorySegment ui_set_visible_addr; public MemorySegment ui_set_enabled_addr; @@ -124,6 +129,7 @@ public class ToolkitFuncs { FunctionDescriptor sigv_mdd = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.JAVA_DOUBLE, ValueLayout.JAVA_DOUBLE); FunctionDescriptor sigv_mmmi = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_INT); FunctionDescriptor sigv_mmmmi = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_INT); + FunctionDescriptor sigb_m = FunctionDescriptor.of(ValueLayout.JAVA_BOOLEAN, ValueLayout.ADDRESS); MemorySegment object_get_context_addr = lib.find("ui_object_get_context").orElseThrow(); @@ -199,6 +205,11 @@ public class ToolkitFuncs { MemorySegment textstyle_set_color_addr = lib.find("ui_textstyle_set_color").orElseThrow(); MemorySegment textstyle_enable_color_addr = lib.find("ui_textstyle_enable_color").orElseThrow(); + MemorySegment cell_value_is_string_addr = lib.find("ui_cell_value_is_string").orElseThrow(); + MemorySegment cell_value_is_int_addr = lib.find("ui_cell_value_is_int").orElseThrow(); + MemorySegment cell_value_get_string_addr = lib.find("ui_cell_value_get_string").orElseThrow(); + MemorySegment cell_value_get_int_addr = lib.find("ui_cell_value_get_int").orElseThrow(); + ui_set_visible_addr = lib.find("ui_set_visible").orElseThrow(); ui_set_enabled_addr = lib.find("ui_set_enabled").orElseThrow(); MemorySegment ui_widget_set_groups2_addr = lib.find("ui_widget_set_groups2").orElseThrow(); @@ -294,6 +305,11 @@ public class ToolkitFuncs { textstyle_set_color = linker.downcallHandle(textstyle_set_color_addr, sigv_miii); textstyle_enable_color = linker.downcallHandle(textstyle_enable_color_addr, sigv_mb); + cell_value_is_string = linker.downcallHandle(cell_value_is_string_addr, sigb_m); + cell_value_is_int = linker.downcallHandle(cell_value_is_int_addr, sigb_m); + cell_value_get_string = linker.downcallHandle(cell_value_get_string_addr, sigm_m); + cell_value_get_int = linker.downcallHandle(cell_value_get_int_addr, sigl_m); + set_enabled = linker.downcallHandle(ui_set_enabled_addr, sigv_mi); set_visible = linker.downcallHandle(ui_set_visible_addr, sigv_mi); set_widget_groups2 = linker.downcallHandle(ui_widget_set_groups2_addr, sigv_mmmmi); diff --git a/ui-java/src/main/java/de/unixwork/ui/UiObject.java b/ui-java/src/main/java/de/unixwork/ui/UiObject.java index f55031b..4b49d1e 100644 --- a/ui-java/src/main/java/de/unixwork/ui/UiObject.java +++ b/ui-java/src/main/java/de/unixwork/ui/UiObject.java @@ -9,6 +9,7 @@ public class UiObject extends Context { private ArrayList eventHandlers = new ArrayList<>(); private ArrayList closeHandlers = new ArrayList<>(); + private ArrayList listSaveHandlers = new ArrayList<>(); private Arena arena; @@ -91,6 +92,15 @@ public class UiObject extends Context { return eventHandlers.get(index); } + public long addListSaveHandler(ListSaveHandler handler) { + listSaveHandlers.add(handler); + return listSaveHandlers.size() - 1; + } + + public ListSaveHandler getListSaveHandler(int index) { + return listSaveHandlers.get(index); + } + public Arena getArena() { if (arena == null) { arena = Arena.ofShared(); -- 2.47.3