5b6a9701e2
* subclassing-ClutterActor.sgml: Fix up the wording and the examples a bit; add a paragraph about the ClutterActor::pick() virtual method.
153 lines
5.2 KiB
Plaintext
153 lines
5.2 KiB
Plaintext
<chapter id="clutter-subclassing-ClutterActor">
|
|
<chapterinfo>
|
|
<author>
|
|
<firstname>Emmanuele</firstname>
|
|
<surname>Bassi</surname>
|
|
<affiliation>
|
|
<address>
|
|
<email>ebassi@openedhand.com</email>
|
|
</address>
|
|
</affiliation>
|
|
</author>
|
|
</chapterinfo>
|
|
|
|
<title>Implementing a new actor</title>
|
|
|
|
<para>In order to implement a new #ClutterActor subclass the usual
|
|
machinery for subclassing a GObject should be used. After that, the
|
|
ClutterActor::query_coords() and ClutterActor::request_coords() virtual
|
|
functions should be overidden. Optionally, also the ClutterActor::paint()
|
|
virtual functions should be overridden.</para>
|
|
|
|
<para>The ClutterActor::query_coords() method of a #ClutterActor is
|
|
invoked when clutter_actor_query_coords() is called on an instance
|
|
of that actor class. It is used to return a #ClutterActorBox containing
|
|
the coordinates of the bounding box for the actor (the coordinates
|
|
of the top left corner and of the bottom right corner of the rectangle
|
|
that fully contains the actor). Container actors, or composite actors
|
|
with internal children, should call clutter_actor_query_coords() on
|
|
each visible child. Remember: the returned coordinates must be relative
|
|
to the parent actor.</para>
|
|
|
|
<example id="clutter-actor-query-coords-example">
|
|
<para>This example shows how an actor class should override the
|
|
query_coords() virtual function of #ClutterActor. In this case,
|
|
the returned bounding box is the sum of the bounding boxes of all
|
|
the <structname>FooActor</structname> children.</para>
|
|
|
|
<programlisting>
|
|
static void
|
|
foo_actor_query_coords (ClutterActor *actor,
|
|
ClutterActorBox *box)
|
|
{
|
|
FooActor *foo_actor = FOO_ACTOR (actor);
|
|
GList *child;
|
|
ClutterUnit width, height;
|
|
|
|
/* initialize our size */
|
|
width = height = 0;
|
|
|
|
for (l = foo_actor->children; l != NULL; l = l->next)
|
|
{
|
|
ClutterActor *child_actor = child->data;
|
|
|
|
/* we return only visible actors */
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (child_actor))
|
|
{
|
|
ClutterActorBox child_box = { 0, };
|
|
|
|
clutter_actor_query_coords (child_actor, &child_box);
|
|
|
|
width += child_box.x2 - child_box.x2;
|
|
height += child_box.y2 - child_box.y1;
|
|
}
|
|
}
|
|
|
|
box->x2 = box->x1 + width
|
|
box->y2 = box->y1 + height;
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
|
|
<para>The ClutterActor::request_coords() method of a #ClutterActor
|
|
is invoked when clutter_actor_request_coords() is called on an instance
|
|
of that actor class. It is used to set the coordinates of the bounding
|
|
box for the actor. Container actors, or composite actors with internal
|
|
children, should override the request_coords() virtual function and call
|
|
clutter_actor_request_coords() on each visible child. Every actor class
|
|
overriding the request_coords() virtual function must chain up to the
|
|
parent class request_coords() method.</para>
|
|
|
|
<para>The ClutterActor::paint() method should be overridden if the
|
|
actor needs to control its drawing process, by using the GL API
|
|
directly. Actors performing transformations should push the GL matrix
|
|
first and then pop the GL matrix before returning. Container actors
|
|
or composite actors with internal children should do the same, and call
|
|
clutter_actor_paint() on every visible child:</para>
|
|
|
|
<example id="clutter-actor-paint-example">
|
|
<programlisting>
|
|
static void
|
|
foo_actor_paint (ClutterActor *actor)
|
|
{
|
|
FooActor *foo_actor = FOO_ACTOR (actor);
|
|
GList *child;
|
|
|
|
/* by including <clutter/cogl.h> it's possible to use the internal
|
|
* COGL abstraction API, which is also used by Clutter itself and avoids
|
|
* changing the GL calls depending on the target platform (GL or GL/ES).
|
|
*/
|
|
cogl_push_matrix ();
|
|
|
|
for (child = foo_actor->children; child != NULL; child = child->next)
|
|
{
|
|
ClutterActor *child_actor = child->data;
|
|
|
|
if (CLUTTER_ACTOR_IS_MAPPED (child_actor))
|
|
clutter_actor_paint (child_actor);
|
|
}
|
|
|
|
cogl_pop_matrix ();
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
|
|
<para>If the actor has a non-rectangular shape, or it has internal childrens
|
|
that needs to be distinguished by the events delivery mechanism, the
|
|
ClutterActor::pick() method should also be overridden. The ::pick() method
|
|
works exactly like the ::paint() method, but the actor should paint just
|
|
its shape with the passed colour:</para>
|
|
|
|
<example id="clutter-actor-pick-example">
|
|
<programlisting>
|
|
static void
|
|
foo_actor_pick (ClutterActor *actor,
|
|
const ClutterColor *pick_color)
|
|
{
|
|
FooActor *foo_actor = FOO_ACTOR (actor);
|
|
guint width, height;
|
|
|
|
/* by including <clutter/cogl.h> it's possible to use the internal
|
|
* COGL abstraction API, which is also used by Clutter itself and avoids
|
|
* changing the GL calls depending on the target platform (GL or GL/ES).
|
|
*/
|
|
cogl_color (pick_color);
|
|
|
|
clutter_actor_get_size (actor, &width, &height);
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
/* draw a triangular shape */
|
|
glBegin (GL_POLYGON);
|
|
glVertex2i (width / 2, 0 );
|
|
glVertex2i (width , height);
|
|
glVertex2i (0 , height);
|
|
glEnd ();
|
|
|
|
cogl_pop_matrix ();
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
|
|
</chapter>
|