Layout managers base class
<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>
.
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);
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.
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; /* retrieve the layout meta-object */ meta = clutter_layout_manager_get_child_meta (manager, container, child); my_meta = MY_LAYOUT_META (meta); /* compute the desired allocation for the child */ compute_allocation (self, my_meta, child, allocation, flags, &child_box); /* this is the additional code that deals with the animation * of the layout manager */ if (!self->is_animating) { /* store the last stable allocation for later use */ my_meta->last_alloc = clutter_actor_box_copy (&child_box); } else { ClutterActorBox end = { 0, }; gdouble p; /* get the progress of the animation */ p = clutter_layout_manager_get_animation_progress (manager); if (my_meta->last_alloc != NULL) { /* copy the desired allocation as the final state */ end = child_box; /* then interpolate the initial and final state * depending on the progress of the animation, * and put the result inside the box we will use * to allocate the child */ clutter_actor_box_interpolate (my_meta->last_alloc, &end, p, &child_box); } else { /* if there is no stable allocation then the child was * added while animating; one possible course of action * is to just bail out and fall through to the allocation * to position the child directly at its final state */ my_meta->last_alloc = clutter_actor_box_copy (&child_box); } } /* allocate the child */ 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.
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>
.
<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
<clutter-layout-manager>
) (container <clutter-container>
) (allocation <clutter-actor-box>
) (flags <clutter-allocation-flags>
)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