#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "container.h"
#include "toolkit.h"
#include "../common/context.h"
#include "../common/object.h"
void ui_container_begin_close(UiObject *obj) {
UiContainer *ct = uic_get_current_container(obj);
ct->close =
1;
}
int ui_container_finish(UiObject *obj) {
UiContainer *ct = uic_get_current_container(obj);
if(ct->close) {
ui_end(obj);
return 0;
}
return 1;
}
GtkWidget* ui_gtk_vbox_new(
int spacing) {
#ifdef UI_GTK3
return gtk_box_new(
GTK_ORIENTATION_VERTICAL, spacing);
#else
return gtk_vbox_new(
FALSE, spacing);
#endif
}
GtkWidget* ui_gtk_hbox_new(
int spacing) {
#ifdef UI_GTK3
return gtk_box_new(
GTK_ORIENTATION_HORIZONTAL, spacing);
#else
return gtk_hbox_new(
FALSE, spacing);
#endif
}
UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame) {
UiContainer *ct = ucx_mempool_calloc(
obj->ctx->mempool,
1,
sizeof(UiContainer));
ct->widget = frame;
ct->add = ui_frame_container_add;
return ct;
}
void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
gtk_container_add(
GTK_CONTAINER(ct->widget), widget);
ui_reset_layout(ct->layout);
ct->current = widget;
}
UiContainer* ui_box_container(UiObject *obj, GtkWidget *box) {
UiBoxContainer *ct = ucx_mempool_calloc(
obj->ctx->mempool,
1,
sizeof(UiBoxContainer));
ct->container.widget = box;
ct->container.add = ui_box_container_add;
return (UiContainer*)ct;
}
void ui_box_container_add(UiContainer *ct, GtkWidget *widget, 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;
}
UiBool expand = fill;
gtk_box_pack_start(
GTK_BOX(ct->widget), widget, expand, fill,
0);
ui_reset_layout(ct->layout);
ct->current = widget;
}
UiContainer* ui_grid_container(UiObject *obj, GtkWidget *grid) {
UiGridContainer *ct = ucx_mempool_calloc(
obj->ctx->mempool,
1,
sizeof(UiGridContainer));
ct->container.widget = grid;
ct->container.add = ui_grid_container_add;
#ifdef UI_GTK2
ct->width =
0;
ct->height =
1;
#endif
return (UiContainer*)ct;
}
#ifdef UI_GTK3
void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
UiGridContainer *grid = (UiGridContainer*)ct;
if(ct->layout.newline) {
grid->x =
0;
grid->y++;
ct->layout.newline =
FALSE;
}
int hexpand =
FALSE;
int vexpand =
FALSE;
if(ct->layout.hexpand !=
UI_LAYOUT_UNDEFINED) {
hexpand = ct->layout.hexpand;
}
if(ct->layout.vexpand !=
UI_LAYOUT_UNDEFINED) {
vexpand = ct->layout.vexpand;
}
if(hexpand) {
gtk_widget_set_hexpand(widget,
TRUE);
}
if(vexpand) {
gtk_widget_set_vexpand(widget,
TRUE);
}
int gwidth = ct->layout.gridwidth >
0 ? ct->layout.gridwidth :
1;
gtk_grid_attach(
GTK_GRID(ct->widget), widget, grid->x, grid->y, gwidth,
1);
grid->x += gwidth;
ui_reset_layout(ct->layout);
ct->current = widget;
}
#endif
#ifdef UI_GTK2
void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
UiGridContainer *grid = (UiGridContainer*)ct;
if(ct->layout.newline) {
grid->x =
0;
grid->y++;
ct->layout.newline =
FALSE;
}
int hexpand =
FALSE;
int vexpand =
FALSE;
if(ct->layout.hexpand !=
UI_LAYOUT_UNDEFINED) {
hexpand = ct->layout.hexpand;
}
if(ct->layout.vexpand !=
UI_LAYOUT_UNDEFINED) {
vexpand = ct->layout.vexpand;
}
GtkAttachOptions xoptions = hexpand ?
GTK_FILL |
GTK_EXPAND :
GTK_FILL;
GtkAttachOptions yoptions = vexpand ?
GTK_FILL |
GTK_EXPAND :
GTK_FILL;
gtk_table_attach(
GTK_TABLE(ct->widget), widget, grid->x, grid->x+
1, grid->y, grid->y+
1, xoptions, yoptions,
0,
0);
grid->x++;
int nw = grid->x > grid->width ? grid->x : grid->width;
if(grid->x > grid->width || grid->y > grid->height) {
grid->width = nw;
grid->height = grid->y +
1;
gtk_table_resize(
GTK_TABLE(ct->widget), grid->width, grid->height);
}
ui_reset_layout(ct->layout);
ct->current = widget;
}
#endif
UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) {
UiContainer *ct = ucx_mempool_calloc(
obj->ctx->mempool,
1,
sizeof(UiContainer));
ct->widget = scrolledwindow;
ct->add = ui_scrolledwindow_container_add;
return ct;
}
void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
#ifdef UI_GTK3
gtk_container_add(
GTK_CONTAINER(ct->widget), widget);
#else
gtk_scrolled_window_add_with_viewport(
GTK_SCROLLED_WINDOW(ct->widget), widget);
#endif
ui_reset_layout(ct->layout);
ct->current = widget;
}
UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview) {
UiTabViewContainer *ct = ucx_mempool_calloc(
obj->ctx->mempool,
1,
sizeof(UiTabViewContainer));
ct->container.widget = tabview;
ct->container.add = ui_tabview_container_add;
return (UiContainer*)ct;
}
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));
ui_reset_layout(ct->layout);
ct->current = widget;
}
UIWIDGET ui_vbox(UiObject *obj) {
return ui_vbox_sp(obj,
0,
0);
}
UIWIDGET ui_hbox(UiObject *obj) {
return ui_hbox_sp(obj,
0,
0);
}
static GtkWidget* box_set_margin(GtkWidget *box,
int margin) {
GtkWidget *ret = box;
#ifdef UI_GTK3
#if GTK_MAJOR_VERSION ==
3 &&
GTK_MINOR_VERSION >=
12
gtk_widget_set_margin_start(box, margin);
gtk_widget_set_margin_end(box, margin);
#else
gtk_widget_set_margin_left(box, margin);
gtk_widget_set_margin_right(box, margin);
#endif
gtk_widget_set_margin_top(box, margin);
gtk_widget_set_margin_bottom(box, margin);
#elif defined(
UI_GTK2)
GtkWidget *a = gtk_alignment_new(
0.
5,
0.
5,
1,
1);
gtk_alignment_set_padding(
GTK_ALIGNMENT(a), margin, margin, margin, margin);
gtk_container_add(
GTK_CONTAINER(a), box);
ret = a;
#endif
return ret;
}
UIWIDGET ui_vbox_sp(UiObject *obj,
int margin,
int spacing) {
UiContainer *ct = uic_get_current_container(obj);
GtkWidget *vbox = ui_gtk_vbox_new(spacing);
GtkWidget *widget = margin >
0 ? box_set_margin(vbox, margin) : vbox;
ct->add(ct, widget,
TRUE);
UiObject *newobj = uic_object_new(obj, vbox);
newobj->container = ui_box_container(obj, vbox);
uic_obj_add(obj, newobj);
return widget;
}
UIWIDGET ui_hbox_sp(UiObject *obj,
int margin,
int spacing) {
UiContainer *ct = uic_get_current_container(obj);
GtkWidget *hbox = ui_gtk_hbox_new(spacing);
GtkWidget *widget = margin >
0 ? box_set_margin(hbox, margin) : hbox;
ct->add(ct, widget,
TRUE);
UiObject *newobj = uic_object_new(obj, hbox);
newobj->container = ui_box_container(obj, hbox);
uic_obj_add(obj, newobj);
return widget;
}
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);
GtkWidget *widget;
#ifdef UI_GTK3
GtkWidget *grid = gtk_grid_new();
gtk_grid_set_column_spacing(
GTK_GRID(grid), columnspacing);
gtk_grid_set_row_spacing(
GTK_GRID(grid), rowspacing);
#if GTK_MAJOR_VERSION ==
3 &&
GTK_MINOR_VERSION >=
12
gtk_widget_set_margin_start(grid, margin);
gtk_widget_set_margin_end(grid, margin);
#else
gtk_widget_set_margin_left(grid, margin);
gtk_widget_set_margin_right(grid, margin);
#endif
gtk_widget_set_margin_top(grid, margin);
gtk_widget_set_margin_bottom(grid, margin);
widget = grid;
#elif defined(
UI_GTK2)
GtkWidget *grid = gtk_table_new(
1,
1,
FALSE);
gtk_table_set_col_spacings(
GTK_TABLE(grid), columnspacing);
gtk_table_set_row_spacings(
GTK_TABLE(grid), rowspacing);
if(margin >
0) {
GtkWidget *a = gtk_alignment_new(
0.
5,
0.
5,
1,
1);
gtk_alignment_set_padding(
GTK_ALIGNMENT(a), margin, margin, margin, margin);
gtk_container_add(
GTK_CONTAINER(a), grid);
widget = a;
}
else {
widget = grid;
}
#endif
ct->add(ct, widget,
TRUE);
UiObject *newobj = uic_object_new(obj, grid);
newobj->container = ui_grid_container(obj, grid);
uic_obj_add(obj, newobj);
return widget;
}
UIWIDGET ui_scrolledwindow(UiObject *obj) {
UiContainer *ct = uic_get_current_container(obj);
GtkWidget *sw = gtk_scrolled_window_new(
NULL,
NULL);
ct->add(ct, sw,
TRUE);
UiObject *newobj = uic_object_new(obj, sw);
newobj->container = ui_scrolledwindow_container(obj, sw);
uic_obj_add(obj, newobj);
return sw;
}
UIWIDGET ui_tabview(UiObject *obj) {
GtkWidget *tabview = gtk_notebook_new();
gtk_notebook_set_show_border(
GTK_NOTEBOOK(tabview),
FALSE);
gtk_notebook_set_show_tabs(
GTK_NOTEBOOK(tabview),
FALSE);
UiContainer *ct = uic_get_current_container(obj);
ct->add(ct, tabview,
TRUE);
UiObject *tabviewobj = uic_object_new(obj, tabview);
tabviewobj->container = ui_tabview_container(obj, tabview);
uic_obj_add(obj, tabviewobj);
return tabview;
}
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) {
gtk_notebook_set_current_page(
GTK_NOTEBOOK(tabview), tab);
}
static GtkWidget* create_paned(UiOrientation orientation) {
#ifdef UI_GTK3
switch(orientation) {
case UI_HORIZONTAL:
return gtk_paned_new(
GTK_ORIENTATION_HORIZONTAL);
case UI_VERTICAL:
return gtk_paned_new(
GTK_ORIENTATION_VERTICAL);
}
#else
switch(orientation) {
case UI_HORIZONTAL:
return gtk_hpaned_new();
case UI_VERTICAL:
return gtk_vpaned_new();
}
#endif
return NULL;
}
UIWIDGET ui_splitpane(UiObject *obj,
int max, UiOrientation orientation) {
GtkWidget *paned = create_paned(orientation);
UiContainer *ct = uic_get_current_container(obj);
ct->add(ct, paned,
TRUE);
if(max <=
0) max =
INT_MAX;
UiPanedContainer *pctn = ucx_mempool_calloc(
obj->ctx->mempool,
1,
sizeof(UiPanedContainer));
pctn->container.widget = paned;
pctn->container.add = ui_paned_container_add;
pctn->current_pane = paned;
pctn->orientation = orientation;
pctn->max = max;
pctn->cur =
0;
UiObject *pobj = uic_object_new(obj, paned);
pobj->container = (UiContainer*)pctn;
uic_obj_add(obj, pobj);
return paned;
}
UIWIDGET ui_hsplitpane(UiObject *obj,
int max) {
return ui_splitpane(obj, max,
UI_HORIZONTAL);
}
UIWIDGET ui_vsplitpane(UiObject *obj,
int max) {
return ui_splitpane(obj, max,
UI_VERTICAL);
}
void ui_paned_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
UiPanedContainer *pctn = (UiPanedContainer*)ct;
gboolean resize = (ct->layout.hexpand || ct->layout.vexpand) ?
TRUE :
FALSE;
int width = ct->layout.width;
ui_reset_layout(ct->layout);
if(pctn->cur ==
0) {
gtk_paned_pack1(
GTK_PANED(pctn->current_pane), widget, resize, resize);
}
else if(pctn->cur < pctn->max-
1) {
GtkWidget *nextPane = create_paned(pctn->orientation);
gtk_paned_pack2(
GTK_PANED(pctn->current_pane), nextPane,
TRUE,
TRUE);
gtk_paned_pack1(
GTK_PANED(nextPane), widget, resize, resize);
pctn->current_pane = nextPane;
}
else if(pctn->cur == pctn->max-
1) {
gtk_paned_pack2(
GTK_PANED(pctn->current_pane), widget, resize, resize);
width =
0;
}
else {
fprintf(stderr,
"Splitpane max reached: %d\n", pctn->max);
return;
}
if(width >
0) {
gtk_paned_set_position(
GTK_PANED(pctn->current_pane), width);
}
pctn->cur++;
}
UIWIDGET ui_sidebar(UiObject *obj) {
#ifdef UI_GTK3
GtkWidget *paned = gtk_paned_new(
GTK_ORIENTATION_HORIZONTAL);
#else
GtkWidget *paned = gtk_hpaned_new();
#endif
gtk_paned_set_position(
GTK_PANED(paned),
200);
GtkWidget *sidebar = ui_gtk_vbox_new(
0);
gtk_paned_pack1(
GTK_PANED(paned), sidebar,
TRUE,
FALSE);
UiObject *left = uic_object_new(obj, sidebar);
UiContainer *ct1 = ui_box_container(obj, sidebar);
left->container = ct1;
UiObject *right = uic_object_new(obj, sidebar);
UiContainer *ct2 = ucx_mempool_malloc(
obj->ctx->mempool,
sizeof(UiContainer));
ct2->widget = paned;
ct2->add = ui_split_container_add2;
right->container = ct2;
UiContainer *ct = uic_get_current_container(obj);
ct->add(ct, paned,
TRUE);
uic_obj_add(obj, right);
uic_obj_add(obj, left);
return sidebar;
}
void ui_split_container_add1(UiContainer *ct, GtkWidget *widget, UiBool fill) {
gtk_paned_pack1(
GTK_PANED(ct->widget), widget,
TRUE,
FALSE);
ui_reset_layout(ct->layout);
ct->current = widget;
}
void ui_split_container_add2(UiContainer *ct, GtkWidget *widget, UiBool fill) {
gtk_paned_pack2(
GTK_PANED(ct->widget), widget,
TRUE,
FALSE);
ui_reset_layout(ct->layout);
ct->current = widget;
}
static void page_change(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer data) {
GQuark q = g_quark_from_static_string(
"ui.tab.object");
UiObject *tab = g_object_get_qdata(
G_OBJECT(page), q);
if(!tab) {
return;
}
UiContext *ctx = tab->ctx;
uic_context_detach_all(ctx->parent);
ctx->parent->attach_document(ctx->parent, ctx->document);
}
UiTabbedPane* ui_tabbed_document_view(UiObject *obj) {
GtkWidget *tabview = gtk_notebook_new();
gtk_notebook_set_show_border(
GTK_NOTEBOOK(tabview),
FALSE);
g_signal_connect(
tabview,
"switch-page",
G_CALLBACK(page_change),
NULL);
UiContainer *ct = uic_get_current_container(obj);
ct->add(ct, tabview,
TRUE);
UiTabbedPane *tabbedpane = ui_malloc(obj->ctx,
sizeof(UiTabbedPane));
tabbedpane->ctx = uic_current_obj(obj)->ctx;
tabbedpane->widget = tabview;
tabbedpane->document =
NULL;
return tabbedpane;
}
UiObject* ui_document_tab(UiTabbedPane *view) {
GtkWidget *frame = gtk_frame_new(
NULL);
gtk_frame_set_shadow_type(
GTK_FRAME(frame),
GTK_SHADOW_NONE);
gtk_notebook_append_page(
GTK_NOTEBOOK(view->widget), frame,
NULL);
UiObject *tab = ui_malloc(view->ctx,
sizeof(UiObject));
tab->widget =
NULL;
tab->ctx = uic_context(tab, view->ctx->mempool);
tab->ctx->parent = view->ctx;
tab->ctx->attach_document = uic_context_attach_document;
tab->ctx->detach_document2 = uic_context_detach_document2;
tab->widget = frame;
tab->window = view->ctx->obj->window;
tab->container = ui_frame_container(tab, frame);
tab->next =
NULL;
GQuark q = g_quark_from_static_string(
"ui.tab.object");
g_object_set_qdata(
G_OBJECT(frame), q, tab);
return tab;
}
void ui_tab_set_document(UiContext *ctx,
void *document) {
if(ctx->parent->document) {
}
}
void ui_tab_detach_document(UiContext *ctx) {
}
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_width(UiObject *obj,
int width) {
UiContainer *ct = uic_get_current_container(obj);
ct->layout.width = width;
}
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;
}