Implement -st-shadow for StWidget
Add support for a new -st-shadow property, which is based loosely on the CSS3 box-shadow property: http://www.css3.info/preview/box-shadow/ It defers from the specification as follows: * no multiple shadows * the optional color argument may be placed anywhere * the shape is not determined by the widget's bounding box, but by the background-image property https://bugzilla.gnome.org/show_bug.cgi?id=603691
This commit is contained in:
parent
a2cae50e0e
commit
2dfe113a42
@ -83,6 +83,8 @@ st_source_h = \
|
||||
st/st-scrollable.h \
|
||||
st/st-scroll-bar.h \
|
||||
st/st-scroll-view.h \
|
||||
st/st-shadow-texture.h \
|
||||
st/st-shadow.h \
|
||||
st/st-subtexture.h \
|
||||
st/st-table.h \
|
||||
st/st-table-child.h \
|
||||
@ -122,6 +124,8 @@ st_source_c = \
|
||||
st/st-scrollable.c \
|
||||
st/st-scroll-bar.c \
|
||||
st/st-scroll-view.c \
|
||||
st/st-shadow-texture.c \
|
||||
st/st-shadow.c \
|
||||
st/st-subtexture.c \
|
||||
st/st-table.c \
|
||||
st/st-table-child.c \
|
||||
|
274
src/st/st-shadow-texture.c
Normal file
274
src/st/st-shadow-texture.c
Normal file
@ -0,0 +1,274 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "st-shadow-texture.h"
|
||||
|
||||
/**
|
||||
* SECTION: st-shadow-texture
|
||||
* @short_description: a class for creating soft shadow textures
|
||||
*
|
||||
* #StShadowTexture is a #ClutterTexture holding a soft shadow texture for
|
||||
* another #ClutterActor.
|
||||
* It is used to implement the box-shadow property in StWidget and should
|
||||
* not be used stand-alone.
|
||||
*/
|
||||
|
||||
struct _StShadowTexture {
|
||||
ClutterTexture parent;
|
||||
|
||||
CoglColor color;
|
||||
gdouble sigma;
|
||||
gdouble blur_radius;
|
||||
};
|
||||
|
||||
struct _StShadowTextureClass {
|
||||
ClutterTextureClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (StShadowTexture, st_shadow_texture, CLUTTER_TYPE_TEXTURE);
|
||||
|
||||
static gdouble *
|
||||
calculate_gaussian_kernel (gdouble sigma, guint n_values)
|
||||
{
|
||||
gdouble *ret, sum;
|
||||
gdouble exp_divisor;
|
||||
gint half, i;
|
||||
|
||||
g_return_val_if_fail ((int) sigma > 0, NULL);
|
||||
|
||||
half = n_values / 2;
|
||||
|
||||
ret = g_malloc (n_values * sizeof (gdouble));
|
||||
sum = 0.0;
|
||||
|
||||
exp_divisor = 2 * sigma * sigma;
|
||||
|
||||
/* n_values of 1D Gauss function */
|
||||
for (i = 0; i < n_values; i++)
|
||||
{
|
||||
ret[i] = exp (-(i - half) * (i - half) / exp_divisor);
|
||||
sum += ret[i];
|
||||
}
|
||||
|
||||
/* normalize */
|
||||
for (i = 0; i < n_values; i++)
|
||||
ret[i] /= sum;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
st_shadow_texture_create_shadow (StShadowTexture *st,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
CoglHandle texture, material;
|
||||
guchar *pixels_in, *pixels_out;
|
||||
gint width_in, height_in, rowstride_in;
|
||||
gint width_out, height_out, rowstride_out;
|
||||
|
||||
g_return_if_fail (ST_IS_SHADOW_TEXTURE (st));
|
||||
|
||||
/* Right now we only deal with actors of type ClutterTexture.
|
||||
It would be nice to extend this to generic actors with some
|
||||
clutter_texture_new_from_actor magic in the future */
|
||||
g_return_if_fail (CLUTTER_IS_TEXTURE (actor));
|
||||
|
||||
texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (actor));
|
||||
if (texture == COGL_INVALID_HANDLE)
|
||||
return;
|
||||
|
||||
width_in = cogl_texture_get_width (texture);
|
||||
height_in = cogl_texture_get_height (texture);
|
||||
rowstride_in = (width_in + 3) & ~3;
|
||||
|
||||
pixels_in = g_malloc0 (rowstride_in * height_in);
|
||||
|
||||
cogl_texture_get_data (texture, COGL_PIXEL_FORMAT_A_8,
|
||||
rowstride_in, pixels_in);
|
||||
cogl_texture_unref (texture);
|
||||
|
||||
if ((guint) st->blur_radius == 0)
|
||||
{
|
||||
width_out = width_in;
|
||||
height_out = height_in;
|
||||
rowstride_out = rowstride_in;
|
||||
pixels_out = g_memdup (pixels_in, rowstride_out * height_out);
|
||||
}
|
||||
else
|
||||
{
|
||||
gdouble *kernel;
|
||||
guchar *line;
|
||||
gint n_values, half;
|
||||
gint x_in, y_in, x_out, y_out, i;
|
||||
|
||||
n_values = (gint) 5 * st->sigma;
|
||||
half = n_values / 2;
|
||||
|
||||
width_out = width_in + 2 * half;
|
||||
height_out = height_in + 2 * half;
|
||||
rowstride_out = (width_out + 3) & ~3;
|
||||
|
||||
pixels_out = g_malloc0 (rowstride_out * height_out);
|
||||
line = g_malloc0 (rowstride_out);
|
||||
|
||||
kernel = calculate_gaussian_kernel (st->sigma, n_values);
|
||||
|
||||
/* vertical blur */
|
||||
for (x_in = 0; x_in < width_in; x_in++)
|
||||
for (y_out = 0; y_out < height_out; y_out++)
|
||||
{
|
||||
guchar *pixel_in, *pixel_out;
|
||||
gint i0, i1;
|
||||
|
||||
y_in = y_out - half;
|
||||
|
||||
/* We read from the source at 'y = y_in + i - half'; clamp the
|
||||
* full i range [0, n_values) so that y is in [0, height_in).
|
||||
*/
|
||||
i0 = MAX (half - y_in, 0);
|
||||
i1 = MIN (height_in + half - y_in, n_values);
|
||||
|
||||
pixel_in = pixels_in + (y_in + i0 - half) * rowstride_in + x_in;
|
||||
pixel_out = pixels_out + y_out * rowstride_out + (x_in + half);
|
||||
|
||||
for (i = i0; i < i1; i++)
|
||||
{
|
||||
*pixel_out += *pixel_in * kernel[i];
|
||||
pixel_in += rowstride_in;
|
||||
}
|
||||
}
|
||||
|
||||
/* horizontal blur */
|
||||
for (y_out = 0; y_out < height_out; y_out++)
|
||||
{
|
||||
memcpy (line, pixels_out + y_out * rowstride_out, rowstride_out);
|
||||
|
||||
for (x_out = 0; x_out < width_out; x_out++)
|
||||
{
|
||||
gint i0, i1;
|
||||
guchar *pixel_out, *pixel_in;
|
||||
|
||||
/* We read from the source at 'x = x_out + i - half'; clamp the
|
||||
* full i range [0, n_values) so that x is in [0, width_out).
|
||||
*/
|
||||
i0 = MAX (half - x_out, 0);
|
||||
i1 = MIN (width_out + half - x_out, n_values);
|
||||
|
||||
pixel_in = line + x_out + i0 - half;
|
||||
pixel_out = pixels_out + rowstride_out * y_out + x_out;
|
||||
|
||||
*pixel_out = 0;
|
||||
for (i = i0; i < i1; i++)
|
||||
{
|
||||
*pixel_out += *pixel_in * kernel[i];
|
||||
pixel_in++;
|
||||
}
|
||||
}
|
||||
}
|
||||
g_free (kernel);
|
||||
g_free (line);
|
||||
}
|
||||
|
||||
material = cogl_material_new ();
|
||||
texture = cogl_texture_new_from_data (width_out,
|
||||
height_out,
|
||||
COGL_TEXTURE_NONE,
|
||||
COGL_PIXEL_FORMAT_A_8,
|
||||
COGL_PIXEL_FORMAT_A_8,
|
||||
rowstride_out,
|
||||
pixels_out);
|
||||
|
||||
cogl_material_set_layer_combine_constant (material, 0, &st->color);
|
||||
cogl_material_set_layer (material, 0, texture);
|
||||
|
||||
/* We ignore the material color, which encodes the overall opacity of the
|
||||
* actor, so setting an ancestor of the shadow to partially opaque won't
|
||||
* work. The easiest way to fix this would be to override paint(). */
|
||||
|
||||
cogl_material_set_layer_combine (material, 0,
|
||||
"RGBA = MODULATE (CONSTANT, TEXTURE[A])",
|
||||
NULL);
|
||||
|
||||
clutter_texture_set_cogl_material (CLUTTER_TEXTURE (st), material);
|
||||
|
||||
cogl_texture_unref (texture);
|
||||
cogl_material_unref (material);
|
||||
|
||||
g_free (pixels_in);
|
||||
g_free (pixels_out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* st_shadow_texture_adjust_allocation:
|
||||
* @shadow: a #StShadowTexture
|
||||
* @allocation: the original allocation of @shadow
|
||||
*
|
||||
* Adjust @allocation to account for size change caused by blurrimg
|
||||
*/
|
||||
void
|
||||
st_shadow_texture_adjust_allocation (StShadowTexture *shadow,
|
||||
ClutterActorBox *allocation)
|
||||
{
|
||||
g_return_if_fail (ST_IS_SHADOW_TEXTURE (shadow));
|
||||
g_return_if_fail (allocation != NULL);
|
||||
|
||||
allocation->x1 -= shadow->blur_radius;
|
||||
allocation->y1 -= shadow->blur_radius;
|
||||
allocation->x2 += shadow->blur_radius;
|
||||
allocation->y2 += shadow->blur_radius;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* st_shadow_texture_new:
|
||||
* @actor: the original actor
|
||||
* @color: (allow-none): the shadow color
|
||||
* @blur: the shadow's blur radius
|
||||
*
|
||||
* Create a shadow texture for @actor. When %NULL is passed for @color, it
|
||||
* defaults to fully opaque black.
|
||||
*
|
||||
* Returns: a new #ClutterActor holding a shadow texture for @actor
|
||||
*/
|
||||
ClutterActor *
|
||||
st_shadow_texture_new (ClutterActor *actor,
|
||||
ClutterColor *color,
|
||||
gdouble blur)
|
||||
{
|
||||
StShadowTexture *st = g_object_new (ST_TYPE_SHADOW_TEXTURE, NULL);
|
||||
|
||||
if (color)
|
||||
{
|
||||
cogl_color_set_from_4ub (&st->color,
|
||||
color->red, color->green,
|
||||
color->blue, color->alpha);
|
||||
cogl_color_premultiply (&st->color);
|
||||
}
|
||||
|
||||
st->blur_radius = blur;
|
||||
/* we use an approximation of the sigma - blur radius relationship used
|
||||
in Firefox for doing SVG blurs; see
|
||||
http://mxr.mozilla.org/mozilla-central/source/gfx/thebes/src/gfxBlur.cpp#280
|
||||
*/
|
||||
st->sigma = blur / 1.9;
|
||||
|
||||
st_shadow_texture_create_shadow (st, actor);
|
||||
|
||||
return CLUTTER_ACTOR (st);
|
||||
}
|
||||
|
||||
static void
|
||||
st_shadow_texture_init (StShadowTexture *st)
|
||||
{
|
||||
st->sigma = 0.0;
|
||||
st->blur_radius = 0.0;
|
||||
|
||||
cogl_color_set_from_4ub (&st->color, 0x0, 0x0, 0x0, 0xff);
|
||||
}
|
||||
|
||||
static void
|
||||
st_shadow_texture_class_init (StShadowTextureClass *klass)
|
||||
{
|
||||
}
|
30
src/st/st-shadow-texture.h
Normal file
30
src/st/st-shadow-texture.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#ifndef __ST_SHADOW_TEXTURE__
|
||||
#define __ST_SHADOW_TEXTURE__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _StShadowTexture StShadowTexture;
|
||||
typedef struct _StShadowTextureClass StShadowTextureClass;
|
||||
|
||||
#define ST_TYPE_SHADOW_TEXTURE (st_shadow_texture_get_type ())
|
||||
#define ST_SHADOW_TEXTURE(object) (G_TYPE_CHECK_INSTANCE_CAST((object),ST_TYPE_SHADOW_TEXTURE, StShadowTexture))
|
||||
#define ST_IS_SHADOW_TEXTURE(object) (G_TYPE_CHECK_INSTANCE_TYPE((object),ST_TYPE_SHADOW_TEXTURE))
|
||||
#define ST_SHADOW_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), ST_TYPE_SHADOW_TEXTURE, StShadowTextureClass))
|
||||
#define ST_IS_SHADOW_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), ST_TYPE_SHADOW_TEXTURE))
|
||||
#define ST_SHADOW_TEXTURE_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), ST_TYPE_SHADOW_TEXTURE, StShadowTextureClass))
|
||||
|
||||
GType st_shadow_texture_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterActor *st_shadow_texture_new (ClutterActor *actor,
|
||||
ClutterColor *color,
|
||||
gdouble blur_radius);
|
||||
|
||||
void st_shadow_texture_adjust_allocation (StShadowTexture *shadow,
|
||||
ClutterActorBox *allocation);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_SHADOW_TEXTURE__ */
|
89
src/st/st-shadow.c
Normal file
89
src/st/st-shadow.c
Normal file
@ -0,0 +1,89 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#include "config.h"
|
||||
|
||||
#include "st-shadow.h"
|
||||
|
||||
/**
|
||||
* SECTION: st-shadow
|
||||
* @short_description: Boxed type for -st-shadow attributes
|
||||
*
|
||||
* #StShadow is a boxed type for storing attributes of the -st-shadow
|
||||
* property, modelled liberally after the CSS3 box-shadow property.
|
||||
* See http://www.css3.info/preview/box-shadow/
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* st_shadow_new:
|
||||
* @color: shadow's color
|
||||
* @xoffset: horizontal offset
|
||||
* @yoffset: vertical offset
|
||||
* @blur: blur radius
|
||||
*
|
||||
* Creates a new #StShadow
|
||||
*
|
||||
* Returns: the newly allocated shadow. Use st_shadow_free() when done
|
||||
*/
|
||||
StShadow *
|
||||
st_shadow_new (ClutterColor *color,
|
||||
gdouble xoffset,
|
||||
gdouble yoffset,
|
||||
gdouble blur)
|
||||
{
|
||||
StShadow *shadow;
|
||||
|
||||
shadow = g_slice_new (StShadow);
|
||||
|
||||
shadow->color = *color;
|
||||
shadow->xoffset = xoffset;
|
||||
shadow->yoffset = yoffset;
|
||||
shadow->blur = blur;
|
||||
|
||||
return shadow;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_shadow_copy:
|
||||
* @shadow: a #StShadow
|
||||
*
|
||||
* Makes a copy of @shadow.
|
||||
*
|
||||
* Returns: an allocated copy of @shadow - the result must be freed with
|
||||
* st_shadow_free() when done
|
||||
*/
|
||||
StShadow *
|
||||
st_shadow_copy (const StShadow *shadow)
|
||||
{
|
||||
g_return_val_if_fail (shadow != NULL, NULL);
|
||||
|
||||
return g_slice_dup (StShadow, shadow);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_shadow_free:
|
||||
* @shadow: a #StShadow
|
||||
*
|
||||
* Frees the shadow structure created with st_shadow_new() or
|
||||
* st_shadow_copy()
|
||||
*/
|
||||
void
|
||||
st_shadow_free (StShadow *shadow)
|
||||
{
|
||||
g_return_if_fail (shadow != NULL);
|
||||
|
||||
g_slice_free (StShadow, shadow);
|
||||
}
|
||||
|
||||
GType
|
||||
st_shadow_get_type (void)
|
||||
{
|
||||
static GType _st_shadow_type = 0;
|
||||
|
||||
if (G_UNLIKELY (_st_shadow_type == 0))
|
||||
_st_shadow_type =
|
||||
g_boxed_type_register_static ("StShadow",
|
||||
(GBoxedCopyFunc) st_shadow_copy,
|
||||
(GBoxedFreeFunc) st_shadow_free);
|
||||
|
||||
return _st_shadow_type;
|
||||
}
|
42
src/st/st-shadow.h
Normal file
42
src/st/st-shadow.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#ifndef __ST_SHADOW__
|
||||
#define __ST_SHADOW__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define ST_TYPE_SHADOW (st_shadow_get_type ())
|
||||
|
||||
typedef struct _StShadow StShadow;
|
||||
|
||||
/**
|
||||
* StShadow:
|
||||
* @color: shadow's color
|
||||
* @xoffset: horizontal offset - positive values mean placement to the right,
|
||||
* negative values placement to the left of the element.
|
||||
* @yoffset: vertical offset - positive values mean placement below, negative
|
||||
* values placement above the element.
|
||||
* @blur: shadow's blur radius - a value of 0.0 will result in a hard shadow.
|
||||
*
|
||||
* Attributes of the -st-shadow property.
|
||||
*/
|
||||
struct _StShadow {
|
||||
ClutterColor color;
|
||||
gdouble xoffset;
|
||||
gdouble yoffset;
|
||||
gdouble blur;
|
||||
};
|
||||
|
||||
GType st_shadow_get_type (void) G_GNUC_CONST;
|
||||
|
||||
StShadow *st_shadow_new (ClutterColor *color,
|
||||
gdouble xoffset,
|
||||
gdouble yoffset,
|
||||
gdouble blur);
|
||||
StShadow *st_shadow_copy (const StShadow *shadow);
|
||||
void st_shadow_free (StShadow *shadow);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_SHADOW__ */
|
@ -39,6 +39,7 @@ struct _StThemeNode {
|
||||
|
||||
char *background_image;
|
||||
StBorderImage *border_image;
|
||||
StShadow *shadow;
|
||||
|
||||
GType element_type;
|
||||
char *element_id;
|
||||
@ -57,6 +58,7 @@ struct _StThemeNode {
|
||||
guint background_computed : 1;
|
||||
guint foreground_computed : 1;
|
||||
guint border_image_computed : 1;
|
||||
guint shadow_computed : 1;
|
||||
guint link_type : 2;
|
||||
};
|
||||
|
||||
@ -118,6 +120,12 @@ st_theme_node_finalize (GObject *object)
|
||||
node->border_image = NULL;
|
||||
}
|
||||
|
||||
if (node->shadow)
|
||||
{
|
||||
st_shadow_free (node->shadow);
|
||||
node->shadow = NULL;
|
||||
}
|
||||
|
||||
if (node->background_image)
|
||||
g_free (node->background_image);
|
||||
|
||||
@ -2116,6 +2124,87 @@ st_theme_node_get_border_image (StThemeNode *node)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_theme_node_get_shadow:
|
||||
* @node: a #StThemeNode
|
||||
*
|
||||
* Gets the value for the -st-shadow style property
|
||||
*
|
||||
* Return value: (transfer none): the node's shadow, or %NULL
|
||||
* if node has no shadow
|
||||
*/
|
||||
StShadow *
|
||||
st_theme_node_get_shadow (StThemeNode *node)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (node->shadow_computed)
|
||||
return node->shadow;
|
||||
|
||||
node->shadow = NULL;
|
||||
node->shadow_computed = TRUE;
|
||||
|
||||
ensure_properties (node);
|
||||
|
||||
for (i = node->n_properties - 1; i >= 0; i--)
|
||||
{
|
||||
CRDeclaration *decl = node->properties[i];
|
||||
|
||||
if (strcmp (decl->property->stryng->str, "-st-shadow") == 0)
|
||||
{
|
||||
/* Set value for width/color/blur in any order */
|
||||
CRTerm *term;
|
||||
ClutterColor color = { 0x0, 0x0, 0x0, 0xff };
|
||||
gdouble xoffset = 0.;
|
||||
gdouble yoffset = 0.;
|
||||
gdouble blur = 0.;
|
||||
int n_offsets = 0;
|
||||
|
||||
for (term = decl->value; term; term = term->next)
|
||||
{
|
||||
GetFromTermResult result;
|
||||
|
||||
if (term->type == TERM_NUMBER)
|
||||
{
|
||||
gdouble value;
|
||||
gdouble multiplier;
|
||||
|
||||
multiplier = (term->unary_op == MINUS_UOP) ? -1. : 1.;
|
||||
result = get_length_from_term (node, term, FALSE, &value);
|
||||
if (result != VALUE_NOT_FOUND)
|
||||
{
|
||||
switch (n_offsets++)
|
||||
{
|
||||
case 0:
|
||||
xoffset = multiplier * value;
|
||||
break;
|
||||
case 1:
|
||||
yoffset = multiplier * value;
|
||||
break;
|
||||
case 2:
|
||||
if (multiplier < 0)
|
||||
g_warning ("Negative blur values are "
|
||||
"not allowed");
|
||||
blur = value;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
result = get_color_from_term (node, term, &color);
|
||||
if (result != VALUE_NOT_FOUND)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
node->shadow = st_shadow_new (&color, xoffset, yoffset, blur);
|
||||
|
||||
return node->shadow;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static float
|
||||
get_width_inc (StThemeNode *node)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include "st-border-image.h"
|
||||
#include "st-shadow.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -142,6 +143,7 @@ StTextDecoration st_theme_node_get_text_decoration (StThemeNode *node);
|
||||
const PangoFontDescription *st_theme_node_get_font (StThemeNode *node);
|
||||
|
||||
StBorderImage *st_theme_node_get_border_image (StThemeNode *node);
|
||||
StShadow *st_theme_node_get_shadow (StThemeNode *node);
|
||||
|
||||
/* Helpers for get_preferred_width()/get_preferred_height() ClutterActor vfuncs */
|
||||
void st_theme_node_adjust_for_height (StThemeNode *node,
|
||||
|
@ -37,6 +37,7 @@
|
||||
|
||||
#include "st-marshal.h"
|
||||
#include "st-private.h"
|
||||
#include "st-shadow-texture.h"
|
||||
#include "st-texture-cache.h"
|
||||
#include "st-texture-frame.h"
|
||||
#include "st-theme-context.h"
|
||||
@ -57,11 +58,15 @@ struct _StWidgetPrivate
|
||||
|
||||
ClutterActor *border_image;
|
||||
ClutterActor *background_image;
|
||||
ClutterActor *background_image_shadow;
|
||||
ClutterColor bg_color;
|
||||
|
||||
StGradientType bg_gradient_type;
|
||||
ClutterColor bg_gradient_end;
|
||||
|
||||
gdouble shadow_xoffset;
|
||||
gdouble shadow_yoffset;
|
||||
|
||||
gboolean is_stylable : 1;
|
||||
gboolean has_tooltip : 1;
|
||||
gboolean is_style_dirty : 1;
|
||||
@ -227,6 +232,12 @@ st_widget_dispose (GObject *gobject)
|
||||
priv->border_image = NULL;
|
||||
}
|
||||
|
||||
if (priv->background_image_shadow)
|
||||
{
|
||||
clutter_actor_unparent (priv->background_image_shadow);
|
||||
priv->background_image_shadow = NULL;
|
||||
}
|
||||
|
||||
if (priv->tooltip)
|
||||
{
|
||||
ClutterContainer *parent;
|
||||
@ -356,6 +367,28 @@ st_widget_allocate (ClutterActor *actor,
|
||||
frame_box.y2 = frame_box.y1 + h;
|
||||
}
|
||||
|
||||
if (priv->background_image_shadow)
|
||||
{
|
||||
StShadowTexture *shadow;
|
||||
ClutterActorBox shadow_box;
|
||||
|
||||
shadow_box.x1 = frame_box.x1 + priv->shadow_xoffset;
|
||||
shadow_box.y1 = frame_box.y1 + priv->shadow_yoffset;
|
||||
shadow_box.x2 = frame_box.x2 + priv->shadow_xoffset;
|
||||
shadow_box.y2 = frame_box.y2 + priv->shadow_yoffset;
|
||||
|
||||
/* The shadow texture is larger than the original image due
|
||||
to blurring, so we let it adjust its size.
|
||||
When the original image has been scaled, this will change
|
||||
the effective blur radius - we ignore this for now. */
|
||||
shadow = ST_SHADOW_TEXTURE (priv->background_image_shadow);
|
||||
st_shadow_texture_adjust_allocation (shadow, &shadow_box);
|
||||
|
||||
clutter_actor_allocate (priv->background_image_shadow,
|
||||
&shadow_box, flags);
|
||||
}
|
||||
|
||||
|
||||
clutter_actor_allocate (CLUTTER_ACTOR (priv->background_image),
|
||||
&frame_box,
|
||||
flags);
|
||||
@ -497,7 +530,11 @@ st_widget_paint (ClutterActor *self)
|
||||
klass->draw_background (ST_WIDGET (self));
|
||||
|
||||
if (priv->background_image != NULL)
|
||||
clutter_actor_paint (priv->background_image);
|
||||
{
|
||||
if (priv->background_image_shadow)
|
||||
clutter_actor_paint (priv->background_image_shadow);
|
||||
clutter_actor_paint (priv->background_image);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -527,6 +564,9 @@ st_widget_map (ClutterActor *actor)
|
||||
|
||||
st_widget_ensure_style ((StWidget*) actor);
|
||||
|
||||
if (priv->background_image_shadow)
|
||||
clutter_actor_map (priv->background_image_shadow);
|
||||
|
||||
if (priv->border_image)
|
||||
clutter_actor_map (priv->border_image);
|
||||
|
||||
@ -544,6 +584,9 @@ st_widget_unmap (ClutterActor *actor)
|
||||
|
||||
CLUTTER_ACTOR_CLASS (st_widget_parent_class)->unmap (actor);
|
||||
|
||||
if (priv->background_image_shadow)
|
||||
clutter_actor_unmap (priv->background_image_shadow);
|
||||
|
||||
if (priv->border_image)
|
||||
clutter_actor_unmap (priv->border_image);
|
||||
|
||||
@ -659,6 +702,7 @@ st_widget_real_style_changed (StWidget *self)
|
||||
StWidgetPrivate *priv = ST_WIDGET (self)->priv;
|
||||
StThemeNode *theme_node;
|
||||
StBorderImage *border_image;
|
||||
StShadow *shadow;
|
||||
StTextureCache *texture_cache;
|
||||
ClutterTexture *texture;
|
||||
const char *bg_file = NULL;
|
||||
@ -706,6 +750,12 @@ st_widget_real_style_changed (StWidget *self)
|
||||
has_changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->background_image_shadow)
|
||||
{
|
||||
clutter_actor_unparent (priv->background_image_shadow);
|
||||
priv->background_image_shadow = NULL;
|
||||
}
|
||||
|
||||
if (priv->border_image)
|
||||
{
|
||||
clutter_actor_unparent (priv->border_image);
|
||||
@ -877,7 +927,39 @@ st_widget_real_style_changed (StWidget *self)
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
|
||||
/* If there are any properties above that need to cause a relayout thay
|
||||
/* CSS based drop shadows
|
||||
*
|
||||
* Drop shadows in ST are modelled after the CSS3 box-shadow property;
|
||||
* see http://www.css3.info/preview/box-shadow/ for a detailed description.
|
||||
*
|
||||
* While the syntax of the property is mostly identical - we do not support
|
||||
* multiple shadows and allow for a more liberal placement of the color
|
||||
* parameter - its interpretation defers significantly in that the shadow's
|
||||
* shape is not determined by the bounding box, but by the CSS background
|
||||
* image (we could exend this in the future to take other CSS properties
|
||||
* like boder and background color into account).
|
||||
*/
|
||||
shadow = st_theme_node_get_shadow (theme_node);
|
||||
if (shadow != NULL)
|
||||
{
|
||||
priv->shadow_xoffset = shadow->xoffset;
|
||||
priv->shadow_yoffset = shadow->yoffset;
|
||||
|
||||
if (priv->background_image)
|
||||
{
|
||||
priv->background_image_shadow =
|
||||
st_shadow_texture_new (priv->background_image,
|
||||
&shadow->color,
|
||||
shadow->blur);
|
||||
|
||||
clutter_actor_set_parent (priv->background_image_shadow,
|
||||
CLUTTER_ACTOR (self));
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there are any properties above that need to cause a relayout they
|
||||
* should set this flag.
|
||||
*/
|
||||
if (has_changed)
|
||||
|
Loading…
x
Reference in New Issue
Block a user