--- a/ui/gtk/container.c Sat Apr 05 17:57:04 2025 +0200 +++ b/ui/gtk/container.c Sun Jul 20 22:04:39 2025 +0200 @@ -120,12 +120,9 @@ return (UiContainer*)ct; } -void ui_box_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { +void ui_box_container_add(UiContainer *ct, GtkWidget *widget) { UiBoxContainer *bc = (UiBoxContainer*)ct; - if(ct->layout.fill != UI_LAYOUT_UNDEFINED) { - fill = ui_lb2bool(ct->layout.fill); - } - + UiBool fill = ct->layout.fill; if(bc->has_fill && fill) { fprintf(stderr, "UiError: container has 2 filled widgets"); fill = FALSE; @@ -180,7 +177,7 @@ } #if GTK_MAJOR_VERSION >= 3 -void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { +void ui_grid_container_add(UiContainer *ct, GtkWidget *widget) { UiGridContainer *grid = (UiGridContainer*)ct; if(ct->layout.newline) { @@ -208,9 +205,7 @@ } } - if(ct->layout.fill != UI_LAYOUT_UNDEFINED) { - fill = ui_lb2bool(ct->layout.fill); - } + UiBool fill = ct->layout.fill; if(ct->layout.hexpand) { hexpand = TRUE; hfill = TRUE; @@ -249,7 +244,7 @@ } #endif #ifdef UI_GTK2 -void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { +void ui_grid_container_add(UiContainer *ct, GtkWidget *widget) { UiGridContainer *grid = (UiGridContainer*)ct; if(ct->layout.newline) { @@ -277,9 +272,7 @@ } } - if(ct->layout.fill != UI_LAYOUT_UNDEFINED) { - fill = ui_lb2bool(ct->layout.fill); - } + UiBool fill = ct->layout.fill; if(ct->layout.hexpand) { hexpand = TRUE; hfill = TRUE; @@ -340,7 +333,7 @@ return ct; } -void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { +void ui_frame_container_add(UiContainer *ct, GtkWidget *widget) { FRAME_SET_CHILD(ct->widget, widget); } @@ -354,11 +347,11 @@ return ct; } -void ui_expander_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { +void ui_expander_container_add(UiContainer *ct, GtkWidget *widget) { EXPANDER_SET_CHILD(ct->widget, widget); } -void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { +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); @@ -385,7 +378,7 @@ return (UiContainer*)ct; } -void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { +void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget) { UiGtkTabView *data = ui_widget_get_tabview_data(ct->widget); if(!data) { fprintf(stderr, "UI Error: widget is not a tabview"); @@ -420,15 +413,15 @@ return ret; } -UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType type) { +UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType type) { UiObject *current = uic_current_obj(obj); UiContainer *ct = current->container; - UI_APPLY_LAYOUT1(current, args); + UI_APPLY_LAYOUT2(current, 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, TRUE); + 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); UiObject *newobj = uic_object_new(obj, box); newobj->container = ui_box_container(obj, box, type); @@ -437,11 +430,11 @@ return widget; } -UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) { +UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) { return ui_box_create(obj, args, UI_CONTAINER_VBOX); } -UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) { +UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args) { return ui_box_create(obj, args, UI_CONTAINER_HBOX); } @@ -458,74 +451,74 @@ return grid; } -UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) { +UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) { UiObject* current = uic_current_obj(obj); - UI_APPLY_LAYOUT1(current, args); + UI_APPLY_LAYOUT2(current, 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, TRUE); + 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); 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); + 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; } -UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs args) { +UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) { UiObject* current = uic_current_obj(obj); - UI_APPLY_LAYOUT1(current, args); + UI_APPLY_LAYOUT2(current, args); - GtkWidget *frame = gtk_frame_new(args.label); + 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); + 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, FALSE); + current->container->add(current->container, frame); uic_obj_add(obj, newobj); return frame; } -UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs args) { +UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs *args) { UiObject* current = uic_current_obj(obj); - UI_APPLY_LAYOUT1(current, args); + UI_APPLY_LAYOUT2(current, args); - GtkWidget *expander = gtk_expander_new(args.label); - gtk_expander_set_expanded(GTK_EXPANDER(expander), args.isexpanded); + 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); + 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, FALSE); + current->container->add(current->container, expander); uic_obj_add(obj, newobj); return expander; } -UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs args) { +UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) { UiObject* current = uic_current_obj(obj); - UI_APPLY_LAYOUT1(current, args); + UI_APPLY_LAYOUT2(current, 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, TRUE); + 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); 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, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin); if(sub) { SCROLLEDWINDOW_SET_CHILD(sw, sub); } else { @@ -689,22 +682,71 @@ return g_object_get_data(G_OBJECT(tabview), "ui_tabview"); } +static void tabview_switch_page( + GtkNotebook *self, + GtkWidget *page, + guint page_num, + gpointer userdata) +{ + UiGtkTabView *tabview = userdata; + if(!tabview->onchange) { + return; + } + + UiEvent event; + event.obj = tabview->obj; + event.window = event.obj->window; + event.document = event.obj->ctx->document; + event.set = ui_get_setop(); + event.eventdata = NULL; + event.eventdatatype = 0; + event.intval = page_num; + + tabview->onchange(&event, tabview->onchange); +} + +#if GTK_CHECK_VERSION(3, 10, 0) + +static void tabview_stack_changed( + GObject *object, + GParamSpec *pspec, + UiGtkTabView *tabview) +{ + if(!tabview->onchange) { + return; + } + + UiEvent event; + event.obj = tabview->obj; + event.window = event.obj->window; + event.document = event.obj->ctx->document; + event.set = ui_get_setop(); + event.eventdata = NULL; + event.eventdatatype = 0; + event.intval = 0; + + tabview->onchange(&event, tabview->onchange); +} + +#endif + typedef int64_t(*ui_tabview_get_func)(UiInteger*); typedef void (*ui_tabview_set_func)(UiInteger*, int64_t); -UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args) { +UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) { UiGtkTabView *data = malloc(sizeof(UiGtkTabView)); - data->margin = args.margin; - data->spacing = args.spacing; - data->columnspacing = args.columnspacing; - data->rowspacing = args.rowspacing; + memset(data, 0, sizeof(UiGtkTabView)); + data->margin = args->margin; + data->spacing = args->spacing; + data->columnspacing = args->columnspacing; + data->rowspacing = args->rowspacing; ui_tabview_get_func getfunc = NULL; ui_tabview_set_func setfunc = NULL; GtkWidget *widget = NULL; GtkWidget *data_widget = NULL; - switch(args.tabview) { + switch(args->tabview) { case UI_TABVIEW_DOC: { // TODO break; @@ -715,6 +757,7 @@ GtkWidget *sidebar = gtk_stack_sidebar_new(); BOX_ADD(widget, sidebar); GtkWidget *stack = gtk_stack_new(); + g_signal_connect(stack, "notify::visible-child", G_CALLBACK(tabview_stack_changed), data); gtk_stack_set_transition_type (GTK_STACK(stack), GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN); gtk_stack_sidebar_set_stack(GTK_STACK_SIDEBAR(sidebar), GTK_STACK(stack)); BOX_ADD_EXPAND(widget, stack); @@ -734,13 +777,18 @@ case UI_TABVIEW_INVISIBLE: /* fall through */ case UI_TABVIEW_NAVIGATION_TOP2: { widget = gtk_notebook_new(); + g_signal_connect( + widget, + "switch-page", + G_CALLBACK(tabview_switch_page), + data); data_widget = widget; data->select_tab = ui_notebook_tab_select; data->remove_tab = ui_notebook_tab_remove; data->add_tab = ui_notebook_tab_add; getfunc = ui_notebook_get; setfunc = ui_notebook_set; - if(args.tabview == UI_TABVIEW_INVISIBLE) { + if(args->tabview == UI_TABVIEW_INVISIBLE) { gtk_notebook_set_show_tabs(GTK_NOTEBOOK(widget), FALSE); gtk_notebook_set_show_border(GTK_NOTEBOOK(widget), FALSE); } @@ -749,8 +797,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); + if(args->value || args->varname) { + UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER); UiInteger *i = var->value; i->get = getfunc; i->set = setfunc; @@ -759,10 +807,10 @@ g_object_set_data(G_OBJECT(widget), "ui_tabview", data); data->widget = data_widget; - data->subcontainer = args.subcontainer; + data->subcontainer = args->subcontainer; - UI_APPLY_LAYOUT1(current, args); - current->container->add(current->container, widget, TRUE); + 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); @@ -872,14 +920,14 @@ hb_set_part(obj, 1); } -UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs args) { +UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs *args) { UiObject *current = uic_current_obj(obj); UiContainer *ct = current->container; - UI_APPLY_LAYOUT1(current, args); + UI_APPLY_LAYOUT2(current, 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, FALSE); + GtkWidget *box = ui_gtk_hbox_new(args->alt_spacing); + ui_set_name_and_style(box, args->name, args->style_class); + ct->add(ct, box); UiObject *newobj = uic_object_new(obj, box); newobj->container = ui_headerbar_fallback_container(obj, box); @@ -910,14 +958,14 @@ return (UiContainer*)ct; } -void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { +void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget) { 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); @@ -940,7 +988,7 @@ return (UiContainer*)ct; } -void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { +void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget) { UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct; if(hb->part == 0) { UI_HEADERBAR_PACK_START(ct->widget, widget); @@ -958,7 +1006,7 @@ #else -UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) { +UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) { return ui_headerbar_fallback_create(obj, args); } @@ -967,15 +1015,15 @@ /* -------------------- Sidebar -------------------- */ #ifdef UI_LIBADWAITA -UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) { +UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) { GtkWidget *sidebar_toolbar_view = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar"); if(!sidebar_toolbar_view) { fprintf(stderr, "Error: window is not configured for sidebar\n"); return NULL; } - GtkWidget *box = ui_gtk_vbox_new(args.spacing); - ui_box_set_margin(box, args.margin); + GtkWidget *box = ui_gtk_vbox_new(args->spacing); + 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); @@ -985,11 +1033,11 @@ return box; } #else -UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) { +UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) { 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); + GtkWidget *box = ui_gtk_vbox_new(args->spacing); + ui_box_set_margin(box, args->margin); BOX_ADD_EXPAND(sidebar_vbox, box); UiObject *newobj = uic_object_new(obj, box); @@ -1019,18 +1067,18 @@ -static UIWIDGET splitpane_create(UiObject *obj, UiOrientation orientation, UiSplitPaneArgs args) { +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); + UI_APPLY_LAYOUT2(current, args); + current->container->add(current->container, pane0); - int max = args.max_panes == 0 ? 2 : args.max_panes; + 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, args.initial_position); + newobj->container = ui_splitpane_container(obj, pane0, orientation, max, args->initial_position); uic_obj_add(obj, newobj); g_object_set_data(G_OBJECT(pane0), "ui_splitpane", newobj->container); @@ -1038,11 +1086,11 @@ return pane0; } -UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs args) { +UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) { return splitpane_create(obj, UI_HORIZONTAL, args); } -UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs args) { +UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) { return splitpane_create(obj, UI_VERTICAL, args); } @@ -1058,7 +1106,7 @@ return (UiContainer*)ct; } -void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { +void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget) { UiSplitPaneContainer *s = (UiSplitPaneContainer*)ct; if(s->nchildren >= s->max) { @@ -1151,7 +1199,7 @@ 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, FALSE); + ui_box_container_add(ct->container, item_obj->widget); } else { // create new widget and object for this list element CxMempool *mp = cxMempoolCreateSimple(256); @@ -1166,7 +1214,7 @@ ct->columnspacing, ct->rowspacing, ct->margin); - ui_box_container_add(ct->container, obj->widget, FALSE); + ui_box_container_add(ct->container, obj->widget); if(ct->create_ui) { ct->create_ui(obj, index, elm, ct->userdata); } @@ -1175,6 +1223,10 @@ elm = list->next(list); index++; } + +#if GTK_MAJOR_VERSION < 4 + gtk_widget_show_all(ct->widget); +#endif } static void destroy_itemlist_container(GtkWidget *w, UiGtkItemListContainer *container) { @@ -1183,33 +1235,33 @@ free(container); } -UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs args) { +UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs *args) { UiObject *current = uic_current_obj(obj); UiContainer *ct = current->container; - UI_APPLY_LAYOUT1(current, args); + UI_APPLY_LAYOUT2(current, 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, TRUE); + 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); UiGtkItemListContainer *container = malloc(sizeof(UiGtkItemListContainer)); container->parent = obj; container->widget = box; - container->container = ui_box_container(current, box, args.container); - container->create_ui = args.create_ui; - container->userdata = args.userdata; - container->subcontainer = args.subcontainer; + container->container = ui_box_container(current, box, args->container); + container->create_ui = args->create_ui; + container->userdata = args->userdata; + container->subcontainer = args->subcontainer; container->current_items = cxHashMapCreateSimple(CX_STORE_POINTERS); container->current_items->collection.advanced_destructor = remove_item; container->current_items->collection.destructor_data = container; - container->margin = args.sub_margin; - container->spacing = args.sub_spacing; - container->columnspacing = args.sub_columnspacing; - container->rowspacing = args.sub_rowspacing; + container->margin = args->sub_margin; + container->spacing = args->sub_spacing; + container->columnspacing = args->sub_columnspacing; + 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, current->ctx, args->value, args->varname, UI_VAR_LIST); if(var) { UiList *list = var->value; list->obj = container; @@ -1236,7 +1288,7 @@ void ui_layout_fill(UiObject *obj, UiBool fill) { UiContainer *ct = uic_get_current_container(obj); - ct->layout.fill = ui_bool2lb(fill); + ct->layout.fill = fill; } void ui_layout_hexpand(UiObject *obj, UiBool expand) {