mirror of
https://github.com/brl/mutter.git
synced 2024-11-30 03:50:47 -05:00
a4c0b1e939
* clutter-sections.txt: Add last-minute API additions. * subclassing-ClutterActor.sgml: Fix some of the notes; the Container implementation will need its own section.
190 lines
6.6 KiB
Plaintext
190 lines
6.6 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:
|
|
- more on composite/container actors, when/why to use...
|
|
+ implementaing a composite actor - set_parent() etc
|
|
+ implementing a container - interface etc
|
|
- Painting
|
|
+ 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>
|
|
|
|
<note>All the coordinates are expressed using #ClutterUnit<!-- -->s,
|
|
the internal high-precision unit type, which guarantee sub-pixel
|
|
precision. #ClutterUnit has the same limitation that #ClutterFixed
|
|
has, see the <link linkend="clutter-Fixed-Point-Support">fixed point page</link>.</note>
|
|
|
|
<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;
|
|
|
|
/* Clutter uses high-precision units which can be converted from
|
|
* and into pixels, typographic points, percentages, etc.
|
|
*/
|
|
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 consider 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>
|
|
|
|
<para>When inside the ClutterActor::paint() method the actor is already
|
|
positioned at the coordinates specified by its bounding box; all the
|
|
paint operations should then take place from the (0, 0) coordinates.</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;
|
|
|
|
/* it is possible to avoid a costly paint by checking whether the
|
|
* actor should really be painted in pick mode
|
|
*/
|
|
if (!clutter_actor_should_pick_paint (actor))
|
|
return;
|
|
|
|
/* 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);
|
|
|
|
/* it is also possible to use raw GL calls, at the cost of losing
|
|
* portability
|
|
*/
|
|
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>
|
|
|
|
<para></para>
|
|
|
|
</chapter>
|