--- a/ui/gtk/container.c Mon Jan 06 22:22:55 2025 +0100 +++ b/ui/gtk/container.c Tue Feb 25 21:11:00 2025 +0100 @@ -52,6 +52,17 @@ return 1; } +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_LAYOUT1(current, args); + current->container->add(current->container, widget, FALSE); + + return widget; +} + GtkWidget* ui_gtk_vbox_new(int spacing) { #if GTK_MAJOR_VERSION >= 3 return gtk_box_new(GTK_ORIENTATION_VERTICAL, spacing); @@ -96,7 +107,7 @@ 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); + newobj->container = ui_grid_container(newobj, sub, FALSE, FALSE, FALSE, FALSE); newobj->widget = sub; break; } @@ -156,11 +167,22 @@ ct->current = widget; } -UiContainer* ui_grid_container(UiObject *obj, GtkWidget *grid) { +UiContainer* ui_grid_container( + UiObject *obj, + GtkWidget *grid, + UiBool def_hexpand, + UiBool def_vexpand, + UiBool def_hfill, + UiBool def_vfill) +{ UiGridContainer *ct = cxCalloc( obj->ctx->allocator, 1, sizeof(UiGridContainer)); + ct->def_hexpand = def_hexpand; + ct->def_vexpand = def_vexpand; + ct->def_hfill = def_hfill; + ct->def_vfill = def_vfill; ct->container.widget = grid; ct->container.add = ui_grid_container_add; UI_GTK_V2(ct->width = 0); @@ -182,15 +204,34 @@ 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; + } + } + if(ct->layout.fill != UI_LAYOUT_UNDEFINED) { fill = ui_lb2bool(ct->layout.fill); } - if(ct->layout.hexpand != UI_LAYOUT_UNDEFINED) { - hexpand = ct->layout.hexpand; + if(ct->layout.hexpand) { + hexpand = TRUE; + hfill = TRUE; + } else if(ct->layout.hfill) { hfill = TRUE; } - if(ct->layout.vexpand != UI_LAYOUT_UNDEFINED) { - vexpand = ct->layout.vexpand; + if(ct->layout.vexpand) { + vexpand = TRUE; + vfill = TRUE; + } else if(ct->layout.vfill) { vfill = TRUE; } if(fill) { @@ -230,14 +271,57 @@ int hexpand = FALSE; int vexpand = FALSE; - if(ct->layout.hexpand != UI_LAYOUT_UNDEFINED) { - hexpand = ct->layout.hexpand; + 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; + } + } + + if(ct->layout.fill != UI_LAYOUT_UNDEFINED) { + fill = ui_lb2bool(ct->layout.fill); + } + if(ct->layout.hexpand) { + hexpand = TRUE; + hfill = TRUE; + } else if(ct->layout.hfill) { + hfill = TRUE; } - if(ct->layout.vexpand != UI_LAYOUT_UNDEFINED) { - vexpand = ct->layout.vexpand; + if(ct->layout.vexpand) { + vexpand = TRUE; + vfill = TRUE; + } else if(ct->layout.vfill) { + vfill = TRUE; + } + if(fill) { + hfill = TRUE; + vfill = TRUE; } - GtkAttachOptions xoptions = hexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL; - GtkAttachOptions yoptions = vexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL; + + GtkAttachOptions xoptions = 0; + GtkAttachOptions yoptions = 0; + if(hexpand) { + xoptions = GTK_EXPAND; + } + if(hfill) { + xoptions |= GTK_FILL; + } + if(vexpand) { + yoptions = GTK_EXPAND; + } + if(vfill) { + yoptions |= GTK_FILL; + } int colspan = ct->layout.colspan > 0 ? ct->layout.colspan : 1; int rowspan = ct->layout.rowspan > 0 ? ct->layout.rowspan : 1; @@ -396,7 +480,7 @@ current->container->add(current->container, widget, TRUE); UiObject *newobj = uic_object_new(obj, grid); - newobj->container = ui_grid_container(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; @@ -755,7 +839,7 @@ } case UI_CONTAINER_GRID: { sub = ui_create_grid_widget(data->columnspacing, data->rowspacing); - newobj->container = ui_grid_container(newobj, sub); + newobj->container = ui_grid_container(newobj, sub, FALSE, FALSE, FALSE, FALSE); break; } } @@ -946,6 +1030,68 @@ +static UIWIDGET splitpane_create(UiObject *obj, UiOrientation orientation, UiSplitPaneArgs args) { + UiObject* current = uic_current_obj(obj); + + GtkWidget *pane0 = create_paned(orientation); + + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, pane0, TRUE); + + int max = args.max_panes == 0 ? 2 : args.max_panes; + + UiObject *newobj = uic_object_new(obj, pane0); + newobj->container = ui_splitpane_container(obj, pane0, orientation, max); + uic_obj_add(obj, newobj); + + return pane0; +} + +UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs args) { + return splitpane_create(obj, UI_HORIZONTAL, args); +} + +UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs args) { + return splitpane_create(obj, UI_VERTICAL, args); +} + +UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max) { + UiSplitPaneContainer *ct = ui_calloc(obj->ctx, 1, sizeof(UiSplitPaneContainer)); + ct->container.widget = pane; + ct->container.add = ui_splitpane_container_add; + ct->current_pane = pane; + ct->orientation = orientation; + ct->max = max; + return (UiContainer*)ct; +} + +void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { + UiSplitPaneContainer *s = (UiSplitPaneContainer*)ct; + + if(s->nchildren >= s->max) { + fprintf(stderr, "splitpane: maximum number of children reached\n"); + return; + } + + if(s->pos == 0) { + gtk_paned_set_start_child(GTK_PANED(s->current_pane), widget); + s->pos++; + s->nchildren++; + } else { + if(s->nchildren+1 == s->max) { + gtk_paned_set_end_child(GTK_PANED(s->current_pane), widget); + } else { + GtkWidget *pane = create_paned(s->orientation); + gtk_paned_set_start_child(GTK_PANED(pane), widget); + gtk_paned_set_end_child(GTK_PANED(s->current_pane), pane); + s->current_pane = pane; + } + + s->pos = 0; + s->nchildren++; + } +} + /* -------------------- ItemList Container -------------------- */ static void remove_item(void *data, void *item) { @@ -997,7 +1143,7 @@ ui_box_container_add(ct->container, item_obj->widget, FALSE); } else { // create new widget and object for this list element - CxMempool *mp = cxBasicMempoolCreate(256); + CxMempool *mp = cxMempoolCreateSimple(256); const CxAllocator *a = mp->allocator; UiObject *obj = cxCalloc(a, 1, sizeof(UiObject)); obj->ctx = uic_context(obj, mp); @@ -1102,6 +1248,11 @@ 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;