[libegg] Add spreadtable
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libegg] Add spreadtable
- Date: Fri, 29 Oct 2010 07:05:06 +0000 (UTC)
commit 6881bab42266316e7085a0c1a807cea2f584c5eb
Author: David King <davidk openismus com>
Date: Thu Oct 28 15:45:19 2010 +0200
Add spreadtable
EggSpreadTable is a dump of the GtkSpreadTable code from the
spread-table branch of gtk+. It modifies configure.in to add a check for
GTK+ 3, and enables the spreadtable subdirectory if GTK+ 3 is installed.
configure.in | 8 +
libegg/Makefile.am | 8 +-
libegg/spreadtable/Makefile.am | 30 +
libegg/spreadtable/eggspreadtable.c | 1126 ++++++++++++++++++++++++++++++++++
libegg/spreadtable/eggspreadtable.h | 89 +++
libegg/spreadtable/testspreadtable.c | 393 ++++++++++++
6 files changed, 1653 insertions(+), 1 deletions(-)
---
diff --git a/configure.in b/configure.in
index fd180f1..5a107e4 100644
--- a/configure.in
+++ b/configure.in
@@ -106,6 +106,13 @@ AM_CONDITIONAL(HAVE_GTK210, $PKG_CONFIG --atleast-version=2.10.0 gtk+-2.0)
## check if we have gtk+ 2.15.x
AM_CONDITIONAL(HAVE_GTK215, $PKG_CONFIG --atleast-version=2.15.0 gtk+-2.0)
+## check if we have gtk+ 3
+AM_CONDITIONAL(HAVE_GTK30, $PKG_CONFIG --atleast-version=2.91.1 gtk+-3.0)
+
+AM_COND_IF(HAVE_GTK30,
+ [PKG_CHECK_MODULES(EGG_30, gtk+-3.0)
+ AC_CONFIG_FILES()])
+
## check if we have the X11 gtk+ backend
AM_CONDITIONAL(HAVE_GTK_TARGET_X11, test `$PKG_CONFIG --variable=target gtk+-2.0` = x11)
@@ -144,6 +151,7 @@ libegg/pixbufthumbnail/Makefile
libegg/thumbnailpreview/Makefile
libegg/iconchooser/Makefile
libegg/smclient/Makefile
+libegg/spreadtable/Makefile
libegg/fileformatchooser/Makefile
doc/Makefile
])
diff --git a/libegg/Makefile.am b/libegg/Makefile.am
index 149a447..cc05c4f 100644
--- a/libegg/Makefile.am
+++ b/libegg/Makefile.am
@@ -1,3 +1,8 @@
+if HAVE_GTK30
+spreadtable_SUBDIRS = \
+ spreadtable
+endif
+
if HAVE_GTK25
thumbnail_SUBDIRS = \
pixbufthumbnail \
@@ -28,7 +33,8 @@ SUBDIRS = util column-chooser treeviewutils \
dock datetime $(thumbnail_SUBDIRS) \
smclient \
$(gtk210_SUBDIRS) \
- $(gtk215_SUBDIRS)
+ $(gtk215_SUBDIRS) \
+ $(gtk30_SUBDIRS)
# Don't compile broken code
#$(iconchooser_SUBDIRS)
diff --git a/libegg/spreadtable/Makefile.am b/libegg/spreadtable/Makefile.am
new file mode 100644
index 0000000..5670e9d
--- /dev/null
+++ b/libegg/spreadtable/Makefile.am
@@ -0,0 +1,30 @@
+INCLUDES = \
+ $(EGG_30_CFLAGS) \
+ -DEGG_COMPILATION \
+ -DGTK_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DG_DISABLE_DEPRECATED \
+ -DGETTEXT_PACKAGE=\"libegg\"
+
+noinst_LTLIBRARIES = libegg-spreadtable.la
+
+libegg_spreadtable_la_LIBADD = $(EGG_30_LIBS)
+
+EGGSOURCES = \
+ eggspreadtable.c
+
+EGGHEADERS = \
+ eggspreadtable.h
+
+libegg_spreadtable_la_SOURCES = $(EGGSOURCES)
+
+noinst_HEADERS = $(EGG_HEADERS)
+
+#Test program
+
+noinst_PROGRAMS = testspreadtable
+
+testspreadtable_SOURCES = testspreadtable.c
+
+testspreadtable_LDADD = $(EGG_30_LIBS) \
+ $(top_builddir)/libegg/spreadtable/libegg-spreadtable.la
diff --git a/libegg/spreadtable/eggspreadtable.c b/libegg/spreadtable/eggspreadtable.c
new file mode 100644
index 0000000..fe20d64
--- /dev/null
+++ b/libegg/spreadtable/eggspreadtable.c
@@ -0,0 +1,1126 @@
+/* gtkspreadtable.c
+ * Copyright (C) 2007-2010 Openismus GmbH
+ *
+ * Authors:
+ * Tristan Van Berkom <tristanvb openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gtkspreadtable
+ * @Short_Description: A container that distributes its children evenly across rows/columns.
+ * @Title: EggSpreadTable
+ *
+ * #EggSpreadTable positions its children by distributing them as
+ * evenly as possible across a fixed number of rows or columns.
+ *
+ * When oriented vertically the #EggSpreadTable will list its
+ * children in order from top to bottom in columns and request
+ * the smallest height as possible regardless of differences in
+ * child sizes.
+ */
+
+#include "config.h"
+#include <gtk/gtk.h>
+#include <string.h>
+#include "eggspreadtable.h"
+
+#define DEFAULT_LINES 2
+#define P_(msgid) (msgid)
+
+enum {
+ PROP_0,
+ PROP_ORIENTATION,
+ PROP_HORIZONTAL_SPACING,
+ PROP_VERTICAL_SPACING,
+ PROP_LINES
+};
+
+struct _EggSpreadTablePrivate {
+ GList *children;
+
+ GtkOrientation orientation;
+
+ guint16 lines;
+ guint16 horizontal_spacing;
+ guint16 vertical_spacing;
+};
+
+/* GObjectClass */
+static void egg_spread_table_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void egg_spread_table_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+/* GtkWidgetClass */
+
+static GtkSizeRequestMode egg_spread_table_get_request_mode (GtkWidget *widget);
+static void egg_spread_table_get_width (GtkWidget *widget,
+ gint *minimum_size,
+ gint *natural_size);
+static void egg_spread_table_get_height (GtkWidget *widget,
+ gint *minimum_size,
+ gint *natural_size);
+static void egg_spread_table_get_height_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height);
+static void egg_spread_table_get_width_for_height (GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height);
+static void egg_spread_table_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+
+/* GtkContainerClass */
+static void egg_spread_table_add (GtkContainer *container,
+ GtkWidget *widget);
+static void egg_spread_table_remove (GtkContainer *container,
+ GtkWidget *widget);
+
+
+static void egg_spread_table_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data);
+static GType egg_spread_table_child_type (GtkContainer *container);
+
+
+G_DEFINE_TYPE_WITH_CODE (EggSpreadTable, egg_spread_table, GTK_TYPE_CONTAINER,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
+
+#define ITEM_SPACING(table) \
+ (((EggSpreadTable *)(table))->priv->orientation == GTK_ORIENTATION_HORIZONTAL ? \
+ ((EggSpreadTable *)(table))->priv->horizontal_spacing : \
+ ((EggSpreadTable *)(table))->priv->vertical_spacing)
+
+#define LINE_SPACING(table) \
+ (((EggSpreadTable *)(table))->priv->orientation == GTK_ORIENTATION_HORIZONTAL ? \
+ ((EggSpreadTable *)(table))->priv->vertical_spacing : \
+ ((EggSpreadTable *)(table))->priv->horizontal_spacing)
+
+#define OPPOSITE_ORIENTATION(table) \
+ (((EggSpreadTable *)(table))->priv->orientation == GTK_ORIENTATION_HORIZONTAL ? \
+ GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL)
+
+static void
+egg_spread_table_class_init (EggSpreadTableClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
+
+ gobject_class->get_property = egg_spread_table_get_property;
+ gobject_class->set_property = egg_spread_table_set_property;
+
+ widget_class->get_request_mode = egg_spread_table_get_request_mode;
+ widget_class->get_preferred_width = egg_spread_table_get_width;
+ widget_class->get_preferred_height = egg_spread_table_get_height;
+ widget_class->get_preferred_height_for_width = egg_spread_table_get_height_for_width;
+ widget_class->get_preferred_width_for_height = egg_spread_table_get_width_for_height;
+ widget_class->size_allocate = egg_spread_table_size_allocate;
+
+ container_class->add = egg_spread_table_add;
+ container_class->remove = egg_spread_table_remove;
+ container_class->forall = egg_spread_table_forall;
+ container_class->child_type = egg_spread_table_child_type;
+
+ gtk_container_class_handle_border_width (container_class);
+
+ /* GObjectClass properties */
+ g_object_class_override_property (gobject_class, PROP_ORIENTATION, "orientation");
+
+ /**
+ * EggSpreadTable:lines:
+ *
+ * The number of lines (rows/columns) to evenly distribute children to.
+ *
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_LINES,
+ g_param_spec_uint ("lines",
+ P_("Lines"),
+ P_("The number of lines (rows/columns) to "
+ "evenly distribute children to."),
+ 1,
+ 65535,
+ DEFAULT_LINES,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+
+ /**
+ * EggSpreadTable:vertical-spacing:
+ *
+ * The amount of vertical space between two children.
+ *
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_VERTICAL_SPACING,
+ g_param_spec_uint ("vertical-spacing",
+ P_("Vertical spacing"),
+ P_("The amount of vertical space between two children"),
+ 0,
+ 65535,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ /**
+ * EggSpreadTable:horizontal-spacing:
+ *
+ * The amount of horizontal space between two children.
+ *
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_HORIZONTAL_SPACING,
+ g_param_spec_uint ("horizontal-spacing",
+ P_("Horizontal spacing"),
+ P_("The amount of horizontal space between two children"),
+ 0,
+ 65535,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_type_class_add_private (class, sizeof (EggSpreadTablePrivate));
+}
+
+static void
+egg_spread_table_init (EggSpreadTable *spread_table)
+{
+ EggSpreadTablePrivate *priv;
+
+ spread_table->priv = priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (spread_table, EGG_TYPE_SPREAD_TABLE, EggSpreadTablePrivate);
+
+ /* We are vertical by default */
+ priv->orientation = GTK_ORIENTATION_VERTICAL;
+ priv->lines = DEFAULT_LINES;
+
+ gtk_widget_set_has_window (GTK_WIDGET (spread_table), FALSE);
+}
+
+/*****************************************************
+ * GObectClass *
+ *****************************************************/
+static void
+egg_spread_table_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggSpreadTable *table = EGG_SPREAD_TABLE (object);
+ EggSpreadTablePrivate *priv = table->priv;
+
+ switch (prop_id)
+ {
+ case PROP_ORIENTATION:
+ g_value_set_enum (value, priv->orientation);
+ break;
+ case PROP_LINES:
+ g_value_set_uint (value, egg_spread_table_get_lines (table));
+ break;
+ case PROP_VERTICAL_SPACING:
+ g_value_set_uint (value, egg_spread_table_get_vertical_spacing (table));
+ break;
+ case PROP_HORIZONTAL_SPACING:
+ g_value_set_uint (value, egg_spread_table_get_horizontal_spacing (table));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_spread_table_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggSpreadTable *table = EGG_SPREAD_TABLE (object);
+ EggSpreadTablePrivate *priv = table->priv;
+
+ switch (prop_id)
+ {
+ case PROP_ORIENTATION:
+ priv->orientation = g_value_get_enum (value);
+
+ /* Re-spread_table the children in the new orientation */
+ gtk_widget_queue_resize (GTK_WIDGET (table));
+ break;
+ case PROP_LINES:
+ egg_spread_table_set_lines (table, g_value_get_uint (value));
+ break;
+ case PROP_HORIZONTAL_SPACING:
+ egg_spread_table_set_horizontal_spacing (table, g_value_get_uint (value));
+ break;
+ case PROP_VERTICAL_SPACING:
+ egg_spread_table_set_vertical_spacing (table, g_value_get_uint (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+
+/*****************************************************
+ * Geometric helper functions for request/allocate *
+ *****************************************************/
+static void
+get_widget_size (GtkWidget *widget,
+ GtkOrientation orientation,
+ gint for_size,
+ gint *min_size,
+ gint *nat_size)
+{
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (for_size < 0)
+ gtk_widget_get_preferred_width (widget, min_size, nat_size);
+ else
+ gtk_widget_get_preferred_width_for_height (widget, for_size, min_size, nat_size);
+ }
+ else
+ {
+ if (for_size < 0)
+ gtk_widget_get_preferred_height (widget, min_size, nat_size);
+ else
+ gtk_widget_get_preferred_height_for_width (widget, for_size, min_size, nat_size);
+ }
+}
+
+
+static GList *
+get_visible_children (EggSpreadTable *table)
+{
+ EggSpreadTablePrivate *priv = table->priv;
+ GtkWidget *child;
+ GList *list, *visible = NULL;
+
+ for (list = priv->children; list; list = list->next)
+ {
+ child = list->data;
+
+ if (!gtk_widget_get_visible (child))
+ continue;
+
+ visible = g_list_prepend (visible, child);
+ }
+
+ return g_list_reverse (visible);
+}
+
+/* This gets the widest child, it is used to reserve
+ * enough space for (columns * widest_child)
+ */
+static void
+get_largest_line_thickness (EggSpreadTable *table,
+ gint *min_thickness,
+ gint *nat_thickness)
+{
+ EggSpreadTablePrivate *priv = table->priv;
+ GList *list;
+ gint min_size = 0, nat_size = 0;
+ GtkOrientation opposite_orientation;
+
+ opposite_orientation = OPPOSITE_ORIENTATION (table);
+
+ for (list = priv->children; list; list = list->next)
+ {
+ GtkWidget *child = list->data;
+ gint child_min, child_nat;
+
+ if (!gtk_widget_get_visible (child))
+ continue;
+
+ get_widget_size (child, opposite_orientation, -1, &child_min, &child_nat);
+
+ min_size = MAX (min_size, child_min);
+ nat_size = MAX (nat_size, child_nat);
+ }
+
+ *min_thickness = min_size;
+ *nat_thickness = nat_size;
+}
+
+/* Gets the column width for a given width */
+static gint
+get_line_thickness (EggSpreadTable *table,
+ gint for_thickness)
+{
+ EggSpreadTablePrivate *priv = table->priv;
+ gint line_thickness;
+
+ /* Get the available size per line (when vertical, we are getting the column width here) */
+ line_thickness = for_thickness - (priv->lines -1) * LINE_SPACING (table);
+ line_thickness = line_thickness / priv->lines;
+
+ return line_thickness;
+}
+
+/* Gets the overall height of a column (length of a line segment) */
+static gint
+get_segment_length (EggSpreadTable *table,
+ gint line_thickness,
+ GList *seg_children)
+{
+ EggSpreadTablePrivate *priv = table->priv;
+ GList *list;
+ gint size = 0, i = 0;
+ gint spacing;
+
+ spacing = ITEM_SPACING (table);
+
+ for (i = 0, list = seg_children; list; list = list->next)
+ {
+ GtkWidget *child = list->data;
+ gint child_nat;
+
+ if (!gtk_widget_get_visible (child))
+ continue;
+
+ get_widget_size (child, priv->orientation, line_thickness, NULL, &child_nat);
+
+ size += child_nat;
+
+ if (i != 0)
+ size += spacing;
+
+ i++;
+ }
+
+ return size;
+}
+
+static gboolean
+children_fit_segment_size (EggSpreadTable *table,
+ GList *children,
+ gint line_thickness,
+ gint size,
+ gint *segments,
+ gint *largest_segment_size)
+{
+ EggSpreadTablePrivate *priv;
+ GList *l;
+ gint segment_size, i;
+ gint spacing;
+
+ priv = table->priv;
+ spacing = ITEM_SPACING (table);
+
+ /* reset segments */
+ memset (segments, 0x0, sizeof (gint) * priv->lines);
+
+ for (l = children, i = 0; l && i < priv->lines; i++)
+ {
+ segment_size = 0;
+
+ /* While we still have children to place and
+ * there is space left on this line */
+ while (l && segment_size < size)
+ {
+ GtkWidget *child = l->data;
+ gint widget_size;
+
+ get_widget_size (child, priv->orientation, line_thickness, NULL, &widget_size);
+
+ if (segment_size != 0)
+ segment_size += spacing;
+
+ segment_size += widget_size;
+
+ /* Consume this widget in this line segment if it fits the size
+ * or it is alone taller than the whole tested size */
+ if (segment_size <= size || segments[i] == 0)
+ {
+ *largest_segment_size = MAX (*largest_segment_size, segment_size);
+ segments[i]++;
+
+ l = l->next;
+ }
+ }
+ }
+
+ /* If we placed all the widgets in the target size, the size fits. */
+ return (l == NULL);
+}
+
+/* All purpose algorithm entry point, this function takes an allocated size
+ * to fit the columns (or rows) and then splits up the child list into
+ * 'n' children per 'segment' in a way that it takes the least space as possible.
+ *
+ * If 'segments' is specified, it will be allocated the array of integers representing
+ * how many children are to be fit per line segment (and must be freed afterwards with g_free()).
+ *
+ * The function returns the required space (the required height for all columns).
+ */
+static gint
+segment_lines_for_size (EggSpreadTable *table,
+ gint for_size,
+ gint **segments)
+{
+ EggSpreadTablePrivate *priv;
+ GList *children;
+ gint line_thickness;
+ gint *segment_counts = NULL, *test_counts;
+ gint upper, lower, segment_size, largest_size = 0;
+ gint i, j;
+
+ priv = table->priv;
+ line_thickness = get_line_thickness (table, for_size);
+
+ segment_counts = g_new0 (gint, priv->lines);
+ test_counts = g_new0 (gint, priv->lines);
+
+ /* Start by getting the child list/total size/average size */
+ children = get_visible_children (table);
+ upper = get_segment_length (table, line_thickness, children);
+ lower = upper / priv->lines;
+
+ /* Handle a single line spread table as a special case */
+ if (priv->lines == 1)
+ {
+ segment_counts[0] = g_list_length (children);
+ largest_size = upper;
+ }
+ else
+ {
+ /* Start with half way between the average and total height */
+ segment_size = lower + (upper - lower) / 2;
+
+ while (segment_size > lower && segment_size < upper)
+ {
+ gint test_largest = 0;
+
+ if (children_fit_segment_size (table, children, line_thickness,
+ segment_size, test_counts, &test_largest))
+ {
+ upper = segment_size;
+ segment_size -= (segment_size - lower) / 2;
+
+ /* Save the last arrangement that 'fit' */
+ largest_size = test_largest;
+ memcpy (segment_counts, test_counts, sizeof (gint) * priv->lines);
+ }
+ else
+ {
+ lower = segment_size;
+ segment_size += (upper - segment_size) / 2;
+ }
+ }
+
+ /* Perform some corrections: fill in any trailing columns that are missing widgets */
+ for (i = 0; i < priv->lines; i++)
+ {
+ /* If this column has no widgets... */
+ if (!segment_counts[i])
+ {
+ /* rewind to the last column that had more than 1 widget */
+ for (j = i - 1; j >= 0; j--)
+ {
+ if (segment_counts[j] > 1)
+ {
+ /* put an available widget in the empty column */
+ segment_counts[j]--;
+ segment_counts[i]++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (segments)
+ *segments = segment_counts;
+ else
+ g_free (segment_counts);
+
+ g_free (test_counts);
+
+ return largest_size;
+}
+
+
+/*****************************************************
+ * GtkWidgetClass *
+ *****************************************************/
+static GtkSizeRequestMode
+egg_spread_table_get_request_mode (GtkWidget *widget)
+{
+ EggSpreadTable *table = EGG_SPREAD_TABLE (widget);
+ EggSpreadTablePrivate *priv = table->priv;
+
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+ else
+ return GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
+}
+
+static void
+egg_spread_table_get_width (GtkWidget *widget,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ EggSpreadTable *table = EGG_SPREAD_TABLE (widget);
+ EggSpreadTablePrivate *priv = table->priv;
+ gint min_width, nat_width;
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ /* Get the width for minimum height */
+ gint min_height;
+
+ GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_height, NULL);
+ GTK_WIDGET_GET_CLASS (widget)->get_preferred_width_for_height (widget, min_height,
+ &min_width, &nat_width);
+ }
+ else /* GTK_ORIENTATION_VERTICAL */
+ {
+ gint min_thickness, nat_thickness;
+
+ get_largest_line_thickness (table, &min_thickness, &nat_thickness);
+
+ min_width = min_thickness * priv->lines + LINE_SPACING (table) * (priv->lines - 1);
+ nat_width = nat_thickness * priv->lines + LINE_SPACING (table) * (priv->lines - 1);
+ }
+
+#if 0
+ g_print ("get_width() called; returning min %d and nat %d\n",
+ min_width, nat_width);
+#endif
+
+ if (minimum_size)
+ *minimum_size = min_width;
+
+ if (natural_size)
+ *natural_size = nat_width;
+}
+
+static void
+egg_spread_table_get_height (GtkWidget *widget,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ EggSpreadTable *table = EGG_SPREAD_TABLE (widget);
+ EggSpreadTablePrivate *priv = table->priv;
+ gint min_height, nat_height;
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ gint min_thickness, nat_thickness;
+
+ get_largest_line_thickness (table, &min_thickness, &nat_thickness);
+
+ min_height = min_thickness * priv->lines + LINE_SPACING (table) * (priv->lines - 1);
+ nat_height = nat_thickness * priv->lines + LINE_SPACING (table) * (priv->lines - 1);
+ }
+ else /* GTK_ORIENTATION_VERTICAL */
+ {
+ /* Return the height for the minimum width */
+ gint min_width;
+
+ GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL);
+ GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, min_width,
+ &min_height, &nat_height);
+ }
+
+#if 0
+ g_print ("get_height() called; returning min %d and nat %d\n",
+ min_height, nat_height);
+#endif
+
+ if (minimum_size)
+ *minimum_size = min_height;
+
+ if (natural_size)
+ *natural_size = nat_height;
+}
+
+static void
+egg_spread_table_get_height_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ EggSpreadTable *table = EGG_SPREAD_TABLE (widget);
+ EggSpreadTablePrivate *priv = table->priv;
+ gint min_height = 0, nat_height = 0;
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ /* Just return the minimum/natural height */
+ GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_height, &nat_height);
+ }
+ else /* GTK_ORIENTATION_VERTICAL */
+ {
+ gint min_width;
+
+ /* Make sure its no smaller than the minimum */
+ GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL);
+
+ /* This will segment the lines evenly and return the overall
+ * lengths of the split segments */
+ nat_height = min_height = segment_lines_for_size (table, MAX (width, min_width), NULL);
+ }
+
+#if 0
+ g_print ("get_height_for_width() called for width %d; returning min %d and nat %d\n",
+ width, min_height, nat_height);
+#endif
+
+ if (minimum_height)
+ *minimum_height = min_height;
+
+ if (natural_height)
+ *natural_height = nat_height;
+}
+
+static void
+egg_spread_table_get_width_for_height (GtkWidget *widget,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width)
+{
+ EggSpreadTable *table = EGG_SPREAD_TABLE (widget);
+ EggSpreadTablePrivate *priv = table->priv;
+ gint min_width = 0, nat_width = 0;
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ gint min_height;
+
+ /* Make sure its no smaller than the minimum */
+ GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_height, NULL);
+
+ /* This will segment the lines evenly and return the overall
+ * lengths of the split segments */
+ nat_width = min_width = segment_lines_for_size (table, MAX (height, min_height), NULL);
+ }
+ else /* GTK_ORIENTATION_VERTICAL */
+ {
+ /* Just return the minimum/natural height */
+ GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, &nat_width);
+ }
+
+#if 0
+ g_print ("get_width_for_height() called for height %d; returning min %d and nat %d\n",
+ height, min_width, nat_width);
+#endif
+
+ if (minimum_width)
+ *minimum_width = min_width;
+
+ if (natural_width)
+ *natural_width = nat_width;
+}
+
+static void
+allocate_child (EggSpreadTable *table,
+ GtkWidget *child,
+ gint item_offset,
+ gint line_offset,
+ gint item_size,
+ gint line_size)
+{
+ EggSpreadTablePrivate *priv = table->priv;
+ GtkAllocation widget_allocation;
+ GtkAllocation child_allocation;
+
+ gtk_widget_get_allocation (GTK_WIDGET (table), &widget_allocation);
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ child_allocation.x = widget_allocation.x + item_offset;
+ child_allocation.y = widget_allocation.y + line_offset;
+ child_allocation.width = item_size;
+ child_allocation.height = line_size;
+ }
+ else /* GTK_ORIENTATION_VERTICAL */
+ {
+ child_allocation.x = widget_allocation.x + line_offset;
+ child_allocation.y = widget_allocation.y + item_offset;
+ child_allocation.width = line_size;
+ child_allocation.height = item_size;
+ }
+
+ gtk_widget_size_allocate (child, &child_allocation);
+}
+
+static void
+egg_spread_table_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ EggSpreadTable *table = EGG_SPREAD_TABLE (widget);
+ EggSpreadTablePrivate *priv = table->priv;
+ GList *list;
+ gint *segments = NULL;
+ gint full_thickness;
+ gint i, j;
+ gint line_offset, item_offset;
+ gint line_thickness;
+ gint line_spacing;
+ gint item_spacing;
+ GtkOrientation opposite_orientation;
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ full_thickness = allocation->height;
+ else
+ full_thickness = allocation->width;
+
+ line_thickness = get_line_thickness (table, full_thickness);
+ line_spacing = LINE_SPACING (table);
+ item_spacing = ITEM_SPACING (table);
+ opposite_orientation = OPPOSITE_ORIENTATION (table);
+
+ segment_lines_for_size (table, full_thickness, &segments);
+
+ for (list = priv->children, line_offset = 0, i = 0;
+ i < priv->lines;
+ line_offset += line_thickness + line_spacing, i++)
+ {
+ for (j = 0, item_offset = 0; list && j < segments[i]; list = list->next)
+ {
+ GtkWidget *child = list->data;
+ gint child_size;
+
+ if (!gtk_widget_get_visible (child))
+ continue;
+
+ get_widget_size (child, priv->orientation,
+ line_thickness, NULL, &child_size);
+
+ allocate_child (table, child, item_offset, line_offset, child_size, line_thickness);
+
+ item_offset += child_size + item_spacing;
+
+ j++;
+ }
+ }
+
+ g_free (segments);
+}
+
+/*****************************************************
+ * GtkContainerClass *
+ *****************************************************/
+static void
+egg_spread_table_add (GtkContainer *container,
+ GtkWidget *widget)
+{
+ egg_spread_table_insert_child (EGG_SPREAD_TABLE (container), widget, -1);
+}
+
+
+static void
+egg_spread_table_remove (GtkContainer *container,
+ GtkWidget *widget)
+{
+ EggSpreadTable *table = EGG_SPREAD_TABLE (container);
+ EggSpreadTablePrivate *priv = table->priv;
+ GList *list;
+
+ list = g_list_find (priv->children, widget);
+
+ if (list)
+ {
+ gboolean was_visible = gtk_widget_get_visible (widget);
+
+ gtk_widget_unparent (widget);
+
+ priv->children = g_list_delete_link (priv->children, list);
+
+ if (was_visible && gtk_widget_get_visible (GTK_WIDGET (container)))
+ gtk_widget_queue_resize (GTK_WIDGET (container));
+ }
+}
+
+
+static void
+egg_spread_table_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ EggSpreadTable *table = EGG_SPREAD_TABLE (container);
+ EggSpreadTablePrivate *priv = table->priv;
+ GList *list;
+
+ for (list = priv->children; list; list = list->next)
+ (* callback) ((GtkWidget *)list->data, callback_data);
+}
+
+static GType
+egg_spread_table_child_type (G_GNUC_UNUSED GtkContainer *container)
+{
+ return GTK_TYPE_WIDGET;
+}
+
+/*****************************************************
+ * API *
+ *****************************************************/
+
+/**
+ * egg_spread_table_new:
+ * @orientation: The #GtkOrientation for the #EggSpreadTable
+ * @lines: The fixed amount of lines to distribute children to.
+ *
+ * Creates a #EggSpreadTable.
+ *
+ * Returns: A new #EggSpreadTable container
+ */
+GtkWidget *
+egg_spread_table_new (GtkOrientation orientation,
+ guint lines)
+{
+ return (GtkWidget *)g_object_new (EGG_TYPE_SPREAD_TABLE,
+ "orientation", orientation,
+ "lines", lines,
+ NULL);
+}
+
+/**
+ * egg_spread_table_insert_child:
+ * @spread_table: An #EggSpreadTable
+ * @widget: the child #GtkWidget to add
+ * @index: the position in the child list to insert, specify -1 to append to the list.
+ *
+ * Adds a child to an #EggSpreadTable with its packing options set
+ */
+void
+egg_spread_table_insert_child (EggSpreadTable *table,
+ GtkWidget *child,
+ gint index)
+{
+ EggSpreadTablePrivate *priv;
+ GList *list;
+
+ g_return_if_fail (EGG_IS_SPREAD_TABLE (table));
+ g_return_if_fail (GTK_IS_WIDGET (child));
+
+ priv = table->priv;
+
+ list = g_list_find (priv->children, child);
+ g_return_if_fail (list == NULL);
+
+ priv->children = g_list_insert (priv->children, child, index);
+
+ gtk_widget_set_parent (child, GTK_WIDGET (table));
+}
+
+
+
+/**
+ * egg_spread_table_get_child_line:
+ * @table: A #EggSpreadTable
+ * @child: A Child of the @table.
+ * @size: A size in the opposing orientation of @table
+ *
+ * Gets the line index in which @child would be positioned
+ * if @table were to be allocated @size in the opposing
+ * orientation of @table.
+ *
+ * For instance, if the @table is oriented vertically,
+ * this function will return @child's column if @table
+ * were to be allocated @size width.
+ *
+ * Returns: the line index @child would be positioned in
+ * for @size (starting from 0).
+ */
+guint
+egg_spread_table_get_child_line (EggSpreadTable *table,
+ GtkWidget *child,
+ gint size)
+
+{
+ EggSpreadTablePrivate *priv;
+ gint *segments = NULL;
+ gint i, child_count, child_idx = 0;
+ GList *l;
+
+ g_return_val_if_fail (EGG_IS_SPREAD_TABLE (table), 0);
+ g_return_val_if_fail (GTK_IS_WIDGET (child), 0);
+
+ priv = table->priv;
+
+ segment_lines_for_size (table, size, &segments);
+
+ /* Get child index in list */
+ l = g_list_find (priv->children, child);
+ g_return_val_if_fail (l != NULL, 0);
+
+ child_idx = g_list_position (priv->children, l);
+
+ for (i = 0, child_count = 0; i < priv->lines; i++)
+ {
+ child_count += segments[i];
+
+ if (child_idx < child_count)
+ break;
+ }
+
+ g_assert (i < priv->lines);
+
+ g_free (segments);
+
+ return i;
+}
+
+
+/**
+ * egg_spread_table_set_lines:
+ * @table: A #EggSpreadTable
+ * @lines: The amount of evenly allocated child segments.
+ *
+ * Sets the fixed amount of lines (rows or columns) to
+ * distribute children to.
+ *
+ * <note><para>Space will be allocated for all lines even
+ * if there are not enough children to be placed on every
+ * line, for instance if @lines is set to 4 and the table
+ * has only 3 children; then the last line will appear empty.</para></note>
+ */
+void
+egg_spread_table_set_lines (EggSpreadTable *table,
+ guint lines)
+{
+ EggSpreadTablePrivate *priv;
+
+ g_return_if_fail (EGG_IS_SPREAD_TABLE (table));
+ g_return_if_fail (lines > 0);
+
+ priv = table->priv;
+
+ if (priv->lines != lines)
+ {
+ priv->lines = lines;
+
+ gtk_widget_queue_resize (GTK_WIDGET (table));
+
+ g_object_notify (G_OBJECT (table), "lines");
+ }
+}
+
+/**
+ * egg_spread_table_get_lines:
+ * @table: An #EggSpreadTable
+ *
+ * Gets the fixed amount of lines (rows or columns) to
+ * distribute children to.
+ *
+ * Returns: The amount of lines.
+ */
+guint
+egg_spread_table_get_lines (EggSpreadTable *table)
+{
+ g_return_val_if_fail (EGG_IS_SPREAD_TABLE (table), 0);
+
+ return table->priv->lines;
+}
+
+
+/**
+ * egg_spread_table_set_vertical_spacing:
+ * @table: An #EggSpreadTable
+ * @spacing: The spacing to use.
+ *
+ * Sets the vertical space to add between children.
+ */
+void
+egg_spread_table_set_vertical_spacing (EggSpreadTable *table,
+ guint spacing)
+{
+ EggSpreadTablePrivate *priv;
+
+ g_return_if_fail (EGG_IS_SPREAD_TABLE (table));
+
+ priv = table->priv;
+
+ if (priv->vertical_spacing != spacing)
+ {
+ priv->vertical_spacing = spacing;
+
+ gtk_widget_queue_resize (GTK_WIDGET (table));
+
+ g_object_notify (G_OBJECT (table), "vertical-spacing");
+ }
+}
+
+/**
+ * egg_spread_table_get_vertical_spacing:
+ * @table: An #EggSpreadTable
+ *
+ * Gets the vertical spacing.
+ *
+ * Returns: The vertical spacing.
+ */
+guint
+egg_spread_table_get_vertical_spacing (EggSpreadTable *table)
+{
+ g_return_val_if_fail (EGG_IS_SPREAD_TABLE (table), 0);
+
+ return table->priv->vertical_spacing;
+}
+
+/**
+ * egg_spread_table_set_horizontal_spacing:
+ * @table: A #EggSpreadTable
+ * @spacing: The spacing to use.
+ *
+ * Sets the horizontal space to add between children.
+ */
+void
+egg_spread_table_set_horizontal_spacing (EggSpreadTable *table,
+ guint spacing)
+{
+ EggSpreadTablePrivate *priv;
+
+ g_return_if_fail (EGG_IS_SPREAD_TABLE (table));
+
+ priv = table->priv;
+
+ if (priv->horizontal_spacing != spacing)
+ {
+ priv->horizontal_spacing = spacing;
+
+ gtk_widget_queue_resize (GTK_WIDGET (table));
+
+ g_object_notify (G_OBJECT (table), "horizontal-spacing");
+ }
+}
+
+/**
+ * egg_spread_table_get_horizontal_spacing:
+ * @table: A #EggSpreadTable
+ *
+ * Gets the horizontal spacing.
+ *
+ * Returns: The horizontal spacing.
+ */
+guint
+egg_spread_table_get_horizontal_spacing (EggSpreadTable *table)
+{
+ g_return_val_if_fail (EGG_IS_SPREAD_TABLE (table), 0);
+
+ return table->priv->horizontal_spacing;
+}
diff --git a/libegg/spreadtable/eggspreadtable.h b/libegg/spreadtable/eggspreadtable.h
new file mode 100644
index 0000000..7531a80
--- /dev/null
+++ b/libegg/spreadtable/eggspreadtable.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 Openismus GmbH
+ *
+ * Authors:
+ * Tristan Van Berkom <tristanvb openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EGG_SPREAD_TABLE_H__
+#define __EGG_SPREAD_TABLE_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+
+#define EGG_TYPE_SPREAD_TABLE (egg_spread_table_get_type ())
+#define EGG_SPREAD_TABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SPREAD_TABLE, EggSpreadTable))
+#define EGG_SPREAD_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SPREAD_TABLE, EggSpreadTableClass))
+#define EGG_IS_SPREAD_TABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SPREAD_TABLE))
+#define EGG_IS_SPREAD_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SPREAD_TABLE))
+#define EGG_SPREAD_TABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SPREAD_TABLE, EggSpreadTableClass))
+
+typedef struct _EggSpreadTable EggSpreadTable;
+typedef struct _EggSpreadTablePrivate EggSpreadTablePrivate;
+typedef struct _EggSpreadTableClass EggSpreadTableClass;
+
+
+struct _EggSpreadTable
+{
+ GtkContainer parent_instance;
+
+ /*< private >*/
+ EggSpreadTablePrivate *priv;
+};
+
+struct _EggSpreadTableClass
+{
+ GtkContainerClass parent_class;
+};
+
+
+GType egg_spread_table_get_type (void) G_GNUC_CONST;
+
+
+GtkWidget *egg_spread_table_new (GtkOrientation orientation,
+ guint lines);
+
+void egg_spread_table_insert_child (EggSpreadTable *table,
+ GtkWidget *child,
+ gint index);
+
+guint egg_spread_table_get_child_line (EggSpreadTable *table,
+ GtkWidget *child,
+ gint size);
+
+void egg_spread_table_set_lines (EggSpreadTable *table,
+ guint lines);
+guint egg_spread_table_get_lines (EggSpreadTable *table);
+
+void egg_spread_table_set_horizontal_spacing (EggSpreadTable *table,
+ guint spacing);
+guint egg_spread_table_get_horizontal_spacing (EggSpreadTable *table);
+
+void egg_spread_table_set_vertical_spacing (EggSpreadTable *table,
+ guint spacing);
+guint egg_spread_table_get_vertical_spacing (EggSpreadTable *table);
+
+
+
+
+G_END_DECLS
+
+
+#endif /* __EGG_SPREAD_TABLE_H__ */
diff --git a/libegg/spreadtable/testspreadtable.c b/libegg/spreadtable/testspreadtable.c
new file mode 100644
index 0000000..2da5073
--- /dev/null
+++ b/libegg/spreadtable/testspreadtable.c
@@ -0,0 +1,393 @@
+/* testspreadtable.c
+ * Copyright (C) 2010 Openismus GmbH
+ *
+ * Author:
+ * Tristan Van Berkom <tristanvb openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <eggspreadtable.h>
+
+enum {
+ IMAGE_NONE,
+ IMAGE_SMALL,
+ IMAGE_LARGE,
+ IMAGE_HUGE
+};
+
+#define INITIAL_HSPACING 2
+#define INITIAL_VSPACING 2
+#define INITIAL_LINES 3
+#define INITIAL_HALIGN GTK_ALIGN_FILL
+#define INITIAL_IMAGE IMAGE_NONE
+#define INITIAL_IMAGE_INDEX 10
+
+static GtkWidget *paper = NULL;
+static GtkAlign child_halign = INITIAL_HALIGN;
+static int test_image = INITIAL_IMAGE;
+static int test_image_index = INITIAL_IMAGE_INDEX;
+
+static void
+populate_spread_table_wrappy (EggSpreadTable *spread_table)
+{
+ GList *children, *l;
+ GtkWidget *widget, *frame;
+ gsize i;
+
+ const gchar *strings[] = {
+ "These are", "some wrappy label", "texts", "of various", "lengths.",
+ "They should always be", "shown", "consecutively. Except it's",
+ "hard to say", "where exactly the", "label", "will wrap", "and where exactly",
+ "the actual", "container", "will wrap.", "This label is really really really long !",
+ "Let's add some more", "labels to the",
+ "mix. Just to", "make sure we", "got something to work", "with here."
+ };
+
+ /* Remove all children first */
+ children = gtk_container_get_children (GTK_CONTAINER (paper));
+ for (l = children; l; l = l->next)
+ {
+ GtkWidget *child = l->data;
+
+ gtk_container_remove (GTK_CONTAINER (paper), child);
+ }
+ g_list_free (children);
+
+ for (i = 0; i < G_N_ELEMENTS (strings); i++)
+ {
+ widget = gtk_label_new (strings[i]);
+ frame = gtk_frame_new (NULL);
+ gtk_widget_show (widget);
+ gtk_widget_show (frame);
+
+ gtk_container_add (GTK_CONTAINER (frame), widget);
+
+ gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
+ gtk_label_set_line_wrap_mode (GTK_LABEL (widget), PANGO_WRAP_WORD);
+ gtk_label_set_width_chars (GTK_LABEL (widget), 10);
+
+ gtk_widget_set_halign (frame, child_halign);
+
+ egg_spread_table_insert_child (EGG_SPREAD_TABLE (spread_table), frame, -1);
+ }
+
+ /* Insert an image into the mix */
+ if (test_image)
+ {
+ widget = gtk_image_new_from_file ("apple-red.png");
+
+ switch (test_image)
+ {
+ case IMAGE_SMALL:
+ gtk_widget_set_size_request (widget, 100, 100);
+ break;
+ case IMAGE_LARGE:
+ gtk_widget_set_size_request (widget, 150, 200);
+ break;
+ case IMAGE_HUGE:
+ gtk_widget_set_size_request (widget, 200, 300);
+ break;
+ default:
+ break;
+ }
+
+ frame = gtk_frame_new (NULL);
+ gtk_widget_show (widget);
+ gtk_widget_show (frame);
+
+ gtk_container_add (GTK_CONTAINER (frame), widget);
+ egg_spread_table_insert_child (EGG_SPREAD_TABLE (spread_table), frame, test_image_index);
+ }
+}
+
+static void
+orientation_changed (GtkComboBox *box,
+ EggSpreadTable *paper)
+{
+ GtkOrientation orientation = gtk_combo_box_get_active (box);
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (paper), orientation);
+}
+
+static void
+lines_changed (GtkSpinButton *button,
+ G_GNUC_UNUSED gpointer data)
+{
+ gint lines = gtk_spin_button_get_value_as_int (button);
+
+ egg_spread_table_set_lines (EGG_SPREAD_TABLE (paper), lines);
+}
+
+static void
+spacing_changed (GtkSpinButton *button,
+ gpointer data)
+{
+ GtkOrientation orientation = GPOINTER_TO_INT (data);
+ gint state = gtk_spin_button_get_value_as_int (button);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ egg_spread_table_set_horizontal_spacing (EGG_SPREAD_TABLE (paper), state);
+ else
+ egg_spread_table_set_vertical_spacing (EGG_SPREAD_TABLE (paper), state);
+}
+
+
+
+static void
+halign_changed (GtkComboBox *box,
+ EggSpreadTable *paper)
+{
+ child_halign = gtk_combo_box_get_active (box);
+
+ populate_spread_table_wrappy (EGG_SPREAD_TABLE (paper));
+}
+
+static void
+test_image_changed (GtkComboBox *box,
+ EggSpreadTable *paper)
+{
+ test_image = gtk_combo_box_get_active (box);
+
+ populate_spread_table_wrappy (EGG_SPREAD_TABLE (paper));
+}
+
+
+
+static void
+test_image_index_changed (GtkSpinButton *button,
+ G_GNUC_UNUSED gpointer data)
+{
+ test_image_index = gtk_spin_button_get_value_as_int (button);
+
+ populate_spread_table_wrappy (EGG_SPREAD_TABLE (paper));
+}
+
+
+static GtkWidget *
+create_window (void)
+{
+ GtkWidget *window;
+ GtkWidget *hbox, *vbox, *widget;
+ GtkWidget *swindow, *frame, *expander;
+ GtkWidget *paper_cntl, *items_cntl;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ hbox = gtk_hbox_new (FALSE, 2);
+ vbox = gtk_vbox_new (FALSE, 6);
+
+ gtk_container_set_border_width (GTK_CONTAINER (window), 8);
+
+ gtk_widget_show (vbox);
+ gtk_widget_show (hbox);
+ gtk_container_add (GTK_CONTAINER (window), hbox);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new ("SpreadTable");
+ gtk_widget_show (frame);
+ gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
+
+ swindow = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ gtk_widget_show (swindow);
+ gtk_container_add (GTK_CONTAINER (frame), swindow);
+
+ paper = egg_spread_table_new (GTK_ORIENTATION_VERTICAL, INITIAL_LINES);
+ egg_spread_table_set_vertical_spacing (EGG_SPREAD_TABLE (paper), INITIAL_VSPACING);
+ egg_spread_table_set_horizontal_spacing (EGG_SPREAD_TABLE (paper), INITIAL_HSPACING);
+ gtk_widget_show (paper);
+
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (swindow), paper);
+
+ /* Add SpreadTable test control frame */
+ expander = gtk_expander_new ("SpreadTable controls");
+ gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);
+ paper_cntl = gtk_vbox_new (FALSE, 2);
+ gtk_widget_show (paper_cntl);
+ gtk_widget_show (expander);
+ gtk_container_add (GTK_CONTAINER (expander), paper_cntl);
+ gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, FALSE, 0);
+
+ /* Add Orientation control */
+ widget = gtk_combo_box_text_new ();
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Horizontal");
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Vertical");
+ gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 1);
+ gtk_widget_show (widget);
+
+ gtk_widget_set_tooltip_text (widget, "Set the spread_table orientation");
+ gtk_box_pack_start (GTK_BOX (paper_cntl), widget, FALSE, FALSE, 0);
+
+ g_signal_connect (G_OBJECT (widget), "changed",
+ G_CALLBACK (orientation_changed), paper);
+
+
+ /* Add horizontal/vertical spacing controls */
+ hbox = gtk_hbox_new (FALSE, 2);
+ gtk_widget_show (hbox);
+
+ widget = gtk_label_new ("H Spacing");
+ gtk_widget_show (widget);
+ gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
+
+ widget = gtk_spin_button_new_with_range (0, 30, 1);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), INITIAL_HSPACING);
+ gtk_widget_show (widget);
+
+ gtk_widget_set_tooltip_text (widget, "Set the horizontal spacing between children");
+ gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+
+ g_signal_connect (G_OBJECT (widget), "changed",
+ G_CALLBACK (spacing_changed), GINT_TO_POINTER (GTK_ORIENTATION_HORIZONTAL));
+ g_signal_connect (G_OBJECT (widget), "value-changed",
+ G_CALLBACK (spacing_changed), GINT_TO_POINTER (GTK_ORIENTATION_HORIZONTAL));
+
+ gtk_box_pack_start (GTK_BOX (paper_cntl), hbox, FALSE, FALSE, 0);
+
+ hbox = gtk_hbox_new (FALSE, 2);
+ gtk_widget_show (hbox);
+
+ widget = gtk_label_new ("V Spacing");
+ gtk_widget_show (widget);
+ gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
+
+ widget = gtk_spin_button_new_with_range (0, 30, 1);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), INITIAL_VSPACING);
+ gtk_widget_show (widget);
+
+ gtk_widget_set_tooltip_text (widget, "Set the vertical spacing between children");
+ gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+
+ g_signal_connect (G_OBJECT (widget), "changed",
+ G_CALLBACK (spacing_changed), GINT_TO_POINTER (GTK_ORIENTATION_VERTICAL));
+ g_signal_connect (G_OBJECT (widget), "value-changed",
+ G_CALLBACK (spacing_changed), GINT_TO_POINTER (GTK_ORIENTATION_VERTICAL));
+
+ gtk_box_pack_start (GTK_BOX (paper_cntl), hbox, FALSE, FALSE, 0);
+
+
+ /* Add lines controls */
+ hbox = gtk_hbox_new (FALSE, 2);
+ gtk_widget_show (hbox);
+
+ widget = gtk_label_new ("Lines");
+ gtk_widget_show (widget);
+ gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
+
+ widget = gtk_spin_button_new_with_range (1, 30, 1);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), INITIAL_LINES);
+ gtk_widget_show (widget);
+
+ gtk_widget_set_tooltip_text (widget, "Set the horizontal spacing between children");
+ gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+
+ g_signal_connect (G_OBJECT (widget), "changed",
+ G_CALLBACK (lines_changed), NULL);
+ g_signal_connect (G_OBJECT (widget), "value-changed",
+ G_CALLBACK (lines_changed), NULL);
+
+ gtk_box_pack_start (GTK_BOX (paper_cntl), hbox, FALSE, FALSE, 0);
+
+
+ /* Add test items control frame */
+ expander = gtk_expander_new ("Test item controls");
+ gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);
+ items_cntl = gtk_vbox_new (FALSE, 2);
+ gtk_widget_show (items_cntl);
+ gtk_widget_show (expander);
+ gtk_container_add (GTK_CONTAINER (expander), items_cntl);
+ gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, FALSE, 0);
+
+ /* Add child halign control */
+ widget = gtk_combo_box_text_new ();
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Fill");
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Start");
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "End");
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Center");
+ gtk_combo_box_set_active (GTK_COMBO_BOX (widget), INITIAL_HALIGN);
+ gtk_widget_show (widget);
+
+ gtk_widget_set_tooltip_text (widget, "Set the children's halign property");
+ gtk_box_pack_start (GTK_BOX (items_cntl), widget, FALSE, FALSE, 0);
+
+ g_signal_connect (G_OBJECT (widget), "changed",
+ G_CALLBACK (halign_changed), paper);
+
+
+ /* Add image control */
+ widget = gtk_combo_box_text_new ();
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "None");
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Small");
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Large");
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Huge");
+ gtk_combo_box_set_active (GTK_COMBO_BOX (widget), INITIAL_IMAGE);
+ gtk_widget_show (widget);
+
+ gtk_widget_set_tooltip_text (widget, "Use an image to test the container");
+ gtk_box_pack_start (GTK_BOX (items_cntl), widget, FALSE, FALSE, 0);
+
+ g_signal_connect (G_OBJECT (widget), "changed",
+ G_CALLBACK (test_image_changed), paper);
+
+
+ /* Add horizontal/vertical spacing controls */
+ hbox = gtk_hbox_new (FALSE, 2);
+ gtk_widget_show (hbox);
+
+ widget = gtk_label_new ("Image index");
+ gtk_widget_show (widget);
+ gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
+
+ widget = gtk_spin_button_new_with_range (0, 25, 1);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), INITIAL_IMAGE_INDEX);
+ gtk_widget_show (widget);
+
+ gtk_widget_set_tooltip_text (widget, "Set the child list index for the optional test image");
+ gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (items_cntl), hbox, FALSE, FALSE, 0);
+
+ g_signal_connect (G_OBJECT (widget), "changed",
+ G_CALLBACK (test_image_index_changed), GINT_TO_POINTER (GTK_ORIENTATION_HORIZONTAL));
+ g_signal_connect (G_OBJECT (widget), "value-changed",
+ G_CALLBACK (test_image_index_changed), GINT_TO_POINTER (GTK_ORIENTATION_HORIZONTAL));
+
+ populate_spread_table_wrappy (EGG_SPREAD_TABLE (paper));
+
+ gtk_window_set_default_size (GTK_WINDOW (window), 500, 400);
+
+ return window;
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+
+ gtk_init (&argc, &argv);
+
+ window = create_window ();
+
+ g_signal_connect (window, "delete-event",
+ G_CALLBACK (gtk_main_quit), window);
+
+ gtk_widget_show (window);
+
+ gtk_main ();
+
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]