[glom/spread-table] Use EggSpreadTable instead of GtkSpreadTable (not added to GTK+).



commit 866dd53f8c717f2ce6aa63f3f88b6a28a3e68621
Author: Murray Cumming <murrayc murrayc com>
Date:   Fri Nov 5 15:54:48 2010 +0100

    Use EggSpreadTable instead of GtkSpreadTable (not added to GTK+).
    
    * glom/utility_widgets/eggspreadtable/eggspreadtable.[h|cc]:
    * glom/utility_widgets/eggspreadtable/testspreadtable.c
    * glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.[h|cc]:
    * glom/utility_widgets/eggspreadtablemm/private/eggspreadtablemm_p.
    h: New files.
    * glom/Makefile_glom.am
    * glom/Makefile_tests.am: Mention the new files.
    * glom/utility_widgets/flowtable.[h|cc]: Use Egg::SpreadTable instead of
    Gtk::SpreadTable.

 ChangeLog                                          |   14 +
 Makefile_glom.am                                   |    5 +
 Makefile_tests.am                                  |    8 +-
 .../eggspreadtable/eggspreadtable.c                | 1126 ++++++++++++++++++++
 .../eggspreadtable/eggspreadtable.h                |   89 ++
 .../eggspreadtable/testspreadtable.c               |  393 +++++++
 .../eggspreadtablemm/eggspreadtablemm.cc           |  230 ++++
 .../eggspreadtablemm/eggspreadtablemm.h            |  202 ++++
 .../eggspreadtablemm/private/eggspreadtablemm_p.h  |   45 +
 glom/utility_widgets/flowtable.cc                  |    6 +-
 glom/utility_widgets/flowtable.h                   |    3 +-
 po/POTFILES.in                                     |    1 +
 12 files changed, 2116 insertions(+), 6 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index b07f324..9f7eb49 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2010-11-05  Murray Cumming  <murrayc murrayc com>
+
+	Use EggSpreadTable instead of GtkSpreadTable (not added to GTK+).
+
+	* glom/utility_widgets/eggspreadtable/eggspreadtable.[h|cc]:
+	* glom/utility_widgets/eggspreadtable/testspreadtable.c
+	* glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.[h|cc]:
+	* glom/utility_widgets/eggspreadtablemm/private/eggspreadtablemm_p.
+	h: New files.
+	* glom/Makefile_glom.am
+	* glom/Makefile_tests.am: Mention the new files.
+	* glom/utility_widgets/flowtable.[h|cc]: Use Egg::SpreadTable instead of
+	Gtk::SpreadTable.
+
 2010-11-04  Murray Cumming  <murrayc murrayc com>
 
 	Remove the gconfmm dependency, because we don't use it.
diff --git a/Makefile_glom.am b/Makefile_glom.am
index d8aae46..0ab3ebe 100644
--- a/Makefile_glom.am
+++ b/Makefile_glom.am
@@ -165,6 +165,11 @@ glom_source_files = \
 	glom/utility_widgets/dialog_properties.h			\
 	glom/utility_widgets/flowtable.cc				\
 	glom/utility_widgets/flowtable.h				\
+	glom/utility_widgets/eggspreadtable/eggspreadtable.c \
+	glom/utility_widgets/eggspreadtable/eggspreadtable.h \
+	glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.c \
+	glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.h \
+	glom/utility_widgets/eggspreadtablemm/private/eggspreadtablemm_p.h \
 	glom/utility_widgets/imageglom.cc				\
 	glom/utility_widgets/imageglom.h				\
 	glom/utility_widgets/layoutwidgetbase.cc			\
diff --git a/Makefile_tests.am b/Makefile_tests.am
index cdb43d2..0bf7a2c 100644
--- a/Makefile_tests.am
+++ b/Makefile_tests.am
@@ -56,7 +56,7 @@ TESTS =	tests/test_document_load	\
 	tests/test_python_execute_script \
 	tests/test_selfhosting_new_empty \
 	tests/test_selfhosting_new_from_example
