a81dbcf483
Add a basic example showing how to implement a ClutterEffect post_paint() function to overlay a highlight border over a rectangular actor.
318 lines
7.9 KiB
C
318 lines
7.9 KiB
C
#include "cb-border-effect.h"
|
|
|
|
G_DEFINE_TYPE (CbBorderEffect, cb_border_effect, CLUTTER_TYPE_EFFECT);
|
|
|
|
#define CB_BORDER_EFFECT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
|
|
CB_TYPE_BORDER_EFFECT, \
|
|
CbBorderEffectPrivate))
|
|
|
|
static const ClutterColor grey = { 0xaa, 0xaa, 0xaa, 0xff };
|
|
|
|
struct _CbBorderEffectPrivate
|
|
{
|
|
CoglMaterial *border;
|
|
ClutterColor color;
|
|
gfloat width;
|
|
};
|
|
|
|
enum {
|
|
PROP_0,
|
|
|
|
PROP_COLOR,
|
|
PROP_WIDTH,
|
|
|
|
PROP_LAST
|
|
};
|
|
|
|
static GParamSpec *obj_props[PROP_LAST];
|
|
|
|
/* ClutterEffect implementation */
|
|
static void
|
|
cb_border_effect_post_paint (ClutterEffect *self)
|
|
{
|
|
ClutterActor *actor;
|
|
gfloat width;
|
|
gfloat height;
|
|
CbBorderEffectPrivate *priv;
|
|
|
|
ClutterActorMeta *meta = CLUTTER_ACTOR_META (self);
|
|
|
|
/* check that the effect is enabled before applying it */
|
|
if (!clutter_actor_meta_get_enabled (meta))
|
|
return;
|
|
|
|
priv = CB_BORDER_EFFECT (self)->priv;
|
|
|
|
/* get the associated actor's dimensions */
|
|
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self));
|
|
clutter_actor_get_size (actor, &width, &height);
|
|
|
|
/* draw Cogl rectangles on top */
|
|
cogl_set_source (priv->border);
|
|
cogl_path_new ();
|
|
|
|
/* left rectangle */
|
|
cogl_path_rectangle (0, 0, priv->width, height);
|
|
|
|
/* top rectangle */
|
|
cogl_path_rectangle (priv->width, 0, width, priv->width);
|
|
|
|
/* right rectangle */
|
|
cogl_path_rectangle (width - priv->width, priv->width, width, height);
|
|
|
|
/* bottom rectangle */
|
|
cogl_path_rectangle (priv->width,
|
|
height - priv->width,
|
|
width - priv->width,
|
|
height);
|
|
|
|
cogl_path_fill ();
|
|
}
|
|
|
|
/* GObject implementation */
|
|
static void
|
|
cb_border_effect_dispose (GObject *gobject)
|
|
{
|
|
CbBorderEffectPrivate *priv = CB_BORDER_EFFECT (gobject)->priv;
|
|
|
|
if (priv->border != COGL_INVALID_HANDLE)
|
|
{
|
|
cogl_handle_unref (priv->border);
|
|
priv->border = COGL_INVALID_HANDLE;
|
|
}
|
|
|
|
G_OBJECT_CLASS (cb_border_effect_parent_class)->dispose (gobject);
|
|
}
|
|
|
|
static void
|
|
cb_border_effect_set_property (GObject *gobject,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
CbBorderEffect *effect = CB_BORDER_EFFECT (gobject);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_COLOR:
|
|
cb_border_effect_set_color (effect, clutter_value_get_color (value));
|
|
break;
|
|
|
|
case PROP_WIDTH:
|
|
cb_border_effect_set_width (effect, g_value_get_float (value));
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
cb_border_effect_get_property (GObject *gobject,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
CbBorderEffectPrivate *priv = CB_BORDER_EFFECT (gobject)->priv;
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_COLOR:
|
|
g_value_set_object (value, &(priv->color));
|
|
break;
|
|
|
|
case PROP_WIDTH:
|
|
g_value_set_float (value, priv->width);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* GObject class and instance init */
|
|
static void
|
|
cb_border_effect_class_init (CbBorderEffectClass *klass)
|
|
{
|
|
ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
GParamSpec *pspec;
|
|
|
|
effect_class->post_paint = cb_border_effect_post_paint;
|
|
|
|
gobject_class->set_property = cb_border_effect_set_property;
|
|
gobject_class->get_property = cb_border_effect_get_property;
|
|
gobject_class->dispose = cb_border_effect_dispose;
|
|
|
|
g_type_class_add_private (klass, sizeof (CbBorderEffectPrivate));
|
|
|
|
/**
|
|
* CbBorderEffect:width:
|
|
*
|
|
* The width of the border
|
|
*/
|
|
pspec = g_param_spec_float ("width",
|
|
"Width",
|
|
"The width of the border (in pixels)",
|
|
1.0, 100.0,
|
|
10.0,
|
|
G_PARAM_READWRITE);
|
|
obj_props[PROP_WIDTH] = pspec;
|
|
g_object_class_install_property (gobject_class, PROP_WIDTH, pspec);
|
|
|
|
/**
|
|
* CbBorderEffect:color:
|
|
*
|
|
* The color of the border
|
|
*/
|
|
pspec = clutter_param_spec_color ("color",
|
|
"Color",
|
|
"The border color",
|
|
&grey,
|
|
G_PARAM_READWRITE);
|
|
obj_props[PROP_COLOR] = pspec;
|
|
g_object_class_install_property (gobject_class, PROP_COLOR, pspec);
|
|
}
|
|
|
|
static void
|
|
cb_border_effect_init (CbBorderEffect *self)
|
|
{
|
|
CbBorderEffectPrivate *priv;
|
|
|
|
priv = self->priv = CB_BORDER_EFFECT_GET_PRIVATE (self);
|
|
|
|
priv->border = cogl_material_new ();
|
|
|
|
priv->color = grey;
|
|
}
|
|
|
|
/* called each time a property is set on the effect */
|
|
static void
|
|
cb_border_effect_update (CbBorderEffect *self)
|
|
{
|
|
ClutterActor *actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self));
|
|
|
|
if (actor != NULL)
|
|
clutter_actor_queue_redraw (actor);
|
|
}
|
|
|
|
/* public API */
|
|
|
|
/**
|
|
* cb_border_effect_new:
|
|
* @width: width of the border applied by the effect
|
|
* @color: a #ClutterColor
|
|
*
|
|
* Creates a new #ClutterEffect with the given @width
|
|
* and of the given @color.
|
|
*/
|
|
ClutterEffect *
|
|
cb_border_effect_new (gfloat width,
|
|
const ClutterColor *color)
|
|
{
|
|
return g_object_new (CB_TYPE_BORDER_EFFECT,
|
|
"width", width,
|
|
"color", color,
|
|
NULL);
|
|
}
|
|
|
|
/**
|
|
* cb_border_effect_set_color:
|
|
* @self: a #CbBorderEffect
|
|
* @color: a #ClutterColor
|
|
*
|
|
* Sets the color of the border provided by the effect @self.
|
|
*/
|
|
void
|
|
cb_border_effect_set_color (CbBorderEffect *self,
|
|
const ClutterColor *color)
|
|
{
|
|
CbBorderEffectPrivate *priv;
|
|
|
|
g_return_if_fail (CB_IS_BORDER_EFFECT (self));
|
|
g_return_if_fail (color != NULL);
|
|
|
|
priv = CB_BORDER_EFFECT_GET_PRIVATE (self);
|
|
|
|
priv->color.red = color->red;
|
|
priv->color.green = color->green;
|
|
priv->color.blue = color->blue;
|
|
priv->color.alpha = color->alpha;
|
|
|
|
cogl_material_set_color4ub (priv->border,
|
|
color->red,
|
|
color->green,
|
|
color->blue,
|
|
color->alpha);
|
|
|
|
cb_border_effect_update (self);
|
|
}
|
|
|
|
/**
|
|
* cb_border_effect_get_color:
|
|
* @self: a #CbBorderEffect
|
|
* @color: return location for a #ClutterColor
|
|
*
|
|
* Retrieves the color of the border applied by the effect @self.
|
|
*/
|
|
void
|
|
cb_border_effect_get_color (CbBorderEffect *self,
|
|
ClutterColor *color)
|
|
{
|
|
CbBorderEffectPrivate *priv;
|
|
|
|
g_return_if_fail (CB_IS_BORDER_EFFECT (self));
|
|
|
|
priv = CB_BORDER_EFFECT_GET_PRIVATE (self);
|
|
|
|
color->red = priv->color.red;
|
|
color->green = priv->color.green;
|
|
color->blue = priv->color.blue;
|
|
color->alpha = priv->color.alpha;
|
|
}
|
|
|
|
/**
|
|
* cb_border_effect_set_width:
|
|
* @self: a #CbBorderEffect
|
|
* @width: the width of the border
|
|
*
|
|
* Sets the width (in pixels) of the border applied by the effect @self.
|
|
*/
|
|
void
|
|
cb_border_effect_set_width (CbBorderEffect *self,
|
|
gfloat width)
|
|
{
|
|
CbBorderEffectPrivate *priv;
|
|
|
|
g_return_if_fail (CB_IS_BORDER_EFFECT (self));
|
|
|
|
priv = CB_BORDER_EFFECT_GET_PRIVATE (self);
|
|
|
|
priv->width = width;
|
|
|
|
cb_border_effect_update (self);
|
|
}
|
|
|
|
/**
|
|
* cb_border_effect_get_width:
|
|
* @self: a #CbBorderEffect
|
|
*
|
|
* Gets the width (in pixels) of the border applied by the effect @self.
|
|
*
|
|
* Return value: the border's width, or 0.0 if @self is not
|
|
* a #CbBorderEffect
|
|
*/
|
|
gfloat
|
|
cb_border_effect_get_width (CbBorderEffect *self)
|
|
{
|
|
CbBorderEffectPrivate *priv;
|
|
|
|
g_return_val_if_fail (CB_IS_BORDER_EFFECT (self), 0.0);
|
|
|
|
priv = CB_BORDER_EFFECT_GET_PRIVATE (self);
|
|
|
|
return priv->width;
|
|
}
|