change ui_active_states to return also active states from sub-documents

Mon, 15 Jun 2026 21:13:05 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 15 Jun 2026 21:13:05 +0200
changeset 1201
fd7dc0716ab6
parent 1200
abb4d3851061
child 1202
412790168d30

change ui_active_states to return also active states from sub-documents

application/Makefile file | annotate | diff | comparison | revisions
application/demo_bindings.c file | annotate | diff | comparison | revisions
application/demo_states.c file | annotate | diff | comparison | revisions
application/demo_states.h file | annotate | diff | comparison | revisions
application/main.c file | annotate | diff | comparison | revisions
ui/common/context.c file | annotate | diff | comparison | revisions
ui/gtk/text.c file | annotate | diff | comparison | revisions
ui/ui/toolkit.h file | annotate | diff | comparison | revisions
--- a/application/Makefile	Sun Jun 14 12:10:34 2026 +0200
+++ b/application/Makefile	Mon Jun 15 21:13:05 2026 +0200
@@ -33,11 +33,13 @@
 
 APP_BIN_OBJ = ../build/application/main$(OBJ_EXT)
 DEMO_BINDINGS_OBJ = ../build/application/demo_bindings$(OBJ_EXT)
+DEMO_STATES_OBJ = ../build/application/demo_states$(OBJ_EXT)
 
 APP_BIN = ../build/$(BUILD_BIN_DIR)/mk12$(APP_EXT)
 DEMO_BINDINGS = ../build/$(BUILD_BIN_DIR)/demo_bindings$(APP_EXT)
+DEMO_STATES = ../build/$(BUILD_BIN_DIR)/demo_states$(APP_EXT)
 
-all: $(APP_BIN) $(DEMO_BINDINGS)
+all: $(APP_BIN) $(DEMO_BINDINGS) $(DEMO_STATES)
 
 include $(SYS_MAKEFILE)
 
@@ -46,12 +48,19 @@
 
 $(DEMO_BINDINGS): $(DEMO_BINDINGS_OBJ) $(RES_FILE) $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)uitk$(LIB_EXT)
 	$(LD) -o $(DEMO_BINDINGS) $(DEMO_BINDINGS_OBJ) $(RES_FILE) $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)uitk$(LIB_EXT) $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)ucx$(LIB_EXT) $(LDFLAGS) $(TK_LDFLAGS)
+	
+$(DEMO_STATES): $(DEMO_STATES_OBJ) $(RES_FILE) $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)uitk$(LIB_EXT)
+	$(LD) -o $(DEMO_STATES) $(DEMO_STATES_OBJ) $(RES_FILE) $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)uitk$(LIB_EXT) $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)ucx$(LIB_EXT) $(LDFLAGS) $(TK_LDFLAGS)
 
 FORCE:
 
 ../build/application/demo_bindings$(OBJ_EXT): demo_bindings.c \
  demo_bindings.h
 	$(CC) -o $@ $(CFLAGS) $(TK_CFLAGS) -c $<
+	
+../build/application/demo_states$(OBJ_EXT): demo_states.c \
+ demo_states.h
+	$(CC) -o $@ $(CFLAGS) $(TK_CFLAGS) -c $<
 
 ../build/application/main$(OBJ_EXT): main.c
 	$(CC) -o $@ $(CFLAGS) $(TK_CFLAGS) -c $<
