]> uap-core.de Git - note.git/commitdiff
add action parameter to button/toggle builder main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Fri, 17 Apr 2026 12:55:40 +0000 (14:55 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Fri, 17 Apr 2026 12:55:40 +0000 (14:55 +0200)
20 files changed:
ui-rs/src/ui/button.rs
ui/common/action.c
ui/common/action.h
ui/common/args.c
ui/common/args.h
ui/common/context.c
ui/common/context.h
ui/common/document.c
ui/common/menu.c
ui/common/menu.h
ui/gtk/action.c [new file with mode: 0644]
ui/gtk/action.h [new file with mode: 0644]
ui/gtk/menu.c
ui/gtk/objs.mk
ui/gtk/toolkit.c
ui/gtk/toolkit.h
ui/ui/button.h
ui/ui/menu.h
ui/ui/text.h
ui/ui/toolkit.h

index c574590fc33a4a65a5870573bee8344a6445b062..26dcf4f39c1ed272440b2d4a856cf1830c4269e7 100644 (file)
@@ -269,6 +269,14 @@ impl<'a, T> ButtonBuilder<'a, T> {
         self
     }
 
+    pub fn action(&mut self, action: &str) -> &mut Self {
+        let cstr = CString::new(action).unwrap();
+        unsafe {
+            ui_button_args_set_action(self.args, cstr.as_ptr());
+        }
+        self
+    }
+
     pub fn visibility_states(&mut self, states: &[i32]) -> &mut Self {
         unsafe {
             ui_button_args_set_visibility_states(self.args, states.as_ptr(), states.len() as c_int);
@@ -453,6 +461,14 @@ impl<'a, T> ToggleBuilder<'a, T> {
         self
     }
 
+    pub fn action(&mut self, action: &str) -> &mut Self {
+        let cstr = CString::new(action).unwrap();
+        unsafe {
+            ui_toggle_args_set_action(self.args, cstr.as_ptr());
+        }
+        self
+    }
+
     pub fn visibility_states(&mut self, states: &[i32]) -> &mut Self {
         unsafe {
             ui_toggle_args_set_visibility_states(self.args, states.as_ptr(), states.len() as c_int);
@@ -499,6 +515,7 @@ extern "C" {
     fn ui_button_args_set_labeltype(args: *mut UiButtonArgs, ltype: c_int);
     fn ui_button_args_set_onclick(args: *mut UiButtonArgs, callback: UiCallback);
     fn ui_button_args_set_onclickdata(args: *mut UiButtonArgs, data: *mut c_void);
+    fn ui_button_args_set_action(args: *mut UiButtonArgs, action: *const c_char);
     fn ui_button_args_set_states(args: *mut UiButtonArgs, states: *const c_int, numstates: c_int);
     fn ui_button_args_set_visibility_states(args: *mut UiButtonArgs, states: *const c_int, numstates: c_int);
     fn ui_button_args_free(args: *mut UiButtonArgs);
@@ -525,6 +542,7 @@ extern "C" {
     fn ui_toggle_args_set_labeltype(args: *mut UiToggleArgs, ltype: c_int);
     fn ui_toggle_args_set_onchange(args: *mut UiToggleArgs, callback: UiCallback);
     fn ui_toggle_args_set_onchangedata(args: *mut UiToggleArgs, data: *mut c_void);
+    fn ui_toggle_args_set_action(args: *mut UiToggleArgs, action: *const c_char);
     fn ui_toggle_args_set_varname(args: *mut UiToggleArgs, varname: *const c_char);
     fn ui_toggle_args_set_value(args: *mut UiToggleArgs, ivalue: *mut UiInteger);
     fn ui_toggle_args_set_enablestate(args: *mut UiToggleArgs, state: c_int);
index 9c53b5d9823ce0556eaed0143689f9a7d9154fab..19f5faa5f04e5d05e45ae2b82b211f44416aa707 100644 (file)
@@ -49,6 +49,7 @@ void uic_add_action(
     action.userdata = userdata;
     action.accelerator = accelerator ? ui_strdup(ctx, accelerator) : NULL;
     action.accelerator_text = accelerator_text ? ui_strdup(ctx, accelerator_text) : NULL;
+    action.ctx = ctx;
     cxMapPut(ctx->actions, name, &action);
     cxMapRehash(ctx->actions);
 }
@@ -57,8 +58,7 @@ void uic_bind_action(
         UiContext *ctx,
         const char *action,
         void *bind_obj,
-        ui_action_binding_set_enabled_func set_enabled,
-        ui_action_binding_set_accelerator_text_func set_accelerator_text)
+        ui_enablefunc set_enabled)
 {
     if(!action) {
         return;
@@ -68,6 +68,76 @@ void uic_bind_action(
     binding.action = ui_strdup(ctx, action);
     binding.userdata = bind_obj;
     binding.set_enabled = set_enabled;
-    binding.set_accelerator_text = set_accelerator_text;
     cxListAdd(ctx->action_bindings, &binding);
 }
+
+UiAction* uic_resolve_action(UiContext *ctx, const char *action) {
+    UiAction *a = NULL;
+    if(ctx->actions) {
+        a = cxMapGet(ctx->actions, action);
+    }
+    // check if any sub-document defines this action
+    // sub-document actions have precedence, the most specific action will
+    // be returned
+    CxIterator i = cxListIterator(ctx->documents);
+    cx_foreach(void *, doc, i) {
+        UiContext *doc_ctx = ui_document_context(doc);
+        UiAction *sub_action = uic_resolve_action(doc_ctx, action);
+        if(sub_action) {
+            a = sub_action;
+            // if one sub-tree has an action, we don't care about other
+            // subtrees
+            break;
+        }
+    }
+    
+    if(!a && ctx->parent) {
+        // check parents
+        a = uic_resolve_action_from_parents(ctx, action);
+    }
+    
+    return a;
+}
+
+UiAction* uic_resolve_action_from_parents(UiContext *ctx, const char *action) {
+    UiContext *parent = ctx->parent;
+    if(parent == NULL) {
+        return NULL;
+    }
+    if(parent->actions) {
+        UiAction *a = cxMapGet(parent->actions, action);
+        if(a) {
+            return a;
+        }
+    }
+    return uic_resolve_action_from_parents(parent, action);
+}
+
+
+
+void ui_update_action_bindings(UiContext *ctx) {
+    CxIterator i = cxListIterator(ctx->action_bindings);
+    cx_foreach(UiActionBinding*, binding, i) {
+        UiAction *action = uic_resolve_action(ctx, binding->action);
+        if(binding->set_enabled) {
+            binding->set_enabled(binding->userdata, action != NULL);
+        }
+    }
+}
+
+void uic_action_callback(UiEvent *event, const char *action_name) {
+    UiContext *ctx = ui_global_context();
+    if(event->obj) {
+        ctx = event->obj->ctx;
+    }
+    
+    UiAction *action = uic_resolve_action(ctx, action_name);
+    if(action) {
+        // override event document: for actions we know that the event is
+        // for a specific document
+        event->document = action->ctx->self_doc;
+        if(action->callback) {
+            action->callback(event, action->userdata);
+        }
+    }
+}
index a36382761af0a9320cbcc6b15cb5f69efcd27f9a..1364635a51fcb16ef40c7efa2ffe630142a44e3d 100644 (file)
@@ -44,14 +44,12 @@ struct UiAction {
     char *accelerator_text;
     ui_callback callback;
     void *userdata;
+    UiContext *ctx;
 };
 
-typedef void (*ui_action_binding_set_enabled_func)(void *bind_obj, UiBool enabled);
-typedef void (*ui_action_binding_set_accelerator_text_func)(void *bind_obj, const char *text);
 struct UiActionBinding {
     const char *action;
-    ui_action_binding_set_enabled_func set_enabled;
-    ui_action_binding_set_accelerator_text_func set_accelerator_text;
+    ui_enablefunc set_enabled;
     void *userdata;
 };
 
@@ -67,8 +65,13 @@ void uic_bind_action(
         UiContext *ctx,
         const char *action,
         void *bind_obj,
-        ui_action_binding_set_enabled_func set_enabled,
-        ui_action_binding_set_accelerator_text_func set_accelerator_text);
+        ui_enablefunc set_enabled);
+
+UiAction* uic_resolve_action(UiContext *ctx, const char *action);
+UiAction* uic_resolve_action_from_parents(UiContext *ctx, const char *action);
+
+// action event wrapper
+void uic_action_callback(UiEvent *event, const char *action_name);
 
 #ifdef __cplusplus
 }
index b6c4f65e8f2582f725fe4b87eee8ccb7444f4051..ac489bf942f5defd2d86a8019677de56779131b4 100644 (file)
@@ -215,9 +215,14 @@ void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata) {
     args->onclickdata = onclickdata;
 }
 
+void ui_menuitem_args_set_action(UiMenuItemArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_menuitem_args_free(UiMenuItemArgs *args) {
     free((void*)args->label);
     free((void*)args->icon);
+    free((void*)args->action);
     free(args);
 }
 
@@ -250,10 +255,15 @@ void ui_menutoggleitem_args_set_onchangedata(UiMenuToggleItemArgs *args, void *o
     args->onchangedata = onclickdata;
 }
 
+void ui_menutoggleitem_args_set_action(UiMenuToggleItemArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_menutoggleitem_args_free(UiMenuToggleItemArgs *args) {
     free((void*)args->label);
     free((void*)args->icon);
     free((void*)args->varname);
+    free((void*)args->action);
     free(args);
 }
 
@@ -1440,6 +1450,10 @@ void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata){
     args->onclickdata = onclickdata;
 }
 
+void ui_button_args_set_action(UiButtonArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_button_args_set_states(UiButtonArgs *args, int *states, int numstates) {
     args->states = calloc(numstates+1, sizeof(int));
     memcpy((void*)args->states, states, numstates * sizeof(int));
@@ -1458,6 +1472,7 @@ void ui_button_args_free(UiButtonArgs *args) {
     free((void*)args->label);
     free((void*)args->icon);
     free((void*)args->tooltip);
+    free((void*)args->action);
     free((void*)args->states);
     free((void*)args->visibility_states);
     free(args);
@@ -1558,6 +1573,10 @@ void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata){
     args->onchangedata = onchangedata;
 }
 
+void ui_toggle_args_set_action(UiToggleArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname) {
     args->varname = strdup(varname);
 }
@@ -1589,6 +1608,7 @@ void ui_toggle_args_free(UiToggleArgs *args) {
     free((void*)args->icon);
     free((void*)args->tooltip);
     free((void*)args->varname);
+    free((void*)args->action);
     free((void*)args->states);
     free((void*)args->visibility_states);
     free(args);
@@ -1688,6 +1708,10 @@ void ui_linkbutton_args_set_onclickdata(UiLinkButtonArgs *args, void *userdata)
     args->onclickdata = userdata;
 }
 
+void ui_linkbutton_args_set_action(UiLinkButtonArgs *args, const char *action) {
+    args->action = strdup(action);
+}
+
 void ui_linkbutton_args_set_nofollow(UiLinkButtonArgs *args, UiBool value) {
     args->nofollow = value;
 }
@@ -1721,6 +1745,7 @@ void ui_linkbutton_args_free(UiLinkButtonArgs *args) {
     free((void*)args->style_class);
     free((void*)args->label);
     free((void*)args->uri);
+    free((void*)args->action);
     free((void*)args->varname);
     free((void*)args->states);
     free(args);
@@ -2286,6 +2311,14 @@ void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivat
     args->onactivatedata = onactivatedata;
 }
 
+void ui_textfield_args_set_onactivate_action(UiTextFieldArgs *args, const char *action) {
+    args->onactivate_action = strdup(action);
+}
+
+void ui_textfield_args_set_onchange_action(UiTextFieldArgs *args, const char *action) {
+    args->onchange_action = action;
+}
+
 void ui_textfield_args_set_varname(UiTextFieldArgs *args, const char *varname) {
     args->varname = strdup(varname);
 }
@@ -2310,6 +2343,8 @@ void ui_textfield_args_free(UiTextFieldArgs *args) {
     free((void*)args->name);
     free((void*)args->style_class);
     free((void*)args->varname);
+    free((void*)args->onactivate_action);
+    free((void*)args->onchange_action);
     free((void*)args->states);
     free((void*)args->visibility_states);
     free(args);
index 5bd93bbe053feafca3c601fabe9082bc75391394..739affbdd4bbfd3cc4cd7e87d1929258b92ed8cf 100644 (file)
@@ -83,6 +83,7 @@ UIEXPORT void ui_menuitem_args_set_label(UiMenuItemArgs *args, const char *label
 UIEXPORT void ui_menuitem_args_set_icon(UiMenuItemArgs *args, const char *icon);
 UIEXPORT void ui_menuitem_args_set_onclick(UiMenuItemArgs *args, ui_callback callback);
 UIEXPORT void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata);
+UIEXPORT void ui_menuitem_args_set_action(UiMenuItemArgs *args, const char *action);
 UIEXPORT void ui_menuitem_args_free(UiMenuItemArgs *args);
 
 UIEXPORT UiMenuToggleItemArgs* ui_menutoggleitem_args_new(void);
@@ -91,6 +92,7 @@ UIEXPORT void ui_menutoggleitem_args_set_icon(UiMenuToggleItemArgs *args, const
 UIEXPORT void ui_menutoggleitem_args_set_varname(UiMenuToggleItemArgs *args, const char *varname);
 UIEXPORT void ui_menutoggleitem_args_set_onchange(UiMenuToggleItemArgs *args, ui_callback callback);
 UIEXPORT void ui_menutoggleitem_args_set_onchangedata(UiMenuToggleItemArgs *args, void *onchangedata);
+UIEXPORT void ui_menutoggleitem_args_set_action(UiMenuToggleItemArgs *args, const char *action);
 UIEXPORT void ui_menutoggleitem_args_free(UiMenuToggleItemArgs *args);
 
 UIEXPORT UiMenuItemListArgs* ui_menuitemlist_args_new(void);
@@ -353,6 +355,7 @@ UIEXPORT void ui_button_args_set_tooltip(UiButtonArgs *args, const char *tooltip
 UIEXPORT void ui_button_args_set_labeltype(UiButtonArgs *args, int labeltype);
 UIEXPORT void ui_button_args_set_onclick(UiButtonArgs *args, ui_callback callback);
 UIEXPORT void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata);
+UIEXPORT void ui_button_args_set_action(UiButtonArgs *args, const char *action);
 UIEXPORT void ui_button_args_set_states(UiButtonArgs *args, int *states, int numstates);
 UIEXPORT void ui_button_args_set_visibility_states(UiButtonArgs *args, int *states, int numstates);
 UIEXPORT void ui_button_args_free(UiButtonArgs *args);
@@ -379,6 +382,7 @@ UIEXPORT void ui_toggle_args_set_tooltip(UiToggleArgs *args, const char *tooltip
 UIEXPORT void ui_toggle_args_set_labeltype(UiToggleArgs *args, int labeltype);
 UIEXPORT void ui_toggle_args_set_onchange(UiToggleArgs *args, ui_callback callback);
 UIEXPORT void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata);
+UIEXPORT void ui_toggle_args_set_action(UiToggleArgs *args, const char *action);
 UIEXPORT void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname);
 UIEXPORT void ui_toggle_args_set_value(UiToggleArgs *args, UiInteger *value);
 UIEXPORT void ui_toggle_args_set_enablestate(UiToggleArgs *args, int state);
@@ -408,6 +412,7 @@ UIEXPORT void ui_linkbutton_args_set_label(UiLinkButtonArgs *args, const char *l
 UIEXPORT void ui_linkbutton_args_set_uri(UiLinkButtonArgs *args, const char *uri);
 UIEXPORT void ui_linkbutton_args_set_onclick(UiLinkButtonArgs *args, ui_callback callback);
 UIEXPORT void ui_linkbutton_args_set_onclickdata(UiLinkButtonArgs *args, void *userdata);
+UIEXPORT void ui_linkbutton_args_set_action(UiLinkButtonArgs *args, const char *action);
 UIEXPORT void ui_linkbutton_args_set_nofollow(UiLinkButtonArgs *args, UiBool value);
 UIEXPORT void ui_linkbutton_args_set_type(UiLinkButtonArgs *args, UiLinkType type);
 UIEXPORT void ui_linkbutton_args_set_states(UiLinkButtonArgs *args, int *states, int numstates);
@@ -506,6 +511,7 @@ UIEXPORT void ui_textarea_args_set_name(UiTextAreaArgs *args, const char *name);
 UIEXPORT void ui_textarea_args_set_style_class(UiTextAreaArgs *args, const char *classname);
 UIEXPORT void ui_textarea_args_set_onchange(UiTextAreaArgs *args, ui_callback callback);
 UIEXPORT void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata);
+UIEXPORT void ui_textarea_args_set_action(UiTextAreaArgs *args, const char *action);
 UIEXPORT void ui_textarea_args_set_varname(UiTextAreaArgs *args, const char *varname);
 UIEXPORT void ui_textarea_args_set_value(UiTextAreaArgs *args, UiText *value);
 UIEXPORT void ui_textarea_args_set_states(UiTextAreaArgs *args, int *states, int numstates);
@@ -532,6 +538,8 @@ UIEXPORT void ui_textfield_args_set_onchange(UiTextFieldArgs *args, ui_callback
 UIEXPORT void ui_textfield_args_set_onchangedata(UiTextFieldArgs *args, void *onchangedata);
 UIEXPORT void ui_textfield_args_set_onactivate(UiTextFieldArgs *args, ui_callback callback);
 UIEXPORT void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivatedata);
+UIEXPORT void ui_textfield_args_set_onactivate_action(UiTextFieldArgs *args, const char *action);
+UIEXPORT void ui_textfield_args_set_onchange_action(UiTextFieldArgs *args, const char *action);
 UIEXPORT void ui_textfield_args_set_varname(UiTextFieldArgs *args, const char *varname);
 UIEXPORT void ui_textfield_args_set_value(UiTextFieldArgs *args, UiString *value);
 UIEXPORT void ui_textfield_args_set_states(UiTextFieldArgs *args, int *states, int numstates);
index 6936de941a7d8a2ce89d09ce6d07f2996f39fdf2..f729978e4c29123e6edc9b6afeea33e50284cf63 100644 (file)
@@ -152,6 +152,8 @@ void uic_context_attach_document(UiContext *ctx, void *document) {
         
         var_ctx = var_ctx->parent;
     }
+    
+    ui_update_action_bindings(ctx);
 }
 
 static void uic_context_unbind_vars(UiContext *ctx) {
@@ -194,6 +196,8 @@ void uic_context_detach_document(UiContext *ctx, void *document) {
     UiContext *docctx = ui_document_context(document);
     uic_context_unbind_vars(docctx); // unbind all doc/subdoc vars from the parent
     docctx->parent = NULL;
+    
+    ui_update_action_bindings(ctx);
 }
 
 void uic_context_detach_all(UiContext *ctx) {
@@ -211,6 +215,7 @@ void uic_context_detach_all(UiContext *ctx) {
     }
     
     cxListFree(ls);
+    ui_update_action_bindings(ctx);
 }
 
 static UiVar* ctx_getvar(UiContext *ctx, CxHashKey key) {
index 50f5b445eec5b31f64447cb5dc29260c27cc2f03..c2bba8b9b2e7f6de6041d943d8b0852dc780f091 100644 (file)
@@ -66,6 +66,9 @@ struct UiContext {
     const CxAllocator *allocator;
     CxList *destroy_handler;
     
+    // document pointer, if this is a document context
+    void          *self_doc;
+    
     void          *document;
     CxList        *documents;
     
index 6c6da19681a9f0b30a770ddbbfa308ebabaedee8..b05d4845a443bb783efec436bc0a942fe3dcd676 100644 (file)
@@ -45,6 +45,7 @@ void* ui_document_new(size_t size) {
     
     UiDoc *document = cxCalloc(a, sizeof(UiDoc) + size, 1);
     document->ctx = ctx;
+    ctx->self_doc = document;
     return &document->doc;
 }
 
index b0a5d2e6bad0e69bdf40c2e182563cf6e54feeaa..84d75204318f7f9c59bfecf049a6f9b2a4a4313f 100644 (file)
@@ -148,6 +148,7 @@ void ui_menuitem_create(UiMenuItemArgs *args) {
     item->item.next = NULL;
     item->item.type = UI_MENU_ITEM;
 
+    item->action = nl_strdup(args->action);
     item->label = nl_strdup(args->label);
     item->icon = nl_strdup(args->icon);
     item->userdata = args->onclickdata;
index 9aea5789962c531fddfc7e618f7307197a1c275f..f2962abc1a07b17f5fe23b27f2a03101f9a6f95d 100644 (file)
@@ -76,6 +76,7 @@ struct UiMenu {
 struct UiMenuItem {
     UiMenuItemI    item;
     ui_callback    callback;
+    char           *action;
     char           *label;
     char           *icon;
     void           *userdata;
diff --git a/ui/gtk/action.c b/ui/gtk/action.c
new file mode 100644 (file)
index 0000000..80f0a42
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "action.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+/* ------------------------------ public API ------------------------------ */
+
+void ui_add_action(UiContext *ctx, const char *name, ui_callback callback, void *userdata) {
+    uic_add_action(ctx, name, callback, userdata, NULL, NULL);
+}
+
+void ui_add_action_with_accelerator(
+        UiContext *ctx,
+        const char *name,
+        ui_callback callback,
+        void *userdata,
+        const char *accelerator,
+        const char *accelerator_text)
+{
+    uic_add_action(ctx, name, callback, userdata, accelerator, accelerator_text);
+    
+    // TODO: accelerator
+}
diff --git a/ui/gtk/action.h b/ui/gtk/action.h
new file mode 100644 (file)
index 0000000..d13d3de
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ACTION_H
+#define ACTION_H
+
+#include "../ui/toolkit.h"
+#include "../common/action.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ACTION_H */
+
index 8bfbbbfe493608bc5617ea9741f9dbff59be66c9..c81cd123696aaa64a30356756ff952bc598e5970 100644 (file)
@@ -37,6 +37,7 @@
 #include "../common/context.h"
 #include "../common/menu.h"
 #include "../common/types.h"
+#include "../common/action.h"
 #include "../ui/properties.h"
 #include "../ui/window.h"
 #include "container.h"
@@ -590,7 +591,15 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject
         cxListFree(groups);
     }
     
-    if(i->callback != NULL) {
+    if(i->action) {
+        uic_bind_action(obj->ctx, i->action, action, (ui_enablefunc)action_enable);
+        UiAction *ui_action = uic_resolve_action(obj->ctx, i->action);
+        if(!ui_action) {
+            action_enable(action, FALSE);
+        }
+    }
+     
+    if(i->callback != NULL || i->action) {
         UiEventData *event = malloc(sizeof(UiEventData));
         event->obj = obj;
         event->userdata = i->userdata;
@@ -598,6 +607,7 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject
         event->value = 0;
         event->customdata = NULL;
         event->customint = 0;
+        event->action = i->action ? strdup(i->action) : NULL;
 
         g_signal_connect(
                 action,
@@ -607,13 +617,13 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject
         g_signal_connect(
                 obj->widget,
                 "destroy",
-                G_CALLBACK(ui_destroy_userdata),
+                G_CALLBACK(ui_destroy_eventdata),
                 event);
     }
     
     char action_name[32];
     snprintf(action_name, 32, "win.%s", item->id);
-    
+     
     g_menu_append(parent, i->label, action_name);
 }
 
@@ -888,7 +898,12 @@ void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEvent
         evt.eventdatatype = uic_get_tmp_eventdata_type();
     }
     evt.intval = intval;
-    event->callback(&evt, event->userdata);
+    if(event->callback) {
+        event->callback(&evt, event->userdata);
+    }
+    if(event->action) {
+        uic_action_callback(&evt, event->action);
+    }
     uic_set_tmp_eventdata(NULL, 0);
 }
 
index abad5a0679c8ab7a816f25b1260ab08ae5bbcffe..1c7964601c6637a9839c0348835efc036886e885 100644 (file)
@@ -48,6 +48,7 @@ GTKOBJ += dnd.o
 GTKOBJ += headerbar.o
 GTKOBJ += webview.o
 GTKOBJ += widget.o
+GTKOBJ += action.o
 
 TOOLKITOBJS += $(GTKOBJ:%=$(GTK_OBJPRE)%)
 TOOLKITSOURCE += $(GTKOBJ:%.o=gtk/%.c)
index e31009174c559a2bcc0b0a90a280aac337e52dcd..0ad0fe83b503e02210c246296a6350ab700fb9e0 100644 (file)
@@ -313,6 +313,11 @@ void ui_destroy_userdata(GtkWidget *object, void *userdata) {
     free(userdata);
 }
 
+void ui_destroy_eventdata(GtkWidget *object, UiEventData *data) {
+    free(data->action);
+    free(data);
+}
+
 void ui_destroy_vardata(GtkWidget *unused, UiVarEventData *data) {
     if(data->var) {
         ui_destroy_boundvar(data->obj->ctx, data->var);
index e16f3614806e243ca48f9049eb55da26f8aacce5..25a48f580f21535b36a99c580424b6ac0426fb8c 100644 (file)
@@ -149,6 +149,7 @@ typedef struct UiEventData {
     int         value;
     int         customint;
     void        *customdata;
+    char        *action;
 } UiEventData;
 
 typedef struct UiEventDataExt {
@@ -200,6 +201,7 @@ void ui_set_widget_visibility_states(UiContext *ctx, GtkWidget *widget, const in
 void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const int *states, size_t ngroups);
 
 void ui_destroy_userdata(GtkWidget *object, void *userdata);
+void ui_destroy_eventdata(GtkWidget *object, UiEventData *data);
 void ui_destroy_vardata(GtkWidget *unused, UiVarEventData *data);
 void ui_destroy_widget_var(GtkWidget *object, UiVar *var);
 void ui_destroy_boundvar(UiContext *ctx, UiVar *var);
index c7db3968f8bf049f10ab16d6f73f8c40d31cc053..b9c56c4e8465e91999383444e1fcdda780f5a869 100644 (file)
@@ -63,7 +63,8 @@ typedef struct UiButtonArgs {
     const char *tooltip;
     UiLabelType labeltype;
     ui_callback onclick;
-    void *onclickdata;
+    void        *onclickdata;
+    const char  *action;
     
     const int *states;
     const int *visibility_states;
@@ -86,18 +87,19 @@ typedef struct UiToggleArgs {
     const char *name;
     const char *style_class;
     
-    const char *label;
-    const char *icon;
-    const char *tooltip;
+    const char  *label;
+    const char  *icon;
+    const char  *tooltip;
     UiLabelType labeltype;
-    UiInteger *value;
-    const char *varname;
+    UiInteger   *value;
+    const char  *varname;
     ui_callback onchange;
-    void *onchangedata;
-    int enable_state;
+    void        *onchangedata;
+    const char  *action;
+    int         enable_state;
     
-    const int *states;
-    const int *visibility_states;
+    const int   *states;
+    const int   *visibility_states;
 } UiToggleArgs;
 
 typedef struct UiLinkButtonArgs {
@@ -123,6 +125,7 @@ typedef struct UiLinkButtonArgs {
     const char *varname;
     ui_callback onclick;
     void *onclickdata;
+    const char *action;
     UiBool nofollow;
     UiLinkType type;
     
index bd5b96b6a5d320ebe88263255808af01eaf378df..f659574a2c405cb7120d4f8ed28657c03152ead9 100644 (file)
@@ -39,7 +39,7 @@ extern "C" {
 typedef struct UiMenuItemArgs {
        const char *label;
        const char *icon;
-
+        
        ui_callback onclick;
        void *onclickdata;
         const char *action;
index ebea880d84bc0c4c7df1b75155cf8dd27df593dc..15f7ced7942ac74fcba207c1023a28bdcd46c8b4 100644 (file)
@@ -58,6 +58,7 @@ typedef struct UiTextAreaArgs {
     const char *varname;
     ui_callback onchange;
     void *onchangedata;
+    const char *action;
     
     const int *states;
     const int *visibility_states;
@@ -87,6 +88,8 @@ typedef struct UiTextFieldArgs {
     void *onchangedata;
     ui_callback onactivate;
     void *onactivatedata;
+    const char *onactivate_action;
+    const char *onchange_action;
     
     const int *states;
     const int *visibility_states;
@@ -129,6 +132,7 @@ typedef struct UiPathTextFieldArgs {
 
     ui_callback onactivate;
     void *onactivatedata;
+    const char *action;
     
     ui_callback ondragstart;
     void *ondragstartdata;
index 76a4e56ae78f57377dcb74e39603f3e46adb9a3a..cdb75b73646594fb6a8ebcb95663981289e5b1bb 100644 (file)
@@ -589,6 +589,16 @@ UIEXPORT void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefun
 UIEXPORT void ui_widget_set_states2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *states, int nstates);
 UIEXPORT void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int *states, int nstates);
 
+UIEXPORT void ui_add_action(UiContext *ctx, const char *name, ui_callback callback, void *userdata);
+UIEXPORT void ui_add_action_with_accelerator(
+        UiContext *ctx,
+        const char *name,
+        ui_callback callback,
+        void *userdata,
+        const char *accelerator,
+        const char *accelerator_text);
+UIEXPORT void ui_update_action_bindings(UiContext *ctx);
+
 UIEXPORT void ui_set_state(UiContext *ctx, int state);
 UIEXPORT void ui_unset_state(UiContext *ctx, int state);
 UIEXPORT int* ui_active_states(UiContext *ctx, int *nstates);