Implement non-uniform borders (when not using corner_radius)
StTheme CSS supports different border widths for different sides. Implement it for StWidget by drawing the border internally. However, we don't support a nonzero corner-radius with nonuniform borders. https://bugzilla.gnome.org/show_bug.cgi?id=599442
This commit is contained in:
parent
e2e513ff08
commit
4f456b9689
@ -63,6 +63,7 @@ struct _StWidgetPrivate
|
||||
gboolean has_tooltip : 1;
|
||||
gboolean is_style_dirty : 1;
|
||||
gboolean draw_bg_color : 1;
|
||||
gboolean draw_border_internal : 1;
|
||||
|
||||
StTooltip *tooltip;
|
||||
};
|
||||
@ -356,25 +357,25 @@ static void
|
||||
st_widget_real_draw_background (StWidget *self)
|
||||
{
|
||||
StWidgetPrivate *priv = self->priv;
|
||||
ClutterActor *actor = CLUTTER_ACTOR (self);
|
||||
ClutterActorBox allocation = { 0, };
|
||||
gfloat w, h;
|
||||
guint8 opacity;
|
||||
|
||||
clutter_actor_get_allocation_box (actor, &allocation);
|
||||
w = allocation.x2 - allocation.x1;
|
||||
h = allocation.y2 - allocation.y1;
|
||||
|
||||
opacity = clutter_actor_get_paint_opacity (actor);
|
||||
|
||||
/* Default implementation just draws the background
|
||||
* colour and the image on top
|
||||
*/
|
||||
if (priv->draw_bg_color)
|
||||
{
|
||||
ClutterActor *actor = CLUTTER_ACTOR (self);
|
||||
ClutterActorBox allocation = { 0, };
|
||||
ClutterColor bg_color = priv->bg_color;
|
||||
gfloat w, h;
|
||||
|
||||
bg_color.alpha = clutter_actor_get_paint_opacity (actor)
|
||||
* bg_color.alpha
|
||||
/ 255;
|
||||
|
||||
clutter_actor_get_allocation_box (actor, &allocation);
|
||||
|
||||
w = allocation.x2 - allocation.x1;
|
||||
h = allocation.y2 - allocation.y1;
|
||||
bg_color.alpha = opacity * bg_color.alpha / 255;
|
||||
|
||||
cogl_set_source_color4ub (bg_color.red,
|
||||
bg_color.green,
|
||||
@ -383,6 +384,76 @@ st_widget_real_draw_background (StWidget *self)
|
||||
cogl_rectangle (0, 0, w, h);
|
||||
}
|
||||
|
||||
if (priv->draw_border_internal)
|
||||
{
|
||||
StThemeNode *node = st_widget_get_theme_node (self);
|
||||
int side;
|
||||
double border_top, border_right, border_bottom, border_left;
|
||||
|
||||
border_top = st_theme_node_get_border_width (node, ST_SIDE_TOP);
|
||||
border_right = st_theme_node_get_border_width (node, ST_SIDE_RIGHT);
|
||||
border_bottom = st_theme_node_get_border_width (node, ST_SIDE_BOTTOM);
|
||||
border_left = st_theme_node_get_border_width (node, ST_SIDE_LEFT);
|
||||
|
||||
for (side = 0; side < 4; side++)
|
||||
{
|
||||
ClutterColor color;
|
||||
|
||||
switch (side)
|
||||
{
|
||||
case ST_SIDE_TOP:
|
||||
if (border_top <= 0)
|
||||
continue;
|
||||
break;
|
||||
case ST_SIDE_RIGHT:
|
||||
if (border_right <= 0)
|
||||
continue;
|
||||
break;
|
||||
case ST_SIDE_BOTTOM:
|
||||
if (border_bottom <= 0)
|
||||
continue;
|
||||
break;
|
||||
case ST_SIDE_LEFT:
|
||||
if (border_left <= 0)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
st_theme_node_get_border_color (node, side, &color);
|
||||
|
||||
color.alpha = (color.alpha * opacity) / 0xff;
|
||||
|
||||
cogl_set_source_color4ub (color.red,
|
||||
color.green,
|
||||
color.blue,
|
||||
color.alpha);
|
||||
|
||||
/* Note top and bottom extend to the ends, left/right
|
||||
* are constrained by them. See comment above about CSS
|
||||
* conformance.
|
||||
*/
|
||||
switch (side)
|
||||
{
|
||||
case ST_SIDE_TOP:
|
||||
cogl_rectangle (0, 0,
|
||||
w, border_top);
|
||||
break;
|
||||
case ST_SIDE_RIGHT:
|
||||
cogl_rectangle (w - border_right, border_top,
|
||||
w, h - border_bottom);
|
||||
break;
|
||||
case ST_SIDE_BOTTOM:
|
||||
cogl_rectangle (0, h - border_bottom,
|
||||
w, h);
|
||||
break;
|
||||
case ST_SIDE_LEFT:
|
||||
cogl_rectangle (0, border_top,
|
||||
border_left, h - border_bottom);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->border_image)
|
||||
clutter_actor_paint (priv->border_image);
|
||||
}
|
||||
@ -491,6 +562,7 @@ st_widget_real_style_changed (StWidget *self)
|
||||
ClutterColor border_color = { 0, };
|
||||
StSide side;
|
||||
StCorner corner;
|
||||
gboolean uniform_border_width;
|
||||
|
||||
/* application has request this widget is not stylable */
|
||||
if (!priv->is_stylable)
|
||||
@ -520,33 +592,6 @@ st_widget_real_style_changed (StWidget *self)
|
||||
|
||||
texture_cache = st_texture_cache_get_default ();
|
||||
|
||||
/* StThemeNode supports different widths and colors for different sides
|
||||
* of the border, and different radii for the different corners. We take
|
||||
* the different border widths into account when positioning, but our current
|
||||
* drawing code (using BigRectangle) can only handle a single width, color,
|
||||
* and radius, so we arbitrarily pick the first non-zero width and radius,
|
||||
* and use that.
|
||||
*/
|
||||
for (side = ST_SIDE_TOP; side <= ST_SIDE_LEFT; side++)
|
||||
{
|
||||
double width = st_theme_node_get_border_width (theme_node, side);
|
||||
if (width > 0.5)
|
||||
{
|
||||
border_width = (int)(0.5 + width);
|
||||
st_theme_node_get_border_color (theme_node, side, &border_color);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (corner = ST_CORNER_TOPLEFT; corner <= ST_CORNER_BOTTOMLEFT; corner++)
|
||||
{
|
||||
double radius = st_theme_node_get_border_radius (theme_node, corner);
|
||||
if (radius > 0.5)
|
||||
{
|
||||
border_radius = (int)(0.5 + radius);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Rough notes about the relationship of borders and backgrounds in CSS3;
|
||||
* see http://www.w3.org/TR/css3-background/ for more accurate details.
|
||||
@ -565,6 +610,8 @@ st_widget_real_style_changed (StWidget *self)
|
||||
* zero width or a border image is being used.
|
||||
*
|
||||
* Deviations from the above as implemented here:
|
||||
* - Nonuniform border widths combined with a non-zero border radius result
|
||||
* in the border radius being ignored
|
||||
* - The combination of border image and a non-zero border radius is
|
||||
* not supported; the background color will be drawn with square
|
||||
* corners.
|
||||
@ -576,6 +623,44 @@ st_widget_real_style_changed (StWidget *self)
|
||||
* and a single background image above it.
|
||||
*/
|
||||
|
||||
/* Check whether all border widths are the same. Also, acquire the
|
||||
* first nonzero border width as well as the border color.
|
||||
*/
|
||||
uniform_border_width = TRUE;
|
||||
border_width = st_theme_node_get_border_width (theme_node, ST_SIDE_TOP);
|
||||
if (border_width > 0.5)
|
||||
border_width = (int)(0.5 + border_width);
|
||||
for (side = 0; side < 4; side++)
|
||||
{
|
||||
double width = st_theme_node_get_border_width (theme_node, side);
|
||||
if (width > 0.5)
|
||||
width = (int)(0.5 + width);
|
||||
if (width > 0)
|
||||
{
|
||||
border_width = width;
|
||||
st_theme_node_get_border_color (theme_node, side, &border_color);
|
||||
}
|
||||
if ((int)width != border_width)
|
||||
{
|
||||
uniform_border_width = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pick the first nonzero border radius, but only if we have a uniform border. */
|
||||
if (uniform_border_width)
|
||||
{
|
||||
for (corner = 0; corner < 4; corner++)
|
||||
{
|
||||
double radius = st_theme_node_get_border_radius (theme_node, corner);
|
||||
if (radius > 0.5)
|
||||
{
|
||||
border_radius = (int)(0.5 + radius);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
border_image = st_theme_node_get_border_image (theme_node);
|
||||
if (border_image)
|
||||
{
|
||||
@ -607,9 +692,9 @@ st_widget_real_style_changed (StWidget *self)
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
else if ((border_width > 0 && border_color.alpha != 0) ||
|
||||
(border_radius > 0 && priv->bg_color.alpha != 0))
|
||||
else if (border_radius > 0)
|
||||
{
|
||||
priv->draw_border_internal = FALSE;
|
||||
priv->draw_bg_color = FALSE;
|
||||
priv->border_image = g_object_new (BIG_TYPE_RECTANGLE,
|
||||
"color", &priv->bg_color,
|
||||
@ -623,6 +708,19 @@ st_widget_real_style_changed (StWidget *self)
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
else if (border_width > 0 && border_color.alpha != 0)
|
||||
{
|
||||
priv->draw_bg_color = TRUE;
|
||||
priv->draw_border_internal = TRUE;
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
else if (priv->draw_border_internal)
|
||||
{
|
||||
priv->draw_border_internal = FALSE;
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
|
||||
bg_file = st_theme_node_get_background_image (theme_node);
|
||||
if (bg_file != NULL)
|
||||
|
Loading…
Reference in New Issue
Block a user