refactor gtk container hierarchy

Sun, 05 Oct 2025 18:13:15 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 05 Oct 2025 18:13:15 +0200
changeset 801
e096c441e874
parent 800
814d374fb689
child 802
cc73993a3ff9

refactor gtk container hierarchy

ui/common/object.c file | annotate | diff | comparison | revisions
ui/common/object.h file | annotate | diff | comparison | revisions
ui/gtk/button.c file | annotate | diff | comparison | revisions
ui/gtk/container.c file | annotate | diff | comparison | revisions
ui/gtk/container.h file | annotate | diff | comparison | revisions
ui/gtk/display.c file | annotate | diff | comparison | revisions
ui/gtk/entry.c file | annotate | diff | comparison | revisions
ui/gtk/graphics.c file | annotate | diff | comparison | revisions
ui/gtk/image.c file | annotate | diff | comparison | revisions
ui/gtk/list.c file | annotate | diff | comparison | revisions
ui/gtk/menu.c file | annotate | diff | comparison | revisions
ui/gtk/range.c file | annotate | diff | comparison | revisions
ui/gtk/text.c file | annotate | diff | comparison | revisions
ui/gtk/webview.c file | annotate | diff | comparison | revisions
ui/gtk/widget.c file | annotate | diff | comparison | revisions
ui/gtk/window.c file | annotate | diff | comparison | revisions
ui/ui/container.h file | annotate | diff | comparison | revisions
ui/ui/toolkit.h file | annotate | diff | comparison | revisions
--- a/ui/common/object.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/common/object.c	Sun Oct 05 18:13:15 2025 +0200
@@ -100,6 +100,13 @@
     ui_free(obj->ctx, rm);
 }
 
+void ui_newline(UiObject *obj) {
+    UiContainerX *container = obj->container_end;
+    if(container) {
+        container->newline = TRUE;
+    }
+}
+
 void ui_object_ref(UiObject *obj) {
     obj->ref++;
 }
@@ -141,10 +148,6 @@
     return obj;
 }
 
-UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget) {
-    return uic_ctx_object_new(toplevel->ctx, widget);
-}
-
 UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget) {
     UiObject *newobj = cxCalloc(ctx->allocator, 1, sizeof(UiObject));
     newobj->ctx = ctx;
@@ -153,26 +156,6 @@
     return newobj;
 }
 
-void uic_obj_add(UiObject *toplevel, UiObject *ctobj) {
-    UiObject *current = uic_current_obj(toplevel);
-    current->next = ctobj;
-}
-
-UiObject* uic_current_obj(UiObject *toplevel) {
-    if(!toplevel) {
-        return NULL;
-    }
-    UiObject *obj = toplevel;
-    while(obj->next) {
-        obj = obj->next;
-    }
-    return obj;
-}
-
-UiContainer* uic_get_current_container(UiObject *obj) {
-    return uic_current_obj(obj)->container;
-}
-
 void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer) {
     newcontainer->prev = toplevel->container_end;
     if(toplevel->container_end) {
--- a/ui/common/object.h	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/common/object.h	Sun Oct 05 18:13:15 2025 +0200
@@ -48,10 +48,6 @@
 UiObject* uic_object_new_toplevel(void);
 UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget);
 UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget);
-void uic_obj_add(UiObject *toplevel, UiObject *ctobj);
-UiObject* uic_current_obj(UiObject *toplevel);
-
-UiContainer* uic_get_current_container(UiObject *obj); // deprecated
 
 void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer);
 void uic_object_pop_container(UiObject *toplevel);
--- a/ui/gtk/button.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/button.c	Sun Oct 05 18:13:15 2025 +0200
@@ -100,12 +100,12 @@
 }
 
 UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args) {
-    UiObject* current = uic_current_obj(obj);
     GtkWidget *button = ui_create_button(obj, args->label, args->icon, args->onclick, args->onclickdata, 0, FALSE);
     ui_set_name_and_style(button, args->name, args->style_class);
     ui_set_widget_groups(obj->ctx, button, args->groups);
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, button);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, button, &layout);
     return button;
 }
 
@@ -220,8 +220,7 @@
         void (*enable_state_func)(void*, void*),
         int enable_state)
 {
-    UiObject* current = uic_current_obj(obj);
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, value, varname, UI_VAR_INTEGER);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, value, varname, UI_VAR_INTEGER);
     if (var) {
         UiInteger* value = (UiInteger*)var->value;
         value->obj = widget;
@@ -291,8 +290,6 @@
 }
 
 static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     ui_setup_togglebutton(
             obj,
             widget,
@@ -306,8 +303,9 @@
     ui_set_name_and_style(widget, args->name, args->style_class);
     ui_set_widget_groups(obj->ctx, widget, args->groups);
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, widget);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, widget, &layout);
     
     return widget;
 }
@@ -350,9 +348,7 @@
     }
 }
 
-UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
+UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) { 
     GtkWidget *widget = gtk_check_button_new_with_label(args->label); 
     ui_bind_togglebutton(
             obj,
@@ -370,8 +366,9 @@
     ui_set_name_and_style(widget, args->name, args->style_class);
     ui_set_widget_groups(obj->ctx, widget, args->groups);
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, widget);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, widget, &layout);
     
     return widget;
 }
@@ -411,12 +408,11 @@
 }
 
 UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) {
-    UiObject* current = uic_current_obj(obj);
     GtkWidget *widget = gtk_switch_new();
     ui_set_name_and_style(widget, args->name, args->style_class);
     ui_set_widget_groups(obj->ctx, widget, args->groups);
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
     if(var) {
         UiInteger *value = var->value;
         value->obj = widget;
@@ -449,8 +445,9 @@
             G_CALLBACK(ui_destroy_vardata),
             event);
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, widget);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, widget, &layout);
     
     return widget;
 }
@@ -519,12 +516,10 @@
 }
 
 UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     GSList *rg = NULL;
     UiInteger *rgroup;
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
     
     UiBool first = FALSE;
     if(var) {
@@ -600,8 +595,9 @@
                 event);
     }
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, rbutton);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, rbutton, &layout);
     
     return rbutton;
 }
@@ -860,8 +856,7 @@
     
     data->widget = button;
     
-    UiObject* current = uic_current_obj(obj);
-    UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
+    UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
     if(var) {
         UiString *str = var->value;
         char *current_value = ui_get(str);
@@ -876,8 +871,9 @@
     
     ui_set_name_and_style(button, args->name, args->style_class);
     ui_set_widget_groups(obj->ctx, button, args->groups);
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, button);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, button, &layout);
     
     return button;
 }
--- a/ui/gtk/container.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/container.c	Sun Oct 05 18:13:15 2025 +0200
@@ -42,14 +42,14 @@
 
 
 void ui_container_begin_close(UiObject *obj) {
-    UiContainer *ct = uic_get_current_container(obj);
+    UiContainerX *ct = obj->container_end;
     ct->close = 1;
 }
 
 int ui_container_finish(UiObject *obj) {
-    UiContainer *ct = uic_get_current_container(obj);
+    UiContainerX *ct = obj->container_end;
     if(ct->close) {
-        ui_end(obj);
+        ui_end_new(obj);
         return 0;
     }
     return 1;
@@ -71,9 +71,10 @@
 #endif
 }
 
