ui/motif/container.c

changeset 100
d2bd73d28ff1
parent 29
3fc287f06305
--- a/ui/motif/container.c	Fri Nov 29 22:21:36 2024 +0100
+++ b/ui/motif/container.c	Thu Dec 12 20:01:43 2024 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2014 Olaf Wintermann. All rights reserved.
+ * Copyright 2024 Olaf Wintermann. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -34,751 +34,189 @@
 #include "../common/context.h"
 #include "../common/object.h"
 
-#include <cx/array_list.h>
-#include <cx/linked_list.h>
-#include <cx/compare.h>
-
-#define UI_GRID_MAX_COLUMNS 512
-
-static UiBool ui_lb2bool(UiLayoutBool b) {
-    return b == UI_LAYOUT_TRUE ? TRUE : FALSE;
-}
-
-static UiLayoutBool ui_bool2lb(UiBool b) {
-    return b ? UI_LAYOUT_TRUE : UI_LAYOUT_FALSE;
-}
-
+#include "Grid.h"
 
-UiContainer* ui_frame_container(UiObject *obj, Widget frame) {
-    UiContainer *ct = cxCalloc(
-            obj->ctx->allocator,
-            1,
-            sizeof(UiContainer));
-    ct->widget = frame;
-    ct->prepare = ui_frame_container_prepare;
-    ct->add = ui_frame_container_add;
-    return ct;
-}
-
-Widget ui_frame_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) {
-    return ct->widget;
-}
-
-void ui_frame_container_add(UiContainer *ct, Widget widget) {
-    ui_reset_layout(ct->layout);
-    ct->current = widget;
-}
-
+/* ---------------------------- Box Container ---------------------------- */
 
