diff -r 1524b5dc4d4d -r 0accf125a65f ui/common/action.c --- a/ui/common/action.c Thu Apr 16 17:41:35 2026 +0200 +++ b/ui/common/action.c Fri Apr 17 13:21:11 2026 +0200 @@ -49,6 +49,7 @@ 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 @@ 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 @@ 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); + } + } +}