summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliot Smith <elliot.smith@intel.com>2011-03-08 11:19:13 +0000
committerElliot Smith <elliot.smith@intel.com>2011-03-17 15:56:55 +0000
commita81dbcf4837a589e63bd026fbc3759b109f96a41 (patch)
treec9fb22b27ee1b14662e6de4a6d5af098059b751e
parent1d14e7468bcf999cc3cd3847eb41372bce6483c4 (diff)
downloadclutter-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.am2
-rw-r--r--doc/cookbook/examples/cb-border-effect.c317
-rw-r--r--doc/cookbook/examples/cb-border-effect.h54
-rw-r--r--doc/cookbook/examples/effects-basic.c106
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;
+}