[gnome-shell/shell-toolkit] Import MxTable as StTable
- From: Owen Taylor <otaylor src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-shell/shell-toolkit] Import MxTable as StTable
- Date: Wed, 30 Sep 2009 14:23:04 +0000 (UTC)
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]