Don't forget to add the boxes
authorEmmanuele Bassi <ebassi@openedhand.com>
Thu, 14 Jun 2007 15:30:27 +0000 (15:30 +0000)
committerEmmanuele Bassi <ebassi@openedhand.com>
Thu, 14 Jun 2007 15:30:27 +0000 (15:30 +0000)
clutter/clutter-box.c [new file with mode: 0644]
clutter/clutter-box.h [new file with mode: 0644]
clutter/clutter-hbox.c [new file with mode: 0644]
clutter/clutter-hbox.h [new file with mode: 0644]
clutter/clutter-vbox.c [new file with mode: 0644]
clutter/clutter-vbox.h [new file with mode: 0644]

diff --git a/clutter/clutter-box.c b/clutter/clutter-box.c
new file mode 100644 (file)
index 0000000..9d2c83a
--- /dev/null
@@ -0,0 +1,409 @@
+#include "config.h"
+
+#include "cogl.h"
+
+#include "clutter-box.h"
+#include "clutter-container.h"
+#include "clutter-debug.h"
+#include "clutter-enum-types.h"
+#include "clutter-main.h"
+#include "clutter-private.h"
+
+/**
+ * SECTION:clutter-box
+ * @short_description: Base class for layout containers
+ *
+ * FIXME
+ *
+ * #ClutterBox is available since Clutter 0.4
+ */
+
+enum
+{
+  PROP_0,
+
+  PROP_SPACING
+};
+
+static void clutter_container_iface_init (ClutterContainerIface *iface);
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterBox,
+                                  clutter_box,
+                                  CLUTTER_TYPE_ACTOR,
+                                  G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
+                                                         clutter_container_iface_init));
+
+
+static void
+clutter_box_add (ClutterContainer *container,
+                 ClutterActor     *actor)
+{
+  clutter_box_pack_start (CLUTTER_BOX (container), actor);
+}
+
+static void
+clutter_box_remove (ClutterContainer *container,
+                    ClutterActor     *actor)
+{
+  ClutterBox *box = CLUTTER_BOX (container);
+  GList *l;
+
+  g_object_ref (actor);
+
+  for (l = box->children; l; l = l->next)
+    {
+      ClutterBoxChild *child = l->data;
+
+      if (child->actor == actor)
+        {
+          CLUTTER_BOX_GET_CLASS (box)->unpack_child (box, child);
+
+          clutter_actor_unparent (actor);
+          
+          box->children = g_list_remove_link (box->children, l);
+          g_list_free (l);
+          g_slice_free (ClutterBoxChild, child);
+
+          g_signal_emit_by_name (container, "actor-removed", actor);
+
+          if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (box)))
+            clutter_actor_queue_redraw (CLUTTER_ACTOR (box));
+          
+          break;
+        }
+    }
+
+  g_object_unref (actor);
+}
+
+static void
+clutter_box_foreach (ClutterContainer *container,
+                     ClutterCallback   callback,
+                     gpointer          user_data)
+{
+  ClutterBox *box = CLUTTER_BOX (container);
+  GList *l;
+
+  for (l = box->children; l; l = l->next)
+    {
+      ClutterBoxChild *child = l->data;
+
+      if (child->pack_type == CLUTTER_PACK_START)
+        (* callback) (child->actor, user_data);
+    }
+
+  for (l = g_list_last (box->children); l; l = l->prev)
+    {
+      ClutterBoxChild *child = l->data;
+
+      if (child->pack_type == CLUTTER_PACK_END)
+        (* callback) (child->actor, user_data);
+    }
+}
+
+static void
+clutter_container_iface_init (ClutterContainerIface *iface)
+{
+  iface->add = clutter_box_add;
+  iface->remove = clutter_box_remove;
+  iface->foreach = clutter_box_foreach;
+}
+
+static void
+clutter_box_show_all (ClutterActor *actor)
+{
+  ClutterBox *box = CLUTTER_BOX (actor);
+  GList *l;
+
+  for (l = box->children; l; l = l->next)
+    {
+      ClutterBoxChild *child = l->data;
+
+      clutter_actor_show (child->actor);
+    }
+
+  clutter_actor_show (actor);
+}
+
+static void
+clutter_box_hide_all (ClutterActor *actor)
+{
+  ClutterBox *box = CLUTTER_BOX (actor);
+  GList *l;
+
+  clutter_actor_hide (actor);
+
+  for (l = box->children; l; l = l->next)
+    {
+      ClutterBoxChild *child = l->data;
+
+      clutter_actor_hide (child->actor);
+    }
+}
+
+static void
+clutter_box_paint (ClutterActor *actor)
+{
+  ClutterBox *box = CLUTTER_BOX (actor);
+  GList *l;
+
+  cogl_push_matrix ();
+
+  for (l = box->children; l; l = l->next)
+    {
+      ClutterBoxChild *child = l->data;
+
+      if (CLUTTER_ACTOR_IS_MAPPED (child->actor))
+        clutter_actor_paint (child->actor);
+    }
+
+  cogl_pop_matrix ();
+}
+
+static void
+clutter_box_dispose (GObject *gobject)
+{
+  ClutterBox *box = CLUTTER_BOX (gobject);
+  GList *l;
+
+  for (l =  box->children; l; l = l->next)
+    {
+      ClutterBoxChild *child = l->data;
+
+      clutter_actor_destroy (child->actor);
+      g_slice_free (ClutterBoxChild, child);
+    }
+
+  g_list_free (box->children);
+  box->children = NULL;
+
+  G_OBJECT_CLASS (clutter_box_parent_class)->dispose (gobject);
+}
+
+static void
+clutter_box_pack_child_unimplemented (ClutterBox      *box,
+                                      ClutterBoxChild *child)
+{
+  g_warning ("ClutterBox of type `%s' does not implement the "
+             "ClutterBox::pack_child method.",
+             g_type_name (G_OBJECT_TYPE (box)));
+}
+
+static void
+clutter_box_unpack_child_unimplemented (ClutterBox      *box,
+                                        ClutterBoxChild *child)
+{
+  g_warning ("ClutterBox of type `%s' does not implement the "
+             "ClutterBox::unpack_child method.",
+             g_type_name (G_OBJECT_TYPE (box)));
+}
+
+static void
+clutter_box_set_property (GObject      *gobject,
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  ClutterBox *box = CLUTTER_BOX (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_SPACING:
+      box->spacing = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_box_get_property (GObject    *gobject,
+                          guint       prop_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+  ClutterBox *box = CLUTTER_BOX (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_SPACING:
+      g_value_set_uint (value, box->spacing);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_box_class_init (ClutterBoxClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  gobject_class->set_property = clutter_box_set_property;
+  gobject_class->get_property = clutter_box_get_property;
+  gobject_class->dispose = clutter_box_dispose;
+
+  actor_class->show_all = clutter_box_show_all;
+  actor_class->hide_all = clutter_box_hide_all;
+  actor_class->paint = clutter_box_paint;
+
+  klass->pack_child = clutter_box_pack_child_unimplemented;
+  klass->unpack_child = clutter_box_unpack_child_unimplemented;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_SPACING,
+                                   g_param_spec_uint ("spacing",
+                                                      "Spacing",
+                                                      "Space between each child actor",
+                                                      0, G_MAXUINT, 0,
+                                                      CLUTTER_PARAM_READWRITE));
+}
+
+static void
+clutter_box_init (ClutterBox *box)
+{
+
+}
+
+/*
+ * Public API
+ */
+
+/**
+ * clutter_box_pack_start:
+ * @box: a #ClutterBox
+ * @actor: a #ClutterActor
+ *
+ * Packs @actor into @box
+ *
+ * Since: 0.4
+ */
+void
+clutter_box_pack_start (ClutterBox   *box,
+                        ClutterActor *actor)
+{
+  ClutterBoxChild *child;
+
+  g_return_if_fail (CLUTTER_IS_BOX (box));
+  g_return_if_fail (CLUTTER_IS_ACTOR (actor));
+
+  child = g_slice_new (ClutterBoxChild);
+  child->actor = actor;
+  child->pack_type = CLUTTER_PACK_START;
+
+  CLUTTER_BOX_GET_CLASS (box)->pack_child (box, child);
+  
+  box->children = g_list_append (box->children, child);
+  clutter_actor_set_parent (actor, CLUTTER_ACTOR (box));
+
+  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (box)))
+    clutter_actor_queue_redraw (CLUTTER_ACTOR (box));
+}
+
+/**
+ * clutter_box_pack_end:
+ * @box: a #ClutterBox
+ * @actor: a #ClutterActor
+ *
+ * Packs @actor into @box
+ *
+ * Since: 0.4
+ */
+void
+clutter_box_pack_end (ClutterBox   *box,
+                      ClutterActor *actor)
+{
+  ClutterBoxChild *child;
+
+  g_return_if_fail (CLUTTER_IS_BOX (box));
+  g_return_if_fail (CLUTTER_IS_ACTOR (actor));
+
+  child = g_slice_new (ClutterBoxChild);
+  child->actor = actor;
+  child->pack_type = CLUTTER_PACK_END;
+
+  box->children = g_list_append (box->children, child);
+  clutter_actor_set_parent (actor, CLUTTER_ACTOR (box));
+
+  CLUTTER_BOX_GET_CLASS (box)->pack_child (box, child);
+
+  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (box)))
+    clutter_actor_queue_redraw (CLUTTER_ACTOR (box));
+}
+
+gboolean
+clutter_box_query_child (ClutterBox      *box,
+                         ClutterActor    *actor,
+                         ClutterBoxChild *child)
+{
+  GList *l;
+
+  g_return_val_if_fail (CLUTTER_IS_BOX (box), FALSE);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
+
+  for (l = box->children; l; l = l->next)
+    {
+      ClutterBoxChild *box_child = l->data;
+
+      if (box_child->actor == actor)
+        {
+          if (child)
+            {
+              child->actor = actor;
+              child->pack_type = box_child->pack_type;
+            }
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+gboolean
+clutter_box_query_nth_child (ClutterBox      *box,
+                             gint             index,
+                             ClutterBoxChild *child)
+{
+  ClutterBoxChild *box_child;
+
+  g_return_val_if_fail (CLUTTER_IS_BOX (box), FALSE);
+  g_return_val_if_fail (index > 0, FALSE);
+
+  box_child = g_list_nth_data (box->children, index);
+  if (!box_child)
+    return FALSE;
+
+  if (child)
+    {
+      child->actor = box_child->actor;
+      child->pack_type = box_child->pack_type;
+    }
+
+  return TRUE;
+}
+
+guint
+clutter_box_get_spacing (ClutterBox *box)
+{
+  g_return_val_if_fail (CLUTTER_IS_BOX (box), 0);
+
+  return box->spacing;
+}
+
+void
+clutter_box_set_spacing (ClutterBox *box,
+                         guint       spacing)
+{
+  g_return_if_fail (CLUTTER_IS_BOX (box));
+
+  if (box->spacing != spacing)
+    {
+      box->spacing = spacing;
+
+      g_object_notify (G_OBJECT (box), "spacing");
+    }
+}
diff --git a/clutter/clutter-box.h b/clutter/clutter-box.h
new file mode 100644 (file)
index 0000000..23b2c8e
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef __CLUTTER_BOX_H__
+#define __CLUTTER_BOX_H__
+
+#include <clutter/clutter-actor.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_BOX                (clutter_box_get_type ())
+#define CLUTTER_BOX(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BOX, ClutterBox))
+#define CLUTTER_IS_BOX(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BOX))
+#define CLUTTER_BOX_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BOX, ClutterBoxClass))
+#define CLUTTER_IS_BOX_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BOX))
+#define CLUTTER_BOX_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BOX, ClutterBoxClass))
+
+/**
+ * ClutterPackType:
+ *
+ * Pack order for a #ClutterBox child.
+ *
+ * @CLUTTER_PACK_START: append child from the start
+ * @CLUTTER_PACK_END: append child from the end
+ *
+ * Since: 0.4
+ */
+typedef enum {
+  CLUTTER_PACK_START,
+  CLUTTER_PACK_END
+} ClutterPackType;
+
+typedef struct _ClutterBoxChild         ClutterBoxChild;
+typedef struct _ClutterBox              ClutterBox; 
+typedef struct _ClutterBoxClass         ClutterBoxClass;
+
+struct _ClutterBox
+{
+  ClutterActor parent_instance;
+
+  /*< private >*/
+
+  /* list of ClutterBoxChild structures */
+  GList *children;
+
+  /* spacing between child actors */
+  guint spacing;
+};
+
+struct _ClutterBoxClass
+{
+  ClutterActorClass parent_class;
+
+  /* vfuncs, not signals */
+  void (* pack_child)   (ClutterBox      *box,
+                         ClutterBoxChild *child);
+  void (* unpack_child) (ClutterBox      *box,
+                         ClutterBoxChild *child);
+
+  /* padding, for future expansion */
+  void (*_clutter_reserved1) (void);
+  void (*_clutter_reserved2) (void);
+  void (*_clutter_reserved3) (void);
+  void (*_clutter_reserved4) (void);
+  void (*_clutter_reserved5) (void);
+  void (*_clutter_reserved6) (void);
+  void (*_clutter_reserved7) (void);
+  void (*_clutter_reserved8) (void);
+};
+
+/**
+ * ClutterBoxChild:
+ *
+ * Packing data for children of a #ClutterBox.
+ *
+ * @actor: the child #ClutterActor
+ * @pack_type: the type of packing used
+ *
+ * Since: 0.4
+ */
+struct _ClutterBoxChild
+{
+  ClutterActor *actor;
+
+  ClutterPackType pack_type;
+};
+
+GType    clutter_box_get_type        (void) G_GNUC_CONST;
+void     clutter_box_set_spacing     (ClutterBox      *box,
+                                      guint            spacing);
+guint    clutter_box_get_spacing     (ClutterBox      *box);
+void     clutter_box_pack_start      (ClutterBox      *box,
+                                      ClutterActor    *actor);
+void     clutter_box_pack_end        (ClutterBox      *box,
+                                      ClutterActor    *actor);
+gboolean clutter_box_query_child     (ClutterBox      *box,
+                                      ClutterActor    *actor,
+                                      ClutterBoxChild *child);
+gboolean clutter_box_query_nth_child (ClutterBox      *box,
+                                      gint             index,
+                                      ClutterBoxChild *child);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_BOX_H__ */
diff --git a/clutter/clutter-hbox.c b/clutter/clutter-hbox.c
new file mode 100644 (file)
index 0000000..fdd8f81
--- /dev/null
@@ -0,0 +1,169 @@
+#include "config.h"
+
+#include "clutter-hbox.h"
+
+#include "clutter-box.h"
+#include "clutter-container.h"
+#include "clutter-layout.h"
+#include "clutter-debug.h"
+#include "clutter-units.h"
+#include "clutter-enum-types.h"
+#include "clutter-main.h"
+#include "clutter-private.h"
+
+/**
+ * SECTION:clutter-hbox
+ * @short_description: Simple horizontal box
+ *
+ * FIXME
+ *
+ * #ClutterHBox is available since Clutter 0.4.
+ */
+
+enum
+{
+  PROP_0,
+
+  PROP_LAYOUT_FLAGS
+};
+
+static void clutter_layout_iface_init (ClutterLayoutIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ClutterHBox,
+                         clutter_hbox,
+                         CLUTTER_TYPE_BOX,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_LAYOUT,
+                                                clutter_layout_iface_init));
+
+static void
+clutter_hbox_query_coords (ClutterActor    *actor,
+                           ClutterActorBox *coords)
+{
+  ClutterBox *box = CLUTTER_BOX (actor);
+  GList *l;
+  gint width, height;
+  guint spacing;
+
+  spacing = clutter_box_get_spacing (box);
+  width = height = 0;
+  
+  for (l = box->children; l; l = l->next)
+    {
+      ClutterBoxChild *child = l->data;
+      
+      if (CLUTTER_ACTOR_IS_VISIBLE (child->actor))
+        {
+          guint child_width, child_height;
+
+          clutter_actor_get_size (child->actor, &child_width, &child_height);
+
+          width += child_width + (spacing * 2);
+          height = MAX (child_height, height);
+        }
+    }
+
+  coords->x2 = coords->x1 + CLUTTER_UNITS_FROM_INT (width);
+  coords->y2 = coords->y1 + CLUTTER_UNITS_FROM_INT (height);
+}
+
+static void
+clutter_hbox_request_coords (ClutterActor    *actor,
+                             ClutterActorBox *coords)
+{
+  /* FIXME */
+}
+
+static void
+clutter_hbox_pack_child (ClutterBox      *box,
+                         ClutterBoxChild *child)
+{
+  ClutterGeometry box_geom, child_geom;
+  guint spacing;
+
+  spacing = clutter_box_get_spacing (box);
+
+  clutter_actor_get_geometry (CLUTTER_ACTOR (box), &box_geom);
+  clutter_actor_get_geometry (child->actor, &child_geom);
+
+  child_geom.x = box_geom.x + box_geom.width + spacing;
+  child_geom.y = box_geom.y;
+
+  clutter_actor_set_geometry (child->actor, &child_geom);
+}
+
+static void
+clutter_hbox_unpack_child (ClutterBox      *box,
+                           ClutterBoxChild *child)
+{
+  /* no need to do anything */
+}
+
+static ClutterLayoutFlags
+clutter_hbox_get_layout_flags (ClutterLayout *layout)
+{
+  return CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH;
+}
+
+static void
+clutter_hbox_height_for_width (ClutterLayout *layout,
+                               gint           width,
+                               gint          *height)
+{
+
+}
+
+static void
+clutter_hbox_get_property (GObject    *gobject,
+                           guint       prop_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+  switch (prop_id)
+    {
+    case PROP_LAYOUT_FLAGS:
+      g_value_set_enum (value, CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_layout_iface_init (ClutterLayoutIface *iface)
+{
+  iface->get_layout_flags = clutter_hbox_get_layout_flags;
+  iface->height_for_width = clutter_hbox_height_for_width;
+}
+
+static void
+clutter_hbox_class_init (ClutterHBoxClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  ClutterBoxClass *box_class = CLUTTER_BOX_CLASS (klass);
+
+  gobject_class->get_property = clutter_hbox_get_property;
+
+  actor_class->query_coords = clutter_hbox_query_coords;
+  actor_class->request_coords = clutter_hbox_request_coords;
+
+  box_class->pack_child = clutter_hbox_pack_child;
+  box_class->unpack_child = clutter_hbox_unpack_child;
+
+  g_object_class_override_property (gobject_class,
+                                    PROP_LAYOUT_FLAGS,
+                                    "layout-flags");
+}
+
+static void
+clutter_hbox_init (ClutterHBox *box)
+{
+
+}
+
+ClutterActor *
+clutter_hbox_new (void)
+{
+  return g_object_new (CLUTTER_TYPE_HBOX, NULL);
+}
diff --git a/clutter/clutter-hbox.h b/clutter/clutter-hbox.h
new file mode 100644 (file)
index 0000000..2cc854b
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __CLUTTER_HBOX_H__
+#define __CLUTTER_HBOX_H__
+
+#include <clutter/clutter-box.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_HBOX               (clutter_hbox_get_type ())
+#define CLUTTER_HBOX(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_HBOX, ClutterHBox))
+#define CLUTTER_IS_HBOX(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_HBOX))
+#define CLUTTER_HBOX_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_HBOX, ClutterHBoxClass))
+#define CLUTTER_IS_HBOX_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_HBOX))
+#define CLUTTER_HBOX_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_HBOX, ClutterHBoxClass))
+
+typedef struct _ClutterHBox             ClutterHBox;
+typedef struct _ClutterHBoxClass        ClutterHBoxClass;
+
+struct _ClutterHBox
+{
+  ClutterBox parent_instance;
+};
+
+struct _ClutterHBoxClass
+{
+  ClutterBoxClass parent_class;
+};
+
+GType         clutter_hbox_get_type (void) G_GNUC_CONST;
+ClutterActor *clutter_hbox_new      (void);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_HBOX_H__ */
diff --git a/clutter/clutter-vbox.c b/clutter/clutter-vbox.c
new file mode 100644 (file)
index 0000000..1e1e3fc
--- /dev/null
@@ -0,0 +1,169 @@
+#include "config.h"
+
+#include "clutter-vbox.h"
+
+#include "clutter-box.h"
+#include "clutter-container.h"
+#include "clutter-layout.h"
+#include "clutter-debug.h"
+#include "clutter-units.h"
+#include "clutter-enum-types.h"
+#include "clutter-main.h"
+#include "clutter-private.h"
+
+/**
+ * SECTION:clutter-vbox
+ * @short_description: Simple horizontal box
+ *
+ * FIXME
+ *
+ * #ClutterVBox is available since Clutter 0.4.
+ */
+
+enum
+{
+  PROP_0,
+
+  PROP_LAYOUT_FLAGS
+};
+
+static void clutter_layout_iface_init (ClutterLayoutIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ClutterVBox,
+                         clutter_vbox,
+                         CLUTTER_TYPE_BOX,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_LAYOUT,
+                                                clutter_layout_iface_init));
+
+static void
+clutter_vbox_query_coords (ClutterActor    *actor,
+                           ClutterActorBox *coords)
+{
+  ClutterBox *box = CLUTTER_BOX (actor);
+  GList *l;
+  gint width, height;
+  guint spacing;
+
+  spacing = clutter_box_get_spacing (box);
+  width = height = 0;
+  
+  for (l = box->children; l; l = l->next)
+    {
+      ClutterBoxChild *child = l->data;
+      
+      if (CLUTTER_ACTOR_IS_VISIBLE (child->actor))
+        {
+          guint child_width, child_height;
+
+          clutter_actor_get_size (child->actor, &child_width, &child_height);
+
+          width = MAX (child_width, width);
+          height += child_height + (spacing * 2);
+        }
+    }
+
+  coords->x2 = coords->x1 + CLUTTER_UNITS_FROM_INT (width);
+  coords->y2 = coords->y1 + CLUTTER_UNITS_FROM_INT (height);
+}
+
+static void
+clutter_vbox_request_coords (ClutterActor    *actor,
+                             ClutterActorBox *coords)
+{
+  /* FIXME */
+}
+
+static void
+clutter_vbox_pack_child (ClutterBox      *box,
+                         ClutterBoxChild *child)
+{
+  ClutterGeometry box_geom, child_geom;
+  guint spacing;
+
+  spacing = clutter_box_get_spacing (box);
+
+  clutter_actor_get_geometry (CLUTTER_ACTOR (box), &box_geom);
+  clutter_actor_get_geometry (child->actor, &child_geom);
+
+  child_geom.x = box_geom.x;
+  child_geom.y = box_geom.y + box_geom.height + spacing;
+
+  clutter_actor_set_geometry (child->actor, &child_geom);
+}
+
+static void
+clutter_vbox_unpack_child (ClutterBox      *box,
+                           ClutterBoxChild *child)
+{
+  /* no need to do anything */
+}
+
+static ClutterLayoutFlags
+clutter_vbox_get_layout_flags (ClutterLayout *layout)
+{
+  return CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT;
+}
+
+static void
+clutter_vbox_width_for_height (ClutterLayout *layout,
+                               gint          *width,
+                               gint           height)
+{
+
+}
+
+static void
+clutter_vbox_get_property (GObject    *gobject,
+                           guint       prop_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+  switch (prop_id)
+    {
+    case PROP_LAYOUT_FLAGS:
+      g_value_set_enum (value, CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_layout_iface_init (ClutterLayoutIface *iface)
+{
+  iface->get_layout_flags = clutter_vbox_get_layout_flags;
+  iface->width_for_height = clutter_vbox_width_for_height;
+}
+
+static void
+clutter_vbox_class_init (ClutterVBoxClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  ClutterBoxClass *box_class = CLUTTER_BOX_CLASS (klass);
+
+  gobject_class->get_property = clutter_vbox_get_property;
+
+  actor_class->query_coords = clutter_vbox_query_coords;
+  actor_class->request_coords = clutter_vbox_request_coords;
+
+  box_class->pack_child = clutter_vbox_pack_child;
+  box_class->unpack_child = clutter_vbox_unpack_child;
+
+  g_object_class_override_property (gobject_class,
+                                    PROP_LAYOUT_FLAGS,
+                                    "layout-flags");
+}
+
+static void
+clutter_vbox_init (ClutterVBox *box)
+{
+
+}
+
+ClutterActor *
+clutter_vbox_new (void)
+{
+  return g_object_new (CLUTTER_TYPE_VBOX, NULL);
+}
diff --git a/clutter/clutter-vbox.h b/clutter/clutter-vbox.h
new file mode 100644 (file)
index 0000000..d8d1944
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __CLUTTER_VBOX_H__
+#define __CLUTTER_VBOX_H__
+
+#include <clutter/clutter-box.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_VBOX               (clutter_vbox_get_type ())
+#define CLUTTER_VBOX(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_VBOX, ClutterVBox))
+#define CLUTTER_IS_VBOX(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_VBOX))
+#define CLUTTER_VBOX_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_VBOX, ClutterVBoxClass))
+#define CLUTTER_IS_VBOX_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_VBOX))
+#define CLUTTER_VBOX_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_VBOX, ClutterVBoxClass))
+
+typedef struct _ClutterVBox             ClutterVBox;
+typedef struct _ClutterVBoxClass        ClutterVBoxClass;
+
+struct _ClutterVBox
+{
+  ClutterBox parent_instance;
+};
+
+struct _ClutterVBoxClass
+{
+  ClutterBoxClass parent_class;
+};
+
+GType         clutter_vbox_get_type (void) G_GNUC_CONST;
+ClutterActor *clutter_vbox_new      (void);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_VBOX_H__ */