mutter/clutter/clutter-flow-layout.c
Emmanuele Bassi eb40e856e1 layout: Change the request-mode along with the orientation
When changing the orientation of a FlowLayout, the associated
container should also change its request mode. A horizontally
flowing layout has a height depending on the width, since it
will reflow vertically; similarly, a vertically reflowing layout
will have a width depending on the height.
2009-10-14 11:31:31 +01:00

1031 lines
29 KiB
C

/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author:
* Emmanuele Bassi <ebassi@linux.intel.com>
*/
/**
* SECTION:clutter-flow-layout
* @short_description: A reflowing layout manager
*
* #ClutterFlowLayout is a layout manager which implements the following
* policy:
*
* <itemizedlist>
* </itemizedlist>
*
* #ClutterFlowLayout is available since Clutter 1.2
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include "clutter-actor.h"
#include "clutter-animatable.h"
#include "clutter-child-meta.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-flow-layout.h"
#include "clutter-layout-meta.h"
#include "clutter-private.h"
#define CLUTTER_FLOW_LAYOUT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_FLOW_LAYOUT, ClutterFlowLayoutPrivate))
struct _ClutterFlowLayoutPrivate
{
ClutterContainer *container;
ClutterFlowOrientation orientation;
gfloat col_spacing;
gfloat row_spacing;
gfloat min_col_width;
gfloat max_col_width;
gfloat col_width;
gfloat min_row_height;
gfloat max_row_height;
gfloat row_height;
guint is_homogeneous : 1;
};
enum
{
PROP_0,
PROP_ORIENTATION,
PROP_HOMOGENEOUS,
PROP_COLUMN_SPACING,
PROP_ROW_SPACING,
PROP_MIN_COLUMN_WIDTH,
PROP_MAX_COLUMN_WIDTH,
PROP_MIN_ROW_HEGHT,
PROP_MAX_ROW_HEIGHT
};
G_DEFINE_TYPE (ClutterFlowLayout,
clutter_flow_layout,
CLUTTER_TYPE_LAYOUT_MANAGER);
static void
clutter_flow_layout_get_preferred_width (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_height,
gfloat *min_width_p,
gfloat *nat_width_p)
{
ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv;
GList *l, *children = clutter_container_get_children (container);
gfloat max_child_min_width, max_child_natural_width;
gfloat row_natural_width;
max_child_min_width = max_child_natural_width = 0;
row_natural_width = 0;
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
gfloat child_min, child_natural;
if (!CLUTTER_ACTOR_IS_VISIBLE (child))
continue;
clutter_actor_get_preferred_width (child, for_height,
&child_min,
&child_natural);
max_child_min_width = MAX (max_child_min_width, child_min);
max_child_natural_width = MAX (max_child_natural_width, child_natural);
if (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
row_natural_width += (child_natural + priv->col_spacing);
else
row_natural_width = MAX (row_natural_width, max_child_natural_width);
}
g_list_free (children);
priv->col_width = max_child_natural_width;
/* if we get a maximum value for the column width we only apply
* it if there isn't a child whose minimum width is bigger than
* the requested maximum width
*/
if (priv->max_col_width > 0 && priv->col_width > priv->max_col_width)
priv->col_width = MAX (priv->max_col_width, max_child_min_width);
if (priv->col_width < priv->min_col_width)
priv->col_width = priv->min_col_width;
if (min_width_p)
*min_width_p = ceilf (max_child_min_width);
if (nat_width_p)
*nat_width_p = ceilf (row_natural_width);
}
static void
clutter_flow_layout_get_preferred_height (ClutterLayoutManager *manager,
ClutterContainer *container,
gfloat for_width,
gfloat *min_height_p,
gfloat *nat_height_p)
{
ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv;
GList *l, *children = clutter_container_get_children (container);
gfloat max_child_min_height, max_child_natural_height;
gfloat col_natural_height;
max_child_min_height = max_child_natural_height = 0;
col_natural_height = 0;
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
gfloat child_min, child_natural;
if (!CLUTTER_ACTOR_IS_VISIBLE (child))
continue;
clutter_actor_get_preferred_height (child, for_width,
&child_min,
&child_natural);
max_child_min_height = MAX (max_child_min_height, child_min);
max_child_natural_height = MAX (max_child_natural_height, child_natural);
if (priv->orientation == CLUTTER_FLOW_VERTICAL)
col_natural_height += (child_natural + priv->row_spacing);
else
col_natural_height = MAX (col_natural_height, max_child_natural_height);
}
g_list_free (children);
priv->row_height = max_child_natural_height;
/* similarly to max-col-width, we only apply max-row-height if there
* is no child with a bigger minimum height
*/
if (priv->max_row_height > 0 && priv->row_height > priv->max_row_height)
priv->row_height = MAX (priv->max_row_height, max_child_min_height);
if (priv->row_height < priv->min_row_height)
priv->row_height = priv->min_row_height;
if (min_height_p)
*min_height_p = ceilf (max_child_min_height);
if (nat_height_p)
*nat_height_p = ceilf (col_natural_height);
}
static gint
compute_lines (ClutterFlowLayout *self,
const GList *children,
gfloat avail_width,
gfloat avail_height)
{
ClutterFlowLayoutPrivate *priv = self->priv;
gint items_per_line;
if (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
{
items_per_line = (avail_width - priv->col_spacing)
/ (priv->col_width + priv->col_spacing);
}
else
{
items_per_line = (avail_height - priv->row_spacing)
/ (priv->row_height + priv->row_spacing);
}
return items_per_line;
}
static void
clutter_flow_layout_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
{
ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv;
GList *l, *children = clutter_container_get_children (container);
gfloat avail_width, avail_height;
gfloat item_x, item_y;
gint line_items_count;
gint items_per_line;
gint line_index;
if (children == NULL)
return;
clutter_actor_box_get_size (allocation, &avail_width, &avail_height);
items_per_line = compute_lines (CLUTTER_FLOW_LAYOUT (manager),
children,
avail_width, avail_height);
item_x = item_y = 0;
line_items_count = 0;
line_index = 0;
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
ClutterActorBox child_alloc;
gfloat item_width, item_height;
gfloat child_min, child_natural;
if (!CLUTTER_ACTOR_IS_VISIBLE (child))
continue;
if (line_items_count == items_per_line)
{
if (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
{
item_x = 0;
item_y += priv->row_height + priv->row_spacing;
}
else
{
item_x += priv->col_width + priv->col_spacing;
item_y = 0;
}
line_items_count = 0;
line_index += 1;
}
if (priv->is_homogeneous)
{
item_width = priv->col_width;
item_height = priv->row_height;
}
else
{
clutter_actor_get_preferred_width (child, priv->row_height,
&child_min,
&child_natural);
item_width = MIN (child_natural, priv->col_width);
clutter_actor_get_preferred_height (child, item_width,
&child_min,
&child_natural);
item_height = MIN (child_natural, priv->row_height);
}
CLUTTER_NOTE (LAYOUT,
"flow[line:%d, item:%d/%d] = { %.2f, %.2f, %.2f, %.2f }",
line_index, line_items_count + 1, items_per_line,
item_x, item_y, item_width, item_height);
child_alloc.x1 = ceil (item_x);
child_alloc.y1 = ceil (item_y);
child_alloc.x2 = ceil (child_alloc.x1 + item_width);
child_alloc.y2 = ceil (child_alloc.y1 + item_height);
clutter_actor_allocate (child, &child_alloc, flags);
if (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
item_x += (priv->col_width + priv->col_spacing);
else
item_y += (priv->row_height + priv->row_spacing);
line_items_count += 1;
}
g_list_free (children);
}
static void
clutter_flow_layout_set_container (ClutterLayoutManager *manager,
ClutterContainer *container)
{
ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv;
priv->container = container;
if (priv->container != NULL)
{
ClutterRequestMode request_mode;
/* we need to change the :request-mode of the container
* to match the orientation
*/
request_mode = (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
? CLUTTER_REQUEST_HEIGHT_FOR_WIDTH
: CLUTTER_REQUEST_WIDTH_FOR_HEIGHT;
clutter_actor_set_request_mode (CLUTTER_ACTOR (priv->container),
request_mode);
}
}
static void
clutter_flow_layout_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterFlowLayout *self = CLUTTER_FLOW_LAYOUT (gobject);
switch (prop_id)
{
case PROP_ORIENTATION:
clutter_flow_layout_set_orientation (self, g_value_get_enum (value));
break;
case PROP_HOMOGENEOUS:
clutter_flow_layout_set_homogeneous (self, g_value_get_boolean (value));
break;
case PROP_COLUMN_SPACING:
clutter_flow_layout_set_column_spacing (self, g_value_get_float (value));
break;
case PROP_ROW_SPACING:
clutter_flow_layout_set_row_spacing (self, g_value_get_float (value));
break;
case PROP_MIN_COLUMN_WIDTH:
clutter_flow_layout_set_column_width (self,
g_value_get_float (value),
self->priv->max_col_width);
break;
case PROP_MAX_COLUMN_WIDTH:
clutter_flow_layout_set_column_width (self,
self->priv->min_col_width,
g_value_get_float (value));
break;
case PROP_MIN_ROW_HEGHT:
clutter_flow_layout_set_row_height (self,
g_value_get_float (value),
self->priv->max_row_height);
break;
case PROP_MAX_ROW_HEIGHT:
clutter_flow_layout_set_row_height (self,
self->priv->min_row_height,
g_value_get_float (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_flow_layout_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (gobject)->priv;
switch (prop_id)
{
case PROP_ORIENTATION:
g_value_set_enum (value, priv->orientation);
break;
case PROP_HOMOGENEOUS:
g_value_set_boolean (value, priv->is_homogeneous);
break;
case PROP_COLUMN_SPACING:
g_value_set_float (value, priv->col_spacing);
break;
case PROP_ROW_SPACING:
g_value_set_float (value, priv->row_spacing);
break;
case PROP_MIN_COLUMN_WIDTH:
g_value_set_float (value, priv->min_col_width);
break;
case PROP_MAX_COLUMN_WIDTH:
g_value_set_float (value, priv->max_col_width);
break;
case PROP_MIN_ROW_HEGHT:
g_value_set_float (value, priv->min_row_height);
break;
case PROP_MAX_ROW_HEIGHT:
g_value_set_float (value, priv->max_row_height);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_flow_layout_class_init (ClutterFlowLayoutClass *klass)
{
GObjectClass *gobject_class;
ClutterLayoutManagerClass *layout_class;
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (ClutterFlowLayoutPrivate));
gobject_class = G_OBJECT_CLASS (klass);
layout_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass);
gobject_class->set_property = clutter_flow_layout_set_property;
gobject_class->get_property = clutter_flow_layout_get_property;
layout_class->get_preferred_width =
clutter_flow_layout_get_preferred_width;
layout_class->get_preferred_height =
clutter_flow_layout_get_preferred_height;
layout_class->allocate = clutter_flow_layout_allocate;
layout_class->set_container = clutter_flow_layout_set_container;
/**
* ClutterFlowLayout:orientation:
*
* The orientation of the #ClutterFlowLayout. The children
* of the layout will be layed out following the orientation.
*
* This property also controls the overflowing directions
*
* Since: 1.2
*/
pspec = g_param_spec_enum ("orientation",
"Orientation",
"The orientation of the layout",
CLUTTER_TYPE_FLOW_ORIENTATION,
CLUTTER_FLOW_HORIZONTAL,
CLUTTER_PARAM_READWRITE |
G_PARAM_CONSTRUCT);
g_object_class_install_property (gobject_class, PROP_ORIENTATION, pspec);
/**
* ClutterFlowLayout:homogeneous:
*
* Whether each child inside the #ClutterFlowLayout should receive
* the same allocation
*
* Since: 1.2
*/
pspec = g_param_spec_boolean ("homogeneous",
"Homogeneous",
"Whether each item should receive the "
"same allocation",
FALSE,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_HOMOGENEOUS, pspec);
/**
* ClutterFlowLayout:column-spacing:
*
* The spacing between columns, in pixels; the value of this
* property is honoured by horizontal non-overflowing layouts
* and by vertical overflowing layouts
*
* Since: 1.2
*/
pspec = g_param_spec_float ("column-spacing",
"Column Spacing",
"The spacing between columns",
0.0, G_MAXFLOAT,
0.0,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_COLUMN_SPACING,
pspec);
/**
* ClutterFlowLayout:row-spacing:
*
* The spacing between rows, in pixels; the value of this
* property is honoured by vertical non-overflowing layouts and
* by horizontal overflowing layouts
*
* Since: 1.2
*/
pspec = g_param_spec_float ("row-spacing",
"Row Spacing",
"The spacing between rows",
0.0, G_MAXFLOAT,
0.0,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_ROW_SPACING,
pspec);
/**
* ClutterFlowLayout:min-column-width:
*
* Minimum width for each column in the layout, in pixels
*
* Since: 1.2
*/
pspec = g_param_spec_float ("min-column-width",
"Minimum Column Width",
"Minimum width for each column",
0.0, G_MAXFLOAT,
0.0,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_MIN_COLUMN_WIDTH,
pspec);
/**
* ClutterFlowLayout:max-column-width:
*
* Maximum width for each column in the layout, in pixels. If
* set to -1 the width will be the maximum child width
*
* Since: 1.2
*/
pspec = g_param_spec_float ("max-column-width",
"Maximum Column Width",
"Maximum width for each column",
-1.0, G_MAXFLOAT,
-1.0,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_MAX_COLUMN_WIDTH,
pspec);
/**
* ClutterFlowLayout:min-row-height:
*
* Minimum height for each row in the layout, in pixels
*
* Since: 1.2
*/
pspec = g_param_spec_float ("min-row-height",
"Minimum Row Height",
"Minimum height for each row",
0.0, G_MAXFLOAT,
0.0,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_MIN_ROW_HEGHT,
pspec);
/**
* ClutterFlowLayout:max-row-height:
*
* Maximum height for each row in the layout, in pixels. If
* set to -1 the width will be the maximum child height
*
* Since: 1.2
*/
pspec = g_param_spec_float ("max-row-height",
"Maximum Row Height",
"Maximum height for each row",
-1.0, G_MAXFLOAT,
-1.0,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_MAX_ROW_HEIGHT,
pspec);
}
static void
clutter_flow_layout_init (ClutterFlowLayout *self)
{
ClutterFlowLayoutPrivate *priv;
self->priv = priv = CLUTTER_FLOW_LAYOUT_GET_PRIVATE (self);
priv->orientation = CLUTTER_FLOW_HORIZONTAL;
priv->col_spacing = 0;
priv->row_spacing = 0;
priv->min_col_width = priv->min_row_height = 0;
priv->max_col_width = priv->max_row_height = -1;
}
/**
* clutter_flow_layout_new:
* @orientation: the orientation of the flow layout
*
* Creates a new #ClutterFlowLayout with the given @orientation
*
* Return value: the newly created #ClutterFlowLayout
*
* Since: 1.2
*/
ClutterLayoutManager *
clutter_flow_layout_new (ClutterFlowOrientation orientation)
{
return g_object_new (CLUTTER_TYPE_FLOW_LAYOUT,
"orientation", orientation,
NULL);
}
/**
* clutter_flow_layout_set_orientation:
* @layout: a #ClutterFlowLayout
* @orientation: the orientation of the layout
*
* Sets the orientation of the flow layout
*
* The orientation controls the direction used to allocate
* the children: either horizontally or vertically. The
* orientation also controls the direction of the overflowing
*
* Since: 1.2
*/
void
clutter_flow_layout_set_orientation (ClutterFlowLayout *layout,
ClutterFlowOrientation orientation)
{
ClutterFlowLayoutPrivate *priv;
g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
priv = layout->priv;
if (priv->orientation != orientation)
{
ClutterLayoutManager *manager;
priv->orientation = orientation;
if (priv->container != NULL)
{
ClutterRequestMode request_mode;
/* we need to change the :request-mode of the container
* to match the orientation
*/
request_mode = (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
? CLUTTER_REQUEST_HEIGHT_FOR_WIDTH
: CLUTTER_REQUEST_WIDTH_FOR_HEIGHT;
clutter_actor_set_request_mode (CLUTTER_ACTOR (priv->container),
request_mode);
}
manager = CLUTTER_LAYOUT_MANAGER (layout);
clutter_layout_manager_layout_changed (manager);
g_object_notify (G_OBJECT (layout), "orientation");
}
}
/**
* clutter_flow_layout_get_orientation:
* @layout: a #ClutterFlowLayout
*
* Retrieves the orientation of the @layout
*
* Return value: the orientation of the #ClutterFlowLayout
*
* Since: 1.2
*/
ClutterFlowOrientation
clutter_flow_layout_get_orientation (ClutterFlowLayout *layout)
{
g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout),
CLUTTER_FLOW_HORIZONTAL);
return layout->priv->orientation;
}
/**
* clutter_flow_layout_set_homogeneous:
* @layout: a #ClutterFlowLayout
* @homogeneous: whether the layout should be homogeneous or not
*
* Sets whether the @layout should allocate the same space for
* each child
*
* Since: 1.2
*/
void
clutter_flow_layout_set_homogeneous (ClutterFlowLayout *layout,
gboolean homogeneous)
{
ClutterFlowLayoutPrivate *priv;
g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
priv = layout->priv;
if (priv->is_homogeneous != homogeneous)
{
ClutterLayoutManager *manager;
priv->is_homogeneous = homogeneous;
manager = CLUTTER_LAYOUT_MANAGER (layout);
clutter_layout_manager_layout_changed (manager);
g_object_notify (G_OBJECT (layout), "homogeneous");
}
}
/**
* clutter_flow_layout_get_homogeneous:
* @layout: a #ClutterFlowLayout
*
* Retrieves whether the @layout is homogeneous
*
* Return value: %TRUE if the #ClutterFlowLayout is homogeneous
*
* Since: 1.2
*/
gboolean
clutter_flow_layout_get_homogeneous (ClutterFlowLayout *layout)
{
g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), FALSE);
return layout->priv->is_homogeneous;
}
/**
* clutter_flow_layout_set_column_spacing:
* @layout: a #ClutterFlowLayout
* @spacing: the space between columns
*
* Sets the space between columns, in pixels
*
* Since: 1.2
*/
void
clutter_flow_layout_set_column_spacing (ClutterFlowLayout *layout,
gfloat spacing)
{
ClutterFlowLayoutPrivate *priv;
g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
priv = layout->priv;
if (priv->col_spacing != spacing)
{
ClutterLayoutManager *manager;
priv->col_spacing = spacing;
manager = CLUTTER_LAYOUT_MANAGER (layout);
clutter_layout_manager_layout_changed (manager);
g_object_notify (G_OBJECT (layout), "column-spacing");
}
}
/**
* clutter_flow_layout_get_column_spacing:
* @layout: a #ClutterFlowLayout
*
* Retrieves the spacing between columns
*
* Return value: the spacing between columns of the #ClutterFlowLayout,
* in pixels
*
* Since: 1.2
*/
gfloat
clutter_flow_layout_get_column_spacing (ClutterFlowLayout *layout)
{
g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), 0.0);
return layout->priv->col_spacing;
}
/**
* clutter_flow_layout_set_row_spacing:
* @layout: a #ClutterFlowLayout
* @spacing: the space between rows
*
* Sets the spacing between rows, in pixels
*
* Since: 1.2
*/
void
clutter_flow_layout_set_row_spacing (ClutterFlowLayout *layout,
gfloat spacing)
{
ClutterFlowLayoutPrivate *priv;
g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
priv = layout->priv;
if (priv->row_spacing != spacing)
{
ClutterLayoutManager *manager;
priv->row_spacing = spacing;
manager = CLUTTER_LAYOUT_MANAGER (layout);
clutter_layout_manager_layout_changed (manager);
g_object_notify (G_OBJECT (layout), "row-spacing");
}
}
/**
* clutter_flow_layout_get_row_spacing:
* @layout: a #ClutterFlowLayout
*
* Retrieves the spacing between rows
*
* Return value: the spacing between rows of the #ClutterFlowLayout,
* in pixels
*
* Since: 1.2
*/
gfloat
clutter_flow_layout_get_row_spacing (ClutterFlowLayout *layout)
{
g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), 0.0);
return layout->priv->row_spacing;
}
/**
* clutter_flow_layout_set_column_width:
* @layout: a #ClutterFlowLayout
* @min_width: minimum width of a column
* @max_width: maximum width of a column
*
* Sets the minimum and maximum widths that a column can have
*
* Since: 1.2
*/
void
clutter_flow_layout_set_column_width (ClutterFlowLayout *layout,
gfloat min_width,
gfloat max_width)
{
ClutterFlowLayoutPrivate *priv;
gboolean notify_min = FALSE, notify_max = FALSE;
g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
priv = layout->priv;
if (priv->min_col_width != min_width)
{
priv->min_col_width = min_width;
notify_min = TRUE;
}
if (priv->max_col_width != max_width)
{
priv->max_col_width = max_width;
notify_max = TRUE;
}
g_object_freeze_notify (G_OBJECT (layout));
if (notify_min || notify_max)
{
ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (layout);
clutter_layout_manager_layout_changed (manager);
}
if (notify_min)
g_object_notify (G_OBJECT (layout), "min-column-width");
if (notify_max)
g_object_notify (G_OBJECT (layout), "max-column-width");
g_object_thaw_notify (G_OBJECT (layout));
}
/**
* clutter_flow_layout_get_column_width:
* @layout: a #ClutterFlowLayout
* @min_width: (out): return location for the minimum column width, or %NULL
* @max_width: (out): return location for the maximum column width, or %NULL
*
* Retrieves the minimum and maximum column widths
*
* Since: 1.2
*/
void
clutter_flow_layout_get_column_width (ClutterFlowLayout *layout,
gfloat *min_width,
gfloat *max_width)
{
g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
if (min_width)
*min_width = layout->priv->min_col_width;
if (max_width)
*max_width = layout->priv->max_col_width;
}
/**
* clutter_flow_layout_set_row_height:
* @layout: a #ClutterFlowLayout
* @min_height: the minimum height of a row
* @max_height: the maximum height of a row
*
* Sets the minimum and maximum heights that a row can have
*
* Since: 1.2
*/
void
clutter_flow_layout_set_row_height (ClutterFlowLayout *layout,
gfloat min_height,
gfloat max_height)
{
ClutterFlowLayoutPrivate *priv;
gboolean notify_min = FALSE, notify_max = FALSE;
g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
priv = layout->priv;
if (priv->min_row_height != min_height)
{
priv->min_row_height = min_height;
notify_min = TRUE;
}
if (priv->max_row_height != max_height)
{
priv->max_row_height = max_height;
notify_max = TRUE;
}
g_object_freeze_notify (G_OBJECT (layout));
if (notify_min || notify_max)
{
ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (layout);
clutter_layout_manager_layout_changed (manager);
}
if (notify_min)
g_object_notify (G_OBJECT (layout), "min-row-height");
if (notify_max)
g_object_notify (G_OBJECT (layout), "max-row-height");
g_object_thaw_notify (G_OBJECT (layout));
}
/**
* clutter_flow_layout_get_row_height:
* @layout: a #ClutterFlowLayout
* @min_height: (out): return location for the minimum row height, or %NULL
* @max_height: (out): return location for the maximum row height, or %NULL
*
* Retrieves the minimum and maximum row heights
*
* Since: 1.2
*/
void
clutter_flow_layout_get_row_height (ClutterFlowLayout *layout,
gfloat *min_height,
gfloat *max_height)
{
g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
if (min_height)
*min_height = layout->priv->min_row_height;
if (max_height)
*max_height = layout->priv->max_row_height;
}