diff options
author | Elliot Smith <elliot.smith@intel.com> | 2011-03-08 11:19:13 +0000 |
---|---|---|
committer | Elliot Smith <elliot.smith@intel.com> | 2011-03-17 15:56:55 +0000 |
commit | a81dbcf4837a589e63bd026fbc3759b109f96a41 (patch) | |
tree | c9fb22b27ee1b14662e6de4a6d5af098059b751e | |
parent | 1d14e7468bcf999cc3cd3847eb41372bce6483c4 (diff) | |
download | clutter-a81dbcf4837a589e63bd026fbc3759b109f96a41.tar.gz |
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.
-rw-r--r-- | doc/cookbook/examples/Makefile.am | 2 | ||||
-rw-r--r-- | doc/cookbook/examples/cb-border-effect.c | 317 | ||||
-rw-r--r-- | doc/cookbook/examples/cb-border-effect.h | 54 | ||||
-rw-r--r-- | doc/cookbook/examples/effects-basic.c | 106 |
4 files changed, 479 insertions, 0 deletions
diff --git a/doc/cookbook/examples/Makefile.am b/doc/cookbook/examples/Makefile.am index fa7a8781a..6f0c4b396 100644 --- a/doc/cookbook/examples/Makefile.am +++ b/doc/cookbook/examples/Makefile.am @@ -18,6 +18,7 @@ noinst_PROGRAMS = \ animations-rotating \ animations-scaling \ animations-scaling-zoom \ + effects-basic \ effects-built-in \ effects-custom-deform \ text-shadow \ @@ -83,6 +84,7 @@ animations_reuse_SOURCES = animations-reuse.c animations_rotating_SOURCES = animations-rotating.c animations_scaling_SOURCES = animations-scaling.c animations_scaling_zoom_SOURCES = animations-scaling-zoom.c +effects_basic_SOURCES = cb-border-effect.c cb-border-effect.h effects-basic.c effects_built_in_SOURCES = effects-built-in.c effects_custom_deform_SOURCES = cb-page-fold-effect.c cb-page-fold-effect.h effects-custom-deform.c text_shadow_SOURCES = text-shadow.c diff --git a/doc/cookbook/examples/cb-border-effect.c b/doc/cookbook/examples/cb-border-effect.c new file mode 100644 index 000000000..f7bb6b9a6 --- /dev/null +++ b/doc/cookbook/examples/cb-border-effect.c @@ -0,0 +1,317 @@ +#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; +} diff --git a/doc/cookbook/examples/cb-border-effect.h b/doc/cookbook/examples/cb-border-effect.h new file mode 100644 index 000000000..c4c6a3675 --- /dev/null +++ b/doc/cookbook/examples/cb-border-effect.h @@ -0,0 +1,54 @@ +#ifndef __CB_BORDER_EFFECT_H__ +#define __CB_BORDER_EFFECT_H__ + +#include <clutter/clutter.h> + +GType cb_border_effect_get_type (void); + +#define CB_TYPE_BORDER_EFFECT (cb_border_effect_get_type ()) +#define CB_BORDER_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + CB_TYPE_BORDER_EFFECT, \ + CbBorderEffect)) +#define CB_IS_BORDER_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + CB_TYPE_BORDER_EFFECT)) +#define CB_BORDER_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \ + CB_TYPE_BORDER_EFFECT, \ + CbBorderEffectClass)) +#define CB_IS_BORDER_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + CB_TYPE_BORDER_EFFECT)) +#define CB_BORDER_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + CB_TYPE_BORDER_EFFECT, \ + CbBorderEffectClass)) + +typedef struct _CbBorderEffectPrivate CbBorderEffectPrivate; +typedef struct _CbBorderEffect CbBorderEffect; +typedef struct _CbBorderEffectClass CbBorderEffectClass; + +/* object */ +struct _CbBorderEffect +{ + ClutterEffect parent_instance; + CbBorderEffectPrivate *priv; +}; + +/* class */ +struct _CbBorderEffectClass +{ + ClutterEffectClass parent_class; +}; + +ClutterEffect *cb_border_effect_new (gfloat width, + const ClutterColor *color); + +void cb_border_effect_set_color (CbBorderEffect *self, + const ClutterColor *color); + +void cb_border_effect_get_color (CbBorderEffect *self, + ClutterColor *color); + +void cb_border_effect_set_width (CbBorderEffect *self, + gfloat width); + +gfloat cb_border_effect_get_width (CbBorderEffect *self); + +#endif /* __CB_BORDER_EFFECT_H__ */ diff --git a/doc/cookbook/examples/effects-basic.c b/doc/cookbook/examples/effects-basic.c new file mode 100644 index 000000000..a59291f24 --- /dev/null +++ b/doc/cookbook/examples/effects-basic.c @@ -0,0 +1,106 @@ +#include <stdlib.h> +#include <clutter/clutter.h> + +#include "cb-border-effect.h" + +static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff }; +static ClutterColor red_color = { 0xff, 0x00, 0x00, 0xff }; + +static gboolean +add_highlight (ClutterActor *actor, + ClutterEvent *event, + gpointer user_data) +{ + ClutterActorMeta *meta = CLUTTER_ACTOR_META (user_data); + + gboolean effect_enabled = clutter_actor_meta_get_enabled (meta); + + clutter_actor_meta_set_enabled (meta, !effect_enabled); + + clutter_actor_queue_redraw (actor); + + return TRUE; +} + +int +main (int argc, + char *argv[]) +{ + ClutterActor *stage; + ClutterActor *box; + ClutterLayoutManager *layout_manager; + ClutterActor *texture; + ClutterEffect *effect; + gchar *filename; + guint i; + GError *error = NULL; + + if (argc < 2) + { + g_print ("Usage: %s <image files>\n", argv[0]); + return EXIT_FAILURE; + } + + if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) + return EXIT_FAILURE; + + stage = clutter_stage_new (); + clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); + clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); + clutter_actor_set_size (stage, 600, 400); + g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); + + layout_manager = clutter_flow_layout_new (CLUTTER_FLOW_HORIZONTAL); + clutter_flow_layout_set_column_spacing (CLUTTER_FLOW_LAYOUT (layout_manager), + 10); + clutter_flow_layout_set_row_spacing (CLUTTER_FLOW_LAYOUT (layout_manager), + 10); + + box = clutter_box_new (layout_manager); + clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_WIDTH, 0.0)); + + /* loop through the files specified on the command line, adding + * each one into the box + */ + for (i = 1; i < argc; i++) + { + filename = argv[i]; + + texture = clutter_texture_new (); + clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (texture), TRUE); + clutter_actor_set_width (texture, 150); + clutter_actor_set_reactive (texture, TRUE); + + clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), + filename, + &error); + + if (error != NULL) + g_warning ("Error loading file %s:\n%s", + filename, + error->message); + + /* create a 5 pixel red border effect */ + effect = cb_border_effect_new (5.0, &red_color); + + /* add the effect to the actor, but disabled */ + clutter_actor_add_effect (texture, effect); + clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE); + + /* on mouse click, toggle the "enabled" property of the border effect */ + g_signal_connect (texture, + "button-press-event", + G_CALLBACK (add_highlight), + effect); + + clutter_container_add_actor (CLUTTER_CONTAINER (box), texture); + } + + clutter_container_add_actor (CLUTTER_CONTAINER (stage), box); + + clutter_actor_show (stage); + + clutter_main (); + + return EXIT_SUCCESS; +} |