[gnome-shell/shell-toolkit] Import MxTable as StTable



commit 083eed140c601d059c41943384da1a0613d97e7b
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Tue Sep 29 23:13:29 2009 -0400

    Import MxTable as StTable
    
    Import table code from Mx library
    
    https://bugzilla.gnome.org/show_bug.cgi?id=596811

 src/Makefile-st.am        |    5 +
 src/st/st-table-child.c   |  805 +++++++++++++++++++++++++
 src/st/st-table-child.h   |  129 ++++
 src/st/st-table-private.h |   36 ++
 src/st/st-table.c         | 1475 +++++++++++++++++++++++++++++++++++++++++++++
 src/st/st-table.h         |  113 ++++
 6 files changed, 2563 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile-st.am b/src/Makefile-st.am
index d5e5dc4..bab1679 100644
--- a/src/Makefile-st.am
+++ b/src/Makefile-st.am
@@ -78,6 +78,8 @@ st_source_h =					\
     st/st-scroll-bar.h				\
     st/st-scroll-view.h				\
     st/st-subtexture.h				\
+    st/st-table.h				\
+    st/st-table-child.h				\
     st/st-texture-cache.h			\
     st/st-texture-frame.h			\
     st/st-theme.h				\
@@ -90,6 +92,7 @@ st_source_h =					\
 
 st_source_private_h =				\
     st/st-private.h				\
+    st/st-table-private.h			\
     st/st-theme-private.h
 
 # please, keep this sorted alphabetically
@@ -108,6 +111,8 @@ st_source_c =					\
     st/st-scroll-bar.c				\
     st/st-scroll-view.c				\
     st/st-subtexture.c				\
+    st/st-table.c				\
+    st/st-table-child.c				\
     st/st-texture-cache.c			\
     st/st-texture-frame.c			\
     st/st-theme.c				\
