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; *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 /* looks for a cached size request for this for_size. If not
* found, returns the oldest entry so it can be overwritten */ * found, returns the oldest entry so it can be overwritten */
static gboolean static gboolean
@ -6318,10 +6490,10 @@ clutter_actor_get_preferred_width (ClutterActor *self,
if (priv->min_width_set && priv->natural_width_set) if (priv->min_width_set && priv->natural_width_set)
{ {
if (min_width_p != NULL) 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) if (natural_width_p != NULL)
*natural_width_p = info->natural_width; *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
return; return;
} }
@ -6352,25 +6524,37 @@ clutter_actor_get_preferred_width (ClutterActor *self,
if (!found_in_cache) if (!found_in_cache)
{ {
gfloat min_width, natural_width; gfloat minimum_width, natural_width;
ClutterActorClass *klass; 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); CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
klass = CLUTTER_ACTOR_GET_CLASS (self); klass = CLUTTER_ACTOR_GET_CLASS (self);
klass->get_preferred_width (self, for_height, klass->get_preferred_width (self, for_height,
&min_width, &minimum_width,
&natural_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 /* Due to accumulated float errors, it's better not to warn
* on this, but just fix it. * on this, but just fix it.
*/ */
if (natural_width < min_width) if (natural_width < minimum_width)
natural_width = min_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->natural_size = natural_width;
cached_size_request->for_size = for_height; cached_size_request->for_size = for_height;
cached_size_request->age = priv->cached_width_age; 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 (priv->min_height_set && priv->natural_height_set)
{ {
if (min_height_p != NULL) 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) if (natural_height_p != NULL)
*natural_height_p = info->natural_height; *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
return; return;
} }
@ -6472,25 +6656,37 @@ clutter_actor_get_preferred_height (ClutterActor *self,
if (!found_in_cache) if (!found_in_cache)
{ {
gfloat min_height, natural_height; gfloat minimum_height, natural_height;
ClutterActorClass *klass; ClutterActorClass *klass;
min_height = natural_height = 0; minimum_height = natural_height = 0;
CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width); 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 = CLUTTER_ACTOR_GET_CLASS (self);
klass->get_preferred_height (self, for_width, klass->get_preferred_height (self, for_width,
&min_height, &minimum_height,
&natural_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 /* Due to accumulated float errors, it's better not to warn
* on this, but just fix it. * on this, but just fix it.
*/ */
if (natural_height < min_height) if (natural_height < minimum_height)
natural_height = min_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->natural_size = natural_height;
cached_size_request->for_size = for_width; cached_size_request->for_size = for_width;
cached_size_request->age = priv->cached_height_age; 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)); 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 > /*< private >
* clutter_actor_adjust_allocation: * clutter_actor_adjust_allocation:
* @self: a #ClutterActor * @self: a #ClutterActor
@ -6697,8 +6814,6 @@ clutter_actor_adjust_allocation (ClutterActor *self,
float min_width, min_height; float min_width, min_height;
float nat_width, nat_height; float nat_width, nat_height;
ClutterRequestMode req_mode; ClutterRequestMode req_mode;
ClutterTextDirection text_dir;
const ClutterLayoutInfo *info;
adj_allocation = *allocation; adj_allocation = *allocation;
@ -6744,24 +6859,17 @@ clutter_actor_adjust_allocation (ClutterActor *self,
} }
#endif #endif
info = _clutter_actor_get_layout_info_or_defaults (self); clutter_actor_adjust_width (self,
text_dir = clutter_actor_get_text_direction (self); &min_width,
&nat_width,
&adj_allocation.x1,
&adj_allocation.x2);
CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width"); clutter_actor_adjust_height (self,
adjust_for_margin (info->margin.left, info->margin.right, &min_height,
&min_width, &nat_width, &nat_height,
&adj_allocation.x1, &adj_allocation.x2); &adj_allocation.y1,
adjust_for_alignment (effective_align (info->x_align, text_dir), &adj_allocation.y2);
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);
/* we maintain the invariant that an allocation cannot be adjusted /* we maintain the invariant that an allocation cannot be adjusted
* to be outside the parent-given box * to be outside the parent-given box
@ -8880,7 +8988,7 @@ clutter_actor_insert_child (ClutterActor *self,
ClutterActor *child) ClutterActor *child)
{ {
ClutterActorPrivate *priv = self->priv; 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 /* 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 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; return self->priv->y_expand_effective;
} }
/*< private > /**
* clutter_actor_queue_compute_expand: * clutter_actor_queue_compute_expand:
* @self: a #ClutterActor * @self: a #ClutterActor
* *
@ -13895,7 +14003,7 @@ clutter_actor_needs_y_expand (ClutterActor *self)
* *
* Since: 1.10 * Since: 1.10
*/ */
static void void
clutter_actor_queue_compute_expand (ClutterActor *self) clutter_actor_queue_compute_expand (ClutterActor *self)
{ {
ClutterActor *parent_actor; ClutterActor *parent_actor;
@ -13993,7 +14101,7 @@ clutter_actor_get_x_expand (ClutterActor *self)
/** /**
* clutter_actor_set_y_expand: * clutter_actor_set_y_expand:
* @self: a #ClutterActor * @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, * Sets whether a #ClutterActor should receive extra space when possible,
* during the allocation. * during the allocation.
@ -14114,7 +14222,7 @@ clutter_actor_get_x_align (ClutterActor *self)
/** /**
* clutter_actor_set_y_align: * clutter_actor_set_y_align:
* @self: a #ClutterActor * @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 * Sets the vertical alignment policy of a #ClutterActor, in case the
* actor received extra vertical space. * 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_get_y_expand (ClutterActor *self);
gboolean clutter_actor_needs_x_expand (ClutterActor *self); gboolean clutter_actor_needs_x_expand (ClutterActor *self);
gboolean clutter_actor_needs_y_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, void clutter_actor_set_x_align (ClutterActor *self,
ClutterActorAlign x_align); ClutterActorAlign x_align);

View File

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