mutter/doc/cookbook/examples/cb-border-effect.c
Elliot Smith a81dbcf483 docs: Add example of a border added through ClutterEffect
Add a basic example showing how to implement a ClutterEffect
post_paint() function to overlay a highlight border over a
rectangular actor.
2011-03-17 15:56:55 +00:00

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;
}