--- a/ui/gtk/container.c Sat Oct 04 14:54:25 2025 +0200 +++ b/ui/gtk/container.c Sun Oct 19 21:20:08 2025 +0200 @@ -37,19 +37,20 @@ #include "../common/context.h" #include "../common/object.h" +#include "../common/container.h" #include "../ui/properties.h" 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; @@ -73,7 +74,7 @@ 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; + add = ui_gtk_set_margin(sub, margin, 0, 0, 0, 0); + 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; + add = ui_gtk_set_margin(sub, margin, 0, 0, 0, 0); + 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; + add = ui_gtk_set_margin(sub, margin, 0, 0, 0, 0); + 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,14 @@ 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; + widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom); + + UiBool fill = layout->fill; if(bc->has_fill && fill) { fprintf(stderr, "UiError: container has 2 filled widgets"); fill = FALSE; @@ -152,11 +156,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 +179,72 @@ 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; } + #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; + widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom); - 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; - } - } + uic_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; + widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom); - 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; - } + uic_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,116 +256,138 @@ 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) { + widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom); + 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) { + widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom); + EXPANDER_SET_CHILD(ct->widget, widget); + ct->current = widget; +} + +void ui_scrolledwindow_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) { + widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom); + // 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); + widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom); + data->add_tab(ct->widget, -1, layout->label, widget); - ui_reset_layout(ct->layout); ct->current = widget; } +#ifdef UI_GTK2 +static void alignment_child_visibility_changed(GtkWidget *widget, gpointer user_data) { + gtk_widget_set_visible(gtk_widget_get_parent(widget), gtk_widget_get_visible(widget)); +} + +#endif -GtkWidget* ui_box_set_margin(GtkWidget *box, int margin) { - GtkWidget *ret = box; +GtkWidget* ui_gtk_set_margin(GtkWidget *widget, int margin, int margin_left, int margin_right, int margin_top, int margin_bottom) { + if(margin > 0) { + margin_left = margin; + margin_right = margin; + margin_top = margin; + margin_bottom = margin; + } + GtkWidget *ret = widget; #if GTK_MAJOR_VERSION >= 3 -#if GTK_MAJOR_VERSION * 1000 + GTK_MINOR_VERSION >= 3012 - gtk_widget_set_margin_start(box, margin); - gtk_widget_set_margin_end(box, margin); +#if GTK_CHECK_VERSION(3, 12, 0) + gtk_widget_set_margin_start(widget, margin_left); + gtk_widget_set_margin_end(widget, margin_right); #else - gtk_widget_set_margin_left(box, margin); - gtk_widget_set_margin_right(box, margin); + gtk_widget_set_margin_left(widget, margin_left); + gtk_widget_set_margin_right(widget, margin_right); #endif - gtk_widget_set_margin_top(box, margin); - gtk_widget_set_margin_bottom(box, margin); + gtk_widget_set_margin_top(widget, margin_top); + gtk_widget_set_margin_bottom(widget, margin_bottom); #elif defined(UI_GTK2) GtkWidget *a = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_alignment_set_padding(GTK_ALIGNMENT(a), margin, margin, margin, margin); - gtk_container_add(GTK_CONTAINER(a), box); + gtk_alignment_set_padding(GTK_ALIGNMENT(a), margin_top, margin_bottom, margin_left, margin_right); + gtk_container_add(GTK_CONTAINER(a), widget); + g_signal_connect( + widget, + "show", + G_CALLBACK(alignment_child_visibility_changed), + NULL); + g_signal_connect( + widget, + "hide", + G_CALLBACK(alignment_child_visibility_changed), + NULL); ret = a; #endif return ret; } 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); + ct->add(ct, box, &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; + return box; } UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) { @@ -457,82 +412,113 @@ } 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, grid, &layout); + + 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); - 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); - - return widget; + return grid; +} + +static void frame_create_subcontainer(UiObject *obj, UiFrameArgs *args) { + switch(args->subcontainer) { + default: + case UI_CONTAINER_VBOX: { + UiContainerArgs sub_args = { .spacing = args->spacing, .margin = args->padding }; + ui_vbox_create(obj, &sub_args); + break; + } + case UI_CONTAINER_HBOX: { + UiContainerArgs sub_args = { .spacing = args->spacing, .margin = args->padding }; + ui_hbox_create(obj, &sub_args); + break; + } + case UI_CONTAINER_GRID: { + UiContainerArgs sub_args = { .columnspacing = args->columnspacing, .rowspacing = args->rowspacing, .margin = args->padding }; + ui_grid_create(obj, &sub_args); + break; + } + case UI_CONTAINER_NO_SUB: { + break; // NOOP + } + } } 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); + ct->add(ct, frame, &layout); + + GtkWidget *sub = ui_subcontainer_create( + args->subcontainer, + obj, args->spacing, + args->columnspacing, + args->rowspacing, + args->padding); if(sub) { FRAME_SET_CHILD(frame, sub); } else { - newobj->widget = frame; - newobj->container = ui_frame_container(obj, frame); + UiContainerX *container = ui_frame_container(obj, frame); + uic_object_push_container(obj, container); } - current->container->add(current->container, frame); - uic_obj_add(obj, newobj); 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); + ct->add(ct, expander, &layout); + + GtkWidget *sub = ui_subcontainer_create( + args->subcontainer, + obj, args->spacing, + args->columnspacing, + args->rowspacing, + args->padding); if(sub) { EXPANDER_SET_CHILD(expander, sub); } else { - newobj->widget = expander; - newobj->container = ui_expander_container(obj, expander); + UiContainerX *container = ui_expander_container(obj, expander); + uic_object_push_container(obj, container); } - current->container->add(current->container, expander); - uic_obj_add(obj, newobj); 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); + GtkWidget *sub = ui_subcontainer_create( + args->subcontainer, + obj, args->spacing, + args->columnspacing, + args->rowspacing, + args->padding); if(sub) { SCROLLEDWINDOW_SET_CHILD(sw, sub); } else { - newobj->widget = sw; - newobj->container = ui_scrolledwindow_container(obj, sw); + UiContainerX *container = ui_scrolledwindow_container(obj, sw); + uic_object_push_container(obj, container); } - uic_obj_add(obj, newobj); - return sw; } @@ -741,7 +727,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 +787,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 +797,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_gtk_set_margin(sub, tabview->padding, 0, 0, 0, 0); + 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 +876,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 +886,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 +911,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); @@ -1028,12 +1009,11 @@ } GtkWidget *box = ui_gtk_vbox_new(args->spacing); - ui_box_set_margin(box, args->margin); + ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom); 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; } @@ -1042,12 +1022,11 @@ GtkWidget *sidebar_vbox = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar"); GtkWidget *box = ui_gtk_vbox_new(args->spacing); - ui_box_set_margin(box, args->margin); + ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom); 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; } @@ -1063,12 +1042,11 @@ GtkWidget *box = ui_gtk_vbox_new(args->spacing); ui_set_name_and_style(box, args->name, args->style_class); - ui_box_set_margin(box, args->margin); + ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom); 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 +1086,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,19 +1111,18 @@ 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); + UiSplitPane *splitpane = ui_create_splitpane_data(pane0, orientation, max, args->initial_position); + UiContainerX *container = ui_splitpane_container(obj, pane0, splitpane); + 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", splitpane); - 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; UiInteger *i = var->value; - s->initial_position = i->value; + splitpane->initial_position = i->value; - i->obj = s; + i->obj = splitpane; i->get = ui_splitpane_get; i->set = ui_splitpane_set; } @@ -1162,20 +1138,27 @@ return splitpane_create(obj, UI_VERTICAL, args); } -UiContainer* 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; +UiSplitPane* ui_create_splitpane_data(GtkWidget *pane, UiOrientation orientation, int max, int init) { + UiSplitPane *ct = malloc(sizeof(UiSplitPane)); ct->current_pane = pane; ct->orientation = orientation; ct->max = max; ct->initial_position = init; ct->children = cxArrayListCreateSimple(CX_STORE_POINTERS, 4); - return (UiContainer*)ct; + return ct; } -void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget) { - UiSplitPaneContainer *s = (UiSplitPaneContainer*)ct; +UiContainerX* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiSplitPane *data) { + UiSplitPaneContainer *ct = ui_calloc(obj->ctx, 1, sizeof(UiSplitPaneContainer)); + ct->container.widget = pane; + ct->container.add = ui_splitpane_container_add; + ct->splitpane = data; + return (UiContainerX*)ct; +} + +void ui_splitpane_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) { + UiSplitPaneContainer *sct = (UiSplitPaneContainer*)ct; + UiSplitPane *s = sct->splitpane; if(s->nchildren >= s->max) { fprintf(stderr, "splitpane: maximum number of children reached\n"); @@ -1207,25 +1190,25 @@ } int64_t ui_splitpane_get(UiInteger *i) { - UiSplitPaneContainer *s = i->obj; - i->value = gtk_paned_get_position(GTK_PANED(s->container.widget)); + UiSplitPane *s = i->obj; + i->value = gtk_paned_get_position(GTK_PANED(s->current_pane)); return i->value; } void ui_splitpane_set(UiInteger *i, int64_t value) { - UiSplitPaneContainer *s = i->obj; + UiSplitPane *s = i->obj; i->value = value; - gtk_paned_set_position(GTK_PANED(s->container.widget), (int)value); + gtk_paned_set_position(GTK_PANED(s->current_pane), (int)value); } UIEXPORT void ui_splitpane_set_visible(UIWIDGET splitpane, int child_index, UiBool visible) { - UiSplitPaneContainer *ct = g_object_get_data(G_OBJECT(splitpane), "ui_splitpane"); - if(!ct) { + UiSplitPane *s = g_object_get_data(G_OBJECT(splitpane), "ui_splitpane"); + if(!s) { fprintf(stderr, "UI Error: not a splitpane\n"); return; } - GtkWidget *w = cxListAt(ct->children, child_index); + GtkWidget *w = cxListAt(s->children, child_index); if(w) { gtk_widget_set_visible(w, visible); } @@ -1279,13 +1262,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 +1276,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 +1299,17 @@ } 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, box, &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 +1322,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 +1339,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; -} -