diff --git a/src/st/st-table-child.c b/src/st/st-table-child.c
new file mode 100644
index 0000000..eafa83d
--- /dev/null
+++ b/src/st/st-table-child.c
@@ -0,0 +1,805 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * st-table-child.h: Table child implementation
+ *
+ * Copyright 2008, 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Thomas Wood  <thomas wood intel com>
+ *
+ */
+
+#include "st-private.h"
+#include "st-table-child.h"
+#include "st-table-private.h"
+#include <st/st-widget.h>
+#include <st/st-table.h>
+
+/*
+ * ClutterChildMeta Implementation
+ */
+
+/**
+ * SECTION:st-table-child
+ * @short_description: The child property store for #StTable
+ *
+ * The #ClutterChildMeta implementation for the #StTable container widget.
+ *
+ */
+
+enum {
+  CHILD_PROP_0,
+
+  CHILD_PROP_COL,
+  CHILD_PROP_ROW,
+  CHILD_PROP_COL_SPAN,
+  CHILD_PROP_ROW_SPAN,
+  CHILD_PROP_X_EXPAND,
+  CHILD_PROP_Y_EXPAND,
+  CHILD_PROP_X_ALIGN,
+  CHILD_PROP_Y_ALIGN,
+  CHILD_PROP_X_FILL,
+  CHILD_PROP_Y_FILL,
+  CHILD_PROP_ALLOCATE_HIDDEN,
+};
+
+G_DEFINE_TYPE (StTableChild, st_table_child, CLUTTER_TYPE_CHILD_META);
+
+static void
+table_child_set_property (GObject      *gobject,
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  StTableChild *child = ST_TABLE_CHILD (gobject);
+  StTable *table = ST_TABLE (CLUTTER_CHILD_META(gobject)->container);
+
+  switch (prop_id)
+    {
+    case CHILD_PROP_COL:
+      child->col = g_value_get_int (value);
+      _st_table_update_row_col (table, -1, child->col);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+      break;
+    case CHILD_PROP_ROW:
+      child->row = g_value_get_int (value);
+      _st_table_update_row_col (table, child->row, -1);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+      break;
+    case CHILD_PROP_COL_SPAN:
+      child->col_span = g_value_get_int (value);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+      break;
+    case CHILD_PROP_ROW_SPAN:
+      child->row_span = g_value_get_int (value);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+      break;
+    case CHILD_PROP_X_EXPAND:
+      child->x_expand = g_value_get_boolean (value);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+      break;
+    case CHILD_PROP_Y_EXPAND:
+      child->y_expand = g_value_get_boolean (value);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+      break;
+    case CHILD_PROP_X_ALIGN:
+      child->x_align = g_value_get_double (value);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+      break;
+    case CHILD_PROP_Y_ALIGN:
+      child->y_align = g_value_get_double (value);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+      break;
+    case CHILD_PROP_X_FILL:
+      child->x_fill = g_value_get_boolean (value);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+      break;
+    case CHILD_PROP_Y_FILL:
+      child->y_fill = g_value_get_boolean (value);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+      break;
+    case CHILD_PROP_ALLOCATE_HIDDEN:
+      child->allocate_hidden = g_value_get_boolean (value);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+table_child_get_property (GObject    *gobject,
+                          guint       prop_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+  StTableChild *child = ST_TABLE_CHILD (gobject);
+
+  switch (prop_id)
+    {
+    case CHILD_PROP_COL:
+      g_value_set_int (value, child->col);
+      break;
+    case CHILD_PROP_ROW:
+      g_value_set_int (value, child->row);
+      break;
+    case CHILD_PROP_COL_SPAN:
+      g_value_set_int (value, child->col_span);
+      break;
+    case CHILD_PROP_ROW_SPAN:
+      g_value_set_int (value, child->row_span);
+      break;
+    case CHILD_PROP_X_EXPAND:
+      g_value_set_boolean (value, child->x_expand);
+      break;
+    case CHILD_PROP_Y_EXPAND:
+      g_value_set_boolean (value, child->y_expand);
+      break;
+    case CHILD_PROP_X_ALIGN:
+      g_value_set_double (value, child->x_align);
+      break;
+    case CHILD_PROP_Y_ALIGN:
+      g_value_set_double (value, child->y_align);
+      break;
+    case CHILD_PROP_X_FILL:
+      g_value_set_boolean (value, child->x_fill);
+      break;
+    case CHILD_PROP_Y_FILL:
+      g_value_set_boolean (value, child->y_fill);
+      break;
+    case CHILD_PROP_ALLOCATE_HIDDEN:
+      g_value_set_boolean (value, child->allocate_hidden);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+st_table_child_class_init (StTableChildClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GParamSpec *pspec;
+
+  gobject_class->set_property = table_child_set_property;
+  gobject_class->get_property = table_child_get_property;
+
+  pspec = g_param_spec_int ("col",
+                            "Column Number",
+                            "The column the widget resides in",
+                            0, G_MAXINT,
+                            0,
+                            ST_PARAM_READWRITE);
+
+  g_object_class_install_property (gobject_class, CHILD_PROP_COL, pspec);
+
+  pspec = g_param_spec_int ("row",
+                            "Row Number",
+                            "The row the widget resides in",
+                            0, G_MAXINT,
+                            0,
+                            ST_PARAM_READWRITE);
+
+  g_object_class_install_property (gobject_class, CHILD_PROP_ROW, pspec);
+
+  pspec = g_param_spec_int ("row-span",
+                            "Row Span",
+                            "The number of rows the widget should span",
+                            1, G_MAXINT,
+                            1,
+                            ST_PARAM_READWRITE);
+
+  g_object_class_install_property (gobject_class, CHILD_PROP_ROW_SPAN, pspec);
+
+  pspec = g_param_spec_int ("col-span",
+                            "Column Span",
+                            "The number of columns the widget should span",
+                            1, G_MAXINT,
+                            1,
+                            ST_PARAM_READWRITE);
+
+  g_object_class_install_property (gobject_class, CHILD_PROP_COL_SPAN, pspec);
+
+  pspec = g_param_spec_boolean ("x-expand",
+                                "X Expand",
+                                "Whether the child should receive priority "
+                                "when the container is allocating spare space "
+                                "on the horizontal axis",
+                                TRUE,
+                                ST_PARAM_READWRITE);
+
+  g_object_class_install_property (gobject_class, CHILD_PROP_X_EXPAND, pspec);
+
+  pspec = g_param_spec_boolean ("y-expand",
+                                "Y Expand",
+                                "Whether the child should receive priority "
+                                "when the container is allocating spare space "
+                                "on the vertical axis",
+                                TRUE,
+                                ST_PARAM_READWRITE);
+
+  g_object_class_install_property (gobject_class, CHILD_PROP_Y_EXPAND, pspec);
+
+  pspec = g_param_spec_double ("x-align",
+                               "X Alignment",
+                               "X alignment of the widget within the cell",
+                               0, 1,
+                               0.5,
+                               ST_PARAM_READWRITE);
+
+  g_object_class_install_property (gobject_class, CHILD_PROP_X_ALIGN, pspec);
+
+  pspec = g_param_spec_double ("y-align",
+                               "Y Alignment",
+                               "Y alignment of the widget within the cell",
+                               0, 1,
+                               0.5,
+                               ST_PARAM_READWRITE);
+
+  g_object_class_install_property (gobject_class, CHILD_PROP_Y_ALIGN, pspec);
+
+  pspec = g_param_spec_boolean ("x-fill",
+                                "X Fill",
+                                "Whether the child should be allocated its "
+                                "entire available space, or whether it should "
+                                "be squashed and aligned.",
+                                TRUE,
+                                ST_PARAM_READWRITE);
+
+  g_object_class_install_property (gobject_class, CHILD_PROP_X_FILL, pspec);
+
+  pspec = g_param_spec_boolean ("y-fill",
+                                "Y Fill",
+                                "Whether the child should be allocated its "
+                                "entire available space, or whether it should "
+                                "be squashed and aligned.",
+                                TRUE,
+                                ST_PARAM_READWRITE);
+
+  g_object_class_install_property (gobject_class, CHILD_PROP_Y_FILL, pspec);
+
+  pspec = g_param_spec_boolean ("allocate-hidden",
+                                "Allocate Hidden",
+                                "Whether the child should be allocate even "
+                                "if it is hidden",
+                                TRUE,
+                                ST_PARAM_READWRITE);
+
+  g_object_class_install_property (gobject_class, CHILD_PROP_ALLOCATE_HIDDEN, pspec);
+}
+
+static void
+st_table_child_init (StTableChild *self)
+{
+  self->col_span = 1;
+  self->row_span = 1;
+
+  self->x_align = 0.5;
+  self->y_align = 0.5;
+
+  self->x_expand = TRUE;
+  self->y_expand = TRUE;
+
+  self->x_fill = TRUE;
+  self->y_fill = TRUE;
+
+  self->allocate_hidden = TRUE;
+}
+
+static StTableChild*
+get_child_meta (StTable      *table,
+                ClutterActor *child)
+{
+  StTableChild *meta;
+
+  meta = (StTableChild*) clutter_container_get_child_meta (CLUTTER_CONTAINER (table), child);
+
+  return meta;
+}
+
+/**
+ * st_table_child_get_col_span:
+ * @table: an #StTable
+ * @child: a #ClutterActor
+ *
+ * Get the column span of the child. Defaults to 1.
+ *
+ * Returns: the column span of the child
+ */
+gint
+st_table_child_get_col_span (StTable      *table,
+                             ClutterActor *child)
+{
+  StTableChild *meta;
+
+  g_return_val_if_fail (ST_IS_TABLE (table), 0);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (child), 0);
+
+  meta = get_child_meta (table, child);
+
+  return meta->col_span;
+}
+
+/**
+ * st_table_child_set_col_span:
+ * @table: An #StTable
+ * @child: An #ClutterActor
+ * @span: The number of columns to span
+ *
+ * Set the column span of the child.
+ *
+ */
+void
+st_table_child_set_col_span (StTable      *table,
+                             ClutterActor *child,
+                             gint          span)
+{
+  StTableChild *meta;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (CLUTTER_IS_ACTOR (child));
+  g_return_if_fail (span > 1);
+
+  meta = get_child_meta (table, child);
+
+  meta->col_span = span;
+
+  clutter_actor_queue_relayout (child);
+}
+
+/**
+ * st_table_child_get_row_span:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ *
+ * Get the row span of the child. Defaults to 1.
+ *
+ * Returns: the row span of the child
+ */
+gint
+st_table_child_get_row_span (StTable      *table,
+                             ClutterActor *child)
+{
+  StTableChild *meta;
+
+  g_return_val_if_fail (ST_IS_TABLE (table), 0);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (child), 0);
+
+  meta = get_child_meta (table, child);
+
+  return meta->row_span;
+}
+
+/**
+ * st_table_child_set_row_span:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ * @span: the number of rows to span
+ *
+ * Set the row span of the child.
+ *
+ */
+void
+st_table_child_set_row_span (StTable      *table,
+                             ClutterActor *child,
+                             gint          span)
+{
+  StTableChild *meta;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (CLUTTER_IS_ACTOR (child));
+  g_return_if_fail (span > 1);
+
+  meta = get_child_meta (table, child);
+
+  meta->row_span = span;
+
+  clutter_actor_queue_relayout (child);
+}
+
+/**
+ * st_table_child_get_x_fill:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ *
+ * Get the x-fill state of the child
+ *
+ * Returns: #TRUE if the child is set to x-fill
+ */
+gboolean
+st_table_child_get_x_fill (StTable      *table,
+                           ClutterActor *child)
+{
+  StTableChild *meta;
+
+  g_return_val_if_fail (ST_IS_TABLE (table), 0);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (child), 0);
+
+  meta = get_child_meta (table, child);
+
+  return meta->x_fill;
+}
+
+/**
+ * st_table_child_set_x_fill:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ * @fill: the fill state
+ *
+ * Set the fill state of the child on the x-axis. This will cause the child to
+ * be allocated the maximum available space.
+ *
+ */
+void
+st_table_child_set_x_fill (StTable      *table,
+                           ClutterActor *child,
+                           gboolean      fill)
+{
+  StTableChild *meta;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (CLUTTER_IS_ACTOR (child));
+
+  meta = get_child_meta (table, child);
+
+  meta->x_fill = fill;
+
+  clutter_actor_queue_relayout (child);
+}
+
+
+/**
+ * st_table_child_get_y_fill:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ *
+ * Get the y-fill state of the child
+ *
+ * Returns: #TRUE if the child is set to y-fill
+ */
+gboolean
+st_table_child_get_y_fill (StTable      *table,
+                           ClutterActor *child)
+{
+  StTableChild *meta;
+
+  g_return_val_if_fail (ST_IS_TABLE (table), 0);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (child), 0);
+
+  meta = get_child_meta (table, child);
+
+  return meta->y_fill;
+}
+
+/**
+ * st_table_child_set_y_fill:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ * @fill: the fill state
+ *
+ * Set the fill state of the child on the y-axis. This will cause the child to
+ * be allocated the maximum available space.
+ *
+ */
+void
+st_table_child_set_y_fill (StTable      *table,
+                           ClutterActor *child,
+                           gboolean      fill)
+{
+  StTableChild *meta;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (CLUTTER_IS_ACTOR (child));
+
+  meta = get_child_meta (table, child);
+
+  meta->y_fill = fill;
+
+  clutter_actor_queue_relayout (child);
+}
+
+/**
+ * st_table_child_get_x_expand:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ *
+ * Get the x-expand property of the child
+ *
+ * Returns: #TRUE if the child is set to x-expand
+ */
+gboolean
+st_table_child_get_x_expand (StTable      *table,
+                             ClutterActor *child)
+{
+  StTableChild *meta;
+
+  g_return_val_if_fail (ST_IS_TABLE (table), 0);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (child), 0);
+
+  meta = get_child_meta (table, child);
+
+  return meta->x_expand;
+}
+
+/**
+ * st_table_child_set_x_expand:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ * @expand: the new value of the x expand child property
+ *
+ * Set x-expand on the child. This causes the column which the child
+ * resides in to be allocated any extra space if the allocation of the table is
+ * larger than the preferred size.
+ *
+ */
+void
+st_table_child_set_x_expand (StTable      *table,
+                             ClutterActor *child,
+                             gboolean      expand)
+{
+  StTableChild *meta;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (CLUTTER_IS_ACTOR (child));
+
+  meta = get_child_meta (table, child);
+
+  meta->x_expand = expand;
+
+  clutter_actor_queue_relayout (child);
+}
+
+/**
+ * st_table_child_set_y_expand:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ * @expand: the new value of the y-expand child property
+ *
+ * Set y-expand on the child. This causes the row which the child
+ * resides in to be allocated any extra space if the allocation of the table is
+ * larger than the preferred size.
+ *
+ */
+void
+st_table_child_set_y_expand (StTable      *table,
+                             ClutterActor *child,
+                             gboolean      expand)
+{
+  StTableChild *meta;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (CLUTTER_IS_ACTOR (child));
+
+  meta = get_child_meta (table, child);
+
+  meta->y_expand = expand;
+
+  clutter_actor_queue_relayout (child);
+}
+
+/**
+ * st_table_child_get_y_expand:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ *
+ * Get the y-expand property of the child.
+ *
+ * Returns: #TRUE if the child is set to y-expand
+ */
+gboolean
+st_table_child_get_y_expand (StTable      *table,
+                             ClutterActor *child)
+{
+  StTableChild *meta;
+
+  g_return_val_if_fail (ST_IS_TABLE (table), 0);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (child), 0);
+
+  meta = get_child_meta (table, child);
+
+  return meta->y_expand;
+}
+
+/**
+ * st_table_child_get_x_align:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ *
+ * Get the x-align value of the child
+ *
+ * Returns: An #StAlign value
+ */
+StAlign
+st_table_child_get_x_align (StTable      *table,
+                            ClutterActor *child)
+{
+  StTableChild *meta;
+
+  g_return_val_if_fail (ST_IS_TABLE (table), 0);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (child), 0);
+
+  meta = get_child_meta (table, child);
+
+  if (meta->x_align == 0.0)
+    return ST_ALIGN_START;
+  else if (meta->x_align == 1.0)
+    return ST_ALIGN_END;
+  else
+    return ST_ALIGN_MIDDLE;
+
+}
+
+/**
+ * st_table_child_set_x_align:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ * @align: A #StAlign value
+ *
+ * Set the alignment of the child within its cell. This will only have an effect
+ * if the the x-fill property is FALSE.
+ *
+ */
+void
+st_table_child_set_x_align (StTable      *table,
+                            ClutterActor *child,
+                            StAlign       align)
+{
+  StTableChild *meta;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (CLUTTER_IS_ACTOR (child));
+
+  meta = get_child_meta (table, child);
+
+  switch (align)
+    {
+    case ST_ALIGN_START:
+      meta->x_align = 0.0;
+      break;
+    case ST_ALIGN_MIDDLE:
+      meta->x_align = 0.5;
+      break;
+    case ST_ALIGN_END:
+      meta->x_align = 1.0;
+      break;
+    }
+
+  clutter_actor_queue_relayout (child);
+}
+
+/**
+ * st_table_child_get_y_align:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ *
+ * Get the y-align value of the child
+ *
+ * Returns: An #StAlign value
+ */
+StAlign
+st_table_child_get_y_align (StTable      *table,
+                            ClutterActor *child)
+{
+  StTableChild *meta;
+
+  g_return_val_if_fail (ST_IS_TABLE (table), 0);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (child), 0);
+
+  meta = get_child_meta (table, child);
+
+  if (meta->y_align == 0.0)
+    return ST_ALIGN_START;
+  else if (meta->y_align == 1.0)
+    return ST_ALIGN_END;
+  else
+    return ST_ALIGN_MIDDLE;
+
+}
+
+/**
+ * st_table_child_set_y_align:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ * @align: A #StAlign value
+ *
+ * Set the value of the y-align property. This will only have an effect if
+ * y-fill value is set to FALSE.
+ *
+ */
+void
+st_table_child_set_y_align (StTable      *table,
+                            ClutterActor *child,
+                            StAlign       align)
+{
+  StTableChild *meta;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (CLUTTER_IS_ACTOR (child));
+
+  meta = get_child_meta (table, child);
+
+  switch (align)
+    {
+    case ST_ALIGN_START:
+      meta->y_align = 0.0;
+      break;
+    case ST_ALIGN_MIDDLE:
+      meta->y_align = 0.5;
+      break;
+    case ST_ALIGN_END:
+      meta->y_align = 1.0;
+      break;
+    }
+
+  clutter_actor_queue_relayout (child);
+}
+
+/**
+ * st_table_child_set_allocate_hidden:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ * @value: #TRUE if the actor should be allocated when hidden
+ *
+ * Set whether the child should be allocate even if it is hidden
+ */
+void
+st_table_child_set_allocate_hidden (StTable      *table,
+                                    ClutterActor *child,
+                                    gboolean      value)
+{
+  StTableChild *meta;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (CLUTTER_IS_ACTOR (child));
+
+  meta = get_child_meta (table, child);
+
+  if (meta->allocate_hidden != value)
+    {
+      meta->allocate_hidden = value;
+
+      clutter_actor_queue_relayout (child);
+
+      g_object_notify (G_OBJECT (meta), "allocate-hidden");
+    }
+}
+
+/**
+ * st_table_child_get_allocate_hidden:
+ * @table: A #StTable
+ * @child: A #ClutterActor
+ *
+ * Determine if the child is allocated even if it is hidden
+ *
+ * Returns: #TRUE if the actor is allocated when hidden
+ */
+gboolean
+st_table_child_get_allocate_hidden (StTable      *table,
+                                    ClutterActor *child)
+{
+  StTableChild *meta;
+
+  g_return_val_if_fail (ST_IS_TABLE (table), TRUE);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (child), TRUE);
+
+  meta = get_child_meta (table, child);
+
+  return meta->allocate_hidden;
+}
diff --git a/src/st/st-table-child.h b/src/st/st-table-child.h
new file mode 100644
index 0000000..cc3cafc
--- /dev/null
+++ b/src/st/st-table-child.h
@@ -0,0 +1,129 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * st-table-child.h: Table child implementation
+ *
+ * Copyright 2008, 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Thomas Wood  <thomas linux intel com>
+ *
+ */
+
+#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
+#error "Only <st/st.h> can be included directly.h"
+#endif
+
+#ifndef __ST_TABLE_CHILD_H__
+#define __ST_TABLE_CHILD_H__
+
+#include <st/st-types.h>
+#include <st/st-widget.h>
+#include <st/st-table.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define ST_TYPE_TABLE_CHILD          (st_table_child_get_type ())
+#define ST_TABLE_CHILD(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_TABLE_CHILD, StTableChild))
+#define ST_IS_TABLE_CHILD(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_TABLE_CHILD))
+#define ST_TABLE_CHILD_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_TABLE_CHILD, StTableChildClass))
+#define ST_IS_TABLE_CHILD_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_TABLE_CHILD))
+#define ST_TABLE_CHILD_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_TABLE_CHILD, StTableChildClass))
+
+typedef struct _StTableChild         StTableChild;
+typedef struct _StTableChildClass    StTableChildClass;
+
+/**
+ * StTableChild:
+ *
+ * The contents of the this structure are private and should only be accessed
+ * through the public API.
+ */
+struct _StTableChild
+{
+  /*< private >*/
+  ClutterChildMeta parent_instance;
+
+  gint col;
+  gint row;
+  gint col_span;
+  gint row_span;
+  gdouble x_align;
+  gdouble y_align;
+  guint allocate_hidden : 1;
+  guint x_expand : 1;
+  guint y_expand : 1;
+  guint x_fill : 1;
+  guint y_fill : 1;
+};
+
+
+struct _StTableChildClass
+{
+  ClutterChildMetaClass parent_class;
+};
+
+GType st_table_child_get_type (void) G_GNUC_CONST;
+
+gint     st_table_child_get_col_span        (StTable      *table,
+                                             ClutterActor *child);
+void     st_table_child_set_col_span        (StTable      *table,
+                                             ClutterActor *child,
+                                             gint          span);
+gint     st_table_child_get_row_span        (StTable      *table,
+                                             ClutterActor *child);
+void     st_table_child_set_row_span        (StTable      *table,
+                                             ClutterActor *child,
+                                             gint          span);
+gboolean st_table_child_get_x_fill          (StTable      *table,
+                                             ClutterActor *child);
+void     st_table_child_set_x_fill          (StTable      *table,
+                                             ClutterActor *child,
+                                             gboolean      fill);
+gboolean st_table_child_get_y_fill          (StTable      *table,
+                                             ClutterActor *child);
+void     st_table_child_set_y_fill          (StTable      *table,
+                                             ClutterActor *child,
+                                             gboolean      fill);
+gboolean st_table_child_get_x_expand        (StTable      *table,
+                                             ClutterActor *child);
+void     st_table_child_set_x_expand        (StTable      *table,
+                                             ClutterActor *child,
+                                             gboolean      expand);
+gboolean st_table_child_get_y_expand        (StTable      *table,
+                                             ClutterActor *child);
+void     st_table_child_set_y_expand        (StTable      *table,
+                                             ClutterActor *child,
+                                             gboolean      expand);
+StAlign  st_table_child_get_x_align         (StTable      *table,
+                                             ClutterActor *child);
+void     st_table_child_set_x_align         (StTable      *table,
+                                             ClutterActor *child,
+                                             StAlign       align);
+StAlign  st_table_child_get_y_align         (StTable      *table,
+                                             ClutterActor *child);
+void     st_table_child_set_y_align         (StTable      *table,
+                                             ClutterActor *child,
+                                             StAlign       align);
+void     st_table_child_set_allocate_hidden (StTable      *table,
+                                             ClutterActor *child,
+                                             gboolean      value);
+gboolean st_table_child_get_allocate_hidden (StTable      *table,
+                                             ClutterActor *child);
+
+G_END_DECLS
+
+#endif /* __ST_TABLE_H__ */
diff --git a/src/st/st-table-private.h b/src/st/st-table-private.h
new file mode 100644
index 0000000..ebf5934
--- /dev/null
+++ b/src/st/st-table-private.h
@@ -0,0 +1,36 @@
+/*
+ * st-private-private.h: Private declarations for StTable
+ *
+ * Copyright 2007 OpenedHand
+ * Copyright 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __ST_TABLE_PRIVATE_H__
+#define __ST_TABLE_PRIVATE_H__
+
+#include "st-table.h"
+
+G_BEGIN_DECLS
+
+void _st_table_update_row_col (StTable *table,
+			       gint     row,
+			       gint     col);
+
+G_END_DECLS
+
+#endif /* __ST_TABLE_PRIVATE_H__ */
diff --git a/src/st/st-table.c b/src/st/st-table.c
new file mode 100644
index 0000000..9a0a18b
--- /dev/null
+++ b/src/st/st-table.c
@@ -0,0 +1,1475 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * st-table.c: Table layout widget
+ *
+ * Copyright 2008, 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Thomas Wood <thomas linux intel com>
+ *
+ */
+
+/**
+ * SECTION:st-table
+ * @short_description: A multi-child layout container based on rows
+ * and columns
+ *
+ * #StTable is a mult-child layout container based on a table arrangement
+ * with rows and columns. #StTable adds several child properties to it's
+ * children that control their position and size in the table.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "st-table.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <clutter/clutter.h>
+
+#include "st-enum-types.h"
+#include "st-marshal.h"
+#include "st-private.h"
+#include "st-table-child.h"
+#include "st-table-private.h"
+#include "st-stylable.h"
+
+enum
+{
+  PROP_0,
+
+  PROP_PADDING,
+
+  PROP_COL_SPACING,
+  PROP_ROW_SPACING,
+
+  PROP_HOMOGENEOUS,
+
+  PROP_ROW_COUNT,
+  PROP_COL_COUNT,
+};
+
+#define ST_TABLE_GET_PRIVATE(obj)    \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_TABLE, StTablePrivate))
+
+struct _StTablePrivate
+{
+  GSList *children;
+
+  gint    col_spacing;
+  gint    row_spacing;
+
+  gint    n_rows;
+  gint    n_cols;
+
+  gint    active_row;
+  gint    active_col;
+
+  GArray *min_widths;
+  GArray *pref_widths;
+  GArray *min_heights;
+  GArray *pref_heights;
+
+  GArray *is_expand_col;
+  GArray *is_expand_row;
+
+  GArray *col_widths;
+  GArray *row_heights;
+
+  guint   homogeneous : 1;
+};
+
+static void st_container_iface_init (ClutterContainerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (StTable, st_table, ST_TYPE_WIDGET,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
+                                                st_container_iface_init));
+
+
+
+/*
+ * ClutterContainer Implementation
+ */
+static void
+st_container_add_actor (ClutterContainer *container,
+                        ClutterActor     *actor)
+{
+  StTablePrivate *priv = ST_TABLE (container)->priv;
+
+  clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
+
+
+  priv->children = g_slist_append (priv->children, actor);
+
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+
+  g_signal_emit_by_name (container, "actor-added", actor);
+}
+
+static void
+st_container_remove_actor (ClutterContainer *container,
+                           ClutterActor     *actor)
+{
+  StTablePrivate *priv = ST_TABLE (container)->priv;
+
+  GSList *item = NULL;
+
+  item = g_slist_find (priv->children, actor);
+
+  if (item == NULL)
+    {
+      g_warning ("Widget of type '%s' is not a child of container of type '%s'",
+                 g_type_name (G_OBJECT_TYPE (actor)),
+                 g_type_name (G_OBJECT_TYPE (container)));
+      return;
+    }
+
+  g_object_ref (actor);
+
+  priv->children = g_slist_delete_link (priv->children, item);
+  clutter_actor_unparent (actor);
+
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+
+  g_signal_emit_by_name (container, "actor-removed", actor);
+
+  g_object_unref (actor);
+}
+
+static void
+st_container_foreach (ClutterContainer *container,
+                      ClutterCallback   callback,
+                      gpointer          callback_data)
+{
+  StTablePrivate *priv = ST_TABLE (container)->priv;
+
+  g_slist_foreach (priv->children, (GFunc) callback, callback_data);
+}
+
+static void
+st_container_lower (ClutterContainer *container,
+                    ClutterActor     *actor,
+                    ClutterActor     *sibling)
+{
+  /* XXX: not yet implemented */
+  g_warning ("%s() not yet implemented", __FUNCTION__);
+}
+
+static void
+st_container_raise (ClutterContainer *container,
+                    ClutterActor     *actor,
+                    ClutterActor     *sibling)
+{
+  /* XXX: not yet implemented */
+  g_warning ("%s() not yet implemented", __FUNCTION__);
+}
+
+static void
+st_container_sort_depth_order (ClutterContainer *container)
+{
+  /* XXX: not yet implemented */
+  g_warning ("%s() not yet implemented", __FUNCTION__);
+}
+
+static void
+st_container_iface_init (ClutterContainerIface *iface)
+{
+  iface->add = st_container_add_actor;
+  iface->remove = st_container_remove_actor;
+  iface->foreach = st_container_foreach;
+  iface->lower = st_container_lower;
+  iface->raise = st_container_raise;
+  iface->sort_depth_order = st_container_sort_depth_order;
+  iface->child_meta_type = ST_TYPE_TABLE_CHILD;
+}
+
+/* StTable Class Implementation */
+
+static void
+st_table_set_property (GObject      *gobject,
+                       guint         prop_id,
+                       const GValue *value,
+                       GParamSpec   *pspec)
+{
+  StTable *table = ST_TABLE (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_COL_SPACING:
+      st_table_set_col_spacing (table, g_value_get_int (value));
+      break;
+
+    case PROP_ROW_SPACING:
+      st_table_set_row_spacing (table, g_value_get_int (value));
+      break;
+
+    case PROP_HOMOGENEOUS:
+      if (table->priv->homogeneous != g_value_get_boolean (value))
+        {
+          table->priv->homogeneous = g_value_get_boolean (value);
+          clutter_actor_queue_relayout ((ClutterActor *) gobject);
+        }
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+st_table_get_property (GObject    *gobject,
+                       guint       prop_id,
+                       GValue     *value,
+                       GParamSpec *pspec)
+{
+  StTablePrivate *priv = ST_TABLE (gobject)->priv;
+
+  switch (prop_id)
+    {
+    case PROP_COL_SPACING:
+      g_value_set_int (value, priv->col_spacing);
+      break;
+
+    case PROP_ROW_SPACING:
+      g_value_set_int (value, priv->row_spacing);
+      break;
+
+    case PROP_HOMOGENEOUS:
+      g_value_set_boolean (value, priv->homogeneous);
+      break;
+
+    case PROP_COL_COUNT:
+      g_value_set_int (value, priv->n_cols);
+      break;
+
+    case PROP_ROW_COUNT:
+      g_value_set_int (value, priv->n_rows);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+st_table_finalize (GObject *gobject)
+{
+  StTablePrivate *priv = ST_TABLE (gobject)->priv;
+
+  g_array_free (priv->min_widths, TRUE);
+  g_array_free (priv->pref_widths, TRUE);
+
+  g_array_free (priv->min_heights, TRUE);
+  g_array_free (priv->pref_heights, TRUE);
+
+  g_array_free (priv->is_expand_col, TRUE);
+  g_array_free (priv->is_expand_row, TRUE);
+
+  g_array_free (priv->col_widths, TRUE);
+  g_array_free (priv->row_heights, TRUE);
+
+  G_OBJECT_CLASS (st_table_parent_class)->finalize (gobject);
+}
+
+static void
+st_table_dispose (GObject *gobject)
+{
+  StTablePrivate *priv = ST_TABLE (gobject)->priv;
+  GSList *l, *next;
+
+  for (l = priv->children; l;)
+    {
+      next = l->next;
+      clutter_container_remove_actor ((ClutterContainer *) gobject,
+                                      CLUTTER_ACTOR (l->data));
+      l = next;
+    }
+
+  G_OBJECT_CLASS (st_table_parent_class)->dispose (gobject);
+}
+
+#define CLAMP_TO_PIXEL(x) ((float)((int)(x)))
+
+/* Utility function to modify a child allocation box with respect to the
+ * x/y-fill child properties. Expects childbox to contain the available
+ * allocation space.
+ */
+static void
+st_table_allocate_fill (ClutterActor    *child,
+                        ClutterActorBox *childbox,
+                        gdouble          x_align,
+                        gdouble          y_align,
+                        gboolean         x_fill,
+                        gboolean         y_fill)
+{
+  gfloat natural_width, natural_height;
+  gfloat min_width, min_height;
+  gfloat child_width, child_height;
+  gfloat available_width, available_height;
+  ClutterRequestMode request;
+  ClutterActorBox allocation = { 0, };
+
+  available_width  = childbox->x2 - childbox->x1;
+  available_height = childbox->y2 - childbox->y1;
+
+  if (available_width < 0)
+    available_width = 0;
+
+  if (available_height < 0)
+    available_height = 0;
+
+  if (x_fill)
+    {
+      allocation.x1 = childbox->x1;
+      allocation.x2 = (int)(allocation.x1 + available_width);
+    }
+
+  if (y_fill)
+    {
+      allocation.y1 = childbox->y1;
+      allocation.y2 = (int)(allocation.y1 + available_height);
+    }
+
+  /* if we are filling horizontally and vertically then we're done */
+  if (x_fill && y_fill)
+    {
+      *childbox = allocation;
+      return;
+    }
+
+  request = CLUTTER_REQUEST_HEIGHT_FOR_WIDTH;
+  g_object_get (G_OBJECT (child), "request-mode", &request, NULL);
+
+  if (request == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
+    {
+      clutter_actor_get_preferred_width (child, available_height,
+                                         &min_width,
+                                         &natural_width);
+
+      child_width = CLAMP (natural_width, min_width, available_width);
+
+      clutter_actor_get_preferred_height (child, child_width,
+                                          &min_height,
+                                          &natural_height);
+
+      child_height = CLAMP (natural_height, min_height, available_height);
+    }
+  else
+    {
+      clutter_actor_get_preferred_height (child, available_width,
+                                          &min_height,
+                                          &natural_height);
+
+      child_height = CLAMP (natural_height, min_height, available_height);
+
+      clutter_actor_get_preferred_width (child, child_height,
+                                         &min_width,
+                                         &natural_width);
+
+      child_width = CLAMP (natural_width, min_width, available_width);
+    }
+
+  if (!x_fill)
+    {
+      allocation.x1 = childbox->x1 + (int)((available_width - child_width) * x_align);
+      allocation.x2 = allocation.x1 + (int) child_width;
+    }
+
+  if (!y_fill)
+    {
+      allocation.y1 = childbox->y1 + (int)((available_height - child_height) * y_align);
+      allocation.y2 = allocation.y1 + (int) child_height;
+    }
+
+  *childbox = allocation;
+
+}
+
+static void
+st_table_homogeneous_allocate (ClutterActor          *self,
+                               const ClutterActorBox *box,
+                               gboolean               flags)
+{
+  GSList *list;
+  gfloat col_width, row_height;
+  gint row_spacing, col_spacing;
+  StTablePrivate *priv = ST_TABLE (self)->priv;
+  StPadding padding;
+
+  st_widget_get_padding (ST_WIDGET (self), &padding);
+
+  col_spacing = priv->col_spacing;
+  row_spacing = priv->row_spacing;
+
+  col_width = (box->x2 - box->x1
+               - padding.left - padding.right
+               - (col_spacing * (priv->n_cols - 1)))
+              / priv->n_cols;
+  row_height = (box->y2 - box->y1
+                - padding.top - padding.bottom
+                - (row_spacing * (priv->n_rows - 1)))
+               / priv->n_rows;
+
+  for (list = priv->children; list; list = g_slist_next (list))
+    {
+      gint row, col, row_span, col_span;
+      StTableChild *meta;
+      ClutterActor *child;
+      ClutterActorBox childbox;
+      gdouble x_align, y_align;
+      gboolean x_fill, y_fill;
+
+      child = CLUTTER_ACTOR (list->data);
+
+      meta = (StTableChild *) clutter_container_get_child_meta (CLUTTER_CONTAINER (self), child);
+
+      if (!meta->allocate_hidden && !CLUTTER_ACTOR_IS_VISIBLE (child))
+        continue;
+
+      /* get child properties */
+      col = meta->col;
+      row = meta->row;
+      row_span = meta->row_span;
+      col_span = meta->col_span;
+      x_align = meta->x_align;
+      y_align = meta->y_align;
+      x_fill = meta->x_fill;
+      y_fill = meta->y_fill;
+
+      childbox.x1 = padding.left + (col_width + col_spacing) * col;
+      childbox.x2 = childbox.x1 + (col_width * col_span) + (col_spacing * (col_span - 1));
+
+      childbox.y1 = padding.top + (row_height + row_spacing) * row;
+      childbox.y2 = childbox.y1 + (row_height * row_span) + (row_spacing * (row_span - 1));
+
+      st_table_allocate_fill (child, &childbox, x_align, y_align, x_fill, y_fill);
+
+      clutter_actor_allocate (child, &childbox, flags);
+    }
+
+}
+
+
+static gint *
+st_table_calculate_col_widths (StTable *table,
+                               gint     for_width)
+{
+  gint total_min_width, i;
+  StTablePrivate *priv = table->priv;
+  gboolean *is_expand_col;
+  gint extra_col_width, n_expanded_cols = 0, expanded_cols = 0;
+  gint *pref_widths, *min_widths;
+  GSList *list;
+  StPadding padding;
+
+  g_array_set_size (priv->is_expand_col, 0);
+  g_array_set_size (priv->is_expand_col, priv->n_cols);
+  is_expand_col = (gboolean *) priv->is_expand_col->data;
+
+  g_array_set_size (priv->pref_widths, 0);
+  g_array_set_size (priv->pref_widths, priv->n_cols);
+  pref_widths = (gint *) priv->pref_widths->data;
+
+  g_array_set_size (priv->min_widths, 0);
+  g_array_set_size (priv->min_widths, priv->n_cols);
+  min_widths = (gint *) priv->min_widths->data;
+
+
+  /* take off the padding values to calculate the allocatable width */
+  st_widget_get_padding (ST_WIDGET (table), &padding);
+
+  for_width -= (int)(padding.left + padding.right);
+
+  for (list = priv->children; list; list = g_slist_next (list))
+    {
+      gint row, col;
+      gfloat w_min, w_pref;
+      gboolean x_expand;
+      StTableChild *meta;
+      ClutterActor *child;
+      gint col_span, row_span;
+
+      child = CLUTTER_ACTOR (list->data);
+
+      meta = (StTableChild *) clutter_container_get_child_meta (CLUTTER_CONTAINER (table), child);
+
+      if (!meta->allocate_hidden && !CLUTTER_ACTOR_IS_VISIBLE (child))
+        continue;
+
+      /* get child properties */
+      col = meta->col;
+      row = meta->row;
+      x_expand = meta->x_expand;
+      col_span = meta->col_span;
+      row_span = meta->row_span;
+
+      if (x_expand)
+        is_expand_col[col] = TRUE;
+
+      clutter_actor_get_preferred_width (child, -1, &w_min, &w_pref);
+      if (col_span == 1 && w_pref > pref_widths[col])
+        {
+          pref_widths[col] = w_pref;
+        }
+      if (col_span == 1 && w_min > min_widths[col])
+        {
+          min_widths[col] = w_min;
+        }
+
+    }
+
+  total_min_width = priv->col_spacing * (priv->n_cols - 1);
+  for (i = 0; i < priv->n_cols; i++)
+    total_min_width += pref_widths[i];
+
+  /* calculate the remaining space and distribute it evenly onto all rows/cols
+   * with the x/y expand property set. */
+  for (i = 0; i < priv->n_cols; i++)
+    if (is_expand_col[i])
+      {
+        expanded_cols += pref_widths[i];
+        n_expanded_cols++;
+      }
+
+  /* for_width - total_min_width */
+  extra_col_width = for_width - total_min_width;
+  if (extra_col_width)
+    for (i = 0; i < priv->n_cols; i++)
+      if (is_expand_col[i])
+        {
+          if (extra_col_width < 0)
+            {
+              pref_widths[i] =
+                MAX (min_widths[i],
+                     pref_widths[i]
+                     + (extra_col_width * (pref_widths[i] / (float) expanded_cols)));
+
+              /* if we reached the minimum width for this column, we need to
+               * stop counting it as expanded */
+              if (pref_widths[i] == min_widths[i])
+                {
+                  /* restart calculations :-( */
+                  expanded_cols -= pref_widths[i];
+                  is_expand_col[i] = 0;
+                  n_expanded_cols--;
+                  i = -1;
+                }
+            }
+          else
+            pref_widths[i] += extra_col_width / n_expanded_cols;
+        }
+
+  return pref_widths;
+}
+
+static gint *
+st_table_calculate_row_heights (StTable *table,
+                                gint     for_height,
+                                gint   * col_widths)
+{
+  StTablePrivate *priv = ST_TABLE (table)->priv;
+  GSList *list;
+  gint *is_expand_row, *min_heights, *pref_heights, *row_heights, extra_row_height;
+  gint i, total_min_height;
+  gint expanded_rows = 0;
+  gint n_expanded_rows = 0;
+  StPadding padding;
+
+  st_widget_get_padding (ST_WIDGET (table), &padding);
+
+  /* take padding off available height */
+  for_height -= (int)(padding.top + padding.bottom);
+
+  g_array_set_size (priv->row_heights, 0);
+  g_array_set_size (priv->row_heights, priv->n_rows);
+  row_heights = (gboolean *) priv->row_heights->data;
+
+  g_array_set_size (priv->is_expand_row, 0);
+  g_array_set_size (priv->is_expand_row, priv->n_rows);
+  is_expand_row = (gboolean *) priv->is_expand_row->data;
+
+  g_array_set_size (priv->min_heights, 0);
+  g_array_set_size (priv->min_heights, priv->n_rows);
+  min_heights = (gboolean *) priv->min_heights->data;
+
+  g_array_set_size (priv->pref_heights, 0);
+  g_array_set_size (priv->pref_heights, priv->n_rows);
+  pref_heights = (gboolean *) priv->pref_heights->data;
+
+  /* calculate minimum row widths and column heights */
+  for (list = priv->children; list; list = g_slist_next (list))
+    {
+      gint row, col, cell_width;
+      gfloat h_min, h_pref;
+      gboolean x_expand, y_expand;
+      StTableChild *meta;
+      ClutterActor *child;
+      gint col_span, row_span;
+
+      child = CLUTTER_ACTOR (list->data);
+
+      meta = (StTableChild *) clutter_container_get_child_meta (CLUTTER_CONTAINER (table), child);
+
+      if (!meta->allocate_hidden && !CLUTTER_ACTOR_IS_VISIBLE (child))
+        continue;
+
+      /* get child properties */
+      col = meta->col;
+      row = meta->row;
+      x_expand = meta->x_expand;
+      y_expand = meta->y_expand;
+      col_span = meta->col_span;
+      row_span = meta->row_span;
+
+      if (y_expand)
+        is_expand_row[row] = TRUE;
+
+      /* calculate the cell width by including any spanned columns */
+      cell_width = 0;
+      for (i = 0; i < col_span && col + i < priv->n_cols; i++)
+        cell_width += (float)(col_widths[col + i]);
+
+      if (!meta->x_fill)
+        {
+          gfloat width;
+          clutter_actor_get_preferred_width (child, -1, NULL, &width);
+          cell_width = MIN (cell_width, width);
+        }
+
+      clutter_actor_get_preferred_height (child, cell_width, &h_min, &h_pref);
+
+      if (row_span == 1 && h_pref > pref_heights[row])
+        {
+          pref_heights[row] = (int)(h_pref);
+        }
+      if (row_span == 1 && h_min > min_heights[row])
+        {
+          min_heights[row] = (int)(h_min);
+        }
+    }
+
+  total_min_height = 0; // priv->row_spacing * (priv->n_rows - 1);
+  for (i = 0; i < priv->n_rows; i++)
+    total_min_height += pref_heights[i];
+
+  /* calculate the remaining space and distribute it evenly onto all rows/cols
+   * with the x/y expand property set. */
+  for (i = 0; i < priv->n_rows; i++)
+    if (is_expand_row[i])
+      {
+        expanded_rows += pref_heights[i];
+        n_expanded_rows++;
+      }
+
+  /* extra row height = for height - row spacings - total_min_height */
+  for_height -= (priv->row_spacing * (priv->n_rows - 1));
+  extra_row_height = for_height - total_min_height;
+
+
+  if (extra_row_height < 0)
+    {
+      gint *skip = g_slice_alloc0 (sizeof (gint) * priv->n_rows);
+      gint total_shrink_height;
+
+      /* If we need to shrink rows, we need to do multiple passes.
+       *
+       * We start by assuming all rows can shrink. All rows are sized
+       * proportional to their height in the total table size. If a row would be
+       * sized smaller than its minimum size, we mark it as non-shrinkable, and
+       * reduce extra_row_height by the amount it has been shrunk. The amount
+       * it has been shrunk by is the difference between the preferred and
+       * minimum height, since all rows start at their preferred height. We
+       * also then reduce the total table size (stored in total_shrink_height) by the height
+       * of the row we are going to be skipping.
+       *
+       */
+
+      /* We start by assuming all rows can shrink */
+      total_shrink_height = total_min_height;
+      for (i = 0; i < priv->n_rows; i++)
+        {
+          if (!skip[i])
+            {
+              gint tmp;
+
+              /* Calculate the height of the row by starting with the preferred
+               * height and taking away the extra row height proportional to
+               * the preferred row height over the rows that are being shrunk
+               */
+              tmp = pref_heights[i]
+                    + (extra_row_height * (pref_heights[i] / (float) total_shrink_height));
+
+              if (tmp < min_heights[i])
+                {
+                  /* This was a row we *were* set to shrink, but we now find it would have
+                   * been shrunk too much. We remove it from the list of rows to shrink and
+                   * adjust extra_row_height and total_shrink_height appropriately */
+                  skip[i] = TRUE;
+                  row_heights[i] = min_heights[i];
+
+                  /* Reduce extra_row_height by the amount we have reduced this
+                   * actor by */
+                  extra_row_height += (pref_heights[i] - min_heights[i]);
+                  /* now take off the row from the total shrink height */
+                  total_shrink_height -= pref_heights[i];
+
+                  /* restart the loop */
+                  i = -1;
+                }
+              else
+                {
+                  skip[i] = FALSE;
+                  row_heights[i] = tmp;
+                }
+            }
+
+        }
+
+      g_slice_free1 (sizeof (gint) * priv->n_rows, skip);
+    }
+  else
+    {
+      for (i = 0; i < priv->n_rows; i++)
+        {
+          if (is_expand_row[i])
+            row_heights[i] = pref_heights[i] + (extra_row_height / n_expanded_rows);
+          else
+            row_heights[i] = pref_heights[i];
+        }
+    }
+
+
+  return row_heights;
+}
+
+static void
+st_table_preferred_allocate (ClutterActor          *self,
+                             const ClutterActorBox *box,
+                             gboolean               flags)
+{
+  GSList *list;
+  gint row_spacing, col_spacing;
+  gint i, table_width, table_height;
+  gint *col_widths, *row_heights;
+  StTable *table;
+  StTablePrivate *priv;
+  StPadding padding;
+
+  table = ST_TABLE (self);
+  priv = ST_TABLE (self)->priv;
+
+  st_widget_get_padding (ST_WIDGET (self), &padding);
+
+  col_spacing = (priv->col_spacing);
+  row_spacing = (priv->row_spacing);
+
+
+  table_height = (int)(box->y2 - box->y1
+                       - padding.top
+                       - padding.bottom);
+  table_width = (int)(box->x2 - box->x1
+                      - padding.right
+                      - padding.left);
+
+  col_widths =
+    st_table_calculate_col_widths (table,
+                                   (int)(box->x2 - box->x1));
+
+  row_heights =
+    st_table_calculate_row_heights (table,
+                                    (int)(box->y2 - box->y1),
+                                    col_widths);
+
+
+  for (list = priv->children; list; list = g_slist_next (list))
+    {
+      gint row, col, row_span, col_span;
+      gint col_width, row_height;
+      StTableChild *meta;
+      ClutterActor *child;
+      ClutterActorBox childbox;
+      gint child_x, child_y;
+      gdouble x_align, y_align;
+      gboolean x_fill, y_fill;
+
+      child = CLUTTER_ACTOR (list->data);
+
+      meta = (StTableChild *) clutter_container_get_child_meta (CLUTTER_CONTAINER (self), child);
+
+      if (!meta->allocate_hidden && !CLUTTER_ACTOR_IS_VISIBLE (child))
+        continue;
+
+      /* get child properties */
+      col = meta->col;
+      row = meta->row;
+      row_span = meta->row_span;
+      col_span = meta->col_span;
+      x_align = meta->x_align;
+      y_align = meta->y_align;
+      x_fill = meta->x_fill;
+      y_fill = meta->y_fill;
+
+
+      /* initialise the width and height */
+      col_width = col_widths[col];
+      row_height = row_heights[row];
+
+      /* Add the widths of the spanned columns:
+       *
+       * First check that we have a non-zero span. Then we loop over each of
+       * the columns that we're spanning but we stop short if we go past the
+       * number of columns in the table. This is necessary to avoid accessing
+       * uninitialised memory. We add the spacing in here too since we only
+       * want to add as much spacing as times we successfully span.
+       */
+      if (col + col_span > priv->n_cols)
+        g_warning ("StTable: col-span exceeds number of columns");
+      if (row + row_span > priv->n_rows)
+        g_warning ("StTable: row-span exceeds number of rows");
+
+      if (col_span > 1)
+        {
+          for (i = col + 1; i < col + col_span && i < priv->n_cols; i++)
+            {
+              col_width += col_widths[i];
+              col_width += col_spacing;
+            }
+        }
+
+      /* add the height of the spanned rows */
+      if (row_span > 1)
+        {
+          for (i = row + 1; i < row + row_span && i < priv->n_rows; i++)
+            {
+              row_height += row_heights[i];
+              row_height += row_spacing;
+            }
+        }
+
+      /* calculate child x */
+      child_x = (int) padding.left
+                + col_spacing * col;
+      for (i = 0; i < col; i++)
+        child_x += col_widths[i];
+
+      /* calculate child y */
+      child_y = (int) padding.top
+                + row_spacing * row;
+      for (i = 0; i < row; i++)
+        child_y += row_heights[i];
+
+      /* set up childbox */
+      childbox.x1 = (float) child_x;
+      childbox.x2 = (float) MAX (0, child_x + col_width);
+
+      childbox.y1 = (float) child_y;
+      childbox.y2 = (float) MAX (0, child_y + row_height);
+
+
+      st_table_allocate_fill (child, &childbox, x_align, y_align, x_fill, y_fill);
+
+      clutter_actor_allocate (child, &childbox, flags);
+    }
+}
+
+static void
+st_table_allocate (ClutterActor          *self,
+                   const ClutterActorBox *box,
+                   ClutterAllocationFlags flags)
+{
+  StTablePrivate *priv = ST_TABLE (self)->priv;
+
+  CLUTTER_ACTOR_CLASS (st_table_parent_class)->allocate (self, box, flags);
+
+  if (priv->n_cols < 1 || priv->n_rows < 1)
+    {
+      return;
+    };
+
+  if (priv->homogeneous)
+    st_table_homogeneous_allocate (self, box, flags);
+  else
+    st_table_preferred_allocate (self, box, flags);
+}
+
+static void
+st_table_get_preferred_width (ClutterActor *self,
+                              gfloat        for_height,
+                              gfloat       *min_width_p,
+                              gfloat       *natural_width_p)
+{
+  gint *min_widths, *pref_widths;
+  gfloat total_min_width, total_pref_width;
+  StTablePrivate *priv = ST_TABLE (self)->priv;
+  GSList *list;
+  gint i;
+  StPadding padding;
+
+  st_widget_get_padding (ST_WIDGET (self), &padding);
+
+  if (priv->n_cols < 1)
+    {
+      *min_width_p = 0;
+      *natural_width_p = 0;
+      return;
+    }
+
+  /* Setting size to zero and then what we want it to be causes a clear if
+   * clear flag is set (which it should be.)
+   */
+  g_array_set_size (priv->min_widths, 0);
+  g_array_set_size (priv->pref_widths, 0);
+  g_array_set_size (priv->min_widths, priv->n_cols);
+  g_array_set_size (priv->pref_widths, priv->n_cols);
+
+  min_widths = (gint *) priv->min_widths->data;
+  pref_widths = (gint *) priv->pref_widths->data;
+
+  /* calculate minimum row widths */
+  for (list = priv->children; list; list = g_slist_next (list))
+    {
+      gint col, col_span;
+      gfloat w_min, w_pref;
+      StTableChild *meta;
+      ClutterActor *child;
+
+      child = CLUTTER_ACTOR (list->data);
+
+      meta = (StTableChild *) clutter_container_get_child_meta (CLUTTER_CONTAINER (self), child);
+
+      if (!meta->allocate_hidden && !CLUTTER_ACTOR_IS_VISIBLE (child))
+        continue;
+
+      /* get child properties */
+      col = meta->col;
+      col_span = meta->col_span;
+
+      clutter_actor_get_preferred_width (child, -1, &w_min, &w_pref);
+
+      if (col_span == 1 && w_min > min_widths[col])
+        min_widths[col] = w_min;
+      if (col_span == 1 && w_pref > pref_widths[col])
+        pref_widths[col] = w_pref;
+    }
+
+  total_min_width = padding.left
+                    + padding.right
+                    + (priv->n_cols - 1)
+                    * (float) priv->col_spacing;
+  total_pref_width = total_min_width;
+
+  for (i = 0; i < priv->n_cols; i++)
+    {
+      total_min_width += min_widths[i];
+      total_pref_width += pref_widths[i];
+    }
+
+  if (min_width_p)
+    *min_width_p = total_min_width;
+  if (natural_width_p)
+    *natural_width_p = total_pref_width;
+}
+
+static void
+st_table_get_preferred_height (ClutterActor *self,
+                               gfloat        for_width,
+                               gfloat       *min_height_p,
+                               gfloat       *natural_height_p)
+{
+  gint *min_heights, *pref_heights;
+  gfloat total_min_height, total_pref_height;
+  StTablePrivate *priv = ST_TABLE (self)->priv;
+  GSList *list;
+  gint i;
+  gint *min_widths;
+  StPadding padding;
+
+  if (priv->n_rows < 1)
+    {
+      *min_height_p = 0;
+      *natural_height_p = 0;
+      return;
+    }
+
+  /* Setting size to zero and then what we want it to be causes a clear if
+   * clear flag is set (which it should be.)
+   */
+  g_array_set_size (priv->min_heights, 0);
+  g_array_set_size (priv->pref_heights, 0);
+  g_array_set_size (priv->min_heights, priv->n_rows);
+  g_array_set_size (priv->pref_heights, priv->n_rows);
+
+  /* use min_widths to help allocation of height-for-width widgets */
+  min_widths = st_table_calculate_col_widths (ST_TABLE (self), for_width);
+
+  min_heights = (gint *) priv->min_heights->data;
+  pref_heights = (gint *) priv->pref_heights->data;
+
+  /* calculate minimum row heights */
+  for (list = priv->children; list; list = g_slist_next (list))
+    {
+      gint row, col, col_span, cell_width, row_span;
+      gfloat min, pref;
+      StTableChild *meta;
+      ClutterActor *child;
+
+      child = CLUTTER_ACTOR (list->data);
+
+      meta = (StTableChild *) clutter_container_get_child_meta (CLUTTER_CONTAINER (self), child);
+
+      if (!meta->allocate_hidden && !CLUTTER_ACTOR_IS_VISIBLE (child))
+        continue;
+
+      /* get child properties */
+      row = meta->row;
+      col = meta->col;
+      col_span = meta->col_span;
+      row_span = meta->row_span;
+
+      cell_width = 0;
+      for (i = 0; i < col_span && col + i < priv->n_cols; i++)
+        cell_width += min_widths[col + i];
+
+      clutter_actor_get_preferred_height (child,
+                                          (float) cell_width, &min, &pref);
+
+      if (row_span == 1 && min > min_heights[row])
+        min_heights[row] = min;
+      if (row_span == 1 && pref > pref_heights[row])
+        pref_heights[row] = pref;
+    }
+
+  st_widget_get_padding (ST_WIDGET (self), &padding);
+
+  /* start off with padding plus row spacing */
+  total_min_height = padding.top + padding.bottom + (priv->n_rows - 1) *
+                     (float)(priv->row_spacing);
+
+  total_pref_height = total_min_height;
+
+  for (i = 0; i < priv->n_rows; i++)
+    {
+      total_min_height += min_heights[i];
+      total_pref_height += pref_heights[i];
+    }
+
+  if (min_height_p)
+    *min_height_p = total_min_height;
+  if (natural_height_p)
+    *natural_height_p = total_pref_height;
+}
+
+static void
+st_table_paint (ClutterActor *self)
+{
+  StTablePrivate *priv = ST_TABLE (self)->priv;
+  GSList *list;
+
+  /* make sure the background gets painted first */
+  CLUTTER_ACTOR_CLASS (st_table_parent_class)->paint (self);
+
+  for (list = priv->children; list; list = g_slist_next (list))
+    {
+      ClutterActor *child = CLUTTER_ACTOR (list->data);
+      if (CLUTTER_ACTOR_IS_VISIBLE (child))
+        clutter_actor_paint (child);
+    }
+}
+
+static void
+st_table_pick (ClutterActor       *self,
+               const ClutterColor *color)
+{
+  StTablePrivate *priv = ST_TABLE (self)->priv;
+  GSList *list;
+
+  /* Chain up so we get a bounding box painted (if we are reactive) */
+  CLUTTER_ACTOR_CLASS (st_table_parent_class)->pick (self, color);
+
+  for (list = priv->children; list; list = g_slist_next (list))
+    {
+      if (CLUTTER_ACTOR_IS_VISIBLE (list->data))
+        clutter_actor_paint (CLUTTER_ACTOR (list->data));
+    }
+}
+
+static void
+st_table_show_all (ClutterActor *table)
+{
+  StTablePrivate *priv = ST_TABLE (table)->priv;
+  GSList *l;
+
+  for (l = priv->children; l; l = l->next)
+    clutter_actor_show_all (CLUTTER_ACTOR (l->data));
+
+  clutter_actor_show (table);
+}
+
+static void
+st_table_hide_all (ClutterActor *table)
+{
+  StTablePrivate *priv = ST_TABLE (table)->priv;
+  GSList *l;
+
+  clutter_actor_hide (table);
+
+  for (l = priv->children; l; l = l->next)
+    clutter_actor_hide_all (CLUTTER_ACTOR (l->data));
+}
+
+static void
+st_table_class_init (StTableClass *klass)
+{
+  GParamSpec *pspec;
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  /* StWidgetClass *st_widget_class = ST_WIDGET_CLASS (klass); */
+
+  g_type_class_add_private (klass, sizeof (StTablePrivate));
+
+  gobject_class->set_property = st_table_set_property;
+  gobject_class->get_property = st_table_get_property;
+  gobject_class->dispose = st_table_dispose;
+  gobject_class->finalize = st_table_finalize;
+
+  actor_class->paint = st_table_paint;
+  actor_class->pick = st_table_pick;
+  actor_class->allocate = st_table_allocate;
+  actor_class->get_preferred_width = st_table_get_preferred_width;
+  actor_class->get_preferred_height = st_table_get_preferred_height;
+  actor_class->show_all = st_table_show_all;
+  actor_class->hide_all = st_table_hide_all;
+
+  pspec = g_param_spec_boolean ("homogeneous",
+                                "Homogeneous",
+                                "Homogeneous rows and columns",
+                                TRUE,
+                                ST_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_HOMOGENEOUS,
+                                   pspec);
+
+  pspec = g_param_spec_int ("col-spacing",
+                            "Column Spacing",
+                            "Spacing between columns",
+                            0, G_MAXINT, 0,
+                            ST_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_COL_SPACING,
+                                   pspec);
+
+  pspec = g_param_spec_int ("row-spacing",
+                            "Row Spacing",
+                            "Spacing between row",
+                            0, G_MAXINT, 0,
+                            ST_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_ROW_SPACING,
+                                   pspec);
+
+  pspec = g_param_spec_int ("row-count",
+                            "Row Count",
+                            "The number of rows in the table",
+                            0, G_MAXINT, 0,
+                            ST_PARAM_READABLE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_ROW_COUNT,
+                                   pspec);
+
+  pspec = g_param_spec_int ("column-count",
+                            "Column Count",
+                            "The number of columns in the table",
+                            0, G_MAXINT, 0,
+                            ST_PARAM_READABLE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_COL_COUNT,
+                                   pspec);
+}
+
+static void
+st_table_init (StTable *table)
+{
+  table->priv = ST_TABLE_GET_PRIVATE (table);
+
+  table->priv->n_cols = 0;
+  table->priv->n_rows = 0;
+
+  table->priv->min_widths = g_array_new (FALSE,
+                                         TRUE,
+                                         sizeof (gint));
+  table->priv->pref_widths = g_array_new (FALSE,
+                                          TRUE,
+                                          sizeof (gint));
+  table->priv->min_heights = g_array_new (FALSE,
+                                          TRUE,
+                                          sizeof (gint));
+  table->priv->pref_heights = g_array_new (FALSE,
+                                           TRUE,
+                                           sizeof (gint));
+
+  table->priv->is_expand_col = g_array_new (FALSE,
+                                            TRUE,
+                                            sizeof (gboolean));
+  table->priv->is_expand_row = g_array_new (FALSE,
+                                            TRUE,
+                                            sizeof (gboolean));
+
+  table->priv->col_widths = g_array_new (FALSE,
+                                         TRUE,
+                                         sizeof (gint));
+  table->priv->row_heights = g_array_new (FALSE,
+                                          TRUE,
+                                          sizeof (gint));
+}
+
+/* used by StTableChild to update row/column count */
+void _st_table_update_row_col (StTable *table,
+                               gint     row,
+                               gint     col)
+{
+  if (col > -1)
+    table->priv->n_cols = MAX (table->priv->n_cols, col + 1);
+
+  if (row > -1)
+    table->priv->n_rows = MAX (table->priv->n_rows, row + 1);
+
+}
+
+/*** Public Functions ***/
+
+/**
+ * st_table_new:
+ *
+ * Create a new #StTable
+ *
+ * Returns: a new #StTable
+ */
+StWidget*
+st_table_new (void)
+{
+  return g_object_new (ST_TYPE_TABLE, NULL);
+}
+
+/**
+ * st_table_set_col_spacing
+ * @table: a #StTable
+ * @spacing: spacing in pixels
+ *
+ * Sets the amount of spacing between columns.
+ */
+void
+st_table_set_col_spacing (StTable *table,
+                          gint     spacing)
+{
+  StTablePrivate *priv;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (spacing >= 0);
+
+  priv = ST_TABLE (table)->priv;
+
+  priv->col_spacing = spacing;
+}
+
+/**
+ * st_table_set_row_spacing
+ * @table: a #StTable
+ * @spacing: spacing in pixels
+ *
+ * Sets the amount of spacing between rows.
+ */
+void
+st_table_set_row_spacing (StTable *table,
+                          gint     spacing)
+{
+  StTablePrivate *priv;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (spacing >= 0);
+
+  priv = ST_TABLE (table)->priv;
+
+  priv->row_spacing = spacing;
+}
+
+/**
+ * st_table_get_row_spacing
+ * @table: a #StTable
+ *
+ * Gets the amount of spacing between rows.
+ *
+ * Returns: the spacing between rows in device units
+ */
+gint
+st_table_get_row_spacing (StTable *table)
+{
+  StTablePrivate *priv;
+
+  g_return_val_if_fail (ST_IS_TABLE (table), -1);
+  priv = ST_TABLE (table)->priv;
+
+  return priv->row_spacing;
+}
+
+/**
+ * st_table_get_col_spacing
+ * @table: a #StTable
+ *
+ * Gets the amount of spacing between columns.
+ *
+ * Returns: the spacing between columns in device units
+ */
+gint
+st_table_get_col_spacing (StTable *table)
+{
+  StTablePrivate *priv;
+
+  g_return_val_if_fail (ST_IS_TABLE (table), -1);
+  priv = ST_TABLE (table)->priv;
+
+  return priv->col_spacing;
+}
+
+/**
+ * st_table_add_actor:
+ * @table: a #StTable
+ * @actor: the child to insert
+ * @row: the row to place the child into
+ * @column: the column to place the child into
+ *
+ * Add an actor at the specified row and column
+ *
+ * Note, column and rows numbers start from zero
+ */
+void
+st_table_add_actor (StTable      *table,
+                    ClutterActor *actor,
+                    gint          row,
+                    gint          column)
+{
+  StTableChild *meta;
+  ClutterContainer *container;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (CLUTTER_IS_ACTOR (actor));
+  g_return_if_fail (row >= -1);
+  g_return_if_fail (column >= -1);
+
+  if (row < 0)
+    row = table->priv->n_rows + 1;
+
+  if (column < 0)
+    column = table->priv->n_cols + 1;
+
+  container = CLUTTER_CONTAINER (table);
+  clutter_container_add_actor (container, actor);
+
+  meta = (StTableChild *) clutter_container_get_child_meta (container, actor);
+  meta->row = row;
+  meta->col = column;
+  _st_table_update_row_col (table, row, column);
+
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+}
+
+/**
+ * st_table_add_actor_with_properties
+ * @table: a #StTable
+ * @actor: the child #ClutterActor
+ * @row: the row to place the child into
+ * @column: the column to place the child into
+ * @first_property_name: name of the first property to set
+ * @...: value for the first property, followed optionally by more name/value pairs terminated with NULL.
+ *
+ * Add an actor into at the specified row and column, with additional child
+ * properties to set.
+ */
+void
+st_table_add_actor_with_properties (StTable      *table,
+                                    ClutterActor *actor,
+                                    gint          row,
+                                    gint          column,
+                                    const gchar  *first_property_name,
+                                    ...)
+{
+  va_list args;
+  StTableChild *meta;
+  ClutterContainer *container;
+
+  g_return_if_fail (ST_IS_TABLE (table));
+  g_return_if_fail (CLUTTER_IS_ACTOR (actor));
+  g_return_if_fail (row >= -1);
+  g_return_if_fail (column >= -1);
+  g_return_if_fail (first_property_name != NULL);
+
+  if (row < 0)
+    row = table->priv->n_rows + 1;
+
+  if (column < 0)
+    column = table->priv->n_cols + 1;
+
+  container = (ClutterContainer *) table;
+  clutter_container_add_actor (container, actor);
+
+  meta = (StTableChild *) clutter_container_get_child_meta (container, actor);
+  meta->row = row;
+  meta->col = column;
+  _st_table_update_row_col (table, row, column);
+
+  va_start (args, first_property_name);
+  g_object_set_valist ((GObject*) meta, first_property_name, args);
+  va_end (args);
+
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (table));
+}
+
+/**
+ * st_table_get_row_count:
+ * @table: A #StTable
+ *
+ * Retrieve the current number rows in the @table
+ *
+ * Returns: the number of rows
+ */
+gint
+st_table_get_row_count (StTable *table)
+{
+  g_return_val_if_fail (ST_IS_TABLE (table), -1);
+
+  return ST_TABLE (table)->priv->n_rows;
+}
+
+/**
+ * st_table_get_column_count:
+ * @table: A #StTable
+ *
+ * Retrieve the current number of columns in @table
+ *
+ * Returns: the number of columns
+ */
+gint
+st_table_get_column_count (StTable *table)
+{
+  g_return_val_if_fail (ST_IS_TABLE (table), -1);
+
+  return ST_TABLE (table)->priv->n_cols;
+}
diff --git a/src/st/st-table.h b/src/st/st-table.h
new file mode 100644
index 0000000..9da27d1
--- /dev/null
+++ b/src/st/st-table.h
@@ -0,0 +1,113 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * st-table.h: Table layout widget
+ *
+ * Copyright 2008, 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Thomas Wood  <thomas linux intel com>
+ *
+ */
+
+#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
+#error "Only <st/st.h> can be included directly.h"
+#endif
+
+#ifndef __ST_TABLE_H__
+#define __ST_TABLE_H__
+
+#include <st/st-types.h>
+#include <st/st-widget.h>
+
+G_BEGIN_DECLS
+
+/**
+ * StTableChildOptions:
+ * @ST_KEEP_ASPECT_RATIO: whether to respect the widget's aspect ratio
+ * @ST_X_EXPAND: whether to allocate extra space on the widget's x-axis
+ * @ST_Y_EXPAND: whether to allocate extra space on the widget's y-axis
+ * @ST_X_FILL: whether to stretch the child to fill the cell horizontally
+ * @ST_Y_FILL: whether to stretch the child to fill the cell vertically
+ *
+ * Denotes the child properties an StTable child will have.
+ */
+typedef enum
+{
+  ST_KEEP_ASPECT_RATIO = 1 << 0,
+  ST_X_EXPAND          = 1 << 1,
+  ST_Y_EXPAND          = 1 << 2,
+  ST_X_FILL            = 1 << 3,
+  ST_Y_FILL            = 1 << 4
+} StTableChildOptions;
+
+#define ST_TYPE_TABLE                (st_table_get_type ())
+#define ST_TABLE(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_TABLE, StTable))
+#define ST_IS_TABLE(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_TABLE))
+#define ST_TABLE_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_TABLE, StTableClass))
+#define ST_IS_TABLE_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_TABLE))
+#define ST_TABLE_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_TABLE, StTableClass))
+
+typedef struct _StTable              StTable;
+typedef struct _StTablePrivate       StTablePrivate;
+typedef struct _StTableClass         StTableClass;
+
+/**
+ * StTable:
+ *
+ * The contents of this structure is private and should only be accessed using
+ * the provided API.
+ */
+struct _StTable
+{
+  /*< private >*/
+  StWidget parent_instance;
+
+  StTablePrivate *priv;
+};
+
+struct _StTableClass
+{
+  StWidgetClass parent_class;
+};
+
+GType st_table_get_type (void) G_GNUC_CONST;
+
+StWidget* st_table_new (void);
+
+void st_table_set_col_spacing (StTable      *table,
+                               gint          spacing);
+void st_table_set_row_spacing (StTable      *table,
+                               gint          spacing);
+gint st_table_get_col_spacing (StTable      *table);
+gint st_table_get_row_spacing (StTable      *table);
+void st_table_add_actor       (StTable      *table,
+                               ClutterActor *actor,
+                               gint          row,
+                               gint          column);
+
+void st_table_add_actor_with_properties (StTable      *table,
+                                         ClutterActor *actor,
+                                         gint          row,
+                                         gint          column,
+                                         const gchar  *first_property_name,
+                                         ...);
+
+gint st_table_get_row_count    (StTable *table);
+gint st_table_get_column_count (StTable *table);
+
+G_END_DECLS
+
+#endif /* __ST_TABLE_H__ */



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