actor: Adjust the preferred size too

Don't adjust just the allocation: we need to adjust the preferred size
of the actor to account for the margin.
This commit is contained in:
Emmanuele Bassi 2011-11-28 15:30:52 +00:00 committed by Emmanuele Bassi
parent bf27575187
commit 37d46649ce
3 changed files with 230 additions and 121 deletions

View File

@ -6239,6 +6239,178 @@ clutter_actor_get_preferred_size (ClutterActor *self,
*natural_height_p = natural_height;
}
/*< private >
* effective_align:
* @align: a #ClutterActorAlign
* @direction: a #ClutterTextDirection
*
* Retrieves the correct alignment depending on the text direction
*
* Return value: the effective alignment
*/
static ClutterActorAlign
effective_align (ClutterActorAlign align,
ClutterTextDirection direction)
{
ClutterActorAlign res;
switch (align)
{
case CLUTTER_ACTOR_ALIGN_START:
res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
? CLUTTER_ACTOR_ALIGN_END
: CLUTTER_ACTOR_ALIGN_START;
break;
case CLUTTER_ACTOR_ALIGN_END:
res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
? CLUTTER_ACTOR_ALIGN_START
: CLUTTER_ACTOR_ALIGN_END;
break;
default:
res = align;
break;
}
return res;
}
static inline void
adjust_for_margin (float margin_start,
float margin_end,
float *minimum_size,
float *natural_size,
float *allocated_start,
float *allocated_end)
{
*minimum_size -= (margin_start + margin_end);
*natural_size -= (margin_start + margin_end);
*allocated_start += margin_start;
*allocated_end -= margin_end;
}
static inline void
adjust_for_alignment (ClutterActorAlign alignment,
float natural_size,
float *allocated_start,
float *allocated_end)
{
float allocated_size = *allocated_end - *allocated_start;
switch (alignment)
{
case CLUTTER_ACTOR_ALIGN_FILL:
/* do nothing */
break;
case CLUTTER_ACTOR_ALIGN_START:
/* keep start */
*allocated_end = *allocated_start + MIN (natural_size, allocated_size);
break;
case CLUTTER_ACTOR_ALIGN_END:
if (allocated_size > natural_size)
{
*allocated_start += (allocated_size - natural_size);
*allocated_end = *allocated_start + natural_size;
}
break;
case CLUTTER_ACTOR_ALIGN_CENTER:
if (allocated_size > natural_size)
{
*allocated_start += ceilf ((allocated_size - natural_size) / 2);
*allocated_end = *allocated_start + MIN (allocated_size, natural_size);
}
break;
}
}
/*< private >
* clutter_actor_adjust_width:
* @self: a #ClutterActor
* @minimum_width: (inout): the actor's preferred minimum width, which
* will be adjusted depending on the margin
* @natural_width: (inout): the actor's preferred natural width, which
* will be adjusted depending on the margin
* @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
* @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
*
* Adjusts the preferred and allocated position and size of an actor,
* depending on the margin and alignment properties.
*/
static void
clutter_actor_adjust_width (ClutterActor *self,
gfloat *minimum_width,
gfloat *natural_width,
gfloat *adjusted_x1,
gfloat *adjusted_x2)
{
ClutterTextDirection text_dir;
const ClutterLayoutInfo *info;
info = _clutter_actor_get_layout_info_or_defaults (self);
text_dir = clutter_actor_get_text_direction (self);
CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
/* this will tweak natural_width to remove the margin, so that
* adjust_for_alignment() will use the correct size
*/
adjust_for_margin (info->margin.left, info->margin.right,
minimum_width, natural_width,
adjusted_x1, adjusted_x2);
adjust_for_alignment (effective_align (info->x_align, text_dir),
*natural_width,
adjusted_x1, adjusted_x2);
}
/*< private >
* clutter_actor_adjust_height:
* @self: a #ClutterActor
* @minimum_height: (inout): the actor's preferred minimum height, which
* will be adjusted depending on the margin
* @natural_height: (inout): the actor's preferred natural height, which
* will be adjusted depending on the margin
* @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
* @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
*
* Adjusts the preferred and allocated position and size of an actor,
* depending on the margin and alignment properties.
*/
static void
clutter_actor_adjust_height (ClutterActor *self,
gfloat *minimum_height,
gfloat *natural_height,
gfloat *adjusted_y1,
gfloat *adjusted_y2)
{
const ClutterLayoutInfo *info;
info = _clutter_actor_get_layout_info_or_defaults (self);
CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
/* this will tweak natural_height to remove the margin, so that
* adjust_for_alignment() will use the correct size
*/
adjust_for_margin (info->margin.top, info->margin.bottom,
minimum_height, natural_height,
adjusted_y1,
adjusted_y2);
/* we don't use effective_align() here, because text direction
* only affects the horizontal axis
*/
adjust_for_alignment (info->y_align,
*natural_height,
adjusted_y1,
adjusted_y2);
}
/* looks for a cached size request for this for_size. If not
* found, returns the oldest entry so it can be overwritten */
static gboolean
@ -6318,10 +6490,10 @@ clutter_actor_get_preferred_width (ClutterActor *self,
if (priv->min_width_set && priv->natural_width_set)
{
if (min_width_p != NULL)
*min_width_p = info->min_width;
*min_width_p = info->min_width + (info->margin.left + info->margin.right);
if (natural_width_p != NULL)
*natural_width_p = info->natural_width;
*natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
return;
}
@ -6352,25 +6524,37 @@ clutter_actor_get_preferred_width (ClutterActor *self,
if (!found_in_cache)
{
gfloat min_width, natural_width;
gfloat minimum_width, natural_width;
ClutterActorClass *klass;
min_width = natural_width = 0;
minimum_width = natural_width = 0;
/* adjust for the margin */
if (for_height >= 0)
{
for_height -= (info->margin.top + info->margin.bottom);
if (for_height < 0)
for_height = 0;
}
CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
klass = CLUTTER_ACTOR_GET_CLASS (self);
klass->get_preferred_width (self, for_height,
&min_width,
&minimum_width,
&natural_width);
/* adjust for the margin */
minimum_width += (info->margin.left + info->margin.right);
natural_width += (info->margin.left + info->margin.right);
/* Due to accumulated float errors, it's better not to warn
* on this, but just fix it.
*/
if (natural_width < min_width)
natural_width = min_width;
if (natural_width < minimum_width)
natural_width = minimum_width;
cached_size_request->min_size = min_width;
cached_size_request->min_size = minimum_width;
cached_size_request->natural_size = natural_width;
cached_size_request->for_size = for_height;
cached_size_request->age = priv->cached_width_age;
@ -6439,10 +6623,10 @@ clutter_actor_get_preferred_height (ClutterActor *self,
if (priv->min_height_set && priv->natural_height_set)
{
if (min_height_p != NULL)
*min_height_p = info->min_height;
*min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
if (natural_height_p != NULL)
*natural_height_p = info->natural_height;
*natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
return;
}
@ -6472,25 +6656,37 @@ clutter_actor_get_preferred_height (ClutterActor *self,
if (!found_in_cache)
{
gfloat min_height, natural_height;
gfloat minimum_height, natural_height;
ClutterActorClass *klass;
min_height = natural_height = 0;
minimum_height = natural_height = 0;
CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
/* adjust for margin */
if (for_width >= 0)
{
for_width -= (info->margin.left + info->margin.right);
if (for_width < 0)
for_width = 0;
}
klass = CLUTTER_ACTOR_GET_CLASS (self);
klass->get_preferred_height (self, for_width,
&min_height,
&minimum_height,
&natural_height);
/* adjust for margin */
minimum_height += (info->margin.top + info->margin.bottom);
natural_height += (info->margin.top + info->margin.bottom);
/* Due to accumulated float errors, it's better not to warn
* on this, but just fix it.
*/
if (natural_height < min_height)
natural_height = min_height;
if (natural_height < minimum_height)
natural_height = minimum_height;
cached_size_request->min_size = min_height;
cached_size_request->min_size = minimum_height;
cached_size_request->natural_size = natural_height;
cached_size_request->for_size = for_width;
cached_size_request->age = priv->cached_height_age;
@ -6601,85 +6797,6 @@ clutter_actor_get_allocation_geometry (ClutterActor *self,
geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
}
static ClutterActorAlign
effective_align (ClutterActorAlign align,
ClutterTextDirection direction)
{
ClutterActorAlign res;
switch (align)
{
case CLUTTER_ACTOR_ALIGN_START:
res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
? CLUTTER_ACTOR_ALIGN_END
: CLUTTER_ACTOR_ALIGN_START;
break;
case CLUTTER_ACTOR_ALIGN_END:
res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
? CLUTTER_ACTOR_ALIGN_START
: CLUTTER_ACTOR_ALIGN_END;
break;
default:
res = align;
break;
}
return res;
}
static inline void
adjust_for_margin (float margin_start,
float margin_end,
float *minimum_size,
float *natural_size,
float *allocated_start,
float *allocated_end)
{
*minimum_size -= (margin_start + margin_end);
*natural_size -= (margin_start + margin_end);
*allocated_start += margin_start;
*allocated_end -= margin_end;
}
static inline void
adjust_for_alignment (ClutterActorAlign alignment,
float natural_size,
float *allocated_start,
float *allocated_end)
{
float allocated_size = *allocated_end - *allocated_start;
switch (alignment)
{
case CLUTTER_ACTOR_ALIGN_FILL:
/* do nothing */
break;
case CLUTTER_ACTOR_ALIGN_START:
/* keep start */
*allocated_end = *allocated_start + MIN (natural_size, allocated_size);
break;
case CLUTTER_ACTOR_ALIGN_END:
if (allocated_size > natural_size)
{
*allocated_start += (allocated_size - natural_size);
*allocated_end = *allocated_start + natural_size;
}
break;
case CLUTTER_ACTOR_ALIGN_CENTER:
if (allocated_size > natural_size)
{
*allocated_start += ceilf ((allocated_size - natural_size) / 2);
*allocated_end = *allocated_start + MIN (allocated_size, natural_size);
}
break;
}
}
/*< private >
* clutter_actor_adjust_allocation:
* @self: a #ClutterActor
@ -6697,8 +6814,6 @@ clutter_actor_adjust_allocation (ClutterActor *self,
float min_width, min_height;
float nat_width, nat_height;
ClutterRequestMode req_mode;
ClutterTextDirection text_dir;
const ClutterLayoutInfo *info;
adj_allocation = *allocation;
@ -6744,24 +6859,17 @@ clutter_actor_adjust_allocation (ClutterActor *self,
}
#endif
info = _clutter_actor_get_layout_info_or_defaults (self);
text_dir = clutter_actor_get_text_direction (self);
clutter_actor_adjust_width (self,
&min_width,
&nat_width,
&adj_allocation.x1,
&adj_allocation.x2);
CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
adjust_for_margin (info->margin.left, info->margin.right,
&min_width, &nat_width,
&adj_allocation.x1, &adj_allocation.x2);
adjust_for_alignment (effective_align (info->x_align, text_dir),
nat_width,
&adj_allocation.x1, &adj_allocation.x2);
CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
adjust_for_margin (info->margin.top, info->margin.bottom,
&min_height, &nat_height,
&adj_allocation.y1, &adj_allocation.y2);
adjust_for_alignment (info->y_align,
nat_height,
&adj_allocation.y1, &adj_allocation.y2);
clutter_actor_adjust_height (self,
&min_height,
&nat_height,
&adj_allocation.y1,
&adj_allocation.y2);
/* we maintain the invariant that an allocation cannot be adjusted
* to be outside the parent-given box
@ -8880,7 +8988,7 @@ clutter_actor_insert_child (ClutterActor *self,
ClutterActor *child)
{
ClutterActorPrivate *priv = self->priv;
GList *l, *prev;
GList *l, *prev = NULL;
/* Find the right place to insert the child so that it will still be
sorted and the child will be after all of the actors at the same
@ -13884,7 +13992,7 @@ clutter_actor_needs_y_expand (ClutterActor *self)
return self->priv->y_expand_effective;
}
/*< private >
/**
* clutter_actor_queue_compute_expand:
* @self: a #ClutterActor
*
@ -13895,7 +14003,7 @@ clutter_actor_needs_y_expand (ClutterActor *self)
*
* Since: 1.10
*/
static void
void
clutter_actor_queue_compute_expand (ClutterActor *self)
{
ClutterActor *parent_actor;
@ -13993,7 +14101,7 @@ clutter_actor_get_x_expand (ClutterActor *self)
/**
* clutter_actor_set_y_expand:
* @self: a #ClutterActor
* @x_expand: whether the actor should expand
* @y_expand: whether the actor should expand
*
* Sets whether a #ClutterActor should receive extra space when possible,
* during the allocation.
@ -14114,7 +14222,7 @@ clutter_actor_get_x_align (ClutterActor *self)
/**
* clutter_actor_set_y_align:
* @self: a #ClutterActor
* @x_align: the vertical alignment policy
* @y_align: the vertical alignment policy
*
* Sets the vertical alignment policy of a #ClutterActor, in case the
* actor received extra vertical space.

View File

@ -375,6 +375,7 @@ void clutter_actor_set_y_expand (ClutterActor
gboolean clutter_actor_get_y_expand (ClutterActor *self);
gboolean clutter_actor_needs_x_expand (ClutterActor *self);
gboolean clutter_actor_needs_y_expand (ClutterActor *self);
void clutter_actor_queue_compute_expand (ClutterActor *self);
void clutter_actor_set_x_align (ClutterActor *self,
ClutterActorAlign x_align);

View File

@ -289,8 +289,8 @@ struct _ClutterMargin
GType clutter_margin_get_type (void) G_GNUC_CONST;
ClutterMargin * clutter_margin_new (void) G_GNUC_MALLOC;
ClutterMargin * clutter_margin_copy (const ClutterMargin *margin);
void clutter_margin_free (ClutterMargin *margin);
ClutterMargin * clutter_margin_copy (const ClutterMargin *margin_);
void clutter_margin_free (ClutterMargin *margin_);
G_END_DECLS