2007-06-16 16:56:40 -04:00
|
|
|
<chapter id="clutter-subclassing-ClutterActor">
|
|
|
|
<chapterinfo>
|
|
|
|
<author>
|
|
|
|
<firstname>Emmanuele</firstname>
|
|
|
|
<surname>Bassi</surname>
|
|
|
|
<affiliation>
|
|
|
|
<address>
|
2009-09-27 06:38:01 -04:00
|
|
|
<email>ebassi@linux.intel.com</email>
|
2007-06-16 16:56:40 -04:00
|
|
|
</address>
|
|
|
|
</affiliation>
|
|
|
|
</author>
|
|
|
|
</chapterinfo>
|
|
|
|
|
|
|
|
<title>Implementing a new actor</title>
|
|
|
|
|
|
|
|
<para>In order to implement a new #ClutterActor subclass the usual
|
2008-06-10 13:12:48 -04:00
|
|
|
machinery for subclassing a #GObject should be used:</para>
|
2007-06-16 16:56:40 -04:00
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
<informalexample>
|
2007-06-16 16:56:40 -04:00
|
|
|
<programlisting>
|
2008-06-10 13:12:48 -04:00
|
|
|
#define FOO_TYPE_ACTOR (foo_actor_get_type ())
|
|
|
|
#define FOO_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE_ACTOR, FooActor))
|
|
|
|
#define FOO_IS_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOO_TYPE_ACTOR))
|
|
|
|
#define FOO_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FOO_TYPE_ACTOR, FooActorClass))
|
|
|
|
#define FOO_IS_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FOO_TYPE_ACTOR))
|
|
|
|
#define FOO_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FOO_TYPE_ACTOR, FooActorClass))
|
|
|
|
|
|
|
|
typedef struct _FooActor
|
|
|
|
{
|
|
|
|
ClutterActor parent_instance;
|
|
|
|
} FooActor;
|
|
|
|
|
|
|
|
typedef struct _FooActorClass
|
|
|
|
{
|
|
|
|
ClutterActorClass parent_class;
|
|
|
|
} FooActorClass;
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR);
|
|
|
|
|
2007-06-16 16:56:40 -04:00
|
|
|
static void
|
2008-06-10 13:12:48 -04:00
|
|
|
foo_actor_class_init (FooActorClass *klass)
|
2007-06-16 16:56:40 -04:00
|
|
|
{
|
2008-06-10 13:12:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
foo_actor_init (FooActor *actor)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
</programlisting>
|
|
|
|
</informalexample>
|
|
|
|
|
|
|
|
<para>The implementation of an actor roughly depends on what kind
|
|
|
|
of actor the class should display.</para>
|
|
|
|
|
|
|
|
<para>The implementation process can be broken down into sections:
|
|
|
|
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry>
|
|
|
|
<term>size requisition</term>
|
|
|
|
<listitem><para>used by containers to know how much space
|
|
|
|
an actor requires for itself and its eventual
|
|
|
|
children.</para></listitem>
|
|
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry>
|
|
|
|
<term>size allocation</term>
|
|
|
|
<listitem><para>used by containers to define how much space
|
|
|
|
an actor should have for itself and its eventual
|
|
|
|
children.</para></listitem>
|
|
|
|
</varlistentry>
|
|
|
|
|
|
|
|
<varlistentry>
|
|
|
|
<term>painting and picking</term>
|
|
|
|
<listitem><para>the actual actor painting and the "picking"
|
|
|
|
done to determine the actors that received events</para></listitem>
|
|
|
|
</varlistentry>
|
|
|
|
|
2009-07-21 09:13:31 -04:00
|
|
|
<varlistentry>
|
|
|
|
<term>realization and visibility</term>
|
|
|
|
<listitem><para>used by containers and composite actors to
|
|
|
|
determine whether their children should allocate (and deallocate)
|
|
|
|
specific resources associated with being added to the #ClutterStage,
|
|
|
|
and whether their children should be painted or not. A
|
|
|
|
#ClutterContainer implementation should not care about overriding
|
2009-09-27 06:38:01 -04:00
|
|
|
the <classname>ClutterActor</classname>::realize(),
|
|
|
|
<classname>ClutterActor</classname>::unrealize(),
|
|
|
|
<classname>ClutterActor</classname>::map() and
|
|
|
|
<classname>ClutterActor</classname>::unmap() virtual functions, but
|
2009-07-21 09:13:31 -04:00
|
|
|
composite actors with private children MUST implement at least
|
2009-09-27 06:38:01 -04:00
|
|
|
<classname>ClutterActor</classname>::map() and
|
|
|
|
<classname>ClutterActor</classname>::unmap().</para></listitem>
|
2009-07-21 09:13:31 -04:00
|
|
|
</varlistentry>
|
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
</variablelist>
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>Container actors should also implement the #ClutterContainer
|
|
|
|
interface to provide a consistent API for adding, removing and iterating
|
|
|
|
over their children.</para>
|
|
|
|
|
|
|
|
<refsect1 id="actor-size-requisition">
|
|
|
|
<title>Size requisition</title>
|
|
|
|
|
|
|
|
<para>Actors should usually implement the size requisition virtual
|
|
|
|
functions unless they depend on explicit sizing by the developer,
|
|
|
|
using the clutter_actor_set_width() and clutter_actor_set_height()
|
|
|
|
functions and their wrappers.</para>
|
|
|
|
|
2008-06-11 13:33:30 -04:00
|
|
|
<note><para>For instance, an actor that depends on the explicit
|
|
|
|
sizing is the #ClutterRectangle actor.</para></note>
|
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
<para>The size requisition is split into two different phases: width
|
|
|
|
requisition and height requisition.</para>
|
|
|
|
|
|
|
|
<para>The <classname>ClutterActor</classname>::get_preferred_width() and
|
|
|
|
<classname>ClutterActor</classname>::get_preferred_height() methods of a
|
|
|
|
#ClutterActor are invoked when clutter_actor_get_preferred_width() and
|
|
|
|
clutter_actor_get_preferred_height() are respectively called on an instance
|
|
|
|
of that actor class. They are used to return the preferred size of the
|
|
|
|
actor. Container actors, or composite actors with internal children,
|
|
|
|
should call clutter_actor_get_preferred_width() and
|
|
|
|
clutter_actor_get_preferred_height() on each visible child inside
|
|
|
|
their implementation of the get_preferred_width() and get_preferred_height()
|
|
|
|
virtual functions.</para>
|
|
|
|
|
|
|
|
<para>The get_preferred_width() and get_preferred_height() virtual
|
|
|
|
functions return both the minimum size of the actor and its natural
|
|
|
|
size. The minimum size is defined as the amount of space an actor
|
|
|
|
must occupy to be useful; the natural size is defined as the amount
|
|
|
|
of space an actor would occupy if nothing would constrain it.</para>
|
|
|
|
|
|
|
|
<note><para>The natural size must always be greater than, or equal
|
2009-09-27 06:38:01 -04:00
|
|
|
to the minimum size. #ClutterActor will just ignore a natural size
|
|
|
|
lesser than a minimum size.</para></note>
|
2008-06-10 13:12:48 -04:00
|
|
|
|
|
|
|
<para>The height request may be computed for a specific width, which
|
|
|
|
is passed to the implementation, thus allowing height-for-width
|
|
|
|
geometry management. Similarly, the width request may be computed
|
|
|
|
for a specific height, allowing width-for-height geometry management.
|
|
|
|
By default, every #ClutterActor uses the height-for-width geometry
|
|
|
|
management, but the setting can be changed by using the
|
|
|
|
#ClutterActor:request-mode property.</para>
|
|
|
|
|
|
|
|
<note><para>The clutter_actor_get_preferred_size() function will
|
|
|
|
automatically check the geometry management preferred by the actor
|
2008-06-11 13:33:30 -04:00
|
|
|
and return its preferred size depending on the value of the request-mode
|
2009-09-27 06:38:01 -04:00
|
|
|
property and on the natural size of the actor. The get_preferred_size()
|
|
|
|
method, though, will ignore any notion of "available size" so it should
|
|
|
|
not be used inside a <classname>ClutterActor</classname>::allocate()
|
|
|
|
implementation.</para></note>
|
2008-06-10 13:12:48 -04:00
|
|
|
|
|
|
|
<para>The size requisition starts from the #ClutterStage and it is
|
|
|
|
performed on every child of the stage following down the hierarchy
|
|
|
|
of the scene graph.</para>
|
|
|
|
|
|
|
|
<note><para>The size requisition should not take into account the
|
|
|
|
actor's scale, rotation or anchor point unless an actor is performing
|
|
|
|
layout management depending on those properties.</para></note>
|
|
|
|
|
2009-09-27 06:38:01 -04:00
|
|
|
<note><para>All the sizes are expressed using pixels with subpixel
|
|
|
|
precision. The sub-pixel precision is useful when animating actors
|
|
|
|
but it can produce odd results on screen, so you might want to
|
|
|
|
truncate the precision of the computed values.</para></note>
|
2008-06-10 13:12:48 -04:00
|
|
|
|
|
|
|
<example id="clutter-actor-get-width-request-example">
|
|
|
|
<title>Width requisition implementation of a container</title>
|
|
|
|
|
|
|
|
<para>This example shows how an actor class should override the
|
|
|
|
get_preferred_width() virtual function of #ClutterActor. In this case,
|
|
|
|
the returned widths are the union of the extents of all the
|
|
|
|
<classname>FooActor</classname> children.</para>
|
|
|
|
|
|
|
|
<para>The get_preferred_height() implementation would be similar to the
|
|
|
|
get_preferred_width() implementation, so it is omitted.</para>
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
static void
|
|
|
|
foo_actor_get_preferred_width (ClutterActor *actor,
|
2009-09-27 06:38:01 -04:00
|
|
|
gfloat for_height,
|
|
|
|
gfloat *min_width_p,
|
|
|
|
gfloat *natural_width_p)
|
2008-06-10 13:12:48 -04:00
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
ClutterUnit min_left, min_right;
|
|
|
|
ClutterUnit natural_left, natural_right;
|
|
|
|
|
|
|
|
min_left = 0;
|
|
|
|
min_right = 0;
|
|
|
|
natural_left = 0;
|
|
|
|
natural_right = 0;
|
|
|
|
|
|
|
|
for (l = children; l != NULL; l = l->next)
|
|
|
|
{
|
|
|
|
ClutterActor *child = l->data;
|
2009-09-27 06:38:01 -04:00
|
|
|
gfloat child_x, child_min, child_natural;
|
2008-06-10 13:12:48 -04:00
|
|
|
|
|
|
|
child_x = clutter_actor_get_xu (child);
|
|
|
|
|
|
|
|
clutter_actor_get_preferred_width (child, for_height,
|
|
|
|
&child_min,
|
|
|
|
&child_natural);
|
|
|
|
|
|
|
|
if (l == children)
|
|
|
|
{
|
|
|
|
/* First child */
|
|
|
|
min_left = child_x;
|
|
|
|
natural_left = child_x;
|
|
|
|
min_right = min_left + child_min;
|
|
|
|
natural_right = natural_left + child_natural;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (child_x < min_left)
|
|
|
|
min_left = child_x;
|
|
|
|
|
|
|
|
if (child_x < natural_left)
|
|
|
|
natural_left = child_x;
|
|
|
|
|
|
|
|
if (child_x + child_min > min_right)
|
|
|
|
min_right = child_x + child_min;
|
|
|
|
|
|
|
|
if (child_x + child_natural > natural_right)
|
|
|
|
natural_right = child_x + child_natural;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The request is defined as the width and height we want starting from
|
|
|
|
* our origin, since our allocation will set the origin; so we now need
|
|
|
|
* to remove any part of the request that is to the left of the origin.
|
2008-02-15 05:46:20 -05:00
|
|
|
*/
|
2008-06-10 13:12:48 -04:00
|
|
|
if (min_left < 0)
|
|
|
|
min_left = 0;
|
|
|
|
|
|
|
|
if (natural_left < 0)
|
|
|
|
natural_left = 0;
|
|
|
|
|
|
|
|
if (min_right < 0)
|
|
|
|
min_right = 0;
|
2007-06-16 16:56:40 -04:00
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
if (natural_right < 0)
|
|
|
|
natural_right = 0;
|
2007-06-16 16:56:40 -04:00
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
g_assert (min_right >= min_left);
|
|
|
|
g_assert (natural_right >= natural_left);
|
|
|
|
|
|
|
|
if (min_width_p)
|
|
|
|
*min_width_p = min_right - min_left;
|
|
|
|
|
|
|
|
if (natural_width_p)
|
|
|
|
*natural_width_p = natural_right - min_left;
|
|
|
|
}
|
|
|
|
</programlisting>
|
|
|
|
</example>
|
|
|
|
|
|
|
|
</refsect1> <!-- actor-size-requisition -->
|
|
|
|
|
|
|
|
<refsect1 id="actor-size-allocation">
|
|
|
|
<title>Size allocation</title>
|
|
|
|
|
|
|
|
<para>The <classname>ClutterActor</classname>::allocate() method of a
|
|
|
|
#ClutterActor is invoked when clutter_actor_allocate() is called on an
|
|
|
|
instance of that actor class. It is used by a parent actor to set the
|
|
|
|
coordinates of the bounding box for its children actors. Hence,
|
|
|
|
container actors, or composite actors with internal children, should
|
|
|
|
override the allocate() virtual function and call clutter_actor_allocate()
|
|
|
|
on each visible child.</para>
|
|
|
|
|
|
|
|
<para>Each actor can know from their allocation box whether they
|
|
|
|
have been moved with respect to their parent actor. Each child will
|
|
|
|
also be able to tell whether their parent has been moved with respect
|
|
|
|
to the stage.</para>
|
|
|
|
|
|
|
|
<note><para>The allocate() virtual function implementation will be
|
|
|
|
notified whether the actor has been moved, while clutter_actor_allocate()
|
2009-09-27 06:38:01 -04:00
|
|
|
will usually be invoked with the %CLUTTER_ABSOLUTE_ORIGIN_CHANGED flag,
|
|
|
|
meaning that the parent has been moved.</para></note>
|
2008-06-10 13:12:48 -04:00
|
|
|
|
|
|
|
<example id="container-allocate-example">
|
|
|
|
<title>Allocation of a container</title>
|
|
|
|
<para>In this example, <classname>FooActor</classname> acts like a
|
|
|
|
horizontal box with overflowing, like a toolbar which will display
|
|
|
|
more children as it expands. The children falling outside of the
|
2009-09-27 06:38:01 -04:00
|
|
|
allocated area will not be allocated.</para>
|
2008-06-10 13:12:48 -04:00
|
|
|
<programlisting language="C">
|
|
|
|
static void
|
2009-09-27 06:38:01 -04:00
|
|
|
foo_actor_allocate (ClutterActor *actor,
|
|
|
|
const ClutterActorBox *box,
|
|
|
|
ClutterAllocationFlags flags)
|
2008-06-10 13:12:48 -04:00
|
|
|
{
|
|
|
|
FooActor *foo_actor = FOO_ACTOR (actor);
|
2009-09-27 06:38:01 -04:00
|
|
|
gfloat available_width, available_height;
|
|
|
|
gfloat current_width, current_height;
|
|
|
|
gfloat row_height;
|
2008-06-10 13:12:48 -04:00
|
|
|
GList *l;
|
|
|
|
|
2009-09-27 06:38:01 -04:00
|
|
|
/* chain up to store the allocation of the actor */
|
|
|
|
CLUTTER_ACTOR_CLASS (foo_actor_parent_class)->allocate (actor, box, flags);
|
|
|
|
|
|
|
|
clutter_actor_box_get_size (box,
|
|
|
|
&available_width,
|
|
|
|
&available_height);
|
2008-06-10 13:12:48 -04:00
|
|
|
|
2009-09-27 06:38:01 -04:00
|
|
|
current_width = 0;
|
|
|
|
current_height = 0;
|
|
|
|
|
|
|
|
row_height = 0;
|
2008-06-10 13:12:48 -04:00
|
|
|
|
|
|
|
for (l = foo_actor->children;
|
|
|
|
l != NULL;
|
|
|
|
l = l->next)
|
2007-06-16 16:56:40 -04:00
|
|
|
{
|
2009-09-27 06:38:01 -04:00
|
|
|
ClutterActor *child = l->data;
|
2008-06-10 13:12:48 -04:00
|
|
|
ClutterActorBox child_box = { 0, };
|
2009-09-27 06:38:01 -04:00
|
|
|
gfloat child_width, child_height;
|
|
|
|
ClutterRequestMode mode;
|
2008-06-10 13:12:48 -04:00
|
|
|
|
2009-09-27 06:38:01 -04:00
|
|
|
/* do not allocate invisible children */
|
|
|
|
if (!CLUTTER_ACTOR_IS_VISIBLE (child))
|
|
|
|
continue;
|
2008-06-10 13:12:48 -04:00
|
|
|
|
2009-09-27 06:38:01 -04:00
|
|
|
g_object_get (G_OBJECT (child), "request-mode", &mode, NULL);
|
|
|
|
if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
|
|
|
|
{
|
|
|
|
gfloat min, natural;
|
|
|
|
|
|
|
|
clutter_actor_get_preferred_width (child, available_height,
|
|
|
|
&min, &natural);
|
|
|
|
child_width = MAX (min, MIN (natural, available_width));
|
|
|
|
|
|
|
|
clutter_actor_get_preferred_height (child, child_width,
|
|
|
|
&min, &natural);
|
|
|
|
child_height = MAX (min, MIN (natural, available_height));
|
|
|
|
}
|
|
|
|
else (mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
|
2008-06-10 13:12:48 -04:00
|
|
|
{
|
2009-09-27 06:38:01 -04:00
|
|
|
gfloat min, natural;
|
2007-06-16 16:56:40 -04:00
|
|
|
|
2009-09-27 06:38:01 -04:00
|
|
|
clutter_actor_get_preferred_height (child, available_width,
|
|
|
|
&min, &natural);
|
|
|
|
child_height = MAX (min, MIN (natural, available_height));
|
2008-06-10 13:12:48 -04:00
|
|
|
|
2009-09-27 06:38:01 -04:00
|
|
|
clutter_actor_get_preferred_width (child, child_height,
|
|
|
|
&min, &natural);
|
|
|
|
child_width = MAX (min, MIN (natural, available_width));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
g_assert_not_reached ();
|
2008-06-10 13:12:48 -04:00
|
|
|
|
2009-09-27 06:38:01 -04:00
|
|
|
/* overflow */
|
|
|
|
if (current_width + child_width > available_width)
|
|
|
|
{
|
|
|
|
current_width = 0;
|
|
|
|
current_height += row_height;
|
2008-06-10 13:12:48 -04:00
|
|
|
}
|
2009-09-27 06:38:01 -04:00
|
|
|
else
|
|
|
|
current_width += child_width;
|
|
|
|
|
|
|
|
/* stop allocating if we are overflowing the available height */
|
|
|
|
if (current_height + child_height > available_height)
|
|
|
|
break;
|
|
|
|
|
|
|
|
child_box.x1 = current_width;
|
|
|
|
child_box.y1 = current_height;
|
|
|
|
child_box.x2 = child_box.x1 + child_width;
|
|
|
|
child_box.y2 = child_box.y1 + child_height;
|
|
|
|
|
|
|
|
/* update the allocation */
|
|
|
|
clutter_actor_allocate (child,
|
|
|
|
&child_box,
|
|
|
|
flags);
|
|
|
|
|
|
|
|
row_height = MAX (row_height, child_height);
|
2008-06-10 13:12:48 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
</programlisting>
|
|
|
|
</example>
|
|
|
|
|
2008-06-23 11:56:30 -04:00
|
|
|
<para>The allocation is also the "paint area", that is the area where
|
|
|
|
the paint operations should be performed.</para>
|
2008-06-10 13:12:48 -04:00
|
|
|
|
|
|
|
</refsect1> <!-- actor-size-allocation -->
|
|
|
|
|
|
|
|
<refsect1 id="actor-painting-and-picking">
|
|
|
|
<title>Painting and picking</title>
|
|
|
|
|
|
|
|
<para>The <classname>ClutterActor</classname>::paint() method should be
|
2010-08-25 15:33:27 -04:00
|
|
|
overridden if the actor needs to control its drawing process, by
|
|
|
|
painting other child actors or drawing with the Cogl 3D graphics
|
|
|
|
API.</para>
|
2008-06-10 13:12:48 -04:00
|
|
|
|
|
|
|
<example id="simple-actor-paint-example">
|
|
|
|
<title>Paint implementation of a simple actor</title>
|
|
|
|
<para>In this example, the <classname>FooActor</classname>
|
|
|
|
implementation of the paint() virtual function is drawing a rectangle
|
2010-08-25 15:33:27 -04:00
|
|
|
with rounded corners with a custom color using the Cogl API.</para>
|
2008-06-10 13:12:48 -04:00
|
|
|
<programlisting>
|
2007-06-16 16:56:40 -04:00
|
|
|
static void
|
|
|
|
foo_actor_paint (ClutterActor *actor)
|
|
|
|
{
|
|
|
|
FooActor *foo_actor = FOO_ACTOR (actor);
|
2009-07-21 09:13:31 -04:00
|
|
|
ClutterActorBox allocation = { 0, };
|
|
|
|
gfloat width, height;
|
2008-06-10 13:12:48 -04:00
|
|
|
|
2008-11-12 08:57:58 -05:00
|
|
|
/* FooActor has a specific background color
|
|
|
|
*
|
|
|
|
* the alpha component must take into account the absolute
|
2008-06-10 13:12:48 -04:00
|
|
|
* opacity of the actor on the screen at this point in the
|
|
|
|
* scenegraph; this value is obtained by calling
|
|
|
|
* clutter_actor_get_paint_opacity().
|
2008-01-18 06:45:12 -05:00
|
|
|
*/
|
2008-11-12 08:57:58 -05:00
|
|
|
cogl_set_source_color4ub (priv->fgcol.red,
|
|
|
|
priv->fgcol.green,
|
|
|
|
priv->fgcol.blue,
|
|
|
|
clutter_actor_get_paint_opacity (actor));
|
2008-06-10 13:12:48 -04:00
|
|
|
|
2009-07-21 09:13:31 -04:00
|
|
|
clutter_actor_get_allocation_box (actor, &allocation);
|
|
|
|
clutter_actor_box_get_size (&allocation &width, &height);
|
2008-06-10 13:12:48 -04:00
|
|
|
|
|
|
|
/* paint a rounded rectangle using GL primitives; the area of
|
|
|
|
* paint is (0, 0) - (width, height), which means the whole
|
|
|
|
* allocation or, if the actor has a fixed size, the size that
|
|
|
|
* has been set.
|
|
|
|
*/
|
2009-07-21 09:13:31 -04:00
|
|
|
cogl_path_round_rectangle (0, 0, width, height, foo_actor->radius, 5);
|
2008-06-10 13:12:48 -04:00
|
|
|
|
|
|
|
/* and fill it with the current color */
|
2008-08-19 06:55:49 -04:00
|
|
|
cogl_path_fill ();
|
2008-06-10 13:12:48 -04:00
|
|
|
}
|
|
|
|
</programlisting>
|
|
|
|
</example>
|
|
|
|
|
|
|
|
<note><para>When inside the <classname>ClutterActor</classname>::paint()
|
|
|
|
method the actor is already positioned at the coordinates specified by
|
|
|
|
its parent; all the paint operations should take place from the (0, 0)
|
|
|
|
coordinates.</para></note>
|
|
|
|
|
|
|
|
<para>Container actors or composite actors with internal children should
|
|
|
|
also override the paint method, and call clutter_actor_paint() on every
|
|
|
|
visible child:</para>
|
|
|
|
|
|
|
|
<example id="container-actor-paint-example">
|
|
|
|
<title>Paint implementation of a container</title>
|
|
|
|
<para>In this example, <classname>FooActor</classname> is a simple
|
2008-07-17 06:40:19 -04:00
|
|
|
container invoking clutter_actor_paint() on every visible child.</para>
|
2008-06-10 13:12:48 -04:00
|
|
|
<programlisting>
|
|
|
|
static void
|
|
|
|
foo_actor_paint (ClutterActor *actor)
|
|
|
|
{
|
|
|
|
FooActor *foo_actor = FOO_ACTOR (actor);
|
|
|
|
GList *child;
|
|
|
|
|
|
|
|
for (child = foo_actor->children;
|
|
|
|
child != NULL;
|
|
|
|
child = child->next)
|
2007-06-16 16:56:40 -04:00
|
|
|
{
|
|
|
|
ClutterActor *child_actor = child->data;
|
|
|
|
|
2009-07-21 09:13:31 -04:00
|
|
|
clutter_actor_paint (child_actor);
|
2007-06-16 16:56:40 -04:00
|
|
|
}
|
2008-01-18 06:45:12 -05:00
|
|
|
}
|
2008-06-10 13:12:48 -04:00
|
|
|
</programlisting>
|
|
|
|
</example>
|
2008-01-18 06:45:12 -05:00
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
<para>If the actor has a non-rectangular shape, or it has internal
|
|
|
|
children that need to be distinguished by the events delivery mechanism,
|
|
|
|
the <classname>ClutterActor</classname>::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="simple-actor-pick-example">
|
|
|
|
<title>Pick implementation of a simple actor</title>
|
|
|
|
<para>In this example, <classname>FooActor</classname> overrides the
|
|
|
|
pick() virtual function default implementation to paint itself with a
|
|
|
|
shaped silhouette, to allow events only on the actual shape of the actor
|
2008-06-23 11:56:30 -04:00
|
|
|
instead of the whole paint area.</para>
|
2008-06-10 13:12:48 -04:00
|
|
|
<programlisting>
|
2008-01-18 06:45:12 -05:00
|
|
|
static void
|
|
|
|
foo_actor_pick (ClutterActor *actor,
|
|
|
|
const ClutterColor *pick_color)
|
|
|
|
{
|
|
|
|
FooActor *foo_actor = FOO_ACTOR (actor);
|
2009-07-21 09:13:31 -04:00
|
|
|
ClutterActorBox allocation = { 0, };
|
|
|
|
gfloat width, height;
|
2008-01-18 06:45:12 -05:00
|
|
|
|
2008-02-15 05:46:20 -05:00
|
|
|
/* 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;
|
|
|
|
|
2009-07-21 09:13:31 -04:00
|
|
|
clutter_actor_get_allocation_box (actor, &allocation);
|
|
|
|
clutter_actor_box_get_size (&allocation, &width, &height);
|
2008-01-18 06:45:12 -05:00
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
/* use the passed color to paint ourselves */
|
2008-11-12 08:57:58 -05:00
|
|
|
cogl_set_source_color4ub (pick_color->red,
|
|
|
|
pick_color->green,
|
|
|
|
pick_color->blue,
|
|
|
|
pick_color->alpha);
|
2008-01-18 06:45:12 -05:00
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
/* paint a round rectangle */
|
2009-07-21 09:13:31 -04:00
|
|
|
cogl_path_round_rectangle (0, 0, width, height, foo_actor->radius, 5);
|
2008-06-10 13:12:48 -04:00
|
|
|
|
|
|
|
/* and fill it with the current color */
|
2009-07-21 09:13:31 -04:00
|
|
|
cogl_path_fill ();
|
2007-06-16 16:56:40 -04:00
|
|
|
}
|
2008-06-10 13:12:48 -04:00
|
|
|
</programlisting>
|
|
|
|
</example>
|
|
|
|
|
|
|
|
<para>Containers should simply chain up to the parent class'
|
|
|
|
pick() implementation to get their silhouette painted and then
|
|
|
|
paint their children:</para>
|
|
|
|
|
|
|
|
<example id="container-actor-pick-example">
|
|
|
|
<title>Pick implementation of a container</title>
|
|
|
|
<para>In this example, <classname>FooActor</classname> allows the
|
|
|
|
picking of each child it contains, as well as itself.</para>
|
|
|
|
<programlisting>
|
|
|
|
static void
|
|
|
|
foo_actor_pick (ClutterActor *actor,
|
|
|
|
const ClutterColor *pick_color)
|
|
|
|
{
|
|
|
|
FooActor *foo_actor = FOO_ACTOR (actor);
|
|
|
|
|
|
|
|
/* this will paint a silhouette corresponding to the paint box */
|
|
|
|
CLUTTER_ACTOR_CLASS (foo_actor_parent_class)->pick (actor, pick_color);
|
|
|
|
|
|
|
|
/* clutter_actor_paint() is context-sensitive, and will perform
|
|
|
|
* a pick paint if the scene graph is in pick mode
|
|
|
|
*/
|
2009-07-21 09:13:31 -04:00
|
|
|
clutter_actor_paint (foo_actor->child);
|
2008-06-10 13:12:48 -04:00
|
|
|
}
|
|
|
|
</programlisting>
|
|
|
|
</example>
|
|
|
|
|
|
|
|
</refsect1> <!-- actor-painting-and-picking -->
|
2007-06-16 16:56:40 -04:00
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
<refsect1 id="implementing-clutter-container">
|
2008-02-15 06:27:34 -05:00
|
|
|
<title>Implementing Containers</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
The #ClutterContainer interface should be implemented by subclasses
|
|
|
|
of #ClutterActor who wants to provide a general API for adding child
|
|
|
|
actors.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
If the #ClutterActor subclass only handles internal children, or it's
|
|
|
|
not suitable for having generic actors added to it, it should not
|
|
|
|
implement the #ClutterContainer interface, but simply use
|
|
|
|
clutter_actor_set_parent():
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<example id="clutter-actor-set-parent-example">
|
2008-06-10 13:12:48 -04:00
|
|
|
<title>Parenting an actor</title>
|
|
|
|
<para>In this example, <classname>FooActor</classname> has an internal
|
|
|
|
child of type <classname>BazActor</classname> which is assigned using a
|
|
|
|
specific function called foo_actor_add_baz(). The
|
|
|
|
<classname>FooActor</classname> instance takes ownership of the
|
|
|
|
<classname>BazActor</classname> instance and sets the parent-child
|
|
|
|
relationship using clutter_actor_set_parent().</para>
|
2008-02-15 06:27:34 -05:00
|
|
|
<programlisting>
|
|
|
|
void
|
|
|
|
foo_actor_add_baz (FooActor *foo_actor,
|
|
|
|
BazActor *baz_actor)
|
|
|
|
{
|
|
|
|
g_return_if_fail (FOO_IS_ACTOR (foo_actor));
|
|
|
|
g_return_if_fail (BAZ_IS_ACTOR (baz_actor));
|
|
|
|
|
|
|
|
/* unparent the previous BazActor; this will automatically call
|
|
|
|
* g_object_unref() on the actor
|
|
|
|
*/
|
|
|
|
if (foo_actor->baz)
|
|
|
|
clutter_actor_unparent (foo_actor->baz);
|
|
|
|
|
|
|
|
foo_actor->baz = baz_actor;
|
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
/* this will cause the initial floating reference of ClutterActor to
|
|
|
|
* disappear, and add a new reference on baz_actor. foo_actor has now
|
|
|
|
* taken ownership of baz_actor, so that:
|
|
|
|
*
|
|
|
|
* foo_actor_add_baz (foo_actor, baz_actor_new ());
|
|
|
|
*
|
|
|
|
* is a safe statement (no reference is leaked).
|
2008-02-15 06:27:34 -05:00
|
|
|
*/
|
|
|
|
clutter_actor_set_parent (CLUTTER_ACTOR (baz_actor),
|
|
|
|
CLUTTER_ACTOR (foo_actor));
|
|
|
|
|
2008-06-11 13:33:30 -04:00
|
|
|
/* a container should queue a change in the layout */
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (foo_actor));
|
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
/* emit a signal and notification */
|
2008-02-15 06:27:34 -05:00
|
|
|
g_signal_emit (foo_actor, foo_actor_signals[BAZ_CHANGED], 0, baz_actor);
|
2008-06-10 13:12:48 -04:00
|
|
|
g_object_notify (G_OBJECT (foo_actor), "baz");
|
2008-02-15 06:27:34 -05:00
|
|
|
}
|
|
|
|
</programlisting>
|
|
|
|
</example>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
In order to implement the #ClutterContainer interface, these virtual
|
|
|
|
functions must be defined:
|
|
|
|
|
|
|
|
<variablelist>
|
|
|
|
<varlistentry>
|
|
|
|
<term>ClutterContainer::add</term>
|
|
|
|
<listitem>
|
2008-06-10 13:12:48 -04:00
|
|
|
<para>The container actor should hold a pointer to the passed
|
2009-09-27 06:38:01 -04:00
|
|
|
#ClutterActor, call clutter_actor_set_parent() on it, queue
|
|
|
|
a relayout on itself and then emit the
|
|
|
|
#ClutterContainer::actor-added signal to notify
|
2008-06-10 13:12:48 -04:00
|
|
|
handlers of the newly added actor.</para>
|
2008-02-15 06:27:34 -05:00
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term>ClutterContainer::remove</term>
|
|
|
|
<listitem>
|
2008-06-10 13:12:48 -04:00
|
|
|
<para>The container actor should increase the reference count
|
|
|
|
of the passed #ClutterActor, remove the pointer held on the
|
|
|
|
child and call clutter_actor_unparent() on it; then, emit the
|
|
|
|
#ClutterContainer::actor-removed signal and decrease the
|
|
|
|
reference count.</para>
|
2008-02-15 06:27:34 -05:00
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term>ClutterContainer::foreach</term>
|
|
|
|
<listitem>
|
2008-06-10 13:12:48 -04:00
|
|
|
<para>The container should invoke the callback on every
|
|
|
|
child it is holding.</para>
|
2008-02-15 06:27:34 -05:00
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
2009-07-21 09:13:31 -04:00
|
|
|
<varlistentry>
|
|
|
|
<term>ClutterContainer::foreach_with_internals</term>
|
|
|
|
<listitem>
|
2009-09-27 06:38:01 -04:00
|
|
|
<para>The container should invoke the callback on every
|
2009-07-21 09:13:31 -04:00
|
|
|
child it is holding, including eventual private children
|
2009-09-27 06:38:01 -04:00
|
|
|
that should not be handled by the #ClutterContainer API.
|
|
|
|
This method can be ignored if the container does not
|
|
|
|
have internal children.</para>
|
2009-07-21 09:13:31 -04:00
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
2008-02-15 06:27:34 -05:00
|
|
|
<varlistentry>
|
|
|
|
<term>ClutterContainer::raise</term>
|
|
|
|
<listitem>
|
2008-06-10 13:12:48 -04:00
|
|
|
<para>The container should move the passed child on top
|
|
|
|
of the given sibling, or on top of the paint stack in
|
2009-09-27 06:38:01 -04:00
|
|
|
case the sibling is NULL. This method can be ignored if the
|
|
|
|
container does not have overlapping children.</para>
|
2008-02-15 06:27:34 -05:00
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term>ClutterContainer::lower</term>
|
|
|
|
<listitem>
|
2008-06-10 13:12:48 -04:00
|
|
|
<para>The container should move the passed child below
|
|
|
|
the given sibling, or on the bottom of the paint stack
|
2009-09-27 06:38:01 -04:00
|
|
|
in case the sibling is NULL. This method can be ignored
|
|
|
|
if the container does not have overlapping children.</para>
|
2008-02-15 06:27:34 -05:00
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
|
|
<term>ClutterContainer::sort_depth_order</term>
|
|
|
|
<listitem>
|
2008-06-10 13:12:48 -04:00
|
|
|
<para>The container should sort the paint stack depending
|
2009-09-27 06:38:01 -04:00
|
|
|
on the relative depths of each child. This method can
|
|
|
|
be ignored if the container does not have overlapping
|
|
|
|
children.</para>
|
2008-02-15 06:27:34 -05:00
|
|
|
</listitem>
|
|
|
|
</varlistentry>
|
|
|
|
</variablelist>
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
2008-06-10 13:12:48 -04:00
|
|
|
</refsect1> <!-- implementing-clutter-container -->
|
2008-02-15 05:46:20 -05:00
|
|
|
|
2007-06-16 16:56:40 -04:00
|
|
|
</chapter>
|