+// TODO: refactoring
 GtkWidget* ui_subcontainer_create(
         UiSubContainerType type,
-        UiObject *newobj,
+        UiObject *obj,
         int spacing,
         int columnspacing,
         int rowspacing,
@@ -81,38 +82,39 @@
 {
     GtkWidget *sub = NULL;
     GtkWidget *add = NULL;
+    UiContainerX *container = NULL;
     switch(type) {
         default: {
             sub = ui_gtk_vbox_new(spacing);
             add = ui_box_set_margin(sub, margin);
-            newobj->container = ui_box_container(newobj, sub, type);
-            newobj->widget = sub;
+            container = ui_box_container(obj, sub, type);
             break;
         }
         case UI_CONTAINER_HBOX: {
             sub = ui_gtk_hbox_new(spacing);
             add = ui_box_set_margin(sub, margin);
-            newobj->container = ui_box_container(newobj, sub, type);
-            newobj->widget = sub;
+            container = ui_box_container(obj, sub, type);
             break;
         }
         case UI_CONTAINER_GRID: {
             sub = ui_create_grid_widget(columnspacing, rowspacing);
             add = ui_box_set_margin(sub, margin);
-            newobj->container = ui_grid_container(newobj, sub, FALSE, FALSE, FALSE, FALSE);
-            newobj->widget = sub;
+            container = ui_grid_container(obj, sub, FALSE, FALSE, FALSE, FALSE);
             break;
         }
         case UI_CONTAINER_NO_SUB: {
             break;
         }
     }
+    if(container) {
+        uic_object_push_container(obj, container);
+    }
     return add;
 }
 
 
 /* -------------------- Box Container -------------------- */
-UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) {
+UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) {
     UiBoxContainer *ct = cxCalloc(
             obj->ctx->allocator,
             1,
@@ -120,12 +122,12 @@
     ct->container.widget = box;
     ct->container.add = ui_box_container_add;
     ct->type = type;
-    return (UiContainer*)ct;
+    return (UiContainerX*)ct;
 }
 
-void ui_box_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_box_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
     UiBoxContainer *bc = (UiBoxContainer*)ct;
-    UiBool fill = ct->layout.fill;
+    UiBool fill = layout->fill;
     if(bc->has_fill && fill) {
         fprintf(stderr, "UiError: container has 2 filled widgets");
         fill = FALSE;
@@ -152,11 +154,10 @@
     gtk_box_pack_start(GTK_BOX(ct->widget), widget, expand, fill, 0);
 #endif
     
-    ui_reset_layout(ct->layout);
     ct->current = widget;
 }
 
-UiContainer* ui_grid_container(
+UiContainerX* ui_grid_container(
         UiObject *obj,
         GtkWidget *grid,
         UiBool def_hexpand,
@@ -176,142 +177,105 @@
     ct->container.add = ui_grid_container_add;
     UI_GTK_V2(ct->width = 0);
     UI_GTK_V2(ct->height = 1);
-    return (UiContainer*)ct;
+    return (UiContainerX*)ct;
+}
+
+/*
+ * TODO: move to common
+ * prepares the layout horizontal and vertical fill/expand settings
+ * based on fill and defaults
+ */
+static void layout_setup_expand_fill(
+        UiLayout *layout,
+        UiBool def_hexpand,
+        UiBool def_vexpand,
+        UiBool def_hfill,
+        UiBool def_vfill)
+{
+    if(layout->fill) {
+        layout->hfill = TRUE;
+        layout->vfill = TRUE;
+        layout->hexpand = TRUE;
+        layout->vexpand = TRUE;
+        return;
+    }
+    
+    if(!layout->override_defaults) {
+        if(def_hexpand) {
+            layout->hexpand = TRUE;
+        }
+        if(def_hfill) {
+            layout->hfill = TRUE;
+        }
+        if(def_vexpand) {
+            layout->vexpand = TRUE;
+        }
+        if(def_vfill) {
+            layout->vfill = TRUE;
+        }
+    }
 }
 
 #if GTK_MAJOR_VERSION >= 3
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_grid_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
     UiGridContainer *grid = (UiGridContainer*)ct;
     
-    if(ct->layout.newline) {
+    if(ct->container.newline) {
         grid->x = 0;
         grid->y++;
-        ct->layout.newline = FALSE;
+        ct->container.newline = FALSE;
     }
     
-    int hexpand = FALSE;
-    int vexpand = FALSE;
-    int hfill = FALSE;
-    int vfill = FALSE;
-    if(!ct->layout.override_defaults) {
-        if(grid->def_hexpand) {
-            hexpand = TRUE;
-        }
-        if(grid->def_hfill) {
-            hfill = TRUE;
-        }
-        if(grid->def_vexpand) {
-            vexpand = TRUE;
-        }
-        if(grid->def_vfill) {
-            vfill = TRUE;
-        }
-    }
+    layout_setup_expand_fill(layout, grid->def_hexpand, grid->def_vexpand, grid->def_hfill, grid->def_vfill);
     
-    UiBool fill = ct->layout.fill;
-    if(ct->layout.hexpand) {
-        hexpand = TRUE;
-    }
-    if(ct->layout.hfill) {
-        hfill = TRUE;
-    }
-    if(ct->layout.vexpand) {
-        vexpand = TRUE;
-    }
-    if(ct->layout.vfill) {
-        vfill = TRUE;
-    }
-    if(fill) {
-        hfill = TRUE;
-        vfill = TRUE;
-        hexpand = TRUE;
-        vexpand = TRUE;
-    }
-    
-    if(!hfill) {
+    if(!layout->hfill) {
         gtk_widget_set_halign(widget, GTK_ALIGN_START);
     }
-    if(!vfill) {
+    if(!layout->vfill) {
         gtk_widget_set_valign(widget, GTK_ALIGN_START);
     }
     
-    gtk_widget_set_hexpand(widget, hexpand);
-    gtk_widget_set_vexpand(widget, vexpand);
+    gtk_widget_set_hexpand(widget, layout->hexpand);
+    gtk_widget_set_vexpand(widget, layout->vexpand);
     
-    int colspan = ct->layout.colspan > 0 ? ct->layout.colspan : 1;
-    int rowspan = ct->layout.rowspan > 0 ? ct->layout.rowspan : 1;
+    int colspan = layout->colspan > 0 ? layout->colspan : 1;
+    int rowspan = layout->rowspan > 0 ? layout->rowspan : 1;
     
     gtk_grid_attach(GTK_GRID(ct->widget), widget, grid->x, grid->y, colspan, rowspan);
     grid->x += colspan;
     
-    ui_reset_layout(ct->layout);
-    ct->current = widget;
+    grid->container.current = widget;
 }
 #endif
 #ifdef UI_GTK2
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_grid_container_add(UiContainerPrivate *ct, GtkWidget *widget) {
     UiGridContainer *grid = (UiGridContainer*)ct;
     
-    if(ct->layout.newline) {
+    if(ct->container.newline) {
         grid->x = 0;
         grid->y++;
-        ct->layout.newline = FALSE;
+        ct->container.newline = FALSE;
     }
     
-    int hexpand = FALSE;
-    int vexpand = FALSE;
-    int hfill = FALSE;
-    int vfill = FALSE;
-    if(!ct->layout.override_defaults) {
-        if(grid->def_hexpand) {
-            hexpand = TRUE;
-            hfill = TRUE;
-        } else if(grid->def_hfill) {
-            hfill = TRUE;
-        }
-        if(grid->def_vexpand) {
-            vexpand = TRUE;
-            vfill = TRUE;
-        } else if(grid->def_vfill) {
-            vfill = TRUE;
-        }
-    }
-    
-    UiBool fill = ct->layout.fill;
-    if(ct->layout.hexpand) {
-        hexpand = TRUE;
-        hfill = TRUE;
-    } else if(ct->layout.hfill) {
-        hfill = TRUE;
-    }
-    if(ct->layout.vexpand) {
-        vexpand = TRUE;
-        vfill = TRUE;
-    } else if(ct->layout.vfill) {
-        vfill = TRUE;
-    }
-    if(fill) {
-        hfill = TRUE;
-        vfill = TRUE;
-    }
+    layout_setup_expand_fill(layout, grid->def_hexpand, grid->def_vexpand, grid->def_hfill, grid->def_vfill);
     
     GtkAttachOptions xoptions = 0;
     GtkAttachOptions yoptions = 0;
-    if(hexpand) {
+    if(layout->hexpand) {
         xoptions = GTK_EXPAND;
     }
-    if(hfill) {
+    if(layout->hfill) {
         xoptions |= GTK_FILL;
     }
-    if(vexpand) {
+    if(layout->vexpand) {
         yoptions = GTK_EXPAND;
     }
-    if(vfill) {
+    if(layout->vfill) {
         yoptions |= GTK_FILL;
     }
     
-    int colspan = ct->layout.colspan > 0 ? ct->layout.colspan : 1;
-    int rowspan = ct->layout.rowspan > 0 ? ct->layout.rowspan : 1;
+    int colspan = layout->colspan > 0 ? layout->colspan : 1;
+    int rowspan = layout->rowspan > 0 ? layout->rowspan : 1;
     // TODO: use colspan/rowspan
     
     gtk_table_attach(GTK_TABLE(ct->widget), widget, grid->x, grid->x+1, grid->y, grid->y+1, xoptions, yoptions, 0, 0);
@@ -323,75 +287,74 @@
         gtk_table_resize(GTK_TABLE(ct->widget), grid->width, grid->height);
     }
     
-    ui_reset_layout(ct->layout);
     ct->current = widget;
 }
 #endif
 
-UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame) {
-    UiContainer *ct = cxCalloc(
+UiContainerX* ui_frame_container(UiObject *obj, GtkWidget *frame) {
+    UiContainerPrivate *ct = cxCalloc(
             obj->ctx->allocator,
             1,
-            sizeof(UiContainer));
+            sizeof(UiContainerPrivate));
     ct->widget = frame;
     ct->add = ui_frame_container_add;
-    return ct;
-}
-
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget) {
-    FRAME_SET_CHILD(ct->widget, widget);
+    return (UiContainerX*)ct;
 }
 
-UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander) {
-    UiContainer *ct = cxCalloc(
-            obj->ctx->allocator,
-            1,
-            sizeof(UiContainer));
-    ct->widget = expander;
-    ct->add = ui_expander_container_add;
-    return ct;
-}
-
-void ui_expander_container_add(UiContainer *ct, GtkWidget *widget) {
-    EXPANDER_SET_CHILD(ct->widget, widget);
-}
-
-void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget) {
-    // TODO: check if the widget implements GtkScrollable
-    SCROLLEDWINDOW_SET_CHILD(ct->widget, widget);
-    ui_reset_layout(ct->layout);
+void ui_frame_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
+    FRAME_SET_CHILD(ct->widget, widget);
     ct->current = widget;
 }
 
-UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) {
-    UiContainer *ct = cxCalloc(
+UiContainerX* ui_expander_container(UiObject *obj, GtkWidget *expander) {
+    UiContainerPrivate *ct = cxCalloc(
             obj->ctx->allocator,
             1,
-            sizeof(UiContainer));
+            sizeof(UiContainerPrivate));
+    ct->widget = expander;
+    ct->add = ui_expander_container_add;
+    return (UiContainerX*)ct;
+}
+
+void ui_expander_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
+    EXPANDER_SET_CHILD(ct->widget, widget);
+    ct->current = widget;
+}
+
+void ui_scrolledwindow_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
+    // TODO: check if the widget implements GtkScrollable
+    SCROLLEDWINDOW_SET_CHILD(ct->widget, widget);
+    ct->current = widget;
+}
+
+UiContainerX* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) {
+    UiContainerPrivate *ct = cxCalloc(
+            obj->ctx->allocator,
+            1,
+            sizeof(UiContainerPrivate));
     ct->widget = scrolledwindow;
     ct->add = ui_scrolledwindow_container_add;
-    return ct;
+    return (UiContainerX*)ct;
 }
 
-UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview) {
+UiContainerX* ui_tabview_container(UiObject *obj, GtkWidget *tabview) {
     UiTabViewContainer *ct = cxCalloc(
             obj->ctx->allocator,
             1,
             sizeof(UiTabViewContainer));
     ct->container.widget = tabview;
     ct->container.add = ui_tabview_container_add;
-    return (UiContainer*)ct;
+    return (UiContainerX*)ct;
 }
 
-void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_tabview_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
     UiGtkTabView *data = ui_widget_get_tabview_data(ct->widget);
     if(!data) {
         fprintf(stderr, "UI Error: widget is not a tabview");
         return;
     }
-    data->add_tab(ct->widget, -1, ct->layout.label, widget);
+    data->add_tab(ct->widget, -1, layout->label, widget);
     
-    ui_reset_layout(ct->layout);
     ct->current = widget;
 }
 
@@ -419,18 +382,16 @@
 }
 
 UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType type) {
-    UiObject *current = uic_current_obj(obj);
-    UiContainer *ct = current->container;
-    UI_APPLY_LAYOUT2(current, args);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
     
     GtkWidget *box = type == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args->spacing) : ui_gtk_hbox_new(args->spacing);
     ui_set_name_and_style(box, args->name, args->style_class);
