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-flow-layout
27 * @short_description: A reflowing layout manager
29 * #ClutterFlowLayout is a layout manager which implements the following
33 * <listitem><para>the preferred natural size depends on the value
34 * of the #ClutterFlowLayout:orientation property; the layout will try
35 * to maintain all its children on a single row or
36 * column;</para></listitem>
37 * <listitem><para>if either the width or the height allocated are
38 * smaller than the preferred ones, the layout will wrap; in this case,
39 * the preferred height or width, respectively, will take into account
40 * the amount of columns and rows;</para></listitem>
41 * <listitem><para>each line (either column or row) in reflowing will
42 * have the size of the biggest cell on that line; if the
43 * #ClutterFlowLayout:homogeneous property is set to %FALSE the actor
44 * will be allocated within that area, and if set to %TRUE instead the
45 * actor will be given exactly that area;</para></listitem>
46 * <listitem><para>the size of the columns or rows can be controlled
47 * for both minimum and maximum; the spacing can also be controlled
48 * in both columns and rows.</para></listitem>
51 * <figure id="flow-layout-image">
52 * <title>Horizontal flow layout</title>
53 * <para>The image shows a #ClutterFlowLayout with the
54 * #ClutterFlowLayout:orientation propert set to
55 * %CLUTTER_FLOW_HORIZONTAL.</para>
56 * <graphic fileref="flow-layout.png" format="PNG"/>
61 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/flow-layout.c">
62 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
67 * #ClutterFlowLayout is available since Clutter 1.2
76 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
77 #include "deprecated/clutter-container.h"
79 #include "clutter-actor.h"
80 #include "clutter-animatable.h"
81 #include "clutter-child-meta.h"
82 #include "clutter-debug.h"
83 #include "clutter-enum-types.h"
84 #include "clutter-flow-layout.h"
85 #include "clutter-layout-meta.h"
86 #include "clutter-private.h"
88 #define CLUTTER_FLOW_LAYOUT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_FLOW_LAYOUT, ClutterFlowLayoutPrivate))
90 struct _ClutterFlowLayoutPrivate
92 ClutterContainer *container;
94 ClutterFlowOrientation orientation;
100 gfloat max_col_width;
103 gfloat min_row_height;
104 gfloat max_row_height;
109 GArray *line_natural;
115 guint is_homogeneous : 1;
129 PROP_MIN_COLUMN_WIDTH,
130 PROP_MAX_COLUMN_WIDTH,
137 static GParamSpec *flow_properties[N_PROPERTIES] = { NULL, };
139 G_DEFINE_TYPE (ClutterFlowLayout,
141 CLUTTER_TYPE_LAYOUT_MANAGER);
144 get_columns (ClutterFlowLayout *self,
147 ClutterFlowLayoutPrivate *priv = self->priv;
153 if (priv->col_width == 0)
156 n_columns = (gint) (for_width + priv->col_spacing)
157 / (priv->col_width + priv->col_spacing);
166 get_rows (ClutterFlowLayout *self,
169 ClutterFlowLayoutPrivate *priv = self->priv;
175 if (priv->row_height == 0)
178 n_rows = (gint) (for_height + priv->row_spacing)
179 / (priv->row_height + priv->row_spacing);
188 compute_lines (ClutterFlowLayout *self,
192 ClutterFlowLayoutPrivate *priv = self->priv;
194 if (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
195 return get_columns (self, avail_width);
197 return get_rows (self, avail_height);
201 clutter_flow_layout_get_preferred_width (ClutterLayoutManager *manager,
202 ClutterContainer *container,
207 ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv;
208 gint n_rows, line_item_count, line_count;
209 gfloat total_min_width, total_natural_width;
210 gfloat line_min_width, line_natural_width;
211 gfloat max_min_width, max_natural_width;
212 ClutterActor *actor, *child;
213 ClutterActorIter iter;
216 n_rows = get_rows (CLUTTER_FLOW_LAYOUT (manager), for_height);
219 total_natural_width = 0;
222 line_natural_width = 0;
229 actor = CLUTTER_ACTOR (container);
231 /* clear the line width arrays */
232 if (priv->line_min != NULL)
233 g_array_free (priv->line_min, TRUE);
235 if (priv->line_natural != NULL)
236 g_array_free (priv->line_natural, TRUE);
238 priv->line_min = g_array_sized_new (FALSE, FALSE,
241 priv->line_natural = g_array_sized_new (FALSE, FALSE,
245 if (clutter_actor_get_n_children (actor) != 0)
248 max_min_width = max_natural_width = 0;
250 clutter_actor_iter_init (&iter, actor);
251 while (clutter_actor_iter_next (&iter, &child))
253 gfloat child_min, child_natural;
254 gfloat new_y, item_height;
256 if (!CLUTTER_ACTOR_IS_VISIBLE (child))
259 if (priv->orientation == CLUTTER_FLOW_VERTICAL && for_height > 0)
261 if (line_item_count == n_rows)
263 total_min_width += line_min_width;
264 total_natural_width += line_natural_width;
266 g_array_append_val (priv->line_min,
268 g_array_append_val (priv->line_natural,
271 line_min_width = line_natural_width = 0;
278 new_y = ((line_item_count + 1) * (for_height + priv->row_spacing))
280 item_height = new_y - item_y - priv->row_spacing;
282 clutter_actor_get_preferred_width (child, item_height,
286 line_min_width = MAX (line_min_width, child_min);
287 line_natural_width = MAX (line_natural_width, child_natural);
290 line_item_count += 1;
292 max_min_width = MAX (max_min_width, line_min_width);
293 max_natural_width = MAX (max_natural_width, line_natural_width);
297 clutter_actor_get_preferred_width (child, for_height,
301 max_min_width = MAX (max_min_width, child_min);
302 max_natural_width = MAX (max_natural_width, child_natural);
304 total_min_width += max_min_width;
305 total_natural_width += max_natural_width;
310 priv->col_width = max_natural_width;
312 if (priv->max_col_width > 0 && priv->col_width > priv->max_col_width)
313 priv->col_width = MAX (priv->max_col_width, max_min_width);
315 if (priv->col_width < priv->min_col_width)
316 priv->col_width = priv->min_col_width;
318 if (priv->orientation == CLUTTER_FLOW_VERTICAL && for_height > 0)
320 /* if we have a non-full row we need to add it */
321 if (line_item_count > 0)
323 total_min_width += line_min_width;
324 total_natural_width += line_natural_width;
326 g_array_append_val (priv->line_min,
328 g_array_append_val (priv->line_natural,
332 priv->line_count = line_count;
334 if (priv->line_count > 0)
336 gfloat total_spacing;
338 total_spacing = priv->col_spacing * (priv->line_count - 1);
340 total_min_width += total_spacing;
341 total_natural_width += total_spacing;
346 g_array_append_val (priv->line_min, line_min_width);
347 g_array_append_val (priv->line_natural, line_natural_width);
349 priv->line_count = line_count;
351 if (priv->line_count > 0)
353 gfloat total_spacing;
355 total_spacing = priv->col_spacing * (priv->line_count - 1);
357 total_min_width += total_spacing;
358 total_natural_width += total_spacing;
362 CLUTTER_NOTE (LAYOUT,
363 "Flow[w]: %d lines (%d per line): w [ %.2f, %.2f ] for h %.2f",
364 n_rows, priv->line_count,
369 priv->req_height = for_height;
372 *min_width_p = max_min_width;
375 *nat_width_p = total_natural_width;
379 clutter_flow_layout_get_preferred_height (ClutterLayoutManager *manager,
380 ClutterContainer *container,
382 gfloat *min_height_p,
383 gfloat *nat_height_p)
385 ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv;
386 gint n_columns, line_item_count, line_count;
387 gfloat total_min_height, total_natural_height;
388 gfloat line_min_height, line_natural_height;
389 gfloat max_min_height, max_natural_height;
390 ClutterActor *actor, *child;
391 ClutterActorIter iter;
394 n_columns = get_columns (CLUTTER_FLOW_LAYOUT (manager), for_width);
396 total_min_height = 0;
397 total_natural_height = 0;
400 line_natural_height = 0;
407 actor = CLUTTER_ACTOR (container);
409 /* clear the line height arrays */
410 if (priv->line_min != NULL)
411 g_array_free (priv->line_min, TRUE);
413 if (priv->line_natural != NULL)
414 g_array_free (priv->line_natural, TRUE);
416 priv->line_min = g_array_sized_new (FALSE, FALSE,
419 priv->line_natural = g_array_sized_new (FALSE, FALSE,
423 if (clutter_actor_get_n_children (actor) != 0)
426 max_min_height = max_natural_height = 0;
428 clutter_actor_iter_init (&iter, actor);
429 while (clutter_actor_iter_next (&iter, &child))
431 gfloat child_min, child_natural;
432 gfloat new_x, item_width;
434 if (!CLUTTER_ACTOR_IS_VISIBLE (child))
437 if (priv->orientation == CLUTTER_FLOW_HORIZONTAL && for_width > 0)
439 if (line_item_count == n_columns)
441 total_min_height += line_min_height;
442 total_natural_height += line_natural_height;
444 g_array_append_val (priv->line_min,
446 g_array_append_val (priv->line_natural,
447 line_natural_height);
449 line_min_height = line_natural_height = 0;
456 new_x = ((line_item_count + 1) * (for_width + priv->col_spacing))
458 item_width = new_x - item_x - priv->col_spacing;
460 clutter_actor_get_preferred_height (child, item_width,
464 line_min_height = MAX (line_min_height, child_min);
465 line_natural_height = MAX (line_natural_height, child_natural);
468 line_item_count += 1;
470 max_min_height = MAX (max_min_height, line_min_height);
471 max_natural_height = MAX (max_natural_height, line_natural_height);
475 clutter_actor_get_preferred_height (child, for_width,
479 max_min_height = MAX (max_min_height, child_min);
480 max_natural_height = MAX (max_natural_height, child_natural);
482 total_min_height += max_min_height;
483 total_natural_height += max_natural_height;
489 priv->row_height = max_natural_height;
491 if (priv->max_row_height > 0 && priv->row_height > priv->max_row_height)
492 priv->row_height = MAX (priv->max_row_height, max_min_height);
494 if (priv->row_height < priv->min_row_height)
495 priv->row_height = priv->min_row_height;
497 if (priv->orientation == CLUTTER_FLOW_HORIZONTAL && for_width > 0)
499 /* if we have a non-full row we need to add it */
500 if (line_item_count > 0)
502 total_min_height += line_min_height;
503 total_natural_height += line_natural_height;
505 g_array_append_val (priv->line_min,
507 g_array_append_val (priv->line_natural,
508 line_natural_height);
511 priv->line_count = line_count;
512 if (priv->line_count > 0)
514 gfloat total_spacing;
516 total_spacing = priv->row_spacing * (priv->line_count - 1);
518 total_min_height += total_spacing;
519 total_natural_height += total_spacing;
524 g_array_append_val (priv->line_min, line_min_height);
525 g_array_append_val (priv->line_natural, line_natural_height);
527 priv->line_count = line_count;
529 if (priv->line_count > 0)
531 gfloat total_spacing;
533 total_spacing = priv->col_spacing * priv->line_count;
535 total_min_height += total_spacing;
536 total_natural_height += total_spacing;
540 CLUTTER_NOTE (LAYOUT,
541 "Flow[h]: %d lines (%d per line): w [ %.2f, %.2f ] for h %.2f",
542 n_columns, priv->line_count,
544 total_natural_height,
547 priv->req_width = for_width;
550 *min_height_p = max_min_height;
553 *nat_height_p = total_natural_height;
557 clutter_flow_layout_allocate (ClutterLayoutManager *manager,
558 ClutterContainer *container,
559 const ClutterActorBox *allocation,
560 ClutterAllocationFlags flags)
562 ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv;
563 ClutterActor *actor, *child;
564 ClutterActorIter iter;
566 gfloat avail_width, avail_height;
567 gfloat item_x, item_y;
568 gint line_item_count;
571 gboolean use_animations;
572 ClutterAnimationMode easing_mode;
573 guint easing_duration, easing_delay;
575 actor = CLUTTER_ACTOR (container);
576 if (clutter_actor_get_n_children (actor) == 0)
579 clutter_actor_box_get_origin (allocation, &x_off, &y_off);
580 clutter_actor_box_get_size (allocation, &avail_width, &avail_height);
582 /* blow the cached preferred size and re-compute with the given
583 * available size in case the FlowLayout wasn't given the exact
586 if ((priv->req_width >= 0 && avail_width != priv->req_width) ||
587 (priv->req_height >= 0 && avail_height != priv->req_height))
589 clutter_flow_layout_get_preferred_width (manager, container,
592 clutter_flow_layout_get_preferred_height (manager, container,
597 items_per_line = compute_lines (CLUTTER_FLOW_LAYOUT (manager),
598 avail_width, avail_height);
606 use_animations = clutter_layout_manager_get_easing_state (manager,
611 clutter_actor_iter_init (&iter, actor);
612 while (clutter_actor_iter_next (&iter, &child))
614 ClutterActorBox child_alloc;
615 gfloat item_width, item_height;
618 if (!CLUTTER_ACTOR_IS_VISIBLE (child))
623 if (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
625 if (line_item_count == items_per_line && line_item_count > 0)
627 item_y += g_array_index (priv->line_natural,
632 item_y += priv->row_spacing;
640 new_x = x_off + ((line_item_count + 1) * (avail_width + priv->col_spacing))
642 item_width = new_x - item_x - priv->col_spacing;
643 item_height = g_array_index (priv->line_natural,
647 if (!priv->is_homogeneous)
649 gfloat child_min, child_natural;
651 clutter_actor_get_preferred_width (child, item_height,
654 item_width = MIN (item_width, child_natural);
656 clutter_actor_get_preferred_height (child, item_width,
659 item_height = MIN (item_height, child_natural);
664 if (line_item_count == items_per_line && line_item_count > 0)
666 item_x += g_array_index (priv->line_natural,
671 item_x += priv->col_spacing;
679 new_y = y_off + ((line_item_count + 1) * (avail_height + priv->row_spacing))
681 item_height = new_y - item_y - priv->row_spacing;
682 item_width = g_array_index (priv->line_natural,
686 if (!priv->is_homogeneous)
688 gfloat child_min, child_natural;
690 clutter_actor_get_preferred_width (child, item_height,
693 item_width = MIN (item_width, child_natural);
695 clutter_actor_get_preferred_height (child, item_width,
698 item_height = MIN (item_height, child_natural);
702 CLUTTER_NOTE (LAYOUT,
703 "flow[line:%d, item:%d/%d] ="
704 "{ %.2f, %.2f, %.2f, %.2f }",
705 line_index, line_item_count + 1, items_per_line,
706 item_x, item_y, item_width, item_height);
708 child_alloc.x1 = ceil (item_x);
709 child_alloc.y1 = ceil (item_y);
710 child_alloc.x2 = ceil (child_alloc.x1 + item_width);
711 child_alloc.y2 = ceil (child_alloc.y1 + item_height);
715 clutter_actor_save_easing_state (child);
716 clutter_actor_set_easing_mode (child, easing_mode);
717 clutter_actor_set_easing_duration (child, easing_duration);
718 clutter_actor_set_easing_delay (child, easing_delay);
721 clutter_actor_allocate (child, &child_alloc, flags);
724 clutter_actor_restore_easing_state (child);
726 if (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
731 line_item_count += 1;
736 clutter_flow_layout_set_container (ClutterLayoutManager *manager,
737 ClutterContainer *container)
739 ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv;
740 ClutterLayoutManagerClass *parent_class;
742 priv->container = container;
744 if (priv->container != NULL)
746 ClutterRequestMode request_mode;
748 /* we need to change the :request-mode of the container
749 * to match the orientation
751 request_mode = (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
752 ? CLUTTER_REQUEST_HEIGHT_FOR_WIDTH
753 : CLUTTER_REQUEST_WIDTH_FOR_HEIGHT;
754 clutter_actor_set_request_mode (CLUTTER_ACTOR (priv->container),
758 parent_class = CLUTTER_LAYOUT_MANAGER_CLASS (clutter_flow_layout_parent_class);
759 parent_class->set_container (manager, container);
763 clutter_flow_layout_set_property (GObject *gobject,
768 ClutterFlowLayout *self = CLUTTER_FLOW_LAYOUT (gobject);
772 case PROP_ORIENTATION:
773 clutter_flow_layout_set_orientation (self, g_value_get_enum (value));
776 case PROP_HOMOGENEOUS:
777 clutter_flow_layout_set_homogeneous (self, g_value_get_boolean (value));
780 case PROP_COLUMN_SPACING:
781 clutter_flow_layout_set_column_spacing (self, g_value_get_float (value));
784 case PROP_ROW_SPACING:
785 clutter_flow_layout_set_row_spacing (self, g_value_get_float (value));
788 case PROP_MIN_COLUMN_WIDTH:
789 clutter_flow_layout_set_column_width (self,
790 g_value_get_float (value),
791 self->priv->max_col_width);
794 case PROP_MAX_COLUMN_WIDTH:
795 clutter_flow_layout_set_column_width (self,
796 self->priv->min_col_width,
797 g_value_get_float (value));
800 case PROP_MIN_ROW_HEGHT:
801 clutter_flow_layout_set_row_height (self,
802 g_value_get_float (value),
803 self->priv->max_row_height);
806 case PROP_MAX_ROW_HEIGHT:
807 clutter_flow_layout_set_row_height (self,
808 self->priv->min_row_height,
809 g_value_get_float (value));
813 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
819 clutter_flow_layout_get_property (GObject *gobject,
824 ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (gobject)->priv;
828 case PROP_ORIENTATION:
829 g_value_set_enum (value, priv->orientation);
832 case PROP_HOMOGENEOUS:
833 g_value_set_boolean (value, priv->is_homogeneous);
836 case PROP_COLUMN_SPACING:
837 g_value_set_float (value, priv->col_spacing);
840 case PROP_ROW_SPACING:
841 g_value_set_float (value, priv->row_spacing);
844 case PROP_MIN_COLUMN_WIDTH:
845 g_value_set_float (value, priv->min_col_width);
848 case PROP_MAX_COLUMN_WIDTH:
849 g_value_set_float (value, priv->max_col_width);
852 case PROP_MIN_ROW_HEGHT:
853 g_value_set_float (value, priv->min_row_height);
856 case PROP_MAX_ROW_HEIGHT:
857 g_value_set_float (value, priv->max_row_height);
861 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
867 clutter_flow_layout_finalize (GObject *gobject)
869 ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (gobject)->priv;
871 if (priv->line_min != NULL)
872 g_array_free (priv->line_min, TRUE);
874 if (priv->line_natural != NULL)
875 g_array_free (priv->line_natural, TRUE);
877 G_OBJECT_CLASS (clutter_flow_layout_parent_class)->finalize (gobject);
881 clutter_flow_layout_class_init (ClutterFlowLayoutClass *klass)
883 GObjectClass *gobject_class;
884 ClutterLayoutManagerClass *layout_class;
886 g_type_class_add_private (klass, sizeof (ClutterFlowLayoutPrivate));
888 gobject_class = G_OBJECT_CLASS (klass);
889 layout_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass);
891 layout_class->get_preferred_width =
892 clutter_flow_layout_get_preferred_width;
893 layout_class->get_preferred_height =
894 clutter_flow_layout_get_preferred_height;
895 layout_class->allocate = clutter_flow_layout_allocate;
896 layout_class->set_container = clutter_flow_layout_set_container;
899 * ClutterFlowLayout:orientation:
901 * The orientation of the #ClutterFlowLayout. The children
902 * of the layout will be layed out following the orientation.
904 * This property also controls the overflowing directions
908 flow_properties[PROP_ORIENTATION] =
909 g_param_spec_enum ("orientation",
911 P_("The orientation of the layout"),
912 CLUTTER_TYPE_FLOW_ORIENTATION,
913 CLUTTER_FLOW_HORIZONTAL,
914 CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT);
917 * ClutterFlowLayout:homogeneous:
919 * Whether each child inside the #ClutterFlowLayout should receive
920 * the same allocation
924 flow_properties[PROP_HOMOGENEOUS] =
925 g_param_spec_boolean ("homogeneous",
927 P_("Whether each item should receive the same allocation"),
929 CLUTTER_PARAM_READWRITE);
932 * ClutterFlowLayout:column-spacing:
934 * The spacing between columns, in pixels; the value of this
935 * property is honoured by horizontal non-overflowing layouts
936 * and by vertical overflowing layouts
940 flow_properties[PROP_COLUMN_SPACING] =
941 g_param_spec_float ("column-spacing",
942 P_("Column Spacing"),
943 P_("The spacing between columns"),
946 CLUTTER_PARAM_READWRITE);
949 * ClutterFlowLayout:row-spacing:
951 * The spacing between rows, in pixels; the value of this
952 * property is honoured by vertical non-overflowing layouts and
953 * by horizontal overflowing layouts
957 flow_properties[PROP_ROW_SPACING] =
958 g_param_spec_float ("row-spacing",
960 P_("The spacing between rows"),
963 CLUTTER_PARAM_READWRITE);
966 * ClutterFlowLayout:min-column-width:
968 * Minimum width for each column in the layout, in pixels
972 flow_properties[PROP_MIN_COLUMN_WIDTH] =
973 g_param_spec_float ("min-column-width",
974 P_("Minimum Column Width"),
975 P_("Minimum width for each column"),
978 CLUTTER_PARAM_READWRITE);
981 * ClutterFlowLayout:max-column-width:
983 * Maximum width for each column in the layout, in pixels. If
984 * set to -1 the width will be the maximum child width
988 flow_properties[PROP_MAX_COLUMN_WIDTH] =
989 g_param_spec_float ("max-column-width",
990 P_("Maximum Column Width"),
991 P_("Maximum width for each column"),
994 CLUTTER_PARAM_READWRITE);
997 * ClutterFlowLayout:min-row-height:
999 * Minimum height for each row in the layout, in pixels
1003 flow_properties[PROP_MIN_ROW_HEGHT] =
1004 g_param_spec_float ("min-row-height",
1005 P_("Minimum Row Height"),
1006 P_("Minimum height for each row"),
1009 CLUTTER_PARAM_READWRITE);
1012 * ClutterFlowLayout:max-row-height:
1014 * Maximum height for each row in the layout, in pixels. If
1015 * set to -1 the width will be the maximum child height
1019 flow_properties[PROP_MAX_ROW_HEIGHT] =
1020 g_param_spec_float ("max-row-height",
1021 P_("Maximum Row Height"),
1022 P_("Maximum height for each row"),
1025 CLUTTER_PARAM_READWRITE);
1027 gobject_class->finalize = clutter_flow_layout_finalize;
1028 gobject_class->set_property = clutter_flow_layout_set_property;
1029 gobject_class->get_property = clutter_flow_layout_get_property;
1030 g_object_class_install_properties (gobject_class,
1036 clutter_flow_layout_init (ClutterFlowLayout *self)
1038 ClutterFlowLayoutPrivate *priv;
1040 self->priv = priv = CLUTTER_FLOW_LAYOUT_GET_PRIVATE (self);
1042 priv->orientation = CLUTTER_FLOW_HORIZONTAL;
1044 priv->col_spacing = 0;
1045 priv->row_spacing = 0;
1047 priv->min_col_width = priv->min_row_height = 0;
1048 priv->max_col_width = priv->max_row_height = -1;
1050 priv->line_min = NULL;
1051 priv->line_natural = NULL;
1055 * clutter_flow_layout_new:
1056 * @orientation: the orientation of the flow layout
1058 * Creates a new #ClutterFlowLayout with the given @orientation
1060 * Return value: the newly created #ClutterFlowLayout
1064 ClutterLayoutManager *
1065 clutter_flow_layout_new (ClutterFlowOrientation orientation)
1067 return g_object_new (CLUTTER_TYPE_FLOW_LAYOUT,
1068 "orientation", orientation,
1073 * clutter_flow_layout_set_orientation:
1074 * @layout: a #ClutterFlowLayout
1075 * @orientation: the orientation of the layout
1077 * Sets the orientation of the flow layout
1079 * The orientation controls the direction used to allocate
1080 * the children: either horizontally or vertically. The
1081 * orientation also controls the direction of the overflowing
1086 clutter_flow_layout_set_orientation (ClutterFlowLayout *layout,
1087 ClutterFlowOrientation orientation)
1089 ClutterFlowLayoutPrivate *priv;
1091 g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
1093 priv = layout->priv;
1095 if (priv->orientation != orientation)
1097 ClutterLayoutManager *manager;
1099 priv->orientation = orientation;
1101 if (priv->container != NULL)
1103 ClutterRequestMode request_mode;
1105 /* we need to change the :request-mode of the container
1106 * to match the orientation
1108 request_mode = (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
1109 ? CLUTTER_REQUEST_HEIGHT_FOR_WIDTH
1110 : CLUTTER_REQUEST_WIDTH_FOR_HEIGHT;
1111 clutter_actor_set_request_mode (CLUTTER_ACTOR (priv->container),
1115 manager = CLUTTER_LAYOUT_MANAGER (layout);
1116 clutter_layout_manager_layout_changed (manager);
1118 g_object_notify_by_pspec (G_OBJECT (layout),
1119 flow_properties[PROP_ORIENTATION]);
1124 * clutter_flow_layout_get_orientation:
1125 * @layout: a #ClutterFlowLayout
1127 * Retrieves the orientation of the @layout
1129 * Return value: the orientation of the #ClutterFlowLayout
1133 ClutterFlowOrientation
1134 clutter_flow_layout_get_orientation (ClutterFlowLayout *layout)
1136 g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout),
1137 CLUTTER_FLOW_HORIZONTAL);
1139 return layout->priv->orientation;
1143 * clutter_flow_layout_set_homogeneous:
1144 * @layout: a #ClutterFlowLayout
1145 * @homogeneous: whether the layout should be homogeneous or not
1147 * Sets whether the @layout should allocate the same space for
1153 clutter_flow_layout_set_homogeneous (ClutterFlowLayout *layout,
1154 gboolean homogeneous)
1156 ClutterFlowLayoutPrivate *priv;
1158 g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
1160 priv = layout->priv;
1162 if (priv->is_homogeneous != homogeneous)
1164 ClutterLayoutManager *manager;
1166 priv->is_homogeneous = homogeneous;
1168 manager = CLUTTER_LAYOUT_MANAGER (layout);
1169 clutter_layout_manager_layout_changed (manager);
1171 g_object_notify_by_pspec (G_OBJECT (layout),
1172 flow_properties[PROP_HOMOGENEOUS]);
1177 * clutter_flow_layout_get_homogeneous:
1178 * @layout: a #ClutterFlowLayout
1180 * Retrieves whether the @layout is homogeneous
1182 * Return value: %TRUE if the #ClutterFlowLayout is homogeneous
1187 clutter_flow_layout_get_homogeneous (ClutterFlowLayout *layout)
1189 g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), FALSE);
1191 return layout->priv->is_homogeneous;
1195 * clutter_flow_layout_set_column_spacing:
1196 * @layout: a #ClutterFlowLayout
1197 * @spacing: the space between columns
1199 * Sets the space between columns, in pixels
1204 clutter_flow_layout_set_column_spacing (ClutterFlowLayout *layout,
1207 ClutterFlowLayoutPrivate *priv;
1209 g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
1211 priv = layout->priv;
1213 if (priv->col_spacing != spacing)
1215 ClutterLayoutManager *manager;
1217 priv->col_spacing = spacing;
1219 manager = CLUTTER_LAYOUT_MANAGER (layout);
1220 clutter_layout_manager_layout_changed (manager);
1222 g_object_notify_by_pspec (G_OBJECT (layout),
1223 flow_properties[PROP_COLUMN_SPACING]);
1228 * clutter_flow_layout_get_column_spacing:
1229 * @layout: a #ClutterFlowLayout
1231 * Retrieves the spacing between columns
1233 * Return value: the spacing between columns of the #ClutterFlowLayout,
1239 clutter_flow_layout_get_column_spacing (ClutterFlowLayout *layout)
1241 g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), 0.0);
1243 return layout->priv->col_spacing;
1247 * clutter_flow_layout_set_row_spacing:
1248 * @layout: a #ClutterFlowLayout
1249 * @spacing: the space between rows
1251 * Sets the spacing between rows, in pixels
1256 clutter_flow_layout_set_row_spacing (ClutterFlowLayout *layout,
1259 ClutterFlowLayoutPrivate *priv;
1261 g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
1263 priv = layout->priv;
1265 if (priv->row_spacing != spacing)
1267 ClutterLayoutManager *manager;
1269 priv->row_spacing = spacing;
1271 manager = CLUTTER_LAYOUT_MANAGER (layout);
1272 clutter_layout_manager_layout_changed (manager);
1274 g_object_notify_by_pspec (G_OBJECT (layout),
1275 flow_properties[PROP_ROW_SPACING]);
1280 * clutter_flow_layout_get_row_spacing:
1281 * @layout: a #ClutterFlowLayout
1283 * Retrieves the spacing between rows
1285 * Return value: the spacing between rows of the #ClutterFlowLayout,
1291 clutter_flow_layout_get_row_spacing (ClutterFlowLayout *layout)
1293 g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), 0.0);
1295 return layout->priv->row_spacing;
1299 * clutter_flow_layout_set_column_width:
1300 * @layout: a #ClutterFlowLayout
1301 * @min_width: minimum width of a column
1302 * @max_width: maximum width of a column
1304 * Sets the minimum and maximum widths that a column can have
1309 clutter_flow_layout_set_column_width (ClutterFlowLayout *layout,
1313 ClutterFlowLayoutPrivate *priv;
1314 gboolean notify_min = FALSE, notify_max = FALSE;
1316 g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
1318 priv = layout->priv;
1320 if (priv->min_col_width != min_width)
1322 priv->min_col_width = min_width;
1327 if (priv->max_col_width != max_width)
1329 priv->max_col_width = max_width;
1334 g_object_freeze_notify (G_OBJECT (layout));
1336 if (notify_min || notify_max)
1338 ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (layout);
1340 clutter_layout_manager_layout_changed (manager);
1344 g_object_notify_by_pspec (G_OBJECT (layout),
1345 flow_properties[PROP_MIN_COLUMN_WIDTH]);
1348 g_object_notify_by_pspec (G_OBJECT (layout),
1349 flow_properties[PROP_MAX_COLUMN_WIDTH]);
1351 g_object_thaw_notify (G_OBJECT (layout));
1355 * clutter_flow_layout_get_column_width:
1356 * @layout: a #ClutterFlowLayout
1357 * @min_width: (out): return location for the minimum column width, or %NULL
1358 * @max_width: (out): return location for the maximum column width, or %NULL
1360 * Retrieves the minimum and maximum column widths
1365 clutter_flow_layout_get_column_width (ClutterFlowLayout *layout,
1369 g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
1372 *min_width = layout->priv->min_col_width;
1375 *max_width = layout->priv->max_col_width;
1379 * clutter_flow_layout_set_row_height:
1380 * @layout: a #ClutterFlowLayout
1381 * @min_height: the minimum height of a row
1382 * @max_height: the maximum height of a row
1384 * Sets the minimum and maximum heights that a row can have
1389 clutter_flow_layout_set_row_height (ClutterFlowLayout *layout,
1393 ClutterFlowLayoutPrivate *priv;
1394 gboolean notify_min = FALSE, notify_max = FALSE;
1396 g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
1398 priv = layout->priv;
1400 if (priv->min_row_height != min_height)
1402 priv->min_row_height = min_height;
1407 if (priv->max_row_height != max_height)
1409 priv->max_row_height = max_height;
1414 g_object_freeze_notify (G_OBJECT (layout));
1416 if (notify_min || notify_max)
1418 ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (layout);
1420 clutter_layout_manager_layout_changed (manager);
1424 g_object_notify_by_pspec (G_OBJECT (layout),
1425 flow_properties[PROP_MIN_ROW_HEGHT]);
1428 g_object_notify_by_pspec (G_OBJECT (layout),
1429 flow_properties[PROP_MAX_ROW_HEIGHT]);
1431 g_object_thaw_notify (G_OBJECT (layout));
1435 * clutter_flow_layout_get_row_height:
1436 * @layout: a #ClutterFlowLayout
1437 * @min_height: (out): return location for the minimum row height, or %NULL
1438 * @max_height: (out): return location for the maximum row height, or %NULL
1440 * Retrieves the minimum and maximum row heights
1445 clutter_flow_layout_get_row_height (ClutterFlowLayout *layout,
1449 g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
1452 *min_height = layout->priv->min_row_height;
1455 *max_height = layout->priv->max_row_height;