Move rendering into st-theme-node-drawing.c
The idea behind this move is that we have a lot more control over rendering if StWidget isn't a big pile of actors, and things are more efficient. https://bugzilla.gnome.org/show_bug.cgi?id=607500
This commit is contained in:
parent
a8fa8a498a
commit
5060081db5
@ -83,13 +83,11 @@ 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 \
|
||||
st/st-texture-cache.h \
|
||||
st/st-texture-frame.h \
|
||||
st/st-theme.h \
|
||||
st/st-theme-context.h \
|
||||
st/st-theme-node.h \
|
||||
@ -109,7 +107,8 @@ BUILT_SOURCES += st.h
|
||||
st_source_private_h = \
|
||||
st/st-private.h \
|
||||
st/st-table-private.h \
|
||||
st/st-theme-private.h
|
||||
st/st-theme-private.h \
|
||||
st/st-theme-node-private.h
|
||||
|
||||
# please, keep this sorted alphabetically
|
||||
st_source_c = \
|
||||
@ -130,16 +129,15 @@ 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 \
|
||||
st/st-texture-cache.c \
|
||||
st/st-texture-frame.c \
|
||||
st/st-theme.c \
|
||||
st/st-theme-context.c \
|
||||
st/st-theme-node.c \
|
||||
st/st-theme-node-drawing.c \
|
||||
st/st-tooltip.c \
|
||||
st/st-widget.c \
|
||||
$(NULL)
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include "st-button.h"
|
||||
|
||||
#include "st-marshal.h"
|
||||
#include "st-texture-frame.h"
|
||||
#include "st-texture-cache.h"
|
||||
#include "st-private.h"
|
||||
|
||||
|
@ -1,273 +0,0 @@
|
||||
/* -*- 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);
|
||||
|
||||
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_handle_unref (texture);
|
||||
cogl_handle_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)
|
||||
{
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/* -*- 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__ */
|
@ -1,621 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* st-texture-frame.h: Expandible texture actor
|
||||
*
|
||||
* Copyright 2007 OpenedHand
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:st-texture-frame
|
||||
* @short_description: Stretch a texture to fit the entire allocation
|
||||
*
|
||||
* #StTextureFrame
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
|
||||
#include "st-texture-frame.h"
|
||||
#include "st-private.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_PARENT_TEXTURE,
|
||||
|
||||
PROP_TOP,
|
||||
PROP_RIGHT,
|
||||
PROP_BOTTOM,
|
||||
PROP_LEFT
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (StTextureFrame, st_texture_frame, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
#define ST_TEXTURE_FRAME_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_TEXTURE_FRAME, StTextureFramePrivate))
|
||||
|
||||
struct _StTextureFramePrivate
|
||||
{
|
||||
ClutterTexture *parent_texture;
|
||||
|
||||
gfloat top;
|
||||
gfloat right;
|
||||
gfloat bottom;
|
||||
gfloat left;
|
||||
};
|
||||
|
||||
static void
|
||||
st_texture_frame_get_preferred_width (ClutterActor *self,
|
||||
gfloat for_height,
|
||||
gfloat *min_width_p,
|
||||
gfloat *natural_width_p)
|
||||
{
|
||||
StTextureFramePrivate *priv = ST_TEXTURE_FRAME (self)->priv;
|
||||
|
||||
if (G_UNLIKELY (priv->parent_texture == NULL))
|
||||
{
|
||||
if (min_width_p)
|
||||
*min_width_p = 0;
|
||||
|
||||
if (natural_width_p)
|
||||
*natural_width_p = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClutterActorClass *klass;
|
||||
|
||||
/* by directly querying the parent texture's class implementation
|
||||
* we are going around any override mechanism the parent texture
|
||||
* might have in place, and we ask directly for the original
|
||||
* preferred width
|
||||
*/
|
||||
klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
|
||||
klass->get_preferred_width (CLUTTER_ACTOR (priv->parent_texture),
|
||||
for_height,
|
||||
min_width_p,
|
||||
natural_width_p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_get_preferred_height (ClutterActor *self,
|
||||
gfloat for_width,
|
||||
gfloat *min_height_p,
|
||||
gfloat *natural_height_p)
|
||||
{
|
||||
StTextureFramePrivate *priv = ST_TEXTURE_FRAME (self)->priv;
|
||||
|
||||
if (G_UNLIKELY (priv->parent_texture == NULL))
|
||||
{
|
||||
if (min_height_p)
|
||||
*min_height_p = 0;
|
||||
|
||||
if (natural_height_p)
|
||||
*natural_height_p = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClutterActorClass *klass;
|
||||
|
||||
/* by directly querying the parent texture's class implementation
|
||||
* we are going around any override mechanism the parent texture
|
||||
* might have in place, and we ask directly for the original
|
||||
* preferred height
|
||||
*/
|
||||
klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
|
||||
klass->get_preferred_height (CLUTTER_ACTOR (priv->parent_texture),
|
||||
for_width,
|
||||
min_height_p,
|
||||
natural_height_p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_paint (ClutterActor *self)
|
||||
{
|
||||
StTextureFramePrivate *priv = ST_TEXTURE_FRAME (self)->priv;
|
||||
CoglHandle cogl_texture = COGL_INVALID_HANDLE;
|
||||
CoglHandle cogl_material = COGL_INVALID_HANDLE;
|
||||
ClutterActorBox box = { 0, };
|
||||
gfloat width, height;
|
||||
gfloat tex_width, tex_height;
|
||||
gfloat ex, ey;
|
||||
gfloat tx1, ty1, tx2, ty2;
|
||||
guint8 opacity;
|
||||
|
||||
/* no need to paint stuff if we don't have a texture */
|
||||
if (G_UNLIKELY (priv->parent_texture == NULL))
|
||||
return;
|
||||
|
||||
/* parent texture may have been hidden, so need to make sure it gets
|
||||
* realized
|
||||
*/
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_texture))
|
||||
clutter_actor_realize (CLUTTER_ACTOR (priv->parent_texture));
|
||||
|
||||
cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture);
|
||||
if (cogl_texture == COGL_INVALID_HANDLE)
|
||||
return;
|
||||
cogl_material = clutter_texture_get_cogl_material (priv->parent_texture);
|
||||
if (cogl_material == COGL_INVALID_HANDLE)
|
||||
return;
|
||||
|
||||
tex_width = cogl_texture_get_width (cogl_texture);
|
||||
tex_height = cogl_texture_get_height (cogl_texture);
|
||||
|
||||
clutter_actor_get_allocation_box (self, &box);
|
||||
width = box.x2 - box.x1;
|
||||
height = box.y2 - box.y1;
|
||||
|
||||
tx1 = priv->left / tex_width;
|
||||
tx2 = (tex_width - priv->right) / tex_width;
|
||||
ty1 = priv->top / tex_height;
|
||||
ty2 = (tex_height - priv->bottom) / tex_height;
|
||||
|
||||
ex = width - priv->right;
|
||||
if (ex < 0)
|
||||
ex = priv->right; /* FIXME ? */
|
||||
|
||||
ey = height - priv->bottom;
|
||||
if (ey < 0)
|
||||
ey = priv->bottom; /* FIXME ? */
|
||||
|
||||
opacity = clutter_actor_get_paint_opacity (self);
|
||||
|
||||
/* Paint using the parent texture's material. It should already have
|
||||
the cogl texture set as the first layer */
|
||||
/* NB: for correct blending we need set a preumultiplied color here: */
|
||||
cogl_material_set_color4ub (cogl_material,
|
||||
opacity, opacity, opacity, opacity);
|
||||
cogl_set_source (cogl_material);
|
||||
|
||||
{
|
||||
GLfloat rectangles[] =
|
||||
{
|
||||
/* top left corner */
|
||||
0, 0, priv->left, priv->top,
|
||||
0.0, 0.0,
|
||||
tx1, ty1,
|
||||
|
||||
/* top middle */
|
||||
priv->left, 0, ex, priv->top,
|
||||
tx1, 0.0,
|
||||
tx2, ty1,
|
||||
|
||||
/* top right */
|
||||
ex, 0, width, priv->top,
|
||||
tx2, 0.0,
|
||||
1.0, ty1,
|
||||
|
||||
/* mid left */
|
||||
0, priv->top, priv->left, ey,
|
||||
0.0, ty1,
|
||||
tx1, ty2,
|
||||
|
||||
/* center */
|
||||
priv->left, priv->top, ex, ey,
|
||||
tx1, ty1,
|
||||
tx2, ty2,
|
||||
|
||||
/* mid right */
|
||||
ex, priv->top, width, ey,
|
||||
tx2, ty1,
|
||||
1.0, ty2,
|
||||
|
||||
/* bottom left */
|
||||
0, ey, priv->left, height,
|
||||
0.0, ty2,
|
||||
tx1, 1.0,
|
||||
|
||||
/* bottom center */
|
||||
priv->left, ey, ex, height,
|
||||
tx1, ty2,
|
||||
tx2, 1.0,
|
||||
|
||||
/* bottom right */
|
||||
ex, ey, width, height,
|
||||
tx2, ty2,
|
||||
1.0, 1.0
|
||||
};
|
||||
|
||||
cogl_rectangles_with_texture_coords (rectangles, 9);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
st_texture_frame_set_frame_internal (StTextureFrame *frame,
|
||||
gfloat top,
|
||||
gfloat right,
|
||||
gfloat bottom,
|
||||
gfloat left)
|
||||
{
|
||||
StTextureFramePrivate *priv = frame->priv;
|
||||
GObject *gobject = G_OBJECT (frame);
|
||||
gboolean changed = FALSE;
|
||||
|
||||
g_object_freeze_notify (gobject);
|
||||
|
||||
if (priv->top != top)
|
||||
{
|
||||
priv->top = top;
|
||||
g_object_notify (gobject, "top");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->right != right)
|
||||
{
|
||||
priv->right = right;
|
||||
g_object_notify (gobject, "right");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->bottom != bottom)
|
||||
{
|
||||
priv->bottom = bottom;
|
||||
g_object_notify (gobject, "bottom");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->left != left)
|
||||
{
|
||||
priv->left = left;
|
||||
g_object_notify (gobject, "left");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (changed && CLUTTER_ACTOR_IS_VISIBLE (frame))
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (frame));
|
||||
|
||||
g_object_thaw_notify (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StTextureFrame *frame = ST_TEXTURE_FRAME (gobject);
|
||||
StTextureFramePrivate *priv = frame->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PARENT_TEXTURE:
|
||||
st_texture_frame_set_parent_texture (frame,
|
||||
g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_TOP:
|
||||
st_texture_frame_set_frame_internal (frame,
|
||||
g_value_get_float (value),
|
||||
priv->right,
|
||||
priv->bottom,
|
||||
priv->left);
|
||||
break;
|
||||
|
||||
case PROP_RIGHT:
|
||||
st_texture_frame_set_frame_internal (frame,
|
||||
priv->top,
|
||||
g_value_get_float (value),
|
||||
priv->bottom,
|
||||
priv->left);
|
||||
break;
|
||||
|
||||
case PROP_BOTTOM:
|
||||
st_texture_frame_set_frame_internal (frame,
|
||||
priv->top,
|
||||
priv->right,
|
||||
g_value_get_float (value),
|
||||
priv->left);
|
||||
break;
|
||||
|
||||
case PROP_LEFT:
|
||||
st_texture_frame_set_frame_internal (frame,
|
||||
priv->top,
|
||||
priv->right,
|
||||
priv->bottom,
|
||||
g_value_get_float (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StTextureFramePrivate *priv = ST_TEXTURE_FRAME (gobject)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PARENT_TEXTURE:
|
||||
g_value_set_object (value, priv->parent_texture);
|
||||
break;
|
||||
|
||||
case PROP_LEFT:
|
||||
g_value_set_float (value, priv->left);
|
||||
break;
|
||||
|
||||
case PROP_TOP:
|
||||
g_value_set_float (value, priv->top);
|
||||
break;
|
||||
|
||||
case PROP_RIGHT:
|
||||
g_value_set_float (value, priv->right);
|
||||
break;
|
||||
|
||||
case PROP_BOTTOM:
|
||||
g_value_set_float (value, priv->bottom);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_dispose (GObject *gobject)
|
||||
{
|
||||
StTextureFramePrivate *priv = ST_TEXTURE_FRAME (gobject)->priv;
|
||||
|
||||
if (priv->parent_texture)
|
||||
{
|
||||
g_object_unref (priv->parent_texture);
|
||||
priv->parent_texture = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (st_texture_frame_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_class_init (StTextureFrameClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
GParamSpec *pspec;
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (StTextureFramePrivate));
|
||||
|
||||
actor_class->get_preferred_width =
|
||||
st_texture_frame_get_preferred_width;
|
||||
actor_class->get_preferred_height =
|
||||
st_texture_frame_get_preferred_height;
|
||||
actor_class->paint = st_texture_frame_paint;
|
||||
|
||||
gobject_class->set_property = st_texture_frame_set_property;
|
||||
gobject_class->get_property = st_texture_frame_get_property;
|
||||
gobject_class->dispose = st_texture_frame_dispose;
|
||||
|
||||
pspec = g_param_spec_object ("parent-texture",
|
||||
"Parent Texture",
|
||||
"The parent ClutterTexture",
|
||||
CLUTTER_TYPE_TEXTURE,
|
||||
ST_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT);
|
||||
g_object_class_install_property (gobject_class, PROP_PARENT_TEXTURE, pspec);
|
||||
|
||||
pspec = g_param_spec_float ("left",
|
||||
"Left",
|
||||
"Left offset",
|
||||
0, G_MAXFLOAT,
|
||||
0,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_LEFT, pspec);
|
||||
|
||||
pspec = g_param_spec_float ("top",
|
||||
"Top",
|
||||
"Top offset",
|
||||
0, G_MAXFLOAT,
|
||||
0,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_TOP, pspec);
|
||||
|
||||
pspec = g_param_spec_float ("bottom",
|
||||
"Bottom",
|
||||
"Bottom offset",
|
||||
0, G_MAXFLOAT,
|
||||
0,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_BOTTOM, pspec);
|
||||
|
||||
pspec = g_param_spec_float ("right",
|
||||
"Right",
|
||||
"Right offset",
|
||||
0, G_MAXFLOAT,
|
||||
0,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_RIGHT, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_init (StTextureFrame *self)
|
||||
{
|
||||
StTextureFramePrivate *priv;
|
||||
|
||||
self->priv = priv = ST_TEXTURE_FRAME_GET_PRIVATE (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_frame_new:
|
||||
* @texture: a #ClutterTexture or %NULL
|
||||
* @left: left margin preserving its content
|
||||
* @top: top margin preserving its content
|
||||
* @right: right margin preserving its content
|
||||
* @bottom: bottom margin preserving its content
|
||||
*
|
||||
* A #StTextureFrame is a specialized texture that efficiently clones
|
||||
* an area of the given @texture while keeping preserving portions of the
|
||||
* same texture.
|
||||
*
|
||||
* A #StTextureFrame can be used to make a rectangular texture fit a
|
||||
* given size without stretching its borders.
|
||||
*
|
||||
* Return value: the newly created #StTextureFrame
|
||||
*/
|
||||
ClutterActor*
|
||||
st_texture_frame_new (ClutterTexture *texture,
|
||||
gfloat top,
|
||||
gfloat right,
|
||||
gfloat bottom,
|
||||
gfloat left)
|
||||
{
|
||||
g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
|
||||
|
||||
return g_object_new (ST_TYPE_TEXTURE_FRAME,
|
||||
"parent-texture", texture,
|
||||
"top", top,
|
||||
"right", right,
|
||||
"bottom", bottom,
|
||||
"left", left,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_frame_get_parent_texture:
|
||||
* @frame: A #StTextureFrame
|
||||
*
|
||||
* Return the texture used by the #StTextureFrame
|
||||
*
|
||||
* Returns: (transfer none): a #ClutterTexture owned by the #StTextureFrame
|
||||
*/
|
||||
ClutterTexture *
|
||||
st_texture_frame_get_parent_texture (StTextureFrame *frame)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_TEXTURE_FRAME (frame), NULL);
|
||||
|
||||
return frame->priv->parent_texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_frame_set_parent_texture:
|
||||
* @frame: A #StTextureFrame
|
||||
* @texture: A #ClutterTexture
|
||||
*
|
||||
* Set the #ClutterTexture used by this #StTextureFrame
|
||||
*
|
||||
*/
|
||||
void
|
||||
st_texture_frame_set_parent_texture (StTextureFrame *frame,
|
||||
ClutterTexture *texture)
|
||||
{
|
||||
StTextureFramePrivate *priv;
|
||||
gboolean was_visible;
|
||||
|
||||
g_return_if_fail (ST_IS_TEXTURE_FRAME (frame));
|
||||
g_return_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture));
|
||||
|
||||
priv = frame->priv;
|
||||
|
||||
was_visible = CLUTTER_ACTOR_IS_VISIBLE (frame);
|
||||
|
||||
if (priv->parent_texture == texture)
|
||||
return;
|
||||
|
||||
if (priv->parent_texture)
|
||||
{
|
||||
g_object_unref (priv->parent_texture);
|
||||
priv->parent_texture = NULL;
|
||||
|
||||
if (was_visible)
|
||||
clutter_actor_hide (CLUTTER_ACTOR (frame));
|
||||
}
|
||||
|
||||
if (texture)
|
||||
{
|
||||
priv->parent_texture = g_object_ref_sink (texture);
|
||||
|
||||
if (was_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture))
|
||||
clutter_actor_show (CLUTTER_ACTOR (frame));
|
||||
}
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
|
||||
|
||||
g_object_notify (G_OBJECT (frame), "parent-texture");
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_frame_set_frame:
|
||||
* @frame: A #StTextureFrame
|
||||
* @top: width of the top slice
|
||||
* @right: width of the right slice
|
||||
* @bottom: width of the bottom slice
|
||||
* @left: width of the left slice
|
||||
*
|
||||
* Set the slice lines of the specified frame. The slices are calculated as
|
||||
* widths from the edge of the frame.
|
||||
*
|
||||
*/
|
||||
void
|
||||
st_texture_frame_set_frame (StTextureFrame *frame,
|
||||
gfloat top,
|
||||
gfloat right,
|
||||
gfloat bottom,
|
||||
gfloat left)
|
||||
{
|
||||
g_return_if_fail (ST_IS_TEXTURE_FRAME (frame));
|
||||
|
||||
st_texture_frame_set_frame_internal (frame, top, right, bottom, left);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_frame_get_frame:
|
||||
* @frame: A #StTextureFrame
|
||||
* @top: width of the top slice
|
||||
* @right: width of the right slice
|
||||
* @bottom: width of the bottom slice
|
||||
* @left: width of the left slice
|
||||
*
|
||||
* Retrieve the current slice lines from the specified frame.
|
||||
*
|
||||
*/
|
||||
void
|
||||
st_texture_frame_get_frame (StTextureFrame *frame,
|
||||
gfloat *top,
|
||||
gfloat *right,
|
||||
gfloat *bottom,
|
||||
gfloat *left)
|
||||
{
|
||||
StTextureFramePrivate *priv;
|
||||
|
||||
g_return_if_fail (ST_IS_TEXTURE_FRAME (frame));
|
||||
|
||||
priv = frame->priv;
|
||||
|
||||
if (top)
|
||||
*top = priv->top;
|
||||
|
||||
if (right)
|
||||
*right = priv->right;
|
||||
|
||||
if (bottom)
|
||||
*bottom = priv->bottom;
|
||||
|
||||
if (left)
|
||||
*left = priv->left;
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* st-texture-frame.h: Expandible texture actor
|
||||
*
|
||||
* Copyright 2007, 2008 OpenedHand Ltd
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||
#error "Only <st/st.h> can be included directly.h"
|
||||
#endif
|
||||
|
||||
#ifndef __ST_TEXTURE_FRAME_H__
|
||||
#define __ST_TEXTURE_FRAME_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define ST_TYPE_TEXTURE_FRAME (st_texture_frame_get_type ())
|
||||
#define ST_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_TEXTURE_FRAME, StTextureFrame))
|
||||
#define ST_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_TEXTURE_FRAME, StTextureFrameClass))
|
||||
#define ST_IS_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_TEXTURE_FRAME))
|
||||
#define ST_IS_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_TEXTURE_FRAME))
|
||||
#define ST_TEXTURE_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_TEXTURE_FRAME, StTextureFrameClass))
|
||||
|
||||
typedef struct _StTextureFrame StTextureFrame;
|
||||
typedef struct _StTextureFramePrivate StTextureFramePrivate;
|
||||
typedef struct _StTextureFrameClass StTextureFrameClass;
|
||||
|
||||
/**
|
||||
* StTextureFrame:
|
||||
*
|
||||
* The contents of this structure are private and should only be accessed
|
||||
* through the public API.
|
||||
*/
|
||||
struct _StTextureFrame
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterActor parent_instance;
|
||||
|
||||
StTextureFramePrivate *priv;
|
||||
};
|
||||
|
||||
struct _StTextureFrameClass
|
||||
{
|
||||
ClutterActorClass parent_class;
|
||||
|
||||
/* padding for future expansion */
|
||||
void (*_clutter_box_1) (void);
|
||||
void (*_clutter_box_2) (void);
|
||||
void (*_clutter_box_3) (void);
|
||||
void (*_clutter_box_4) (void);
|
||||
};
|
||||
|
||||
GType st_texture_frame_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterActor * st_texture_frame_new (ClutterTexture *texture,
|
||||
gfloat top,
|
||||
gfloat right,
|
||||
gfloat bottom,
|
||||
gfloat left);
|
||||
void st_texture_frame_set_parent_texture (StTextureFrame *frame,
|
||||
ClutterTexture *texture);
|
||||
ClutterTexture *st_texture_frame_get_parent_texture (StTextureFrame *frame);
|
||||
void st_texture_frame_set_frame (StTextureFrame *frame,
|
||||
gfloat top,
|
||||
gfloat right,
|
||||
gfloat bottom,
|
||||
gfloat left);
|
||||
void st_texture_frame_get_frame (StTextureFrame *frame,
|
||||
gfloat *top,
|
||||
gfloat *right,
|
||||
gfloat *bottom,
|
||||
gfloat *left);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_TEXTURE_FRAME_H__ */
|
1097
src/st/st-theme-node-drawing.c
Normal file
1097
src/st/st-theme-node-drawing.c
Normal file
File diff suppressed because it is too large
Load Diff
86
src/st/st-theme-node-private.h
Normal file
86
src/st/st-theme-node-private.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#ifndef __ST_THEME_NODE_PRIVATE_H__
|
||||
#define __ST_THEME_NODE_PRIVATE_H__
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#include "st-theme-node.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct _StThemeNode {
|
||||
GObject parent;
|
||||
|
||||
StThemeContext *context;
|
||||
StThemeNode *parent_node;
|
||||
StTheme *theme;
|
||||
|
||||
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];
|
||||
|
||||
int border_width[4];
|
||||
int border_radius[4];
|
||||
guint padding[4];
|
||||
|
||||
int width;
|
||||
int height;
|
||||
int min_width;
|
||||
int min_height;
|
||||
int max_width;
|
||||
int max_height;
|
||||
|
||||
char *background_image;
|
||||
StBorderImage *border_image;
|
||||
StShadow *shadow;
|
||||
|
||||
GType element_type;
|
||||
char *element_id;
|
||||
char *element_class;
|
||||
char *pseudo_class;
|
||||
char *inline_style;
|
||||
|
||||
CRDeclaration **properties;
|
||||
int n_properties;
|
||||
|
||||
/* We hold onto these separately so we can destroy them on finalize */
|
||||
CRDeclaration *inline_properties;
|
||||
|
||||
guint properties_computed : 1;
|
||||
guint geometry_computed : 1;
|
||||
guint background_computed : 1;
|
||||
guint foreground_computed : 1;
|
||||
guint border_image_computed : 1;
|
||||
guint shadow_computed : 1;
|
||||
guint link_type : 2;
|
||||
|
||||
/* Graphics state */
|
||||
float alloc_width;
|
||||
float alloc_height;
|
||||
|
||||
CoglHandle shadow_material;
|
||||
CoglHandle background_texture;
|
||||
CoglHandle border_texture;
|
||||
CoglHandle corner_texture;
|
||||
};
|
||||
|
||||
struct _StThemeNodeClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
};
|
||||
|
||||
void _st_theme_node_ensure_background (StThemeNode *node);
|
||||
void _st_theme_node_ensure_geometry (StThemeNode *node);
|
||||
|
||||
void _st_theme_node_init_drawing_state (StThemeNode *node);
|
||||
void _st_theme_node_free_drawing_state (StThemeNode *node);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_THEME_NODE_PRIVATE_H__ */
|
@ -5,70 +5,12 @@
|
||||
|
||||
#include "st-theme-private.h"
|
||||
#include "st-theme-context.h"
|
||||
#include "st-theme-node.h"
|
||||
#include "st-theme-node-private.h"
|
||||
|
||||
static void st_theme_node_init (StThemeNode *node);
|
||||
static void st_theme_node_class_init (StThemeNodeClass *klass);
|
||||
static void st_theme_node_finalize (GObject *object);
|
||||
|
||||
struct _StThemeNode {
|
||||
GObject parent;
|
||||
|
||||
StThemeContext *context;
|
||||
StThemeNode *parent_node;
|
||||
StTheme *theme;
|
||||
|
||||
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];
|
||||
|
||||
int border_width[4];
|
||||
int border_radius[4];
|
||||
guint padding[4];
|
||||
|
||||
int width;
|
||||
int height;
|
||||
int min_width;
|
||||
int min_height;
|
||||
int max_width;
|
||||
int max_height;
|
||||
|
||||
char *background_image;
|
||||
StBorderImage *border_image;
|
||||
StShadow *shadow;
|
||||
|
||||
GType element_type;
|
||||
char *element_id;
|
||||
char *element_class;
|
||||
char *pseudo_class;
|
||||
char *inline_style;
|
||||
|
||||
CRDeclaration **properties;
|
||||
int n_properties;
|
||||
|
||||
/* We hold onto these separately so we can destroy them on finalize */
|
||||
CRDeclaration *inline_properties;
|
||||
|
||||
guint properties_computed : 1;
|
||||
guint geometry_computed : 1;
|
||||
guint background_computed : 1;
|
||||
guint foreground_computed : 1;
|
||||
guint border_image_computed : 1;
|
||||
guint shadow_computed : 1;
|
||||
guint link_type : 2;
|
||||
};
|
||||
|
||||
struct _StThemeNodeClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
};
|
||||
|
||||
static const ClutterColor BLACK_COLOR = { 0, 0, 0, 0xff };
|
||||
static const ClutterColor TRANSPARENT_COLOR = { 0, 0, 0, 0 };
|
||||
|
||||
@ -77,6 +19,7 @@ G_DEFINE_TYPE (StThemeNode, st_theme_node, G_TYPE_OBJECT)
|
||||
static void
|
||||
st_theme_node_init (StThemeNode *node)
|
||||
{
|
||||
_st_theme_node_init_drawing_state (node);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -131,6 +74,8 @@ st_theme_node_finalize (GObject *object)
|
||||
if (node->background_image)
|
||||
g_free (node->background_image);
|
||||
|
||||
_st_theme_node_free_drawing_state (node);
|
||||
|
||||
G_OBJECT_CLASS (st_theme_node_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -259,7 +204,7 @@ st_theme_node_get_pseudo_class (StThemeNode *node)
|
||||
return node->pseudo_class;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
ensure_properties (StThemeNode *node)
|
||||
{
|
||||
if (!node->properties_computed)
|
||||
@ -1108,8 +1053,8 @@ do_size_property (StThemeNode *node,
|
||||
get_length_from_term_int (node, decl->value, FALSE, node_value);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_geometry (StThemeNode *node)
|
||||
void
|
||||
_st_theme_node_ensure_geometry (StThemeNode *node)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
@ -1192,7 +1137,7 @@ st_theme_node_get_border_width (StThemeNode *node,
|
||||
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
|
||||
g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
|
||||
return node->border_width[side];
|
||||
}
|
||||
@ -1204,7 +1149,7 @@ st_theme_node_get_border_radius (StThemeNode *node,
|
||||
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
|
||||
g_return_val_if_fail (corner >= ST_CORNER_TOPLEFT && corner <= ST_CORNER_BOTTOMLEFT, 0.);
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
|
||||
return node->border_radius[corner];
|
||||
}
|
||||
@ -1214,7 +1159,7 @@ st_theme_node_get_width (StThemeNode *node)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
return node->width;
|
||||
}
|
||||
|
||||
@ -1223,7 +1168,7 @@ st_theme_node_get_height (StThemeNode *node)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
return node->height;
|
||||
}
|
||||
|
||||
@ -1232,7 +1177,7 @@ st_theme_node_get_min_width (StThemeNode *node)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
return node->min_width;
|
||||
}
|
||||
|
||||
@ -1241,7 +1186,7 @@ st_theme_node_get_min_height (StThemeNode *node)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
return node->min_height;
|
||||
}
|
||||
|
||||
@ -1250,7 +1195,7 @@ st_theme_node_get_max_width (StThemeNode *node)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
return node->max_width;
|
||||
}
|
||||
|
||||
@ -1259,7 +1204,7 @@ st_theme_node_get_max_height (StThemeNode *node)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
return node->max_height;
|
||||
}
|
||||
|
||||
@ -1281,8 +1226,8 @@ get_background_color_from_term (StThemeNode *node,
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_background (StThemeNode *node)
|
||||
void
|
||||
_st_theme_node_ensure_background (StThemeNode *node)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1429,7 +1374,7 @@ st_theme_node_get_background_color (StThemeNode *node,
|
||||
{
|
||||
g_return_if_fail (ST_IS_THEME_NODE (node));
|
||||
|
||||
ensure_background (node);
|
||||
_st_theme_node_ensure_background (node);
|
||||
|
||||
*color = node->background_color;
|
||||
}
|
||||
@ -1439,7 +1384,7 @@ st_theme_node_get_background_image (StThemeNode *node)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
|
||||
|
||||
ensure_background (node);
|
||||
_st_theme_node_ensure_background (node);
|
||||
|
||||
return node->background_image;
|
||||
}
|
||||
@ -1500,7 +1445,7 @@ st_theme_node_get_background_gradient (StThemeNode *node,
|
||||
{
|
||||
g_return_if_fail (ST_IS_THEME_NODE (node));
|
||||
|
||||
ensure_background (node);
|
||||
_st_theme_node_ensure_background (node);
|
||||
|
||||
*type = node->background_gradient_type;
|
||||
if (*type != ST_GRADIENT_NONE)
|
||||
@ -1518,7 +1463,7 @@ st_theme_node_get_border_color (StThemeNode *node,
|
||||
g_return_if_fail (ST_IS_THEME_NODE (node));
|
||||
g_return_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT);
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
|
||||
*color = node->border_color[side];
|
||||
}
|
||||
@ -1530,7 +1475,7 @@ st_theme_node_get_padding (StThemeNode *node,
|
||||
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
|
||||
g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
|
||||
return node->padding[side];
|
||||
}
|
||||
@ -2353,7 +2298,7 @@ st_theme_node_adjust_preferred_width (StThemeNode *node,
|
||||
|
||||
g_return_if_fail (ST_IS_THEME_NODE (node));
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
|
||||
width_inc = get_width_inc (node);
|
||||
|
||||
@ -2420,7 +2365,7 @@ st_theme_node_adjust_preferred_height (StThemeNode *node,
|
||||
|
||||
g_return_if_fail (ST_IS_THEME_NODE (node));
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
|
||||
height_inc = get_height_inc (node);
|
||||
|
||||
@ -2461,7 +2406,7 @@ st_theme_node_get_content_box (StThemeNode *node,
|
||||
|
||||
g_return_if_fail (ST_IS_THEME_NODE (node));
|
||||
|
||||
ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
|
||||
avail_width = allocation->x2 - allocation->x1;
|
||||
avail_height = allocation->y2 - allocation->y1;
|
||||
@ -2501,8 +2446,8 @@ st_theme_node_geometry_equal (StThemeNode *node,
|
||||
{
|
||||
StSide side;
|
||||
|
||||
ensure_geometry (node);
|
||||
ensure_geometry (other);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
_st_theme_node_ensure_geometry (other);
|
||||
|
||||
for (side = ST_SIDE_TOP; side <= ST_SIDE_LEFT; side++)
|
||||
{
|
||||
|
@ -171,6 +171,11 @@ void st_theme_node_get_content_box (StThemeNode *node,
|
||||
gboolean st_theme_node_geometry_equal (StThemeNode *node,
|
||||
StThemeNode *other);
|
||||
|
||||
void st_theme_node_paint (StThemeNode *node,
|
||||
const ClutterActorBox *box,
|
||||
guint8 paint_opacity);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_THEME_NODE_H__ */
|
||||
|
@ -38,9 +38,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"
|
||||
#include "st-tooltip.h"
|
||||
|
||||
@ -59,7 +57,6 @@ struct _StWidgetPrivate
|
||||
|
||||
ClutterActor *border_image;
|
||||
ClutterActor *background_image;
|
||||
ClutterActor *background_image_shadow;
|
||||
ClutterColor bg_color;
|
||||
|
||||
guint border_width;
|
||||
@ -68,6 +65,7 @@ struct _StWidgetPrivate
|
||||
StGradientType bg_gradient_type;
|
||||
ClutterColor bg_gradient_end;
|
||||
|
||||
ClutterActorBox background_allocation;
|
||||
gdouble shadow_xoffset;
|
||||
gdouble shadow_yoffset;
|
||||
|
||||
@ -125,7 +123,6 @@ 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,
|
||||
@ -254,12 +251,6 @@ 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->theme_node)
|
||||
{
|
||||
g_object_unref (priv->theme_node);
|
||||
@ -295,18 +286,20 @@ st_widget_finalize (GObject *gobject)
|
||||
G_OBJECT_CLASS (st_widget_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
st_widget_allocate (ClutterActor *actor,
|
||||
const ClutterActorBox *box,
|
||||
ClutterAllocationFlags flags)
|
||||
{
|
||||
StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
|
||||
StWidget *self = ST_WIDGET (actor);
|
||||
StWidgetPrivate *priv = self->priv;
|
||||
StThemeNode *theme_node;
|
||||
ClutterActorClass *klass;
|
||||
ClutterGeometry area;
|
||||
ClutterVertex in_v, out_v;
|
||||
|
||||
theme_node = st_widget_get_theme_node ((StWidget*) actor);
|
||||
theme_node = st_widget_get_theme_node (self);
|
||||
|
||||
klass = CLUTTER_ACTOR_CLASS (st_widget_parent_class);
|
||||
klass->allocate (actor, box, flags);
|
||||
@ -327,249 +320,20 @@ st_widget_allocate (ClutterActor *actor,
|
||||
|
||||
st_tooltip_set_tip_area (priv->tooltip, &area);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (priv->border_image && priv->bg_gradient_type == ST_GRADIENT_NONE)
|
||||
{
|
||||
ClutterActorBox frame_box;
|
||||
|
||||
frame_box.x1 = frame_box.y1 = 0;
|
||||
frame_box.x2 = box->x2 - box->x1;
|
||||
frame_box.y2 = box->y2 - box->y1;
|
||||
|
||||
clutter_actor_allocate (CLUTTER_ACTOR (priv->border_image),
|
||||
&frame_box,
|
||||
flags);
|
||||
}
|
||||
else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
|
||||
{
|
||||
guint width, old_width,
|
||||
height, old_height;
|
||||
ClutterActorBox frame_box;
|
||||
|
||||
frame_box.x1 = frame_box.y1 = 0;
|
||||
frame_box.x2 = box->x2 - box->x1;
|
||||
frame_box.y2 = box->y2 - box->y1;
|
||||
|
||||
width = (guint)(0.5 + frame_box.x2);
|
||||
height = (guint)(0.5 + frame_box.y2);
|
||||
|
||||
clutter_cairo_texture_get_surface_size (CLUTTER_CAIRO_TEXTURE (priv->border_image),
|
||||
&old_width, &old_height);
|
||||
|
||||
if (width > 0 && height > 0 &&
|
||||
(old_width != width || old_height != height))
|
||||
{
|
||||
|
||||
clutter_cairo_texture_set_surface_size (CLUTTER_CAIRO_TEXTURE (priv->border_image),
|
||||
width, height);
|
||||
st_widget_redraw_gradient ((StWidget*) actor);
|
||||
}
|
||||
clutter_actor_allocate (CLUTTER_ACTOR (priv->border_image),
|
||||
&frame_box,
|
||||
flags);
|
||||
}
|
||||
|
||||
if (priv->background_image)
|
||||
{
|
||||
ClutterActorBox frame_box;
|
||||
gfloat w, h;
|
||||
|
||||
frame_box.x1 = frame_box.y1 = 0;
|
||||
frame_box.x2 = box->x2 - box->x1;
|
||||
frame_box.y2 = box->y2 - box->y1;
|
||||
|
||||
clutter_actor_get_size (CLUTTER_ACTOR (priv->background_image), &w, &h);
|
||||
|
||||
/* scale the background into the allocated bounds */
|
||||
if (w > frame_box.x2 || h > frame_box.y2)
|
||||
{
|
||||
gint new_h, new_w, offset;
|
||||
gint box_w, box_h;
|
||||
|
||||
box_w = (int) frame_box.x2;
|
||||
box_h = (int) frame_box.y2;
|
||||
|
||||
/* scale to fit */
|
||||
new_h = (int)((h / w) * ((gfloat) box_w));
|
||||
new_w = (int)((w / h) * ((gfloat) box_h));
|
||||
|
||||
if (new_h > box_h)
|
||||
{
|
||||
/* center for new width */
|
||||
offset = ((box_w) - new_w) * 0.5;
|
||||
frame_box.x1 = offset;
|
||||
frame_box.x2 = offset + new_w;
|
||||
|
||||
frame_box.y2 = box_h;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* center for new height */
|
||||
offset = ((box_h) - new_h) * 0.5;
|
||||
frame_box.y1 = offset;
|
||||
frame_box.y2 = offset + new_h;
|
||||
|
||||
frame_box.x2 = box_w;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* center the background on the widget */
|
||||
frame_box.x1 = (int)(((box->x2 - box->x1) / 2) - (w / 2));
|
||||
frame_box.y1 = (int)(((box->y2 - box->y1) / 2) - (h / 2));
|
||||
frame_box.x2 = frame_box.x1 + w;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_real_draw_background (StWidget *self)
|
||||
st_widget_paint (ClutterActor *actor)
|
||||
{
|
||||
StWidgetPrivate *priv = self->priv;
|
||||
ClutterActor *actor = CLUTTER_ACTOR (self);
|
||||
ClutterActorBox allocation = { 0, };
|
||||
gfloat w, h;
|
||||
guint8 opacity;
|
||||
StWidget *self = ST_WIDGET (actor);
|
||||
StThemeNode *theme_node;
|
||||
ClutterActorBox allocation;
|
||||
|
||||
theme_node = st_widget_get_theme_node (self);
|
||||
|
||||
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)
|
||||
{
|
||||
ClutterColor bg_color = priv->bg_color;
|
||||
|
||||
bg_color.alpha = opacity * bg_color.alpha / 255;
|
||||
|
||||
cogl_set_source_color4ub (bg_color.red,
|
||||
bg_color.green,
|
||||
bg_color.blue,
|
||||
bg_color.alpha);
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_paint (ClutterActor *self)
|
||||
{
|
||||
StWidgetPrivate *priv = ST_WIDGET (self)->priv;
|
||||
|
||||
st_widget_real_draw_background (ST_WIDGET (self));
|
||||
|
||||
if (priv->background_image != NULL)
|
||||
{
|
||||
if (priv->background_image_shadow)
|
||||
clutter_actor_paint (priv->background_image_shadow);
|
||||
clutter_actor_paint (priv->background_image);
|
||||
}
|
||||
st_theme_node_paint (theme_node, &allocation, clutter_actor_get_paint_opacity (actor));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -599,9 +363,6 @@ 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);
|
||||
|
||||
@ -619,9 +380,6 @@ 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);
|
||||
|
||||
@ -632,125 +390,6 @@ st_widget_unmap (ClutterActor *actor)
|
||||
clutter_actor_unmap ((ClutterActor *) priv->tooltip);
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_redraw_gradient (StWidget *widget)
|
||||
{
|
||||
ClutterCairoTexture *texture;
|
||||
ClutterColor *start, *end;
|
||||
StWidgetPrivate *priv;
|
||||
guint width, height;
|
||||
guint radius[4], i;
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
gboolean round_border = FALSE;
|
||||
|
||||
if (widget->priv->bg_gradient_type == ST_GRADIENT_NONE)
|
||||
return;
|
||||
|
||||
texture = CLUTTER_CAIRO_TEXTURE (widget->priv->border_image);
|
||||
priv = widget->priv;
|
||||
start = &widget->priv->bg_color;
|
||||
end = &widget->priv->bg_gradient_end;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
radius[i] = st_theme_node_get_border_radius (priv->theme_node, i);
|
||||
if (radius[i] > 0)
|
||||
round_border = TRUE;
|
||||
}
|
||||
|
||||
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
||||
clutter_cairo_texture_clear (texture);
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
if (priv->bg_gradient_type == ST_GRADIENT_VERTICAL)
|
||||
pattern = cairo_pattern_create_linear (0, 0, 0, height);
|
||||
else if (priv->bg_gradient_type == ST_GRADIENT_HORIZONTAL)
|
||||
pattern = cairo_pattern_create_linear (0, 0, width, 0);
|
||||
else
|
||||
{
|
||||
gdouble cx, cy;
|
||||
|
||||
cx = width / 2.;
|
||||
cy = height / 2.;
|
||||
pattern = cairo_pattern_create_radial (cx, cy, 0, cx, cy, MIN (cx, cy));
|
||||
}
|
||||
|
||||
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.);
|
||||
|
||||
if (round_border)
|
||||
{
|
||||
if (radius[ST_CORNER_TOPLEFT] > 0)
|
||||
cairo_arc (cr,
|
||||
radius[ST_CORNER_TOPLEFT],
|
||||
radius[ST_CORNER_TOPLEFT],
|
||||
radius[ST_CORNER_TOPLEFT], M_PI, 3 * M_PI / 2);
|
||||
else
|
||||
cairo_move_to (cr, 0, 0);
|
||||
cairo_line_to (cr, width - radius[ST_CORNER_TOPRIGHT], 0);
|
||||
if (radius[ST_CORNER_TOPRIGHT] > 0)
|
||||
cairo_arc (cr,
|
||||
width - radius[ST_CORNER_TOPRIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI);
|
||||
cairo_line_to (cr, width, height - radius[ST_CORNER_BOTTOMRIGHT]);
|
||||
if (radius[ST_CORNER_BOTTOMRIGHT])
|
||||
cairo_arc (cr,
|
||||
width - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
height - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2);
|
||||
cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], height);
|
||||
if (radius[ST_CORNER_BOTTOMLEFT])
|
||||
cairo_arc (cr,
|
||||
radius[ST_CORNER_BOTTOMLEFT],
|
||||
height - radius[ST_CORNER_BOTTOMLEFT],
|
||||
radius[ST_CORNER_BOTTOMLEFT], M_PI / 2, M_PI);
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
else
|
||||
cairo_rectangle (cr, 0, 0, width, height);
|
||||
|
||||
if (priv->border_width > 0)
|
||||
{
|
||||
guint8 opacity;
|
||||
gdouble effective_alpha;
|
||||
cairo_path_t *path;
|
||||
|
||||
path = cairo_copy_path (cr);
|
||||
opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (widget));
|
||||
effective_alpha = priv->border_color.alpha * opacity / (255. * 255.);
|
||||
|
||||
cairo_set_source_rgba (cr,
|
||||
priv->border_color.red / 255.,
|
||||
priv->border_color.green / 255.,
|
||||
priv->border_color.blue / 255.,
|
||||
effective_alpha);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_translate (cr, priv->border_width, priv->border_width);
|
||||
cairo_scale (cr,
|
||||
(gdouble)(width - 2 * priv->border_width) / width,
|
||||
(gdouble)(height - 2 * priv->border_width) / height);
|
||||
cairo_append_path (cr, path);
|
||||
cairo_path_destroy (path);
|
||||
}
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void notify_children_of_style_change (ClutterContainer *container);
|
||||
|
||||
static void
|
||||
@ -776,270 +415,12 @@ static void
|
||||
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;
|
||||
gboolean relayout_needed = FALSE;
|
||||
gboolean has_changed = FALSE;
|
||||
ClutterColor color;
|
||||
guint border_radius = 0;
|
||||
StGradientType gradient;
|
||||
ClutterColor gradient_end;
|
||||
StSide side;
|
||||
StCorner corner;
|
||||
gboolean uniform_border_width;
|
||||
|
||||
/* application has request this widget is not stylable */
|
||||
if (!priv->is_stylable)
|
||||
return;
|
||||
|
||||
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)
|
||||
{
|
||||
st_theme_node_get_background_color (theme_node, &color);
|
||||
if (gradient != priv->bg_gradient_type ||
|
||||
!clutter_color_equal (&color, &priv->bg_color))
|
||||
{
|
||||
priv->bg_gradient_type = gradient;
|
||||
priv->bg_color = color;
|
||||
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->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);
|
||||
priv->border_image = NULL;
|
||||
}
|
||||
|
||||
if (priv->background_image)
|
||||
{
|
||||
clutter_actor_unparent (priv->background_image);
|
||||
priv->background_image = NULL;
|
||||
}
|
||||
|
||||
texture_cache = st_texture_cache_get_default ();
|
||||
|
||||
|
||||
/* Rough notes about the relationship of borders and backgrounds in CSS3;
|
||||
* see http://www.w3.org/TR/css3-background/ for more accurate details.
|
||||
*
|
||||
* - Things are drawn in 4 layers, from the bottom:
|
||||
* Background color
|
||||
* Background image
|
||||
* Border color or border image
|
||||
* Content
|
||||
* - The background color, gradient and image extend to and are clipped by
|
||||
* the edge of the border area, so will be rounded if the border is
|
||||
* rounded. (CSS3 background-clip property modifies this)
|
||||
* - The border image replaces what would normally be drawn by the border
|
||||
* - The border image is not clipped by a rounded border-radius
|
||||
* - The border radius rounds the background even if the border is
|
||||
* 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.
|
||||
* - The combination of border image and a background gradient is not
|
||||
* supported; the background will be drawn as a solid color
|
||||
* - The background image is drawn above the border color or image,
|
||||
* not below it.
|
||||
* - We don't clip the background image to the (rounded) border area.
|
||||
*
|
||||
* The first three allow us to always draw with no more than a single
|
||||
* border_image 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;
|
||||
priv->border_width = st_theme_node_get_border_width (theme_node,
|
||||
ST_SIDE_TOP);
|
||||
if (priv->border_width > 0.5)
|
||||
priv->border_width = (int)(0.5 + priv->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)
|
||||
{
|
||||
priv->border_width = width;
|
||||
st_theme_node_get_border_color (theme_node,
|
||||
side, &priv->border_color);
|
||||
}
|
||||
if ((int)width != priv->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)
|
||||
{
|
||||
const char *filename;
|
||||
gint border_left, border_right, border_top, border_bottom;
|
||||
gint width, height;
|
||||
|
||||
filename = st_border_image_get_filename (border_image);
|
||||
|
||||
/* `border-image' takes precedence over `background-image'.
|
||||
* Firefox lets the background-image shine thru when border-image has
|
||||
* alpha an channel, maybe that would be an option for the future. */
|
||||
texture = (ClutterTexture*) st_texture_cache_load_file_simple (texture_cache,
|
||||
filename);
|
||||
|
||||
clutter_texture_get_base_size (CLUTTER_TEXTURE (texture),
|
||||
&width, &height);
|
||||
|
||||
st_border_image_get_borders (border_image,
|
||||
&border_left, &border_right, &border_top, &border_bottom);
|
||||
|
||||
priv->border_image = st_texture_frame_new (texture,
|
||||
border_top,
|
||||
border_right,
|
||||
border_bottom,
|
||||
border_left);
|
||||
clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self));
|
||||
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
|
||||
{
|
||||
priv->draw_border_internal = FALSE;
|
||||
priv->draw_bg_color = FALSE;
|
||||
texture = g_object_new (CLUTTER_TYPE_CAIRO_TEXTURE, NULL);
|
||||
priv->border_image = CLUTTER_ACTOR (texture);
|
||||
clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self));
|
||||
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
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,
|
||||
"border-width", priv->border_width,
|
||||
"border-color", &priv->border_color,
|
||||
"corner-radius", border_radius,
|
||||
NULL);
|
||||
|
||||
clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self));
|
||||
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
else if (priv->border_width > 0 && priv->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)
|
||||
{
|
||||
priv->background_image = st_texture_cache_load_file_simple (texture_cache, bg_file);
|
||||
clutter_actor_set_parent (priv->background_image, CLUTTER_ACTOR (self));
|
||||
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
if (relayout_needed)
|
||||
clutter_actor_queue_relayout ((ClutterActor *) self);
|
||||
else
|
||||
clutter_actor_queue_redraw ((ClutterActor *) self);
|
||||
}
|
||||
|
||||
if (CLUTTER_IS_CONTAINER (self))
|
||||
notify_children_of_style_change ((ClutterContainer *)self);
|
||||
|
Loading…
Reference in New Issue
Block a user