261 lines
8.4 KiB
XML
261 lines
8.4 KiB
XML
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||
|
|
||
|
<chapter id="actors">
|
||
|
<title>Actors</title>
|
||
|
|
||
|
<epigraph>
|
||
|
<attribution>Edmon Gween, actor, on his deathbed</attribution>
|
||
|
<para>An actor's a guy who if you ain't talkin' about him, ain't
|
||
|
listening.</para>
|
||
|
</epigraph>
|
||
|
|
||
|
<section id="actors-introduction">
|
||
|
<title>Introduction</title>
|
||
|
|
||
|
<para>When building a User Interface with Clutter, the visible part
|
||
|
of the UI — that is, what is displayed on the screen — is
|
||
|
commonly referred to as "the scene graph". Like every graph, a scene
|
||
|
graph is composed by nodes.</para>
|
||
|
|
||
|
<para>Every node on the Clutter scene graph is an
|
||
|
<emphasis>actor</emphasis>. Every actor has a single relationship
|
||
|
with the others: it can be the parent of another actor, or a child of
|
||
|
another actor.</para>
|
||
|
|
||
|
<note><para>The Stage is an actor that can have children but cannot have
|
||
|
any parent.</para></note>
|
||
|
|
||
|
<para>Actors have different attributes: a position, a size, a
|
||
|
scale factor, a rotation angle on each axis (relative to a specific
|
||
|
center on the normal plane for that axis), an opacity factor.</para>
|
||
|
|
||
|
<para>The scene graph is not fixed: it can be changed, not only
|
||
|
by adding or removing actors, but also by changing the parent-child
|
||
|
relationship: it is possible, for instance, to move an entire
|
||
|
section of the scene graph from one parent actor to another.</para>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section id="actors-allocation-notify">
|
||
|
<title>Knowing when an actor position or size change</title>
|
||
|
|
||
|
<section>
|
||
|
<title>Problem</title>
|
||
|
|
||
|
<para>You want to know when the position or the size, or
|
||
|
both, of an actor change, for instance to update an unrelated
|
||
|
actor or some internal state.</para>
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Solution</title>
|
||
|
|
||
|
<para>You can use the <emphasis>notify</emphasis> signal,
|
||
|
detailed with the coordinate or the dimension you want
|
||
|
to know has changed:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
g_signal_connect (actor, "notify::x",
|
||
|
G_CALLBACK (on_x_changed),
|
||
|
NULL);
|
||
|
g_signal_connect (actor, "notify::height",
|
||
|
G_CALLBACK (on_height_changed),
|
||
|
NULL);
|
||
|
g_signal_connect (actor, "notify::depth",
|
||
|
G_CALLBACK (on_depth_changed),
|
||
|
NULL);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>If you want to know if any of the coordinates or dimensions of
|
||
|
an actor have been changed, except for depth, you can use the
|
||
|
<emphasis>allocation-changed</emphasis> signal:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
g_signal_connect (actor, "allocation-changed",
|
||
|
G_CALLBACK (on_allocation_changed),
|
||
|
NULL);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>The signature for the handler of the "notify" signal is:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
void
|
||
|
on_notify (GObject *gobject,
|
||
|
GParamSpec *pspec,
|
||
|
gpointer user_data);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>While the signature for the handler of the "allocation-changed"
|
||
|
signal is:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
void
|
||
|
on_allocation_changed (ClutterActor *actor,
|
||
|
const ClutterActorBox *allocation,
|
||
|
ClutterAllocationFlags flags,
|
||
|
gpointer user_data);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Discussion</title>
|
||
|
|
||
|
<para>Any change the position and size of an actor will cause a
|
||
|
change in the allocation of the actor itself. This will update the
|
||
|
values of the :x, :y, :width and :height properties as well.</para>
|
||
|
|
||
|
<para>The first technique allows a greater deal of granularity,
|
||
|
allowing you to know what exactly changed. Inside the callback
|
||
|
for the signal you can query the value of the property:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
void
|
||
|
on_x_changed (GObject *gobject,
|
||
|
GParamSpec *pspec,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
gint x_value = 0;
|
||
|
|
||
|
/* Round the X coordinate to the nearest pixel */
|
||
|
x_value = floorf (clutter_actor_get_x (CLUTTER_ACTOR (gobject))) + 0.5;
|
||
|
|
||
|
g_print ("The new X coordinate is '%d' pixels\n", x_value);
|
||
|
}
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>The second technique is more indicated if you want to
|
||
|
get notification that any of the positional or dimensional
|
||
|
attributes changed, except for the depth:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
void
|
||
|
on_allocation_changed (ClutterActor *actor,
|
||
|
const ClutterActorBox *allocation,
|
||
|
ClutterAllocationFlags flags,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
ClutterActor *actor = CLUTTER_ACTOR (gobject);
|
||
|
|
||
|
g_print ("The bounding box is now: (%.2f, %.2f) (%.2f x %.2f)\n",
|
||
|
clutter_actor_box_get_x (allocation),
|
||
|
clutter_actor_box_get_y (allocation),
|
||
|
clutter_actor_box_get_width (allocation),
|
||
|
clutter_actor_box_get_height (allocation));
|
||
|
}
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>All actors will update these properties when their size
|
||
|
or position change.</para>
|
||
|
|
||
|
<para>Note that the Stage, on the other hand, will not notify on
|
||
|
position changes, so it is not possible to use the :x and :y
|
||
|
properties to know that the platform-specific window embedding the
|
||
|
stage has been moved — if the platform supports a windowing
|
||
|
system. In order to achieve that you will have to use backend-specific
|
||
|
API to extract the surface used by the Stage and then platform-specific
|
||
|
API to retrieve its coordinates.</para>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section id="actors-paint-wrappers">
|
||
|
<title>Overriding the paint sequence</title>
|
||
|
|
||
|
<section>
|
||
|
<title>Problem</title>
|
||
|
|
||
|
<para>You want to override the way an actor paints itself
|
||
|
without creating a subclass.</para>
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Solution</title>
|
||
|
|
||
|
<para>You can use the <emphasis>paint</emphasis> signal to
|
||
|
invoke a callback that will be executed before the actor's
|
||
|
paint implementation:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
g_signal_connect (actor, "paint", G_CALLBACK (on_paint), NULL);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>You can paint something after the actor's paint implementation
|
||
|
by using the <function>g_signal_connect_after()</function> function
|
||
|
instead of <function>g_signal_connect()</function>:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
g_signal_connect_after (actor, "paint", G_CALLBACK (on_paint_after), NULL);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>The signature for the handler of the "paint" signal is:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
void on_paint (ClutterActor *actor, gpointer user_data);
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Discussion</title>
|
||
|
|
||
|
<para>The paint cycle in Clutter works its way recursively from the
|
||
|
Stage through every child.</para>
|
||
|
|
||
|
<para>Whenever an Actor is going to be painted it will be positioned in
|
||
|
a new frame of reference according to the list of transformations
|
||
|
(scaling, rotation and additional traslations). After that, the "paint"
|
||
|
signal will be emitted.</para>
|
||
|
|
||
|
<para>The "paint" signal is defined as <emphasis>run-last</emphasis>,
|
||
|
that is the signal handlers connected to it using
|
||
|
<function>g_signal_connetc()</function> will be called first; then the
|
||
|
default handler defined by the Actor's sub-class will be called;
|
||
|
finally, all the signal handlers connected to the signal using
|
||
|
<function>g_signal_connect_after()</function> will be called.</para>
|
||
|
|
||
|
<para>This allows pre- and post-default paint handlers, and it also
|
||
|
allows completely overriding the way an Actor draws itself by default;
|
||
|
for instance:</para>
|
||
|
|
||
|
<informalexample>
|
||
|
<programlisting>
|
||
|
void
|
||
|
on_paint (ClutterActor *actor)
|
||
|
{
|
||
|
do_my_paint (actor);
|
||
|
|
||
|
g_signal_stop_emission_by_name (actor, "paint");
|
||
|
}
|
||
|
</programlisting>
|
||
|
</informalexample>
|
||
|
|
||
|
<para>The code above will prevent the default paint implementation of
|
||
|
the actor from running.</para>
|
||
|
</section>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
</chapter>
|
||
|
|