Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-box-layout.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright (C) 2009  Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  * Author:
22  *   Emmanuele Bassi <ebassi@linux.intel.com>
23  *
24  * Based on the NBTK NbtkBoxLayout actor by:
25  *   Thomas Wood <thomas.wood@intel.com>
26  */
27
28 /**
29  * SECTION:clutter-box-layout
30  * @short_description: A layout manager arranging children on a single line
31  *
32  * The #ClutterBoxLayout is a #ClutterLayoutManager implementing the
33  * following layout policy:
34  * <itemizedlist>
35  *   <listitem><para>all children are arranged on a single
36  *   line;</para></listitem>
37  *   <listitem><para>the axis used is controlled by the
38  *   #ClutterBoxLayout:orientation property;</para></listitem>
39  *   <listitem><para>the order of the packing is determined by the
40  *   #ClutterBoxLayout:pack-start boolean property;</para></listitem>
41  *   <listitem><para>each child will be allocated to its natural
42  *   size or, if #ClutterActor:x-expand/#ClutterActor:y-expand
43  *   is set, the available size;</para></listitem>
44  *   <listitem><para>honours the #ClutterActor's #ClutterActor:x-align
45  *   and #ClutterActor:y-align properties to fill the available
46  *   size;</para></listitem>
47  *   <listitem><para>if the #ClutterBoxLayout:homogeneous boolean property
48  *   is set, then all widgets will get the same size, ignoring expand
49  *   settings and the preferred sizes</para></listitem>
50  * </itemizedlist>
51  *
52  *  <figure id="box-layout">
53  *   <title>Box layout</title>
54  *   <para>The image shows a #ClutterBoxLayout with the
55  *   #ClutterBoxLayout:vertical property set to %FALSE.</para>
56  *   <graphic fileref="box-layout.png" format="PNG"/>
57  * </figure>
58  *
59  * It is possible to control the spacing between children of a
60  * #ClutterBoxLayout by using clutter_box_layout_set_spacing().
61  *
62  * #ClutterBoxLayout is available since Clutter 1.2
63  */
64
65 #ifdef HAVE_CONFIG_H
66 #include "config.h"
67 #endif
68
69 #include <math.h>
70
71 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
72 #include "deprecated/clutter-container.h"
73 #include "deprecated/clutter-alpha.h"
74
75 #include "clutter-box-layout.h"
76
77 #include "clutter-actor-private.h"
78 #include "clutter-debug.h"
79 #include "clutter-enum-types.h"
80 #include "clutter-layout-meta.h"
81 #include "clutter-private.h"
82 #include "clutter-types.h"
83
84 #define CLUTTER_TYPE_BOX_CHILD          (clutter_box_child_get_type ())
85 #define CLUTTER_BOX_CHILD(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BOX_CHILD, ClutterBoxChild))
86 #define CLUTTER_IS_BOX_CHILD(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BOX_CHILD))
87
88 #define CLUTTER_BOX_LAYOUT_GET_PRIVATE(obj)     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_BOX_LAYOUT, ClutterBoxLayoutPrivate))
89
90 typedef struct _ClutterBoxChild         ClutterBoxChild;
91 typedef struct _ClutterLayoutMetaClass  ClutterBoxChildClass;
92
93 struct _ClutterBoxLayoutPrivate
94 {
95   ClutterContainer *container;
96
97   guint spacing;
98
99   gulong easing_mode;
100   guint easing_duration;
101
102   ClutterOrientation orientation;
103
104   guint is_pack_start  : 1;
105   guint is_homogeneous : 1;
106 };
107
108 struct _ClutterBoxChild
109 {
110   ClutterLayoutMeta parent_instance;
111
112   ClutterBoxAlignment x_align;
113   ClutterBoxAlignment y_align;
114
115   guint x_fill              : 1;
116   guint y_fill              : 1;
117   guint expand              : 1;
118 };
119
120 enum
121 {
122   PROP_CHILD_0,
123
124   PROP_CHILD_X_ALIGN,
125   PROP_CHILD_Y_ALIGN,
126   PROP_CHILD_X_FILL,
127   PROP_CHILD_Y_FILL,
128   PROP_CHILD_EXPAND,
129
130   PROP_CHILD_LAST
131 };
132
133 enum
134 {
135   PROP_0,
136
137   PROP_SPACING,
138   PROP_VERTICAL,
139   PROP_HOMOGENEOUS,
140   PROP_PACK_START,
141   PROP_ORIENTATION,
142   PROP_EASING_DURATION,
143
144   PROP_LAST
145 };
146
147 static GParamSpec *obj_props[PROP_LAST] = { NULL, };
148
149 GType clutter_box_child_get_type (void);
150
151 G_DEFINE_TYPE (ClutterBoxChild,
152                clutter_box_child,
153                CLUTTER_TYPE_LAYOUT_META);
154
155 G_DEFINE_TYPE (ClutterBoxLayout,
156                clutter_box_layout,
157                CLUTTER_TYPE_LAYOUT_MANAGER);
158
159 /*
160  * ClutterBoxChild
161  */
162
163 static void
164 box_child_set_align (ClutterBoxChild     *self,
165                      ClutterBoxAlignment  x_align,
166                      ClutterBoxAlignment  y_align)
167 {
168   gboolean x_changed = FALSE, y_changed = FALSE;
169
170   if (self->x_align != x_align)
171     {
172       self->x_align = x_align;
173
174       x_changed = TRUE;
175     }
176
177   if (self->y_align != y_align)
178     {
179       self->y_align = y_align;
180
181       y_changed = TRUE;
182     }
183
184   if (x_changed || y_changed)
185     {
186       ClutterLayoutManager *layout;
187
188       layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self));
189
190       clutter_layout_manager_layout_changed (layout);
191
192       if (x_changed)
193         g_object_notify (G_OBJECT (self), "x-align");
194
195       if (y_changed)
196         g_object_notify (G_OBJECT (self), "y-align");
197     }
198 }
199
200 static void
201 box_child_set_fill (ClutterBoxChild *self,
202                     gboolean         x_fill,
203                     gboolean         y_fill)
204 {
205   gboolean x_changed = FALSE, y_changed = FALSE;
206
207   if (self->x_fill != x_fill)
208     {
209       self->x_fill = x_fill;
210
211       x_changed = TRUE;
212     }
213
214   if (self->y_fill != y_fill)
215     {
216       self->y_fill = y_fill;
217
218       y_changed = TRUE;
219     }
220
221   if (x_changed || y_changed)
222     {
223       ClutterLayoutManager *layout;
224
225       layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self));
226
227       clutter_layout_manager_layout_changed (layout);
228
229       if (x_changed)
230         g_object_notify (G_OBJECT (self), "x-fill");
231
232       if (y_changed)
233         g_object_notify (G_OBJECT (self), "y-fill");
234     }
235 }
236
237 static void
238 box_child_set_expand (ClutterBoxChild *self,
239                       gboolean         expand)
240 {
241   if (self->expand != expand)
242     {
243       ClutterLayoutManager *layout;
244
245       self->expand = expand;
246
247       layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self));
248
249       clutter_layout_manager_layout_changed (layout);
250
251       g_object_notify (G_OBJECT (self), "expand");
252     }
253 }
254
255 static void
256 clutter_box_child_set_property (GObject      *gobject,
257                                 guint         prop_id,
258                                 const GValue *value,
259                                 GParamSpec   *pspec)
260 {
261   ClutterBoxChild *self = CLUTTER_BOX_CHILD (gobject);
262
263   switch (prop_id)
264     {
265     case PROP_CHILD_X_ALIGN:
266       box_child_set_align (self,
267                            g_value_get_enum (value),
268                            self->y_align);
269       break;
270
271     case PROP_CHILD_Y_ALIGN:
272       box_child_set_align (self,
273                            self->x_align,
274                            g_value_get_enum (value));
275       break;
276
277     case PROP_CHILD_X_FILL:
278       box_child_set_fill (self,
279                           g_value_get_boolean (value),
280                           self->y_fill);
281       break;
282
283     case PROP_CHILD_Y_FILL:
284       box_child_set_fill (self,
285                           self->x_fill,
286                           g_value_get_boolean (value));
287       break;
288
289     case PROP_CHILD_EXPAND:
290       box_child_set_expand (self, g_value_get_boolean (value));
291       break;
292
293     default:
294       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
295       break;
296     }
297 }
298
299 static void
300 clutter_box_child_get_property (GObject    *gobject,
301                                 guint       prop_id,
302                                 GValue     *value,
303                                 GParamSpec *pspec)
304 {
305   ClutterBoxChild *self = CLUTTER_BOX_CHILD (gobject);
306
307   switch (prop_id)
308     {
309     case PROP_CHILD_X_ALIGN:
310       g_value_set_enum (value, self->x_align);
311       break;
312
313     case PROP_CHILD_Y_ALIGN:
314       g_value_set_enum (value, self->y_align);
315       break;
316
317     case PROP_CHILD_X_FILL:
318       g_value_set_boolean (value, self->x_fill);
319       break;
320
321     case PROP_CHILD_Y_FILL:
322       g_value_set_boolean (value, self->y_fill);
323       break;
324
325     case PROP_CHILD_EXPAND:
326       g_value_set_boolean (value, self->expand);
327       break;
328
329     default:
330       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
331       break;
332     }
333 }
334
335 static void
336 clutter_box_child_class_init (ClutterBoxChildClass *klass)
337 {
338   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
339   GParamSpec *pspec;
340
341   gobject_class->set_property = clutter_box_child_set_property;
342   gobject_class->get_property = clutter_box_child_get_property;
343
344   pspec = g_param_spec_boolean ("expand",
345                                 P_("Expand"),
346                                 P_("Allocate extra space for the child"),
347                                 FALSE,
348                                 CLUTTER_PARAM_READWRITE);
349   g_object_class_install_property (gobject_class, PROP_CHILD_EXPAND, pspec);
350
351   pspec = g_param_spec_boolean ("x-fill",
352                                 P_("Horizontal Fill"),
353                                 P_("Whether the child should receive priority "
354                                    "when the container is allocating spare space "
355                                    "on the horizontal axis"),
356                                 FALSE,
357                                 CLUTTER_PARAM_READWRITE);
358   g_object_class_install_property (gobject_class, PROP_CHILD_X_FILL, pspec);
359
360   pspec = g_param_spec_boolean ("y-fill",
361                                 P_("Vertical Fill"),
362                                 P_("Whether the child should receive priority "
363                                    "when the container is allocating spare space "
364                                    "on the vertical axis"),
365                                 FALSE,
366                                 CLUTTER_PARAM_READWRITE);
367   g_object_class_install_property (gobject_class, PROP_CHILD_Y_FILL, pspec);
368
369   pspec = g_param_spec_enum ("x-align",
370                              P_("Horizontal Alignment"),
371                              P_("Horizontal alignment of the actor within "
372                                 "the cell"),
373                              CLUTTER_TYPE_BOX_ALIGNMENT,
374                              CLUTTER_BOX_ALIGNMENT_CENTER,
375                              CLUTTER_PARAM_READWRITE);
376   g_object_class_install_property (gobject_class, PROP_CHILD_X_ALIGN, pspec);
377
378   pspec = g_param_spec_enum ("y-align",
379                              P_("Vertical Alignment"),
380                              P_("Vertical alignment of the actor within "
381                                 "the cell"),
382                              CLUTTER_TYPE_BOX_ALIGNMENT,
383                              CLUTTER_BOX_ALIGNMENT_CENTER,
384                              CLUTTER_PARAM_READWRITE);
385   g_object_class_install_property (gobject_class, PROP_CHILD_Y_ALIGN, pspec);
386 }
387
388 static void
389 clutter_box_child_init (ClutterBoxChild *self)
390 {
391   self->x_align = CLUTTER_BOX_ALIGNMENT_CENTER;
392   self->y_align = CLUTTER_BOX_ALIGNMENT_CENTER;
393
394   self->x_fill = self->y_fill = FALSE;
395
396   self->expand = FALSE;
397 }
398
399 static gdouble
400 get_box_alignment_factor (ClutterBoxAlignment alignment)
401 {
402   switch (alignment)
403     {
404     case CLUTTER_BOX_ALIGNMENT_CENTER:
405       return 0.5;
406
407     case CLUTTER_BOX_ALIGNMENT_START:
408       return 0.0;
409
410     case CLUTTER_BOX_ALIGNMENT_END:
411       return 1.0;
412     }
413
414   return 0.0;
415 }
416
417 static GType
418 clutter_box_layout_get_child_meta_type (ClutterLayoutManager *manager)
419 {
420   return CLUTTER_TYPE_BOX_CHILD;
421 }
422
423 static void
424 clutter_box_layout_set_container (ClutterLayoutManager *layout,
425                                   ClutterContainer     *container)
426 {
427   ClutterBoxLayoutPrivate *priv = CLUTTER_BOX_LAYOUT (layout)->priv;
428   ClutterLayoutManagerClass *parent_class;
429
430   priv->container = container;
431
432   if (priv->container != NULL)
433     {
434       ClutterRequestMode request_mode;
435
436       /* we need to change the :request-mode of the container
437        * to match the orientation
438        */
439       request_mode = priv->orientation == CLUTTER_ORIENTATION_VERTICAL
440                    ? CLUTTER_REQUEST_HEIGHT_FOR_WIDTH
441                    : CLUTTER_REQUEST_WIDTH_FOR_HEIGHT;
442       clutter_actor_set_request_mode (CLUTTER_ACTOR (priv->container),
443                                       request_mode);
444     }
445
446   parent_class = CLUTTER_LAYOUT_MANAGER_CLASS (clutter_box_layout_parent_class);
447   parent_class->set_container (layout, container);
448 }
449
450 static void
451 get_preferred_width (ClutterBoxLayout *self,
452                      ClutterActor     *container,
453                      gfloat            for_height,
454                      gfloat           *min_width_p,
455                      gfloat           *natural_width_p)
456 {
457   ClutterBoxLayoutPrivate *priv = self->priv;
458   ClutterActor *child;
459   gint n_children = 0;
460   gboolean is_rtl, is_vertical;
461
462   if (min_width_p)
463     *min_width_p = 0;
464
465   if (natural_width_p)
466     *natural_width_p = 0;
467
468   if (priv->orientation == CLUTTER_ORIENTATION_HORIZONTAL)
469     {
470       ClutterTextDirection text_dir;
471
472       text_dir = clutter_actor_get_text_direction (container);
473       is_rtl = (text_dir == CLUTTER_TEXT_DIRECTION_RTL) ? TRUE : FALSE;
474     }
475   else
476     is_rtl = FALSE;
477
478   is_vertical = priv->orientation == CLUTTER_ORIENTATION_VERTICAL;
479
480   for (child = (is_rtl) ? clutter_actor_get_last_child (container)
481                         : clutter_actor_get_first_child (container);
482        child != NULL;
483        child = (is_rtl) ? clutter_actor_get_previous_sibling (child)
484                         : clutter_actor_get_next_sibling (child))
485     {
486       gfloat child_min = 0, child_nat = 0;
487
488       if (!CLUTTER_ACTOR_IS_VISIBLE (child))
489         continue;
490
491       n_children++;
492
493       clutter_actor_get_preferred_width (child,
494                                          !is_vertical ? for_height : -1,
495                                          &child_min,
496                                          &child_nat);
497
498       if (is_vertical)
499         {
500           if (min_width_p)
501             *min_width_p = MAX (child_min, *min_width_p);
502
503           if (natural_width_p)
504             *natural_width_p = MAX (child_nat, *natural_width_p);
505         }
506       else
507         {
508           if (min_width_p)
509             *min_width_p += child_min;
510
511           if (natural_width_p)
512             *natural_width_p += child_nat;
513         }
514     }
515
516
517   if (!is_vertical && n_children > 1)
518     {
519       if (min_width_p)
520         *min_width_p += priv->spacing * (n_children - 1);
521
522       if (natural_width_p)
523         *natural_width_p += priv->spacing * (n_children - 1);
524     }
525 }
526
527 static void
528 get_preferred_height (ClutterBoxLayout *self,
529                       ClutterActor     *container,
530                       gfloat            for_width,
531                       gfloat           *min_height_p,
532                       gfloat           *natural_height_p)
533 {
534   ClutterBoxLayoutPrivate *priv = self->priv;
535   ClutterActor *child;
536   gint n_children = 0;
537   gboolean is_rtl, is_vertical;
538
539   if (min_height_p)
540     *min_height_p = 0;
541
542   if (natural_height_p)
543     *natural_height_p = 0;
544
545   if (priv->orientation == CLUTTER_ORIENTATION_HORIZONTAL)
546     {
547       ClutterTextDirection text_dir;
548
549       text_dir = clutter_actor_get_text_direction (container);
550       is_rtl = (text_dir == CLUTTER_TEXT_DIRECTION_RTL) ? TRUE : FALSE;
551     }
552   else
553     is_rtl = FALSE;
554
555   is_vertical = priv->orientation == CLUTTER_ORIENTATION_VERTICAL;
556
557   for (child = (is_rtl) ? clutter_actor_get_last_child (container)
558                         : clutter_actor_get_first_child (container);
559        child != NULL;
560        child = (is_rtl) ? clutter_actor_get_previous_sibling (child)
561                         : clutter_actor_get_next_sibling (child))
562     {
563       gfloat child_min = 0, child_nat = 0;
564
565       if (!CLUTTER_ACTOR_IS_VISIBLE (child))
566         continue;
567
568       n_children++;
569
570       clutter_actor_get_preferred_height (child,
571                                           is_vertical ? for_width : -1,
572                                           &child_min,
573                                           &child_nat);
574
575       if (!is_vertical)
576         {
577           if (min_height_p)
578             *min_height_p = MAX (child_min, *min_height_p);
579
580           if (natural_height_p)
581             *natural_height_p = MAX (child_nat, *natural_height_p);
582         }
583       else
584         {
585           if (min_height_p)
586             *min_height_p += child_min;
587
588           if (natural_height_p)
589             *natural_height_p += child_nat;
590         }
591     }
592
593   if (is_vertical && n_children > 1)
594     {
595       if (min_height_p)
596         *min_height_p += priv->spacing * (n_children - 1);
597
598       if (natural_height_p)
599         *natural_height_p += priv->spacing * (n_children - 1);
600     }
601 }
602
603 static void
604 allocate_box_child (ClutterBoxLayout       *self,
605                     ClutterContainer       *container,
606                     ClutterActor           *child,
607                     ClutterActorBox        *child_box,
608                     ClutterAllocationFlags  flags,
609                     gboolean                use_animations,
610                     ClutterAnimationMode    easing_mode,
611                     guint                   easing_duration,
612                     guint                   easing_delay)
613 {
614   ClutterBoxChild *box_child;
615   ClutterLayoutMeta *meta;
616
617   meta = clutter_layout_manager_get_child_meta (CLUTTER_LAYOUT_MANAGER (self),
618                                                 container,
619                                                 child);
620   box_child = CLUTTER_BOX_CHILD (meta);
621
622   CLUTTER_NOTE (LAYOUT, "Allocation for %s { %.2f, %.2f, %.2f, %.2f }",
623                 _clutter_actor_get_debug_name (child),
624                 child_box->x1, child_box->y1,
625                 child_box->x2 - child_box->x1,
626                 child_box->y2 - child_box->y1);
627
628   if (use_animations)
629     {
630       clutter_actor_save_easing_state (child);
631       clutter_actor_set_easing_mode (child, easing_mode);
632       clutter_actor_set_easing_duration (child, easing_duration);
633       clutter_actor_set_easing_delay (child, easing_delay);
634     }
635
636   /* call allocate() instead of allocate_align_fill() if the actor needs
637    * expand in either direction. this will honour the actors alignment settings
638    */
639   if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL) ||
640       clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL))
641     clutter_actor_allocate (child, child_box, flags);
642   else
643     clutter_actor_allocate_align_fill (child, child_box,
644                                        get_box_alignment_factor (box_child->x_align),
645                                        get_box_alignment_factor (box_child->y_align),
646                                        box_child->x_fill,
647                                        box_child->y_fill,
648                                        flags);
649
650   if (use_animations)
651     clutter_actor_restore_easing_state (child);
652 }
653
654 static void
655 clutter_box_layout_get_preferred_width (ClutterLayoutManager *layout,
656                                         ClutterContainer     *container,
657                                         gfloat                for_height,
658                                         gfloat               *min_width_p,
659                                         gfloat               *natural_width_p)
660 {
661   ClutterBoxLayout *self = CLUTTER_BOX_LAYOUT (layout);
662
663   get_preferred_width (self, CLUTTER_ACTOR (container), for_height,
664                        min_width_p,
665                        natural_width_p);
666 }
667
668 static void
669 clutter_box_layout_get_preferred_height (ClutterLayoutManager *layout,
670                                          ClutterContainer     *container,
671                                          gfloat                for_width,
672                                          gfloat               *min_height_p,
673                                          gfloat               *natural_height_p)
674 {
675   ClutterBoxLayout *self = CLUTTER_BOX_LAYOUT (layout);
676
677   get_preferred_height (self, CLUTTER_ACTOR (container), for_width,
678                         min_height_p,
679                         natural_height_p);
680 }
681
682 static void
683 count_expand_children (ClutterLayoutManager *layout,
684                        ClutterContainer     *container,
685                        gint                 *visible_children,
686                        gint                 *expand_children)
687 {
688   ClutterBoxLayoutPrivate *priv = CLUTTER_BOX_LAYOUT (layout)->priv;
689   ClutterActor *actor, *child;
690   ClutterActorIter iter;
691
692   actor = CLUTTER_ACTOR (container);
693
694   *visible_children = *expand_children = 0;
695
696   clutter_actor_iter_init (&iter, actor);
697   while (clutter_actor_iter_next (&iter, &child))
698     {
699       if (CLUTTER_ACTOR_IS_VISIBLE (child))
700         {
701           ClutterLayoutMeta *meta;
702
703           *visible_children += 1;
704
705           meta = clutter_layout_manager_get_child_meta (layout,
706                                                         container,
707                                                         child);
708
709           if (clutter_actor_needs_expand (child, priv->orientation) ||
710               CLUTTER_BOX_CHILD (meta)->expand)
711             *expand_children += 1;
712         }
713     }
714 }
715
716 typedef struct _RequestedSize
717 {
718   ClutterActor *actor;
719
720   gfloat minimum_size;
721   gfloat natural_size;
722 } RequestedSize;
723
724 /* Pulled from gtksizerequest.c from Gtk+ */
725 static gint
726 compare_gap (gconstpointer p1,
727              gconstpointer p2,
728              gpointer      data)
729 {
730   RequestedSize *sizes = data;
731   const guint *c1 = p1;
732   const guint *c2 = p2;
733
734   const gint d1 = MAX (sizes[*c1].natural_size -
735                        sizes[*c1].minimum_size,
736                        0);
737   const gint d2 = MAX (sizes[*c2].natural_size -
738                        sizes[*c2].minimum_size,
739                        0);
740
741   gint delta = (d2 - d1);
742
743   if (0 == delta)
744     delta = (*c2 - *c1);
745
746   return delta;
747 }
748
749 /*
750  * distribute_natural_allocation:
751  * @extra_space: Extra space to redistribute among children after subtracting
752  *   minimum sizes and any child padding from the overall allocation
753  * @n_requested_sizes: Number of requests to fit into the allocation
754  * @sizes: An array of structs with a client pointer and a minimum/natural size
755  *   in the orientation of the allocation.
756  *
757  * Distributes @extra_space to child @sizes by bringing smaller
758  * children up to natural size first.
759  *
760  * The remaining space will be added to the @minimum_size member of the
761  * RequestedSize struct. If all sizes reach their natural size then
762  * the remaining space is returned.
763  *
764  * Returns: The remainder of @extra_space after redistributing space
765  * to @sizes.
766  *
767  * Pulled from gtksizerequest.c from Gtk+
768  */
769 static gint
770 distribute_natural_allocation (gint           extra_space,
771                                guint          n_requested_sizes,
772                                RequestedSize *sizes)
773 {
774   guint *spreading;
775   gint   i;
776
777   g_return_val_if_fail (extra_space >= 0, 0);
778
779   spreading = g_newa (guint, n_requested_sizes);
780
781   for (i = 0; i < n_requested_sizes; i++)
782     spreading[i] = i;
783
784   /* Distribute the container's extra space c_gap. We want to assign
785    * this space such that the sum of extra space assigned to children
786    * (c^i_gap) is equal to c_cap. The case that there's not enough
787    * space for all children to take their natural size needs some
788    * attention. The goals we want to achieve are:
789    *
790    *   a) Maximize number of children taking their natural size.
791    *   b) The allocated size of children should be a continuous
792    *   function of c_gap.  That is, increasing the container size by
793    *   one pixel should never make drastic changes in the distribution.
794    *   c) If child i takes its natural size and child j doesn't,
795    *   child j should have received at least as much gap as child i.
796    *
797    * The following code distributes the additional space by following
798    * these rules.
799    */
800
801   /* Sort descending by gap and position. */
802   g_qsort_with_data (spreading,
803                      n_requested_sizes, sizeof (guint),
804                      compare_gap, sizes);
805
806   /* Distribute available space.
807    * This master piece of a loop was conceived by Behdad Esfahbod.
808    */
809   for (i = n_requested_sizes - 1; extra_space > 0 && i >= 0; --i)
810     {
811       /* Divide remaining space by number of remaining children.
812        * Sort order and reducing remaining space by assigned space
813        * ensures that space is distributed equally.
814        */
815       gint glue = (extra_space + i) / (i + 1);
816       gint gap = sizes[(spreading[i])].natural_size
817                - sizes[(spreading[i])].minimum_size;
818
819       gint extra = MIN (glue, gap);
820
821       sizes[spreading[i]].minimum_size += extra;
822
823       extra_space -= extra;
824     }
825
826   return extra_space;
827 }
828
829 /* Pulled from gtkbox.c from Gtk+ */
830
831 static void
832 clutter_box_layout_allocate (ClutterLayoutManager   *layout,
833                              ClutterContainer       *container,
834                              const ClutterActorBox  *box,
835                              ClutterAllocationFlags  flags)
836 {
837   ClutterBoxLayoutPrivate *priv = CLUTTER_BOX_LAYOUT (layout)->priv;
838   ClutterActor *actor, *child;
839   gint nvis_children;
840   gint nexpand_children;
841   gboolean is_rtl;
842   ClutterActorIter iter;
843
844   ClutterActorBox child_allocation;
845   RequestedSize *sizes;
846
847   gint size;
848   gint extra;
849   gint n_extra_widgets = 0; /* Number of widgets that receive 1 extra px */
850   gint x = 0, y = 0, i;
851   gint child_size;
852
853   gboolean use_animations;
854   ClutterAnimationMode easing_mode;
855   guint easing_duration, easing_delay;
856
857   count_expand_children (layout, container, &nvis_children, &nexpand_children);
858
859   CLUTTER_NOTE (LAYOUT, "BoxLayout for %s: visible=%d, expand=%d",
860                 _clutter_actor_get_debug_name (CLUTTER_ACTOR (container)),
861                 nvis_children,
862                 nexpand_children);
863
864   /* If there is no visible child, simply return. */
865   if (nvis_children <= 0)
866     return;
867
868   sizes = g_newa (RequestedSize, nvis_children);
869
870   if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL)
871     size = box->y2 - box->y1 - (nvis_children - 1) * priv->spacing;
872   else
873     size = box->x2 - box->x1 - (nvis_children - 1) * priv->spacing;
874
875   actor = CLUTTER_ACTOR (container);
876
877   use_animations = clutter_layout_manager_get_easing_state (layout,
878                                                             &easing_mode,
879                                                             &easing_duration,
880                                                             &easing_delay);
881
882   /* Retrieve desired size for visible children. */
883   i = 0;
884   clutter_actor_iter_init (&iter, actor);
885   while (clutter_actor_iter_next (&iter, &child))
886     {
887       if (!CLUTTER_ACTOR_IS_VISIBLE (child))
888         continue;
889
890       if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL)
891         clutter_actor_get_preferred_height (child,
892                                             box->x2 - box->x1,
893                                             &sizes[i].minimum_size,
894                                             &sizes[i].natural_size);
895       else
896         clutter_actor_get_preferred_width (child,
897                                            box->y2 - box->y1,
898                                            &sizes[i].minimum_size,
899                                            &sizes[i].natural_size);
900
901
902       /* Assert the api is working properly */
903       if (sizes[i].minimum_size < 0)
904         g_error ("ClutterBoxLayout child %s minimum %s: %f < 0 for %s %f",
905                  _clutter_actor_get_debug_name (child),
906                  priv->orientation == CLUTTER_ORIENTATION_VERTICAL
907                    ? "height"
908                    : "width",
909                  sizes[i].minimum_size,
910                  priv->orientation == CLUTTER_ORIENTATION_VERTICAL
911                    ? "width"
912                    : "height",
913                  priv->orientation == CLUTTER_ORIENTATION_VERTICAL
914                    ? box->x2 - box->x1
915                    : box->y2 - box->y1);
916
917       if (sizes[i].natural_size < sizes[i].minimum_size)
918         g_error ("ClutterBoxLayout child %s natural %s: %f < minimum %f for %s %f",
919                  _clutter_actor_get_debug_name (child),
920                  priv->orientation == CLUTTER_ORIENTATION_VERTICAL
921                    ? "height"
922                    : "width",
923                  sizes[i].natural_size,
924                  sizes[i].minimum_size,
925                  priv->orientation == CLUTTER_ORIENTATION_VERTICAL
926                    ? "width"
927                    : "height",
928                  priv->orientation == CLUTTER_ORIENTATION_VERTICAL
929                    ? box->x2 - box->x1
930                    : box->y2 - box->y1);
931
932       size -= sizes[i].minimum_size;
933
934       sizes[i].actor = child;
935
936       i += 1;
937     }
938
939   if (priv->is_homogeneous)
940     {
941       /* If were homogenous we still need to run the above loop to get the
942        * minimum sizes for children that are not going to fill
943        */
944       if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL)
945         size = box->y2 - box->y1 - (nvis_children - 1) * priv->spacing;
946       else
947         size = box->x2 - box->x1 - (nvis_children - 1) * priv->spacing;
948
949       extra = size / nvis_children;
950       n_extra_widgets = size % nvis_children;
951     }
952   else
953     {
954       /* Bring children up to size first */
955       size = distribute_natural_allocation (MAX (0, size), nvis_children, sizes);
956
957       /* Calculate space which hasn't distributed yet,
958        * and is available for expanding children.
959        */
960       if (nexpand_children > 0)
961         {
962           extra = size / nexpand_children;
963           n_extra_widgets = size % nexpand_children;
964         }
965       else
966         extra = 0;
967     }
968
969   if (priv->orientation == CLUTTER_ORIENTATION_HORIZONTAL)
970     {
971       ClutterTextDirection text_dir;
972
973       text_dir = clutter_actor_get_text_direction (CLUTTER_ACTOR (container));
974       is_rtl = (text_dir == CLUTTER_TEXT_DIRECTION_RTL) ? TRUE : FALSE;
975     }
976   else
977     is_rtl = FALSE;
978
979   /* Allocate child positions. */
980   if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL)
981     {
982       child_allocation.x1 = box->x1;
983       child_allocation.x2 = MAX (1.0, box->x2 - box->x1);
984       if (priv->is_pack_start)
985         y = box->y2 - box->y1;
986       else
987         y = box->y1;
988     }
989   else
990     {
991       child_allocation.y1 = box->y1;
992       child_allocation.y2 = MAX (1.0, box->y2 - box->y1);
993       if (priv->is_pack_start)
994         x = box->x2 - box->x1;
995       else
996         x = box->x1;
997     }
998
999   i = 0;
1000   clutter_actor_iter_init (&iter, actor);
1001   while (clutter_actor_iter_next (&iter, &child))
1002     {
1003       ClutterLayoutMeta *meta;
1004       ClutterBoxChild *box_child;
1005
1006       /* If widget is not visible, skip it. */
1007       if (!CLUTTER_ACTOR_IS_VISIBLE (child))
1008         continue;
1009
1010       meta = clutter_layout_manager_get_child_meta (layout,
1011                                                     container,
1012                                                     child);
1013       box_child = CLUTTER_BOX_CHILD (meta);
1014
1015       /* Assign the child's size. */
1016       if (priv->is_homogeneous)
1017         {
1018           child_size = extra;
1019
1020           if (n_extra_widgets > 0)
1021             {
1022               child_size++;
1023               n_extra_widgets--;
1024             }
1025         }
1026       else
1027         {
1028           child_size = sizes[i].minimum_size;
1029
1030           if (clutter_actor_needs_expand (child, priv->orientation) ||
1031               box_child->expand)
1032             {
1033               child_size += extra;
1034
1035               if (n_extra_widgets > 0)
1036                 {
1037                   child_size++;
1038                   n_extra_widgets--;
1039                 }
1040             }
1041         }
1042
1043       /* Assign the child's position. */
1044       if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL)
1045         {
1046           if (clutter_actor_needs_expand (child, priv->orientation) ||
1047               box_child->y_fill)
1048             {
1049               child_allocation.y1 = y;
1050               child_allocation.y2 = child_allocation.y1 + MAX (1.0, child_size);
1051             }
1052           else
1053             {
1054               child_allocation.y1 = y + (child_size - sizes[i].minimum_size) / 2;
1055               child_allocation.y2 = child_allocation.y1 + sizes[i].minimum_size;
1056             }
1057
1058           if (priv->is_pack_start)
1059             {
1060               y -= child_size + priv->spacing;
1061
1062               child_allocation.y1 -= child_size;
1063               child_allocation.y2 -= child_size;
1064             }
1065           else
1066             {
1067               y += child_size + priv->spacing;
1068             }
1069         }
1070       else /* CLUTTER_ORIENTATION_HORIZONTAL */
1071         {
1072           if (clutter_actor_needs_expand (child, priv->orientation) ||
1073               box_child->x_fill)
1074             {
1075               child_allocation.x1 = x;
1076               child_allocation.x2 = child_allocation.x1 + MAX (1.0, child_size);
1077             }
1078           else
1079             {
1080               child_allocation.x1 = x + (child_size - sizes[i].minimum_size) / 2;
1081               child_allocation.x2 = child_allocation.x1 + sizes[i].minimum_size;
1082             }
1083
1084           if (priv->is_pack_start)
1085             {
1086               x -= child_size + priv->spacing;
1087
1088               child_allocation.x1 -= child_size;
1089               child_allocation.x2 -= child_size;
1090             }
1091           else
1092             {
1093               x += child_size + priv->spacing;
1094             }
1095
1096           if (is_rtl)
1097             {
1098               gfloat width = child_allocation.x2 - child_allocation.x1;
1099
1100               child_allocation.x1 = box->x2 - box->x1
1101                                   - child_allocation.x1
1102                                   - (child_allocation.x2 - child_allocation.x1);
1103               child_allocation.x2 = child_allocation.x1 + width;
1104             }
1105
1106         }
1107
1108         allocate_box_child (CLUTTER_BOX_LAYOUT (layout),
1109                             container,
1110                             child,
1111                             &child_allocation,
1112                             flags,
1113                             use_animations,
1114                             easing_mode,
1115                             easing_duration,
1116                             easing_delay);
1117
1118         i += 1;
1119     }
1120 }
1121
1122 static void
1123 clutter_box_layout_set_property (GObject      *gobject,
1124                                  guint         prop_id,
1125                                  const GValue *value,
1126                                  GParamSpec   *pspec)
1127 {
1128   ClutterBoxLayout *self = CLUTTER_BOX_LAYOUT (gobject);
1129
1130   switch (prop_id)
1131     {
1132     case PROP_VERTICAL:
1133       clutter_box_layout_set_vertical (self, g_value_get_boolean (value));
1134       break;
1135
1136     case PROP_ORIENTATION:
1137       clutter_box_layout_set_orientation (self, g_value_get_enum (value));
1138       break;
1139
1140     case PROP_HOMOGENEOUS:
1141       clutter_box_layout_set_homogeneous (self, g_value_get_boolean (value));
1142       break;
1143
1144     case PROP_SPACING:
1145       clutter_box_layout_set_spacing (self, g_value_get_uint (value));
1146       break;
1147
1148     case PROP_PACK_START:
1149       clutter_box_layout_set_pack_start (self, g_value_get_boolean (value));
1150       break;
1151
1152     default:
1153       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
1154       break;
1155     }
1156 }
1157
1158 static void
1159 clutter_box_layout_get_property (GObject    *gobject,
1160                                  guint       prop_id,
1161                                  GValue     *value,
1162                                  GParamSpec *pspec)
1163 {
1164   ClutterBoxLayoutPrivate *priv = CLUTTER_BOX_LAYOUT (gobject)->priv;
1165
1166   switch (prop_id)
1167     {
1168     case PROP_VERTICAL:
1169       g_value_set_boolean (value,
1170                            priv->orientation == CLUTTER_ORIENTATION_VERTICAL);
1171       break;
1172
1173     case PROP_ORIENTATION:
1174       g_value_set_enum (value, priv->orientation);
1175       break;
1176
1177     case PROP_HOMOGENEOUS:
1178       g_value_set_boolean (value, priv->is_homogeneous);
1179       break;
1180
1181     case PROP_SPACING:
1182       g_value_set_uint (value, priv->spacing);
1183       break;
1184
1185     case PROP_PACK_START:
1186       g_value_set_boolean (value, priv->is_pack_start);
1187       break;
1188
1189     default:
1190       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
1191       break;
1192     }
1193 }
1194
1195 static void
1196 clutter_box_layout_class_init (ClutterBoxLayoutClass *klass)
1197 {
1198   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1199   ClutterLayoutManagerClass *layout_class;
1200
1201   layout_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass);
1202
1203   layout_class->get_preferred_width = clutter_box_layout_get_preferred_width;
1204   layout_class->get_preferred_height = clutter_box_layout_get_preferred_height;
1205   layout_class->allocate = clutter_box_layout_allocate;
1206   layout_class->set_container = clutter_box_layout_set_container;
1207   layout_class->get_child_meta_type = clutter_box_layout_get_child_meta_type;
1208
1209   g_type_class_add_private (klass, sizeof (ClutterBoxLayoutPrivate));
1210
1211   /**
1212    * ClutterBoxLayout:vertical:
1213    *
1214    * Whether the #ClutterBoxLayout should arrange its children
1215    * alongside the Y axis, instead of alongside the X axis
1216    *
1217    * Since: 1.2
1218    *
1219    * Deprecated: 1.12: Use #ClutterBoxLayout:orientation instead.
1220    */
1221   obj_props[PROP_VERTICAL] =
1222     g_param_spec_boolean ("vertical",
1223                           P_("Vertical"),
1224                           P_("Whether the layout should be vertical, "
1225                              "rather than horizontal"),
1226                           FALSE,
1227                           G_PARAM_READWRITE |
1228                           G_PARAM_STATIC_STRINGS |
1229                           G_PARAM_DEPRECATED);
1230
1231   /**
1232    * ClutterBoxLayout:orientation:
1233    *
1234    * The orientation of the #ClutterBoxLayout, either horizontal
1235    * or vertical
1236    *
1237    * Since: 1.12
1238    */
1239   obj_props[PROP_ORIENTATION] =
1240     g_param_spec_enum ("orientation",
1241                        P_("Orientation"),
1242                        P_("The orientation of the layout"),
1243                        CLUTTER_TYPE_ORIENTATION,
1244                        CLUTTER_ORIENTATION_HORIZONTAL,
1245                        G_PARAM_READWRITE |
1246                        G_PARAM_STATIC_STRINGS);
1247
1248   /**
1249    * ClutterBoxLayout:homogeneous:
1250    *
1251    * Whether the #ClutterBoxLayout should arrange its children
1252    * homogeneously, i.e. all childs get the same size
1253    *
1254    * Since: 1.4
1255    */
1256   obj_props[PROP_HOMOGENEOUS] =
1257     g_param_spec_boolean ("homogeneous",
1258                           P_("Homogeneous"),
1259                           P_("Whether the layout should be homogeneous, "
1260                              "i.e. all childs get the same size"),
1261                           FALSE,
1262                           CLUTTER_PARAM_READWRITE);
1263
1264   /**
1265    * ClutterBoxLayout:pack-start:
1266    *
1267    * Whether the #ClutterBoxLayout should pack items at the start
1268    * or append them at the end
1269    *
1270    * Since: 1.2
1271    */
1272   obj_props[PROP_PACK_START] =
1273     g_param_spec_boolean ("pack-start",
1274                           P_("Pack Start"),
1275                           P_("Whether to pack items at the start of the box"),
1276                           FALSE,
1277                           CLUTTER_PARAM_READWRITE);
1278
1279   /**
1280    * ClutterBoxLayout:spacing:
1281    *
1282    * The spacing between children of the #ClutterBoxLayout, in pixels
1283    *
1284    * Since: 1.2
1285    */
1286   obj_props[PROP_SPACING] =
1287     g_param_spec_uint ("spacing",
1288                        P_("Spacing"),
1289                        P_("Spacing between children"),
1290                        0, G_MAXUINT, 0,
1291                        CLUTTER_PARAM_READWRITE);
1292
1293   /* a leftover to be compatible to the previous implementation */
1294   obj_props[PROP_EASING_DURATION] =
1295     g_param_spec_uint ("easing-duration",
1296                        P_("Easing Duration"),
1297                        P_("The duration of the animations"),
1298                        0, G_MAXUINT, 500,
1299                        CLUTTER_PARAM_READWRITE);
1300
1301   gobject_class->set_property = clutter_box_layout_set_property;
1302   gobject_class->get_property = clutter_box_layout_get_property;
1303   g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
1304 }
1305
1306 static void
1307 clutter_box_layout_init (ClutterBoxLayout *layout)
1308 {
1309   ClutterBoxLayoutPrivate *priv;
1310
1311   layout->priv = priv = CLUTTER_BOX_LAYOUT_GET_PRIVATE (layout);
1312
1313   priv->orientation = CLUTTER_ORIENTATION_HORIZONTAL;
1314   priv->is_homogeneous = FALSE;
1315   priv->is_pack_start = FALSE;
1316   priv->spacing = 0;
1317 }
1318
1319 /**
1320  * clutter_box_layout_new:
1321  *
1322  * Creates a new #ClutterBoxLayout layout manager
1323  *
1324  * Return value: the newly created #ClutterBoxLayout
1325  *
1326  * Since: 1.2
1327  */
1328 ClutterLayoutManager *
1329 clutter_box_layout_new (void)
1330 {
1331   return g_object_new (CLUTTER_TYPE_BOX_LAYOUT, NULL);
1332 }
1333
1334 /**
1335  * clutter_box_layout_set_spacing:
1336  * @layout: a #ClutterBoxLayout
1337  * @spacing: the spacing between children of the layout, in pixels
1338  *
1339  * Sets the spacing between children of @layout
1340  *
1341  * Since: 1.2
1342  */
1343 void
1344 clutter_box_layout_set_spacing (ClutterBoxLayout *layout,
1345                                 guint             spacing)
1346 {
1347   ClutterBoxLayoutPrivate *priv;
1348
1349   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
1350
1351   priv = layout->priv;
1352
1353   if (priv->spacing != spacing)
1354     {
1355       ClutterLayoutManager *manager;
1356
1357       priv->spacing = spacing;
1358
1359       manager = CLUTTER_LAYOUT_MANAGER (layout);
1360
1361       clutter_layout_manager_layout_changed (manager);
1362
1363       g_object_notify (G_OBJECT (layout), "spacing");
1364     }
1365 }
1366
1367 /**
1368  * clutter_box_layout_get_spacing:
1369  * @layout: a #ClutterBoxLayout
1370  *
1371  * Retrieves the spacing set using clutter_box_layout_set_spacing()
1372  *
1373  * Return value: the spacing between children of the #ClutterBoxLayout
1374  *
1375  * Since: 1.2
1376  */
1377 guint
1378 clutter_box_layout_get_spacing (ClutterBoxLayout *layout)
1379 {
1380   g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), 0);
1381
1382   return layout->priv->spacing;
1383 }
1384
1385 /**
1386  * clutter_box_layout_set_vertical:
1387  * @layout: a #ClutterBoxLayout
1388  * @vertical: %TRUE if the layout should be vertical
1389  *
1390  * Sets whether @layout should arrange its children vertically alongside
1391  * the Y axis, instead of horizontally alongside the X axis
1392  *
1393  * Since: 1.2
1394  *
1395  * Deprecated: 1.12: Use clutter_box_layout_set_orientation() instead.
1396  */
1397 void
1398 clutter_box_layout_set_vertical (ClutterBoxLayout *layout,
1399                                  gboolean          vertical)
1400 {
1401   ClutterOrientation new_orientation, old_orientation;
1402
1403   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
1404
1405   old_orientation = layout->priv->orientation;
1406   new_orientation = vertical
1407                   ? CLUTTER_ORIENTATION_VERTICAL
1408                   : CLUTTER_ORIENTATION_HORIZONTAL;
1409   clutter_box_layout_set_orientation (layout, new_orientation);
1410
1411   if (old_orientation != new_orientation)
1412     g_object_notify_by_pspec (G_OBJECT (layout), obj_props[PROP_VERTICAL]);
1413 }
1414
1415 /**
1416  * clutter_box_layout_set_orientation:
1417  * @layout: a #ClutterBoxLayout
1418  * @orientation: the orientation of the #ClutterBoxLayout
1419  *
1420  * Sets the orientation of the #ClutterBoxLayout layout manager.
1421  *
1422  * Since: 1.12
1423  */
1424 void
1425 clutter_box_layout_set_orientation (ClutterBoxLayout   *layout,
1426                                     ClutterOrientation  orientation)
1427 {
1428   ClutterBoxLayoutPrivate *priv;
1429   ClutterLayoutManager *manager;
1430
1431   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
1432
1433   priv = layout->priv;
1434
1435   if (priv->orientation == orientation)
1436     return;
1437
1438   priv->orientation = orientation;
1439
1440   manager = CLUTTER_LAYOUT_MANAGER (layout);
1441
1442   clutter_layout_manager_layout_changed (manager);
1443
1444   g_object_notify_by_pspec (G_OBJECT (layout), obj_props[PROP_ORIENTATION]);
1445 }
1446
1447 /**
1448  * clutter_box_layout_get_vertical:
1449  * @layout: a #ClutterBoxLayout
1450  *
1451  * Retrieves the orientation of the @layout as set using the
1452  * clutter_box_layout_set_vertical() function
1453  *
1454  * Return value: %TRUE if the #ClutterBoxLayout is arranging its children
1455  *   vertically, and %FALSE otherwise
1456  *
1457  * Since: 1.2
1458  *
1459  * Deprecated: 1.12: Use clutter_box_layout_get_orientation() instead
1460  */
1461 gboolean
1462 clutter_box_layout_get_vertical (ClutterBoxLayout *layout)
1463 {
1464   g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), FALSE);
1465
1466   return layout->priv->orientation == CLUTTER_ORIENTATION_VERTICAL;
1467 }
1468
1469 /**
1470  * clutter_box_layout_get_orientation:
1471  * @layout: a #ClutterBoxLayout
1472  *
1473  * Retrieves the orientation of the @layout.
1474  *
1475  * Return value: the orientation of the layout
1476  *
1477  * Since: 1.12
1478  */
1479 ClutterOrientation
1480 clutter_box_layout_get_orientation (ClutterBoxLayout *layout)
1481 {
1482   g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout),
1483                         CLUTTER_ORIENTATION_HORIZONTAL);
1484
1485   return layout->priv->orientation;
1486 }
1487
1488 /**
1489  * clutter_box_layout_set_homogeneous:
1490  * @layout: a #ClutterBoxLayout
1491  * @homogeneous: %TRUE if the layout should be homogeneous
1492  *
1493  * Sets whether the size of @layout children should be
1494  * homogeneous
1495  *
1496  * Since: 1.4
1497  */
1498 void
1499 clutter_box_layout_set_homogeneous (ClutterBoxLayout *layout,
1500                                     gboolean          homogeneous)
1501 {
1502   ClutterBoxLayoutPrivate *priv;
1503
1504   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
1505
1506   priv = layout->priv;
1507
1508   if (priv->is_homogeneous != homogeneous)
1509     {
1510       ClutterLayoutManager *manager;
1511
1512       priv->is_homogeneous = !!homogeneous;
1513
1514       manager = CLUTTER_LAYOUT_MANAGER (layout);
1515
1516       clutter_layout_manager_layout_changed (manager);
1517
1518       g_object_notify (G_OBJECT (layout), "homogeneous");
1519     }
1520 }
1521
1522 /**
1523  * clutter_box_layout_get_homogeneous:
1524  * @layout: a #ClutterBoxLayout
1525  *
1526  * Retrieves if the children sizes are allocated homogeneously.
1527  *
1528  * Return value: %TRUE if the #ClutterBoxLayout is arranging its children
1529  *   homogeneously, and %FALSE otherwise
1530  *
1531  * Since: 1.4
1532  */
1533 gboolean
1534 clutter_box_layout_get_homogeneous (ClutterBoxLayout *layout)
1535 {
1536   g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), FALSE);
1537
1538   return layout->priv->is_homogeneous;
1539 }
1540
1541 /**
1542  * clutter_box_layout_set_pack_start:
1543  * @layout: a #ClutterBoxLayout
1544  * @pack_start: %TRUE if the @layout should pack children at the
1545  *   beginning of the layout
1546  *
1547  * Sets whether children of @layout should be layed out by appending
1548  * them or by prepending them
1549  *
1550  * Since: 1.2
1551  */
1552 void
1553 clutter_box_layout_set_pack_start (ClutterBoxLayout *layout,
1554                                    gboolean          pack_start)
1555 {
1556   ClutterBoxLayoutPrivate *priv;
1557
1558   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
1559
1560   priv = layout->priv;
1561
1562   if (priv->is_pack_start != pack_start)
1563     {
1564       ClutterLayoutManager *manager;
1565
1566       priv->is_pack_start = pack_start ? TRUE : FALSE;
1567
1568       manager = CLUTTER_LAYOUT_MANAGER (layout);
1569
1570       clutter_layout_manager_layout_changed (manager);
1571
1572       g_object_notify (G_OBJECT (layout), "pack-start");
1573     }
1574 }
1575
1576 /**
1577  * clutter_box_layout_get_pack_start:
1578  * @layout: a #ClutterBoxLayout
1579  *
1580  * Retrieves the value set using clutter_box_layout_set_pack_start()
1581  *
1582  * Return value: %TRUE if the #ClutterBoxLayout should pack children
1583  *  at the beginning of the layout, and %FALSE otherwise
1584  *
1585  * Since: 1.2
1586  */
1587 gboolean
1588 clutter_box_layout_get_pack_start (ClutterBoxLayout *layout)
1589 {
1590   g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), FALSE);
1591
1592   return layout->priv->is_pack_start;
1593 }
1594
1595 /**
1596  * clutter_box_layout_pack:
1597  * @layout: a #ClutterBoxLayout
1598  * @actor: a #ClutterActor
1599  * @expand: whether the @actor should expand
1600  * @x_fill: whether the @actor should fill horizontally
1601  * @y_fill: whether the @actor should fill vertically
1602  * @x_align: the horizontal alignment policy for @actor
1603  * @y_align: the vertical alignment policy for @actor
1604  *
1605  * Packs @actor inside the #ClutterContainer associated to @layout
1606  * and sets the layout properties
1607  *
1608  * Since: 1.2
1609  * Deprecated: 1.12: #ClutterBoxLayout honours #ClutterActor's
1610  *   align and expand properties. The preferred way is adding
1611  *   the @actor with clutter_actor_add_child() and setting
1612  *   #ClutterActor:x-align, #ClutterActor:y-align,
1613  *   #ClutterActor:x-expand and #ClutterActor:y-expand
1614  */
1615 void
1616 clutter_box_layout_pack (ClutterBoxLayout    *layout,
1617                          ClutterActor        *actor,
1618                          gboolean             expand,
1619                          gboolean             x_fill,
1620                          gboolean             y_fill,
1621                          ClutterBoxAlignment  x_align,
1622                          ClutterBoxAlignment  y_align)
1623 {
1624   ClutterBoxLayoutPrivate *priv;
1625   ClutterLayoutManager *manager;
1626   ClutterLayoutMeta *meta;
1627
1628   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
1629   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
1630
1631   priv = layout->priv;
1632
1633   if (priv->container == NULL)
1634     {
1635       g_warning ("The layout of type '%s' must be associated to "
1636                  "a ClutterContainer before adding children",
1637                  G_OBJECT_TYPE_NAME (layout));
1638       return;
1639     }
1640
1641   clutter_container_add_actor (priv->container, actor);
1642
1643   manager = CLUTTER_LAYOUT_MANAGER (layout);
1644   meta = clutter_layout_manager_get_child_meta (manager,
1645                                                 priv->container,
1646                                                 actor);
1647   g_assert (CLUTTER_IS_BOX_CHILD (meta));
1648
1649   box_child_set_align (CLUTTER_BOX_CHILD (meta), x_align, y_align);
1650   box_child_set_fill (CLUTTER_BOX_CHILD (meta), x_fill, y_fill);
1651   box_child_set_expand (CLUTTER_BOX_CHILD (meta), expand);
1652 }
1653
1654 /**
1655  * clutter_box_layout_set_alignment:
1656  * @layout: a #ClutterBoxLayout
1657  * @actor: a #ClutterActor child of @layout
1658  * @x_align: Horizontal alignment policy for @actor
1659  * @y_align: Vertical alignment policy for @actor
1660  *
1661  * Sets the horizontal and vertical alignment policies for @actor
1662  * inside @layout
1663  *
1664  * Since: 1.2
1665  * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's
1666  *   #ClutterActor:x-align and #ClutterActor:y-align properies
1667  */
1668 void
1669 clutter_box_layout_set_alignment (ClutterBoxLayout    *layout,
1670                                   ClutterActor        *actor,
1671                                   ClutterBoxAlignment  x_align,
1672                                   ClutterBoxAlignment  y_align)
1673 {
1674   ClutterBoxLayoutPrivate *priv;
1675   ClutterLayoutManager *manager;
1676   ClutterLayoutMeta *meta;
1677
1678   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
1679   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
1680
1681   priv = layout->priv;
1682
1683   if (priv->container == NULL)
1684     {
1685       g_warning ("The layout of type '%s' must be associated to "
1686                  "a ClutterContainer before querying layout "
1687                  "properties",
1688                  G_OBJECT_TYPE_NAME (layout));
1689       return;
1690     }
1691
1692   manager = CLUTTER_LAYOUT_MANAGER (layout);
1693   meta = clutter_layout_manager_get_child_meta (manager,
1694                                                 priv->container,
1695                                                 actor);
1696   if (meta == NULL)
1697     {
1698       g_warning ("No layout meta found for the child of type '%s' "
1699                  "inside the layout manager of type '%s'",
1700                  G_OBJECT_TYPE_NAME (actor),
1701                  G_OBJECT_TYPE_NAME (manager));
1702       return;
1703     }
1704
1705   g_assert (CLUTTER_IS_BOX_CHILD (meta));
1706
1707   box_child_set_align (CLUTTER_BOX_CHILD (meta), x_align, y_align);
1708 }
1709
1710 /**
1711  * clutter_box_layout_get_alignment:
1712  * @layout: a #ClutterBoxLayout
1713  * @actor: a #ClutterActor child of @layout
1714  * @x_align: (out): return location for the horizontal alignment policy
1715  * @y_align: (out): return location for the vertical alignment policy
1716  *
1717  * Retrieves the horizontal and vertical alignment policies for @actor
1718  * as set using clutter_box_layout_pack() or clutter_box_layout_set_alignment()
1719  *
1720  * Since: 1.2
1721  * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's
1722  *   #ClutterActor:x-align and #ClutterActor:y-align properies
1723  */
1724 void
1725 clutter_box_layout_get_alignment (ClutterBoxLayout    *layout,
1726                                   ClutterActor        *actor,
1727                                   ClutterBoxAlignment *x_align,
1728                                   ClutterBoxAlignment *y_align)
1729 {
1730   ClutterBoxLayoutPrivate *priv;
1731   ClutterLayoutManager *manager;
1732   ClutterLayoutMeta *meta;
1733
1734   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
1735   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
1736
1737   priv = layout->priv;
1738
1739   if (priv->container == NULL)
1740     {
1741       g_warning ("The layout of type '%s' must be associated to "
1742                  "a ClutterContainer before querying layout "
1743                  "properties",
1744                  G_OBJECT_TYPE_NAME (layout));
1745       return;
1746     }
1747
1748   manager = CLUTTER_LAYOUT_MANAGER (layout);
1749   meta = clutter_layout_manager_get_child_meta (manager,
1750                                                 priv->container,
1751                                                 actor);
1752   if (meta == NULL)
1753     {
1754       g_warning ("No layout meta found for the child of type '%s' "
1755                  "inside the layout manager of type '%s'",
1756                  G_OBJECT_TYPE_NAME (actor),
1757                  G_OBJECT_TYPE_NAME (manager));
1758       return;
1759     }
1760
1761   g_assert (CLUTTER_IS_BOX_CHILD (meta));
1762
1763   if (x_align)
1764     *x_align = CLUTTER_BOX_CHILD (meta)->x_align;
1765
1766   if (y_align)
1767     *y_align = CLUTTER_BOX_CHILD (meta)->y_align;
1768 }
1769
1770 /**
1771  * clutter_box_layout_set_fill:
1772  * @layout: a #ClutterBoxLayout
1773  * @actor: a #ClutterActor child of @layout
1774  * @x_fill: whether @actor should fill horizontally the allocated space
1775  * @y_fill: whether @actor should fill vertically the allocated space
1776  *
1777  * Sets the horizontal and vertical fill policies for @actor
1778  * inside @layout
1779  *
1780  * Since: 1.2
1781  * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's
1782  *   #ClutterActor:x-align and #ClutterActor:y-align properies
1783  */
1784 void
1785 clutter_box_layout_set_fill (ClutterBoxLayout *layout,
1786                              ClutterActor     *actor,
1787                              gboolean          x_fill,
1788                              gboolean          y_fill)
1789 {
1790   ClutterBoxLayoutPrivate *priv;
1791   ClutterLayoutManager *manager;
1792   ClutterLayoutMeta *meta;
1793
1794   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
1795   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
1796
1797   priv = layout->priv;
1798
1799   if (priv->container == NULL)
1800     {
1801       g_warning ("The layout of type '%s' must be associated to "
1802                  "a ClutterContainer before querying layout "
1803                  "properties",
1804                  G_OBJECT_TYPE_NAME (layout));
1805       return;
1806     }
1807
1808   manager = CLUTTER_LAYOUT_MANAGER (layout);
1809   meta = clutter_layout_manager_get_child_meta (manager,
1810                                                 priv->container,
1811                                                 actor);
1812   if (meta == NULL)
1813     {
1814       g_warning ("No layout meta found for the child of type '%s' "
1815                  "inside the layout manager of type '%s'",
1816                  G_OBJECT_TYPE_NAME (actor),
1817                  G_OBJECT_TYPE_NAME (manager));
1818       return;
1819     }
1820
1821   g_assert (CLUTTER_IS_BOX_CHILD (meta));
1822
1823   box_child_set_fill (CLUTTER_BOX_CHILD (meta), x_fill, y_fill);
1824 }
1825
1826 /**
1827  * clutter_box_layout_get_fill:
1828  * @layout: a #ClutterBoxLayout
1829  * @actor: a #ClutterActor child of @layout
1830  * @x_fill: (out): return location for the horizontal fill policy
1831  * @y_fill: (out): return location for the vertical fill policy
1832  *
1833  * Retrieves the horizontal and vertical fill policies for @actor
1834  * as set using clutter_box_layout_pack() or clutter_box_layout_set_fill()
1835  *
1836  * Since: 1.2
1837  * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's
1838  *   #ClutterActor:x-align and #ClutterActor:y-align properies
1839  */
1840 void
1841 clutter_box_layout_get_fill (ClutterBoxLayout *layout,
1842                              ClutterActor     *actor,
1843                              gboolean         *x_fill,
1844                              gboolean         *y_fill)
1845 {
1846   ClutterBoxLayoutPrivate *priv;
1847   ClutterLayoutManager *manager;
1848   ClutterLayoutMeta *meta;
1849
1850   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
1851   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
1852
1853   priv = layout->priv;
1854
1855   if (priv->container == NULL)
1856     {
1857       g_warning ("The layout of type '%s' must be associated to "
1858                  "a ClutterContainer before querying layout "
1859                  "properties",
1860                  G_OBJECT_TYPE_NAME (layout));
1861       return;
1862     }
1863
1864   manager = CLUTTER_LAYOUT_MANAGER (layout);
1865   meta = clutter_layout_manager_get_child_meta (manager,
1866                                                 priv->container,
1867                                                 actor);
1868   if (meta == NULL)
1869     {
1870       g_warning ("No layout meta found for the child of type '%s' "
1871                  "inside the layout manager of type '%s'",
1872                  G_OBJECT_TYPE_NAME (actor),
1873                  G_OBJECT_TYPE_NAME (manager));
1874       return;
1875     }
1876
1877   g_assert (CLUTTER_IS_BOX_CHILD (meta));
1878
1879   if (x_fill)
1880     *x_fill = CLUTTER_BOX_CHILD (meta)->x_fill;
1881
1882   if (y_fill)
1883     *y_fill = CLUTTER_BOX_CHILD (meta)->y_fill;
1884 }
1885
1886 /**
1887  * clutter_box_layout_set_expand:
1888  * @layout: a #ClutterBoxLayout
1889  * @actor: a #ClutterActor child of @layout
1890  * @expand: whether @actor should expand
1891  *
1892  * Sets whether @actor should expand inside @layout
1893  *
1894  * Since: 1.2
1895  * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's
1896  *   #ClutterActor:x-expand and #ClutterActor:y-expand properies
1897  */
1898 void
1899 clutter_box_layout_set_expand (ClutterBoxLayout *layout,
1900                                ClutterActor     *actor,
1901                                gboolean          expand)
1902 {
1903   ClutterBoxLayoutPrivate *priv;
1904   ClutterLayoutManager *manager;
1905   ClutterLayoutMeta *meta;
1906
1907   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
1908   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
1909
1910   priv = layout->priv;
1911
1912   if (priv->container == NULL)
1913     {
1914       g_warning ("The layout of type '%s' must be associated to "
1915                  "a ClutterContainer before querying layout "
1916                  "properties",
1917                  G_OBJECT_TYPE_NAME (layout));
1918       return;
1919     }
1920
1921   manager = CLUTTER_LAYOUT_MANAGER (layout);
1922   meta = clutter_layout_manager_get_child_meta (manager,
1923                                                 priv->container,
1924                                                 actor);
1925   if (meta == NULL)
1926     {
1927       g_warning ("No layout meta found for the child of type '%s' "
1928                  "inside the layout manager of type '%s'",
1929                  G_OBJECT_TYPE_NAME (actor),
1930                  G_OBJECT_TYPE_NAME (manager));
1931       return;
1932     }
1933
1934   g_assert (CLUTTER_IS_BOX_CHILD (meta));
1935
1936   box_child_set_expand (CLUTTER_BOX_CHILD (meta), expand);
1937 }
1938
1939 /**
1940  * clutter_box_layout_get_expand:
1941  * @layout: a #ClutterBoxLayout
1942  * @actor: a #ClutterActor child of @layout
1943  *
1944  * Retrieves whether @actor should expand inside @layout
1945  *
1946  * Return value: %TRUE if the #ClutterActor should expand, %FALSE otherwise
1947  *
1948  * Since: 1.2
1949  * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's
1950  *   #ClutterActor:x-expand and #ClutterActor:y-expand properies
1951  */
1952 gboolean
1953 clutter_box_layout_get_expand (ClutterBoxLayout *layout,
1954                                ClutterActor     *actor)
1955 {
1956   ClutterBoxLayoutPrivate *priv;
1957   ClutterLayoutManager *manager;
1958   ClutterLayoutMeta *meta;
1959
1960   g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), FALSE);
1961   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
1962
1963   priv = layout->priv;
1964
1965   if (priv->container == NULL)
1966     {
1967       g_warning ("The layout of type '%s' must be associated to "
1968                  "a ClutterContainer before querying layout "
1969                  "properties",
1970                  G_OBJECT_TYPE_NAME (layout));
1971       return FALSE;
1972     }
1973
1974   manager = CLUTTER_LAYOUT_MANAGER (layout);
1975   meta = clutter_layout_manager_get_child_meta (manager,
1976                                                 priv->container,
1977                                                 actor);
1978   if (meta == NULL)
1979     {
1980       g_warning ("No layout meta found for the child of type '%s' "
1981                  "inside the layout manager of type '%s'",
1982                  G_OBJECT_TYPE_NAME (actor),
1983                  G_OBJECT_TYPE_NAME (manager));
1984       return FALSE;
1985     }
1986
1987   g_assert (CLUTTER_IS_BOX_CHILD (meta));
1988
1989   return CLUTTER_BOX_CHILD (meta)->expand;
1990 }
1991
1992 /**
1993  * clutter_box_layout_set_use_animations:
1994  * @layout: a #ClutterBoxLayout
1995  * @animate: %TRUE if the @layout should use animations
1996  *
1997  * Sets whether @layout should animate changes in the layout properties
1998  *
1999  * The duration of the animations is controlled by
2000  * clutter_box_layout_set_easing_duration(); the easing mode to be used
2001  * by the animations is controlled by clutter_box_layout_set_easing_mode().
2002  *
2003  * Enabling animations will override the easing state of each child
2004  * of the actor using @layout, and will use the #ClutterBoxLayout:easing-mode
2005  * and #ClutterBoxLayout:easing-duration properties instead.
2006  *
2007  * Since: 1.2
2008  *
2009  * Deprecated: 1.12: #ClutterBoxLayout will honour the
2010  *   #ClutterLayoutManager:use-animations property
2011  */
2012 void
2013 clutter_box_layout_set_use_animations (ClutterBoxLayout *layout,
2014                                        gboolean          animate)
2015 {
2016   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
2017
2018   clutter_layout_manager_set_use_animations (CLUTTER_LAYOUT_MANAGER (layout),
2019                                              animate);
2020 }
2021
2022 /**
2023  * clutter_box_layout_get_use_animations:
2024  * @layout: a #ClutterBoxLayout
2025  *
2026  * Retrieves whether @layout should animate changes in the layout properties.
2027  *
2028  * Return value: %TRUE if the animations should be used, %FALSE otherwise
2029  *
2030  * Since: 1.2
2031  *
2032  * Deprecated: 1.12: #ClutterBoxLayout will honour the
2033  *   #ClutterLayoutManager:use-animations property
2034  */
2035 gboolean
2036 clutter_box_layout_get_use_animations (ClutterBoxLayout *layout)
2037 {
2038   ClutterLayoutManager *manager;
2039
2040   g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), FALSE);
2041
2042   manager = CLUTTER_LAYOUT_MANAGER (layout);
2043
2044   return clutter_layout_manager_get_use_animations (manager);
2045 }
2046
2047 /**
2048  * clutter_box_layout_set_easing_mode:
2049  * @layout: a #ClutterBoxLayout
2050  * @mode: an easing mode, either from #ClutterAnimationMode or a logical id
2051  *   from clutter_alpha_register_func()
2052  *
2053  * Sets the easing mode to be used by @layout when animating changes in layout
2054  * properties.
2055  *
2056  * Since: 1.2
2057  *
2058  * Deprecated: 1.12: #ClutterBoxLayout will honour the
2059  *   #ClutterLayoutManager:easing-mode property
2060  */
2061 void
2062 clutter_box_layout_set_easing_mode (ClutterBoxLayout *layout,
2063                                     gulong            mode)
2064 {
2065   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
2066
2067   clutter_layout_manager_set_easing_mode (CLUTTER_LAYOUT_MANAGER (layout),
2068                                           mode);
2069 }
2070
2071 /**
2072  * clutter_box_layout_get_easing_mode:
2073  * @layout: a #ClutterBoxLayout
2074  *
2075  * Retrieves the easing mode set using clutter_box_layout_set_easing_mode()
2076  *
2077  * Return value: an easing mode
2078  *
2079  * Since: 1.2
2080  *
2081  * Deprecated: 1.12: #ClutterBoxLayout will honour the
2082  *   #ClutterLayoutManager:easing-mode property
2083  */
2084 gulong
2085 clutter_box_layout_get_easing_mode (ClutterBoxLayout *layout)
2086 {
2087   ClutterLayoutManager *manager;
2088
2089   g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout),
2090                         CLUTTER_EASE_OUT_CUBIC);
2091
2092   manager = CLUTTER_LAYOUT_MANAGER (layout);
2093
2094   return clutter_layout_manager_get_easing_mode (manager);
2095 }
2096
2097 /**
2098  * clutter_box_layout_set_easing_duration:
2099  * @layout: a #ClutterBoxLayout
2100  * @msecs: the duration of the animations, in milliseconds
2101  *
2102  * Sets the duration of the animations used by @layout when animating changes
2103  * in the layout properties.
2104  *
2105  * Since: 1.2
2106  *
2107  * Deprecated: 1.12: #ClutterBoxLayout will honour the
2108  *   #ClutterLayoutManager:easing-duration property
2109  */
2110 void
2111 clutter_box_layout_set_easing_duration (ClutterBoxLayout *layout,
2112                                         guint             msecs)
2113 {
2114   g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
2115
2116   clutter_layout_manager_set_easing_duration (CLUTTER_LAYOUT_MANAGER (layout),
2117                                               msecs);
2118 }
2119
2120 /**
2121  * clutter_box_layout_get_easing_duration:
2122  * @layout: a #ClutterBoxLayout
2123  *
2124  * Retrieves the duration set using clutter_box_layout_set_easing_duration()
2125  *
2126  * Return value: the duration of the animations, in milliseconds
2127  *
2128  * Since: 1.2
2129  *
2130  * Deprecated: 1.12: #ClutterBoxLayout will honour the
2131  *   #ClutterLayoutManager:easing-duration property
2132  */
2133 guint
2134 clutter_box_layout_get_easing_duration (ClutterBoxLayout *layout)
2135 {
2136   ClutterLayoutManager *manager;
2137
2138   g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), 500);
2139
2140   manager = CLUTTER_LAYOUT_MANAGER (layout);
2141
2142   return clutter_layout_manager_get_easing_duration (manager);
2143 }