implement frame container (Motif)

Fri, 31 Oct 2025 10:12:27 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 31 Oct 2025 10:12:27 +0100
changeset 886
6f5e02fcb7b9
parent 885
28ecfe5399ae
child 887
2a2aee73c789

implement frame container (Motif)

application/demo_bindings.c file | annotate | diff | comparison | revisions
ui/common/object.c file | annotate | diff | comparison | revisions
ui/common/object.h file | annotate | diff | comparison | revisions
ui/motif/container.c file | annotate | diff | comparison | revisions
ui/motif/container.h file | annotate | diff | comparison | revisions
--- a/application/demo_bindings.c	Thu Oct 30 21:29:18 2025 +0100
+++ b/application/demo_bindings.c	Fri Oct 31 10:12:27 2025 +0100
@@ -104,7 +104,7 @@
         ui_newline(obj);
         
         ui_frame(obj, .label = "Document", .colspan = 2, .fill = TRUE) {
-            ui_grid(obj, .margin = 10, .columnspacing = 10, .rowspacing = 10) {
+            ui_grid(obj, .margin = 10, .columnspacing = 10, .rowspacing = 10, .fill = TRUE) {
                 ui_rlabel(obj, .label = "Name:", .vfill = TRUE);
                 ui_textfield(obj, .varname = "input_name", .onchange = update_name);
             }
--- a/ui/common/object.c	Thu Oct 30 21:29:18 2025 +0100
+++ b/ui/common/object.c	Fri Oct 31 10:12:27 2025 +0100
@@ -144,4 +144,29 @@
     } else {
         toplevel->container_begin = NULL;
     }
+    
+    // TODO: free container?
 }
+
+/*
+ * This might look like a weird function, but in case a container creates a
+ * sub-container, 2 container objects are added to the list, however we want
+ * only one container, otherwise ui_container_finish() would not work
+ */
+void uic_object_remove_second_last_container(UiObject *toplevel) {
+    if(toplevel->container_end && toplevel->container_end->prev) {
+        UiContainerX *end = toplevel->container_end;
+        UiContainerX *rm = toplevel->container_end->prev;
+        
+        end->prev = rm->prev;
+        if(rm->prev) {
+            rm->prev->next = end;
+        } else {
+            toplevel->container_begin = end;
+        }
+        
+        // TODO: free container?
+    } else {
+        fprintf(stderr, "Error: uic_object_remove_second_last_container expected at least 2 containers\n");
+    }
+}
--- a/ui/common/object.h	Thu Oct 30 21:29:18 2025 +0100
+++ b/ui/common/object.h	Fri Oct 31 10:12:27 2025 +0100
@@ -51,6 +51,7 @@
 
 void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer);
 void uic_object_pop_container(UiObject *toplevel);
+void uic_object_remove_second_last_container(UiObject *toplevel);
 
 
 
--- a/ui/motif/container.c	Thu Oct 30 21:29:18 2025 +0100
+++ b/ui/motif/container.c	Fri Oct 31 10:12:27 2025 +0100
@@ -227,6 +227,82 @@
     grid->container.container.newline = FALSE;
 }
 
+/* -------------------------- Frame Container -------------------------- */
+
+UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) {
+    Arg xargs[16];
+    int n = 0;
+    
+    UiContainerPrivate *ctn = ui_obj_container(obj);
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    
+    Widget parent = ui_container_prepare(ctn, &layout, xargs, &n);
+    
+    char *name = args->name ? (char*)args->name : "frame";
+    Widget frame = XmCreateFrame(parent, name, xargs, 6);
+    XtManageChild(frame);
+    ui_container_add(ctn, frame);
+    
+    if(args->label) {
+        XmString s = XmStringCreateLocalized((char*)args->label);
+        n = 0;
+        XtSetArg(xargs[n], XmNlabelString, s); n++;
+        XtSetArg(xargs[n], XmNchildType, XmFRAME_TITLE_CHILD); n++;
+        Widget label = XmCreateLabel(frame, "frame_label", xargs, n);
+        XtManageChild(label);
+        XmStringFree(s);
+    }
+    
+    UiContainerX *container = ui_frame_container(obj, frame);
+    uic_object_push_container(obj, container);
+    
+    UiContainerArgs sub_args = {
+        .spacing = args->spacing,
+        .columnspacing = args->columnspacing,
+        .rowspacing = args->rowspacing
+    };
+    switch(args->subcontainer) {
+        default: break;
+        case UI_CONTAINER_VBOX: {
+            ui_vbox_create(obj, &sub_args);
+            uic_object_remove_second_last_container(obj);
+            break;
+        }
+        case UI_CONTAINER_HBOX: {
+            ui_hbox_create(obj, &sub_args);
+            uic_object_remove_second_last_container(obj);
+            break;
+        }
+        case UI_CONTAINER_GRID: {
+            ui_grid_create(obj, &sub_args);
+            uic_object_remove_second_last_container(obj);
+            break;
+        }
+    }
+    
+    
+    return frame;
+}
+
+UiContainerX* ui_frame_container(UiObject *obj, Widget frame) {
+    UiContainerPrivate *ctn = ui_malloc(obj->ctx, sizeof(UiContainerPrivate));
+    memset(ctn, 0, sizeof(UiContainerPrivate));
+    ctn->prepare = ui_frame_container_prepare;
+    ctn->add = ui_frame_container_add;
+    ctn->widget = frame;
+    return (UiContainerX*)ctn;
+}
+
+Widget ui_frame_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n) {
+    int a = *n;
+    XtSetArg(args[a], XmNchildType, XmFRAME_WORKAREA_CHILD);
+    *n = a+1;
+    return ctn->widget;
+}
+
+void ui_frame_container_add(UiContainerPrivate *ctn, Widget widget) {
+    // NOOP
+}
 
 /* -------------------------- TabView Container -------------------------- */
 
--- a/ui/motif/container.h	Thu Oct 30 21:29:18 2025 +0100
+++ b/ui/motif/container.h	Fri Oct 31 10:12:27 2025 +0100
@@ -156,6 +156,10 @@
 Widget ui_grid_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n);
 void ui_grid_container_add(UiContainerPrivate *ctn, Widget widget);
 
+UiContainerX* ui_frame_container(UiObject *obj, Widget frame);
+Widget ui_frame_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n);
+void ui_frame_container_add(UiContainerPrivate *ctn, Widget widget);
+
 #ifdef	__cplusplus
 }
 #endif

mercurial