--- a/application/demo_bindings.c	Sun Jun 14 12:10:34 2026 +0200
+++ b/application/demo_bindings.c	Mon Jun 15 21:13:05 2026 +0200
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2017 Olaf Wintermann. All rights reserved.
+ * 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:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/application/demo_states.c	Mon Jun 15 21:13:05 2026 +0200
@@ -0,0 +1,162 @@
+/*
+ * 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 "demo_states.h"
+
+#include <inttypes.h>
+
+static void *doc1;
+static void *doc2;
+
+static void doc1_attachment(UiEvent *event, void *userdata) {
+    if(event->intval) {
+        printf("attach document 1\n");
+        ui_attach_document(event->obj->ctx, doc1);
+    } else {
+        printf("detach document 1\n");
+        ui_detach_document(event->obj->ctx, doc1);
+    }
+}
+
+static void doc2_attachment(UiEvent *event, void *userdata) {
+    UiContext *ctx = ui_document_context(doc1);
+    if(event->intval) {
+        printf("attach document 2 to document 1\n");
+        ui_attach_document(ctx, doc2);
+    } else {
+        printf("detach document 2 from document 1\n");
+        ui_detach_document(ctx, doc2);
+    }
+}
+
+static void doc_enable_state1(UiEvent *event, void *doc) {
+    UiContext *ctx = ui_document_context(doc);
+    if(event->intval) {
+        ui_set_state(ctx, 1);
+    } else {
+        ui_unset_state(ctx, 1);
+    }
+}
+
+static void doc_enable_state2(UiEvent *event, void *doc) {
+    UiContext *ctx = ui_document_context(doc);
+    if(event->intval) {
+        ui_set_state(ctx, 2);
+    } else {
+        ui_unset_state(ctx, 2);
+    }
+}
+
+static void doc_enable_state3(UiEvent *event, void *doc) {
+    UiContext *ctx = ui_document_context(doc);
+    if(event->intval) {
+        ui_set_state(ctx, 3);
+    } else {
+        ui_unset_state(ctx, 3);
+    }
+}
+
+static void doc_enable_state4(UiEvent *event, void *doc) {
+    UiContext *ctx = ui_document_context(doc);
+    if(event->intval) {
+        ui_set_state(ctx, 4);
+    } else {
+        ui_unset_state(ctx, 4);
+    }
+}
+
+static void application_startup(UiEvent *event, void *userdata) {
+    UiObject *obj = ui_window("States Demo");
+    
+    doc1 = ui_document_new(8);
+    doc2 = ui_document_new(8);
+    
+    ui_hbox(obj, .margin = 10, .spacing = 8) {
+        ui_button(obj, .label = "State 1", .states = UI_STATES(1));
+        ui_button(obj, .label = "State 2", .states = UI_STATES(2));
+        ui_button(obj, .label = "State 3", .states = UI_STATES(3));
+        ui_button(obj, .label = "State 4", .states = UI_STATES(4));
+        ui_button(obj, .label = "State 1,2", .states = UI_STATES(1, 2));
+        ui_button(obj, .label = "State 1,2,3", .states = UI_STATES(1, 2, 3));
+        ui_button(obj, .label = "State 1,2,3,4", .states = UI_STATES(1, 2, 3, 4));
+    }
+    
+    ui_frame(obj, .label = "Window", .fill = TRUE, .margin = 10, .subcontainer = UI_CONTAINER_VBOX) {
+        ui_hbox(obj, .margin = 10, .spacing = 8) {
+            ui_togglebutton(obj, .label = "Enable 1", .enable_state = 1);
+            ui_togglebutton(obj, .label = "Enable 2", .enable_state = 2);
+            ui_togglebutton(obj, .label = "Enable 3", .enable_state = 3);
+            ui_togglebutton(obj, .label = "Enable 4", .enable_state = 4);
+        }
+        
+        ui_frame(obj, .label = "Doc 1", .fill = TRUE, .margin = 10, .padding = 10, .spacing = 10, .subcontainer = UI_CONTAINER_VBOX) {
+            ui_togglebutton(obj, .label = "Attach", .onchange = doc1_attachment);
+            
+            ui_hbox(obj, .margin = 10, .spacing = 8) {
+                ui_togglebutton(obj, .label = "Enable 1", .onchange = doc_enable_state1, .onchangedata = doc1);
+                ui_togglebutton(obj, .label = "Enable 2", .onchange = doc_enable_state2, .onchangedata = doc1);
+                ui_togglebutton(obj, .label = "Enable 3", .onchange = doc_enable_state3, .onchangedata = doc1);
+                ui_togglebutton(obj, .label = "Enable 4", .onchange = doc_enable_state4, .onchangedata = doc1);
+            }
+            
+            ui_frame(obj, .label = "Doc 2", .fill = TRUE, .margin = 10, .padding = 10, .spacing = 10, .subcontainer = UI_CONTAINER_VBOX) {
+                ui_togglebutton(obj, .label = "Attach", .onchange = doc2_attachment);
+            
+                ui_hbox(obj, .margin = 10, .spacing = 8) {
+                    ui_togglebutton(obj, .label = "Enable 1", .onchange = doc_enable_state1, .onchangedata = doc2);
+                    ui_togglebutton(obj, .label = "Enable 2", .onchange = doc_enable_state2, .onchangedata = doc2);
+                    ui_togglebutton(obj, .label = "Enable 3", .onchange = doc_enable_state3, .onchangedata = doc2);
+                    ui_togglebutton(obj, .label = "Enable 4", .onchange = doc_enable_state4, .onchangedata = doc2);
+                }
+            }
+        }
+    }
+    
+    ui_show(obj);
+}
+
+
+#ifndef UI_WIN32
+
+int main(int argc, char **argv) {
+    ui_init(NULL, argc, argv);
+    ui_onstartup(application_startup, NULL);
+    ui_main();
+    return 0;
+}
+
+#else
+
+int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
+    //ui_init(NULL, argc, argv);
+    //ui_onstartup(application_startup, NULL);
+    //ui_main();
+    return 0;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/application/demo_states.h	Mon Jun 15 21:13:05 2026 +0200
@@ -0,0 +1,46 @@
+/*
+ * 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 DEMO_STATES_H
+#define DEMO_STATES_H
+
+#include <ui/ui.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DEMO_STATES_H */
+
--- a/application/main.c	Sun Jun 14 12:10:34 2026 +0200
+++ b/application/main.c	Mon Jun 15 21:13:05 2026 +0200
@@ -726,7 +726,7 @@
                 ui_button(obj, .label = "Disable Group 2", .onclick = action_group2, .onclickdata = "disable");
                 ui_newline(obj);
                 
