From 4b149ddfefa29a2d4ae5f123ee7357779025a940 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Thu, 9 Jun 2016 18:57:58 -0400 Subject: [PATCH] Implemented uiGrid on GTK+. --- common/controlsigs.h | 1 + test/page14.c | 8 +-- ui_unix.h | 1 + unix/CMakeLists.txt | 1 + unix/form.c | 1 - unix/grid.c | 141 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 unix/grid.c diff --git a/common/controlsigs.h b/common/controlsigs.h index b788135d..03e675cc 100644 --- a/common/controlsigs.h +++ b/common/controlsigs.h @@ -11,6 +11,7 @@ #define uiEntrySignature 0x456E7472 #define uiFontButtonSignature 0x466F6E42 #define uiFormSignature 0x466F726D +#define uiGridSignature 0x47726964 #define uiGroupSignature 0x47727062 #define uiLabelSignature 0x4C61626C #define uiMultilineEntrySignature 0x4D6C6E45 diff --git a/test/page14.c b/test/page14.c index babb9467..af181ab6 100644 --- a/test/page14.c +++ b/test/page14.c @@ -47,13 +47,13 @@ static uiControl *simpleGrid(void) t4 = testControl("4", green); uiGridAppend(g, t4, 0, 1, 1, 1, - 0, uiAreaFill, 1, uiAreaFill); + 0, uiAlignFill, 1, uiAlignFill); uiGridInsertAt(g, testControl("5", blue), t4, uiAtTrailing, 2, 1, - 0, uiAreaFill, 0, uiAreaFill); + 0, uiAlignFill, 0, uiAlignFill); uiGridAppend(g, testControl("6", yellow), -1, 0, 1, 2, - 1, uiAreaFill, 0, uiAreaFill); + 1, uiAlignFill, 0, uiAlignFill); return uiControl(g); } @@ -64,7 +64,7 @@ static const struct { } pages[] = { { "Simple Grid", simpleGrid }, // from GTK+ test/testgrid.c { NULL, NULL }, -} +}; uiTab *makePage14(void) { diff --git a/ui_unix.h b/ui_unix.h index f8cdf3dd..5a91257b 100644 --- a/ui_unix.h +++ b/ui_unix.h @@ -80,6 +80,7 @@ _UI_EXTERN void uiUnixControlSetContainer(uiUnixControl *, GtkContainer *, gbool { \ gtk_widget_set_sensitive(type(c)->widget, FALSE); \ } +// TODO this whole addedBefore stuff is a MASSIVE HACK. #define uiUnixControlDefaultSetContainer(type) \ static void type ## SetContainer(uiUnixControl *c, GtkContainer *container, gboolean remove) \ { \ diff --git a/unix/CMakeLists.txt b/unix/CMakeLists.txt index 42903125..33eedfac 100644 --- a/unix/CMakeLists.txt +++ b/unix/CMakeLists.txt @@ -24,6 +24,7 @@ list(APPEND _LIBUI_SOURCES unix/fontbutton.c unix/form.c unix/graphemes.c + unix/grid.c unix/group.c unix/label.c unix/main.c diff --git a/unix/form.c b/unix/form.c index 03acd23a..bf0c9b52 100644 --- a/unix/form.c +++ b/unix/form.c @@ -37,7 +37,6 @@ static void uiFormDestroy(uiControl *c) for (i = 0; i < f->children->len; i++) { fc = ctrl(f, i); uiControlSetParent(fc->c, NULL); - // and make sure the widget itself stays alive uiUnixControlSetContainer(uiUnixControl(fc->c), f->container, TRUE); uiControlDestroy(fc->c); gtk_widget_destroy(fc->label); diff --git a/unix/grid.c b/unix/grid.c new file mode 100644 index 00000000..3ed60ec5 --- /dev/null +++ b/unix/grid.c @@ -0,0 +1,141 @@ +// 9 june 2016 +#include "uipriv_unix.h" + +struct gridChild { + uiControl *c; + GtkWidget *label; + gboolean oldhexpand; + GtkAlign oldhalign; + gboolean oldvexpand; + GtkAlign oldvalign; +}; + +struct uiGrid { + uiUnixControl c; + GtkWidget *widget; + GtkContainer *container; + GtkGrid *grid; + GArray *children; + int padded; +}; + +uiUnixControlAllDefaultsExceptDestroy(uiGrid) + +#define ctrl(g, i) &g_array_index(g->children, struct gridChild, i) + +static void uiGridDestroy(uiControl *c) +{ + uiGrid *g = uiGrid(c); + struct gridChild *gc; + guint i; + + // free all controls + for (i = 0; i < g->children->len; i++) { + gc = ctrl(g, i); + uiControlSetParent(gc->c, NULL); + uiUnixControlSetContainer(uiUnixControl(gc->c), g->container, TRUE); + uiControlDestroy(gc->c); + } + g_array_free(g->children, TRUE); + // and then ourselves + g_object_unref(g->widget); + uiFreeControl(uiControl(g)); +} + +#define TODO_MASSIVE_HACK(c) \ + if (!uiUnixControl(c)->addedBefore) { \ + g_object_ref_sink(GTK_WIDGET(uiControlHandle(uiControl(c)))); \ + gtk_widget_show(GTK_WIDGET(uiControlHandle(uiControl(c)))); \ + uiUnixControl(c)->addedBefore = TRUE; \ + } + +static const GtkAlign gtkAligns[] = { + [uiAlignFill] = GTK_ALIGN_FILL, + [uiAlignStart] = GTK_ALIGN_START, + [uiAlignCenter] = GTK_ALIGN_CENTER, + [uiAlignEnd] = GTK_ALIGN_END, +}; + +static const GtkPositionType gtkPositions[] = { + [uiAtLeading] = GTK_POS_LEFT, + [uiAtTop] = GTK_POS_TOP, + [uiAtTrailing] = GTK_POS_RIGHT, + [uiAtBottom] = GTK_POS_BOTTOM, +}; + +static GtkWidget *prepare(struct gridChild *gc, uiControl *c, int hexpand, uiAlign halign, int vexpand, uiAlign valign) +{ + GtkWidget *widget; + + gc->c = c; + widget = GTK_WIDGET(uiControlHandle(gc->c)); + gc->oldhexpand = gtk_widget_get_hexpand(widget); + gc->oldhalign = gtk_widget_get_halign(widget); + gc->oldvexpand = gtk_widget_get_vexpand(widget); + gc->oldvalign = gtk_widget_get_valign(widget); + gtk_widget_set_hexpand(widget, hexpand != 0); + gtk_widget_set_halign(widget, gtkAligns[halign]); + gtk_widget_set_vexpand(widget, vexpand != 0); + gtk_widget_set_valign(widget, gtkAligns[valign]); + return widget; +} + +void uiGridAppend(uiGrid *g, uiControl *c, intmax_t left, intmax_t top, intmax_t xspan, intmax_t yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) +{ + struct gridChild gc; + GtkWidget *widget; + + widget = prepare(&gc, c, hexpand, halign, vexpand, valign); + uiControlSetParent(gc.c, uiControl(g)); + TODO_MASSIVE_HACK(uiUnixControl(gc.c)); + gtk_grid_attach(g->grid, widget, + left, top, + xspan, yspan); + g_array_append_val(g->children, gc); +} + +void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, intmax_t xspan, intmax_t yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) +{ + struct gridChild gc; + GtkWidget *widget; + + widget = prepare(&gc, c, hexpand, halign, vexpand, valign); + uiControlSetParent(gc.c, uiControl(g)); + TODO_MASSIVE_HACK(uiUnixControl(gc.c)); + gtk_grid_attach_next_to(g->grid, widget, + GTK_WIDGET(uiControlHandle(existing)), gtkPositions[at], + xspan, yspan); + g_array_append_val(g->children, gc); +} + +int uiGridPadded(uiGrid *g) +{ + return g->padded; +} + +void uiGridSetPadded(uiGrid *g, int padded) +{ + g->padded = padded; + if (g->padded) { + gtk_grid_set_row_spacing(g->grid, gtkYPadding); + gtk_grid_set_column_spacing(g->grid, gtkXPadding); + } else { + gtk_grid_set_row_spacing(g->grid, 0); + gtk_grid_set_column_spacing(g->grid, 0); + } +} + +uiGrid *uiNewGrid(void) +{ + uiGrid *g; + + uiUnixNewControl(uiGrid, g); + + g->widget = gtk_grid_new(); + g->container = GTK_CONTAINER(g->widget); + g->grid = GTK_GRID(g->widget); + + g->children = g_array_new(FALSE, TRUE, sizeof (struct gridChild)); + + return g; +}