2 * SECTION:clutter-constraint
3 * @Title: ClutterConstraint
4 * @Short_Description: Abstract class for constraints on position or size
5 * @See_Also: #ClutterAction
7 * #ClutterConstraint is a base abstract class for modifiers of a #ClutterActor
10 * A #ClutterConstraint sub-class should contain the logic for modifying
11 * the position or size of the #ClutterActor to which it is applied, by
12 * updating the actor's allocation. Each #ClutterConstraint can change the
13 * allocation of the actor to which they are applied by overriding the
14 * #ClutterConstraintClass.update_allocation() virtual function.
16 * <refsect2 id="ClutterConstraint-usage">
17 * <title>Using Constraints</title>
18 * <para>Constraints can be used with fixed layout managers, like
19 * #ClutterFixedLayout, or with actors implicitly using a fixed layout
20 * manager, like #ClutterGroup and #ClutterStage.</para>
21 * <para>Constraints provide a way to build user interfaces by using
22 * relations between #ClutterActor<!-- -->s, without explicit fixed
23 * positioning and sizing, similarly to how fluid layout managers like
24 * #ClutterBoxLayout and #ClutterTableLayout lay out their children.</para>
25 * <para>Constraints are attached to a #ClutterActor, and are available
26 * for inspection using clutter_actor_get_constraints().</para>
27 * <para>Clutter provides different implementation of the #ClutterConstraint
28 * abstract class, for instance:</para>
31 * <term>#ClutterAlignConstraint</term>
32 * <listitem><simpara>this constraint can be used to align an actor
33 * to another one, on either the horizontal or the vertical axis; the
34 * #ClutterAlignConstraint uses a normalized offset between 0.0 (the
35 * top or the left of the source actor, depending on the axis) and
36 * 1.0 (the bottom or the right of the source actor, depending on the
37 * axis).</simpara></listitem>
40 * <term>#ClutterBindConstraint</term>
41 * <listitem><simpara>this constraint binds the X, Y, width or height
42 * of an actor to the corresponding position or size of a source
43 * actor; it can also apply an offset.</simpara></listitem>
46 * <term>#ClutterSnapConstraint</term>
47 * <listitem><simpara>this constraint "snaps" together the edges of
48 * two #ClutterActor<!-- -->s; if an actor uses two constraints on
49 * both its horizontal or vertical edges then it can also expand to
50 * fit the empty space.</simpara></listitem>
53 * <example id="ClutterConstraint-usage-example">
54 * <title>Usage of constraints</title>
55 * <para>The example below uses various #ClutterConstraint<!-- -->s to
56 * lay out three actors on a resizable stage. Only the central actor has
57 * an explicit size, and no actor has an explicit position.</para>
59 * <listitem><simpara>The #ClutterRectangle with #ClutterActor:name
60 * <emphasis>layerA</emphasis> is explicitly sized to 100 pixels by 25
61 * pixels, and it's added to the #ClutterStage;</simpara></listitem>
62 * <listitem><simpara>two #ClutterAlignConstraint<!-- -->s are used
63 * to anchor <emphasis>layerA</emphasis> to the center of the stage,
64 * by using 0.5 as the alignment #ClutterAlignConstraint:factor on
65 * both the X and Y axis.</simpara></listitem>
66 * <listitem><simpara>the #ClutterRectangle with #ClutterActor:name
67 * <emphasis>layerB</emphasis> is added to the #ClutterStage with
68 * no explicit size;</simpara></listitem>
69 * <listitem><simpara>the #ClutterActor:x and #ClutterActor:width
70 * of <emphasis>layerB</emphasis> are bound to the same properties
71 * of <emphasis>layerA</emphasis> using two #ClutterBindConstraint
72 * objects, thus keeping <emphasis>layerB</emphasis> aligned to
73 * <emphasis>layerA</emphasis>;</simpara></listitem>
74 * <listitem><simpara>the top edge of <emphasis>layerB</emphasis> is
75 * snapped together with the bottom edge of <emphasis>layerA</emphasis>;
76 * the bottom edge of <emphasis>layerB</emphasis> is also snapped
77 * together with the bottom edge of the #ClutterStage; an offset is
78 * given to the two #ClutterSnapConstraint<!-- -->s to allow for some
79 * padding; since <emphasis>layerB</emphasis> is snapped between two
80 * different #ClutterActor<!-- -->s, its height is stretched to match
81 * the gap;</simpara></listitem>
82 * <listitem><simpara>the #ClutterRectangle with #ClutterActor:name
83 * <emphasis>layerC</emphasis> mirrors <emphasis>layerB</emphasis>,
84 * snapping the top edge of the #ClutterStage to the top edge of
85 * <emphasis>layerC</emphasis> and the top edge of
86 * <emphasis>layerA</emphasis> to the bottom edge of
87 * <emphasis>layerC</emphasis>;</simpara></listitem>
89 * <figure id="constraints-example">
90 * <title>Constraints</title>
91 * <graphic fileref="constraints-example.png" format="PNG"/>
94 *<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../../../examples/constraints.c" parse="text">
95 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
98 * <para>You can try resizing interactively the #ClutterStage and verify
99 * that the three #ClutterActor<!-- -->s maintain the same position and
100 * size relative to each other, and to the #ClutterStage.</para>
102 * <warning><para>It's important to note that Clutter does not avoid loops
103 * or competing constraints; if two or more #ClutterConstraint<!-- -->s
104 * are operating on the same positional or dimensional attributes of an
105 * actor, or if the constraints on two different actors depend on each
106 * other, then the behavior is undefined.</para></warning>
109 * <refsect2 id="ClutterConstraint-implementation">
110 * <title>Implementing a ClutterConstraint</title>
111 * <para>Creating a sub-class of #ClutterConstraint requires the
112 * implementation of the <function>update_allocation()</function>
113 * virtual function.</para>
114 * <para>The <function>update_allocation()</function> virtual function
115 * is called during the allocation sequence of a #ClutterActor, and
116 * allows any #ClutterConstraint attached to that actor to modify the
117 * allocation before it is passed to the <function>allocate()</function>
118 * implementation.</para>
119 * <para>The #ClutterActorBox passed to the
120 * <function>update_allocation()</function> implementation contains the
121 * original allocation of the #ClutterActor, plus the eventual modifications
122 * applied by the other #ClutterConstraint<!-- -->s.</para>
123 * <note><para>Constraints are queried in the same order as they were
124 * applied using clutter_actor_add_constraint() or
125 * clutter_actor_add_constraint_with_name().</para></note>
126 * <para>It is not necessary for a #ClutterConstraint sub-class to chain
127 * up to the parent's implementation.</para>
128 * <para>If a #ClutterConstraint is parametrized - i.e. if it contains
129 * properties that affect the way the constraint is implemented - it should
130 * call clutter_actor_queue_relayout() on the actor to which it is attached
131 * to whenever any parameter is changed. The actor to which it is attached
132 * can be recovered at any point using clutter_actor_meta_get_actor().</para>
135 * #ClutterConstraint is available since Clutter 1.4
144 #include "clutter-constraint.h"
146 #include "clutter-actor.h"
147 #include "clutter-actor-meta-private.h"
148 #include "clutter-private.h"
150 G_DEFINE_ABSTRACT_TYPE (ClutterConstraint,
152 CLUTTER_TYPE_ACTOR_META);
155 constraint_update_allocation (ClutterConstraint *constraint,
157 ClutterActorBox *allocation)
162 clutter_constraint_notify (GObject *gobject,
165 if (strcmp (pspec->name, "enabled") == 0)
167 ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
168 ClutterActor *actor = clutter_actor_meta_get_actor (meta);
171 clutter_actor_queue_relayout (actor);
174 if (G_OBJECT_CLASS (clutter_constraint_parent_class)->notify != NULL)
175 G_OBJECT_CLASS (clutter_constraint_parent_class)->notify (gobject, pspec);
179 clutter_constraint_class_init (ClutterConstraintClass *klass)
181 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
183 gobject_class->notify = clutter_constraint_notify;
185 klass->update_allocation = constraint_update_allocation;
189 clutter_constraint_init (ClutterConstraint *self)
194 _clutter_constraint_update_allocation (ClutterConstraint *constraint,
196 ClutterActorBox *allocation)
198 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
199 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
200 g_return_if_fail (allocation != NULL);
202 CLUTTER_CONSTRAINT_GET_CLASS (constraint)->update_allocation (constraint,