ui/gtk/container.c

changeset 51
e324291ca9f8
parent 45
ab71409644b0
--- a/ui/gtk/container.c	Sun Oct 06 18:43:06 2024 +0200
+++ b/ui/gtk/container.c	Sun Oct 20 21:24:13 2024 +0200
@@ -32,6 +32,7 @@
 
 #include "container.h"
 #include "toolkit.h"
+#include "headerbar.h"
 
 #include "../common/context.h"
 #include "../common/object.h"
@@ -228,10 +229,12 @@
 }
 
 void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
-    gtk_notebook_append_page(
-            GTK_NOTEBOOK(ct->widget),
-            widget,
-            gtk_label_new(ct->layout.label));
+    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);
     
     ui_reset_layout(ct->layout);
     ct->current = widget;
@@ -330,10 +333,431 @@
 }
 
 
-void ui_select_tab(UIWIDGET tabview, int tab) {
+void ui_notebook_tab_select(UIWIDGET tabview, int tab) {
     gtk_notebook_set_current_page(GTK_NOTEBOOK(tabview), tab);
 }
 
+void ui_notebook_tab_remove(UIWIDGET tabview, int tab) {
+    gtk_notebook_remove_page(GTK_NOTEBOOK(tabview), tab);
+}
+
+void ui_notebook_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) {
+    gtk_notebook_insert_page(
+            GTK_NOTEBOOK(widget),
+            child,
+            gtk_label_new(name),
+            index);
+}
+
+int64_t ui_notebook_get(UiInteger *i) {
+    GtkNotebook *nb = i->obj;
+    i->value = gtk_notebook_get_current_page(nb);
+    return i->value;
+}
+
+void ui_notebook_set(UiInteger *i, int64_t value) {
+    GtkNotebook *nb = i->obj;
+    gtk_notebook_set_current_page(nb, value);
+    i->value = gtk_notebook_get_current_page(nb);
+}
+
+
+#if GTK_MAJOR_VERSION >= 4
+static int stack_set_page(GtkWidget *stack, int index) {
+    GtkSelectionModel *pages = gtk_stack_get_pages(GTK_STACK(stack));
+    GListModel *list = G_LIST_MODEL(pages);
+    GtkStackPage *page = g_list_model_get_item(list, index);
+    if(page) {
+        gtk_stack_set_visible_child(GTK_STACK(stack), gtk_stack_page_get_child(page));
+    } else {
+        fprintf(stderr, "UI Error: ui_stack_set value out of bounds\n");
+        return -1;
+    }
+    return index;
+}
+
+void ui_stack_tab_select(UIWIDGET tabview, int tab) {
+    stack_set_page(tabview, tab);
+}
+
+void ui_stack_tab_remove(UIWIDGET tabview, int tab) {
+    GtkStack *stack = GTK_STACK(tabview);
+    GtkWidget *current = gtk_stack_get_visible_child(stack);
+    GtkSelectionModel *pages = gtk_stack_get_pages(stack);
+    GListModel *list = G_LIST_MODEL(pages);
+    GtkStackPage *page = g_list_model_get_item(list, tab);
+    if(page) {
+        gtk_stack_remove(stack, gtk_stack_page_get_child(page));
+    }
+}
+
+void ui_stack_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) {
+    (void)gtk_stack_add_titled(GTK_STACK(widget), child, name, name);
+}
+
+int64_t ui_stack_get(UiInteger *i) {
+    GtkStack *stack = GTK_STACK(i->obj);
+    GtkWidget *current = gtk_stack_get_visible_child(stack);
+    GtkSelectionModel *pages = gtk_stack_get_pages(stack);
+    GListModel *list = G_LIST_MODEL(pages);
+    int nitems = g_list_model_get_n_items(list);
+    for(int p=0;p<nitems;p++) {
+        GtkStackPage *page = g_list_model_get_item(list, p);
+        GtkWidget *child = gtk_stack_page_get_child(page);
+        if(child == current) {
+            i->value = p;
+            break;
+        }
+    }
+    return i->value;
+}
+
+void ui_stack_set(UiInteger *i, int64_t value) {
+    GtkWidget *widget = i->obj;
+    if(stack_set_page(widget, value) >= 0) {
+        i->value = value;
+    }
+}
+#elif GTK_MAJOR_VERSION >= 3
+static GtkWidget* stack_get_child(GtkWidget *stack, int index) {
+    GList *children = gtk_container_get_children(GTK_CONTAINER(stack));
+    if(children) {
+        return g_list_nth_data(children, index);
+    }
+    return NULL;
+}
+
+void ui_stack_tab_select(UIWIDGET tabview, int tab) {
+    GtkWidget *child = stack_get_child(tabview, tab);
+    if(child) {
+        gtk_stack_set_visible_child(GTK_STACK(tabview), child);
+    }
+}
+
+void ui_stack_tab_remove(UIWIDGET tabview, int tab) {
+    GtkWidget *child = stack_get_child(tabview, tab);
+    if(child) {
+        gtk_container_remove(GTK_CONTAINER(tabview), child);
+    }
+}
+
+void ui_stack_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) {
+    gtk_stack_add_titled(GTK_STACK(widget), child, name, name);
+}
+
+int64_t ui_stack_get(UiInteger *i) {
+    GtkWidget *visible = gtk_stack_get_visible_child(GTK_STACK(i->obj));
+    GList *children = gtk_container_get_children(GTK_CONTAINER(i->obj));
+    GList *elm = children;
+    int n = 0;
+    int64_t v = -1;
+    while(elm) {
+        GtkWidget *child = elm->data;
+        if(child == visible) {
+            v = n;
+            break;
+        }
+        
+        elm = elm->next;
+        n++;
+    }
+    g_list_free(children);
+    i->value = v;
+    return v;
+}
+
+void ui_stack_set(UiInteger *i, int64_t value) {
+    GtkWidget *child = stack_get_child(i->obj, value);
+    if(child) {
+        gtk_stack_set_visible_child(GTK_STACK(i->obj), child);
+        i->value = value;
+    }
+}
+
+#endif
+
+
+
+
+UiGtkTabView* ui_widget_get_tabview_data(UIWIDGET tabview) {
+    return g_object_get_data(G_OBJECT(tabview), "ui_tabview");
+}
+
+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) {
+    UiGtkTabView *data = malloc(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) {
+        case UI_TABVIEW_DOC: {
+            // TODO
+            break;
+        }
+        case UI_TABVIEW_NAVIGATION_SIDE: {
+#if GTK_CHECK_VERSION(3, 10, 0)
+            widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+            GtkWidget *sidebar = gtk_stack_sidebar_new();
+            BOX_ADD(widget, sidebar);
+            GtkWidget *stack = gtk_stack_new();
+            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);
+            data->select_tab = ui_stack_tab_select;
+            data->remove_tab = ui_stack_tab_remove;
+            data->add_tab = ui_stack_tab_add;
+            getfunc = ui_stack_get;
+            setfunc = ui_stack_set;
+            data_widget = stack;
+#else
+            // TODO
+#endif
+            break;
+        }
+        case UI_TABVIEW_DEFAULT: /* fall through */
+        case UI_TABVIEW_NAVIGATION_TOP: /* fall through */
+        case UI_TABVIEW_INVISIBLE: /* fall through */
+        case UI_TABVIEW_NAVIGATION_TOP2: {
+            widget = gtk_notebook_new();
+            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) {
+                gtk_notebook_set_show_tabs(GTK_NOTEBOOK(widget), FALSE);
+                gtk_notebook_set_show_border(GTK_NOTEBOOK(widget), FALSE);
+            }
+            break;
+        }
+    }
+    
+    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);
+        UiInteger *i = var->value;
+        i->get = getfunc;
+        i->set = setfunc;
+        i->obj = data_widget;
+    }
+    
+    g_object_set_data(G_OBJECT(widget), "ui_tabview", data);
+    data->widget = data_widget;
+    data->subcontainer = args.subcontainer;
+    
+    UI_APPLY_LAYOUT1(current, args);
+    current->container->add(current->container, widget, TRUE);
+    
+    UiObject *newobj = uic_object_new(obj, widget);
+    newobj->container = ui_tabview_container(obj, widget);
+    uic_obj_add(obj, newobj);
+    data->obj = newobj;
+    
+    return widget;
+}
+
+void ui_tab_create(UiObject* obj, const char* title) {
+    UiObject* current = uic_current_obj(obj);
+    UiGtkTabView *data = ui_widget_get_tabview_data(current->widget);
+    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;
+}
+
+
+
+void ui_tabview_select(UIWIDGET tabview, int tab) {
+    UiGtkTabView *data = ui_widget_get_tabview_data(tabview);
+    if(!data) {
+        fprintf(stderr, "UI Error: widget is not a tabview\n");
+        return;
+    }
+    data->select_tab(tabview, tab);
+}
+
+void ui_tabview_remove(UIWIDGET tabview, int tab) {
+    UiGtkTabView *data = ui_widget_get_tabview_data(tabview);
+    if(!data) {
+        fprintf(stderr, "UI Error: widget is not a tabview\n");
+        return;
+    }
+    data->remove_tab(tabview, tab);
+}
+
+UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index) {
+    UiGtkTabView *data = ui_widget_get_tabview_data(tabview);
+    if(!data) {
+        fprintf(stderr, "UI Error: widget is not a tabview\n");
+        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 = create_grid(data->columnspacing, data->rowspacing);
+            newobj->container = ui_grid_container(newobj, sub);
+            break;
+        }
+    }
+    newobj->widget = sub;
+    GtkWidget *widget = box_set_margin(sub, data->margin);
+    
+    data->add_tab(data->widget, tab_index, name, widget);
+    
+    return newobj;
+}
+
+
+/* -------------------- Headerbar -------------------- */
+
+static void hb_set_part(UiObject *obj, int part) {
+    UiObject* current = uic_current_obj(obj);
+    GtkWidget *headerbar = current->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);
+    
+    hb->part = part;
+}
+
+void ui_headerbar_start_create(UiObject *obj) {
+    hb_set_part(obj, 0);
+}
+
+void ui_headerbar_center_create(UiObject *obj) {
+    hb_set_part(obj, 2);
+}
+
+void ui_headerbar_end_create(UiObject *obj) {
+    hb_set_part(obj, 1);
+}
+
+UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs args) {
+    UiObject *current = uic_current_obj(obj);
+    UiContainer *ct = current->container;
+    UI_APPLY_LAYOUT1(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);
+    
+    UiObject *newobj = uic_object_new(obj, box);
+    newobj->container = ui_headerbar_fallback_container(obj, box);
+    uic_obj_add(obj, newobj);
+    
+    return box;
+}
+
+static void hb_fallback_set_part(UiObject *obj, int part) {
+    UiObject* current = uic_current_obj(obj);
+    GtkWidget *headerbar = current->widget;
+    
+    UiObject *newobj = uic_object_new(obj, headerbar);
+    newobj->container = ui_headerbar_container(obj, headerbar);
+    uic_obj_add(obj, newobj);
+    
+    UiHeaderbarContainer *hb = (UiHeaderbarContainer*)newobj->container;
+    hb->part = part;
+}
+
+UiContainer* 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;
+}
+
+void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+    UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
+    BOX_ADD(ct->widget, widget);
+}
+
+#if GTK_CHECK_VERSION(3, 10, 0)
+
+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);
+    
+    return headerbar;    
+}
+
+UiContainer* 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;
+}
+
+void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
+    UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
+    if(hb->part == 0) {
+        UI_HEADERBAR_PACK_START(ct->widget, widget);
+    } else if(hb->part == 1) {
+        UI_HEADERBAR_PACK_END(ct->widget, widget);
+    } else if(hb->part == 2) {
+        if(!hb->centerbox) {
+            GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
+            hb->centerbox = box;
+            UI_HEADERBAR_SET_TITLE_WIDGET(ct->widget, box);
+        }
+        BOX_ADD(hb->centerbox, widget);
+    }
+}
+
+#else
+
+UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) {
+    return ui_headerbar_fallback_create(obj, args);  
+}
+
+#endif
+
 /* -------------------- Splitpane -------------------- */
 
 static GtkWidget* create_paned(UiOrientation orientation) {

mercurial