[gtk+/wip/actor: 7/42] xxx: Add layout managers



commit b97aab56eae6f95c2e38a74010ff8b0587cc5887
Author: Benjamin Otte <otte redhat com>
Date:   Sun Dec 9 02:18:45 2012 +0100

    xxx: Add layout managers

 gtk/actors/Makefile.am               |    6 +-
 gtk/actors/gtkactor.c                |  146 ++++++++++-
 gtk/actors/gtkactorprivate.h         |   41 ++--
 gtk/actors/gtklayoutmanager.c        |  498 ++++++++++++++++++++++++++++++++++
 gtk/actors/gtklayoutmanagerprivate.h |  134 +++++++++
 5 files changed, 802 insertions(+), 23 deletions(-)
---
diff --git a/gtk/actors/Makefile.am b/gtk/actors/Makefile.am
index 58377f9..86e00a2 100644
--- a/gtk/actors/Makefile.am
+++ b/gtk/actors/Makefile.am
@@ -4,11 +4,13 @@ noinst_LTLIBRARIES = libgtkactors.la
 
 gtkactors_c_sources =			\
 	gtkactor.c			\
-	gtkcssbox.c
+	gtkcssbox.c			\
+	gtklayoutmanager.c
 
 gtkactors_private_h_sources =		\
 	gtkactorprivate.h		\
-	gtkcssboxprivate.h
+	gtkcssboxprivate.h		\
+	gtklayoutmanagerprivate.h
 
 libgtkactors_la_SOURCES = 		\
 	$(gtkactors_c_sources)		\
diff --git a/gtk/actors/gtkactor.c b/gtk/actors/gtkactor.c
index 40463ae..aab7dcb 100644
--- a/gtk/actors/gtkactor.c
+++ b/gtk/actors/gtkactor.c
@@ -24,6 +24,7 @@
 #include "gtkactorprivate.h"
 #include "gtkdebug.h"
 #include "gtkintl.h"
+#include "actors/gtklayoutmanagerprivate.h"
 #include "gtkprivate.h"
 #include "gtksizerequestcacheprivate.h"
 #include "gtktypebuiltins.h"