-    GtkWidget *widget = args->margin > 0 ? ui_box_set_margin(box, args->margin) : box;
-    ct->add(ct, widget);
+    GtkWidget *widget = args->margin > 0 ? ui_box_set_margin(box, args->margin) : box; // TODO: remove, margin will be handled by container add-functions
+    ct->add(ct, widget, &layout);
     
-    UiObject *newobj = uic_object_new(obj, box);
-    newobj->container = ui_box_container(obj, box, type);
-    uic_obj_add(obj, newobj);
+    UiContainerX *container = ui_box_container(obj, box, type);
+    uic_object_push_container(obj, container);
     
     return widget;
 }
@@ -457,81 +418,59 @@
 }
 
 UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    UI_APPLY_LAYOUT2(current, args);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
     GtkWidget *widget;
     
     GtkWidget *grid = ui_create_grid_widget(args->columnspacing, args->rowspacing);
     ui_set_name_and_style(grid, args->name, args->style_class);
     widget = ui_box_set_margin(grid, args->margin);
-    current->container->add(current->container, widget);
+    ct->add(ct, widget, &layout);
     
-    UiObject *newobj = uic_object_new(obj, grid);
-    newobj->container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill);
-    uic_obj_add(obj, newobj);
+    UiContainerX *container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill);
+    uic_object_push_container(obj, container);
     
     return widget;
 }
 
 UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    UI_APPLY_LAYOUT2(current, args);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
     
     GtkWidget *frame = gtk_frame_new(args->label);
-    UiObject *newobj = uic_object_new(obj, frame);
-    GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
-    if(sub) {
-        FRAME_SET_CHILD(frame, sub);
-    } else {
-        newobj->widget = frame;
-        newobj->container = ui_frame_container(obj, frame);
-    }
-    current->container->add(current->container, frame);
-    uic_obj_add(obj, newobj);
+    ct->add(ct, frame, &layout);
+    
+    UiContainerX *container = ui_frame_container(obj, frame);
+    uic_object_push_container(obj, container);
     
     return frame;
 }
 
 UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    UI_APPLY_LAYOUT2(current, args);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
     
     GtkWidget *expander = gtk_expander_new(args->label);
     gtk_expander_set_expanded(GTK_EXPANDER(expander), args->isexpanded);
-    UiObject *newobj = uic_object_new(obj, expander);
-    GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
-    if(sub) {
-        EXPANDER_SET_CHILD(expander, sub);
-    } else {
-        newobj->widget = expander;
-        newobj->container = ui_expander_container(obj, expander);
-    }
-    current->container->add(current->container, expander);
-    uic_obj_add(obj, newobj);
+    ct->add(ct, expander, &layout);
+    
+    UiContainerX *container = ui_expander_container(obj, expander);
+    uic_object_push_container(obj, container);
     
     return expander;
 }
 
 
 UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    UI_APPLY_LAYOUT2(current, args);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
     
     GtkWidget *sw = SCROLLEDWINDOW_NEW();
     ui_set_name_and_style(sw, args->name, args->style_class);
-    GtkWidget *widget = ui_box_set_margin(sw, args->margin);
-    current->container->add(current->container, widget);
+    ct->add(ct, sw, &layout);
     