-UiContainer* ui_box_container(UiObject *obj, Widget box, int margin, int spacing, UiBoxOrientation orientation) {
-    UiBoxContainer *ct = cxCalloc(
-            obj->ctx->allocator,
-            1,
-            sizeof(UiBoxContainer));
-    ct->container.widget = box;
-    ct->container.prepare = ui_box_container_prepare;
-    ct->container.add = ui_box_container_add;
-    ct->orientation = orientation;
-    ct->margin = margin;
-    ct->spacing = spacing;
-    return (UiContainer*)ct;
-}
-
-Widget ui_box_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) {
-    UiBoxContainer *bc = (UiBoxContainer*)ct;
-    if(ct->layout.fill != UI_LAYOUT_UNDEFINED) {
-        fill = ui_lb2bool(ct->layout.fill);
-    }
+static UIWIDGET box_create(UiObject *obj, UiContainerArgs args, UiBoxOrientation orientation) { 
+    UiContainerPrivate *ctn = ui_obj_container(obj);
+    UI_APPLY_LAYOUT(ctn->layout, args);
     
-    if(bc->has_fill && fill) {
-        fprintf(stderr, "UiError: container has 2 filled widgets");
-        fill = FALSE;
-    }
-    if(fill) {
-        bc->has_fill = TRUE;
-    }
+    Arg xargs[16];
+    int n = 0;
     
-    int a = *n;
-    // determine fixed and dynamic attachments
-    void *f1;
-    void *f2;
-    void *d1;
-    void *d2;
-    void *w1;
-    void *w2;
-    if(bc->orientation == UI_BOX_VERTICAL) {
-        f1 = XmNleftAttachment;
-        f2 = XmNrightAttachment;
-        d1 = XmNtopAttachment;
-        d2 = XmNbottomAttachment;
-        w1 = XmNtopWidget;
-        w2 = XmNbottomWidget;
-        
-        // margin/spacing
-        XtSetArg(args[a], XmNleftOffset, bc->margin); a++;
-        XtSetArg(args[a], XmNrightOffset, bc->margin); a++;
-        
-        XtSetArg(args[a], XmNtopOffset, bc->prev_widget ? bc->spacing : bc->margin); a++;
+    if(orientation == UI_BOX_VERTICAL) {
+        //XtSetArg(xargs[n], gridRowSpacing, args.spacing); n++;
     } else {
-        f1 = XmNtopAttachment;
-        f2 = XmNbottomAttachment;
-        d1 = XmNleftAttachment;
-        d2 = XmNrightAttachment;
-        w1 = XmNleftWidget;
-        w2 = XmNrightWidget;
-        
-        // margin/spacing
-        XtSetArg(args[a], XmNtopOffset, bc->margin); a++;
-        XtSetArg(args[a], XmNbottomOffset, bc->margin); a++;
-        
-        XtSetArg(args[a], XmNleftOffset, bc->prev_widget ? bc->spacing : bc->margin); a++;
-    }
-    XtSetArg(args[a], f1, XmATTACH_FORM); a++;
-    XtSetArg(args[a], f2, XmATTACH_FORM); a++;
-
-    if(fill) {
-        XtSetArg(args[a], d2, XmATTACH_FORM); a++;
-    }
-    if(bc->prev_widget) {
-        XtSetArg(args[a], d1, XmATTACH_WIDGET); a++;
-        XtSetArg(args[a], w1, bc->prev_widget); a++;
-    } else {
-        XtSetArg(args[a], d1, XmATTACH_FORM); a++;
-    }
-    
-    *n = a;
-    return ct->widget;
-}
-
-void ui_box_container_add(UiContainer *ct, Widget widget) {
-    UiBoxContainer *bc = (UiBoxContainer*)ct;
-    // determine dynamic attachments
-    void *d1;
-    void *d2;
-    void *w1;
-    void *w2;
-    if(bc->orientation == UI_BOX_VERTICAL) {
-        d1 = XmNtopAttachment;
-        d2 = XmNbottomAttachment;
-        w1 = XmNtopWidget;
-        w2 = XmNbottomWidget;
-        
-    } else {
-        d1 = XmNleftAttachment;
-        d2 = XmNrightAttachment;
-        w1 = XmNleftWidget;
-        w2 = XmNrightWidget;
-    }
-    
-    if(bc->prev_widget) {
-        int v = 0;
-        XtVaGetValues(bc->prev_widget, d2, &v, NULL);
-        if(v == XmATTACH_FORM) {
-            XtVaSetValues(
-                    bc->prev_widget,
-                    d2,
-                    XmATTACH_WIDGET,
-                    w2,
-                    widget,
-                    NULL);
-            XtVaSetValues(
-                    widget,
-                    d1,
-                    XmATTACH_NONE,
-                    d2,
-                    XmATTACH_FORM,
-                    NULL);
-        }
-    }
-    bc->prev_widget = widget;
-    
-    ui_reset_layout(ct->layout);
-    ct->current = widget;
-}
-
-UiContainer* ui_grid_container(UiObject *obj, Widget form, int columnspacing, int rowspacing) {
-    UiGridContainer *ct = cxCalloc(
-            obj->ctx->allocator,
-            1,
-            sizeof(UiGridContainer));
-    ct->container.widget = form;
-    ct->container.prepare = ui_grid_container_prepare;
-    ct->container.add = ui_grid_container_add;
-    ct->columnspacing = columnspacing;
-    ct->rowspacing = rowspacing;
-    ct->lines = cxLinkedListCreateSimple(CX_STORE_POINTERS);
-    return (UiContainer*)ct;
-}
-
-void ui_grid_newline(UiGridContainer *grid) {
-    if(grid->current) {
-        grid->current = NULL;
-    }
-    grid->container.layout.newline = FALSE;
-}
-
-Widget ui_grid_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) {
-    UiGridContainer *grid = (UiGridContainer*)ct;
-    if(ct->layout.newline) {
-        ui_grid_newline(grid);
-    }
-    return ct->widget;
-}
-
-void ui_grid_container_add(UiContainer *ct, Widget widget) {
-    UiGridContainer *grid = (UiGridContainer*)ct;
-    
-    if(grid->current) {
-        cxListAdd(grid->current, widget);
-    } else {
-        grid->current = cxLinkedListCreateSimple(CX_STORE_POINTERS);
-        cxListAdd(grid->current, widget);
-        cxListAdd(grid->lines, grid->current);
+        //XtSetArg(xargs[n], gridColumnSpacing, args.spacing); n++;
     }
     
-    ui_reset_layout(ct->layout);
-    ct->current = widget;
-}
-
-static void ui_grid_resize(Widget widget, XtPointer udata, XtPointer cdata) {
-    UiGridContainer *grid = udata;
-    
-    CxList *rowdim = cxArrayListCreateSimple(sizeof(int), grid->lines->size);
-    int coldim[UI_GRID_MAX_COLUMNS];
-    memset(coldim, 0, UI_GRID_MAX_COLUMNS*sizeof(int));
-    int numcol = 0;
-    
-    // get the minimum size of the columns and rows
-    int sumw = 0;
-    int sumh = 0;
-    CxIterator lineIterator = cxListIterator(grid->lines);
-    cx_foreach(CxList *, row, lineIterator) {
-        int rheight = 0;
-        int i=0;
-        int sum_width = 0;
-        CxIterator colIterator = cxListIterator(row);
-        cx_foreach(Widget, w, colIterator) {
-            int widget_width = 0;
-            int widget_height = 0;
-            XtVaGetValues(
-                    w,
-                    XmNwidth,
-                    &widget_width,
-                    XmNheight,
-                    &widget_height, 
-                    NULL);
-            
-            // get the maximum height in this row
-            if(widget_height > rheight) {
-                rheight = widget_height;
-            }
-            
-            // get the maximum width in this column
-            if(widget_width > coldim[i]) {
-                coldim[i] = widget_width;
-            }
-            sum_width += widget_width;
-            if(sum_width > sumw) {
-                sumw = sum_width;
-            }
-            
-            i++;
-            if(i > numcol) {
-                numcol = i;
-            }
-        }
-        cxListAdd(rowdim, &rheight);
-        sumh += rheight;
-    }
-    
-    // check container size
-    int gwidth = 0;
-    int gheight = 0;
-    XtVaGetValues(widget, XmNwidth, &gwidth, XmNheight, &gheight, NULL);
-    if(gwidth < sumw || gheight < sumh) {
-        XtVaSetValues(widget, XmNwidth, sumw, XmNheight, sumh, NULL);
-        cxListDestroy(rowdim);
-        return;
-    }
-    
-    
-    // adjust the positions of all children
-    int y = 0;
-    lineIterator = cxListIterator(grid->lines);
-    cx_foreach(CxList *, row, lineIterator) {
-        int x = 0;       
-        int i=0;
-        int *rowheight = cxListAt(rowdim, lineIterator.index);
-        CxIterator colIterator = cxListIterator(row);
-        cx_foreach(Widget, w, colIterator) {
-            XtVaSetValues(
-                    w,
-                    XmNx, x,
-                    XmNy, y,
-                    XmNwidth, coldim[i],
-                    XmNheight, *rowheight,
-                    NULL);
-            
-            x += coldim[i];
-            i++;
-        }
-        y += *rowheight;
-    }
+    Widget parent = ctn->prepare(ctn, xargs, &n);
+    Widget grid = XtCreateManagedWidget(args.name ? args.name : "boxcontainer", gridClass, parent, xargs, n);
+    ctn->add(ctn, grid);
     
-    cxListDestroy(rowdim);
-}
-
-UiContainer* ui_scrolledwindow_container(UiObject *obj, Widget scrolledwindow) {
-    UiContainer *ct = cxCalloc(
-            obj->ctx->allocator,
-            1,
-            sizeof(UiContainer));
-    ct->widget = scrolledwindow;
-    ct->prepare = ui_scrolledwindow_container_prepare;
-    ct->add = ui_scrolledwindow_container_add;
-    return ct;
-}
-
-Widget ui_scrolledwindow_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) {
-    return ct->widget;
-}
-
-void ui_scrolledwindow_container_add(UiContainer *ct, Widget widget) {
-    ui_reset_layout(ct->layout);
-    ct->current = widget;
-}
-
-
-UiContainer* ui_tabview_container(UiObject *obj, Widget frame) {
-    UiTabViewContainer *ct = cxCalloc(
-            obj->ctx->allocator,
-            1,
-            sizeof(UiTabViewContainer));
-    ct->context = obj->ctx;
-    ct->container.widget = frame;
-    ct->container.prepare = ui_tabview_container_prepare;
-    ct->container.add = ui_tabview_container_add;
-    ct->tabs = cxArrayListCreate(cxDefaultAllocator, cx_cmp_uintptr, CX_STORE_POINTERS, 16);
-    return (UiContainer*)ct;
-}
-
-Widget ui_tabview_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) {
-    int a = *n;
-    XtSetArg(args[a], XmNleftAttachment, XmATTACH_FORM); a++;
-    XtSetArg(args[a], XmNrightAttachment, XmATTACH_FORM); a++;
-    XtSetArg(args[a], XmNtopAttachment, XmATTACH_FORM); a++;
-    XtSetArg(args[a], XmNbottomAttachment, XmATTACH_FORM); a++;
-    *n = a;
-    return ct->widget;
-}
-
-void ui_tabview_container_add(UiContainer *ct, Widget widget) {
-    UiTabViewContainer *tabview = (UiTabViewContainer*)ct; 
-    
-    if(tabview->current) {
-        XtUnmanageChild(tabview->current);
-    }
-
-    tabview->current = widget;
-    cxListAdd(tabview->tabs, widget);
-    
-    ui_select_tab(ct->widget, 0);
-    ui_reset_layout(ct->layout);
-    ct->current = widget;
-}
-
-UIWIDGET ui_box(UiObject *obj, int margin, int spacing, UiBoxOrientation orientation) {
-    UiContainer *ct = uic_get_current_container(obj);
-    
-    Arg args[16];
-    int n = 0;
-    Widget parent = ct->prepare(ct, args, &n, TRUE);
-    Widget form = XmCreateForm(parent, "vbox", args, n);
-    ct->add(ct, form);
-    XtManageChild(form);
-    
-    UiObject *newobj = uic_object_new(obj, form);
-    newobj->container = ui_box_container(obj, form, margin, spacing, orientation);
-    uic_obj_add(obj, newobj);
-    
-    return form;
-}
-
-UIWIDGET ui_vbox(UiObject *obj) {
-    return ui_box(obj, 0, 0, UI_BOX_VERTICAL);
-}
-
-UIWIDGET ui_hbox(UiObject *obj) {
-    return ui_box(obj, 0, 0, UI_BOX_HORIZONTAL);
-}
-
-UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing) {
-    return ui_box(obj, margin, spacing, UI_BOX_VERTICAL);
-}
-
-UIWIDGET ui_hbox_sp(UiObject *obj, int margin, int spacing) {
-    return ui_box(obj, margin, spacing, UI_BOX_HORIZONTAL);
-}
-
-UIWIDGET ui_grid(UiObject *obj) {
-    return ui_grid_sp(obj, 0, 0, 0);
-}
-
-UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing) {
-    UiContainer *ct = uic_get_current_container(obj);
-    
-    Arg args[16];
-    int n = 0;
-    Widget parent = ct->prepare(ct, args, &n, TRUE);
-    Widget grid = XmCreateDrawingArea(parent, "grid", args, n);
-    ct->add(ct, grid);
-    XtManageChild(grid);
-    
-    UiObject *newobj = uic_object_new(obj, grid);
-    newobj->container = ui_grid_container(obj, grid, columnspacing, rowspacing);
-    uic_obj_add(obj, newobj);
-    
-    XtAddCallback (grid, XmNresizeCallback , ui_grid_resize, newobj->container);
+    UiContainerX *container = ui_box_container(obj, grid, orientation);
+    uic_object_push_container(obj, container);
     
     return grid;
 }
 