-	
+
 # These hang most of the time, but not always:
 #	tests/import/test_parsing \
 #	tests/import/test_signals
@@ -116,6 +116,11 @@ glom_libglom_test_sharedptr_layoutitem_LDADD = $(tests_ldadd)
 glom_utility_widgets_test_flowtable_SOURCES =	\
 	glom/utility_widgets/flowtable.cc	\
 	glom/utility_widgets/flowtable.h	\
+	glom/utility_widgets/eggspreadtable/eggspreadtable.c \
+	glom/utility_widgets/eggspreadtable/eggspreadtable.h \
+	glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.c \
+	glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.h \
+	glom/utility_widgets/eggspreadtablemm/private/eggspreadtablemm_p.h \
 	glom/utility_widgets/test_flowtable.cc
 glom_utility_widgets_test_flowtable_LDADD = $(GLOM_LIBS)
 
@@ -157,4 +162,3 @@ tests_import_test_signals_LDADD = $(GLOM_LIBS)
 tests_test_glade_derived_instantiation_LDADD = $(glom_all_libs)
 tests_test_selfhosting_new_empty_LDADD = $(glom_all_libs)
 tests_test_selfhosting_new_from_example_LDADD = $(glom_all_libs)
-
diff --git a/glom/utility_widgets/eggspreadtable/eggspreadtable.c b/glom/utility_widgets/eggspreadtable/eggspreadtable.c
new file mode 100644
index 0000000..2e9170e
--- /dev/null
+++ b/glom/utility_widgets/eggspreadtable/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,
+			 G_GNUC_UNUSED 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/glom/utility_widgets/eggspreadtable/eggspreadtable.h b/glom/utility_widgets/eggspreadtable/eggspreadtable.h
new file mode 100644
index 0000000..7531a80
--- /dev/null
+++ b/glom/utility_widgets/eggspreadtable/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/glom/utility_widgets/eggspreadtable/testspreadtable.c b/glom/utility_widgets/eggspreadtable/testspreadtable.c
new file mode 100644
index 0000000..2da5073
--- /dev/null
+++ b/glom/utility_widgets/eggspreadtable/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;
+}
diff --git a/glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.cc b/glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.cc
new file mode 100644
index 0000000..7cadf23
--- /dev/null
+++ b/glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.cc
@@ -0,0 +1,230 @@
+/*
+ *
+ * Copyright 2010 The gtkmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.h>
+#include <glom/utility_widgets/eggspreadtablemm/private/eggspreadtablemm_p.h>
+
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <glom/utility_widgets/eggspreadtable/eggspreadtable.h>
+
+namespace Egg
+{
+
+void SpreadTable::append_child(Widget& widget)
+{
+  insert_child(widget, -1 /* see the C documentation */);
+}
+
+} // namespace Egg
+
+namespace Glib
+{
+
+Egg::SpreadTable* wrap(EggSpreadTable* object, bool take_copy)
+{
+  return dynamic_cast<Egg::SpreadTable *> (Glib::wrap_auto ((GObject*)(object), take_copy));
+}
+
+} /* namespace Glib */
+
+namespace Egg
+{
+
+
+/* The *_Class implementation: */
+
+const Glib::Class& SpreadTable_Class::init()
+{
+  if(!gtype_) // create the GType if necessary
+  {
+    // Glib::Class has to know the class init function to clone custom types.
+    class_init_func_ = &SpreadTable_Class::class_init_function;
+
+    // This is actually just optimized away, apparently with no harm.
+    // Make sure that the parent type has been created.
+    //CppClassParent::CppObjectType::get_type();
+
+    // Create the wrapper type, with the same class/instance size as the base type.
+    register_derived_type(egg_spread_table_get_type());
+
+    // Add derived versions of interfaces, if the C type implements any interfaces:
+    Gtk::Orientable::add_interface(get_type());
+
+  }
+
+  return *this;
+}
+
+
+void SpreadTable_Class::class_init_function(void* g_class, void* class_data)
+{
+  BaseClassType *const klass = static_cast<BaseClassType*>(g_class);
+  CppClassParent::class_init_function(klass, class_data);
+
+
+}
+
+
+Glib::ObjectBase* SpreadTable_Class::wrap_new(GObject* o)
+{
+  return manage(new SpreadTable((EggSpreadTable*)(o)));
+
+}
+
+
+/* The implementation: */
+
+SpreadTable::SpreadTable(const Glib::ConstructParams& construct_params)
+:
+  Gtk::Container(construct_params)
+{
+  }
+
+SpreadTable::SpreadTable(EggSpreadTable* castitem)
+:
+  Gtk::Container((GtkContainer*)(castitem))
+{
+  }
+
+SpreadTable::~SpreadTable()
+{
+  destroy_();
+}
+
+SpreadTable::CppClassType SpreadTable::spreadtable_class_; // initialize static member
+
+GType SpreadTable::get_type()
+{
+  return spreadtable_class_.init().get_type();
+}
+
+
+GType SpreadTable::get_base_type()
+{
+  return egg_spread_table_get_type();
+}
+
+
+SpreadTable::SpreadTable()
+:
+  // Mark this class as non-derived to allow C++ vfuncs to be skipped.
+  Glib::ObjectBase(0),
+  Gtk::Container(Glib::ConstructParams(spreadtable_class_.init()))
+{
+
+
+}
+
+SpreadTable::SpreadTable(Gtk::Orientation orientation, guint lines)
+:
+  // Mark this class as non-derived to allow C++ vfuncs to be skipped.
+  Glib::ObjectBase(0),
+  Gtk::Container(Glib::ConstructParams(spreadtable_class_.init(), "orientation", ((GtkOrientation)(orientation)), "lines", lines, static_cast<char*>(0)))
+{
+
+
+}
+
+void SpreadTable::insert_child(Gtk::Widget& widget, int index)
+{
+egg_spread_table_insert_child(gobj(), (widget).gobj(), index);
+}
+
+guint SpreadTable::get_child_line(const Gtk::Widget& child, int size) const
+{
+  return egg_spread_table_get_child_line(const_cast<EggSpreadTable*>(gobj()), const_cast<GtkWidget*>(child.gobj()), size);
+}
+
+void SpreadTable::set_lines(guint lines)
+{
+egg_spread_table_set_lines(gobj(), lines);
+}
+
+guint SpreadTable::get_lines() const
+{
+  return egg_spread_table_get_lines(const_cast<EggSpreadTable*>(gobj()));
+}
+
+void SpreadTable::set_vertical_spacing(guint spacing)
+{
+egg_spread_table_set_vertical_spacing(gobj(), spacing);
+}
+
+guint SpreadTable::get_vertical_spacing() const
+{
+  return egg_spread_table_get_vertical_spacing(const_cast<EggSpreadTable*>(gobj()));
+}
+
+void SpreadTable::set_horizontal_spacing(guint spacing)
+{
+egg_spread_table_set_horizontal_spacing(gobj(), spacing);
+}
+
+guint SpreadTable::get_horizontal_spacing() const
+{
+  return egg_spread_table_get_horizontal_spacing(const_cast<EggSpreadTable*>(gobj()));
+}
+
+
+#ifdef GLIBMM_PROPERTIES_ENABLED
+Glib::PropertyProxy<guint> SpreadTable::property_vertical_spacing()
+{
+  return Glib::PropertyProxy<guint>(this, "vertical-spacing");
+}
+#endif //GLIBMM_PROPERTIES_ENABLED
+
+#ifdef GLIBMM_PROPERTIES_ENABLED
+Glib::PropertyProxy_ReadOnly<guint> SpreadTable::property_vertical_spacing() const
+{
+  return Glib::PropertyProxy_ReadOnly<guint>(this, "vertical-spacing");
+}
+#endif //GLIBMM_PROPERTIES_ENABLED
+
+#ifdef GLIBMM_PROPERTIES_ENABLED
+Glib::PropertyProxy<guint> SpreadTable::property_horizontal_spacing()
+{
+  return Glib::PropertyProxy<guint>(this, "horizontal-spacing");
+}
+#endif //GLIBMM_PROPERTIES_ENABLED
+
+#ifdef GLIBMM_PROPERTIES_ENABLED
+Glib::PropertyProxy_ReadOnly<guint> SpreadTable::property_horizontal_spacing() const
+{
+  return Glib::PropertyProxy_ReadOnly<guint>(this, "horizontal-spacing");
+}
+#endif //GLIBMM_PROPERTIES_ENABLED
+
+#ifdef GLIBMM_PROPERTIES_ENABLED
+Glib::PropertyProxy<guint> SpreadTable::property_lines()
+{
+  return Glib::PropertyProxy<guint>(this, "lines");
+}
+#endif //GLIBMM_PROPERTIES_ENABLED
+
+#ifdef GLIBMM_PROPERTIES_ENABLED
+Glib::PropertyProxy_ReadOnly<guint> SpreadTable::property_lines() const
+{
+  return Glib::PropertyProxy_ReadOnly<guint>(this, "lines");
+}
+#endif //GLIBMM_PROPERTIES_ENABLED
+
+
+} // namespace Egg
diff --git a/glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.h b/glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.h
new file mode 100644
index 0000000..ce89c4d
--- /dev/null
+++ b/glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.h
@@ -0,0 +1,202 @@
+/* Copyright (C) 2010 The gtkmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _EGG_SPREADTABLE_H
+#define _EGG_SPREADTABLE_H
+
+#include <glibmm.h>
+#include <gtkmm/container.h>
+#include <gtkmm/orientable.h>
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+typedef struct _EggSpreadTable EggSpreadTable;
+typedef struct _EggSpreadTableClass EggSpreadTableClass;
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+
+namespace Egg
+{ class SpreadTable_Class; } // namespace Egg
+namespace Egg
+{
+
+class SpreadTable
+: public Gtk::Container
+{
+  public:
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+  typedef SpreadTable CppObjectType;
+  typedef SpreadTable_Class CppClassType;
+  typedef EggSpreadTable BaseObjectType;
+  typedef EggSpreadTableClass BaseClassType;
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+  virtual ~SpreadTable();
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+private:
+  friend class SpreadTable_Class;
+  static CppClassType spreadtable_class_;
+
+  // noncopyable
+  SpreadTable(const SpreadTable&);
+  SpreadTable& operator=(const SpreadTable&);
+
+protected:
+  explicit SpreadTable(const Glib::ConstructParams& construct_params);
+  explicit SpreadTable(EggSpreadTable* castitem);
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+public:
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+  static GType get_type()      G_GNUC_CONST;
+
+
+  static GType get_base_type() G_GNUC_CONST;
+#endif
+
+  ///Provides access to the underlying C GtkObject.
+  EggSpreadTable*       gobj()       { return reinterpret_cast<EggSpreadTable*>(gobject_); }
+
+  ///Provides access to the underlying C GtkObject.
+  const EggSpreadTable* gobj() const { return reinterpret_cast<EggSpreadTable*>(gobject_); }
+
+
+public:
+  //C++ methods used to invoke GTK+ virtual functions:
+
+protected:
+  //GTK+ Virtual Functions (override these to change behaviour):
+
+  //Default Signal Handlers::
+
+
+private:
+
+
+public:
+  SpreadTable();
+  explicit SpreadTable(Gtk::Orientation orientation, guint lines);
+
+  //TODO: Is the default packing appropriate (and like the default for a Box::pack_start())?
+
+  void insert_child(Gtk::Widget& widget, int index);
+
+
+  guint get_child_line(const Gtk::Widget& child, int size) const;
+
+
+  void set_lines(guint lines);
+
+  guint get_lines() const;
+
+
+  void set_vertical_spacing(guint spacing);
+
+  guint get_vertical_spacing() const;
+
+
+  void set_horizontal_spacing(guint spacing);
+
+  guint get_horizontal_spacing() const;
+
+  //TODO: Documentation
+  void append_child(Widget& widget);
+
+  #ifdef GLIBMM_PROPERTIES_ENABLED
+/** The amount of vertical space between two children.
+   *
+   * You rarely need to use properties because there are get_ and set_ methods for almost all of them.
+   * @return A PropertyProxy that allows you to get or set the property of the value, or receive notification when
+   * the value of the property changes.
+   */
+  Glib::PropertyProxy<guint> property_vertical_spacing() ;
+#endif //#GLIBMM_PROPERTIES_ENABLED
+
+#ifdef GLIBMM_PROPERTIES_ENABLED
+/** The amount of vertical space between two children.
+   *
+   * You rarely need to use properties because there are get_ and set_ methods for almost all of them.
+   * @return A PropertyProxy that allows you to get or set the property of the value, or receive notification when
+   * the value of the property changes.
+   */
+  Glib::PropertyProxy_ReadOnly<guint> property_vertical_spacing() const;
+#endif //#GLIBMM_PROPERTIES_ENABLED
+
+  #ifdef GLIBMM_PROPERTIES_ENABLED
+/** The amount of horizontal space between two children.
+   *
+   * You rarely need to use properties because there are get_ and set_ methods for almost all of them.
+   * @return A PropertyProxy that allows you to get or set the property of the value, or receive notification when
+   * the value of the property changes.
+   */
+  Glib::PropertyProxy<guint> property_horizontal_spacing() ;
+#endif //#GLIBMM_PROPERTIES_ENABLED
+
+#ifdef GLIBMM_PROPERTIES_ENABLED
+/** The amount of horizontal space between two children.
+   *
+   * You rarely need to use properties because there are get_ and set_ methods for almost all of them.
+   * @return A PropertyProxy that allows you to get or set the property of the value, or receive notification when
+   * the value of the property changes.
+   */
+  Glib::PropertyProxy_ReadOnly<guint> property_horizontal_spacing() const;
+#endif //#GLIBMM_PROPERTIES_ENABLED
+
+  #ifdef GLIBMM_PROPERTIES_ENABLED
+/** The number of lines (rows/columns) to evenly distribute children to.
+   *
+   * You rarely need to use properties because there are get_ and set_ methods for almost all of them.
+   * @return A PropertyProxy that allows you to get or set the property of the value, or receive notification when
+   * the value of the property changes.
+   */
+  Glib::PropertyProxy<guint> property_lines() ;
+#endif //#GLIBMM_PROPERTIES_ENABLED
+
+#ifdef GLIBMM_PROPERTIES_ENABLED
+/** The number of lines (rows/columns) to evenly distribute children to.
+   *
+   * You rarely need to use properties because there are get_ and set_ methods for almost all of them.
+   * @return A PropertyProxy that allows you to get or set the property of the value, or receive notification when
+   * the value of the property changes.
+   */
+  Glib::PropertyProxy_ReadOnly<guint> property_lines() const;
+#endif //#GLIBMM_PROPERTIES_ENABLED
+
+
+};
+
+} // namespace Egg
+
+
+namespace Glib
+{
+  /** A Glib::wrap() method for this object.
+   *
+   * @param object The C instance.
+   * @param take_copy False if the result should take ownership of the C instance. True if it should take a new copy or ref.
+   * @result A C++ instance that wraps this C instance.
+   *
+   * @relates Egg::SpreadTable
+   */
+  Egg::SpreadTable* wrap(EggSpreadTable* object, bool take_copy = false);
+} //namespace Glib
+
+
+#endif /* _EGG_SPREADTABLE_H */
diff --git a/glom/utility_widgets/eggspreadtablemm/private/eggspreadtablemm_p.h b/glom/utility_widgets/eggspreadtablemm/private/eggspreadtablemm_p.h
new file mode 100644
index 0000000..eb95ba2
--- /dev/null
+++ b/glom/utility_widgets/eggspreadtablemm/private/eggspreadtablemm_p.h
@@ -0,0 +1,45 @@
+#ifndef _EGG_SPREADTABLE_P_H
+#define _EGG_SPREADTABLE_P_H
+
+
+#include <gtkmm/private/container_p.h>
+
+#include <glibmm/class.h>
+
+namespace Egg
+{
+
+class SpreadTable_Class : public Glib::Class
+{
+public:
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+  typedef SpreadTable CppObjectType;
+  typedef EggSpreadTable BaseObjectType;
+  typedef EggSpreadTableClass BaseClassType;
+  typedef Gtk::Container_Class CppClassParent;
+  typedef GtkContainerClass BaseClassParent;
+
+  friend class SpreadTable;
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+  const Glib::Class& init();
+
+
+  static void class_init_function(void* g_class, void* class_data);
+
+  static Glib::ObjectBase* wrap_new(GObject*);
+
+protected:
+
+  //Callbacks (default signal handlers):
+  //These will call the *_impl member methods, which will then call the existing default signal callbacks, if any.
+  //You could prevent the original default signal handlers being called by overriding the *_impl method.
+
+  //Callbacks (virtual functions):
+};
+
+
+} // namespace Egg
+
+
+#endif /* _EGG_SPREADTABLE_P_H */
diff --git a/glom/utility_widgets/flowtable.cc b/glom/utility_widgets/flowtable.cc
index 9947a76..f9a4e44 100644
--- a/glom/utility_widgets/flowtable.cc
+++ b/glom/utility_widgets/flowtable.cc
@@ -99,7 +99,7 @@ void FlowTable::delete_and_forget_hbox(Gtk::HBox* hbox)
   std::cout << G_STRFUNC << "Removing: hbox=" << hbox << std::endl;
   if(hbox->get_parent() == this)
   {
-    Gtk::SpreadTable::remove(*hbox);
+    Egg::SpreadTable::remove(*hbox);
   }
   else
   {
@@ -231,7 +231,7 @@ void FlowTable::remove(Gtk::Widget& first)
     return;
   }
 