-    UiObject *newobj = uic_object_new(obj, sw);
-    GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
-    if(sub) {
-        SCROLLEDWINDOW_SET_CHILD(sw, sub);
-    } else {
-        newobj->widget = sw;
-        newobj->container = ui_scrolledwindow_container(obj, sw);
-    }
-    
-    uic_obj_add(obj, newobj);
+    UiContainerX *container = ui_scrolledwindow_container(obj, sw);
+    uic_object_push_container(obj, container);
     
     return sw;
 }
@@ -741,7 +680,7 @@
 UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) {
     UiGtkTabView *data = malloc(sizeof(UiGtkTabView));
     memset(data, 0, sizeof(UiGtkTabView));
-    data->margin = args->margin;
+    data->padding = args->padding;
     data->spacing = args->spacing;
     data->columnspacing = args->columnspacing;
     data->rowspacing = args->rowspacing;
@@ -801,9 +740,8 @@
         }
     }
     
-    UiObject* current = uic_current_obj(obj);
     if(args->value || args->varname) {
-        UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
+        UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
         UiInteger *i = var->value;
         i->get = getfunc;
         i->set = setfunc;
@@ -812,29 +750,56 @@
     
     g_object_set_data(G_OBJECT(widget), "ui_tabview", data);
     data->widget = data_widget;
-    data->subcontainer = args->subcontainer;
-    
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, widget);
     
-    UiObject *newobj = uic_object_new(obj, widget);
-    newobj->container = ui_tabview_container(obj, widget);
-    uic_obj_add(obj, newobj);
-    data->obj = newobj;
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, widget, &layout);
+    
+    UiContainerX *container = ui_tabview_container(obj, widget);
+    uic_object_push_container(obj, container);
     
     return widget;
 }
 
+static GtkWidget* create_tab(UiObject *obj, UiGtkTabView *tabview, const char *title, int tab) {
+    UiContainerX *container;
+    GtkWidget *sub;
+    switch(tabview->subcontainer) {
+        default: {
+            sub = ui_gtk_vbox_new(tabview->spacing);
+            container = ui_box_container(obj, sub, tabview->subcontainer);
+            break;
+        }
+        case UI_CONTAINER_HBOX: {
+            sub = ui_gtk_hbox_new(tabview->spacing);
+            container = ui_box_container(obj, sub, tabview->subcontainer);
+            break;
+        }
+        case UI_CONTAINER_GRID: {
+            sub = ui_create_grid_widget(tabview->columnspacing, tabview->rowspacing);
+            container = ui_grid_container(obj, sub, FALSE, FALSE, FALSE, FALSE);
+            break;
+        }
+    }
+    
+    uic_object_push_container(obj, container);
+    
+    GtkWidget *widget = ui_box_set_margin(sub, tabview->padding);
+    tabview->add_tab(tabview->widget, tab, title, widget);
+    
+    return sub;
+}
+
 void ui_tab_create(UiObject* obj, const char* title) {
-    UiObject* current = uic_current_obj(obj);
-    UiGtkTabView *data = ui_widget_get_tabview_data(current->widget);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; 
+    GtkWidget *tabview = ct->widget;
+    UiGtkTabView *data = ui_widget_get_tabview_data(tabview);
     if(!data) {
         fprintf(stderr, "UI Error: widget is not a tabview\n");
         return;
     }
     
-    UiObject *newobj = ui_tabview_add(current->widget, title, -1);
-    current->next = newobj;
+    create_tab(obj, data, title, -1);
 }
 
 
@@ -864,31 +829,8 @@
         return NULL;
     }
     
-    UiObject *newobj = cxCalloc(data->obj->ctx->allocator, 1, sizeof(UiObject));
-    newobj->ctx = data->obj->ctx;
-    
-    GtkWidget *sub;
-    switch(data->subcontainer) {
-        default: {
-            sub = ui_gtk_vbox_new(data->spacing);
-            newobj->container = ui_box_container(newobj, sub, data->subcontainer);
-            break;
-        }
-        case UI_CONTAINER_HBOX: {
-            sub = ui_gtk_hbox_new(data->spacing);
-            newobj->container = ui_box_container(newobj, sub, data->subcontainer);
-            break;
-        }
-        case UI_CONTAINER_GRID: {
-            sub = ui_create_grid_widget(data->columnspacing, data->rowspacing);
-            newobj->container = ui_grid_container(newobj, sub, FALSE, FALSE, FALSE, FALSE);
-            break;
-        }
-    }
-    newobj->widget = sub;
-    GtkWidget *widget = ui_box_set_margin(sub, data->margin);
-    
-    data->add_tab(data->widget, tab_index, name, widget);
+    UiObject *newobj = uic_object_new_toplevel();
+    newobj->widget = create_tab(newobj, data, name, tab_index);
     
     return newobj;
 }
@@ -897,20 +839,16 @@
 /* -------------------- Headerbar -------------------- */
 
 static void hb_set_part(UiObject *obj, int part) {
-    UiObject* current = uic_current_obj(obj);
-    GtkWidget *headerbar = current->widget;
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    GtkWidget *headerbar = ct->widget;
     
     UiHeaderbarContainer *hb = cxCalloc(
             obj->ctx->allocator,
             1,
             sizeof(UiHeaderbarContainer));
-    memcpy(hb, current->container, sizeof(UiHeaderbarContainer));
-    
-    UiObject *newobj = uic_object_new(obj, headerbar);
-    newobj->container = (UiContainer*)hb;
-    uic_obj_add(obj, newobj);
-    
+    memcpy(hb, ct, sizeof(UiHeaderbarContainer));
     hb->part = part;
+    uic_object_push_container(obj, (UiContainerX*)hb);
 }
 
 void ui_headerbar_start_create(UiObject *obj) {
@@ -926,74 +864,70 @@
 }
 
 UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs *args) {
-    UiObject *current = uic_current_obj(obj);
-    UiContainer *ct = current->container;
-    UI_APPLY_LAYOUT2(current, args);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
     
     GtkWidget *box = ui_gtk_hbox_new(args->alt_spacing);
     ui_set_name_and_style(box, args->name, args->style_class);
-    ct->add(ct, box);
+    ct->add(ct, box, &layout);
     
-    UiObject *newobj = uic_object_new(obj, box);
-    newobj->container = ui_headerbar_fallback_container(obj, box);
-    uic_obj_add(obj, newobj);
+    UiContainerX *container = ui_headerbar_fallback_container(obj, box);
+    uic_object_push_container(obj, container);
     
     return box;
 }
 
 static void hb_fallback_set_part(UiObject *obj, int part) {
-    UiObject* current = uic_current_obj(obj);
-    GtkWidget *headerbar = current->widget;
+     UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    GtkWidget *headerbar = ct->widget;
     
-    UiObject *newobj = uic_object_new(obj, headerbar);
-    newobj->container = ui_headerbar_container(obj, headerbar);
-    uic_obj_add(obj, newobj);
+    UiContainerX *container = ui_headerbar_container(obj, headerbar);
+    uic_object_push_container(obj, container);
     
-    UiHeaderbarContainer *hb = (UiHeaderbarContainer*)newobj->container;
+    UiHeaderbarContainer *hb = (UiHeaderbarContainer*)container;
     hb->part = part;
 }
 
-UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar) {
+UiContainerX* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar) {
     UiHeaderbarContainer *ct = cxCalloc(
             obj->ctx->allocator,
             1,
             sizeof(UiHeaderbarContainer));
     ct->container.widget = headerbar;
     ct->container.add = ui_headerbar_fallback_container_add;
-    return (UiContainer*)ct;
+    return (UiContainerX*)ct;
 }
 
-void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_headerbar_fallback_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
     UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
     BOX_ADD(ct->widget, widget);
 }
 
 #if GTK_CHECK_VERSION(3, 10, 0)
 
-UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) {
+UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) {  
     GtkWidget *headerbar = g_object_get_data(G_OBJECT(obj->widget), "ui_headerbar");
     if(!headerbar) {
         return ui_headerbar_fallback_create(obj, args);
     }
     
-    UiObject *newobj = uic_object_new(obj, headerbar);
-    newobj->container = ui_headerbar_container(obj, headerbar);
-    uic_obj_add(obj, newobj);
+    UiContainerX *container = ui_headerbar_container(obj, headerbar);
+    uic_object_push_container(obj, container);
     
     return headerbar;    
 }
 
-UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) {
+UiContainerX* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) {
     UiHeaderbarContainer *ct = cxCalloc(
             obj->ctx->allocator,
             1,
             sizeof(UiHeaderbarContainer));
     ct->container.widget = headerbar;
     ct->container.add = ui_headerbar_container_add;
-    return (UiContainer*)ct;
+    return (UiContainerX*)ct;
 }
 
-void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_headerbar_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
     UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
     if(hb->part == 0) {
         UI_HEADERBAR_PACK_START(ct->widget, widget);
@@ -1031,9 +965,8 @@
     ui_box_set_margin(box, args->margin);
     adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), box);
     
-    UiObject *newobj = uic_object_new(obj, box);
-    newobj->container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
-    uic_obj_add(obj, newobj);
+    UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
+    uic_object_push_container(obj, container);
     
     return box;
 }
@@ -1045,9 +978,8 @@
     ui_box_set_margin(box, args->margin);
     BOX_ADD_EXPAND(sidebar_vbox, box);
     
-    UiObject *newobj = uic_object_new(obj, box);
-    newobj->container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
-    uic_obj_add(obj, newobj);
+    UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
+    uic_object_push_container(obj, container);
     
     return box;
 }
@@ -1066,9 +998,8 @@
     ui_box_set_margin(box, args->margin);
     BOX_ADD_EXPAND(pbox, box);
     
-    UiObject *newobj = uic_object_new(obj, box);
-    newobj->container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
-    uic_obj_add(obj, newobj);
+    UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
+    uic_object_push_container(obj, container);
     
     return box;
 }
@@ -1108,12 +1039,11 @@
 }
 
 static UIWIDGET splitpane_create(UiObject *obj, UiOrientation orientation, UiSplitPaneArgs *args) {
-    UiObject* current = uic_current_obj(obj);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
     
     GtkWidget *pane0 = create_paned(orientation);
-    
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, pane0);
+    ct->add(ct, pane0, &layout);
     
     int max = args->max_panes == 0 ? 2 : args->max_panes;
     
@@ -1134,15 +1064,14 @@
                 strdup(args->position_property));
     }
     
-    UiObject *newobj = uic_object_new(obj, pane0);
-    newobj->container = ui_splitpane_container(obj, pane0, orientation, max, args->initial_position);
-    uic_obj_add(obj, newobj);
+    UiContainerX *container = ui_splitpane_container(obj, pane0, orientation, max, args->initial_position);
+    uic_object_push_container(obj, container);
     
-    g_object_set_data(G_OBJECT(pane0), "ui_splitpane", newobj->container);
+    g_object_set_data(G_OBJECT(pane0), "ui_splitpane", container);
     
-    UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
+    UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
     if(var) {
-        UiSplitPaneContainer *s = (UiSplitPaneContainer*)newobj->container;
+        UiSplitPaneContainer *s = (UiSplitPaneContainer*)container;
         UiInteger *i = var->value;
         s->initial_position = i->value;
         
@@ -1162,7 +1091,7 @@
     return splitpane_create(obj, UI_VERTICAL, args);
 }
 
-UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max, int init) {
+UiContainerX* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max, int init) {
     UiSplitPaneContainer *ct = ui_calloc(obj->ctx, 1, sizeof(UiSplitPaneContainer));
     ct->container.widget = pane;
     ct->container.add = ui_splitpane_container_add;
@@ -1171,10 +1100,10 @@
     ct->max = max;
     ct->initial_position = init;
     ct->children = cxArrayListCreateSimple(CX_STORE_POINTERS, 4);
-    return (UiContainer*)ct;
+    return (UiContainerX*)ct;
 }
 
-void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_splitpane_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
     UiSplitPaneContainer *s = (UiSplitPaneContainer*)ct;
     
     if(s->nchildren >= s->max) {
@@ -1279,13 +1208,12 @@
         UiObject *item_obj = cxMapGet(ct->current_items, key);
         if(item_obj) {
             // re-add previously created widget
-            ui_box_container_add(ct->container, item_obj->widget);
+            UiLayout layout = {0};
+            ui_box_container_add(ct->container, item_obj->widget, &layout);
         } else {
             // create new widget and object for this list element
-            CxMempool *mp = cxMempoolCreateSimple(256);
-            const CxAllocator *a = mp->allocator;
-            UiObject *obj = cxCalloc(a, 1, sizeof(UiObject));
-            obj->ctx = uic_context(obj, mp);
+            UiObject *obj = uic_object_new_toplevel();
+            obj->ctx->parent = ct->parent->ctx;
             obj->window = NULL;
             obj->widget = ui_subcontainer_create(
                     ct->subcontainer,
@@ -1294,7 +1222,8 @@
                     ct->columnspacing,
                     ct->rowspacing,
                     ct->margin);
-            ui_box_container_add(ct->container, obj->widget);
+            UiLayout layout = {0};
+            ui_box_container_add(ct->container, obj->widget, &layout);
             if(ct->create_ui) {
                 ct->create_ui(obj, index, elm, ct->userdata);
             }
@@ -1316,19 +1245,18 @@
 }
 
 UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs *args) {
-    UiObject *current = uic_current_obj(obj);
-    UiContainer *ct = current->container;
-    UI_APPLY_LAYOUT2(current, args);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
     
     GtkWidget *box = args->container == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args->spacing) : ui_gtk_hbox_new(args->spacing);
     ui_set_name_and_style(box, args->name, args->style_class);
     GtkWidget *widget = args->margin > 0 ? ui_box_set_margin(box, args->margin) : box;
-    ct->add(ct, widget);
+    ct->add(ct, widget, &layout);
     
     UiGtkItemListContainer *container = malloc(sizeof(UiGtkItemListContainer));
     container->parent = obj;
     container->widget = box;
-    container->container = ui_box_container(current, box, args->container);
+    container->container = (UiContainerPrivate*)ui_box_container(obj, box, args->container);
     container->create_ui = args->create_ui;
     container->userdata = args->userdata;
     container->subcontainer = args->subcontainer;
@@ -1341,7 +1269,7 @@
     container->rowspacing = args->sub_rowspacing;
     container->remove_items = TRUE;
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_LIST);
     if(var) {
         UiList *list = var->value;
         list->obj = container;
@@ -1358,56 +1286,3 @@
 }
 
 
-
-/*
- * -------------------- Layout Functions --------------------
- * 
- * functions for setting layout attributes for the current container
- *
- */
-
-void ui_layout_fill(UiObject *obj, UiBool fill) {
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->layout.fill = fill;
-}
-
-void ui_layout_hexpand(UiObject *obj, UiBool expand) {
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->layout.hexpand = expand;
-}
-
-void ui_layout_vexpand(UiObject *obj, UiBool expand) {
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->layout.vexpand = expand;
-}
-
-void ui_layout_hfill(UiObject *obj, UiBool fill) {
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->layout.hfill = fill;
-}
-
-void ui_layout_vfill(UiObject *obj, UiBool fill) {
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->layout.vfill = fill;
-}
-
-UIEXPORT void ui_layout_override_defaults(UiObject *obj, UiBool d) {
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->layout.override_defaults = d;
-}
-
-void ui_layout_colspan(UiObject* obj, int cols) {
-    UiContainer* ct = uic_get_current_container(obj);
-    ct->layout.colspan = cols;
-}
-
-void ui_layout_rowspan(UiObject* obj, int rows) {
-    UiContainer* ct = uic_get_current_container(obj);
-    ct->layout.rowspan = rows;
-}
-
-void ui_newline(UiObject *obj) {
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->layout.newline = TRUE;
-}
-
--- a/ui/gtk/container.h	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/container.h	Sun Oct 05 18:13:15 2025 +0200
@@ -45,45 +45,30 @@
   
 #define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout))
     