-UIWIDGET ui_scrolledwindow(UiObject *obj) {
-    UiContainer *ct = uic_get_current_container(obj);
-    
-    Arg args[16];
-    int n = 0;
-    XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); // TODO: dosn't work, use XmAPPLICATION_DEFINED
-    n++;
-    Widget parent = ct->prepare(ct, args, &n, TRUE);
-    Widget scrolledwindow = XmCreateScrolledWindow(parent, "scrolledwindow", args, n);
-    ct->add(ct, scrolledwindow);
-    XtManageChild(scrolledwindow);
-    
-    UiObject *newobj = uic_object_new(obj, scrolledwindow);
-    newobj->container = ui_scrolledwindow_container(obj, scrolledwindow);
-    uic_obj_add(obj, newobj);
-    
-    return scrolledwindow;
+// public
+UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) {
+    return box_create(obj, args, UI_BOX_VERTICAL);
+}
+
+// public
+UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) {
+    return box_create(obj, args, UI_BOX_HORIZONTAL);
 }
 
-UIWIDGET ui_sidebar(UiObject *obj) {
-    UiContainer *ct = uic_get_current_container(obj);
-    
-    Arg args[16];
-    int n = 0;
-    
-    XtSetArg(args[n], XmNorientation, XmHORIZONTAL);
-    n++;
-    
-    Widget parent = ct->prepare(ct, args, &n, TRUE);
-    Widget pane = XmCreatePanedWindow(parent, "pane", args, n);
-    ct->add(ct, pane);
-    XtManageChild(pane);
-    
-    // add sidebar widget
-    Widget sidebar = XmCreateForm(pane, "sidebar", args, 0);
-    XtManageChild(sidebar);
-    
-    UiObject *left = uic_object_new(obj, sidebar);
-    left->container = ui_box_container(left, sidebar, 0, 0, UI_BOX_VERTICAL);
-    
-    // add content widget
-    XtSetArg (args[0], XmNpaneMaximum, 8000);
-    Widget content = XmCreateForm(pane, "content_area", args, 1);
-    XtManageChild(content);
-    
-    UiObject *right = uic_object_new(obj, content);
-    right->container = ui_box_container(right, content, 0, 0, UI_BOX_VERTICAL);
-    
-    uic_obj_add(obj, right);
-    uic_obj_add(obj, left);
-    
-    return sidebar;
+UiContainerX* ui_box_container(UiObject *obj, Widget grid, UiBoxOrientation orientation) {
+    UiBoxContainer *ctn = ui_malloc(obj->ctx, sizeof(UiBoxContainer));
+    memset(ctn, 0, sizeof(UiBoxContainer));
+    ctn->container.prepare = orientation == UI_BOX_VERTICAL ? ui_vbox_prepare : ui_hbox_prepare;
+    ctn->container.add = ui_box_container_add;
+    ctn->container.widget = grid;
+    ctn->n = 0;
+    return (UiContainerX*)ctn;
 }
 
-UIWIDGET ui_tabview(UiObject *obj) {
-    UiContainer *ct = uic_get_current_container(obj);
-    
-    // create a simple frame as container widget
-    // when tabs are selected, the current child will be replaced by the
-    // the new tab widget
-    Arg args[16];
-    int n = 0;
-    XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_OUT);
-    n++;
-    XtSetArg(args[n], XmNshadowThickness, 0);
-    n++;
-    Widget parent = ct->prepare(ct, args, &n, TRUE);
-    Widget form = XmCreateForm(parent, "tabview", args, n);
-    ct->add(ct, form);
-    XtManageChild(form);
-    
-    UiObject *tabviewobj = uic_object_new(obj, form);
-    tabviewobj->container = ui_tabview_container(obj, form);
-    uic_obj_add(obj, tabviewobj);
-    
-    XtVaSetValues(form, XmNuserData, tabviewobj->container, NULL);
-    
-    return form;
+static Widget ui_box_container_prepare(UiBoxContainer *box, Arg *args, int *n) {
+    int a = *n;
+    box->n++;
+    return box->container.widget;
 }
 
-void ui_tab(UiObject *obj, char *title) {
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->layout.label = title;
-    
-    ui_vbox(obj);
-}
-
-void ui_select_tab(UIWIDGET tabview, int tab) {
-    UiTabViewContainer *ct = NULL;
-    XtVaGetValues(tabview, XmNuserData, &ct, NULL);
-    if(ct) {
-        XtUnmanageChild(ct->current);
-        Widget w = cxListAt(ct->tabs, tab);
-        if(w) {
-            XtManageChild(w);
-            ct->current = w;
-        } else {
-            fprintf(stderr, "UiError: front tab index: %d\n", tab);
-        }
-    } else {
-        fprintf(stderr, "UiError: widget is not a tabview\n");
+Widget ui_vbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n) {
+    UiBoxContainer *box = (UiBoxContainer*)ctn;
+    int a = *n;
+    XtSetArg(args[a], gridRow, box->n); a++;
+    if(box->container.layout.fill == UI_ON) {
+        XtSetArg(args[a], gridVExpand, TRUE); a++;
+        XtSetArg(args[a], gridVFill, TRUE); a++;
     }
+    XtSetArg(args[a], gridHExpand, TRUE); a++;
+    XtSetArg(args[a], gridHFill, TRUE); a++;
+    *n = a;
+    return ui_box_container_prepare(box, args, n);
 }
 
-
-/* document tabview */
-
-static void ui_tabbar_resize(Widget widget, XtPointer udata, XtPointer cdata) {
-    MotifTabbedPane *v = (MotifTabbedPane*)udata;
-    
-    int width = 0;
-    int height = 0;
-    XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, NULL);
-    int button_width = width / 4;
-    int x = 0;
-    CxIterator tabIterator = cxListIterator(v->tabs);
-    cx_foreach(UiTab*, tab, tabIterator) {
-        XtVaSetValues(
-                tab->tab_button,
-                XmNx, x,
-                XmNy, 0,
-                XmNwidth,
-                button_width,
-                
-                NULL);
-        x += button_width;
+Widget ui_hbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n) {
+    UiBoxContainer *box = (UiBoxContainer*)ctn;
+    int a = *n;
+    XtSetArg(args[a], gridColumn, box->n); a++;
+    if(box->container.layout.fill == UI_ON) {
+        XtSetArg(args[a], gridHExpand, TRUE); a++;
+        XtSetArg(args[a], gridHFill, TRUE); a++;
     }
-    
-    if(height <= v->height) {
-        XtVaSetValues(widget, XmNheight, v->height + 4, NULL);
-    }
+    XtSetArg(args[a], gridVExpand, TRUE); a++;
+    XtSetArg(args[a], gridVFill, TRUE); a++;
+    *n = a;
+    return ui_box_container_prepare(box, args, n);
 }
 
-static void ui_tabbar_expose(Widget widget, XtPointer udata, XtPointer cdata) {
-    MotifTabbedPane *v = (MotifTabbedPane*)udata;
-    XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct *)cdata;
-    XEvent *event = cbs->event;
-    Display *dpy = XtDisplay(widget); 
-    
-    XGCValues gcvals;
-    GC gc;
-    Pixel fgpix;
-    
-    int tab_x;
-    int tab_width;
-    XtVaGetValues(v->current->tab_button, XmNx, &tab_x, XmNwidth, &tab_width, XmNhighlightColor, &fgpix, NULL);
-    
-    gcvals.foreground = v->bg1;
-    gc = XCreateGC( dpy, XtWindow(widget), (GCForeground), &gcvals);
-      
-    int width = 0;
-    int height = 0;
-    XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, NULL);
-    XFillRectangle(dpy, XtWindow(widget), gc, 0, 0, width, height);
-    
-    gcvals.foreground = fgpix;
-    gc = XCreateGC( dpy, XtWindow(widget), (GCForeground), &gcvals);
-    
-    XFillRectangle(dpy, XtWindow(widget), gc, tab_x, 0, tab_width, height);
+void ui_box_container_add(UiContainerPrivate *ctn, Widget widget) {
+    ui_reset_layout(ctn->layout);
     
 }
 
-UiTabbedPane* ui_tabbed_document_view(UiObject *obj) {
+
+/* ---------------------------- Grid Container ---------------------------- */
+
+// public
+UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) {
+    Arg xargs[16];
     int n = 0;
-    Arg args[16];
-    
-    UiContainer *ct = uic_get_current_container(obj);
-    Widget parent = ct->prepare(ct, args, &n, TRUE);
-    
-    Widget tabview = XmCreateForm(parent, "tabview_form", args, n);
-    XtManageChild(tabview);
     
-    XtSetArg(args[0], XmNorientation, XmHORIZONTAL);
-    XtSetArg(args[1], XmNpacking, XmPACK_TIGHT);
-    XtSetArg(args[2], XmNspacing, 1);
-    XtSetArg(args[3], XmNleftAttachment, XmATTACH_FORM);
-    XtSetArg(args[4], XmNrightAttachment, XmATTACH_FORM);
-    XtSetArg(args[5], XmNtopAttachment, XmATTACH_FORM);
-    XtSetArg(args[6], XmNmarginWidth, 0);
-    XtSetArg(args[7], XmNmarginHeight, 0);
-    Widget tabbar = XmCreateDrawingArea(tabview, "tabbar", args, 8);
-    XtManageChild(tabbar);
+    XtSetArg(xargs[n], XmNbackground, 0); n++;
     
-    XtSetArg(args[0], XmNleftAttachment, XmATTACH_FORM);
-    XtSetArg(args[1], XmNrightAttachment, XmATTACH_FORM);
-    XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET);
-    XtSetArg(args[3], XmNtopWidget, tabbar);
-    XtSetArg(args[4], XmNbottomAttachment, XmATTACH_FORM);
-    XtSetArg(args[5], XmNshadowThickness, 0);
-    Widget tabct = XmCreateForm(tabview, "tabview", args, 6);
-    XtManageChild(tabct);
+    UiContainerPrivate *ctn = ui_obj_container(obj);
+    UI_APPLY_LAYOUT(ctn->layout, args);
     
-    MotifTabbedPane *tabbedpane = ui_malloc(obj->ctx, sizeof(MotifTabbedPane));
-    tabbedpane->view.ctx = uic_current_obj(obj)->ctx;
-    tabbedpane->view.widget = tabct;
-    tabbedpane->view.document = NULL;
-    tabbedpane->tabbar = tabbar;
-    tabbedpane->tabs = cxArrayListCreate(obj->ctx->allocator, cx_cmp_uintptr, CX_STORE_POINTERS, 16);
-    tabbedpane->current = NULL;
-    tabbedpane->height = 0;
+    Widget parent = ctn->prepare(ctn, xargs, &n);
+    Widget grid = XtCreateManagedWidget(args.name ? args.name : "gridcontainer", gridClass, parent, xargs, n);
+    ctn->add(ctn, grid);
     
-    XtAddCallback(tabbar, XmNresizeCallback , ui_tabbar_resize, tabbedpane);
-    XtAddCallback(tabbar, XmNexposeCallback, ui_tabbar_expose, tabbedpane);
+    UiContainerX *container = ui_grid_container(obj, grid);
+    uic_object_push_container(obj, container);
     
-    return &tabbedpane->view;
+    return grid;
 }
 
