Implement gradients for StWidget
Rather than having gradients be individually implemented by higher level JS widgets, move basic gradient functionality into StWidget. There is prior art in WebKit for CSS gradients: http://webkit.org/blog/175/introducing-css-gradients/ However, implementing this would be quite a lot of work; all we need in the Shell design at the moment is basic horizontal/vertical linear gradients. So, the syntax now supported is: background-gradient-type: [vertical|horizontal] background-gradient-start: color; background-gradient-end: color; https://bugzilla.gnome.org/show_bug.cgi?id=602131
This commit is contained in:
parent
0bc578230f
commit
7b9f5b7643
@ -21,8 +21,13 @@ struct _StThemeNode {
|
||||
PangoFontDescription *font_desc;
|
||||
|
||||
ClutterColor background_color;
|
||||
/* If gradient is set, then background_color is the gradient start */
|
||||
StGradientType background_gradient_type;
|
||||
ClutterColor background_gradient_end;
|
||||
|
||||
ClutterColor foreground_color;
|
||||
ClutterColor border_color[4];
|
||||
|
||||
double border_width[4];
|
||||
double border_radius[4];
|
||||
guint padding[4];
|
||||
@ -1236,6 +1241,7 @@ ensure_background (StThemeNode *node)
|
||||
|
||||
node->background_computed = TRUE;
|
||||
node->background_color = TRANSPARENT_COLOR;
|
||||
node->background_gradient_type = ST_GRADIENT_NONE;
|
||||
|
||||
ensure_properties (node);
|
||||
|
||||
@ -1331,6 +1337,31 @@ ensure_background (StThemeNode *node)
|
||||
node->background_image = NULL;
|
||||
}
|
||||
}
|
||||
else if (strcmp (property_name, "-gradient-direction") == 0)
|
||||
{
|
||||
CRTerm *term = decl->value;
|
||||
if (strcmp (term->content.str->stryng->str, "vertical") == 0)
|
||||
{
|
||||
node->background_gradient_type = ST_GRADIENT_VERTICAL;
|
||||
}
|
||||
else if (strcmp (term->content.str->stryng->str, "horizontal") == 0)
|
||||
{
|
||||
node->background_gradient_type = ST_GRADIENT_HORIZONTAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Unrecognized background-gradient-direction \"%s\"",
|
||||
term->content.str->stryng->str);
|
||||
}
|
||||
}
|
||||
else if (strcmp (property_name, "-gradient-start") == 0)
|
||||
{
|
||||
get_color_from_term (node, decl->value, &node->background_color);
|
||||
}
|
||||
else if (strcmp (property_name, "-gradient-end") == 0)
|
||||
{
|
||||
get_color_from_term (node, decl->value, &node->background_gradient_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1393,6 +1424,34 @@ st_theme_node_get_foreground_color (StThemeNode *node,
|
||||
*color = node->foreground_color;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* st_theme_node_get_background_gradient:
|
||||
* @node: A #StThemeNode
|
||||
* @type: (out): Type of gradient
|
||||
* @start: Color at start of gradient
|
||||
* @end: Color at end of gradient
|
||||
*
|
||||
* The @start and @end arguments will only be set if @type is not #ST_GRADIENT_NONE.
|
||||
*/
|
||||
void
|
||||
st_theme_node_get_background_gradient (StThemeNode *node,
|
||||
StGradientType *type,
|
||||
ClutterColor *start,
|
||||
ClutterColor *end)
|
||||
{
|
||||
g_return_if_fail (ST_IS_THEME_NODE (node));
|
||||
|
||||
ensure_background (node);
|
||||
|
||||
*type = node->background_gradient_type;
|
||||
if (*type != ST_GRADIENT_NONE)
|
||||
{
|
||||
*start = node->background_color;
|
||||
*end = node->background_gradient_end;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
st_theme_node_get_border_color (StThemeNode *node,
|
||||
StSide side,
|
||||
|
@ -57,6 +57,12 @@ typedef enum {
|
||||
ST_TEXT_DECORATION_BLINK = 1 << 3
|
||||
} StTextDecoration;
|
||||
|
||||
typedef enum {
|
||||
ST_GRADIENT_NONE,
|
||||
ST_GRADIENT_VERTICAL,
|
||||
ST_GRADIENT_HORIZONTAL
|
||||
} StGradientType;
|
||||
|
||||
GType st_theme_node_get_type (void) G_GNUC_CONST;
|
||||
|
||||
StThemeNode *st_theme_node_new (StThemeContext *context,
|
||||
@ -103,6 +109,10 @@ void st_theme_node_get_background_color (StThemeNode *node,
|
||||
ClutterColor *color);
|
||||
void st_theme_node_get_foreground_color (StThemeNode *node,
|
||||
ClutterColor *color);
|
||||
void st_theme_node_get_background_gradient (StThemeNode *node,
|
||||
StGradientType *type,
|
||||
ClutterColor *start,
|
||||
ClutterColor *end);
|
||||
|
||||
const char *st_theme_node_get_background_image (StThemeNode *node);
|
||||
|
||||
|
@ -59,6 +59,9 @@ struct _StWidgetPrivate
|
||||
ClutterActor *background_image;
|
||||
ClutterColor bg_color;
|
||||
|
||||
StGradientType bg_gradient_type;
|
||||
ClutterColor bg_gradient_end;
|
||||
|
||||
gboolean is_stylable : 1;
|
||||
gboolean has_tooltip : 1;
|
||||
gboolean is_style_dirty : 1;
|
||||
@ -111,6 +114,7 @@ G_DEFINE_ABSTRACT_TYPE (StWidget, st_widget, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
static void st_widget_recompute_style (StWidget *widget,
|
||||
StThemeNode *old_theme_node);
|
||||
static void st_widget_redraw_gradient (StWidget *widget);
|
||||
|
||||
static void
|
||||
st_widget_set_property (GObject *gobject,
|
||||
@ -258,10 +262,13 @@ st_widget_allocate (ClutterActor *actor,
|
||||
ClutterAllocationFlags flags)
|
||||
{
|
||||
StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
|
||||
StThemeNode *theme_node;
|
||||
ClutterActorClass *klass;
|
||||
ClutterGeometry area;
|
||||
ClutterVertex in_v, out_v;
|
||||
|
||||
theme_node = st_widget_get_theme_node ((StWidget*) actor);
|
||||
|
||||
klass = CLUTTER_ACTOR_CLASS (st_widget_parent_class);
|
||||
klass->allocate (actor, box, flags);
|
||||
|
||||
@ -298,7 +305,7 @@ st_widget_allocate (ClutterActor *actor,
|
||||
flags);
|
||||
}
|
||||
|
||||
if (priv->background_image)
|
||||
if (priv->background_image && priv->bg_gradient_type == ST_GRADIENT_NONE)
|
||||
{
|
||||
ClutterActorBox frame_box = {
|
||||
0, 0, box->x2 - box->x1, box->y2 - box->y1
|
||||
@ -353,6 +360,27 @@ st_widget_allocate (ClutterActor *actor,
|
||||
&frame_box,
|
||||
flags);
|
||||
}
|
||||
else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
|
||||
{
|
||||
float width, height;
|
||||
ClutterActorBox frame_box, content_box;
|
||||
|
||||
width = box->x2 - box->x1;
|
||||
height = box->y2 - box->y1;
|
||||
frame_box.x1 = frame_box.y1 = 0;
|
||||
frame_box.x2 = width;
|
||||
frame_box.y2 = height;
|
||||
|
||||
st_theme_node_get_content_box (theme_node, &frame_box, &content_box);
|
||||
|
||||
if (width > 0 && height > 0)
|
||||
clutter_cairo_texture_set_surface_size (CLUTTER_CAIRO_TEXTURE (priv->background_image),
|
||||
width, height);
|
||||
st_widget_redraw_gradient ((StWidget*) actor);
|
||||
clutter_actor_allocate (CLUTTER_ACTOR (priv->background_image),
|
||||
&content_box,
|
||||
flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -526,6 +554,84 @@ st_widget_unmap (ClutterActor *actor)
|
||||
clutter_actor_unmap ((ClutterActor *) priv->tooltip);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_vertical_gradient (ClutterCairoTexture *texture,
|
||||
ClutterColor *start,
|
||||
ClutterColor *end)
|
||||
{
|
||||
guint width, height;
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
||||
clutter_cairo_texture_clear (texture);
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, 0, 0, height);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
||||
start->red / 255.,
|
||||
start->green / 255.,
|
||||
start->blue / 255.,
|
||||
start->alpha / 255.);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
||||
end->red / 255.,
|
||||
end->green / 255.,
|
||||
end->blue / 255.,
|
||||
end->alpha / 255.);
|
||||
|
||||
cairo_rectangle (cr, 0, 0, width, height);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_horizontal_gradient (ClutterCairoTexture *texture,
|
||||
ClutterColor *start,
|
||||
ClutterColor *end)
|
||||
{
|
||||
guint width, height;
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
||||
clutter_cairo_texture_clear (texture);
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, 0, width, 0);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
||||
start->red / 255.,
|
||||
start->green / 255.,
|
||||
start->blue / 255.,
|
||||
start->alpha / 255.);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
||||
end->red / 255.,
|
||||
end->green / 255.,
|
||||
end->blue / 255.,
|
||||
end->alpha / 255.);
|
||||
cairo_rectangle (cr, 0, 0, width, height);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_redraw_gradient (StWidget *widget)
|
||||
{
|
||||
if (widget->priv->bg_gradient_type == ST_GRADIENT_VERTICAL)
|
||||
draw_vertical_gradient ((ClutterCairoTexture*) widget->priv->background_image,
|
||||
&widget->priv->bg_color,
|
||||
&widget->priv->bg_gradient_end);
|
||||
else if (widget->priv->bg_gradient_type == ST_GRADIENT_HORIZONTAL)
|
||||
draw_horizontal_gradient ((ClutterCairoTexture*) widget->priv->background_image,
|
||||
&widget->priv->bg_color,
|
||||
&widget->priv->bg_gradient_end);
|
||||
}
|
||||
|
||||
static void notify_children_of_style_change (ClutterContainer *container);
|
||||
|
||||
static void
|
||||
@ -562,6 +668,8 @@ st_widget_real_style_changed (StWidget *self)
|
||||
guint border_width = 0;
|
||||
guint border_radius = 0;
|
||||
ClutterColor border_color = { 0, };
|
||||
StGradientType gradient;
|
||||
ClutterColor gradient_end;
|
||||
StSide side;
|
||||
StCorner corner;
|
||||
gboolean uniform_border_width;
|
||||
@ -572,6 +680,13 @@ st_widget_real_style_changed (StWidget *self)
|
||||
|
||||
theme_node = st_widget_get_theme_node (self);
|
||||
|
||||
st_theme_node_get_background_gradient (theme_node, &gradient, &color, &gradient_end);
|
||||
|
||||
if (gradient == ST_GRADIENT_NONE)
|
||||
{
|
||||
if (gradient != priv->bg_gradient_type)
|
||||
has_changed = TRUE;
|
||||
priv->bg_gradient_type = gradient;
|
||||
st_theme_node_get_background_color (theme_node, &color);
|
||||
if (!clutter_color_equal (&color, &priv->bg_color))
|
||||
{
|
||||
@ -579,6 +694,17 @@ st_widget_real_style_changed (StWidget *self)
|
||||
priv->draw_bg_color = color.alpha != 0;
|
||||
has_changed = TRUE;
|
||||
}
|
||||
}
|
||||
else if (gradient != priv->bg_gradient_type ||
|
||||
!clutter_color_equal (&color, &priv->bg_color) ||
|
||||
!clutter_color_equal (&gradient_end, &priv->bg_gradient_end))
|
||||
{
|
||||
priv->bg_gradient_type = gradient;
|
||||
priv->bg_color = color;
|
||||
priv->bg_gradient_end = gradient_end;
|
||||
priv->draw_bg_color = TRUE;
|
||||
has_changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->border_image)
|
||||
{
|
||||
@ -741,6 +867,15 @@ st_widget_real_style_changed (StWidget *self)
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
|
||||
{
|
||||
texture = g_object_new (CLUTTER_TYPE_CAIRO_TEXTURE, NULL);
|
||||
priv->background_image = CLUTTER_ACTOR (texture);
|
||||
clutter_actor_set_parent (priv->background_image,
|
||||
CLUTTER_ACTOR (self));
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
|
||||
/* If there are any properties above that need to cause a relayout thay
|
||||
* should set this flag.
|
||||
@ -1248,12 +1383,22 @@ static void
|
||||
st_widget_recompute_style (StWidget *widget,
|
||||
StThemeNode *old_theme_node)
|
||||
{
|
||||
ClutterActorBox allocation_box;
|
||||
StThemeNode *new_theme_node = st_widget_get_theme_node (widget);
|
||||
|
||||
clutter_actor_get_allocation_box ((ClutterActor *) widget, &allocation_box);
|
||||
|
||||
if (!old_theme_node ||
|
||||
!st_theme_node_geometry_equal (old_theme_node, new_theme_node))
|
||||
clutter_actor_queue_relayout ((ClutterActor *) widget);
|
||||
|
||||
/* Could compare gradient values here if we hit a performance issue.
|
||||
* Also, only redraw if we've been allocated.
|
||||
*/
|
||||
if (allocation_box.x2 - allocation_box.x1 > 0 &&
|
||||
allocation_box.y2 - allocation_box.y1 > 0)
|
||||
st_widget_redraw_gradient (widget);
|
||||
|
||||
g_signal_emit (widget, signals[STYLE_CHANGED], 0);
|
||||
widget->priv->is_style_dirty = FALSE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user