-typedef void (*ui_container_add_f)(UiContainer*, GtkWidget*);
 
 typedef struct UiDocumentView UiDocumentView;
 
-
-typedef struct UiLayout UiLayout;
-struct UiLayout {
-    UiBool       fill;
-    UiBool       newline;
-    char         *label;
-    UiBool       hexpand;
-    UiBool       vexpand;
-    UiBool       hfill;
-    UiBool       vfill;
-    UiBool       override_defaults;
-    int          width;
-    int          colspan;
-    int          rowspan;
-};
-
-struct UiContainer {
+typedef struct UiContainerPrivate UiContainerPrivate;
+struct UiContainerPrivate {
+    UiContainerX container;
     GtkWidget *widget;
     UIMENU menu;
-    GtkWidget *current;
+    GtkWidget *current; // TODO: remove
     
-    void (*add)(UiContainer*, GtkWidget*);
+    void (*add)(UiContainerPrivate*, GtkWidget*, UiLayout *layout);
     UiLayout layout;
     
     int close;
 };
 
 typedef struct UiBoxContainer {
-    UiContainer container;
+    UiContainerPrivate container;
     UiSubContainerType type;
     UiBool has_fill;
 } UiBoxContainer;
 
 typedef struct UiGridContainer {
-    UiContainer container;
+    UiContainerPrivate container;
     UiBool def_hexpand;
     UiBool def_vexpand;
     UiBool def_hfill;
@@ -97,7 +82,7 @@
 } UiGridContainer;
 
 typedef struct UiTabViewContainer {
-    UiContainer container;
+    UiContainerPrivate container;
 } UiTabViewContainer;
 
 typedef void (*ui_select_tab_func)(UIWIDGET widget, int tab);
@@ -110,7 +95,7 @@
     ui_select_tab_func remove_tab;
     ui_add_tab_func add_tab;
     UiSubContainerType subcontainer;
-    int margin;
+    int padding;
     int spacing;
     int columnspacing;
     int rowspacing;
@@ -120,7 +105,7 @@
 
 
 typedef struct UiSplitPaneContainer {
-    UiContainer container;
+    UiContainerPrivate container;
     GtkWidget *current_pane;
     CxList *children;
     UiOrientation orientation;
@@ -131,7 +116,7 @@
 } UiSplitPaneContainer;
 
 typedef struct UiHeaderbarContainer {
-    UiContainer container;
+    UiContainerPrivate container;
     GtkWidget *centerbox;
     int part;
     UiHeaderbarAlternative alternative; /* only used by fallback headerbar */
@@ -140,7 +125,7 @@
 typedef struct UiGtkItemListContainer {
     UiObject *parent;
     GtkWidget *widget;
-    UiContainer *container;
+    UiContainerPrivate *container;
     void (*create_ui)(UiObject *, int, void *, void *);
     void *userdata;
     UiSubContainerType subcontainer;
@@ -163,39 +148,36 @@
         int rowspacing,
         int margin);
 
-UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame);
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget);
-
 GtkWidget* ui_box_set_margin(GtkWidget *box, int margin);
 UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType type);
 
-UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type);
-void ui_box_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type);
+void ui_box_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
 GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing);
-UiContainer* ui_grid_container(
+UiContainerX* ui_grid_container(
         UiObject *obj,
         GtkWidget *grid,
         UiBool def_hexpand,
         UiBool def_vexpand,
         UiBool def_hfill,
         UiBool def_vfill);
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget);
+void ui_grid_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
-UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame);
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_frame_container(UiObject *obj, GtkWidget *frame);
+void ui_frame_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
-UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander);
-void ui_expander_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_expander_container(UiObject *obj, GtkWidget *expander);
+void ui_expander_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
-UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow);
-void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow);
+void ui_scrolledwindow_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
-UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview);
-void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_tabview_container(UiObject *obj, GtkWidget *tabview);
+void ui_tabview_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
-UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max, int init);
-void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max, int init);
+void ui_splitpane_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
 int64_t ui_splitpane_get(UiInteger *i);
 void ui_splitpane_set(UiInteger *i, int64_t value);
@@ -205,12 +187,12 @@
 void ui_gtk_notebook_select_tab(GtkWidget *widget, int tab);
 
 #if GTK_CHECK_VERSION(3, 10, 0)
-UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar);
-void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar);
+void ui_headerbar_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 #endif
 
-UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar);
-void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar);
+void ui_headerbar_fallback_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
 
 #ifdef	__cplusplus
 }
--- a/ui/gtk/display.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/display.c	Sun Oct 05 18:13:15 2025 +0200
@@ -47,8 +47,6 @@
 }
 
 UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     const char *css_class = NULL;
     char *markup = NULL;
     if(args->label) {
@@ -105,7 +103,7 @@
     }
     
 
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
     if(var) {
         UiString* value = (UiString*)var->value;
         value->obj = widget;
@@ -113,8 +111,9 @@
         value->set = ui_label_set;
     }
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, widget);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, widget, &layout);
     
     return widget;
 }
@@ -147,10 +146,12 @@
     }
 }
 
+/*
 UIWIDGET ui_space_deprecated(UiObject *obj) {
     GtkWidget *widget = gtk_label_new("");
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->add(ct, widget);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, widget, &layout);
     
     return widget;
 }
@@ -161,12 +162,14 @@
 #else
     GtkWidget *widget = gtk_hseparator_new();
 #endif
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->add(ct, widget);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, widget, &layout);
     
     return widget;
 }
-
+*/
+ 
 /* ------------------------- progress bar ------------------------- */
 
 typedef struct UiProgressBarRange {
@@ -175,8 +178,6 @@
 } UiProgressBarRange;
 
 UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     GtkWidget *progressbar = gtk_progress_bar_new();
     if(args->max > args->min) {
         UiProgressBarRange *range = malloc(sizeof(UiProgressBarRange));
@@ -191,7 +192,7 @@
     }
     
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_DOUBLE);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_DOUBLE);
     if(var && var->value) {
         UiDouble *value = var->value;
         value->get = ui_progressbar_get;
@@ -200,8 +201,9 @@
         ui_progressbar_set(value, value->value);
     }
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, progressbar);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, progressbar, &layout);
     
     return progressbar;
 }
@@ -229,11 +231,9 @@
 /* ------------------------- progress spinner ------------------------- */
 
 UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     GtkWidget *spinner = gtk_spinner_new();
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
     if(var && var->value) {
         UiInteger *value = var->value;
         value->get = ui_spinner_get;
@@ -242,8 +242,9 @@
         ui_spinner_set(value, value->value);
     }
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, spinner);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, spinner, &layout);
     
     return spinner;
 }
--- a/ui/gtk/entry.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/entry.c	Sun Oct 05 18:13:15 2025 +0200
@@ -39,8 +39,6 @@
     double min = args->min;
     double max = args->max != 0 ? args->max : 1000;
     
