Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-constraint.c
1 /**
2  * SECTION:clutter-constraint
3  * @Title: ClutterConstraint
4  * @Short_Description: Abstract class for constraints on position or size
5  * @See_Also: #ClutterAction
6  *
7  * #ClutterConstraint is a base abstract class for modifiers of a #ClutterActor
8  * position or size.
9  *
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.
15  *
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>
29  *   <variablelist>
30  *     <varlistentry>
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>
38  *     </varlistentry>
39  *     <varlistentry>
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>
44  *     </varlistentry>
45  *     <varlistentry>
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>
51  *     </varlistentry>
52  *   </variablelist>
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>
58  *     <orderedlist>
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>
88  *     </orderedlist>
89  *     <figure id="constraints-example">
90  *       <title>Constraints</title>
91  *       <graphic fileref="constraints-example.png" format="PNG"/>
92  *     </figure>
93  *     <programlisting>
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>
96  *</xi:include>
97  *     </programlisting>
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>
101  *   </example>
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>
107  * </refsect2>
108  *
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>
133  * </refsect2>
134  *
135  * #ClutterConstraint is available since Clutter 1.4
136  */
137
138 #ifdef HAVE_CONFIG_H
139 #include "config.h"
140 #endif
141
142 #include <string.h>
143
144 #include "clutter-constraint.h"
145
146 #include "clutter-actor.h"
147 #include "clutter-actor-meta-private.h"
148 #include "clutter-private.h"
149
150 G_DEFINE_ABSTRACT_TYPE (ClutterConstraint,
151                         clutter_constraint,
152                         CLUTTER_TYPE_ACTOR_META);
153
154 static void
155 constraint_update_allocation (ClutterConstraint *constraint,
156                               ClutterActor      *actor,
157                               ClutterActorBox   *allocation)
158 {
159 }
160
161 static void
162 clutter_constraint_notify (GObject    *gobject,
163                            GParamSpec *pspec)
164 {
165   if (strcmp (pspec->name, "enabled") == 0)
166     {
167       ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
168       ClutterActor *actor = clutter_actor_meta_get_actor (meta);
169
170       if (actor != NULL)
171         clutter_actor_queue_relayout (actor);
172     }
173
174   if (G_OBJECT_CLASS (clutter_constraint_parent_class)->notify != NULL)
175     G_OBJECT_CLASS (clutter_constraint_parent_class)->notify (gobject, pspec);
176 }
177
178 static void
179 clutter_constraint_class_init (ClutterConstraintClass *klass)
180 {
181   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
182
183   gobject_class->notify = clutter_constraint_notify;
184
185   klass->update_allocation = constraint_update_allocation;
186 }
187
188 static void
189 clutter_constraint_init (ClutterConstraint *self)
190 {
191 }
192
193 void
194 _clutter_constraint_update_allocation (ClutterConstraint *constraint,
195                                        ClutterActor      *actor,
196                                        ClutterActorBox   *allocation)
197 {
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);
201
202   CLUTTER_CONSTRAINT_GET_CLASS (constraint)->update_allocation (constraint,
203                                                                 actor,
204                                                                 allocation);
205 }