ui/motif/container.c

changeset 102
64ded9f6a6c6
parent 101
7b3a3130be44
--- a/ui/motif/container.c	Mon Jan 06 22:22:55 2025 +0100
+++ b/ui/motif/container.c	Tue Feb 25 21:11:00 2025 +0100
@@ -34,8 +34,26 @@
 #include "../common/context.h"
 #include "../common/object.h"
 
+#include <cx/array_list.h>
+
 #include "Grid.h"
 
+
+UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs args) {
+    Arg xargs[64];
+    int n = 0;
+    
+    UiContainerPrivate *ctn = ui_obj_container(obj);
+    UI_APPLY_LAYOUT(ctn->layout, args);
+    
+    Widget parent = ctn->prepare(ctn, xargs, &n);
+    Widget widget = create_widget(obj, args, userdata, parent, xargs, n);
+    XtManageChild(widget);
+    ctn->add(ctn, widget);
+    
+    return widget;
+}
+
 /* ---------------------------- Box Container ---------------------------- */
 
 static UIWIDGET box_create(UiObject *obj, UiContainerArgs args, UiBoxOrientation orientation) { 
@@ -203,6 +221,344 @@
 }
 
 
+/* -------------------------- TabView Container -------------------------- */
+
+static void ui_tabbar_resize(Widget widget, XtPointer udata, XtPointer cdata) {
+    UiMotifTabView *tabview = udata;
+    
+    if(tabview->tabview == UI_TABVIEW_INVISIBLE) {
+        return;
+    }
+    
+    int width = 0;
+    int height = 0;
+    XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, NULL);
+    int numbuttons = cxListSize(tabview->tabs);
+    if(numbuttons == 0) {
+        return;
+    }
+    int button_width = width / numbuttons;
+    int x = 0;
+    
+    CxIterator i = cxListIterator(tabview->tabs);
+    cx_foreach(UiTab *, tab, i) {
+        if(i.index + 1 == numbuttons) {
+            button_width = width - x;
+        }
+        XtVaSetValues(
+                tab->tab_button,
+                XmNx, x,
+                XmNy, 0,
+                XmNwidth,
+                button_width,
+                
+                NULL);
+        x += button_width;
+    }
+    
+    if(height <= tabview->height) {
+        XtVaSetValues(widget, XmNheight, tabview->height + 4, NULL);
+    }
+}
+
+static void ui_tabbar_expose(Widget widget, XtPointer udata, XtPointer cdata) {
+    UiMotifTabView *tabview = udata;
+    XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct *)cdata;
+    XEvent *event = cbs->event;
+    Display *dpy = XtDisplay(widget); 
+    
+    if(!tabview->gc_initialized) {
+        XGCValues gcvals;
+        gcvals.foreground = tabview->fg1;
+        tabview->gc = XCreateGC(XtDisplay(tabview->tabbar), XtWindow(tabview->tabbar), (GCForeground), &gcvals);
+    }
+    
+    if(tabview->current_tab) {
+        Widget tab = tabview->current_tab->tab_button;
+        XFillRectangle(dpy, XtWindow(widget), tabview->gc, tab->core.x, tab->core.height, tab->core.width, 4);
+    }
+}
+
+UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs args) {
+    Arg xargs[16];
+    int n = 0;
+    
+    UiContainerPrivate *ctn = ui_obj_container(obj);
+    UI_APPLY_LAYOUT(ctn->layout, args);
+    
+    // create widgets
+    // form
+    // - tabbar  (Drawing Area)
+    // - content (Frame)
+    UiMotifTabView *tabview = malloc(sizeof(UiMotifTabView));
+    memset(tabview, 0, sizeof(UiMotifTabView));
+    char *name = args.name ? (char*)args.name : "tabview";
+    XtSetArg(xargs[n], XmNuserData, tabview); n++;
+    Widget parent = ctn->prepare(ctn, xargs, &n);
+    Widget form = XmCreateForm(parent, name, xargs, n);
+    XtManageChild(form);
+    
+    n = 0;
+    XtSetArg(xargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
+    XtSetArg(xargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
+    XtSetArg(xargs[n], XmNtopAttachment, XmATTACH_FORM); n++;
+    XtSetArg(xargs[n], XmNorientation, XmHORIZONTAL); n++;
+    XtSetArg(xargs[n], XmNpacking, XmPACK_TIGHT); n++;
+    XtSetArg(xargs[n], XmNspacing, 1); n++;
+    XtSetArg(xargs[n], XmNmarginWidth, 0); n++;
+    XtSetArg(xargs[n], XmNmarginHeight, 0); n++;
+    Widget tabbar = XmCreateDrawingArea(form, "ui_test", xargs, n);
+    XtManageChild(tabbar);
+    XtAddCallback(tabbar, XmNresizeCallback , ui_tabbar_resize, tabview);
+    XtAddCallback(tabbar, XmNexposeCallback, ui_tabbar_expose, tabview);
+    
+    n = 0;
+    XtSetArg(xargs[n], XmNleftAttachment, XmATTACH_FORM); n++;
+    XtSetArg(xargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
+    XtSetArg(xargs[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+    XtSetArg(xargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
+    XtSetArg(xargs[n], XmNtopWidget, tabbar); n++;
+    Widget content = XmCreateFrame(form, "tabviewcontent", xargs, n);
+    
+    // setup tabview object, that holds all relevant objects
+    tabview->obj = obj;
+    tabview->form = form;
+    tabview->tabbar = tabbar;
+    tabview->content = content;
+    tabview->tabview = args.tabview;
+    tabview->subcontainer = args.subcontainer;
+    tabview->select = ui_motif_tabview_select;
+    tabview->add = ui_motif_tabview_add_tab;
+    tabview->remove = ui_motif_tabview_remove;
+    tabview->tabs = cxArrayListCreate(obj->ctx->allocator, cx_cmp_ptr, sizeof(UiTab), 8);
+    tabview->current_index = -1;
+    
+    UiTabViewContainer *ct = ui_malloc(obj->ctx, sizeof(UiTabViewContainer));
+    ct->container.widget = form;
+    ct->container.type = UI_CONTAINER_TABVIEW;
+    ct->container.prepare = ui_tabview_container_prepare;
+    ct->container.add = ui_tabview_container_add;
+    ct->tabview = tabview;
+    
+    UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER);
+    if(var) {
+        UiInteger *i = var->value;
+        i->obj = tabview;
+        i->get = ui_tabview_get;
+        i->set = ui_tabview_set;
+    }
+    
+    uic_object_push_container(obj, (UiContainerX*)ct);
+    
+    return form;
+}
+
+int64_t ui_tabview_get(UiInteger *i) {
+    UiMotifTabView *tabview = i->obj;
+    i->value = tabview->current_index;
+    return i->value;
+}
+
+void ui_tabview_set(UiInteger *i, int64_t value) {
+    UiMotifTabView *tabview = i->obj;
+    if(value < cxListSize(tabview->tabs)) {
+        ui_motif_tabview_select(tabview, value);
+        i->value = value;
+    }
+}
+
+void ui_tab_create(UiObject *obj, const char* title) {
+    UiContainerPrivate *ctn = ui_obj_container(obj);
+    if(ctn->type != UI_CONTAINER_TABVIEW) {
+        fprintf(stderr, "UI Error: container is not a tabview\n");
+        return;
+    }
+    
+    UiMotifTabView *tabview = NULL;
+    XtVaGetValues(ctn->widget, XmNuserData, &tabview, NULL);
+    if(!tabview) {
+        fprintf(stderr, "UI Error: no tabview\n");
+        return;
+    }
+    
+    
+    Widget child = ui_vbox_create(obj, (UiContainerArgs) { 0 });
+    if(tabview->current) {
+        XtUnmanageChild(child);
+    } else {
+        tabview->current = child;
+    }
+    
+    tabview->add(tabview, -1, title, child);
+}
+
+void ui_tabview_select(UIWIDGET tabview, int tab) {
+    UiMotifTabView *tabviewdata = NULL;
+    XtVaGetValues(tabview, XmNuserData, &tabviewdata, NULL);
+    if(tabviewdata) {
+        ui_motif_tabview_select(tabviewdata, tab);
+    } else {
+        fprintf(stderr, "ui_tabview_select: widget is not a tabview\n");
+    }
+}
+
+void ui_tabview_remove(UIWIDGET tabview, int tab) {
+    UiMotifTabView *tabviewdata = NULL;
+    XtVaGetValues(tabview, XmNuserData, &tabviewdata, NULL);
+    if(tabviewdata) {
+        ui_motif_tabview_remove(tabviewdata, tab);
+    } else {
+        fprintf(stderr, "ui_tabview_select: widget is not a tabview\n");
+    }
+}
+
+UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index) {
+    UiMotifTabView *tabviewdata = NULL;
+    XtVaGetValues(tabview, XmNuserData, &tabviewdata, NULL);
+    if(tabviewdata) {
+        Arg args[16];
+        int n = 0;
+        
+        XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+        XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
+        XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+        XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
+        XtSetArg(args[n], XmNtopWidget, tabviewdata->tabbar); n++;
+        
+        Widget grid = XtCreateManagedWidget("vbox", gridClass, tabviewdata->content, args, n);
+        
+        UiObject *newobj = ui_calloc(tabviewdata->obj->ctx, 1, sizeof(UiObject));
+        newobj->ctx = tabviewdata->obj->ctx;
+        newobj->widget = grid;
+        UiContainerX *container = ui_box_container(newobj, grid, UI_BOX_VERTICAL);
+        newobj->container_begin = container;
+        newobj->container_end = container;
+        return newobj;
+    } else {
+        fprintf(stderr, "ui_tabview_select: widget is not a tabview\n");
+        return NULL;
+    }
+}
+
+void ui_motif_tabview_select(UiMotifTabView *tabview, int tab) {
+    UiTab *t = cxListAt(tabview->tabs, tab);
+    if(t) {
+        tabview->current_index = tab;
+        ui_motif_tabview_change_tab(tabview, t);
+    }
+}
+
+static void ui_tab_button_callback(Widget widget, UiTab *tab, XtPointer d) {
+    UiMotifTabView *tabview = NULL;
+    XtVaGetValues(widget, XmNuserData, &tabview, NULL);
+    ui_motif_tabview_change_tab(tabview, tab);
+}
+
+void ui_motif_tabview_add_tab(UiMotifTabView *tabview, int index, const char *name, Widget child) {
+    UiTab tab;
+    
+    Arg args[16];
+    int n = 0;
+    
+    XmString label = XmStringCreateLocalized((char*)name);
+    XtSetArg(args[n], XmNlabelString, label); n++;
+    XtSetArg(args[n], XmNshadowThickness, 0); n++;
+    XtSetArg(args[n], XmNhighlightThickness, 0); n++;
+    XtSetArg(args[n], XmNuserData, tabview); n++;
+    
+    Widget button = XmCreatePushButton(tabview->tabbar, "tab_button", args, n);
+    if(tabview->tabview != UI_TABVIEW_INVISIBLE) {
+        XtManageChild(button);
+    }
+    
+    if(tabview->height == 0) {
+        Dimension h;
+        XtVaGetValues(
+                button,
+                XmNarmColor,
+                &tabview->bg1,
+                XmNbackground,
+                &tabview->bg2,
+                XmNhighlightColor,
+                &tabview->fg1,
+                XmNheight,
+                &h,
+                NULL);
+        tabview->height = h + 2; // border
+        
+        XtVaSetValues(tabview->tabbar, XmNbackground, tabview->bg1, NULL);
+    }
+    
+    tab.tab_button = button;
+    tab.child = child;
+    size_t newtab_index = cxListSize(tabview->tabs);
+    cxListAdd(tabview->tabs, &tab);
+    UiTab *newtab = cxListAt(tabview->tabs, newtab_index);
+    
+    XtAddCallback(
+            button,
+            XmNactivateCallback,
+            (XtCallbackProc)ui_tab_button_callback,
+            newtab);
+    
+    if(newtab_index == 0) {
+        ui_motif_tabview_change_tab(tabview, newtab);
+    } else {
+        XtVaSetValues(button, XmNbackground, tabview->bg1, NULL);
+    }
+}
+
+void ui_motif_tabview_remove(UiMotifTabView *tabview, int index) {
+    UiTab *tab = cxListAt(tabview->tabs, index);
+    if(tab) {
+        if(tab == tabview->current_tab) {
+            if(index > 0) {
+                ui_motif_tabview_select(tabview, index-1);
+            } else {
+                if(index < cxListSize(tabview->tabs)) {
+                    ui_motif_tabview_select(tabview, index+1);
+                } else {
+                    tabview->current_tab = NULL;
+                    tabview->current_index = -1;
+                }
+            }
+        }
+        XtDestroyWidget(tab->tab_button);
+        XtDestroyWidget(tab->child);
+        cxListRemove(tabview->tabs, index);
+    }
+}
+
+void ui_motif_tabview_change_tab(UiMotifTabView *tabview, UiTab *tab) {
+    if(tabview->current_tab) {
+        XtVaSetValues(tabview->current_tab->tab_button, XmNshadowThickness, 0, XmNbackground, tabview->bg1, NULL);
+        XtUnmanageChild(tabview->current_tab->child);
+    }
+    XtVaSetValues(tab->tab_button, XmNshadowThickness, 1, XmNbackground, tabview->bg2, NULL);
+    tabview->current_tab = tab;
+    tabview->current_index = (int)cxListFind(tabview->tabs, tab);;
+    XtManageChild(tab->child);
+}
+
+Widget ui_tabview_container_prepare(UiContainerPrivate *ctn, Arg *args, int *n) {
+    UiTabViewContainer *ct = (UiTabViewContainer*)ctn;
+    UiMotifTabView *tabview = ct->tabview;
+    int a = *n;
+    XtSetArg(args[a], XmNleftAttachment, XmATTACH_FORM); a++;
+    XtSetArg(args[a], XmNrightAttachment, XmATTACH_FORM); a++;
+    XtSetArg(args[a], XmNbottomAttachment, XmATTACH_FORM); a++;
+    XtSetArg(args[a], XmNtopAttachment, XmATTACH_WIDGET); a++;
+    XtSetArg(args[a], XmNtopWidget, tabview->tabbar); a++;
+    *n = a;
+    return tabview->form;
+}
+
+void ui_tabview_container_add(UiContainerPrivate *ctn, Widget widget) {
+    ui_reset_layout(ctn->layout);
+}
+
+
+
 /* -------------------- Container Helper Functions -------------------- */
 
 void ui_container_begin_close(UiObject *obj) {

mercurial