[gnome-builder] egg: add EggThreeGrid
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] egg: add EggThreeGrid
- Date: Sun, 18 Sep 2016 10:03:14 +0000 (UTC)
commit 41c725d02a45e36ae3df47aa4158b4a2c0b864bd
Author: Christian Hergert <chergert redhat com>
Date: Sun Sep 18 03:01:08 2016 -0700
egg: add EggThreeGrid
This is a GtkGrid-like container with some restraints that make it easier
to implement some designs. It only has 3 columns, and the center column
is always centered (and the left/right columns are of equal sizing).
Still to do to make this more generally useful is to nail down the
baseline support which has been tricky thus far.
This should allow us to simplify the project greeter layout quite a bit
since we no longer need all the size groups for row/column enforcement.
contrib/egg/Makefile.am | 2 +
contrib/egg/egg-three-grid.c | 795 ++++++++++++++++++++++++++++++++++++++++++
contrib/egg/egg-three-grid.h | 57 +++
3 files changed, 854 insertions(+), 0 deletions(-)
---
diff --git a/contrib/egg/Makefile.am b/contrib/egg/Makefile.am
index e462473..0f040fc 100644
--- a/contrib/egg/Makefile.am
+++ b/contrib/egg/Makefile.am
@@ -37,6 +37,7 @@ headers_DATA = \
egg-state-machine-buildable.h \
egg-state-machine.h \
egg-task-cache.h \
+ egg-three-grid.h \
egg-widget-action-group.h \
$(NULL)
@@ -70,6 +71,7 @@ libegg_private_la_SOURCES = \
egg-state-machine-buildable.c \
egg-state-machine.c \
egg-task-cache.c \
+ egg-three-grid.c \
egg-widget-action-group.c \
$(NULL)
diff --git a/contrib/egg/egg-three-grid.c b/contrib/egg/egg-three-grid.c
new file mode 100644
index 0000000..6178f12
--- /dev/null
+++ b/contrib/egg/egg-three-grid.c
@@ -0,0 +1,795 @@
+/* egg-three-grid.c
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LGO_DOMAIN "egg-three-grid"
+
+#include <math.h>
+
+#include "egg-three-grid.h"
+
+typedef struct
+{
+ GtkWidget *widget;
+ gint column;
+ gint row;
+ gint min_height;
+ gint nat_height;
+ gint min_baseline;
+ gint nat_baseline;
+} EggThreeGridChild;
+
+typedef struct
+{
+ GPtrArray *children;
+ GHashTable *row_infos;
+ guint column_spacing;
+ guint row_spacing;
+} EggThreeGridPrivate;
+
+typedef struct
+{
+ gint row;
+ gint min_above_baseline;
+ gint min_below_baseline;
+ gint nat_above_baseline;
+ gint nat_below_baseline;
+} EggThreeGridRowInfo;
+
+G_DEFINE_TYPE_WITH_PRIVATE (EggThreeGrid, egg_three_grid, GTK_TYPE_CONTAINER)
+
+enum {
+ PROP_0,
+ PROP_COLUMN_SPACING,
+ PROP_ROW_SPACING,
+ N_PROPS
+};
+
+enum {
+ CHILD_PROP_0,
+ CHILD_PROP_ROW,
+ CHILD_PROP_COLUMN,
+ N_CHILD_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+static GParamSpec *child_properties [N_CHILD_PROPS];
+static EggThreeGridChild dummy;
+
+static EggThreeGridChild *
+egg_three_grid_child_new (void)
+{
+ return g_slice_new0 (EggThreeGridChild);
+}
+
+static void
+egg_three_grid_child_free (gpointer data)
+{
+ EggThreeGridChild *child = data;
+
+ g_clear_object (&child->widget);
+ g_slice_free (EggThreeGridChild, child);
+}
+
+static EggThreeGridChild *
+egg_three_grid_find_child (EggThreeGrid *self,
+ GtkWidget *widget)
+{
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+
+ g_assert (EGG_IS_THREE_GRID (self));
+ g_assert (GTK_IS_WIDGET (widget));
+
+ for (guint i = 0; i < priv->children->len; i++)
+ {
+ EggThreeGridChild *child = g_ptr_array_index (priv->children, i);
+
+ if (child->widget == widget)
+ return child;
+ }
+
+ return &dummy;
+}
+
+static void
+egg_three_grid_add (GtkContainer *container,
+ GtkWidget *widget)
+{
+ EggThreeGrid *self = (EggThreeGrid *)container;
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+ EggThreeGridChild *child;
+
+ g_assert (EGG_IS_THREE_GRID (self));
+ g_assert (GTK_IS_WIDGET (widget));
+
+ child = egg_three_grid_child_new ();
+ child->widget = g_object_ref_sink (widget);
+ g_ptr_array_add (priv->children, child);
+
+ gtk_widget_set_parent (widget, GTK_WIDGET (self));
+}
+
+static void
+egg_three_grid_remove (GtkContainer *container,
+ GtkWidget *widget)
+{
+ EggThreeGrid *self = (EggThreeGrid *)container;
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+
+ g_assert (EGG_IS_THREE_GRID (self));
+ g_assert (GTK_IS_WIDGET (widget));
+
+ for (guint i = 0; i < priv->children->len; i++)
+ {
+ EggThreeGridChild *child = g_ptr_array_index (priv->children, i);
+
+ if (child->widget == widget)
+ {
+ gtk_widget_unparent (child->widget);
+ g_ptr_array_remove_index (priv->children, i);
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+ return;
+ }
+ }
+}
+
+static GtkSizeRequestMode
+egg_three_grid_get_request_mode (GtkWidget *widget)
+{
+ return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+}
+
+static void
+egg_three_grid_get_column_width (EggThreeGrid *self,
+ EggThreeGridColumn column,
+ gint *min_width,
+ gint *nat_width)
+{
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+ gint real_min_width = 0;
+ gint real_nat_width = 0;
+
+ g_assert (EGG_IS_THREE_GRID (self));
+ g_assert (column >= EGG_THREE_GRID_COLUMN_LEFT);
+ g_assert (column <= EGG_THREE_GRID_COLUMN_RIGHT);
+ g_assert (min_width != NULL);
+ g_assert (nat_width != NULL);
+
+ for (guint i = 0; i < priv->children->len; i++)
+ {
+ EggThreeGridChild *child = g_ptr_array_index (priv->children, i);
+
+ if (child->column == column)
+ {
+ gint child_min_width;
+ gint child_nat_width;
+
+ gtk_widget_get_preferred_width (child->widget, &child_min_width, &child_nat_width);
+
+ real_min_width = MAX (real_min_width, child_min_width);
+ real_nat_width = MAX (real_nat_width, child_nat_width);
+ }
+ }
+
+ *min_width = real_min_width;
+ *nat_width = real_nat_width;
+}
+
+static void
+egg_three_grid_get_preferred_width (GtkWidget *widget,
+ gint *min_width,
+ gint *nat_width)
+{
+ EggThreeGrid *self = (EggThreeGrid *)widget;
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+ gint total_min_width = 0;
+ gint total_nat_width = 0;
+ gint min_widths[3];
+ gint nat_widths[3];
+ gint border_width;
+
+ g_assert (EGG_IS_THREE_GRID (self));
+ g_assert (min_width != NULL);
+ g_assert (nat_width != NULL);
+
+ for (guint i = 0; i < 3; i++)
+ egg_three_grid_get_column_width (self, i, &min_widths[i], &nat_widths[i]);
+
+ total_min_width = MAX (min_widths[0], min_widths[2]) * 2 + min_widths[1];
+ total_nat_width = MAX (nat_widths[0], nat_widths[2]) * 2 + nat_widths[1];
+
+ border_width = gtk_container_get_border_width (GTK_CONTAINER (self));
+
+ *min_width = total_min_width + (border_width * 2) + (priv->column_spacing * 2);
+ *nat_width = total_nat_width + (border_width * 2) + (priv->column_spacing * 2);
+}
+
+static void
+row_info_merge (EggThreeGridRowInfo *row_info,
+ const EggThreeGridRowInfo *other)
+{
+ g_assert (row_info);
+ g_assert (other);
+
+ row_info->min_above_baseline = MAX (row_info->min_above_baseline, other->min_above_baseline);
+ row_info->min_below_baseline = MAX (row_info->min_below_baseline, other->min_below_baseline);
+ row_info->nat_above_baseline = MAX (row_info->nat_above_baseline, other->nat_above_baseline);
+ row_info->nat_below_baseline = MAX (row_info->nat_below_baseline, other->nat_below_baseline);
+}
+
+static void
+update_row_info (GHashTable *hashtable,
+ EggThreeGridChild *child)
+{
+ GtkBaselinePosition baseline_position = GTK_BASELINE_POSITION_CENTER;
+ EggThreeGridRowInfo *row_info;
+ EggThreeGridRowInfo current = { 0 };
+
+ g_assert (hashtable);
+ g_assert (child);
+
+ row_info = g_hash_table_lookup (hashtable, GINT_TO_POINTER (child->row));
+
+ if (row_info == NULL)
+ {
+ row_info = g_new0 (EggThreeGridRowInfo, 1);
+ row_info->row = child->row;
+ g_hash_table_insert (hashtable, GINT_TO_POINTER (child->row), row_info);
+ }
+
+ /*
+ * TODO:
+ *
+ * Allow setting baseline position per row. Right now we only support center
+ * because that is the easiest thing to start with.
+ */
+
+ if (child->min_baseline == -1)
+ {
+ if (baseline_position == GTK_BASELINE_POSITION_CENTER)
+ {
+ current.min_above_baseline = current.min_below_baseline = ceil (child->min_height / 2.0);
+ current.nat_above_baseline = current.nat_below_baseline = ceil (child->min_height / 2.0);
+ }
+ else if (baseline_position == GTK_BASELINE_POSITION_TOP)
+ {
+ g_assert_not_reached ();
+ }
+ else if (baseline_position == GTK_BASELINE_POSITION_BOTTOM)
+ {
+ g_assert_not_reached ();
+ }
+ }
+ else
+ {
+ current.min_above_baseline = child->min_baseline;
+ current.min_below_baseline = child->min_height - child->min_baseline;
+ current.nat_above_baseline = child->nat_baseline;
+ current.nat_below_baseline = child->nat_height - child->nat_baseline;
+ }
+
+ row_info_merge (row_info, ¤t);
+}
+
+static void
+egg_three_grid_get_preferred_height_for_width (GtkWidget *widget,
+ gint width,
+ gint *min_height,
+ gint *nat_height)
+{
+ EggThreeGrid *self = (EggThreeGrid *)widget;
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+ g_autoptr(GHashTable) row_infos = NULL;
+ EggThreeGridRowInfo *row_info;
+ GHashTableIter iter;
+ gint real_min_height = 0;
+ gint real_nat_height = 0;
+ gint column_min_widths[3];
+ gint column_nat_widths[3];
+ gint widths[3];
+ gint border_width;
+ gint n_rows;
+
+ g_assert (EGG_IS_THREE_GRID (self));
+ g_assert (min_height != NULL);
+ g_assert (nat_height != NULL);
+
+ border_width = gtk_container_get_border_width (GTK_CONTAINER (self));
+ width -= border_width * 2;
+ width -= priv->column_spacing * 2;
+
+ egg_three_grid_get_column_width (self, EGG_THREE_GRID_COLUMN_LEFT, &column_min_widths[0],
&column_nat_widths[0]);
+ egg_three_grid_get_column_width (self, EGG_THREE_GRID_COLUMN_CENTER, &column_min_widths[1],
&column_nat_widths[1]);
+ egg_three_grid_get_column_width (self, EGG_THREE_GRID_COLUMN_RIGHT, &column_min_widths[2],
&column_nat_widths[2]);
+
+ if ((MAX (column_min_widths[0], column_min_widths[2]) * 2 + column_nat_widths[1]) >= width)
+ {
+ widths[0] = column_min_widths[0];
+ widths[2] = column_min_widths[2];
+ widths[1] = width - widths[0] - widths[2];
+ }
+ else
+ {
+ /* Handle #1 and #2 */
+ widths[1] = column_nat_widths[1];
+ widths[0] = (width - widths[1]) / 2;
+ widths[2] = width - widths[1] - widths[0];
+ }
+
+ row_infos = g_hash_table_new_full (NULL, NULL, NULL, g_free);
+
+ for (guint i = 0; i < priv->children->len; i++)
+ {
+ EggThreeGridChild *child = g_ptr_array_index (priv->children, i);
+
+ if (!gtk_widget_get_visible (child->widget) ||
+ !gtk_widget_get_child_visible (child->widget))
+ continue;
+
+ gtk_widget_get_preferred_height_and_baseline_for_width (child->widget,
+ widths[child->column],
+ &child->min_height,
+ &child->nat_height,
+ &child->min_baseline,
+ &child->nat_baseline);
+ update_row_info (row_infos, child);
+ }
+
+ g_hash_table_iter_init (&iter, row_infos);
+
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&row_info))
+ {
+#if 0
+ g_print ("Row %d: MIN Above %d Below %d\n",
+ row_info->row,
+ row_info->min_above_baseline, row_info->min_below_baseline);
+ g_print ("Row %d: NAT Above %d Below %d\n",
+ row_info->row,
+ row_info->nat_above_baseline, row_info->nat_below_baseline);
+#endif
+ real_min_height += row_info->min_above_baseline + row_info->min_below_baseline;
+ real_nat_height += row_info->nat_above_baseline + row_info->nat_below_baseline;
+ }
+
+ real_min_height += border_width * 2;
+ real_nat_height += border_width * 2;
+
+ n_rows = g_hash_table_size (row_infos);
+
+ if (n_rows > 1)
+ {
+ real_min_height += (n_rows - 1) * priv->row_spacing;
+ real_nat_height += (n_rows - 1) * priv->row_spacing;
+ }
+
+ *min_height = real_min_height;
+ *nat_height = real_nat_height;
+
+#if 0
+ g_print ("%d children in %d rows: %dx%d\n",
+ priv->children->len,
+ g_hash_table_size (row_infos),
+ real_min_height, real_nat_height);
+#endif
+
+ g_clear_pointer (&priv->row_infos, g_hash_table_unref);
+ priv->row_infos = g_steal_pointer (&row_infos);
+}
+
+static gint
+sort_by_row (gconstpointer a,
+ gconstpointer b)
+{
+ const EggThreeGridRowInfo *info_a = a;
+ const EggThreeGridRowInfo *info_b = b;
+
+ return info_a->row - info_b->row;
+}
+
+static void
+egg_three_grid_size_allocate_children (EggThreeGrid *self,
+ EggThreeGridColumn column,
+ gint row,
+ GtkAllocation *allocation,
+ gint baseline)
+{
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+
+ g_assert (EGG_IS_THREE_GRID (self));
+ g_assert (allocation != NULL);
+
+ for (guint i = 0; i < priv->children->len; i++)
+ {
+ EggThreeGridChild *child = g_ptr_array_index (priv->children, i);
+
+ if (child->row == row && child->column == column)
+ {
+ GtkAllocation copy = *allocation;
+ gtk_widget_size_allocate_with_baseline (child->widget, ©, baseline);
+ }
+ }
+}
+
+static void
+egg_three_grid_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ EggThreeGrid *self = (EggThreeGrid *)widget;
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+ g_autofree GtkRequestedSize *rows = NULL;
+ const GList *iter;
+ GtkAllocation area;
+ GList *values;
+ guint i;
+ guint n_rows;
+ gint min_height;
+ gint nat_height;
+ gint border_width;
+ gint left_min_width;
+ gint left_nat_width;
+ gint center_min_width;
+ gint center_nat_width;
+ gint right_min_width;
+ gint right_nat_width;
+ gint left;
+ gint center;
+ gint right;
+
+ g_assert (EGG_IS_THREE_GRID (self));
+ g_assert (allocation != NULL);
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ egg_three_grid_get_preferred_height_for_width (widget, allocation->width, &min_height, &nat_height);
+
+ if (min_height > allocation->height)
+ g_warning ("%s requested a minimum height of %d and got %d",
+ G_OBJECT_TYPE_NAME (widget), min_height, allocation->height);
+
+ if (priv->row_infos == NULL)
+ return;
+
+ values = g_hash_table_get_values (priv->row_infos);
+ values = g_list_sort (values, sort_by_row);
+
+ area = *allocation;
+ border_width = gtk_container_get_border_width (GTK_CONTAINER (self));
+
+ area.x += border_width;
+ area.y += border_width;
+ area.width -= border_width * 2;
+ area.height -= border_width * 2;
+
+ egg_three_grid_get_column_width (self, EGG_THREE_GRID_COLUMN_LEFT, &left_min_width, &left_nat_width);
+ egg_three_grid_get_column_width (self, EGG_THREE_GRID_COLUMN_CENTER, ¢er_min_width, ¢er_nat_width);
+ egg_three_grid_get_column_width (self, EGG_THREE_GRID_COLUMN_RIGHT, &right_min_width, &right_nat_width);
+
+ /*
+ * Determine how much to give to the center widget first. This is because we will
+ * just give the rest of the space on the sides to left/right columns and they
+ * can deal with alignment by using halign.
+ *
+ * We can be in one of a couple states:
+ *
+ * 1) There is enough room for all columns natural size.
+ * (We allocate the same to the left and the right).
+ * 2) There is enough for the natural size of the center
+ * but for some amount between natural and min sizing
+ * of the left/right columns.
+ * 3) There is only minimum size for columns and some
+ * amount between natural/minimum of the center.
+ *
+ * We can handle #1 and #2 with the same logic though.
+ */
+
+ if ((MAX (left_min_width, right_min_width) * 2 + center_nat_width) >= (area.width - (priv->column_spacing
* 2)))
+ {
+ /* Handle #3 */
+ left = left_min_width;
+ right = right_min_width;
+ center = area.width - left - right;
+ }
+ else
+ {
+ /* Handle #1 and #2 */
+ center = center_nat_width;
+ right = left = (area.width - center) / 2 - priv->column_spacing;
+ }
+
+ n_rows = g_list_length (values);
+ rows = g_new0 (GtkRequestedSize, n_rows);
+
+ for (iter = values, i = 0; iter != NULL; iter = iter->next, i++)
+ {
+ EggThreeGridRowInfo *row_info = iter->data;
+
+ rows[i].data = row_info;
+ rows[i].minimum_size = row_info->min_above_baseline + row_info->min_below_baseline;
+ rows[i].natural_size = row_info->nat_above_baseline + row_info->nat_below_baseline;
+ }
+
+ gtk_distribute_natural_allocation (area.height, n_rows, rows);
+
+ for (i = 0; i < n_rows; i++)
+ {
+ GtkRequestedSize *size = &rows[i];
+ EggThreeGridRowInfo *row_info = size->data;
+ GtkAllocation child_alloc;
+ gint baseline;
+
+ if (row_info->nat_above_baseline + row_info->nat_below_baseline <= size->minimum_size)
+ baseline = row_info->nat_above_baseline;
+ else
+ baseline = row_info->min_above_baseline;
+
+ child_alloc.x = area.x;
+ child_alloc.width = left;
+ child_alloc.y = area.y;
+ child_alloc.height = size->minimum_size;
+ egg_three_grid_size_allocate_children (self, EGG_THREE_GRID_COLUMN_LEFT, row_info->row, &child_alloc,
baseline);
+
+ child_alloc.x = area.x + left + priv->column_spacing;
+ child_alloc.width = center;
+ child_alloc.y = area.y;
+ child_alloc.height = size->minimum_size;
+ egg_three_grid_size_allocate_children (self, EGG_THREE_GRID_COLUMN_CENTER, row_info->row,
&child_alloc, baseline);
+
+ child_alloc.x = area.x + area.width - right;
+ child_alloc.width = right;
+ child_alloc.y = area.y;
+ child_alloc.height = size->minimum_size;
+ egg_three_grid_size_allocate_children (self, EGG_THREE_GRID_COLUMN_RIGHT, row_info->row, &child_alloc,
baseline);
+
+ area.y += child_alloc.height + priv->row_spacing;
+ area.height -= child_alloc.height + priv->row_spacing;
+ }
+}
+
+static void
+egg_three_grid_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer user_data)
+{
+ EggThreeGrid *self = (EggThreeGrid *)container;
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+
+ g_assert (GTK_IS_CONTAINER (self));
+ g_assert (callback != NULL);
+
+ for (guint i = priv->children->len; i > 0; i--)
+ {
+ EggThreeGridChild *child = g_ptr_array_index (priv->children, i - 1);
+
+ callback (child->widget, user_data);
+ }
+}
+
+static void
+egg_three_grid_get_child_property (GtkContainer *container,
+ GtkWidget *widget,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggThreeGrid *self = (EggThreeGrid *)container;
+ EggThreeGridChild *child = egg_three_grid_find_child (self, widget);
+
+ switch (prop_id)
+ {
+ case CHILD_PROP_COLUMN:
+ g_value_set_enum (value, child->column);
+ break;
+
+ case CHILD_PROP_ROW:
+ g_value_set_uint (value, child->row);
+ break;
+
+ default:
+ GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
+ }
+}
+
+static void
+egg_three_grid_set_child_property (GtkContainer *container,
+ GtkWidget *widget,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggThreeGrid *self = (EggThreeGrid *)container;
+ EggThreeGridChild *child = egg_three_grid_find_child (self, widget);
+
+ switch (prop_id)
+ {
+ case CHILD_PROP_COLUMN:
+ child->column = g_value_get_enum (value);
+ break;
+
+ case CHILD_PROP_ROW:
+ child->row = g_value_get_uint (value);
+ break;
+
+ default:
+ GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
+ }
+
+ gtk_widget_queue_resize (GTK_WIDGET (container));
+}
+
+static void
+egg_three_grid_finalize (GObject *object)
+{
+ EggThreeGrid *self = (EggThreeGrid *)object;
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+
+ g_clear_pointer (&priv->row_infos, g_hash_table_unref);
+ g_clear_pointer (&priv->children, g_ptr_array_unref);
+
+ G_OBJECT_CLASS (egg_three_grid_parent_class)->finalize (object);
+}
+
+static void
+egg_three_grid_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggThreeGrid *self = EGG_THREE_GRID (object);
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+
+ switch (prop_id)
+ {
+ case PROP_COLUMN_SPACING:
+ g_value_set_uint (value, priv->column_spacing);
+ break;
+
+ case PROP_ROW_SPACING:
+ g_value_set_uint (value, priv->row_spacing);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+egg_three_grid_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggThreeGrid *self = EGG_THREE_GRID (object);
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+
+ switch (prop_id)
+ {
+ case PROP_COLUMN_SPACING:
+ priv->column_spacing = g_value_get_uint (value);
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+ break;
+
+ case PROP_ROW_SPACING:
+ priv->row_spacing = g_value_get_uint (value);
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+egg_three_grid_class_init (EggThreeGridClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+ object_class->finalize = egg_three_grid_finalize;
+ object_class->get_property = egg_three_grid_get_property;
+ object_class->set_property = egg_three_grid_set_property;
+
+ widget_class->get_request_mode = egg_three_grid_get_request_mode;
+ widget_class->get_preferred_height_for_width = egg_three_grid_get_preferred_height_for_width;
+ widget_class->get_preferred_width = egg_three_grid_get_preferred_width;
+ widget_class->size_allocate = egg_three_grid_size_allocate;
+
+ container_class->add = egg_three_grid_add;
+ container_class->forall = egg_three_grid_forall;
+ container_class->get_child_property = egg_three_grid_get_child_property;
+ container_class->remove = egg_three_grid_remove;
+ container_class->set_child_property = egg_three_grid_set_child_property;
+
+ properties [PROP_COLUMN_SPACING] =
+ g_param_spec_uint ("column-spacing",
+ "Column Spacing",
+ "The amount of spacing to add between columns",
+ 0,
+ G_MAXUINT,
+ 0,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_ROW_SPACING] =
+ g_param_spec_uint ("row-spacing",
+ "Row Spacing",
+ "The amount of spacing to add between rows",
+ 0,
+ G_MAXUINT,
+ 0,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ child_properties [CHILD_PROP_COLUMN] =
+ g_param_spec_enum ("column",
+ "Column",
+ "Column",
+ EGG_TYPE_THREE_GRID_COLUMN,
+ EGG_THREE_GRID_COLUMN_LEFT,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ child_properties [CHILD_PROP_ROW] =
+ g_param_spec_uint ("row",
+ "Row",
+ "Row",
+ 0,
+ G_MAXUINT,
+ 0,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gtk_container_class_install_child_properties (container_class, N_CHILD_PROPS, child_properties);
+
+ gtk_widget_class_set_css_name (widget_class, "threegrid");
+}
+
+static void
+egg_three_grid_init (EggThreeGrid *self)
+{
+ EggThreeGridPrivate *priv = egg_three_grid_get_instance_private (self);
+
+ priv->children = g_ptr_array_new_with_free_func (egg_three_grid_child_free);
+
+ gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
+}
+
+GtkWidget *
+egg_three_grid_new (void)
+{
+ return g_object_new (EGG_TYPE_THREE_GRID, NULL);
+}
+
+GType
+egg_three_grid_column_get_type (void)
+{
+ static GType type_id;
+
+ if (g_once_init_enter (&type_id))
+ {
+ GType _type_id;
+ static const GEnumValue values[] = {
+ { EGG_THREE_GRID_COLUMN_LEFT, "EGG_THREE_GRID_COLUMN_LEFT", "left" },
+ { EGG_THREE_GRID_COLUMN_CENTER, "EGG_THREE_GRID_COLUMN_CENTER", "center" },
+ { EGG_THREE_GRID_COLUMN_RIGHT, "EGG_THREE_GRID_COLUMN_RIGHT", "right" },
+ { 0 }
+ };
+ _type_id = g_enum_register_static ("EggThreeGridColumn", values);
+ g_once_init_leave (&type_id, _type_id);
+ }
+
+ return type_id;
+}
diff --git a/contrib/egg/egg-three-grid.h b/contrib/egg/egg-three-grid.h
new file mode 100644
index 0000000..8e72706
--- /dev/null
+++ b/contrib/egg/egg-three-grid.h
@@ -0,0 +1,57 @@
+/* egg-three-grid.h
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EGG_THREE_GRID_H
+#define EGG_THREE_GRID_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_THREE_GRID (egg_three_grid_get_type())
+#define EGG_TYPE_THREE_GRID_COLUMN (egg_three_grid_column_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (EggThreeGrid, egg_three_grid, EGG, THREE_GRID, GtkContainer)
+
+struct _EggThreeGridClass
+{
+ GtkContainerClass parent_class;
+
+ gpointer _reserved1;
+ gpointer _reserved2;
+ gpointer _reserved3;
+ gpointer _reserved4;
+ gpointer _reserved5;
+ gpointer _reserved6;
+ gpointer _reserved7;
+ gpointer _reserved8;
+};
+
+typedef enum
+{
+ EGG_THREE_GRID_COLUMN_LEFT,
+ EGG_THREE_GRID_COLUMN_CENTER,
+ EGG_THREE_GRID_COLUMN_RIGHT
+} EggThreeGridColumn;
+
+GType egg_three_grid_column_get_type (void);
+GtkWidget *egg_three_grid_new (void);
+
+G_END_DECLS
+
+#endif /* EGG_THREE_GRID_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]