Centralize computations of border and padding into StThemeNode

Rather than repeating the computation of borders in many different
widget subclasses, add helper functions:

 st_theme_node_adjust_for_height()
 st_theme_node_adjust_preferred_width()
 st_theme_node_adjust_for_width()
 st_theme_node_adjust_preferred_height()
 st_theme_node_get_content_box()

That are used in get_preferred_width()/get_preferred_height() and
allocate() methods to consistently apply the necessary adjustments.
This allows removing the StPadding type.

Queueing a relayout when the borders/padding change is moved from
st_widget_real_style_changed() to the invoking code to allow access
to the old StThemeNode for comparison. (Should this be added as
a parameter to the signal?)

Borders are included in the geometry adjustments, but borders
are not yet drawn.

https://bugzilla.gnome.org/show_bug.cgi?id=595993
This commit is contained in:
Owen W. Taylor 2009-09-20 13:41:13 -04:00
parent c1c4adda02
commit 0ce05a04c8
12 changed files with 448 additions and 387 deletions

View File

@ -198,23 +198,22 @@ st_bin_allocate (ClutterActor *self,
if (priv->child)
{
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
gfloat natural_width, natural_height;
gfloat min_width, min_height;
gfloat child_width, child_height;
gfloat available_width, available_height;
ClutterRequestMode request;
ClutterActorBox content_box;
ClutterActorBox allocation = { 0, };
StPadding padding = { 0, };
gdouble x_align, y_align;
st_theme_node_get_content_box (theme_node, box, &content_box);
_st_bin_get_align_factors (ST_BIN (self), &x_align, &y_align);
st_widget_get_padding (ST_WIDGET (self), &padding);
available_width = box->x2 - box->x1
- padding.left - padding.right;
available_height = box->y2 - box->y1
- padding.top - padding.bottom;
available_width = content_box.x2 - content_box.x1;
available_height = content_box.y2 - content_box.y1;
if (available_width < 0)
available_width = 0;
@ -224,14 +223,14 @@ st_bin_allocate (ClutterActor *self,
if (priv->x_fill)
{
allocation.x1 = (int) padding.left;
allocation.x2 = (int)(allocation.x1 + available_width);
allocation.x1 = (int) content_box.x1;
allocation.x2 = (int) content_box.x2;
}
if (priv->y_fill)
{
allocation.y1 = (int) padding.top;
allocation.y2 = (int)(allocation.y1 + available_height);
allocation.y1 = (int) content_box.y1;
allocation.y2 = (int) content_box.y2;
}
/* if we are filling horizontally and vertically then we're done */
@ -275,15 +274,13 @@ st_bin_allocate (ClutterActor *self,
if (!priv->x_fill)
{
allocation.x1 = (int)((available_width - child_width) * x_align
+ padding.left);
allocation.x1 = content_box.x1 + (int) ((available_width - child_width) * x_align);
allocation.x2 = allocation.x1 + child_width;
}
if (!priv->y_fill)
{
allocation.y1 = (int)((available_height - child_height) * y_align
+ padding.top);
allocation.y1 = content_box.y1 + (int) ((available_height - child_height) * y_align);
allocation.y2 = allocation.y1 + child_height;
}
@ -298,33 +295,26 @@ st_bin_get_preferred_width (ClutterActor *self,
gfloat *natural_width_p)
{
StBinPrivate *priv = ST_BIN (self)->priv;
gfloat min_width, natural_width;
StPadding padding = { 0, };
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
st_widget_get_padding (ST_WIDGET (self), &padding);
min_width = natural_width = padding.left + padding.right;
st_theme_node_adjust_for_height (theme_node, &for_height);
if (priv->child == NULL)
{
if (min_width_p)
*min_width_p = min_width;
*min_width_p = 0;
if (natural_width_p)
*natural_width_p = natural_width;
*natural_width_p = 0;
}
else
{
clutter_actor_get_preferred_width (priv->child, for_height,
min_width_p,
natural_width_p);
if (min_width_p)
*min_width_p += min_width;
if (natural_width_p)
*natural_width_p += natural_width;
}
st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
@ -334,33 +324,26 @@ st_bin_get_preferred_height (ClutterActor *self,
gfloat *natural_height_p)
{
StBinPrivate *priv = ST_BIN (self)->priv;
gfloat min_height, natural_height;
StPadding padding = { 0, };
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
st_widget_get_padding (ST_WIDGET (self), &padding);
min_height = natural_height = padding.top + padding.bottom;
st_theme_node_adjust_for_width (theme_node, &for_width);
if (priv->child == NULL)
{
if (min_height_p)
*min_height_p = min_height;
*min_height_p = 0;
if (natural_height_p)
*natural_height_p = natural_height;
*natural_height_p = 0;
}
else
{
clutter_actor_get_preferred_height (priv->child, for_width,
min_height_p,
natural_height_p);
if (min_height_p)
*min_height_p += min_height;
if (natural_height_p)
*natural_height_p += natural_height;
}
st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
@ -763,29 +746,3 @@ st_bin_get_fill (StBin *bin,
if (y_fill)
*y_fill = bin->priv->y_fill;
}
static gpointer
st_padding_copy (gpointer data)
{
return g_slice_dup (StPadding, data);
}
static void
st_padding_free (gpointer data)
{
if (G_LIKELY (data))
g_slice_free (StPadding, data);
}
GType
st_padding_get_type (void)
{
static GType our_type = 0;
if (G_UNLIKELY (our_type == 0))
our_type = g_boxed_type_register_static (I_("StPadding"),
st_padding_copy,
st_padding_free);
return our_type;
}

View File

@ -420,26 +420,18 @@ st_box_layout_dispose (GObject *object)
}
static void
st_box_layout_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
get_content_preferred_width (StBoxLayout *self,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (actor)->priv;
StPadding padding = { 0, };
StBoxLayoutPrivate *priv = self->priv;
gint n_children = 0;
gfloat min_width, natural_width;
GList *l;
st_widget_get_padding (ST_WIDGET (actor), &padding);
if (min_width_p)
*min_width_p = padding.left + padding.right;
if (natural_width_p)
*natural_width_p = padding.left + padding.right;
if (priv->children == NULL)
return;
min_width = 0;
natural_width = 0;
for (l = priv->children; l; l = g_list_next (l))
{
@ -457,55 +449,59 @@ st_box_layout_get_preferred_width (ClutterActor *actor,
if (priv->is_vertical)
{
if (min_width_p)
*min_width_p = MAX (child_min, *min_width_p);
if (natural_width_p)
*natural_width_p = MAX (child_nat, *natural_width_p);
min_width = MAX (child_min, min_width);
natural_width = MAX (child_nat, natural_width);
}
else
{
if (min_width_p)
*min_width_p += child_min;
if (natural_width_p)
*natural_width_p += child_nat;
min_width += child_min;
natural_width += child_nat;
}
}
if (!priv->is_vertical && n_children > 1)
{
if (min_width_p)
*min_width_p += priv->spacing * (n_children - 1);
if (natural_width_p)
*natural_width_p += priv->spacing * (n_children - 1);
min_width += priv->spacing * (n_children - 1);
natural_width += priv->spacing * (n_children - 1);
}
if (min_width_p)
*min_width_p = min_width;
if (natural_width_p)
*natural_width_p = natural_width;
}
static void
st_box_layout_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
st_box_layout_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (actor)->priv;
StPadding padding = { 0, };
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
st_theme_node_adjust_for_height (theme_node, &for_height);
get_content_preferred_width (ST_BOX_LAYOUT (actor), for_height,
min_width_p, natural_width_p);
st_theme_node_adjust_preferred_width (theme_node,
min_width_p, natural_width_p);
}
static void
get_content_preferred_height (StBoxLayout *self,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
StBoxLayoutPrivate *priv = self->priv;
gint n_children = 0;
gfloat min_height, natural_height;
GList *l;
st_widget_get_padding (ST_WIDGET (actor), &padding);
if (min_height_p)
*min_height_p = padding.top + padding.bottom;
if (natural_height_p)
*natural_height_p = padding.top + padding.bottom;
if (priv->children == NULL)
return;
min_height = 0;
natural_height = 0;
for (l = priv->children; l; l = g_list_next (l))
{
@ -523,30 +519,44 @@ st_box_layout_get_preferred_height (ClutterActor *actor,
if (!priv->is_vertical)
{
if (min_height_p)
*min_height_p = MAX (child_min, *min_height_p);
if (natural_height_p)
*natural_height_p = MAX (child_nat, *natural_height_p);
min_height = MAX (child_min, min_height);
natural_height = MAX (child_nat, natural_height);
}
else
{
if (min_height_p)
*min_height_p += child_min;
if (natural_height_p)
*natural_height_p += child_nat;
min_height += child_min;
natural_height += child_nat;
}
}
if (priv->is_vertical && n_children > 1)
{
if (min_height_p)
*min_height_p += priv->spacing * (n_children - 1);
if (natural_height_p)
*natural_height_p += priv->spacing * (n_children - 1);
min_height += priv->spacing * (n_children - 1);
natural_height += priv->spacing * (n_children - 1);
}
if (min_height_p)
*min_height_p = min_height;
if (natural_height_p)
*natural_height_p = natural_height;
}
static void
st_box_layout_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
st_theme_node_adjust_for_width (theme_node, &for_width);
get_content_preferred_height (ST_BOX_LAYOUT (actor), for_width,
min_height_p, natural_height_p);
st_theme_node_adjust_preferred_height (theme_node,
min_height_p, natural_height_p);
}
static void
@ -555,8 +565,9 @@ st_box_layout_allocate (ClutterActor *actor,
ClutterAllocationFlags flags)
{
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (actor)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
ClutterActorBox content_box;
gfloat avail_width, avail_height, pref_width, pref_height;
StPadding padding = { 0, };
gfloat position = 0;
GList *l;
gint n_expand_children, extra_space;
@ -567,18 +578,15 @@ st_box_layout_allocate (ClutterActor *actor,
if (priv->children == NULL)
return;
st_widget_get_padding (ST_WIDGET (actor), &padding);
avail_width = box->x2 - box->x1
- padding.left
- padding.right;
avail_height = box->y2 - box->y1
- padding.top
- padding.bottom;
st_theme_node_get_content_box (theme_node, box, &content_box);
st_box_layout_get_preferred_height (actor, avail_width, NULL,
&pref_height);
st_box_layout_get_preferred_width (actor, avail_height, NULL,
&pref_width);
avail_width = content_box.x2 - content_box.x1;
avail_height = content_box.y2 - content_box.y1;
get_content_preferred_height (ST_BOX_LAYOUT (actor), avail_width,
NULL, &pref_height);
get_content_preferred_width (ST_BOX_LAYOUT (actor), avail_height,
NULL, &pref_width);
/* update adjustments for scrolling */
if (priv->vadjustment)
@ -644,9 +652,9 @@ st_box_layout_allocate (ClutterActor *actor,
}
if (priv->is_vertical)
position = padding.top;
position = content_box.y1;
else
position = padding.left;
position = content_box.x1;
if (priv->is_pack_start)
l = g_list_last (priv->children);
@ -684,8 +692,8 @@ st_box_layout_allocate (ClutterActor *actor,
child_box.y2 = position + child_nat + extra_space;
else
child_box.y2 = position + child_nat;
child_box.x1 = padding.left;
child_box.x2 = avail_width;
child_box.x1 = content_box.x1;
child_box.x2 = content_box.x2;
_st_allocate_fill (child, &child_box, xalign, yalign, xfill, yfill);
clutter_actor_allocate (child, &child_box, flags);
@ -708,8 +716,8 @@ st_box_layout_allocate (ClutterActor *actor,
else
child_box.x2 = position + child_nat;
child_box.y1 = padding.top;
child_box.y2 = avail_height;
child_box.y1 = content_box.y1;
child_box.y2 = content_box.y2;
_st_allocate_fill (child, &child_box, xalign, yalign, xfill, yfill);
clutter_actor_allocate (child, &child_box, flags);

View File

@ -205,12 +205,10 @@ st_entry_get_preferred_width (ClutterActor *actor,
gfloat *natural_width_p)
{
StEntryPrivate *priv = ST_ENTRY_PRIV (actor);
StPadding padding;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
gfloat icon_w;
st_widget_get_padding (ST_WIDGET (actor), &padding);
for_height -= padding.top + padding.bottom;
st_theme_node_adjust_for_height (theme_node, &for_height);
clutter_actor_get_preferred_width (priv->entry, for_height,
min_width_p,
@ -239,11 +237,7 @@ st_entry_get_preferred_width (ClutterActor *actor,
*natural_width_p += icon_w + priv->spacing;
}
if (min_width_p)
*min_width_p += padding.left + padding.right;
if (natural_width_p)
*natural_width_p += padding.left + padding.right;
st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
@ -253,12 +247,10 @@ st_entry_get_preferred_height (ClutterActor *actor,
gfloat *natural_height_p)
{
StEntryPrivate *priv = ST_ENTRY_PRIV (actor);
StPadding padding;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
gfloat icon_h;
st_widget_get_padding (ST_WIDGET (actor), &padding);
for_width -= padding.left + padding.right;
st_theme_node_adjust_for_width (theme_node, &for_width);
clutter_actor_get_preferred_height (priv->entry, for_width,
min_height_p,
@ -288,11 +280,7 @@ st_entry_get_preferred_height (ClutterActor *actor,
*natural_height_p = icon_h;
}
if (min_height_p)
*min_height_p += padding.top + padding.bottom;
if (natural_height_p)
*natural_height_p += padding.top + padding.bottom;
st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
@ -301,21 +289,21 @@ st_entry_allocate (ClutterActor *actor,
ClutterAllocationFlags flags)
{
StEntryPrivate *priv = ST_ENTRY_PRIV (actor);
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
ClutterActorClass *parent_class;
ClutterActorBox child_box, icon_box;
StPadding padding;
ClutterActorBox content_box, child_box, icon_box;
gfloat icon_w, icon_h;
gfloat entry_h, min_h, pref_h, avail_h;
st_widget_get_padding (ST_WIDGET (actor), &padding);
parent_class = CLUTTER_ACTOR_CLASS (st_entry_parent_class);
parent_class->allocate (actor, box, flags);
avail_h = (box->y2 - box->y1) - padding.top - padding.bottom;
st_theme_node_get_content_box (theme_node, box, &content_box);
child_box.x1 = padding.left;
child_box.x2 = box->x2 - box->x1 - padding.right;
avail_h = content_box.y2 - content_box.y1;
child_box.x1 = content_box.x1;
child_box.x2 = content_box.x2;
if (priv->primary_icon)
{
@ -324,10 +312,10 @@ st_entry_allocate (ClutterActor *actor,
clutter_actor_get_preferred_height (priv->primary_icon,
-1, NULL, &icon_h);
icon_box.x1 = padding.left;
icon_box.x1 = content_box.x1;
icon_box.x2 = icon_box.x1 + icon_w;
icon_box.y1 = (int)(padding.top + avail_h / 2 - icon_h / 2);
icon_box.y1 = (int) (content_box.y1 + avail_h / 2 - icon_h / 2);
icon_box.y2 = icon_box.y1 + icon_h;
clutter_actor_allocate (priv->primary_icon,
@ -345,10 +333,10 @@ st_entry_allocate (ClutterActor *actor,
clutter_actor_get_preferred_height (priv->secondary_icon,
-1, NULL, &icon_h);
icon_box.x2 = (box->x2 - box->x1) - padding.right;
icon_box.x2 = content_box.x2;
icon_box.x1 = icon_box.x2 - icon_w;
icon_box.y1 = (int)(padding.top + avail_h / 2 - icon_h / 2);
icon_box.y1 = (int) (content_box.y1 + avail_h / 2 - icon_h / 2);
icon_box.y2 = icon_box.y1 + icon_h;
clutter_actor_allocate (priv->secondary_icon,
@ -364,7 +352,7 @@ st_entry_allocate (ClutterActor *actor,
entry_h = CLAMP (pref_h, min_h, avail_h);
child_box.y1 = (int)(padding.top + avail_h / 2 - entry_h / 2);
child_box.y1 = (int) (content_box.y1 + avail_h / 2 - entry_h / 2);
child_box.y2 = child_box.y1 + entry_h;
clutter_actor_allocate (priv->entry, &child_box, flags);

View File

@ -131,19 +131,15 @@ st_label_get_preferred_width (ClutterActor *actor,
gfloat *natural_width_p)
{
StLabelPrivate *priv = ST_LABEL (actor)->priv;
StPadding padding = { 0, };
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
st_widget_get_padding (ST_WIDGET (actor), &padding);
st_theme_node_adjust_for_height (theme_node, &for_height);
clutter_actor_get_preferred_width (priv->label, for_height,
min_width_p,
natural_width_p);
if (min_width_p)
*min_width_p += padding.left + padding.right;
if (natural_width_p)
*natural_width_p += padding.left + padding.right;
st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
@ -153,19 +149,15 @@ st_label_get_preferred_height (ClutterActor *actor,
gfloat *natural_height_p)
{
StLabelPrivate *priv = ST_LABEL (actor)->priv;
StPadding padding = { 0, };
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
st_widget_get_padding (ST_WIDGET (actor), &padding);
st_theme_node_adjust_for_width (theme_node, &for_width);
clutter_actor_get_preferred_height (priv->label, for_width,
min_height_p,
natural_height_p);
if (min_height_p)
*min_height_p += padding.top + padding.bottom;
if (natural_height_p)
*natural_height_p += padding.top + padding.bottom;
st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
@ -174,21 +166,16 @@ st_label_allocate (ClutterActor *actor,
ClutterAllocationFlags flags)
{
StLabelPrivate *priv = ST_LABEL (actor)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
ClutterActorClass *parent_class;
ClutterActorBox child_box;
StPadding padding = { 0, };
ClutterActorBox content_box;
st_widget_get_padding (ST_WIDGET (actor), &padding);
st_theme_node_get_content_box (theme_node, box, &content_box);
parent_class = CLUTTER_ACTOR_CLASS (st_label_parent_class);
parent_class->allocate (actor, box, flags);
child_box.x1 = padding.left;
child_box.y1 = padding.top;
child_box.x2 = box->x2 - box->x1 - padding.right;
child_box.y2 = box->y2 - box->y1 - padding.bottom;
clutter_actor_allocate (priv->label, &child_box, flags);
clutter_actor_allocate (priv->label, &content_box, flags);
}
static void

View File

@ -269,71 +269,65 @@ st_scroll_bar_allocate (ClutterActor *actor,
ClutterAllocationFlags flags)
{
StScrollBarPrivate *priv = ST_SCROLL_BAR (actor)->priv;
StPadding padding;
ClutterActorBox bw_box, fw_box, trough_box;
gfloat x, y, width, height, stepper_size;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
ClutterActorBox content_box, bw_box, fw_box, trough_box;
gfloat stepper_size;
/* Chain up */
CLUTTER_ACTOR_CLASS (st_scroll_bar_parent_class)->
allocate (actor, box, flags);
st_widget_get_padding (ST_WIDGET (actor), &padding);
/* calculate the child area */
x = padding.left;
y = padding.top;
width = (box->x2 - box->x1) - padding.left - padding.right;
height = (box->y2 - box->y1) - padding.top - padding.bottom;
st_theme_node_get_content_box (theme_node, box, &content_box);
if (priv->vertical)
{
stepper_size = width;
stepper_size = content_box.x2 - content_box.x1;
/* Backward stepper */
bw_box.x1 = x;
bw_box.y1 = y;
bw_box.x2 = bw_box.x1 + stepper_size;
bw_box.x1 = content_box.x1;
bw_box.y1 = content_box.y1;
bw_box.x2 = content_box.x2;
bw_box.y2 = bw_box.y1 + stepper_size;
clutter_actor_allocate (priv->bw_stepper, &bw_box, flags);
/* Forward stepper */
fw_box.x1 = x;
fw_box.y1 = y + height - stepper_size;
fw_box.x2 = fw_box.x1 + stepper_size;
fw_box.y2 = fw_box.y1 + stepper_size;
fw_box.x1 = content_box.x1;
fw_box.y1 = content_box.y2 - stepper_size;
fw_box.x2 = content_box.x2;
fw_box.y2 = content_box.y2;
clutter_actor_allocate (priv->fw_stepper, &fw_box, flags);
/* Trough */
trough_box.x1 = x;
trough_box.y1 = y + stepper_size;
trough_box.x2 = x + width;
trough_box.y2 = y + height - stepper_size;
trough_box.x1 = content_box.x1;
trough_box.y1 = content_box.y1 + stepper_size;
trough_box.x2 = content_box.x2;
trough_box.y2 = content_box.y2 - stepper_size;
clutter_actor_allocate (priv->trough, &trough_box, flags);
}
else
{
stepper_size = height;
stepper_size = content_box.y2 - content_box.y1;
/* Backward stepper */
bw_box.x1 = x;
bw_box.y1 = y;
bw_box.x1 = content_box.x1;
bw_box.y1 = content_box.y1;
bw_box.x2 = bw_box.x1 + stepper_size;
bw_box.y2 = bw_box.y1 + stepper_size;
bw_box.y2 = content_box.y2;
clutter_actor_allocate (priv->bw_stepper, &bw_box, flags);
/* Forward stepper */
fw_box.x1 = x + width - stepper_size;
fw_box.y1 = y;
fw_box.x2 = fw_box.x1 + stepper_size;
fw_box.y2 = fw_box.y1 + stepper_size;
fw_box.x1 = content_box.x2 - stepper_size;
fw_box.y1 = content_box.y1;
fw_box.x2 = content_box.x2;
fw_box.y2 = content_box.y2;
clutter_actor_allocate (priv->fw_stepper, &fw_box, flags);
/* Trough */
trough_box.x1 = x + stepper_size;
trough_box.y1 = y;
trough_box.x2 = x + width - stepper_size;
trough_box.y2 = y + height;
trough_box.x1 = content_box.x1 + stepper_size;
trough_box.y1 = content_box.y1;
trough_box.x2 = content_box.x2 - stepper_size;
trough_box.y2 = content_box.y2;
clutter_actor_allocate (priv->trough, &trough_box, flags);
}
@ -371,27 +365,27 @@ st_scroll_bar_allocate (ClutterActor *actor,
if (priv->vertical)
{
avail_size = height - stepper_size * 2;
avail_size = content_box.y2 - content_box.y1 - stepper_size * 2;
handle_size = increment * avail_size;
handle_size = CLAMP (handle_size, min_size, max_size);
handle_box.x1 = x;
handle_box.x1 = content_box.x1;
handle_box.y1 = bw_box.y2 + position * (avail_size - handle_size);
handle_box.x2 = handle_box.x1 + width;
handle_box.x2 = content_box.x2;
handle_box.y2 = handle_box.y1 + handle_size;
}
else
{
avail_size = width - stepper_size * 2;
avail_size = content_box.x2 - content_box.x1 - stepper_size * 2;
handle_size = increment * avail_size;
handle_size = CLAMP (handle_size, min_size, max_size);
handle_box.x1 = bw_box.x2 + position * (avail_size - handle_size);
handle_box.y1 = y;
handle_box.y1 = content_box.y1;
handle_box.x2 = handle_box.x1 + handle_size;
handle_box.y2 = handle_box.y1 + height;
handle_box.y2 = content_box.y2;
}
/* snap to pixel */

View File

@ -207,14 +207,13 @@ st_scroll_view_get_preferred_width (ClutterActor *actor,
gfloat *min_width_p,
gfloat *natural_width_p)
{
StPadding padding;
StScrollViewPrivate *priv = ST_SCROLL_VIEW (actor)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
if (!priv->child)
return;
st_widget_get_padding (ST_WIDGET (actor), &padding);
st_theme_node_adjust_for_height (theme_node, &for_height);
/* Our natural width is the natural width of the child */
clutter_actor_get_preferred_width (priv->child,
@ -234,12 +233,10 @@ st_scroll_view_get_preferred_width (ClutterActor *actor,
*natural_width_p += get_scrollbar_width (ST_SCROLL_VIEW (actor));
}
/* Add space for padding */
if (min_width_p)
*min_width_p = padding.left + padding.right;
*min_width_p = 0;
if (natural_width_p)
*natural_width_p += padding.left + padding.right;
st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
@ -248,14 +245,13 @@ st_scroll_view_get_preferred_height (ClutterActor *actor,
gfloat *min_height_p,
gfloat *natural_height_p)
{
StPadding padding;
StScrollViewPrivate *priv = ST_SCROLL_VIEW (actor)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
if (!priv->child)
return;
st_widget_get_padding (ST_WIDGET (actor), &padding);
st_theme_node_adjust_for_width (theme_node, &for_width);
/* Our natural height is the natural height of the child */
clutter_actor_get_preferred_height (priv->child,
@ -275,12 +271,10 @@ st_scroll_view_get_preferred_height (ClutterActor *actor,
*natural_height_p += get_scrollbar_height (ST_SCROLL_VIEW (actor));
}
/* Add space for padding */
if (min_height_p)
*min_height_p = padding.top + padding.bottom;
*min_height_p = 0;
if (natural_height_p)
*natural_height_p += padding.top + padding.bottom;
st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
@ -288,12 +282,12 @@ st_scroll_view_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
StPadding padding;
ClutterActorBox child_box;
ClutterActorBox content_box, child_box;
ClutterActorClass *parent_parent_class;
gfloat avail_width, avail_height, sb_width, sb_height;
StScrollViewPrivate *priv = ST_SCROLL_VIEW (actor)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
/* Chain up to the parent's parent class
*
@ -308,10 +302,10 @@ st_scroll_view_allocate (ClutterActor *actor,
allocate (actor, box, flags);
st_widget_get_padding (ST_WIDGET (actor), &padding);
st_theme_node_get_content_box (theme_node, box, &content_box);
avail_width = (box->x2 - box->x1) - padding.left - padding.right;
avail_height = (box->y2 - box->y1) - padding.top - padding.bottom;
avail_width = content_box.x2 - content_box.x1;
avail_height = content_box.y2 - content_box.y1;
sb_width = get_scrollbar_width (ST_SCROLL_VIEW (actor));
sb_height = get_scrollbar_width (ST_SCROLL_VIEW (actor));
@ -325,10 +319,10 @@ st_scroll_view_allocate (ClutterActor *actor,
/* Vertical scrollbar */
if (CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
{
child_box.x1 = avail_width - sb_width;
child_box.y1 = padding.top;
child_box.x2 = avail_width;
child_box.y2 = child_box.y1 + avail_height - sb_height;
child_box.x1 = content_box.x2 - sb_width;
child_box.y1 = content_box.y1;
child_box.x2 = content_box.x2;
child_box.y2 = content_box.y2 - sb_height;
clutter_actor_allocate (priv->vscroll, &child_box, flags);
}
@ -336,20 +330,20 @@ st_scroll_view_allocate (ClutterActor *actor,
/* Horizontal scrollbar */
if (CLUTTER_ACTOR_IS_VISIBLE (priv->hscroll))
{
child_box.x1 = padding.left;
child_box.x2 = child_box.x1 + avail_width - sb_width;
child_box.y1 = avail_height - sb_height;
child_box.y2 = avail_height;
child_box.x1 = content_box.x1;
child_box.y1 = content_box.y2 - sb_height;
child_box.x2 = content_box.x2 - sb_width;
child_box.y2 = content_box.y2;
clutter_actor_allocate (priv->hscroll, &child_box, flags);
}
/* Child */
child_box.x1 = padding.left;
child_box.x2 = avail_width - sb_width;
child_box.y1 = padding.top;
child_box.y2 = avail_height - sb_height;
child_box.x1 = content_box.x1;
child_box.y1 = content_box.y1;
child_box.x2 = content_box.x2 - sb_width;
child_box.y2 = content_box.y2 - sb_height;
if (priv->child)
clutter_actor_allocate (priv->child, &child_box, flags);

View File

@ -1,5 +1,6 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include <math.h>
#include <stdlib.h>
#include <string.h>
@ -1919,3 +1920,183 @@ st_theme_node_get_background_theme_image (StThemeNode *node)
return NULL;
}
static float
get_width_inc (StThemeNode *node)
{
return (round (node->border_width[ST_SIDE_LEFT]) + node->padding[ST_SIDE_LEFT] +
round (node->border_width[ST_SIDE_RIGHT]) + node->padding[ST_SIDE_RIGHT]);
}
static float
get_height_inc (StThemeNode *node)
{
return (round (node->border_width[ST_SIDE_TOP]) + node->padding[ST_SIDE_TOP] +
round (node->border_width[ST_SIDE_BOTTOM]) + node->padding[ST_SIDE_BOTTOM]);
}
/**
* st_theme_node_adjust_for_height:
* @node: a #StThemeNode
* @for_height: (inout): the "for height" to adjust
*
* Adjusts a "for height" passed to clutter_actor_get_preferred_width() to
* account for borders and padding. This is a convenience function meant
* to be called from a get_preferred_width() method of a #ClutterActor
* subclass. The value after adjustment is the height available for the actor's
* content.
*/
void
st_theme_node_adjust_for_height (StThemeNode *node,
float *for_height)
{
g_return_if_fail (ST_IS_THEME_NODE (node));
g_return_if_fail (for_height != NULL);
if (*for_height >= 0)
{
float height_inc = get_height_inc (node);
*for_height = MAX (0, *for_height - height_inc);
}
}
/**
* st_theme_node_adjust_preferred_width:
* @node: a #StThemeNode
* @min_width_p: (inout) (allow-none): the width to adjust
* @for_height: (inout): the height to adjust
*
* Adjusts the minimum and natural width computed for an actor by
* adding on the necessary space for borders and padding. This is a
* convenience function meant to be called from the get_preferred_width()
* method of a #ClutterActor subclass
*/
void
st_theme_node_adjust_preferred_width (StThemeNode *node,
float *min_width_p,
float *natural_width_p)
{
float width_inc;
g_return_if_fail (ST_IS_THEME_NODE (node));
ensure_borders (node);
width_inc = get_width_inc (node);
if (min_width_p)
*min_width_p += width_inc;
if (natural_width_p)
*natural_width_p += width_inc;
}
/**
* st_theme_node_adjust_for_width:
* @node: a #StThemeNode
* @for_width: (inout): the "for width" to adjust
*
* Adjusts a "for width" passed to clutter_actor_get_preferred_height() to
* account for borders and padding. This is a convenience function meant
* to be called from a get_preferred_height() method of a #ClutterActor
* subclass. The value after adjustmnet is the width available for the actor's
* content.
*/
void
st_theme_node_adjust_for_width (StThemeNode *node,
float *for_width)
{
g_return_if_fail (ST_IS_THEME_NODE (node));
g_return_if_fail (for_width != NULL);
if (*for_width >= 0)
{
float width_inc = get_width_inc (node);
*for_width = MAX (0, *for_width - width_inc);
}
}
/**
* st_theme_node_adjust_preferred_height:
* @node: a #StThemeNode
* @min_height_p: (inout) (allow-none): the height to adjust
* @for_height: (inout): the height to adjust
*
* Adjusts the minimum and natural height computed for an actor by
* adding on the necessary space for borders and padding. This is a
* convenience function meant to be called from the get_preferred_height()
* method of a #ClutterActor subclass
*/
void
st_theme_node_adjust_preferred_height (StThemeNode *node,
float *min_height_p,
float *natural_height_p)
{
float height_inc;
g_return_if_fail (ST_IS_THEME_NODE (node));
ensure_borders (node);
height_inc = get_height_inc (node);
if (min_height_p)
*min_height_p += height_inc;
if (natural_height_p)
*natural_height_p += height_inc;
}
/**
* st_theme_node_get_content_box:
* @node: a #StThemeNode
* @allocation: the box allocated to a #ClutterAlctor
* @content_box: (out): computed box occupied by the actor's content
*
* Gets the box within an actor's allocation that contents the content
* of an actor (excluding borders and padding). This is a convenience function
* meant to be used from the allocate() or paint() methods of a #ClutterActor
* subclass.
*/
void
st_theme_node_get_content_box (StThemeNode *node,
const ClutterActorBox *allocation,
ClutterActorBox *content_box)
{
g_return_if_fail (ST_IS_THEME_NODE (node));
ensure_borders (node);
content_box->x1 = round (node->border_width[ST_SIDE_LEFT]) + node->padding[ST_SIDE_LEFT];
content_box->y1 = round (node->border_width[ST_SIDE_TOP]) + node->padding[ST_SIDE_TOP];
content_box->x2 = allocation->x2 - allocation->x1 - (round (node->border_width[ST_SIDE_RIGHT]) + node->padding[ST_SIDE_RIGHT]);
content_box->y2 = allocation->y2 - allocation->y1 - (round (node->border_width[ST_SIDE_BOTTOM]) + node->padding[ST_SIDE_BOTTOM]);
}
/**
* st_theme_node_geometry_equal:
* @node: a #StThemeNode
* @node: a different #StThemeNode
*
* Tests if two theme nodes have the same borders and padding; this can be
* used to optimize having to relayout when the style applied to a Clutter
* actor changes colors without changing the geometry.
*/
gboolean
st_theme_node_geometry_equal (StThemeNode *node,
StThemeNode *other)
{
StSide side;
ensure_borders (node);
ensure_borders (other);
for (side = ST_SIDE_TOP; side <= ST_SIDE_LEFT; side++)
{
if (node->border_width[side] != other->border_width[side])
return FALSE;
if (node->padding[side] != other->padding[side])
return FALSE;
}
return TRUE;
}

View File

@ -121,6 +121,26 @@ const PangoFontDescription *st_theme_node_get_font (StThemeNode *node);
*/
StThemeImage *st_theme_node_get_background_theme_image (StThemeNode *node);
/* Helpers for get_preferred_width()/get_preferred_height() ClutterActor vfuncs */
void st_theme_node_adjust_for_height (StThemeNode *node,
float *for_height);
void st_theme_node_adjust_preferred_width (StThemeNode *node,
float *min_width_p,
float *natural_width_p);
void st_theme_node_adjust_for_width (StThemeNode *node,
float *for_width);
void st_theme_node_adjust_preferred_height (StThemeNode *node,
float *min_height_p,
float *natural_height_p);
/* Helper for allocate() ClutterActor vfunc */
void st_theme_node_get_content_box (StThemeNode *node,
const ClutterActorBox *actor_box,
ClutterActorBox *content_box);
gboolean st_theme_node_geometry_equal (StThemeNode *node,
StThemeNode *other);
G_END_DECLS
#endif /* __ST_THEME_NODE_H__ */

View File

@ -147,12 +147,12 @@ st_tooltip_get_preferred_width (ClutterActor *self,
gfloat *natural_width_p)
{
StTooltipPrivate *priv = ST_TOOLTIP (self)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
gfloat min_label_w, natural_label_w;
gfloat label_height, arrow_height;
ClutterActor *arrow_image;
StPadding padding;
st_widget_get_padding (ST_WIDGET (self), &padding);
st_theme_node_adjust_for_height (theme_node, &for_height);
arrow_image = st_widget_get_background_image (ST_WIDGET (self));
if (arrow_image)
@ -169,7 +169,7 @@ st_tooltip_get_preferred_width (ClutterActor *self,
if (for_height > -1)
{
label_height = for_height - arrow_height - padding.top - padding.bottom;
label_height = for_height - arrow_height;
}
else
{
@ -189,16 +189,7 @@ st_tooltip_get_preferred_width (ClutterActor *self,
natural_label_w = 0;
}
if (min_width_p)
{
*min_width_p = padding.left + padding.right + min_label_w;
}
if (natural_width_p)
{
*natural_width_p = padding.left + padding.right + natural_label_w;
}
st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
@ -208,11 +199,12 @@ st_tooltip_get_preferred_height (ClutterActor *self,
gfloat *natural_height_p)
{
StTooltipPrivate *priv = ST_TOOLTIP (self)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
gfloat arrow_height;
gfloat min_label_h, natural_label_h;
gfloat label_width;
ClutterActor *arrow_image;
StPadding padding;
st_theme_node_adjust_for_width (theme_node, &for_width);
arrow_image = st_widget_get_background_image (ST_WIDGET (self));
@ -227,21 +219,11 @@ st_tooltip_get_preferred_height (ClutterActor *self,
{
arrow_height = 0;
}
st_widget_get_padding (ST_WIDGET (self), &padding);
if (for_width > -1)
{
label_width = for_width - padding.left - padding.right;
}
else
{
label_width = -1;
}
if (priv->label)
{
clutter_actor_get_preferred_height (priv->label,
label_width,
for_width,
&min_label_h,
&natural_label_h);
}
@ -252,16 +234,12 @@ st_tooltip_get_preferred_height (ClutterActor *self,
}
if (min_height_p)
{
*min_height_p = padding.top + padding.bottom
+ arrow_height + min_label_h;
}
*min_height_p = arrow_height + min_label_h;
if (natural_height_p)
{
*natural_height_p = padding.top + padding.bottom
+ arrow_height + natural_label_h;
}
*natural_height_p = arrow_height + natural_label_h;
st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
@ -270,16 +248,16 @@ st_tooltip_allocate (ClutterActor *self,
ClutterAllocationFlags flags)
{
StTooltipPrivate *priv = ST_TOOLTIP (self)->priv;
ClutterActorBox child_box, arrow_box;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
ClutterActorBox content_box, child_box, arrow_box;
gfloat arrow_height, arrow_width;
ClutterActor *border_image, *arrow_image;
StPadding padding;
CLUTTER_ACTOR_CLASS (st_tooltip_parent_class)->allocate (self,
box,
flags);
st_widget_get_padding (ST_WIDGET (self), &padding);
st_theme_node_get_content_box (theme_node, box, &content_box);
arrow_image = st_widget_get_background_image (ST_WIDGET (self));
@ -314,11 +292,8 @@ st_tooltip_allocate (ClutterActor *self,
if (priv->label)
{
/* now remove the padding */
child_box.y1 += padding.top;
child_box.x1 += padding.left;
child_box.x2 -= padding.right;
child_box.y2 -= padding.bottom;
child_box = content_box;
child_box.y1 += arrow_height;
clutter_actor_allocate (priv->label, &child_box, flags);
}
@ -456,7 +431,7 @@ st_tooltip_update_position (StTooltip *tooltip)
return;
}
/* we need to have a style in case there are padding values to take into
/* we need to have a style in case there are padding/border values to take into
* account when calculating width/height */
st_widget_ensure_style ((StWidget *) tooltip);

View File

@ -37,29 +37,6 @@
G_BEGIN_DECLS
#define ST_TYPE_PADDING (st_padding_get_type ())
typedef struct _StPadding StPadding;
/**
* StPadding:
* @top: padding from the top
* @right: padding from the right
* @bottom: padding from the bottom
* @left: padding from the left
*
* The padding from the internal border of the parent container.
*/
struct _StPadding
{
gfloat top;
gfloat right;
gfloat bottom;
gfloat left;
};
GType st_padding_get_type (void) G_GNUC_CONST;
typedef enum {
ST_ALIGN_START,
ST_ALIGN_MIDDLE,

View File

@ -28,6 +28,7 @@
#include "config.h"
#endif
#include <math.h>
#include <stdlib.h>
#include <string.h>
@ -42,14 +43,13 @@
#include "st-theme-context.h"
#include "st-tooltip.h"
#include <big/rectangle.h>
/*
* Forward declaration for sake of StWidgetChild
*/
struct _StWidgetPrivate
{
StPadding border;
StPadding padding;
StTheme *theme;
StThemeNode *theme_node;
gchar *pseudo_class;
@ -106,6 +106,9 @@ G_DEFINE_ABSTRACT_TYPE (StWidget, st_widget, CLUTTER_TYPE_ACTOR);
#define ST_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_WIDGET, StWidgetPrivate))
static void st_widget_recompute_style (StWidget *widget,
StThemeNode *old_theme_node);
static void
st_widget_set_property (GObject *gobject,
guint prop_id,
@ -484,7 +487,6 @@ st_widget_real_style_changed (StWidget *self)
const char *bg_file = NULL;
gboolean relayout_needed = FALSE;
gboolean has_changed = FALSE;
StPadding padding;
ClutterColor color;
/* application has request this widget is not stylable */
@ -500,21 +502,6 @@ st_widget_real_style_changed (StWidget *self)
has_changed = TRUE;
}
padding.top = st_theme_node_get_padding (theme_node, ST_SIDE_TOP);
padding.right = st_theme_node_get_padding (theme_node, ST_SIDE_RIGHT);
padding.bottom = st_theme_node_get_padding (theme_node, ST_SIDE_BOTTOM);
padding.left = st_theme_node_get_padding (theme_node, ST_SIDE_LEFT);
if (priv->padding.top != padding.top ||
priv->padding.left != padding.left ||
priv->padding.right != padding.right ||
priv->padding.bottom != padding.bottom)
{
priv->padding = padding;
has_changed = TRUE;
relayout_needed = TRUE;
}
if (priv->border_image)
{
clutter_actor_unparent (priv->border_image);
@ -597,18 +584,21 @@ st_widget_real_style_changed (StWidget *self)
void
st_widget_style_changed (StWidget *widget)
{
StThemeNode *old_theme_node = NULL;
widget->priv->is_style_dirty = TRUE;
if (widget->priv->theme_node)
{
g_object_unref (widget->priv->theme_node);
old_theme_node = widget->priv->theme_node;
widget->priv->theme_node = NULL;
}
/* update the style only if we are mapped */
if (!CLUTTER_ACTOR_IS_MAPPED (CLUTTER_ACTOR (widget)))
return;
if (CLUTTER_ACTOR_IS_MAPPED (CLUTTER_ACTOR (widget)))
st_widget_recompute_style (widget, old_theme_node);
st_widget_ensure_style (widget);
if (old_theme_node)
g_object_unref (old_theme_node);
}
static void
@ -1064,6 +1054,20 @@ st_widget_init (StWidget *actor)
g_signal_connect (actor, "notify::name", G_CALLBACK (st_widget_name_notify), NULL);
}
static void
st_widget_recompute_style (StWidget *widget,
StThemeNode *old_theme_node)
{
StThemeNode *new_theme_node = st_widget_get_theme_node (widget);
if (!old_theme_node ||
!st_theme_node_geometry_equal (old_theme_node, new_theme_node))
clutter_actor_queue_relayout ((ClutterActor *) widget);
g_signal_emit (widget, signals[STYLE_CHANGED], 0);
widget->priv->is_style_dirty = FALSE;
}
/**
* st_widget_ensure_style:
* @widget: A #StWidget
@ -1077,10 +1081,7 @@ st_widget_ensure_style (StWidget *widget)
g_return_if_fail (ST_IS_WIDGET (widget));
if (widget->priv->is_style_dirty)
{
g_signal_emit (widget, signals[STYLE_CHANGED], 0);
widget->priv->is_style_dirty = FALSE;
}
st_widget_recompute_style (widget, NULL);
}
/**
@ -1117,25 +1118,6 @@ st_widget_get_background_image (StWidget *actor)
return priv->background_image;
}
/**
* st_widget_get_padding:
* @widget: A #StWidget
* @padding: A pointer to an #StPadding to fill
*
* Gets the padding of the widget, set using the "padding" CSS property. This
* function should normally only be used by subclasses.
*
*/
void
st_widget_get_padding (StWidget *widget,
StPadding *padding)
{
g_return_if_fail (ST_IS_WIDGET (widget));
g_return_if_fail (padding != NULL);
*padding = widget->priv->padding;
}
/**
* st_widget_set_has_tooltip:
* @widget: A #StWidget

View File

@ -112,8 +112,6 @@ StThemeNode *st_widget_get_theme_node (StWidget *widget);
ClutterActor *st_widget_get_background_image (StWidget *actor);
ClutterActor *st_widget_get_border_image (StWidget *actor);
void st_widget_get_padding (StWidget *widget,
StPadding *padding);
void st_widget_draw_background (StWidget *widget);
G_END_DECLS