Next: , Previous: Value intervals, Up: Top


41 ClutterLayoutManager

Layout managers base class

41.1 Overview

<clutter-layout-manager> 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 <clutter-actor> subclass can delegate the layouting of its children to a <clutter-layout-manager>. Clutter provides a generic container using <clutter-layout-manager> called <clutter-box>.

Clutter provides some simple <clutter-layout-manager> sub-classes, like <clutter-flow-layout> and <clutter-bin-layout>.

41.2 Using a Layout Manager inside an Actor

In order to use a <clutter-layout-manager> inside a <clutter-actor> sub-class you should invoke clutter-layout-manager-get-preferred-width inside the (structname "ClutterActor") ::get-preferred-width virtual function and clutter-layout-manager-get-preferred-height inside the function implementations. You should also call clutter-layout-manager-allocate inside the implementation of the

In order to receive notifications for changes in the layout manager policies you should also connect to the <"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:

     
      g_signal_connect_swapped (layout_manager,
                                "layout-changed",
                                G_CALLBACK (clutter_actor_queue_relayout),
                                actor);
     

41.3 Implementing a ClutterLayoutManager

The implementation of a layout manager does not differ from the implementation of the size requisition and allocation bits of <clutter-actor>, so you should read the relative documentation for subclassing ClutterActor.

The layout manager implementation can hold a back pointer to the <clutter-container> by implementing the set-container 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.

If a layout manager has properties affecting the layout policies then it should emit the <"layout-changed"> signal on itself by using the clutter-layout-manager-layout-changed function whenever one of these properties changes.

41.4 Animating a ClutterLayoutManager

A layout manager is used to let a <clutter-container> take complete ownership over the layout (that is: the position and sizing) of its children; this means that using the Clutter animation API, like clutter-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.

It is possible for a <clutter-layout-manager> sub-class to animate its children layout by using the base class animation support. The <clutter-layout-manager> animation support consists of three virtual functions: begin-animation, get-animation-progress and end-animation.

get-animation-progress

end-animation

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 <clutter-timeline> for the given duration and a <clutter-alpha> binding the timeline to the given easing mode. This function returns a <clutter-alpha> which should be used to control the animation from the caller perspective.

This virtual function should be invoked when animating a layout manager. It returns the progress of the animation, using the same semantics as the <"alpha"> value.

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 begin-animation function. The default implementation will call it implicitly when the timeline is complete.

The simplest way to animate a layout is to create a <clutter-timeline> inside the begin-animation virtual function, along with a <clutter-alpha>, and for each <"new-frame"> signal emission call clutter-layout-manager-layout-changed, which will cause a relayout. The <"completed"> signal emission should cause clutter-layout-manager-end-animation to be called. The default implementation provided internally by <clutter-layout-manager> does exactly this, so most sub-classes should either not override any animation-related virtual function or simply override begin-animation and end-animation to set up ad hoc state, and then chain up to the parent's implementation.

The code below shows how a <clutter-layout-manager> sub-class should provide animating the allocation of its children from within the allocate virtual function implementation. The animation is computed between the last stable allocation performed before the animation started and the desired final allocation.

The <clutter-layout-manager> sub-class and it is updated by overriding the begin-animation and end-animation virtual functions and chaining up to the base class implementation.