-UiObject* ui_document_tab(UiTabbedPane *view) {
-    MotifTabbedPane *v = (MotifTabbedPane*)view;
-    int n = 0;
-    Arg args[16];
-    
-    // hide the current tab content
-    if(v->current) {
-        XtUnmanageChild(v->current->content->widget);
+UiContainerX* ui_grid_container(UiObject *obj, Widget grid) {
+    UiGridContainer *ctn = ui_malloc(obj->ctx, sizeof(UiGridContainer));
+    memset(ctn, 0, sizeof(UiBoxContainer));
+    ctn->container.prepare = ui_grid_container_prepare;
+    ctn->container.add = ui_grid_container_add;
+    ctn->container.widget = grid;
+    ctn->x = 0;
+    ctn->y = 0;
+    return (UiContainerX*)ctn;
+}
+
+Widget ui_grid_container_prepare(UiContainerPrivate *ctn, Arg *args, int *n) {
+    UiGridContainer *grid = (UiGridContainer*)ctn;
+    if(ctn->layout.newline) {
+        grid->y++;
+        grid->x = 0;
     }
     
-    UiTab *tab = ui_malloc(view->ctx, sizeof(UiTab));
-    
-    // create the new tab content
-    XtSetArg(args[0], XmNshadowThickness, 0);
-    XtSetArg(args[1], XmNleftAttachment, XmATTACH_FORM);
-    XtSetArg(args[2], XmNrightAttachment, XmATTACH_FORM);
-    XtSetArg(args[3], XmNtopAttachment, XmATTACH_FORM);
-    XtSetArg(args[4], XmNbottomAttachment, XmATTACH_FORM);
-    XtSetArg(args[5], XmNuserData, tab);
-    Widget frame = XmCreateFrame(view->widget, "tab", args, 6);
-    XtManageChild(frame);
-    
-    UiObject *content = ui_malloc(view->ctx, sizeof(UiObject));
-    content->widget = NULL; // initialization for uic_context()
-    content->ctx = uic_context(content, view->ctx->mp);
-    content->ctx->parent = view->ctx;
-    content->ctx->attach_document = uic_context_attach_document;
-    content->ctx->detach_document2 = uic_context_detach_document2;
-    content->widget = frame;
-    content->window = view->ctx->obj->window;
-    content->container = ui_frame_container(content, frame);
-    content->next = NULL;
-    
-    // add tab button
-    cxListAdd(v->tabs, tab);
+    int a = *n;
+    XtSetArg(args[a], gridColumn, grid->x); a++;
+    XtSetArg(args[a], gridRow, grid->y); a++;
+    if(ctn->layout.colspan > 0) {
+        XtSetArg(args[a], gridColspan, ctn->layout.colspan); a++;
+    }
+    if(ctn->layout.rowspan > 0) {
+        XtSetArg(args[a], gridRowspan, ctn->layout.rowspan); a++;
+    }
     
-    XmString label = XmStringCreateLocalized("tab");
-    XtSetArg(args[0], XmNlabelString, label);
-    XtSetArg(args[1], XmNshadowThickness, 0);
-    XtSetArg(args[2], XmNhighlightThickness, 0);
-    
-    Widget button = XmCreatePushButton(v->tabbar, "tab_button", args, 3);
-    tab->tabbedpane = v;
-    tab->content = content;
-    tab->tab_button = button; 
-    XtManageChild(button);
-    XtAddCallback(
-        button,
-        XmNactivateCallback,
-        (XtCallbackProc)ui_tab_button_callback,
-        tab);
-    
-    if(v->height == 0) {
-        XtVaGetValues(
-                button,
-                XmNarmColor,
-                &v->bg1,
-                XmNbackground,
-                &v->bg2,
-                XmNheight,
-                &v->height,
-                NULL);
-        v->height += 2; // border
+    if(grid->container.layout.fill == UI_ON) {
+        grid->container.layout.hfill = TRUE;
+        grid->container.layout.vfill = TRUE;
+        grid->container.layout.hexpand = TRUE;
+        grid->container.layout.vexpand = TRUE;
     }
     
-    ui_change_tab(v, tab);
-    ui_tabbar_resize(v->tabbar, v, NULL);
+    if(grid->container.layout.hfill) {
+        XtSetArg(args[a], gridHFill, TRUE); a++;
+    }
+    if(grid->container.layout.vfill) {
+        XtSetArg(args[a], gridVFill, TRUE); a++;
+    }
+    if(grid->container.layout.hexpand) {
+        XtSetArg(args[a], gridHExpand, TRUE); a++;
+    }
+    if(grid->container.layout.vexpand) {
+        XtSetArg(args[a], gridVExpand, TRUE); a++;
+    }
     
-    return content;
-}
-
-void ui_tab_button_callback(Widget widget, UiTab *tab, XtPointer d) {  
-    MotifTabbedPane *t = tab->tabbedpane;
-    if(t->current) {
-        XtUnmanageChild(t->current->content->widget);
-        XtVaSetValues(t->current->tab_button, XmNset, 0, NULL);
-    }
-    XtManageChild(tab->content->widget);
-    
-    ui_change_tab(t, tab);
-    
+    *n = a;
+    return ctn->widget;
 }
 
-void ui_change_tab(MotifTabbedPane *pane, UiTab *tab) {
-    UiContext *ctx = tab->content->ctx;
-    ctx->parent->detach_document2(ctx->parent, pane->current->content->ctx->document);
-    ctx->parent->attach_document(ctx->parent, ctx->document);
-    
-    if(pane->current) {
-        XtVaSetValues(pane->current->tab_button, XmNshadowThickness, 0, XmNbackground, pane->bg1, NULL);
-    }
-    XtVaSetValues(tab->tab_button, XmNshadowThickness, 1, XmNbackground, pane->bg2, NULL);
-    
-    pane->current = tab;
-    pane->index = cxListFind(pane->tabs, tab);
-    printf("index: %d\n", pane->index);
-    
-    // redraw tabbar
-    Display *dpy = XtDisplay(pane->tabbar);
-    Window window = XtWindow(pane->tabbar);
-    if(dpy && window) {
-        XClearArea(dpy, XtWindow(pane->tabbar), 0, 0, 0, 0, TRUE);
-        XFlush(dpy);
-    }
+void ui_grid_container_add(UiContainerPrivate *ctn, Widget widget) {
+    UiGridContainer *grid = (UiGridContainer*)ctn;
+    grid->x++;
+    ui_reset_layout(ctn->layout);
 }
 
-void ui_tab_set_document(UiContext *ctx, void *document) {
-    if(ctx->parent->document) {
-        //ctx->parent->detach_document(ctx->parent, ctx->parent->document);
-    }
-    uic_context_attach_document(ctx, document);
-    //uic_context_set_document(ctx->parent, document);
-    //ctx->parent->document = document;
-    
-    UiTab *tab = NULL;
-    XtVaGetValues(
-            ctx->obj->widget,
-            XmNuserData,
-            &tab,
-            NULL);
-    if(tab) {
-        if(tab->tabbedpane->current == tab) {
-            ctx->parent->attach_document(ctx->parent, ctx->document);
-        }
-    } else {
-        fprintf(stderr, "UiError: ui_bar_set_document: Cannot set document");
-    }
+
+/* -------------------- Container Helper Functions -------------------- */
+
+void ui_container_begin_close(UiObject *obj) {
+    UiContainerPrivate *ct = ui_obj_container(obj);
+    ct->container.close = 1;
 }
 
+int ui_container_finish(UiObject *obj) {
+    UiContainerPrivate *ct = ui_obj_container(obj);
+    if(ct->container.close) {
+        ui_end_new(obj);
+        return 0;
+    }
+    return 1;
+}
 
 
 /*
@@ -788,27 +226,7 @@
  *
  */
 
-void ui_layout_fill(UiObject *obj, UiBool fill) {
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->layout.fill = ui_bool2lb(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_gridwidth(UiObject *obj, int width) {
-    UiContainer *ct = uic_get_current_container(obj);
-    ct->layout.gridwidth = width;
-}
-
 void ui_newline(UiObject *obj) {
-    UiContainer *ct = uic_get_current_container(obj);
+    UiContainerPrivate *ct = ui_obj_container(obj);
     ct->layout.newline = TRUE;
 }

mercurial