4 * An OpenGL based 'interactive canvas' library.
6 * Copyright (C) 2009 Intel Corporation.
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.
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.
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/>.
22 * Emmanuele Bassi <ebassi@linux.intel.com>
26 * SECTION:clutter-bin-layout
27 * @short_description: A simple layout manager
29 * #ClutterBinLayout is a layout manager which implements the following
33 * <listitem><simpara>the preferred size is the maximum preferred size
34 * between all the children of the container using the
35 * layout;</simpara></listitem>
36 * <listitem><simpara>each child is allocated in "layers", on on top
37 * of the other;</simpara></listitem>
38 * <listitem><simpara>for each layer there are horizontal and vertical
39 * alignment policies.</simpara></listitem>
42 * <figure id="bin-layout">
43 * <title>Bin layout</title>
44 * <para>The image shows a #ClutterBinLayout with three layers:
45 * a background #ClutterCairoTexture, set to fill on both the X
46 * and Y axis; a #ClutterTexture, set to center on both the X and
47 * Y axis; and a #ClutterRectangle, set to %CLUTTER_BIN_ALIGNMENT_END
48 * on both the X and Y axis.</para>
49 * <graphic fileref="bin-layout.png" format="PNG"/>
52 * <example id="example-clutter-bin-layout">
53 * <title>How to pack actors inside a BinLayout</title>
55 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/bin-layout.c">
56 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
61 * #ClutterBinLayout is available since Clutter 1.2
70 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
71 #include "deprecated/clutter-container.h"
72 #include "deprecated/clutter-bin-layout.h"
74 #include "clutter-actor-private.h"
75 #include "clutter-animatable.h"
76 #include "clutter-child-meta.h"
77 #include "clutter-debug.h"
78 #include "clutter-enum-types.h"
79 #include "clutter-layout-meta.h"
80 #include "clutter-private.h"
82 #define CLUTTER_TYPE_BIN_LAYER (clutter_bin_layer_get_type ())
83 #define CLUTTER_BIN_LAYER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BIN_LAYER, ClutterBinLayer))
84 #define CLUTTER_IS_BIN_LAYER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BIN_LAYER))
86 #define CLUTTER_BIN_LAYOUT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_BIN_LAYOUT, ClutterBinLayoutPrivate))
88 typedef struct _ClutterBinLayer ClutterBinLayer;
89 typedef struct _ClutterLayoutMetaClass ClutterBinLayerClass;
91 struct _ClutterBinLayoutPrivate
93 ClutterBinAlignment x_align;
94 ClutterBinAlignment y_align;
96 ClutterContainer *container;
99 struct _ClutterBinLayer
101 ClutterLayoutMeta parent_instance;
103 ClutterBinAlignment x_align;
104 ClutterBinAlignment y_align;
127 static GParamSpec *layer_props[PROP_LAYER_LAST] = { NULL, };
128 static GParamSpec *bin_props[PROP_LAST] = { NULL, };
130 GType clutter_bin_layer_get_type (void);
132 G_DEFINE_TYPE (ClutterBinLayer,
134 CLUTTER_TYPE_LAYOUT_META);
136 G_DEFINE_TYPE (ClutterBinLayout,
138 CLUTTER_TYPE_LAYOUT_MANAGER);
145 set_layer_x_align (ClutterBinLayer *self,
146 ClutterBinAlignment alignment)
148 ClutterLayoutManager *manager;
149 ClutterLayoutMeta *meta;
151 if (self->x_align == alignment)
154 self->x_align = alignment;
156 meta = CLUTTER_LAYOUT_META (self);
157 manager = clutter_layout_meta_get_manager (meta);
158 clutter_layout_manager_layout_changed (manager);
160 g_object_notify_by_pspec (G_OBJECT (self), layer_props[PROP_LAYER_X_ALIGN]);
164 set_layer_y_align (ClutterBinLayer *self,
165 ClutterBinAlignment alignment)
167 ClutterLayoutManager *manager;
168 ClutterLayoutMeta *meta;
170 if (self->y_align == alignment)
173 self->y_align = alignment;
175 meta = CLUTTER_LAYOUT_META (self);
176 manager = clutter_layout_meta_get_manager (meta);
177 clutter_layout_manager_layout_changed (manager);
179 g_object_notify_by_pspec (G_OBJECT (self), layer_props[PROP_LAYER_Y_ALIGN]);
183 clutter_bin_layer_set_property (GObject *gobject,
188 ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject);
192 case PROP_LAYER_X_ALIGN:
193 set_layer_x_align (layer, g_value_get_enum (value));
196 case PROP_LAYER_Y_ALIGN:
197 set_layer_y_align (layer, g_value_get_enum (value));
201 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
207 clutter_bin_layer_get_property (GObject *gobject,
212 ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject);
216 case PROP_LAYER_X_ALIGN:
217 g_value_set_enum (value, layer->x_align);
220 case PROP_LAYER_Y_ALIGN:
221 g_value_set_enum (value, layer->y_align);
225 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
231 clutter_bin_layer_class_init (ClutterBinLayerClass *klass)
233 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
235 gobject_class->set_property = clutter_bin_layer_set_property;
236 gobject_class->get_property = clutter_bin_layer_get_property;
238 layer_props[PROP_LAYER_X_ALIGN] =
239 g_param_spec_enum ("x-align",
240 P_("Horizontal Alignment"),
241 P_("Horizontal alignment for the actor "
242 "inside the layout manager"),
243 CLUTTER_TYPE_BIN_ALIGNMENT,
244 CLUTTER_BIN_ALIGNMENT_CENTER,
245 CLUTTER_PARAM_READWRITE);
247 layer_props[PROP_LAYER_Y_ALIGN] =
248 g_param_spec_enum ("y-align",
249 P_("Vertical Alignment"),
250 P_("Vertical alignment for the actor "
251 "inside the layout manager"),
252 CLUTTER_TYPE_BIN_ALIGNMENT,
253 CLUTTER_BIN_ALIGNMENT_CENTER,
254 CLUTTER_PARAM_READWRITE);
256 g_object_class_install_properties (gobject_class,
262 clutter_bin_layer_init (ClutterBinLayer *layer)
264 layer->x_align = CLUTTER_BIN_ALIGNMENT_CENTER;
265 layer->y_align = CLUTTER_BIN_ALIGNMENT_CENTER;
273 set_x_align (ClutterBinLayout *self,
274 ClutterBinAlignment alignment)
276 ClutterBinLayoutPrivate *priv = self->priv;
278 if (priv->x_align != alignment)
280 ClutterLayoutManager *manager;
282 priv->x_align = alignment;
284 manager = CLUTTER_LAYOUT_MANAGER (self);
285 clutter_layout_manager_layout_changed (manager);
287 g_object_notify_by_pspec (G_OBJECT (self), bin_props[PROP_X_ALIGN]);
292 set_y_align (ClutterBinLayout *self,
293 ClutterBinAlignment alignment)
295 ClutterBinLayoutPrivate *priv = self->priv;
297 if (priv->y_align != alignment)
299 ClutterLayoutManager *manager;
301 priv->y_align = alignment;
303 manager = CLUTTER_LAYOUT_MANAGER (self);
304 clutter_layout_manager_layout_changed (manager);
306 g_object_notify_by_pspec (G_OBJECT (self), bin_props[PROP_Y_ALIGN]);
311 clutter_bin_layout_get_preferred_width (ClutterLayoutManager *manager,
312 ClutterContainer *container,
317 ClutterActor *actor = CLUTTER_ACTOR (container);
318 ClutterActorIter iter;
320 gfloat min_width, nat_width;
322 min_width = nat_width = 0.0;
324 clutter_actor_iter_init (&iter, actor);
325 while (clutter_actor_iter_next (&iter, &child))
327 gfloat minimum, natural;
329 if (!CLUTTER_ACTOR_IS_VISIBLE (child))
332 clutter_actor_get_preferred_width (child, for_height,
336 min_width = MAX (min_width, minimum);
337 nat_width = MAX (nat_width, natural);
341 *min_width_p = min_width;
344 *nat_width_p = nat_width;
348 clutter_bin_layout_get_preferred_height (ClutterLayoutManager *manager,
349 ClutterContainer *container,
351 gfloat *min_height_p,
352 gfloat *nat_height_p)
354 ClutterActor *actor = CLUTTER_ACTOR (container);
355 ClutterActorIter iter;
357 gfloat min_height, nat_height;
359 min_height = nat_height = 0.0;
361 clutter_actor_iter_init (&iter, actor);
362 while (clutter_actor_iter_next (&iter, &child))
364 gfloat minimum, natural;
366 if (!CLUTTER_ACTOR_IS_VISIBLE (child))
369 clutter_actor_get_preferred_height (child, for_width,
373 min_height = MAX (min_height, minimum);
374 nat_height = MAX (nat_height, natural);
378 *min_height_p = min_height;
381 *nat_height_p = nat_height;
385 get_bin_alignment_factor (ClutterBinAlignment alignment)
389 case CLUTTER_BIN_ALIGNMENT_CENTER:
392 case CLUTTER_BIN_ALIGNMENT_START:
395 case CLUTTER_BIN_ALIGNMENT_END:
398 case CLUTTER_BIN_ALIGNMENT_FIXED:
399 case CLUTTER_BIN_ALIGNMENT_FILL:
407 get_actor_align_factor (ClutterActorAlign alignment)
411 case CLUTTER_ACTOR_ALIGN_CENTER:
414 case CLUTTER_ACTOR_ALIGN_START:
417 case CLUTTER_ACTOR_ALIGN_END:
420 case CLUTTER_ACTOR_ALIGN_FILL:
428 clutter_bin_layout_allocate (ClutterLayoutManager *manager,
429 ClutterContainer *container,
430 const ClutterActorBox *allocation,
431 ClutterAllocationFlags flags)
433 gfloat allocation_x, allocation_y;
434 gfloat available_w, available_h;
435 ClutterActor *actor, *child;
436 ClutterActorIter iter;
437 gboolean use_animations;
438 ClutterAnimationMode easing_mode;
439 guint easing_duration, easing_delay;
441 clutter_actor_box_get_origin (allocation, &allocation_x, &allocation_y);
442 clutter_actor_box_get_size (allocation, &available_w, &available_h);
444 actor = CLUTTER_ACTOR (container);
446 use_animations = clutter_layout_manager_get_easing_state (manager,
450 clutter_actor_iter_init (&iter, actor);
451 while (clutter_actor_iter_next (&iter, &child))
453 ClutterLayoutMeta *meta;
454 ClutterBinLayer *layer;
455 ClutterActorBox child_alloc = { 0, };
456 gdouble x_align, y_align;
457 gboolean x_fill, y_fill;
459 meta = clutter_layout_manager_get_child_meta (manager,
462 layer = CLUTTER_BIN_LAYER (meta);
464 if (layer->x_align == CLUTTER_BIN_ALIGNMENT_FIXED)
465 child_alloc.x1 = clutter_actor_get_x (child);
467 child_alloc.x1 = allocation_x;
469 if (layer->y_align == CLUTTER_BIN_ALIGNMENT_FIXED)
470 child_alloc.y1 = clutter_actor_get_y (child);
472 child_alloc.y1 = allocation_y;
474 child_alloc.x2 = available_w;
475 child_alloc.y2 = available_h;
477 if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL))
479 ClutterActorAlign align;
481 align = _clutter_actor_get_effective_x_align (child);
482 x_fill = align == CLUTTER_ACTOR_ALIGN_FILL;
483 x_align = get_actor_align_factor (align);
487 x_fill = (layer->x_align == CLUTTER_BIN_ALIGNMENT_FILL);
488 x_align = get_bin_alignment_factor (layer->x_align);
491 if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL))
493 ClutterActorAlign align;
495 align = clutter_actor_get_y_align (child);
496 y_fill = align == CLUTTER_ACTOR_ALIGN_FILL;
497 y_align = get_actor_align_factor (align);
501 y_fill = (layer->y_align == CLUTTER_BIN_ALIGNMENT_FILL);
502 y_align = get_bin_alignment_factor (layer->y_align);
507 clutter_actor_save_easing_state (child);
508 clutter_actor_set_easing_mode (child, easing_mode);
509 clutter_actor_set_easing_duration (child, easing_duration);
510 clutter_actor_set_easing_delay (child, easing_delay);
513 clutter_actor_allocate_align_fill (child, &child_alloc,
519 clutter_actor_restore_easing_state (child);
524 clutter_bin_layout_get_child_meta_type (ClutterLayoutManager *manager)
526 return CLUTTER_TYPE_BIN_LAYER;
529 static ClutterLayoutMeta *
530 clutter_bin_layout_create_child_meta (ClutterLayoutManager *manager,
531 ClutterContainer *container,
534 ClutterBinLayoutPrivate *priv;
536 priv = CLUTTER_BIN_LAYOUT (manager)->priv;
538 return g_object_new (CLUTTER_TYPE_BIN_LAYER,
539 "container", container,
542 "x-align", priv->x_align,
543 "y_align", priv->y_align,
548 clutter_bin_layout_set_container (ClutterLayoutManager *manager,
549 ClutterContainer *container)
551 ClutterBinLayoutPrivate *priv;
552 ClutterLayoutManagerClass *parent_class;
554 priv = CLUTTER_BIN_LAYOUT (manager)->priv;
555 priv->container = container;
557 parent_class = CLUTTER_LAYOUT_MANAGER_CLASS (clutter_bin_layout_parent_class);
558 parent_class->set_container (manager, container);
562 clutter_bin_layout_set_property (GObject *gobject,
567 ClutterBinLayout *layout = CLUTTER_BIN_LAYOUT (gobject);
572 set_x_align (layout, g_value_get_enum (value));
576 set_y_align (layout, g_value_get_enum (value));
580 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
586 clutter_bin_layout_get_property (GObject *gobject,
591 ClutterBinLayoutPrivate *priv;
593 priv = CLUTTER_BIN_LAYOUT (gobject)->priv;
598 g_value_set_enum (value, priv->x_align);
602 g_value_set_enum (value, priv->y_align);
606 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
612 clutter_bin_layout_class_init (ClutterBinLayoutClass *klass)
614 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
615 ClutterLayoutManagerClass *layout_class =
616 CLUTTER_LAYOUT_MANAGER_CLASS (klass);
618 g_type_class_add_private (klass, sizeof (ClutterBinLayoutPrivate));
621 * ClutterBinLayout:x-align:
623 * The default horizontal alignment policy for actors managed
624 * by the #ClutterBinLayout
628 * Deprecated: 1.12: Use the #ClutterActor:x-expand and the
629 * #ClutterActor:x-align properties on #ClutterActor instead.
631 bin_props[PROP_X_ALIGN] =
632 g_param_spec_enum ("x-align",
633 P_("Horizontal Alignment"),
634 P_("Default horizontal alignment for the actors "
635 "inside the layout manager"),
636 CLUTTER_TYPE_BIN_ALIGNMENT,
637 CLUTTER_BIN_ALIGNMENT_CENTER,
638 CLUTTER_PARAM_READWRITE);
641 * ClutterBinLayout:y-align:
643 * The default vertical alignment policy for actors managed
644 * by the #ClutterBinLayout
648 * Deprecated: 1.12: Use the #ClutterActor:y-expand and the
649 * #ClutterActor:y-align properties on #ClutterActor instead.
651 bin_props[PROP_Y_ALIGN] =
652 g_param_spec_enum ("y-align",
653 P_("Vertical Alignment"),
654 P_("Default vertical alignment for the actors "
655 "inside the layout manager"),
656 CLUTTER_TYPE_BIN_ALIGNMENT,
657 CLUTTER_BIN_ALIGNMENT_CENTER,
658 CLUTTER_PARAM_READWRITE);
660 gobject_class->set_property = clutter_bin_layout_set_property;
661 gobject_class->get_property = clutter_bin_layout_get_property;
662 g_object_class_install_properties (gobject_class, PROP_LAST, bin_props);
664 layout_class->get_preferred_width = clutter_bin_layout_get_preferred_width;
665 layout_class->get_preferred_height = clutter_bin_layout_get_preferred_height;
666 layout_class->allocate = clutter_bin_layout_allocate;
667 layout_class->create_child_meta = clutter_bin_layout_create_child_meta;
668 layout_class->get_child_meta_type = clutter_bin_layout_get_child_meta_type;
669 layout_class->set_container = clutter_bin_layout_set_container;
673 clutter_bin_layout_init (ClutterBinLayout *self)
675 self->priv = CLUTTER_BIN_LAYOUT_GET_PRIVATE (self);
677 self->priv->x_align = CLUTTER_BIN_ALIGNMENT_CENTER;
678 self->priv->y_align = CLUTTER_BIN_ALIGNMENT_CENTER;
682 * clutter_bin_layout_new:
683 * @x_align: the default alignment policy to be used on the
685 * @y_align: the default alignment policy to be used on the
688 * Creates a new #ClutterBinLayout layout manager
690 * Return value: the newly created layout manager
694 ClutterLayoutManager *
695 clutter_bin_layout_new (ClutterBinAlignment x_align,
696 ClutterBinAlignment y_align)
698 return g_object_new (CLUTTER_TYPE_BIN_LAYOUT,
705 * clutter_bin_layout_set_alignment:
706 * @self: a #ClutterBinLayout
707 * @child: (allow-none): a child of @container
708 * @x_align: the horizontal alignment policy to be used for the @child
710 * @y_align: the vertical aligment policy to be used on the @child
713 * Sets the horizontal and vertical alignment policies to be applied
714 * to a @child of @self
716 * If @child is %NULL then the @x_align and @y_align values will
717 * be set as the default alignment policies
721 * Deprecated: 1.12: Use the #ClutterActor:x-align and
722 * #ClutterActor:y-align properties of #ClutterActor instead.
725 clutter_bin_layout_set_alignment (ClutterBinLayout *self,
727 ClutterBinAlignment x_align,
728 ClutterBinAlignment y_align)
730 ClutterBinLayoutPrivate *priv;
731 ClutterLayoutManager *manager;
732 ClutterLayoutMeta *meta;
734 g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
735 g_return_if_fail (child == NULL || CLUTTER_IS_ACTOR (child));
739 if (priv->container == NULL)
743 set_x_align (self, x_align);
744 set_y_align (self, y_align);
747 g_warning ("The layout of type '%s' must be associated to "
748 "a ClutterContainer before setting the alignment "
750 G_OBJECT_TYPE_NAME (self));
755 manager = CLUTTER_LAYOUT_MANAGER (self);
756 meta = clutter_layout_manager_get_child_meta (manager,
759 g_assert (CLUTTER_IS_BIN_LAYER (meta));
761 set_layer_x_align (CLUTTER_BIN_LAYER (meta), x_align);
762 set_layer_y_align (CLUTTER_BIN_LAYER (meta), y_align);
766 * clutter_bin_layout_get_alignment:
767 * @self: a #ClutterBinLayout
768 * @child: (allow-none): a child of @container
769 * @x_align: (out) (allow-none): return location for the horizontal
771 * @y_align: (out) (allow-none): return location for the vertical
774 * Retrieves the horizontal and vertical alignment policies for
777 * If @child is %NULL the default alignment policies will be returned
782 * Deprecated: 1.12: Use the #ClutterActor:x-align and the
783 * #ClutterActor:y-align properties of #ClutterActor instead.
786 clutter_bin_layout_get_alignment (ClutterBinLayout *self,
788 ClutterBinAlignment *x_align,
789 ClutterBinAlignment *y_align)
791 ClutterBinLayoutPrivate *priv;
792 ClutterLayoutManager *manager;
793 ClutterLayoutMeta *meta;
794 ClutterBinLayer *layer;
796 g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
800 if (priv->container == NULL)
805 *x_align = priv->x_align;
808 *y_align = priv->y_align;
811 g_warning ("The layout of type '%s' must be associated to "
812 "a ClutterContainer before getting the alignment "
814 G_OBJECT_TYPE_NAME (self));
819 manager = CLUTTER_LAYOUT_MANAGER (self);
820 meta = clutter_layout_manager_get_child_meta (manager,
823 g_assert (CLUTTER_IS_BIN_LAYER (meta));
825 layer = CLUTTER_BIN_LAYER (meta);
828 *x_align = layer->x_align;
831 *y_align = layer->y_align;
835 * clutter_bin_layout_add:
836 * @self: a #ClutterBinLayout
837 * @child: a #ClutterActor
838 * @x_align: horizontal alignment policy for @child
839 * @y_align: vertical alignment policy for @child
841 * Adds a #ClutterActor to the container using @self and
842 * sets the alignment policies for it
844 * This function is equivalent to clutter_container_add_actor()
845 * and clutter_layout_manager_child_set_property() but it does not
846 * require a pointer to the #ClutterContainer associated to the
851 * Deprecated: 1.12: Use clutter_actor_add_child() instead.
854 clutter_bin_layout_add (ClutterBinLayout *self,
856 ClutterBinAlignment x_align,
857 ClutterBinAlignment y_align)
859 ClutterBinLayoutPrivate *priv;
860 ClutterLayoutManager *manager;
861 ClutterLayoutMeta *meta;
863 g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
864 g_return_if_fail (CLUTTER_IS_ACTOR (child));
868 if (priv->container == NULL)
870 g_warning ("The layout of type '%s' must be associated to "
871 "a ClutterContainer before adding children",
872 G_OBJECT_TYPE_NAME (self));
876 clutter_container_add_actor (priv->container, child);
878 manager = CLUTTER_LAYOUT_MANAGER (self);
879 meta = clutter_layout_manager_get_child_meta (manager,
882 g_assert (CLUTTER_IS_BIN_LAYER (meta));
884 set_layer_x_align (CLUTTER_BIN_LAYER (meta), x_align);
885 set_layer_y_align (CLUTTER_BIN_LAYER (meta), y_align);