mutter/doc/reference/subclassing-ClutterActor.sgml
Matthew Allum d903a79d81 2008-02-13 Matthew Allum <mallum@openedhand.com>
* Makefile.am:
        * clutter-docs.sgml:
        Add new appendix + FIXME for building
        * creating-your-own-behaviours.sgml:
        Add new initial doc on custom behaviour creation.
        * subclassing-ClutterActor.sgml:
        Add FIXME notes.
2008-02-13 16:46:07 +00:00

168 lines
5.8 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>
<programlisting>
A few FIXMES:
- note use of units in sizing
- more on composite/container actors, when/why to use...
+ implementaing a composite actor - set_parent() etc
+ implementing a container - interface etc
- Painting
+ note transform already applied. (including position, scale etc)
+ note on cogl_enable if painting texture or blended item
(should at least call cogl_enable(0) - to reset state cache)
+ fine to use regular GL but then wont be portable
+ avoid further transforms ?
</programlisting>
<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-&gt;children; l != NULL; l = l-&gt;next)
{
ClutterActor *child_actor = child-&gt;data;
/* we return only visible actors */
if (CLUTTER_ACTOR_IS_VISIBLE (child_actor))
{
ClutterActorBox child_box = { 0, };
clutter_actor_query_coords (child_actor, &amp;child_box);
width += child_box.x2 - child_box.x2;
height += child_box.y2 - child_box.y1;
}
}
box-&gt;x2 = box-&gt;x1 + width
box-&gt;y2 = box-&gt;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 &lt;clutter/cogl.h&gt; 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-&gt;children; child != NULL; child = child-&gt;next)
{
ClutterActor *child_actor = child-&gt;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 &lt;clutter/cogl.h&gt; 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, &amp;width, &amp;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>