#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include "container.h"
#include "../common/context.h"
#include "../common/object.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;
}
UiContainer* ui_frame_container(UiObject *obj, Widget frame) {
UiContainer *ct = ucx_mempool_calloc(
obj->ctx->mempool,
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;
}
UiContainer* ui_box_container(UiObject *obj, Widget box,
int margin,
int spacing, UiBoxOrientation orientation) {
UiBoxContainer *ct = ucx_mempool_calloc(
obj->ctx->mempool,
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);
}
if(bc->has_fill && fill) {
fprintf(stderr,
"UiError: container has 2 filled widgets");
fill =
FALSE;
}
if(fill) {
bc->has_fill =
TRUE;
}
int a = *n;
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;
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++;
}
else {
f1 = XmNtopAttachment;
f2 = XmNbottomAttachment;
d1 = XmNleftAttachment;
d2 = XmNrightAttachment;
w1 = XmNleftWidget;
w2 = XmNrightWidget;
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;
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 = ucx_mempool_calloc(
obj->ctx->mempool,
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;
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) {
grid->current = ucx_list_append(grid->current, widget);
}
else {
grid->current = ucx_list_append(grid->current, widget);
grid->lines = ucx_list_append(grid->lines, grid->current);
}
ui_reset_layout(ct->layout);
ct->current = widget;
}
static void ui_grid_resize(Widget widget, XtPointer udata, XtPointer cdata) {
UiGridContainer *grid = udata;
UcxList *rowdim =
NULL;
int coldim[
UI_GRID_MAX_COLUMNS];
memset(coldim,
0,
UI_GRID_MAX_COLUMNS*
sizeof(
int));
int numcol =
0;
int sumw =
0;
int sumh =
0;
UCX_FOREACH(row, grid->lines) {
int rheight =
0;
int i=
0;
int sum_width =
0;
UCX_FOREACH(elm, row->data) {
Widget w = elm->data;
int widget_width =
0;
int widget_height =
0;
XtVaGetValues(
w,
XmNwidth,
&widget_width,
XmNheight,
&widget_height,
NULL);
if(widget_height > rheight) {
rheight = widget_height;
}
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;
}
}
rowdim = ucx_list_append(rowdim, (
void*)(
intptr_t)rheight);
sumh += rheight;
}
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);
ucx_list_free(rowdim);
return;
}
int y =
0;
UCX_FOREACH(row, grid->lines) {
int x =
0;
int i=
0;
UCX_FOREACH(elm, row->data) {
Widget w = elm->data;
XtVaSetValues(
w,
XmNx, x,
XmNy, y,
XmNwidth, coldim[i],
XmNheight, rowdim->data,
NULL);
x += coldim[i];
i++;
}
y += (
intptr_t)rowdim->data;
rowdim = rowdim->next;
}
ucx_list_free(rowdim);
}
UiContainer* ui_scrolledwindow_container(UiObject *obj, Widget scrolledwindow) {
UiContainer *ct = ucx_mempool_calloc(
obj->ctx->mempool,
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 = ucx_mempool_calloc(
obj->ctx->mempool,
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;
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;
tabview->tabs = ucx_list_append(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);
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);
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;
}
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);
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);
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;
}
UIWIDGET ui_tabview(UiObject *obj) {
UiContainer *ct = uic_get_current_container(obj);
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;
}
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);
UcxList *elm = ucx_list_get(ct->tabs, tab);
if(elm) {
XtManageChild(elm->data);
ct->current = elm->data;
}
else {
fprintf(stderr,
"UiError: front tab index: %d\n", tab);
}
}
else {
fprintf(stderr,
"UiError: widget is not a tabview\n");
}
}
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;
UCX_FOREACH(elm, v->tabs) {
UiTab *tab = elm->data;
XtVaSetValues(
tab->tab_button,
XmNx, x,
XmNy,
0,
XmNwidth,
button_width,
NULL);
x += button_width;
}
if(height <= v->height) {
XtVaSetValues(widget, XmNheight, v->height +
4,
NULL);
}
}
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);
}
UiTabbedPane* ui_tabbed_document_view(UiObject *obj) {
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(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);
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 =
NULL;
tabbedpane->current =
NULL;
tabbedpane->height =
0;
XtAddCallback(tabbar, XmNresizeCallback , ui_tabbar_resize, tabbedpane);
XtAddCallback(tabbar, XmNexposeCallback, ui_tabbar_expose, tabbedpane);
return &tabbedpane->view;
}
UiObject* ui_document_tab(UiTabbedPane *view) {
MotifTabbedPane *v = (MotifTabbedPane*)view;
int n =
0;
Arg args[
16];
if(v->current) {
XtUnmanageChild(v->current->content->widget);
}
UiTab *tab = ui_malloc(view->ctx,
sizeof(UiTab));
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;
content->ctx = uic_context(content, view->ctx->mempool);
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;
v->tabs = ucx_list_append_a(view->ctx->mempool->allocator, v->tabs, tab);
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;
}
ui_change_tab(v, tab);
ui_tabbar_resize(v->tabbar, v,
NULL);
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);
}
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 = ucx_list_find(pane->tabs, tab,
NULL,
NULL);
printf(
"index: %d\n", pane->index);
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_tab_set_document(UiContext *ctx,
void *document) {
if(ctx->parent->document) {
}
uic_context_attach_document(ctx, 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");
}
}
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);
ct->layout.newline =
TRUE;
}