The last stable allocation is stored within a <clutter-layout-meta> sub-class used by the implementation.

     
     static void
     my_layout_manager_allocate (ClutterLayoutManager   *manager,
                                 ClutterContainer       *container,
                                 const ClutterActorBox  *allocation,
                                 ClutterAllocationFlags  flags)
     {
       MyLayoutManager *self = MY_LAYOUT_MANAGER (manager);
       ClutterActor *child;
     
       for (child = clutter_actor_get_first_child (CLUTTER_ACTOR (container));
            child != NULL;
            child = clutter_actor_get_next_sibling (child))
         {
           ClutterLayoutMeta *meta;
           MyLayoutMeta *my_meta;
     
           /&#x002A; retrieve the layout meta-object &#x002A;/
           meta = clutter_layout_manager_get_child_meta (manager,
                                                         container,
                                                         child);
           my_meta = MY_LAYOUT_META (meta);
     
           /&#x002A; compute the desired allocation for the child &#x002A;/
           compute_allocation (self, my_meta, child,
                               allocation, flags,
                               &child_box);
     
           /&#x002A; this is the additional code that deals with the animation
            &#x002A; of the layout manager
            &#x002A;/
           if (!self->is_animating)
             {
               /&#x002A; store the last stable allocation for later use &#x002A;/
               my_meta->last_alloc = clutter_actor_box_copy (&child_box);
             }
           else
             {
               ClutterActorBox end = { 0, };
               gdouble p;
     
               /&#x002A; get the progress of the animation &#x002A;/
               p = clutter_layout_manager_get_animation_progress (manager);
     
               if (my_meta->last_alloc != NULL)
                 {
                   /&#x002A; copy the desired allocation as the final state &#x002A;/
                   end = child_box;
     
                   /&#x002A; then interpolate the initial and final state
                    &#x002A; depending on the progress of the animation,
                    &#x002A; and put the result inside the box we will use
                    &#x002A; to allocate the child
                    &#x002A;/
                   clutter_actor_box_interpolate (my_meta->last_alloc,
                                                  &end,
                                                  p,
                                                  &child_box);
                 }
               else
                 {
                   /&#x002A; if there is no stable allocation then the child was
                    &#x002A; added while animating; one possible course of action
                    &#x002A; is to just bail out and fall through to the allocation
                    &#x002A; to position the child directly at its final state
                    &#x002A;/
                   my_meta->last_alloc =
                     clutter_actor_box_copy (&child_box);
                 }
             }
     
           /&#x002A; allocate the child &#x002A;/
           clutter_actor_allocate (child, &child_box, flags);
         }
     }
     

Sub-classes of <clutter-layout-manager> that support animations of the layout changes should call clutter-layout-manager-begin-animation whenever a layout property changes value, e.g.:

     
     if (self->orientation != new_orientation)
       {
         ClutterLayoutManager *manager;
     
         self->orientation = new_orientation;
     
         manager = CLUTTER_LAYOUT_MANAGER (self);
         clutter_layout_manager_layout_changed (manager);
         clutter_layout_manager_begin_animation (manager, 500, CLUTTER_LINEAR);
     
         g_object_notify (G_OBJECT (self), "orientation");
       }
     

The code above will animate a change in the layout property of a layout manager.

41.5 Layout Properties

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 <clutter-layout-meta>, then it should override the ::get-child-meta-type virtual function to return the <g-type> of the <clutter-layout-meta> sub-class used to store the layout properties; optionally, the <clutter-layout-manager> sub-class might also override the (structname "ClutterLayoutManager") ::create-child-meta virtual function to control how the <clutter-layout-meta> instance is created, otherwise the default implementation will be equivalent to:

     
      ClutterLayoutManagerClass *klass;
      GType meta_type;
     
      klass = CLUTTER_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);
     

Where (varname "container") is the <clutter-container> using the <clutter-layout-manager> and <clutter-actor> child of the <clutter-container>.

41.6 Using ClutterLayoutManager with ClutterScript

<clutter-layout-manager> instance can be created in the same way as other objects in <clutter-script>; properties can be set using the common syntax.

Layout properties can be set on children of a container with a <clutter-layout-manager> using the layout:: modifier on the property name, for instance:

     
     {
       "type" : "ClutterBox",
       "layout-manager" : { "type" : "ClutterTableLayout" },
       "children" : [
         {
           "type" : "ClutterTexture",
           "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" : "ClutterTexture",
           "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
         }
       ]
     }
     

<clutter-layout-manager> is available since Clutter 1.2

41.7 Usage

— Function: clutter-layout-manager-allocate (self <clutter-layout-manager>) (container <clutter-container>) (allocation <clutter-actor-box>) (flags <clutter-allocation-flags>)
— Method: allocate

Allocates the children of container given an area

See also clutter-actor-allocate

manager
a <clutter-layout-manager>
container
the <clutter-container> using manager
allocation
the <clutter-actor-box> containing the allocated area of container
flags
the allocation flags

Since 1.2