[StThemeNode] implement CSS "outline" property
Could potentially be used for focus indication https://bugzilla.gnome.org/show_bug.cgi?id=621669
This commit is contained in:
parent
ab61017041
commit
cae61e62fd
@ -1054,6 +1054,54 @@ st_theme_node_paint_sliced_border_image (StThemeNode *node,
|
|||||||
cogl_handle_unref (material);
|
cogl_handle_unref (material);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
st_theme_node_paint_outline (StThemeNode *node,
|
||||||
|
const ClutterActorBox *box,
|
||||||
|
guint8 paint_opacity)
|
||||||
|
|
||||||
|
{
|
||||||
|
float width, height;
|
||||||
|
int outline_width;
|
||||||
|
ClutterColor outline_color, effective_outline;
|
||||||
|
|
||||||
|
width = box->x2 - box->x1;
|
||||||
|
height = box->y2 - box->y1;
|
||||||
|
|
||||||
|
outline_width = st_theme_node_get_outline_width (node);
|
||||||
|
if (outline_width == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
st_theme_node_get_outline_color (node, &outline_color);
|
||||||
|
over (&outline_color, &node->background_color, &effective_outline);
|
||||||
|
|
||||||
|
cogl_set_source_color4ub (effective_outline.red,
|
||||||
|
effective_outline.green,
|
||||||
|
effective_outline.blue,
|
||||||
|
paint_opacity * effective_outline.alpha / 255);
|
||||||
|
|
||||||
|
/* The outline is drawn just outside the border, which means just
|
||||||
|
* outside the allocation box. This means that in some situations
|
||||||
|
* involving clip_to_allocation or the screen edges, you won't be
|
||||||
|
* able to see the outline. In practice, it works well enough.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* NORTH */
|
||||||
|
cogl_rectangle (-outline_width, -outline_width,
|
||||||
|
width + outline_width, 0);
|
||||||
|
|
||||||
|
/* EAST */
|
||||||
|
cogl_rectangle (width, 0,
|
||||||
|
width + outline_width, height);
|
||||||
|
|
||||||
|
/* SOUTH */
|
||||||
|
cogl_rectangle (-outline_width, height,
|
||||||
|
width + outline_width, height + outline_width);
|
||||||
|
|
||||||
|
/* WEST */
|
||||||
|
cogl_rectangle (-outline_width, 0,
|
||||||
|
0, height);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
st_theme_node_paint (StThemeNode *node,
|
st_theme_node_paint (StThemeNode *node,
|
||||||
const ClutterActorBox *box,
|
const ClutterActorBox *box,
|
||||||
@ -1121,6 +1169,8 @@ st_theme_node_paint (StThemeNode *node,
|
|||||||
else
|
else
|
||||||
st_theme_node_paint_borders (node, box, paint_opacity);
|
st_theme_node_paint_borders (node, box, paint_opacity);
|
||||||
|
|
||||||
|
st_theme_node_paint_outline (node, box, paint_opacity);
|
||||||
|
|
||||||
if (node->background_texture != COGL_INVALID_HANDLE)
|
if (node->background_texture != COGL_INVALID_HANDLE)
|
||||||
{
|
{
|
||||||
ClutterActorBox background_box;
|
ClutterActorBox background_box;
|
||||||
|
@ -24,9 +24,11 @@ struct _StThemeNode {
|
|||||||
|
|
||||||
ClutterColor foreground_color;
|
ClutterColor foreground_color;
|
||||||
ClutterColor border_color[4];
|
ClutterColor border_color[4];
|
||||||
|
ClutterColor outline_color;
|
||||||
|
|
||||||
int border_width[4];
|
int border_width[4];
|
||||||
int border_radius[4];
|
int border_radius[4];
|
||||||
|
int outline_width;
|
||||||
guint padding[4];
|
guint padding[4];
|
||||||
|
|
||||||
int width;
|
int width;
|
||||||
|
@ -943,7 +943,7 @@ do_border_property (StThemeNode *node,
|
|||||||
|
|
||||||
if (strcmp (property_name, "") == 0)
|
if (strcmp (property_name, "") == 0)
|
||||||
{
|
{
|
||||||
/* Set value for width/color/node in any order */
|
/* Set value for width/color/style in any order */
|
||||||
CRTerm *term;
|
CRTerm *term;
|
||||||
|
|
||||||
for (term = decl->value; term; term = term->next)
|
for (term = decl->value; term; term = term->next)
|
||||||
@ -965,7 +965,6 @@ do_border_property (StThemeNode *node,
|
|||||||
}
|
}
|
||||||
else if (strcmp (ident, "dotted") == 0 ||
|
else if (strcmp (ident, "dotted") == 0 ||
|
||||||
strcmp (ident, "dashed") == 0 ||
|
strcmp (ident, "dashed") == 0 ||
|
||||||
strcmp (ident, "solid") == 0 ||
|
|
||||||
strcmp (ident, "double") == 0 ||
|
strcmp (ident, "double") == 0 ||
|
||||||
strcmp (ident, "groove") == 0 ||
|
strcmp (ident, "groove") == 0 ||
|
||||||
strcmp (ident, "ridge") == 0 ||
|
strcmp (ident, "ridge") == 0 ||
|
||||||
@ -1036,6 +1035,97 @@ do_border_property (StThemeNode *node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_outline_property (StThemeNode *node,
|
||||||
|
CRDeclaration *decl)
|
||||||
|
{
|
||||||
|
const char *property_name = decl->property->stryng->str + 7; /* Skip 'outline' */
|
||||||
|
ClutterColor color;
|
||||||
|
gboolean color_set = FALSE;
|
||||||
|
int width;
|
||||||
|
gboolean width_set = FALSE;
|
||||||
|
|
||||||
|
if (strcmp (property_name, "") == 0)
|
||||||
|
{
|
||||||
|
/* Set value for width/color/style in any order */
|
||||||
|
CRTerm *term;
|
||||||
|
|
||||||
|
for (term = decl->value; term; term = term->next)
|
||||||
|
{
|
||||||
|
GetFromTermResult result;
|
||||||
|
|
||||||
|
if (term->type == TERM_IDENT)
|
||||||
|
{
|
||||||
|
const char *ident = term->content.str->stryng->str;
|
||||||
|
if (strcmp (ident, "none") == 0 || strcmp (ident, "hidden") == 0)
|
||||||
|
{
|
||||||
|
width = 0.;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (strcmp (ident, "solid") == 0)
|
||||||
|
{
|
||||||
|
/* The only thing we support */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (strcmp (ident, "dotted") == 0 ||
|
||||||
|
strcmp (ident, "dashed") == 0 ||
|
||||||
|
strcmp (ident, "double") == 0 ||
|
||||||
|
strcmp (ident, "groove") == 0 ||
|
||||||
|
strcmp (ident, "ridge") == 0 ||
|
||||||
|
strcmp (ident, "inset") == 0 ||
|
||||||
|
strcmp (ident, "outset") == 0)
|
||||||
|
{
|
||||||
|
/* Treat the same as solid */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Presumably a color, fall through */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (term->type == TERM_NUMBER)
|
||||||
|
{
|
||||||
|
result = get_length_from_term_int (node, term, FALSE, &width);
|
||||||
|
if (result != VALUE_NOT_FOUND)
|
||||||
|
{
|
||||||
|
width_set = result == VALUE_FOUND;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = get_color_from_term (node, term, &color);
|
||||||
|
if (result != VALUE_NOT_FOUND)
|
||||||
|
{
|
||||||
|
color_set = result == VALUE_FOUND;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strcmp (property_name, "-color") == 0)
|
||||||
|
{
|
||||||
|
if (decl->value == NULL || decl->value->next != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (get_color_from_term (node, decl->value, &color) == VALUE_FOUND)
|
||||||
|
/* Ignore inherit */
|
||||||
|
color_set = TRUE;
|
||||||
|
}
|
||||||
|
else if (strcmp (property_name, "-width") == 0)
|
||||||
|
{
|
||||||
|
if (decl->value == NULL || decl->value->next != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (get_length_from_term_int (node, decl->value, FALSE, &width) == VALUE_FOUND)
|
||||||
|
/* Ignore inherit */
|
||||||
|
width_set = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color_set)
|
||||||
|
node->outline_color = color;
|
||||||
|
if (width_set)
|
||||||
|
node->outline_width = width;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_padding_property_term (StThemeNode *node,
|
do_padding_property_term (StThemeNode *node,
|
||||||
CRTerm *term,
|
CRTerm *term,
|
||||||
@ -1144,6 +1234,9 @@ _st_theme_node_ensure_geometry (StThemeNode *node)
|
|||||||
node->border_color[j] = TRANSPARENT_COLOR;
|
node->border_color[j] = TRANSPARENT_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node->outline_width = 0;
|
||||||
|
node->outline_color = TRANSPARENT_COLOR;
|
||||||
|
|
||||||
node->width = -1;
|
node->width = -1;
|
||||||
node->height = -1;
|
node->height = -1;
|
||||||
node->min_width = -1;
|
node->min_width = -1;
|
||||||
@ -1158,6 +1251,8 @@ _st_theme_node_ensure_geometry (StThemeNode *node)
|
|||||||
|
|
||||||
if (g_str_has_prefix (property_name, "border"))
|
if (g_str_has_prefix (property_name, "border"))
|
||||||
do_border_property (node, decl);
|
do_border_property (node, decl);
|
||||||
|
else if (g_str_has_prefix (property_name, "outline"))
|
||||||
|
do_outline_property (node, decl);
|
||||||
else if (g_str_has_prefix (property_name, "padding"))
|
else if (g_str_has_prefix (property_name, "padding"))
|
||||||
do_padding_property (node, decl);
|
do_padding_property (node, decl);
|
||||||
else if (strcmp (property_name, "width") == 0)
|
else if (strcmp (property_name, "width") == 0)
|
||||||
@ -1223,6 +1318,27 @@ st_theme_node_get_border_radius (StThemeNode *node,
|
|||||||
return node->border_radius[corner];
|
return node->border_radius[corner];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
st_theme_node_get_outline_width (StThemeNode *node)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0);
|
||||||
|
|
||||||
|
_st_theme_node_ensure_geometry (node);
|
||||||
|
|
||||||
|
return node->outline_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
st_theme_node_get_outline_color (StThemeNode *node,
|
||||||
|
ClutterColor *color)
|
||||||
|
{
|
||||||
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
||||||
|
|
||||||
|
_st_theme_node_ensure_geometry (node);
|
||||||
|
|
||||||
|
*color = node->outline_color;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
st_theme_node_get_width (StThemeNode *node)
|
st_theme_node_get_width (StThemeNode *node)
|
||||||
{
|
{
|
||||||
@ -2539,13 +2655,13 @@ st_theme_node_get_content_box (StThemeNode *node,
|
|||||||
/**
|
/**
|
||||||
* st_theme_node_get_paint_box:
|
* st_theme_node_get_paint_box:
|
||||||
* @node: a #StThemeNode
|
* @node: a #StThemeNode
|
||||||
* @allocation: the box allocated to a #ClutterAlctor
|
* @allocation: the box allocated to a #ClutterActor
|
||||||
* @paint_box: computed box occupied when painting the actor
|
* @paint_box: computed box occupied when painting the actor
|
||||||
*
|
*
|
||||||
* Gets the box used to paint the actor, including the area occupied by
|
* Gets the box used to paint the actor, including the area occupied
|
||||||
* properties which paint outside the actor's assigned allocation
|
* by properties which paint outside the actor's assigned allocation.
|
||||||
* (currently only st-shadow). When painting @node to an offscreen buffer,
|
* When painting @node to an offscreen buffer, this function can be
|
||||||
* this function can be used to determine the necessary size of the buffer.
|
* used to determine the necessary size of the buffer.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
st_theme_node_get_paint_box (StThemeNode *node,
|
st_theme_node_get_paint_box (StThemeNode *node,
|
||||||
@ -2553,25 +2669,30 @@ st_theme_node_get_paint_box (StThemeNode *node,
|
|||||||
ClutterActorBox *paint_box)
|
ClutterActorBox *paint_box)
|
||||||
{
|
{
|
||||||
StShadow *shadow;
|
StShadow *shadow;
|
||||||
|
ClutterActorBox shadow_box;
|
||||||
|
int outline_width;
|
||||||
|
|
||||||
g_return_if_fail (ST_IS_THEME_NODE (node));
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
||||||
g_return_if_fail (actor_box != NULL);
|
g_return_if_fail (actor_box != NULL);
|
||||||
g_return_if_fail (paint_box != NULL);
|
g_return_if_fail (paint_box != NULL);
|
||||||
|
|
||||||
shadow = st_theme_node_get_shadow (node);
|
shadow = st_theme_node_get_shadow (node);
|
||||||
if (shadow)
|
outline_width = st_theme_node_get_outline_width (node);
|
||||||
|
if (!shadow && !outline_width)
|
||||||
{
|
{
|
||||||
ClutterActorBox shadow_box;
|
*paint_box = *actor_box;
|
||||||
|
return;
|
||||||
st_shadow_get_box (shadow, actor_box, &shadow_box);
|
|
||||||
|
|
||||||
paint_box->x1 = MIN (actor_box->x1, shadow_box.x1);
|
|
||||||
paint_box->x2 = MAX (actor_box->x2, shadow_box.x2);
|
|
||||||
paint_box->y1 = MIN (actor_box->y1, shadow_box.y1);
|
|
||||||
paint_box->y2 = MAX (actor_box->y2, shadow_box.y2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shadow)
|
||||||
|
st_shadow_get_box (shadow, actor_box, &shadow_box);
|
||||||
else
|
else
|
||||||
*paint_box = *actor_box;
|
shadow_box = *actor_box;
|
||||||
|
|
||||||
|
paint_box->x1 = MIN (actor_box->x1 - outline_width, shadow_box.x1);
|
||||||
|
paint_box->x2 = MAX (actor_box->x2 + outline_width, shadow_box.x2);
|
||||||
|
paint_box->y1 = MIN (actor_box->y1 - outline_width, shadow_box.y1);
|
||||||
|
paint_box->y2 = MAX (actor_box->y2 + outline_width, shadow_box.y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,6 +128,10 @@ void st_theme_node_get_border_color (StThemeNode *node,
|
|||||||
StSide side,
|
StSide side,
|
||||||
ClutterColor *color);
|
ClutterColor *color);
|
||||||
|
|
||||||
|
int st_theme_node_get_outline_width (StThemeNode *node);
|
||||||
|
void st_theme_node_get_outline_color (StThemeNode *node,
|
||||||
|
ClutterColor *color);
|
||||||
|
|
||||||
double st_theme_node_get_padding (StThemeNode *node,
|
double st_theme_node_get_padding (StThemeNode *node,
|
||||||
StSide side);
|
StSide side);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user