summaryrefslogtreecommitdiff
path: root/new/unix/newcontrol.c
diff options
context:
space:
mode:
Diffstat (limited to 'new/unix/newcontrol.c')
-rw-r--r--new/unix/newcontrol.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/new/unix/newcontrol.c b/new/unix/newcontrol.c
new file mode 100644
index 0000000..500798b
--- /dev/null
+++ b/new/unix/newcontrol.c
@@ -0,0 +1,229 @@
+// 7 april 2015
+#include "uipriv_unix.h"
+
+typedef struct singleWidget singleWidget;
+
+struct singleWidget {
+ GtkWidget *widget;
+ GtkWidget *scrolledWindow;
+ GtkWidget *immediate; // the widget that is added to the parent container; either widget or scrolledWindow
+ uiParent *parent;
+ gboolean userHid;
+ gboolean containerHid;
+ gboolean userDisabled;
+ gboolean containerDisabled;
+};
+
+static void singleDestroy(uiControl *c)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ gtk_widget_destroy(s->immediate);
+}
+
+static uintptr_t singleHandle(uiControl *c)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ return (uintptr_t) (s->widget);
+}
+
+static void singleSetParent(uiControl *c, uiParent *parent)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+ uiParent *oldparent;
+
+ oldparent = s->parent;
+ s->parent = parent;
+ if (oldparent != NULL) {
+ gtk_container_remove(GTK_CONTAINER(uiParentHandle(oldparent)), s->immediate);
+ uiParentUpdate(oldparent);
+ }
+ if (s->parent != NULL) {
+ gtk_container_add(GTK_CONTAINER(uiParentHandle(s->parent)), s->immediate);
+ uiParentUpdate(s->parent);
+ }
+}
+
+static void singlePreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+ GtkRequisition natural;
+
+ // use the natural size as the minimum size is an *absolute* minimum
+ // for example, if a label has ellipsizing on, it can be the width of the ellipses, not the text
+ // there is a warning about height-for-width sizing, but in my tests this isn't an issue
+ gtk_widget_get_preferred_size(s->widget, NULL, &natural);
+ *width = natural.width;
+ *height = natural.height;
+}
+
+static void singleResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+ GtkAllocation a;
+
+ a.x = x;
+ a.y = y;
+ a.width = width;
+ a.height = height;
+ gtk_widget_size_allocate(s->immediate, &a);
+}
+
+static int singleVisible(uiControl *c)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ if (s->userHid)
+ return 0;
+ return 1;
+}
+
+static void singleShow(uiControl *c)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ s->userHid = FALSE;
+ if (!s->containerHid) {
+ gtk_widget_show_all(s->immediate);
+ if (s->parent != NULL)
+ uiParentUpdate(s->parent);
+ }
+}
+
+static void singleHide(uiControl *c)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ s->userHid = TRUE;
+ gtk_widget_hide(s->immediate);
+ if (s->parent != NULL)
+ uiParentUpdate(s->parent);
+}
+
+static void singleContainerShow(uiControl *c)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ s->containerHid = FALSE;
+ if (!s->userHid) {
+ gtk_widget_show_all(s->immediate);
+ if (s->parent != NULL)
+ uiParentUpdate(s->parent);
+ }
+}
+
+static void singleContainerHide(uiControl *c)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ s->containerHid = TRUE;
+ gtk_widget_hide(s->immediate);
+ if (s->parent != NULL)
+ uiParentUpdate(s->parent);
+}
+
+static void singleEnable(uiControl *c)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ s->userDisabled = FALSE;
+ if (!s->containerDisabled)
+ gtk_widget_set_sensitive(s->immediate, TRUE);
+}
+
+static void singleDisable(uiControl *c)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ s->userDisabled = TRUE;
+ gtk_widget_set_sensitive(s->immediate, FALSE);
+}
+
+static void singleContainerEnable(uiControl *c)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ s->containerDisabled = FALSE;
+ if (!s->userDisabled)
+ gtk_widget_set_sensitive(s->immediate, TRUE);
+}
+
+static void singleContainerDisable(uiControl *c)
+{
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ s->containerDisabled = TRUE;
+ gtk_widget_set_sensitive(s->immediate, FALSE);
+}
+
+static void onDestroy(GtkWidget *widget, gpointer data)
+{
+ uiControl *c = (uiControl *) data;
+ singleWidget *s = (singleWidget *) (c->internal);
+
+ uiFree(s);
+ uiFree(c);
+}
+
+uiControl *uiUnixNewControl(GType type, gboolean inScrolledWindow, gboolean scrolledWindowHasBorder, const char *firstProperty, ...)
+{
+ uiControl *c;
+ singleWidget *s;
+ va_list ap;
+
+ s = uiNew(singleWidget);
+
+ va_start(ap, firstProperty);
+ s->widget = GTK_WIDGET(g_object_new_valist(type, firstProperty, ap));
+ va_end(ap);
+ s->immediate = s->widget;
+
+ if (inScrolledWindow) {
+ s->scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
+ if (!GTK_IS_SCROLLABLE(s->widget))
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(s->scrolledWindow), s->widget);
+ else
+ gtk_container_add(GTK_CONTAINER(s->scrolledWindow), s->widget);
+ if (scrolledWindowHasBorder)
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(s->scrolledWindow), GTK_SHADOW_IN);
+ s->immediate = s->scrolledWindow;
+ }
+
+ // we need to keep an extra reference on the immediate widget
+ // this is so uiControlDestroy() can work regardless of when it is called and who calls it
+ // without this:
+ // - end user call works (only one ref)
+ // - call in uiContainer destructor fails (uiContainer ref freed)
+ // with this:
+ // - end user call works (shoudn't be in any container)
+ // - call in uiContainer works (both refs freed)
+ // this also ensures singleRemoveParent() works properly
+ g_object_ref_sink(s->immediate);
+
+ c = uiNew(uiControl);
+ // assign s later; we still need it for one more thing
+ c->destroy = singleDestroy;
+ c->handle = singleHandle;
+ c->setParent = singleSetParent;
+ c->preferredSize = singlePreferredSize;
+ c->resize = singleResize;
+ c->visible = singleVisible;
+ c->show = singleShow;
+ c->hide = singleHide;
+ c->containerShow = singleContainerShow;
+ c->containerHide = singleContainerHide;
+ c->enable = singleEnable;
+ c->disable = singleDisable;
+ c->containerEnable = singleContainerEnable;
+ c->containerDisable = singleContainerDisable;
+
+ // and let's free everything with the immediate widget
+ g_signal_connect(s->immediate, "destroy", G_CALLBACK(onDestroy), c);
+
+ // finally, call gtk_widget_show_all() here to set the initial visibility of the widget
+ gtk_widget_show_all(s->immediate);
+
+ c->internal = s;
+ return c;
+}