-  Gtk::SpreadTable::remove(first);
+  Egg::SpreadTable::remove(first);
 }
 
 bool FlowTable::get_column_for_first_widget(const Gtk::Widget& first, guint& column) const
@@ -250,7 +250,7 @@ bool FlowTable::get_column_for_first_widget(const Gtk::Widget& first, guint& col
     if(!widget)
       continue;
 
-    //Get the widget that GtkSpreadTable thinks of as the child:
+    //Get the widget that EggSpreadTable thinks of as the child:
     const Gtk::Widget* child = 0;
 
     if(widget == &first) //It must be a single item.
diff --git a/glom/utility_widgets/flowtable.h b/glom/utility_widgets/flowtable.h
index 117b77d..8a426e3 100644
--- a/glom/utility_widgets/flowtable.h
+++ b/glom/utility_widgets/flowtable.h
@@ -22,12 +22,13 @@
 #define GLOM_UTILITYWIDGETS_FLOWTABLE_H
 
 #include <gtkmm.h>
+#include <glom/utility_widgets/eggspreadtablemm/eggspreadtablemm.h>
 #include "layoutwidgetbase.h"
 
 namespace Glom
 {
 
-class FlowTable : public Gtk::SpreadTable
+class FlowTable : public Egg::SpreadTable
 {
 public:
   FlowTable();
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 7d30d5e..fa69055 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -124,6 +124,7 @@ glom/mode_data/db_adddel/db_adddel.cc
 glom/mode_data/datawidget/dialog_choose_id.cc
 glom/utility_widgets/dialog_image_progress.cc
 glom/mode_data/datawidget/entry.cc
+glom/utility_widgets/eggspreadtable/eggspreadtable.c
 glom/utility_widgets/filechooserdialog_saveextras.cc
 glom/utility_widgets/imageglom.cc
 glom/utility_widgets/layouttoolbar.cc



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]