-    UiObject* current = uic_current_obj(obj);
-    
     UiVar *var = NULL;
     UiVarType vartype = 0;
     if(args->varname) {
@@ -48,20 +46,20 @@
         if(var) {
             vartype = var->type;
         } else {
-            var = uic_widget_var(obj->ctx, current->ctx, args->rangevalue, args->varname, UI_VAR_RANGE);
+            var = uic_widget_var(obj->ctx, obj->ctx, args->rangevalue, args->varname, UI_VAR_RANGE);
             vartype = UI_VAR_RANGE;
         }
     }
     
     if(!var) {
         if(args->intvalue) {
-            var = uic_widget_var(obj->ctx, current->ctx, args->intvalue, NULL, UI_VAR_INTEGER);
+            var = uic_widget_var(obj->ctx, obj->ctx, args->intvalue, NULL, UI_VAR_INTEGER);
             vartype = UI_VAR_INTEGER;
         } else if(args->doublevalue) {
-            var = uic_widget_var(obj->ctx, current->ctx, args->doublevalue, NULL, UI_VAR_DOUBLE);
+            var = uic_widget_var(obj->ctx, obj->ctx, args->doublevalue, NULL, UI_VAR_DOUBLE);
             vartype = UI_VAR_DOUBLE;
         } else if(args->rangevalue) {
-            var = uic_widget_var(obj->ctx, current->ctx, args->rangevalue, NULL, UI_VAR_RANGE);
+            var = uic_widget_var(obj->ctx, obj->ctx, args->rangevalue, NULL, UI_VAR_RANGE);
             vartype = UI_VAR_RANGE;
         }
     }
@@ -144,8 +142,9 @@
             G_CALLBACK(ui_destroy_vardata),
             event);
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, spin);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, spin, &layout);
     
     return spin;
 }
--- a/ui/gtk/graphics.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/graphics.c	Sun Oct 05 18:13:15 2025 +0200
@@ -44,8 +44,10 @@
         ui_connect_draw_handler(widget, event);
     }
     
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->add(ct, widget);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    //UiLayout layout = UI_ARGS2LAYOUT(args);
+    UiLayout layout = {0};
+    ct->add(ct, widget, &layout);
     
     return widget;
 }
--- a/ui/gtk/image.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/image.c	Sun Oct 05 18:13:15 2025 +0200
@@ -64,8 +64,6 @@
 #endif
 
 UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs *args) {
-    UiObject *current = uic_current_obj(obj);
-    
     GtkWidget *drawingarea = gtk_drawing_area_new();
     GtkWidget *toplevel;
     GtkWidget *widget = drawingarea;
@@ -111,7 +109,7 @@
     
     g_object_set_data_full(G_OBJECT(drawingarea), "uiimageviewer", imgviewer, (GDestroyNotify)imageviewer_destroy);
     
-    UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_GENERIC);
+    UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_GENERIC);
     imgviewer->var = var;
     imgviewer->widget = drawingarea;
     
@@ -187,8 +185,9 @@
         ui_widget_set_contextmenu(widget, menu);
     }
        
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, toplevel);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, toplevel, &layout);
     
     return toplevel;
 }
--- a/ui/gtk/list.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/list.c	Sun Oct 05 18:13:15 2025 +0200
@@ -435,8 +435,6 @@
 }
 
 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     // to simplify things and share code with ui_table_create, we also
     // use a UiModel for the listview
     UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
@@ -464,7 +462,7 @@
     GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection);
     GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory);
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
     
     // init listview
     listview->widget = view;
@@ -513,19 +511,14 @@
             GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
     SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, scroll_area);
-    
-    // ct->current should point to view, not scroll_area, to make it possible
-    // to add a context menu
-    current->container->current = view;
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, scroll_area, &layout);
     
     return scroll_area;
 }
 
 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     // to simplify things and share code with ui_tableview_create, we also
     // use a UiModel for the listview
     UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
@@ -554,7 +547,7 @@
     GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL);
     gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory);
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
     
     // init listview
     listview->widget = view;
@@ -589,8 +582,10 @@
     }
     
     // add widget to parent 
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, view);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, view, &layout);
+    
     return view;
 }
 
@@ -604,8 +599,6 @@
 }
 
 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
     //g_list_store_append(ls, v1);
     
@@ -616,7 +609,7 @@
     GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args->multiselection);
     GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model));
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
     
     // init tableview
     tableview->widget = view;
@@ -697,12 +690,9 @@
             GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
     SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, scroll_area);
-    
-    // ct->current should point to view, not scroll_area, to make it possible
-    // to add a context menu
-    current->container->current = view;
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, scroll_area, &layout);
     
     return scroll_area;
 }
@@ -1126,8 +1116,6 @@
 
 
 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     // create treeview
     GtkWidget *view = gtk_tree_view_new();
     ui_set_name_and_style(view, args->name, args->style_class);
@@ -1161,7 +1149,7 @@
                 G_CALLBACK(ui_listview_destroy),
                 listview);
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
     
     // init listview
     listview->widget = view;
@@ -1221,12 +1209,9 @@
             GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS  
     SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, scroll_area);
-    
-    // ct->current should point to view, not scroll_area, to make it possible
-    // to add a context menu
-    current->container->current = view;
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, scroll_area, &layout);
     
     return scroll_area;
 }
@@ -1243,8 +1228,6 @@
 }
 
 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     // create treeview
     GtkWidget *view = gtk_tree_view_new();
     
@@ -1343,7 +1326,7 @@
     
 #endif
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
     
     //g_signal_connect(view, "drag-begin", G_CALLBACK(drag_begin), NULL);
     //g_signal_connect(view, "drag-end", G_CALLBACK(drag_end), NULL);
@@ -1425,12 +1408,9 @@
 #endif
     }
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, scroll_area);
-    
-    // ct->current should point to view, not scroll_area, to make it possible
-    // to add a context menu
-    current->container->current = view;
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, scroll_area, &layout);
     
     return scroll_area;
 }
@@ -1476,15 +1456,13 @@
 /* --------------------------- ComboBox ---------------------------  */
 
 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     GtkWidget *combobox = gtk_combo_box_new();
     
     ui_set_name_and_style(combobox, args->name, args->style_class);
     ui_set_widget_groups(obj->ctx, combobox, args->groups);
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, combobox);
-    current->container->current = combobox;
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, combobox, &layout);
     
     UiListView *listview = create_listview(obj, args);
     listview->widget = combobox;
@@ -1496,7 +1474,7 @@
                 G_CALLBACK(ui_listview_destroy),
                 listview);
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
     UiList *list = var ? var->value : NULL;
     GtkListStore *listmodel = create_list_store(listview, list);
     if(var) {
@@ -2110,8 +2088,6 @@
 }
 
 UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
 #ifdef UI_GTK3
     GtkWidget *listbox = g_object_new(ui_sidebar_list_box_get_type(), NULL);
 #else
@@ -2130,8 +2106,9 @@
     
     ui_set_name_and_style(listbox, args->name, args->style_class);
     ui_set_widget_groups(obj->ctx, listbox, args->groups);
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, scroll_area);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, scroll_area, &layout);
     
     UiListBox *uilistbox = malloc(sizeof(UiListBox));
     uilistbox->obj = obj;
@@ -2164,7 +2141,7 @@
         // fill items
         ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
     } else {
-        UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->dynamic_sublist, args->varname, UI_VAR_LIST);
+        UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->dynamic_sublist, args->varname, UI_VAR_LIST);
         if(var) {
             UiList *list = var->value;
             list->obj = uilistbox;
--- a/ui/gtk/menu.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/menu.c	Sun Oct 05 18:13:15 2025 +0200
@@ -33,6 +33,7 @@
 
 #include "menu.h"
 #include "toolkit.h"
+#include "widget.h"
 #include "../common/context.h"
 #include "../common/menu.h"
 #include "../common/types.h"
--- a/ui/gtk/range.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/range.c	Sun Oct 05 18:13:15 2025 +0200
@@ -76,8 +76,10 @@
                 event);
     }
     
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->add(ct, scrollbar);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    //UiLayout layout = UI_ARGS2LAYOUT(args);
+    UiLayout layout = {0};
+    ct->add(ct, scrollbar, &layout);
     
     return scrollbar;
 }
--- a/ui/gtk/text.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/text.c	Sun Oct 05 18:13:15 2025 +0200
@@ -108,8 +108,7 @@
 }
 
 UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_TEXT);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_TEXT);
     
     GtkWidget *text_area = gtk_text_view_new();
     ui_set_name_and_style(text_area, args->name, args->style_class);