-                ui_button(obj, .label = "Groups 1,2", .colspan = 2, .states = UI_GROUPS(1, 2));
+                ui_button(obj, .label = "Groups 1,2", .colspan = 2, .states = UI_STATES(1, 2));
                 ui_newline(obj);
 
                 ui_label(obj, .label = "Label Col 1", .align = UI_ALIGN_LEFT);
--- a/ui/common/context.c	Sun Jun 14 12:10:34 2026 +0200
+++ b/ui/common/context.c	Mon Jun 15 21:13:05 2026 +0200
@@ -196,6 +196,7 @@
         event.document = document;
         doc_ctx->onattach(&event, doc_ctx->onattachdata);
     }
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
     uic_send_status_change(doc_ctx);
 }
 
@@ -252,6 +253,7 @@
         doc_ctx->ondetach(&event, doc_ctx->ondetachdata);
     }
     
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
     uic_send_status_change(doc_ctx);
     ui_document_unref(document);
 }
@@ -651,6 +653,15 @@
     return ctx->parent;
 }
 
+UiContext* ui_context_toplevel_parent(UiContext *ctx) {
+    if(ctx->obj) {
+        return ctx;
+    } else if (ctx->parent) {
+        return ui_context_toplevel_parent(ctx->parent);
+    }
+    return NULL;
+}
+
 
 void ui_set_state(UiContext *ctx, int state) {
     if(!cxListIndexValid(ctx->states, cxListFind(ctx->states, &state))) {
@@ -658,7 +669,7 @@
     }
     
     // enable/disable group widgets
-    uic_check_state_widgets(ctx);
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
 }
 
 void ui_unset_state(UiContext *ctx, int state) {
@@ -668,15 +679,39 @@
     }
     
     // enable/disable group widgets
-    uic_check_state_widgets(ctx);
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
+}
+
+typedef struct StatesList {
+    CX_ARRAY(int, states);
+} StatesList;
+
+static void add_ctx_states(UiContext *ctx, StatesList *states) {
+    size_t nstates = cxListSize(ctx->states);
+    int *ctx_states = cxListAt(ctx->states, 0);;
+    
+    cx_array_add_array(states->states, ctx_states, nstates);
+    
+    CxIterator i = cxListIterator(ctx->documents);
+    cx_foreach(void *, doc, i) {
+        UiContext *doc_ctx = ui_document_context(doc);
+        add_ctx_states(doc_ctx, states);
+    }
 }
 
 int* ui_active_states(UiContext *ctx, int *nstates) {
-    *nstates = cxListSize(ctx->states);
-    return cxListAt(ctx->states, 0);
+    StatesList states;
+    cx_array_init(states.states, 32);
+    add_ctx_states(ctx, &states);
+    *nstates = (int)states.states.size;
+    return states.states.data;
 }
 
 void uic_check_state_widgets(UiContext *ctx) {
+    if(!ctx) {
+        return;
+    }
+    
     int ngroups = 0;
     int *groups = ui_active_states(ctx, &ngroups);
     
@@ -702,6 +737,8 @@
         free(check);
         gw->enable(gw->widget, enable);
     }
+    
+    free(groups);
 }
 
 void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) {
--- a/ui/gtk/text.c	Sun Jun 14 12:10:34 2026 +0200
+++ b/ui/gtk/text.c	Mon Jun 15 21:13:05 2026 +0200
@@ -54,9 +54,9 @@
         int sel = gtk_text_buffer_get_selection_bounds (buf, &begin, &end);
         if(sel != textview->last_selection_state) {
             if(sel) {
-                ui_set_state(textview->ctx, UI_GROUP_SELECTION);
+                ui_set_state(textview->ctx, UI_STATE_SELECTION);
             } else {
-                ui_unset_state(textview->ctx, UI_GROUP_SELECTION);
+                ui_unset_state(textview->ctx, UI_STATE_SELECTION);
             }
         }
         textview->last_selection_state = sel;
--- a/ui/ui/toolkit.h	Sun Jun 14 12:10:34 2026 +0200
+++ b/ui/ui/toolkit.h	Mon Jun 15 21:13:05 2026 +0200
@@ -180,9 +180,9 @@
 extern "C" {
 #endif
 
-#define UI_GROUP_SELECTION  20000
+#define UI_STATE_SELECTION  20000
 
-#define UI_GROUPS(...) (const int[]){ __VA_ARGS__, -1 }
+#define UI_STATES(...) (const int[]){ __VA_ARGS__, -1 }
     
 /* public types */
 #ifndef __cplusplus
@@ -542,6 +542,7 @@
 UIEXPORT void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata);
 
 UIEXPORT UiContext* ui_context_parent(UiContext *ctx);
+UIEXPORT UiContext* ui_context_toplevel_parent(UiContext *ctx);
 
 UIEXPORT void ui_object_ref(UiObject *obj);
 UIEXPORT int ui_object_unref(UiObject *obj);

mercurial