mirror of
https://github.com/brl/mutter.git
synced 2024-11-30 03:50:47 -05:00
Merge remote-tracking branch 'elliot/cookbook-effects-basic'
* elliot/cookbook-effects-basic: docs: Remove checks for whether an effect is disabled docs: Add recipe about implementing a ClutterEffect docs: Add example of setting background color with ClutterEffect docs: Add example of a border added through ClutterEffect
This commit is contained in:
commit
a51c4cff72
@ -37,6 +37,8 @@ HTML_FILES = $(top_builddir)/doc/cookbook/html/*.html
|
||||
CSS_FILES = $(top_builddir)/doc/cookbook/html/*.css
|
||||
IMAGE_FILES = \
|
||||
$(srcdir)/images/clutter-logo.png \
|
||||
$(srcdir)/images/effects-basic.png \
|
||||
$(srcdir)/images/effects-basic-background.png \
|
||||
$(srcdir)/images/effects-built-in.png \
|
||||
$(srcdir)/images/effects-custom-deform.png \
|
||||
$(srcdir)/images/effects-custom-deform-back-material.png \
|
||||
|
@ -245,6 +245,536 @@ clutter_actor_add_effect (texture, effect);
|
||||
|
||||
</section>
|
||||
|
||||
<section id="effects-basic">
|
||||
<title>Changing an actor's paint sequence using
|
||||
<type>ClutterEffect</type></title>
|
||||
|
||||
<section>
|
||||
<title>Problem</title>
|
||||
|
||||
<para>You want to paint on top of or under an actor in a generic
|
||||
way, without editing the actor's <function>paint()</function>
|
||||
implementation. Example use cases are:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Adding a border on top of an actor.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Drawing a background for an actor.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>A quick way to achieve the same thing (though not
|
||||
readily portable between actors) is to connect a callback
|
||||
before or after an actor's <emphasis>paint</emphasis> signal.
|
||||
See <link linkend="actors-paint-wrappers">this recipe</link> for
|
||||
more details. However, using a <type>ClutterEffect</type>
|
||||
implementation, as explained in this recipe, is the preferred
|
||||
approach.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Solution</title>
|
||||
|
||||
<para>Create a subclass of the <type>ClutterEffect</type> abstract
|
||||
class; then implement the <function>pre_paint()</function> and/or
|
||||
<function>post_paint()</function> virtual functions. When the
|
||||
effect is applied to an actor, these functions will paint
|
||||
before and after the actor's own <function>paint()</function>
|
||||
implementation.</para>
|
||||
|
||||
<note>
|
||||
<para>For this solution, we implement a simple
|
||||
<type>CbBackgroundEffect</type> which draws a gray rectangle
|
||||
under an actor. The full source is in
|
||||
<link linkend="effects-basic-example-cbbackgroundeffect">this
|
||||
section</link>. To keep it simple, the effect has no properties
|
||||
and isn't configurable (the background is always gray); see the
|
||||
<link linkend="effects-basic-example-cbbordereffect">border
|
||||
effect</link> for a more detailed implementation with GObject
|
||||
trimmings.</para>
|
||||
</note>
|
||||
|
||||
<para>First, create a <type>ClutterEffect</type> subclass. This
|
||||
requires the trappings of a GObject class; in particular,
|
||||
it needs a private struct to hold the effect's state. This
|
||||
should include any <type>CoglMaterials</type>,
|
||||
<type>CoglColors</type> or other private member variables
|
||||
you intend to use to draw the effect.</para>
|
||||
|
||||
<para>In the case of the background effect, we have a background
|
||||
<type>CoglMaterial</type> and a <type>CoglColor</type> for that
|
||||
material:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
struct _CbBackgroundEffectPrivate
|
||||
{
|
||||
CoglMaterial *background;
|
||||
CoglColor *color;
|
||||
};
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>In the <function>init()</function> function for objects of
|
||||
your class, create any Cogl resources which you need to draw the
|
||||
effect. In the case of the background effect,
|
||||
we need to create the <type>CoglMaterial</type> and
|
||||
<type>CoglColor</type> for the private struct:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
static void
|
||||
cb_background_effect_init (CbBackgroundEffect *self)
|
||||
{
|
||||
/* get the private struct for the object
|
||||
CbBackgroundEffectPrivate *priv;
|
||||
priv = self->priv = CB_BACKGROUND_EFFECT_GET_PRIVATE (self);
|
||||
|
||||
/* create the background material */
|
||||
priv->background = cogl_material_new ();
|
||||
|
||||
/* gray color for filling the background material */
|
||||
priv->color = cogl_color_new ();
|
||||
cogl_color_init_from_4ub (priv->color, 122, 122, 122, 255);
|
||||
|
||||
/* set the color on the material; NB this isn't configurable
|
||||
* for this effect, and is always gray
|
||||
*/
|
||||
cogl_material_set_color (priv->background, priv->color);
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Optionally, you can create GObject properties for
|
||||
the class, if you want a configurable effect: see
|
||||
<link linkend="effects-basic-discussion-properties">this
|
||||
section</link> for details.</para>
|
||||
|
||||
<para>The <function>dispose()</function> function for your effect
|
||||
should clean up any Cogl resources:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
static void
|
||||
cb_background_effect_dispose (GObject *gobject)
|
||||
{
|
||||
CbBackgroundEffectPrivate *priv = CB_BACKGROUND_EFFECT (gobject)->priv;
|
||||
|
||||
if (priv->background != COGL_INVALID_HANDLE)
|
||||
{
|
||||
cogl_handle_unref (priv->background);
|
||||
priv->background = COGL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (priv->color != NULL)
|
||||
{
|
||||
cogl_color_free (priv->color);
|
||||
priv->color = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (cb_background_effect_parent_class)->dispose (gobject);
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Now, the important part: implement <function>pre_paint()</function>
|
||||
and/or <function>post_paint()</function>, using Cogl to draw on the
|
||||
material(s) set up for the effect.</para>
|
||||
|
||||
<para>For the background effect, we implement <function>pre_paint()</function>,
|
||||
to draw a gray rectangle under the actor:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
/* note that if pre_paint() returns FALSE
|
||||
* any post_paint() defined for the effect will not be called
|
||||
*/
|
||||
static gboolean
|
||||
cb_background_effect_pre_paint (ClutterEffect *self)
|
||||
{
|
||||
ClutterActor *actor;
|
||||
gfloat width;
|
||||
gfloat height;
|
||||
CbBackgroundEffectPrivate *priv;
|
||||
|
||||
priv = CB_BACKGROUND_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 a Cogl rectangle in the background using the default color */
|
||||
cogl_set_source (priv->background);
|
||||
|
||||
/* the rectangle has the same dimensions as the actor */
|
||||
cogl_rectangle (0, 0, width, height);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Now, in the <function>init()</function> function for the
|
||||
effect <emphasis>class</emphasis>, assign your implementations to the
|
||||
virtual methods of the <type>ClutterEffect</type> abstract class:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
static void
|
||||
cb_background_effect_class_init (CbBackgroundEffectClass *klass)
|
||||
{
|
||||
ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
effect_class->pre_paint = cb_background_effect_pre_paint;
|
||||
gobject_class->dispose = cb_background_effect_dispose;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (CbBackgroundEffectPrivate));
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>If you intend to make your effect reusable, provide
|
||||
a public constructor (as is done for the example effects in this
|
||||
recipe):</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
ClutterEffect *
|
||||
cb_background_effect_new ()
|
||||
{
|
||||
return g_object_new (CB_TYPE_BACKGROUND_EFFECT,
|
||||
NULL);
|
||||
}
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>The effect is now ready to be used. The application code
|
||||
for applying your effect to an actor is the same as for any
|
||||
other effect:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
ClutterActor *texture;
|
||||
ClutterEffect *background_effect;
|
||||
|
||||
/* ...initialize texture, load image file etc... */
|
||||
|
||||
/* create a gray background effect */
|
||||
background_effect = cb_background_effect_new ();
|
||||
|
||||
/* apply the effect to the actor */
|
||||
clutter_actor_add_effect (texture, background_effect);
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Below is an example of applying this effect to a texture loaded
|
||||
with an image; the image has a transparent background, so the
|
||||
background is visible through it. The screenshot is from
|
||||
the <link linkend="effects-basic-example-5">example
|
||||
application</link>:</para>
|
||||
|
||||
<screenshot>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata format="PNG"
|
||||
fileref="images/effects-basic-background.png" />
|
||||
</imageobject>
|
||||
<alt>
|
||||
<para>Applying <type>CbBackgroundEffect</type>
|
||||
to a texture loaded with an image that has a transparent
|
||||
background</para>
|
||||
</alt>
|
||||
</mediaobject>
|
||||
</screenshot>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Discussion</title>
|
||||
|
||||
<para>A basic <type>ClutterEffect</type> is particularly useful for
|
||||
amending the appearance of an actor on the fly: for example,
|
||||
to highlight an actor in response to a button presses. This
|
||||
<emphasis>could</emphasis> be done by creating a custom widget
|
||||
whose appearance could be toggled. But what if you wanted to make
|
||||
an arbitrary actor's appearance "togglable"? A generic effect
|
||||
in the style of the border effect in this recipe can be applied
|
||||
to any actor, and easily toggled by enabling/disabling the
|
||||
effect.</para>
|
||||
|
||||
<para><type>ClutterEffect</type> works best where
|
||||
you want to overlay or underlay the actor with Cogl paths or
|
||||
primitives, without changing the actor's geometry. If you want
|
||||
to do complicated geometry transformations, or other subtle
|
||||
manipulations of an actor's appearance, it is better to use
|
||||
a <type>ClutterEffect</type> subclass like
|
||||
<type>ClutterOffscreenEffect</type>, <type>ClutterDeformEffect</type>,
|
||||
or <type>ClutterShaderEffect</type>.</para>
|
||||
|
||||
<para>In a similar vein, when a <type>ClutterEffect</type> is
|
||||
applied to an actor, the effect shouldn't paint outside the actor's
|
||||
allocation. However, if the effect provides a
|
||||
<function>get_paint_volume()</function> implementation which
|
||||
returns a volume larger than the actor's allocation, the effect
|
||||
<emphasis>can</emphasis> paint anywhere within that volume. Though
|
||||
in most cases, creating a custom paint volume is only going to be
|
||||
useful for offscreen effects, where you are changing the
|
||||
actor's geometry.</para>
|
||||
|
||||
<section id="effects-basic-discussion-properties">
|
||||
<title>Effect properties</title>
|
||||
|
||||
<para>If your effect has GObject properties, you should
|
||||
ensure that an actor associated with the effect is queued
|
||||
for a redraw when those properties change. (You only need to
|
||||
do this for properties which change the effect's appearance;
|
||||
but this is likely to include most of an effect's properties.)</para>
|
||||
|
||||
<para>In most cases, you're likely define standard GObject
|
||||
properties for the class; for example,
|
||||
<link linkend="effects-basic-example-2"><type>CbBorderEffect</type></link>
|
||||
defines a <varname>width</varname> property like this:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
static void
|
||||
cb_border_effect_class_init (CbBorderEffectClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GParamSpec *pspec;
|
||||
|
||||
/* ...more class initialization code here... */
|
||||
|
||||
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);
|
||||
|
||||
/* ...more property definitions...*/
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>It also defines a standard GObject
|
||||
<function>set_property()</function> function for
|
||||
<varname>width</varname>:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
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)
|
||||
{
|
||||
/* ...other cases here ... */
|
||||
|
||||
case PROP_WIDTH:
|
||||
cb_border_effect_set_width (effect, g_value_get_float (value));
|
||||
break;
|
||||
|
||||
/* ...default case ... */
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Note that this calls
|
||||
<function>cb_border_effect_set_width()</function>, which is
|
||||
also exposed in the public API. This is where the
|
||||
<varname>width</varname> member variable is actually set in
|
||||
the private struct; and also where the redraw for the actor
|
||||
associated with the effect should be queued:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
/* queues a redraw of the actor associated with the effect, if there is one */
|
||||
static void
|
||||
cb_border_effect_update (CbBorderEffect *self)
|
||||
{
|
||||
ClutterActor *actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self));
|
||||
|
||||
/* this guard is necessary as an effect's properties can be manipulated
|
||||
* before it has an actor associated with it
|
||||
*/
|
||||
if (actor != NULL)
|
||||
clutter_actor_queue_redraw (actor);
|
||||
}
|
||||
|
||||
/* public setter for the width property, which calls the update function */
|
||||
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;
|
||||
|
||||
/* the property has been updated, so queue a redraw of the actor (if set) */
|
||||
cb_border_effect_update (self);
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Any other property setters which affect the associated
|
||||
actor's appearance (i.e. color in the case of
|
||||
<type>CbBorderEffect</type>) should also call the update
|
||||
function after setting the property.</para>
|
||||
|
||||
<tip>
|
||||
<para>If your effect exposes GObject properties in this way,
|
||||
it can also be animated with the Clutter animation API as usual.
|
||||
For example, you could animate the border effect in this recipe
|
||||
so that the border gradually becomes thinner or thicker.</para>
|
||||
</tip>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="effects-basic-example">
|
||||
<title>Full example</title>
|
||||
|
||||
<para>The example application applies two effects to a
|
||||
group of <type>ClutterTextures</type>:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>A <type>CbBackgroundEffect</type> which draws a gray
|
||||
background under each actor. The effect is implemented in
|
||||
<link linkend="effects-basic-example-1">a header
|
||||
file</link> and <link linkend="effects-basic-example-2">a C
|
||||
code file</link>.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>A <type>CbBorderEffect</type> which draws a
|
||||
red border on top of an actor; this is toggled by clicking
|
||||
on the actor. The effect is implemented in
|
||||
<link linkend="effects-basic-example-3">a header
|
||||
file</link> and <link linkend="effects-basic-example-4">a C
|
||||
code file</link>.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>The <link linkend="effects-basic-example-5">application</link>
|
||||
creates textures from the file paths specified
|
||||
on the command line then applies both of these effects to
|
||||
each texture. In the case of the <type>CbBorderEffect</type>,
|
||||
a 5 pixel red border is applied; this is also disabled by default,
|
||||
and enabled when a texture is clicked.</para>
|
||||
|
||||
<para>Here is an example of the output when the application is loaded
|
||||
with four images:</para>
|
||||
|
||||
<screenshot>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata format="PNG"
|
||||
fileref="images/effects-basic.png" />
|
||||
</imageobject>
|
||||
<alt>
|
||||
<para>Applying <type>CbBackgroundEffect</type>
|
||||
and a togglable <type>CbBorderEffect</type>
|
||||
to a several textures</para>
|
||||
</alt>
|
||||
</mediaobject>
|
||||
</screenshot>
|
||||
|
||||
<section id="effects-basic-example-cbbackgroundeffect">
|
||||
<title><type>CbBackgroundEffect</type></title>
|
||||
|
||||
<example id="effects-basic-example-1">
|
||||
<title><filename>cb-background-effect.h</filename> (header file)</title>
|
||||
<programlisting>
|
||||
<xi:include href="examples/cb-background-effect.h" parse="text">
|
||||
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
||||
</xi:include>
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<example id="effects-basic-example-2">
|
||||
<title><filename>cb-background-effect.c</filename> (code file)</title>
|
||||
<programlisting>
|
||||
<xi:include href="examples/cb-background-effect.c" parse="text">
|
||||
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
||||
</xi:include>
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
<section id="effects-basic-example-cbbordereffect">
|
||||
<title><type>CbBorderEffect</type></title>
|
||||
|
||||
<para>This is a more sophisticated effect with configurable
|
||||
border color and width.</para>
|
||||
|
||||
<example id="effects-basic-example-3">
|
||||
<title><filename>cb-border-effect.h</filename> (header file)</title>
|
||||
<programlisting>
|
||||
<xi:include href="examples/cb-border-effect.h" parse="text">
|
||||
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
||||
</xi:include>
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<example id="effects-basic-example-4">
|
||||
<title><filename>cb-border-effect.c</filename> (code file)</title>
|
||||
<programlisting>
|
||||
<xi:include href="examples/cb-border-effect.c" parse="text">
|
||||
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
||||
</xi:include>
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
<section id="effects-basic-example-application">
|
||||
<title>Application</title>
|
||||
|
||||
<example id="effects-basic-example-5">
|
||||
<title>Application which applies <type>CbBorderEffect</type>
|
||||
and <type>CbBackgroundEffect</type> to a group of
|
||||
<type>ClutterTextures</type>.</title>
|
||||
<programlisting>
|
||||
<xi:include href="examples/effects-basic.c" parse="text">
|
||||
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
|
||||
</xi:include>
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="effects-custom-deform">
|
||||
<title>Creating and animating a custom <type>ClutterDeformEffect</type></title>
|
||||
|
||||
|
@ -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,11 @@ 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 \
|
||||
cb-background-effect.c \
|
||||
cb-background-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
|
||||
|
104
doc/cookbook/examples/cb-background-effect.c
Normal file
104
doc/cookbook/examples/cb-background-effect.c
Normal file
@ -0,0 +1,104 @@
|
||||
#include "cb-background-effect.h"
|
||||
|
||||
G_DEFINE_TYPE (CbBackgroundEffect, cb_background_effect, CLUTTER_TYPE_EFFECT);
|
||||
|
||||
#define CB_BACKGROUND_EFFECT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
|
||||
CB_TYPE_BACKGROUND_EFFECT, \
|
||||
CbBackgroundEffectPrivate))
|
||||
|
||||
struct _CbBackgroundEffectPrivate
|
||||
{
|
||||
CoglMaterial *background;
|
||||
CoglColor *color;
|
||||
};
|
||||
|
||||
/* ClutterEffect implementation */
|
||||
|
||||
/* note that if pre_paint() returns FALSE
|
||||
* any post_paint() defined for the effect will not be called
|
||||
*/
|
||||
static gboolean
|
||||
cb_background_effect_pre_paint (ClutterEffect *self)
|
||||
{
|
||||
ClutterActor *actor;
|
||||
gfloat width;
|
||||
gfloat height;
|
||||
CbBackgroundEffectPrivate *priv;
|
||||
|
||||
priv = CB_BACKGROUND_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 a grey Cogl rectangle in the background */
|
||||
cogl_set_source (priv->background);
|
||||
|
||||
cogl_rectangle (0, 0, width, height);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* GObject implementation */
|
||||
static void
|
||||
cb_background_effect_dispose (GObject *gobject)
|
||||
{
|
||||
CbBackgroundEffectPrivate *priv = CB_BACKGROUND_EFFECT (gobject)->priv;
|
||||
|
||||
if (priv->background != COGL_INVALID_HANDLE)
|
||||
{
|
||||
cogl_handle_unref (priv->background);
|
||||
priv->background = COGL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (priv->color != NULL)
|
||||
{
|
||||
cogl_color_free (priv->color);
|
||||
priv->color = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (cb_background_effect_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
cb_background_effect_class_init (CbBackgroundEffectClass *klass)
|
||||
{
|
||||
ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
effect_class->pre_paint = cb_background_effect_pre_paint;
|
||||
gobject_class->dispose = cb_background_effect_dispose;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (CbBackgroundEffectPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
cb_background_effect_init (CbBackgroundEffect *self)
|
||||
{
|
||||
CbBackgroundEffectPrivate *priv;
|
||||
|
||||
priv = self->priv = CB_BACKGROUND_EFFECT_GET_PRIVATE (self);
|
||||
|
||||
priv->background = cogl_material_new ();
|
||||
|
||||
/* grey color for filling the background material */
|
||||
priv->color = cogl_color_new ();
|
||||
cogl_color_init_from_4ub (priv->color, 122, 122, 122, 255);
|
||||
|
||||
cogl_material_set_color (priv->background, priv->color);
|
||||
}
|
||||
|
||||
/* public API */
|
||||
|
||||
/**
|
||||
* cb_background_effect_new:
|
||||
*
|
||||
* Creates a new #ClutterEffect which adds a grey background
|
||||
* when applied to a rectangular actor.
|
||||
*/
|
||||
ClutterEffect *
|
||||
cb_background_effect_new ()
|
||||
{
|
||||
return g_object_new (CB_TYPE_BACKGROUND_EFFECT,
|
||||
NULL);
|
||||
}
|
42
doc/cookbook/examples/cb-background-effect.h
Normal file
42
doc/cookbook/examples/cb-background-effect.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef __CB_BACKGROUND_EFFECT_H__
|
||||
#define __CB_BACKGROUND_EFFECT_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
GType cb_background_effect_get_type (void);
|
||||
|
||||
#define CB_TYPE_BACKGROUND_EFFECT (cb_background_effect_get_type ())
|
||||
#define CB_BACKGROUND_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
|
||||
CB_TYPE_BACKGROUND_EFFECT, \
|
||||
CbBackgroundEffect))
|
||||
#define CB_IS_BACKGROUND_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
|
||||
CB_TYPE_BACKGROUND_EFFECT))
|
||||
#define CB_BACKGROUND_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
|
||||
CB_TYPE_BACKGROUND_EFFECT, \
|
||||
CbBackgroundEffectClass))
|
||||
#define CB_IS_BACKGROUND_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
CB_TYPE_BACKGROUND_EFFECT))
|
||||
#define CB_BACKGROUND_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
|
||||
CB_TYPE_BACKGROUND_EFFECT, \
|
||||
CbBackgroundEffectClass))
|
||||
|
||||
typedef struct _CbBackgroundEffectPrivate CbBackgroundEffectPrivate;
|
||||
typedef struct _CbBackgroundEffect CbBackgroundEffect;
|
||||
typedef struct _CbBackgroundEffectClass CbBackgroundEffectClass;
|
||||
|
||||
/* object */
|
||||
struct _CbBackgroundEffect
|
||||
{
|
||||
ClutterEffect parent_instance;
|
||||
CbBackgroundEffectPrivate *priv;
|
||||
};
|
||||
|
||||
/* class */
|
||||
struct _CbBackgroundEffectClass
|
||||
{
|
||||
ClutterEffectClass parent_class;
|
||||
};
|
||||
|
||||
ClutterEffect *cb_background_effect_new ();
|
||||
|
||||
#endif /* __CB_BACKGROUND_EFFECT_H__ */
|
311
doc/cookbook/examples/cb-border-effect.c
Normal file
311
doc/cookbook/examples/cb-border-effect.c
Normal file
@ -0,0 +1,311 @@
|
||||
#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;
|
||||
|
||||
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;
|
||||
}
|
54
doc/cookbook/examples/cb-border-effect.h
Normal file
54
doc/cookbook/examples/cb-border-effect.h
Normal file
@ -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__ */
|
119
doc/cookbook/examples/effects-basic.c
Normal file
119
doc/cookbook/examples/effects-basic.c
Normal file
@ -0,0 +1,119 @@
|
||||
#include <stdlib.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "cb-border-effect.h"
|
||||
#include "cb-background-effect.h"
|
||||
|
||||
static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff };
|
||||
static ClutterColor red_color = { 0xff, 0x00, 0x00, 0xff };
|
||||
|
||||
static gboolean
|
||||
toggle_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 *background_effect;
|
||||
ClutterEffect *border_effect;
|
||||
ClutterConstraint *width_constraint;
|
||||
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);
|
||||
width_constraint = clutter_bind_constraint_new (stage,
|
||||
CLUTTER_BIND_WIDTH,
|
||||
0.0);
|
||||
clutter_actor_add_constraint (box, width_constraint);
|
||||
|
||||
/* 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 grey background effect */
|
||||
background_effect = cb_background_effect_new ();
|
||||
|
||||
/* apply the effect to the actor */
|
||||
clutter_actor_add_effect (texture, background_effect);
|
||||
|
||||
/* create a 5 pixel red border effect */
|
||||
border_effect = cb_border_effect_new (5.0, &red_color);
|
||||
|
||||
/* apply the effect to the actor, but disabled */
|
||||
clutter_actor_add_effect (texture, border_effect);
|
||||
clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (border_effect),
|
||||
FALSE);
|
||||
|
||||
/* on mouse click, toggle the "enabled" property of the border effect */
|
||||
g_signal_connect (texture,
|
||||
"button-press-event",
|
||||
G_CALLBACK (toggle_highlight),
|
||||
border_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;
|
||||
}
|
BIN
doc/cookbook/images/effects-basic-background.png
Normal file
BIN
doc/cookbook/images/effects-basic-background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.9 KiB |
BIN
doc/cookbook/images/effects-basic.png
Normal file
BIN
doc/cookbook/images/effects-basic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 70 KiB |
Loading…
Reference in New Issue
Block a user