@@ -155,8 +154,9 @@
     gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text_area), 2);
     
     // add
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, scroll_area);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, scroll_area, &layout);
     
     // bind value
     if(var) {
@@ -598,8 +598,7 @@
     ui_set_name_and_style(textfield, args->name, args->style_class);
     ui_set_widget_groups(obj->ctx, textfield, args->groups);
     
-    UiObject* current = uic_current_obj(obj);
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
     
     UiTextField *uitext = malloc(sizeof(UiTextField));
     uitext->obj = obj;
@@ -630,8 +629,9 @@
         gtk_entry_set_visibility(GTK_ENTRY(textfield), FALSE);
     }
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, textfield);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, textfield, &layout);
     
     if(var) {
         UiString *value = var->value;
@@ -922,8 +922,6 @@
 }
 
 UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     UiPathTextField *pathtf = malloc(sizeof(UiPathTextField));
     memset(pathtf, 0, sizeof(UiPathTextField));
     pathtf->obj = obj;
@@ -946,8 +944,9 @@
     pathtf->stack = gtk_stack_new();
     gtk_widget_set_name(pathtf->stack, "path-textfield-box");
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, pathtf->stack);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, pathtf->stack, &layout);
     
     pathtf->entry_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
     pathtf->entry = gtk_entry_new();
@@ -979,7 +978,7 @@
     gtk_stack_set_visible_child(GTK_STACK(pathtf->stack), pathtf->entry_box);
     
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
     if (var) {
         UiString* value = (UiString*)var->value;
         value->obj = pathtf;
@@ -1083,8 +1082,6 @@
 }
 
 UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     UiPathTextField *pathtf = malloc(sizeof(UiPathTextField));
     memset(pathtf, 0, sizeof(UiPathTextField));
     pathtf->obj = obj;
@@ -1118,8 +1115,9 @@
             G_CALLBACK(ui_path_textfield_destroy),
             pathtf);
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, eventbox);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, eventbox, &layout);
     
     // hbox as parent for the GtkEntry and GtkButtonBox
     GtkWidget *hbox = ui_gtk_hbox_new(0);
@@ -1143,7 +1141,7 @@
             G_CALLBACK(ui_path_textfield_key_press),
             pathtf);
     
-    UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
     if (var) {
         UiString* value = (UiString*)var->value;
         value->obj = pathtf;
--- a/ui/gtk/webview.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/webview.c	Sun Oct 05 18:13:15 2025 +0200
@@ -34,13 +34,11 @@
 #ifdef UI_WEBVIEW
 
 UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     GtkWidget *webview = webkit_web_view_new();
     
     ui_set_name_and_style(webview, args->name, args->style_class);
     
-    UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_GENERIC);
+    UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_GENERIC);
     if(var) {
         WebViewData *data = malloc(sizeof(WebViewData));
         memset(data, 0, sizeof(WebViewData));
@@ -60,8 +58,9 @@
     }
     
     ui_set_widget_groups(obj->ctx, webview, args->groups);
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, webview);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, webview, &layout);
     
     return webview;
 }
--- a/ui/gtk/widget.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/widget.c	Sun Oct 05 18:13:15 2025 +0200
@@ -32,22 +32,21 @@
 #include "../common/object.h"
 
 UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args) {
-    UiObject* current = uic_current_obj(obj);
-    
     UIWIDGET widget = create_widget(obj, args, userdata);
     
-    UI_APPLY_LAYOUT2(current, args);
-    current->container->add(current->container, widget);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, widget, &layout);
     
     return widget;
 }
 
 UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args) {
-    UiObject* current = uic_current_obj(obj);
     GtkWidget *widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
     ui_set_name_and_style(widget, args->name, args->style_class);
-    UI_APPLY_LAYOUT1(current, (*args));
-    current->container->add(current->container, widget);
+    UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ct->add(ct, widget, &layout);
     return widget;
 }
 
--- a/ui/gtk/window.c	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/gtk/window.c	Sun Oct 05 18:13:15 2025 +0200
@@ -372,7 +372,8 @@
     gtk_container_add(GTK_CONTAINER(frame), content_box);
     obj->container = ui_box_container(obj, content_box);
     */
-    obj->container = ui_box_container(obj, content_box, UI_CONTAINER_VBOX);
+    UiContainerX *container = ui_box_container(obj, content_box, UI_CONTAINER_VBOX);
+    uic_object_push_container(obj, container);
     
     nwindows++;
     return obj;
@@ -932,7 +933,8 @@
 #endif
     
     GtkWidget *content_vbox = ui_gtk_vbox_new(0);
-    obj->container = ui_box_container(obj, content_vbox, UI_CONTAINER_VBOX);
+    UiContainerX *container = ui_box_container(obj, content_vbox, UI_CONTAINER_VBOX);
+    uic_object_push_container(obj, container);
     if(args->lbutton1 || args->lbutton2 || args->rbutton3 || args->rbutton4) {
 #if GTK_CHECK_VERSION(3, 10, 0)
         if(args->titlebar_buttons != UI_OFF) {
--- a/ui/ui/container.h	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/ui/container.h	Sun Oct 05 18:13:15 2025 +0200
@@ -101,8 +101,6 @@
     const char *name;
     const char *style_class;
 
-    UiSubContainerType subcontainer;
-
     int spacing;
     int columnspacing;
     int rowspacing;
@@ -137,6 +135,7 @@
     UiInteger *value;
     const char* varname;
 
+    int padding;
     int spacing;
     int columnspacing;
     int rowspacing;
@@ -149,6 +148,11 @@
     UiBool hfill;
     UiBool vfill;
     UiBool override_defaults;
+    int margin;
+    int margin_left;
+    int margin_right;
+    int margin_top;
+    int margin_bottom;
     int colspan;
     int rowspan;
     const char *name;
@@ -249,9 +253,29 @@
     UiSubContainerType subcontainer;
 } UiItemListContainerArgs;
 
+
+typedef struct UiLayout UiLayout;
+struct UiLayout {
+    UiBool       fill;
+    char         *label;
+    UiBool       hexpand;
+    UiBool       vexpand;
+    UiBool       hfill;
+    UiBool       vfill;
+    UiBool       override_defaults;
+    int          margin;
+    int          margin_left;
+    int          margin_right;
+    int          margin_top;
+    int          margin_bottom;
+    int          colspan;
+    int          rowspan;
+};
+
 struct UiContainerX {
     void *container;
-    int close;
+    UiBool close;
+    UiBool newline;
     UiContainerX *prev;
     UiContainerX *next;
 };
@@ -384,7 +408,21 @@
     if(args->rowspan > 0) ui_layout_rowspan(obj, args->rowspan); \
     /*force caller to add ';'*/(void)0
 
-
+#define UI_ARGS2LAYOUT(args) { \
+    .fill = args->fill, \
+    .hexpand = args->hexpand, \
+    .vexpand = args->vexpand, \
+    .hfill = args->hfill, \
+    .vfill = args->vfill, \
+    .override_defaults = args->override_defaults, \
+    .margin = args->margin, \
+    .margin_left = args->margin_left, \
+    .margin_right = args->margin_right, \
+    .margin_top = args->margin_top, \
+    .margin_bottom = args->margin_bottom, \
+    .colspan = args->colspan, \
+    .rowspan = args->rowspan }
+    
 #ifdef __cplusplus
 }
 #endif
--- a/ui/ui/toolkit.h	Sun Oct 05 13:30:19 2025 +0200
+++ b/ui/ui/toolkit.h	Sun Oct 05 18:13:15 2025 +0200
@@ -286,11 +286,6 @@
     UiContext   *ctx;
     
     /*
-     * container interface (deprecated)
-     */
-    UiContainer *container;
-    
-    /*
      * container list
      * TODO: remove old UiContainer and rename UiContainerX to UiContainer
      */

mercurial