flow-layout: Add :snap-to-grid property

Add a :snap-to-grid property to FlowLayout to prevent the layout from
assigning it's children a position based on the size of the largest
child.

https://bugzilla.gnome.org/show_bug.cgi?id=648873
This commit is contained in:
Bastian Winkler 2013-05-03 11:53:44 -04:00 committed by Erick Pérez Castellanos
parent fd9109e6d6
commit cd9ba0ad8d
5 changed files with 182 additions and 43 deletions

View File

@ -113,6 +113,7 @@ struct _ClutterFlowLayoutPrivate
guint line_count;
guint is_homogeneous : 1;
guint snap_to_grid : 1;
};
enum
@ -131,6 +132,8 @@ enum
PROP_MIN_ROW_HEGHT,
PROP_MAX_ROW_HEIGHT,
PROP_SNAP_TO_GRID,
N_PROPERTIES
};
@ -258,7 +261,12 @@ clutter_flow_layout_get_preferred_width (ClutterLayoutManager *manager,
if (priv->orientation == CLUTTER_FLOW_VERTICAL && for_height > 0)
{
if (line_item_count == n_rows)
clutter_actor_get_preferred_height (child, -1,
&child_min,
&child_natural);
if ((priv->snap_to_grid && line_item_count == n_rows) ||
(!priv->snap_to_grid && item_y + child_natural > for_height))
{
total_min_width += line_min_width;
total_natural_width += line_natural_width;
@ -275,9 +283,17 @@ clutter_flow_layout_get_preferred_width (ClutterLayoutManager *manager,
item_y = 0;
}
if (priv->snap_to_grid)
{
new_y = ((line_item_count + 1) * (for_height + priv->row_spacing))
/ n_rows;
item_height = new_y - item_y - priv->row_spacing;
}
else
{
new_y = item_y + child_natural + priv->row_spacing;
item_height = child_natural;
}
clutter_actor_get_preferred_width (child, item_height,
&child_min,
@ -436,7 +452,12 @@ clutter_flow_layout_get_preferred_height (ClutterLayoutManager *manager,
if (priv->orientation == CLUTTER_FLOW_HORIZONTAL && for_width > 0)
{
if (line_item_count == n_columns)
clutter_actor_get_preferred_width (child, -1,
&child_min,
&child_natural);
if ((priv->snap_to_grid && line_item_count == n_columns) ||
(!priv->snap_to_grid && item_x + child_natural > for_width))
{
total_min_height += line_min_height;
total_natural_height += line_natural_height;
@ -453,9 +474,17 @@ clutter_flow_layout_get_preferred_height (ClutterLayoutManager *manager,
item_x = 0;
}
if (priv->snap_to_grid)
{
new_x = ((line_item_count + 1) * (for_width + priv->col_spacing))
/ n_columns;
item_width = new_x - item_x - priv->col_spacing;
}
else
{
new_x = item_x + child_natural + priv->col_spacing;
item_width = child_natural;
}
clutter_actor_get_preferred_height (child, item_width,
&child_min,
@ -606,15 +635,24 @@ clutter_flow_layout_allocate (ClutterLayoutManager *manager,
ClutterActorBox child_alloc;
gfloat item_width, item_height;
gfloat new_x, new_y;
gfloat child_min, child_natural;
if (!CLUTTER_ACTOR_IS_VISIBLE (child))
continue;
new_x = new_y = 0;
if (!priv->snap_to_grid)
clutter_actor_get_preferred_size (child,
NULL, NULL,
&item_width,
&item_height);
if (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
{
if (line_item_count == items_per_line && line_item_count > 0)
if ((priv->snap_to_grid &&
line_item_count == items_per_line && line_item_count > 0) ||
(!priv->snap_to_grid && item_x + item_width > avail_width))
{
item_y += g_array_index (priv->line_natural,
gfloat,
@ -629,31 +667,27 @@ clutter_flow_layout_allocate (ClutterLayoutManager *manager,
item_x = x_off;
}
if (priv->snap_to_grid)
{
new_x = x_off + ((line_item_count + 1) * (avail_width + priv->col_spacing))
/ items_per_line;
item_width = new_x - item_x - priv->col_spacing;
}
else
{
new_x = item_x + item_width + priv->col_spacing;
}
item_height = g_array_index (priv->line_natural,
gfloat,
line_index);
if (!priv->is_homogeneous)
{
gfloat child_min, child_natural;
clutter_actor_get_preferred_width (child, item_height,
&child_min,
&child_natural);
item_width = MIN (item_width, child_natural);
clutter_actor_get_preferred_height (child, item_width,
&child_min,
&child_natural);
item_height = MIN (item_height, child_natural);
}
}
else
{
if (line_item_count == items_per_line && line_item_count > 0)
if ((priv->snap_to_grid &&
line_item_count == items_per_line && line_item_count > 0) ||
(!priv->snap_to_grid && item_y + item_height > avail_height))
{
item_x += g_array_index (priv->line_natural,
gfloat,
@ -668,28 +702,41 @@ clutter_flow_layout_allocate (ClutterLayoutManager *manager,
item_y = y_off;
}
if (priv->snap_to_grid)
{
new_y = y_off + ((line_item_count + 1) * (avail_height + priv->row_spacing))
/ items_per_line;
item_height = new_y - item_y - priv->row_spacing;
}
else
{
new_y = item_y + item_height + priv->row_spacing;
}
item_width = g_array_index (priv->line_natural,
gfloat,
line_index);
}
if (!priv->is_homogeneous)
if (!priv->is_homogeneous &&
!clutter_actor_needs_expand (child,
CLUTTER_ORIENTATION_HORIZONTAL))
{
gfloat child_min, child_natural;
clutter_actor_get_preferred_width (child, item_height,
&child_min,
&child_natural);
item_width = MIN (item_width, child_natural);
}
if (!priv->is_homogeneous &&
!clutter_actor_needs_expand (child,
CLUTTER_ORIENTATION_VERTICAL))
{
clutter_actor_get_preferred_height (child, item_width,
&child_min,
&child_natural);
item_height = MIN (item_height, child_natural);
}
}
CLUTTER_NOTE (LAYOUT,
"flow[line:%d, item:%d/%d] ="
@ -789,6 +836,11 @@ clutter_flow_layout_set_property (GObject *gobject,
g_value_get_float (value));
break;
case PROP_SNAP_TO_GRID:
clutter_flow_layout_set_snap_to_grid (self,
g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@ -837,6 +889,10 @@ clutter_flow_layout_get_property (GObject *gobject,
g_value_set_float (value, priv->max_row_height);
break;
case PROP_SNAP_TO_GRID:
g_value_set_boolean (value, priv->snap_to_grid);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@ -1004,6 +1060,21 @@ clutter_flow_layout_class_init (ClutterFlowLayoutClass *klass)
-1.0,
CLUTTER_PARAM_READWRITE);
/**
* ClutterFlowLayout:snap-to-grid:
*
* Whether the #ClutterFlowLayout should arrange its children
* on a grid
*
* Since: 1.16
*/
flow_properties[PROP_SNAP_TO_GRID] =
g_param_spec_boolean ("snap-to-grid",
P_("Snap to grid"),
P_("Snap to grid"),
TRUE,
CLUTTER_PARAM_READWRITE);
gobject_class->finalize = clutter_flow_layout_finalize;
gobject_class->set_property = clutter_flow_layout_set_property;
gobject_class->get_property = clutter_flow_layout_get_property;
@ -1029,6 +1100,7 @@ clutter_flow_layout_init (ClutterFlowLayout *self)
priv->line_min = NULL;
priv->line_natural = NULL;
priv->snap_to_grid = TRUE;
}
/**
@ -1434,3 +1506,51 @@ clutter_flow_layout_get_row_height (ClutterFlowLayout *layout,
if (max_height)
*max_height = layout->priv->max_row_height;
}
/**
* clutter_flow_layout_set_snap_to_grid:
* @layout: a #ClutterFlowLayout
* @snap_to_grid: %TRUE if @layout should place its children on a grid
*
* Whether the @layout should place its children on a grid.
*
* Since: 1.16
*/
void
clutter_flow_layout_set_snap_to_grid (ClutterFlowLayout *layout,
gboolean snap_to_grid)
{
ClutterFlowLayoutPrivate *priv;
g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout));
priv = layout->priv;
if (priv->snap_to_grid != snap_to_grid)
{
priv->snap_to_grid = snap_to_grid;
clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (layout));
g_object_notify_by_pspec (G_OBJECT (layout),
flow_properties[PROP_SNAP_TO_GRID]);
}
}
/**
* clutter_flow_layout_get_snap_to_grid:
* @layout: a #ClutterFlowLayout
*
* Retrieves the value of #ClutterFlowLayout:snap-to-grid property
*
* Return value: %TRUE if the @layout is placing its children on a grid
*
* Since: 1.16
*/
gboolean
clutter_flow_layout_get_snap_to_grid (ClutterFlowLayout *layout)
{
g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), FALSE);
return layout->priv->snap_to_grid;
}

View File

@ -104,6 +104,11 @@ void clutter_flow_layout_set_row_height (ClutterFlowLayout
void clutter_flow_layout_get_row_height (ClutterFlowLayout *layout,
gfloat *min_height,
gfloat *max_height);
CLUTTER_AVAILABLE_IN_1_16
void clutter_flow_layout_set_snap_to_grid (ClutterFlowLayout *layout,
gboolean snap_to_grid);
CLUTTER_AVAILABLE_IN_1_16
gboolean clutter_flow_layout_get_snap_to_grid (ClutterFlowLayout *layout);
G_END_DECLS

View File

@ -707,6 +707,7 @@ clutter_flow_layout_get_column_spacing
clutter_flow_layout_get_column_width
clutter_flow_layout_get_homogeneous
clutter_flow_layout_get_orientation
clutter_flow_layout_get_snap_to_grid
clutter_flow_layout_get_row_height
clutter_flow_layout_get_row_spacing
clutter_flow_layout_get_type
@ -715,6 +716,7 @@ clutter_flow_layout_set_column_spacing
clutter_flow_layout_set_column_width
clutter_flow_layout_set_homogeneous
clutter_flow_layout_set_orientation
clutter_flow_layout_set_snap_to_grid
clutter_flow_layout_set_row_height
clutter_flow_layout_set_row_spacing
clutter_flow_orientation_get_type

View File

@ -2298,6 +2298,8 @@ clutter_flow_layout_set_homogeneous
clutter_flow_layout_get_homogeneous
clutter_flow_layout_set_orientation
clutter_flow_layout_get_orientation
clutter_flow_layout_set_snap_to_grid
clutter_flow_layout_get_snap_to_grid
<SUBSECTION>
clutter_flow_layout_set_column_spacing

View File

@ -9,6 +9,7 @@ static gboolean is_homogeneous = FALSE;
static gboolean vertical = FALSE;
static gboolean random_size = FALSE;
static gboolean fixed_size = FALSE;
static gboolean snap_to_grid = TRUE;
static gint n_rects = N_RECTS;
static gint x_spacing = 0;
@ -64,6 +65,13 @@ static GOptionEntry entries[] = {
&fixed_size,
"Fix the layout size", NULL
},
{
"no-snap-to-grid", 's',
G_OPTION_FLAG_REVERSE,
G_OPTION_ARG_NONE,
&snap_to_grid,
"Don't snap elements to grid", NULL
},
{ NULL }
};
@ -102,6 +110,8 @@ main (int argc, char *argv[])
x_spacing);
clutter_flow_layout_set_row_spacing (CLUTTER_FLOW_LAYOUT (layout),
y_spacing);
clutter_flow_layout_set_snap_to_grid (CLUTTER_FLOW_LAYOUT (layout),
snap_to_grid);
box = clutter_actor_new ();
clutter_actor_set_layout_manager (box, layout);