@@ -32,6 +33,8 @@
 struct _GtkActorPrivate {
   SizeRequestCache requests;
 
+  GtkLayoutManager *layout_manager;
+
   cairo_matrix_t transform;
   gfloat width;
   gfloat height;
@@ -81,6 +84,8 @@ enum
 
   PROP_TEXT_DIRECTION,
 
+  PROP_LAYOUT_MANAGER,
+
   PROP_FIRST_CHILD,
   PROP_LAST_CHILD,
 
@@ -92,6 +97,16 @@ static GParamSpec *obj_props[PROP_LAST];
 G_DEFINE_TYPE (GtkActor, _gtk_actor, G_TYPE_INITIALLY_UNOWNED)
 
 static void
+gtk_actor_dispose (GObject *object)
+{
+  GtkActor *self = GTK_ACTOR (object);
+
+  _gtk_actor_set_layout_manager (self, NULL);
+
+  G_OBJECT_CLASS (_gtk_actor_parent_class)->dispose (object);
+}
+
+static void
 gtk_actor_finalize (GObject *object)
 {
   GtkActor *self = GTK_ACTOR (object);
@@ -121,6 +136,10 @@ gtk_actor_set_property (GObject      *object,
       _gtk_actor_set_text_direction (actor, g_value_get_enum (value));
       break;
 
+    case PROP_LAYOUT_MANAGER:
+      _gtk_actor_set_layout_manager (actor, g_value_get_object (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -154,6 +173,10 @@ gtk_actor_get_property (GObject    *object,
       g_value_set_enum (value, _gtk_actor_get_text_direction (actor));
       break;
 
+    case PROP_LAYOUT_MANAGER:
+      g_value_set_object (value, _gtk_actor_get_layout_manager (actor));
+      break;
+
     case PROP_FIRST_CHILD:
       g_value_set_object (value, priv->first_child);
       break;
@@ -334,12 +357,25 @@ gtk_actor_real_get_request_mode (GtkActor *self)
 static void
 gtk_actor_real_get_preferred_size (GtkActor       *self,
                                    GtkOrientation  orientation,
-                                   gfloat          for_width,
+                                   gfloat          for_size,
                                    gfloat         *min_size_p,
-                                   gfloat         *natural_size_p)
+                                   gfloat         *nat_size_p)
 {
-  *min_size_p = 0;
-  *natural_size_p = 0;
+  GtkActorPrivate *priv = self->priv;
+
+  if (priv->layout_manager)
+    {
+      _gtk_layout_manager_get_preferred_size (priv->layout_manager,
+                                              orientation,
+                                              for_size,
+                                              min_size_p,
+                                              nat_size_p);
+    }
+  else
+    {
+      *min_size_p = 0;
+      *nat_size_p = 0;
+    }
 }
 
 static void
@@ -349,6 +385,16 @@ gtk_actor_real_allocate (GtkActor *self,
 {
   GtkActorPrivate *priv = self->priv;
 
+  if (priv->layout_manager &&
+      GTK_ACTOR_GET_CLASS (self)->allocate == gtk_actor_real_allocate)
+    {
+      cairo_matrix_t identity = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 };
+
+      _gtk_layout_manager_allocate (priv->layout_manager,
+                                    &identity,
+                                    width, height);
+    }
+
   priv->width = width;
   priv->height = height;
   priv->needs_allocation = FALSE;
@@ -359,6 +405,7 @@ _gtk_actor_class_init (GtkActorClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  object_class->dispose = gtk_actor_dispose;
   object_class->finalize = gtk_actor_finalize;
   object_class->set_property = gtk_actor_set_property;
   object_class->get_property = gtk_actor_get_property;
@@ -438,6 +485,21 @@ _gtk_actor_class_init (GtkActorClass *klass)
                        GTK_PARAM_READWRITE);
 
   /**
+   * GtkActor:layout-manager:
+   *
+   * A delegate object for controlling the layout of the children of
+   * an actor.
+   *
+   * Since: 1.10
+   */
+  obj_props[PROP_LAYOUT_MANAGER] =
+    g_param_spec_object ("layout-manager",
+                         P_("Layout Manager"),
+                         P_("The object controlling the layout of an actor's children"),
+                         GTK_TYPE_LAYOUT_MANAGER,
+                         GTK_PARAM_READWRITE);
+
+  /**
    * GtkActor:first-child:
    *
    * The actor's first child.
@@ -2279,3 +2341,79 @@ _gtk_actor_get_screen (GtkActor *self)
   /* FIXME */
   return gdk_screen_get_default ();
 }
+
+/**
+ * _gtk_actor_set_layout_manager:
+ * @self: a #GtkActor
+ * @manager: (allow-none): a #GtkLayoutManager, or %NULL to unset it
+ *
+ * Sets the #GtkLayoutManager delegate object that will be used to
+ * lay out the children of @self. The @manager must not yet be used with
+ * a different #GtkActor.
+ *
+ * The #GtkActor will take a reference on the passed @manager which
+ * will be released either when the layout manager is removed, or when
+ * the actor is destroyed.
+ *
+ * Since: 1.10
+ */
+void
+_gtk_actor_set_layout_manager (GtkActor         *self,
+                               GtkLayoutManager *manager)
+{
+  GtkActorPrivate *priv;
+
+  g_return_if_fail (GTK_IS_ACTOR (self));
+  g_return_if_fail (manager == NULL || GTK_IS_LAYOUT_MANAGER (manager));
+  if (manager)
+    g_return_if_fail (_gtk_layout_manager_get_actor (manager) == NULL);
+
+  priv = self->priv;
+
+  if (priv->layout_manager == manager)
+    return;
+
+  if (priv->layout_manager != NULL)
+    {
+      _gtk_layout_manager_set_actor (priv->layout_manager, NULL);
+      g_clear_object (&priv->layout_manager);
+    }
+
+  priv->layout_manager = manager;
+
+  if (priv->layout_manager != NULL)
+    {
+      g_object_ref_sink (priv->layout_manager);
+      _gtk_layout_manager_set_actor (priv->layout_manager, self);
+    }
+
+  _gtk_actor_layout_manager_changed (self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
+}
+
+void
+_gtk_actor_layout_manager_changed (GtkActor *self)
+{
+  _gtk_actor_queue_relayout (self);
+}
+
+/**
+ * _gtk_actor_get_layout_manager:
+ * @self: a #GtkActor
+ *
+ * Retrieves the #GtkLayoutManager used by @self.
+ *
+ * Return value: (transfer none): a pointer to the #GtkLayoutManager,
+ *   or %NULL
+ *
+ * Since: 1.10
+ */
+GtkLayoutManager *
+_gtk_actor_get_layout_manager (GtkActor *self)
+{
+  g_return_val_if_fail (GTK_IS_ACTOR (self), NULL);
+
+  return self->priv->layout_manager;
+}
+
diff --git a/gtk/actors/gtkactorprivate.h b/gtk/actors/gtkactorprivate.h
index 9bc0175..7d119d4 100644
--- a/gtk/actors/gtkactorprivate.h
+++ b/gtk/actors/gtkactorprivate.h
@@ -35,6 +35,9 @@ G_BEGIN_DECLS
 #define GTK_IS_ACTOR_CLASS(obj)  (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_ACTOR))
 #define GTK_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_ACTOR, GtkActorClass))
 
+/* forward declarations go here */
+typedef struct _GtkLayoutManager   GtkLayoutManager;
+
 typedef struct _GtkActor           GtkActor;
 typedef struct _GtkActorPrivate    GtkActorPrivate;
 typedef struct _GtkActorClass      GtkActorClass;
@@ -116,25 +119,29 @@ gboolean                        _gtk_actor_get_mapped
 gboolean                        _gtk_actor_get_realized                         (GtkActor                   *self);
 
 /* Size negotiation */
-GtkSizeRequestMode              _gtk_actor_get_request_mode                     (GtkActor                    *self);
-void                            _gtk_actor_get_preferred_size                   (GtkActor                    *self,
-                                                                                 GtkOrientation               orientation,
-                                                                                 gfloat                       for_size,
-                                                                                 gfloat                      *min_size_p,
-                                                                                 gfloat                      *natural_size_p);
-gfloat                          _gtk_actor_get_width                            (GtkActor                    *self);
-gfloat                          _gtk_actor_get_height                           (GtkActor                    *self);
-void                            _gtk_actor_allocate                             (GtkActor                    *self,
-                                                                                 gfloat                       width,
-                                                                                 gfloat                       height);
-const cairo_matrix_t *          _gtk_actor_get_position                         (GtkActor                    *actor);
+GtkSizeRequestMode              _gtk_actor_get_request_mode                     (GtkActor                   *self);
+void                            _gtk_actor_get_preferred_size                   (GtkActor                   *self,
+                                                                                 GtkOrientation              orientation,
+                                                                                 gfloat                      for_size,
+                                                                                 gfloat                     *min_size_p,
+                                                                                 gfloat                     *natural_size_p);
+gfloat                          _gtk_actor_get_width                            (GtkActor                   *self);
+gfloat                          _gtk_actor_get_height                           (GtkActor                   *self);
+void                            _gtk_actor_allocate                             (GtkActor                   *self,
+                                                                                 gfloat                      width,
+                                                                                 gfloat                      height);
+const cairo_matrix_t *          _gtk_actor_get_position                         (GtkActor                   *actor);
 /* XXX: Do we wanna support that?
-void                            _gtk_actor_position                             (GtkActor                    *actor,
-                                                                                 const cairo_matrix_t *       position);
+void                            _gtk_actor_position                             (GtkActor                   *actor,
+                                                                                 const cairo_matrix_t       *position);
 */
-void                            _gtk_actor_position_at                          (GtkActor                    *actor,
-                                                                                 gfloat                       x,
-                                                                                 gfloat                       y);
+void                            _gtk_actor_position_at                          (GtkActor                   *actor,
+                                                                                 gfloat                      x,
+                                                                                 gfloat                      y);
+void                            _gtk_actor_set_layout_manager                   (GtkActor                   *actor,
+                                                                                 GtkLayoutManager           *layout_manager);
+GtkLayoutManager *              _gtk_actor_get_layout_manager                   (GtkActor                   *actor);
+void                            _gtk_actor_layout_manager_changed               (GtkActor                   *self);
 
 /* Text */
 void                            _gtk_actor_set_text_direction                   (GtkActor                   *self,
diff --git a/gtk/actors/gtklayoutmanager.c b/gtk/actors/gtklayoutmanager.c
new file mode 100644
index 0000000..2ff490a
--- /dev/null
+++ b/gtk/actors/gtklayoutmanager.c
@@ -0,0 +1,498 @@
+/*
+ * Gtk.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2009  Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Emmanuele Bassi <ebassi linux intel com>
+ */
+
+/**
+ * SECTION:_gtk-layout-manager
+ * @short_description: Layout managers base class
+ *
+ * #GtkLayoutManager is a base abstract class for layout managers. A
+ * layout manager implements the layouting policy for a composite or a
+ * container actor: it controls the preferred size of the actor to which
+ * it has been paired, and it controls the allocation of its children.
+ *
+ * Any composite or container #GtkActor subclass can delegate the
+ * layouting of its children to a #GtkLayoutManager.
+ *
+ * Gtk provides some simple #GtkLayoutManager sub-classes, like
+ * #GtkBoxLayout and #GtkBinLayout.
+ *
+ * <refsect2 id="GtkLayoutManager-use-in-Actor">
+ *   <title>Using a Layout Manager inside an Actor</title>
+ *   <para>In order to use a #GtkLayoutManager inside a #GtkActor
+ *   sub-class you should invoke _gtk_layout_manager_get_preferred_size()
+ *   inside the #GtkActorClass.get_preferred_size() virtual function and
+ *   _gtk_layout_manager_get_preferred_height() inside the
+ *   #GtkActorClass.get_preferred_height() virtual functions implementation.
+ *   You should also call _gtk_layout_manager_allocate() inside the
+ *   implementation of the #GtkActorClass.allocate() virtual function.</para>
+ *   <para>In order to receive notifications for changes in the layout
+ *   manager policies you should also connect to the
+ *   #GtkLayoutManager::layout-changed signal and queue a relayout
+ *   on your actor. The following code should be enough if the actor
+ *   does not need to perform specific operations whenever a layout
+ *   manager changes:</para>
+ *   <informalexample><programlisting>
+ *  g_signal_connect_swapped (layout_manager,
+ *                            "layout-changed",
+ *                            G_CALLBACK (_gtk_actor_queue_relayout),
+ *                            actor);
+ *   </programlisting></informalexample>
+ * </refsect2>
+ *
+ * <refsect2 id="GtkLayoutManager-implementation">
+ *   <title>Implementing a GtkLayoutManager</title>
+ *   <para>The implementation of a layout manager does not differ from
+ *   the implementation of the size requisition and allocation bits of
+ *   #GtkActor, so you should read the relative documentation
+ *   <link linkend="_gtk-subclassing-GtkActor">for subclassing
+ *   GtkActor</link>.</para>
+ *   <para>The layout manager implementation can hold a back pointer
+ *   to the #GtkContainer by implementing the
+ *   <function>set_container()</function> virtual function. The layout manager
+ *   should not hold a real reference (i.e. call g_object_ref()) on the
+ *   container actor, to avoid reference cycles.</para>
+ *   <para>If a layout manager has properties affecting the layout
+ *   policies then it should emit the #GtkLayoutManager::layout-changed
+ *   signal on itself by using the _gtk_layout_manager_layout_changed()
+ *   function whenever one of these properties changes.</para>
+ * </refsect2>
+ *
+ * <refsect2 id="GtkLayoutManager-animation">
+ *   <title>Animating a GtkLayoutManager</title>
+ *   <para>A layout manager is used to let a #GtkContainer take complete
+ *   ownership over the layout (that is: the position and sizing) of its
+ *   children; this means that using the Gtk animation API, like
+ *   _gtk_actor_animate(), to animate the position and sizing of a child of
+ *   a layout manager it is not going to work properly, as the animation will
+ *   automatically override any setting done by the layout manager
+ *   itself.</para>
+ *   <para>It is possible for a #GtkLayoutManager sub-class to animate its
+ *   children layout by using the base class animation support. The
+ *   #GtkLayoutManager animation support consists of three virtual
+ *   functions: #GtkLayoutManagerClass.begin_animation(),
+ *   #GtkLayoutManagerClass.get_animation_progress(), and
+ *   #GtkLayoutManagerClass.end_animation().</para>
+ *   <variablelist>
+ *     <varlistentry>
+ *       <term><function>begin_animation (duration, easing)</function></term>
+ *       <listitem><para>This virtual function is invoked when the layout
+ *       manager should begin an animation. The implementation should set up
+ *       the state for the animation and create the ancillary objects for
+ *       animating the layout. The default implementation creates a
+ *       #GtkTimeline for the given duration and a #GtkAlpha binding
+ *       the timeline to the given easing mode. This function returns a
+ *       #GtkAlpha which should be used to control the animation from
+ *       the caller perspective.</para></listitem>
+ *     </varlistentry>
+ *     <varlistentry>
+ *       <term><function>get_animation_progress()</function></term>
+ *       <listitem><para>This virtual function should be invoked when animating
+ *       a layout manager. It returns the progress of the animation, using the
+ *       same semantics as the #GtkAlpha:alpha value.</para></listitem>
+ *     </varlistentry>
+ *     <varlistentry>
+ *       <term><function>end_animation()</function></term>
+ *       <listitem><para>This virtual function is invoked when the animation of
+ *       a layout manager ends, and it is meant to be used for bookkeeping the
+ *       objects created in the <function>begin_animation()</function>
+ *       function. The default implementation will call it implicitly when the
+ *       timeline is complete.</para></listitem>
+ *     </varlistentry>
+ *   </variablelist>
+ *   <para>The simplest way to animate a layout is to create a #GtkTimeline
+ *   inside the <function>begin_animation()</function> virtual function, along
+ *   with a #GtkAlpha, and for each #GtkTimeline::new-frame signal
+ *   emission call _gtk_layout_manager_layout_changed(), which will cause a
+ *   relayout. The #GtkTimeline::completed signal emission should cause
+ *   _gtk_layout_manager_end_animation() to be called. The default
+ *   implementation provided internally by #GtkLayoutManager does exactly
+ *   this, so most sub-classes should either not override any animation-related
+ *   virtual function or simply override #GtkLayoutManagerClass.begin_animation()
+ *   and #GtkLayoutManagerClass.end_animation() to set up ad hoc state, and then
+ *   chain up to the parent's implementation.</para>
+ *   <example id="example-GtkLayoutManager-animation">
+ *     <title>Animation of a Layout Manager</title>
+ *     <para>The code below shows how a #GtkLayoutManager sub-class should
+ *     provide animating the allocation of its children from within the
+ *     #GtkLayoutManagerClass.allocate() virtual function implementation. The
+ *     animation is computed between the last stable allocation performed
+ *     before the animation started and the desired final allocation.</para>
+ *     <para>The <varname>is_animating</varname> variable is stored inside the
+ *     #GtkLayoutManager sub-class and it is updated by overriding the
+ *     #GtkLayoutManagerClass.begin_animation() and the
+ *     #GtkLayoutManagerClass.end_animation() virtual functions and chaining up
+ *     to the base class implementation.</para>
+ *     <para>The last stable allocation is stored within a #GtkLayoutMeta
+ *     sub-class used by the implementation.</para>
+ *     <programlisting>
+ * static void
+ * my_layout_manager_allocate (GtkLayoutManager   *manager,
+ *                             GtkContainer       *container,
+ *                             const GtkActorBox  *allocation,
+ *                             GtkAllocationFlags  flags)
+ * {
+ *   MyLayoutManager *self = MY_LAYOUT_MANAGER (manager);
+ *   GtkActor *child;
+ *
+ *   for (child = _gtk_actor_get_first_child (GTK_ACTOR (container));
+ *        child != NULL;
+ *        child = _gtk_actor_get_next_sibling (child))
+ *     {
+ *       GtkLayoutMeta *meta;
+ *       MyLayoutMeta *my_meta;
+ *
+ *       /&ast; retrieve the layout meta-object &ast;/
+ *       meta = _gtk_layout_manager_get_child_meta (manager,
+ *                                                     container,
+ *                                                     child);
+ *       my_meta = MY_LAYOUT_META (meta);
+ *
+ *       /&ast; compute the desired allocation for the child &ast;/
+ *       compute_allocation (self, my_meta, child,
+ *                           allocation, flags,
+ *                           &amp;child_box);
+ *
+ *       /&ast; this is the additional code that deals with the animation
+ *        &ast; of the layout manager
+ *        &ast;/
+ *       if (!self-&gt;is_animating)
+ *         {
+ *           /&ast; store the last stable allocation for later use &ast;/
+ *           my_meta-&gt;last_alloc = _gtk_actor_box_copy (&amp;child_box);
+ *         }
+ *       else
+ *         {
+ *           GtkActorBox end = { 0, };
+ *           gdouble p;
+ *
+ *           /&ast; get the progress of the animation &ast;/
+ *           p = _gtk_layout_manager_get_animation_progress (manager);
+ *
+ *           if (my_meta-&gt;last_alloc != NULL)
+ *             {
+ *               /&ast; copy the desired allocation as the final state &ast;/
+ *               end = child_box;
+ *
+ *               /&ast; then interpolate the initial and final state
+ *                &ast; depending on the progress of the animation,
+ *                &ast; and put the result inside the box we will use
+ *                &ast; to allocate the child
+ *                &ast;/
+ *               _gtk_actor_box_interpolate (my_meta-&gt;last_alloc,
+ *                                              &amp;end,
+ *                                              p,
+ *                                              &amp;child_box);
+ *             }
+ *           else
+ *             {
+ *               /&ast; if there is no stable allocation then the child was
+ *                &ast; added while animating; one possible course of action
+ *                &ast; is to just bail out and fall through to the allocation
+ *                &ast; to position the child directly at its final state
+ *                &ast;/
+ *               my_meta-&gt;last_alloc =
+ *                 _gtk_actor_box_copy (&amp;child_box);
+ *             }
+ *         }
+ *
+ *       /&ast; allocate the child &ast;/
+ *       _gtk_actor_allocate (child, &child_box, flags);
+ *     }
+ * }
+ *     </programlisting>
+ *   </example>
+ *   <para>Sub-classes of #GtkLayoutManager that support animations of the
+ *   layout changes should call _gtk_layout_manager_begin_animation()
+ *   whenever a layout property changes value, e.g.:</para>
+ *   <informalexample>
+ *     <programlisting>
+ * if (self->orientation != new_orientation)
+ *   {
+ *     GtkLayoutManager *manager;
+ *
+ *     self->orientation = new_orientation;
+ *
+ *     manager = GTK_LAYOUT_MANAGER (self);
+ *     _gtk_layout_manager_layout_changed (manager);
+ *     _gtk_layout_manager_begin_animation (manager, 500, GTK_LINEAR);
+ *
+ *     g_object_notify (G_OBJECT (self), "orientation");
+ *   }
+ *     </programlisting>
+ *   </informalexample>
+ *   <para>The code above will animate a change in the
+ *   <varname>orientation</varname> layout property of a layout manager.</para>
+ * </refsect2>
+ *
+ * <refsect2 id="_gtk-layout-properties">
+ *   <title>Layout Properties</title>
+ *   <para>If a layout manager has layout properties, that is properties that
+ *   should exist only as the result of the presence of a specific (layout
+ *   manager, container actor, child actor) combination, and it wishes to store
+ *   those properties inside a #GtkLayoutMeta, then it should override the
+ *   #GtkLayoutManagerClass.get_child_meta_type() virtual function to return
+ *   the #GType of the #GtkLayoutMeta sub-class used to store the layout
+ *   properties; optionally, the #GtkLayoutManager sub-class might also
+ *   override the #GtkLayoutManagerClass.create_child_meta() virtual function
+ *   to control how the #GtkLayoutMeta instance is created, otherwise the
+ *   default implementation will be equivalent to:</para>
+ *   <informalexample><programlisting>
+ *  GtkLayoutManagerClass *klass;
+ *  GType meta_type;
+ *
+ *  klass = GTK_LAYOUT_MANAGER_GET_CLASS (manager);
+ *  meta_type = klass->get_child_meta_type (manager);
+ *
+ *  return g_object_new (meta_type,
+ *                       "manager", manager,
+ *                       "container", container,
+ *                       "actor", actor,
+ *                       NULL);
+ *   </programlisting></informalexample>
+ *   <para>Where <varname>manager</varname> is the  #GtkLayoutManager,
+ *   <varname>container</varname> is the #GtkContainer using the
+ *   #GtkLayoutManager and <varname>actor</varname> is the #GtkActor
+ *   child of the #GtkContainer.</para>
+ * </refsect2>
+ *
+ * <refsect2 id="_gtk-layout-script">
+ *   <title>Using GtkLayoutManager with GtkScript</title>
+ *   <para>#GtkLayoutManager instance can be created in the same way
+ *   as other objects in #GtkScript; properties can be set using the
+ *   common syntax.</para>
+ *   <para>Layout properties can be set on children of a container with
+ *   a #GtkLayoutManager using the <emphasis>layout::</emphasis>
+ *   modifier on the property name, for instance:</para>
+ *   <informalexample><programlisting>
+ * {
+ *   "type" : "GtkBox",
+ *   "layout-manager" : { "type" : "GtkTableLayout" },
+ *   "children" : [
+ *     {
+ *       "type" : "GtkTexture",
+ *       "filename" : "image-00.png",
+ *
+ *       "layout::row" : 0,
+ *       "layout::column" : 0,
+ *       "layout::x-align" : "left",
+ *       "layout::y-align" : "center",
+ *       "layout::x-expand" : true,
+ *       "layout::y-expand" : true
+ *     },
+ *     {
+ *       "type" : "GtkTexture",
+ *       "filename" : "image-01.png",
+ *
+ *       "layout::row" : 0,
+ *       "layout::column" : 1,
+ *       "layout::x-align" : "right",
+ *       "layout::y-align" : "center",
+ *       "layout::x-expand" : true,
+ *       "layout::y-expand" : true
+ *     }
+ *   ]
+ * }
+ *   </programlisting></informalexample>
+ * </refsect2>
+ *
+ * #GtkLayoutManager is available since Gtk 1.2
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gtklayoutmanagerprivate.h"
+
+#define LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED(m,method)   G_STMT_START {  \
+        GObject *_obj = G_OBJECT (m);                                   \
+        g_warning ("Layout managers of type %s do not implement "       \
+                   "the GtkLayoutManager::%s method",               \
+                   G_OBJECT_TYPE_NAME (_obj),                           \
+                   (method));                           } G_STMT_END
+
+struct _GtkLayoutManagerPrivate
+{
+  GtkActor *actor;
+};
+
+G_DEFINE_ABSTRACT_TYPE (GtkLayoutManager,
+                        _gtk_layout_manager,
+                        G_TYPE_INITIALLY_UNOWNED);
+
+static void
+layout_manager_real_get_preferred_size (GtkLayoutManager *manager,
+                                        GtkOrientation    orientation,
+                                        gfloat            for_size,
+                                        gfloat           *min_size_p,
+                                        gfloat           *nat_size_p)
+{
+  LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, "get_preferred_size");
+
+  *min_size_p = 0.0;
+  *nat_size_p = 0.0;
+}
+
+static void
+layout_manager_real_allocate (GtkLayoutManager   *manager,
+                              const cairo_matrix_t *transform,
+                              gfloat                width,
+                              gfloat                height)
+{
+  LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, "allocate");
+}
+
+static void
+_gtk_layout_manager_class_init (GtkLayoutManagerClass *klass)
+{
+  g_type_class_add_private (klass, sizeof (GtkLayoutManagerPrivate));
+
+  klass->get_preferred_size = layout_manager_real_get_preferred_size;
+  klass->allocate = layout_manager_real_allocate;
+}
+
+static void
+_gtk_layout_manager_init (GtkLayoutManager *manager)
+{
+  manager->priv =
+    G_TYPE_INSTANCE_GET_PRIVATE (manager, GTK_TYPE_LAYOUT_MANAGER,
+                                 GtkLayoutManagerPrivate);
+}
+
+/**
+ * _gtk_layout_manager_get_preferred_size:
+ * @manager: a #GtkLayoutManager
+ * @orientation: orientation to query size for
+ * @for_size: the size in the opposite direction, or -1
+ * @min_width_p: (out) (allow-none): return location for the minimum width
+ *   of the layout, or %NULL
+ * @nat_width_p: (out) (allow-none): return location for the natural width
+ *   of the layout, or %NULL
+ *
+ * Computes the minimum and natural widths of the @container according
+ * to @manager.
+ *
+ * See also _gtk_actor_get_preferred_size()
+ *
+ * Since: 1.2
+ */
+void
+_gtk_layout_manager_get_preferred_size (GtkLayoutManager *manager,
+                                        GtkOrientation    orientation,
+                                        gfloat            for_size,
+                                        gfloat           *min_size_p,
+                                        gfloat           *nat_size_p)
+{
+  GtkLayoutManagerClass *klass;
+  gfloat ignore;
+
+  g_return_if_fail (GTK_IS_LAYOUT_MANAGER (manager));
+
+  if (min_size_p == NULL)
+    min_size_p = &ignore;
+  if (nat_size_p == NULL)
+    nat_size_p = &ignore;
+
+  klass = GTK_LAYOUT_MANAGER_GET_CLASS (manager);
+  klass->get_preferred_size (manager,
+                             orientation,
+                             for_size,
+                             min_size_p,
+                             nat_size_p);
+}
+
+/**
+ * _gtk_layout_manager_allocate:
+ * @manager: a #GtkLayoutManager
+ * @transform: transformation to apply to all children
+ * @width: width of allocation area
+ * @height: height of allocation area
+ *
+ * Allocates the children to the area given with @width and @height.
+ *
+ * See also _gtk_actor_allocate()
+ *
+ * Since: 1.2
+ */
+void
+_gtk_layout_manager_allocate (GtkLayoutManager     *manager,
+                              const cairo_matrix_t *transform,
+                              gfloat                width,
+                              gfloat                height)
+{
+  GtkLayoutManagerClass *klass;
+
+  g_return_if_fail (GTK_IS_LAYOUT_MANAGER (manager));
+  g_return_if_fail (transform != NULL);
+  g_return_if_fail (width >= 0.0);
+  g_return_if_fail (height >= 0.0);
+
+  klass = GTK_LAYOUT_MANAGER_GET_CLASS (manager);
+  klass->allocate (manager, transform, width, height);
+}
+
+/**
+ * _gtk_layout_manager_layout_changed:
+ * @manager: a #GtkLayoutManager
+ *
+ * Signals Emits the #GtkLayoutManager::layout-changed signal on @manager
+ *
+ * This function should only be called by implementations of the
+ * #GtkLayoutManager class
+ *
+ * Since: 1.2
+ */
+void
+_gtk_layout_manager_layout_changed (GtkLayoutManager *manager)
+{
+  GtkLayoutManagerPrivate *priv;
+
+  g_return_if_fail (GTK_IS_LAYOUT_MANAGER (manager));
+
+  priv = manager->priv;
+
+  if (priv->actor)
+    _gtk_actor_layout_manager_changed (priv->actor);
+}
+
+/*<private>
+ * Called from GtkActor when the layout manager is set.
+ */
+void
+_gtk_layout_manager_set_actor (GtkLayoutManager *manager,
+                               GtkActor         *actor)
+{
+  g_return_if_fail (GTK_IS_LAYOUT_MANAGER (manager));
+  g_return_if_fail (actor == NULL || GTK_IS_ACTOR (actor));
+
+  manager->priv->actor = actor;
+}
+
+GtkActor *
+_gtk_layout_manager_get_actor (GtkLayoutManager *manager)
+{
+  g_return_val_if_fail (GTK_IS_LAYOUT_MANAGER (manager), NULL);
+
+  return manager->priv->actor;
+}
diff --git a/gtk/actors/gtklayoutmanagerprivate.h b/gtk/actors/gtklayoutmanagerprivate.h
new file mode 100644
index 0000000..7ebcc62
--- /dev/null
+++ b/gtk/actors/gtklayoutmanagerprivate.h
@@ -0,0 +1,134 @@
+/*
+ * Gtk.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2009  Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#ifndef __GTK_LAYOUT_MANAGER_PRIVATE_H__
+#define __GTK_LAYOUT_MANAGER_PRIVATE_H__
+
+#include <gtk/actors/gtkactorprivate.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_LAYOUT_MANAGER             (_gtk_layout_manager_get_type ())
+#define GTK_LAYOUT_MANAGER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_LAYOUT_MANAGER, GtkLayoutManager))
+#define GTK_IS_LAYOUT_MANAGER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_LAYOUT_MANAGER))
+#define GTK_LAYOUT_MANAGER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_LAYOUT_MANAGER, GtkLayoutManagerClass))
+#define GTK_IS_LAYOUT_MANAGER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_LAYOUT_MANAGER))
+#define GTK_LAYOUT_MANAGER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_LAYOUT_MANAGER, GtkLayoutManagerClass))
+
+typedef struct _GtkLayoutManagerPrivate     GtkLayoutManagerPrivate;
+typedef struct _GtkLayoutManagerClass       GtkLayoutManagerClass;
+
+/**
+ * GtkLayoutManager:
+ *
+ * The #GtkLayoutManager structure contains only private data
+ * and should be accessed using the provided API
+ *
+ * Since: 1.2
+ */
+struct _GtkLayoutManager
+{
+  /*< private >*/
+  GInitiallyUnowned parent_instance;
+
+  GtkLayoutManagerPrivate *priv;
+};
+
+/**
+ * GtkLayoutManagerClass:
+ * @get_preferred_width: virtual function; override to provide a preferred
+ *   width for the layout manager. See also the get_preferred_width()
+ *   virtual function in #GtkActor
+ * @get_preferred_height: virtual function; override to provide a preferred
+ *   height for the layout manager. See also the get_preferred_height()
+ *   virtual function in #GtkActor
+ * @allocate: virtual function; override to allocate the children of the
+ *   layout manager. See also the allocate() virtual function in
+ *   #GtkActor
+ * @set_container: virtual function; override to set a back pointer
+ *   on the #GtkContainer using the layout manager. The implementation
+ *   should not take a reference on the container, but just take a weak
+ *   reference, to avoid potential leaks due to reference cycles
+ * @get_child_meta_type: virtual function; override to return the #GType
+ *   of the #GtkLayoutMeta sub-class used by the #GtkLayoutManager
+ * @create_child_meta: virtual function; override to create a
+ *   #GtkLayoutMeta instance associated to a #GtkContainer and a
+ *   child #GtkActor, used to maintain layout manager specific properties
+ * @begin_animation: virtual function; override to control the animation
+ *   of a #GtkLayoutManager with the given duration and easing mode.
+ *   This virtual function is deprecated, and it should not be overridden
+ *   in newly written code.
+ * @end_animation: virtual function; override to end an animation started
+ *   by _gtk_layout_manager_begin_animation(). This virtual function is
+ *   deprecated, and it should not be overriden in newly written code.
+ * @get_animation_progress: virtual function; override to control the
+ *   progress of the animation of a #GtkLayoutManager. This virtual
+ *   function is deprecated, and it should not be overridden in newly written
+ *   code.
+ * @layout_changed: class handler for the #GtkLayoutManager::layout-changed
+ *   signal
+ *
+ * The #GtkLayoutManagerClass structure contains only private
+ * data and should be accessed using the provided API
+ *
+ * Since: 1.2
+ */
+struct _GtkLayoutManagerClass
+{
+  /*< private >*/
+  GInitiallyUnownedClass parent_class;
+
+  /*< public >*/
+  void               (* get_preferred_size)     (GtkLayoutManager       *manager,
+                                                 GtkOrientation          orientation,
+                                                 gfloat                  for_size,
+                                                 gfloat                 *min_size_p,
+                                                 gfloat                 *nat_size_p);
+  void               (* allocate)               (GtkLayoutManager       *manager,
+                                                 const cairo_matrix_t   *transform,
+                                                 gfloat                  width,
+                                                 gfloat                  height);
+};
+
+GType              _gtk_layout_manager_get_type                 (void) G_GNUC_CONST;
+
+void               _gtk_layout_manager_get_preferred_size       (GtkLayoutManager       *manager,
+                                                                 GtkOrientation          orientation,
+                                                                 gfloat                  for_size,
+                                                                 gfloat                 *min_size_p,
+                                                                 gfloat                 *nat_size_p);
+void               _gtk_layout_manager_allocate                 (GtkLayoutManager       *manager,
+                                                                 const cairo_matrix_t   *transform,
+                                                                 gfloat                  width,
+                                                                 gfloat                  height);
+
+void               _gtk_layout_manager_set_actor                (GtkLayoutManager       *manager,
+                                                                 GtkActor               *actor);
+GtkActor *         _gtk_layout_manager_get_actor                (GtkLayoutManager       *manager);
+void               _gtk_layout_manager_layout_changed           (GtkLayoutManager       *manager);
+
+
+G_END_DECLS
+
+#endif /* __GTK_LAYOUT_MANAGER_PRIVATE_H__ */



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