mirror of
https://github.com/brl/mutter.git
synced 2024-11-23 00:20:42 -05:00
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-sections.txt: Update with the new API. * clutter/subclassing-ClutterActor.sgml: Update with the new size negotiation API.
This commit is contained in:
parent
4a788a6df7
commit
d93c7d1f85
@ -1,3 +1,10 @@
|
||||
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* clutter/clutter-sections.txt: Update with the new API.
|
||||
|
||||
* clutter/subclassing-ClutterActor.sgml: Update with the new
|
||||
size negotiation API.
|
||||
|
||||
2008-06-09 Chris Lord <chris@openedhand.com>
|
||||
|
||||
* cogl/cogl-sections.txt:
|
||||
|
@ -255,15 +255,15 @@ clutter_container_lower_child
|
||||
clutter_container_sort_depth_order
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_container_find_child_property
|
||||
clutter_container_list_child_properties
|
||||
clutter_container_class_find_child_property
|
||||
clutter_container_class_list_child_properties
|
||||
clutter_container_child_set_property
|
||||
clutter_container_child_get_property
|
||||
clutter_container_child_set
|
||||
clutter_container_child_get
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_container_get_child_data
|
||||
clutter_container_get_child_meta
|
||||
|
||||
<SUBSECTION Standard>
|
||||
CLUTTER_TYPE_CONTAINER
|
||||
@ -275,21 +275,21 @@ clutter_container_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>clutter-child-data</FILE>
|
||||
<TITLE>ClutterChildData<TITLE>
|
||||
ClutterChildData
|
||||
ClutterChildDataClass
|
||||
clutter_child_data_get_container
|
||||
clutter_child_data_get_actor
|
||||
<FILE>clutter-child-meta</FILE>
|
||||
<TITLE>ClutterChildMeta</TITLE>
|
||||
ClutterChildMeta
|
||||
ClutterChildMetaClass
|
||||
clutter_child_meta_get_container
|
||||
clutter_child_meta_get_actor
|
||||
<SUBSECTION Standard>
|
||||
CLUTTER_TYPE_CHILD_DATA
|
||||
CLUTTER_CHILD_DATA
|
||||
CLUTTER_IS_CHILD_DATA
|
||||
CLUTTER_CHILD_DATA_CLASS
|
||||
CLUTTER_IS_CHILD_DATA_CLASS
|
||||
CLUTTER_CHILD_DATA_GET_CLASS
|
||||
CLUTTER_TYPE_CHILD_META
|
||||
CLUTTER_CHILD_META
|
||||
CLUTTER_IS_CHILD_META
|
||||
CLUTTER_CHILD_META_CLASS
|
||||
CLUTTER_IS_CHILD_META_CLASS
|
||||
CLUTTER_CHILD_META_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
clutter_child_data_get_type
|
||||
clutter_child_meta_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
@ -330,6 +330,7 @@ CLUTTER_ACTOR_IS_REACTIVE
|
||||
<SUBSECTION>
|
||||
ClutterActorBox
|
||||
ClutterActorFlags
|
||||
ClutterRequestMode
|
||||
ClutterGeometry
|
||||
CLUTTER_CALLBACK
|
||||
ClutterCallback
|
||||
@ -343,22 +344,32 @@ clutter_actor_realize
|
||||
clutter_actor_unrealize
|
||||
clutter_actor_paint
|
||||
clutter_actor_queue_redraw
|
||||
clutter_actor_queue_relayout
|
||||
clutter_actor_destroy
|
||||
clutter_actor_request_coords
|
||||
clutter_actor_query_coords
|
||||
clutter_actor_event
|
||||
clutter_actor_pick
|
||||
clutter_actor_should_pick_paint
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_actor_allocate
|
||||
clutter_actor_get_allocation_coords
|
||||
clutter_actor_get_allocation_box
|
||||
clutter_actor_get_allocation_geometry
|
||||
clutter_actor_get_allocation_vertices
|
||||
clutter_actor_get_preferred_size
|
||||
clutter_actor_get_preferred_width
|
||||
clutter_actor_get_preferred_height
|
||||
clutter_actor_get_paint_area
|
||||
clutter_actor_set_fixed_position_set
|
||||
clutter_actor_get_fixed_position_set
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_actor_set_geometry
|
||||
clutter_actor_get_geometry
|
||||
clutter_actor_get_coords
|
||||
clutter_actor_set_size
|
||||
clutter_actor_get_size
|
||||
clutter_actor_set_position
|
||||
clutter_actor_get_position
|
||||
clutter_actor_get_abs_position
|
||||
clutter_actor_set_width
|
||||
clutter_actor_get_width
|
||||
clutter_actor_set_height
|
||||
@ -392,6 +403,7 @@ clutter_actor_raise
|
||||
clutter_actor_lower
|
||||
clutter_actor_raise_top
|
||||
clutter_actor_lower_bottom
|
||||
clutter_actor_get_stage
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_actor_set_depth
|
||||
@ -399,15 +411,16 @@ clutter_actor_get_depth
|
||||
clutter_actor_set_scale
|
||||
clutter_actor_get_scale
|
||||
clutter_actor_is_scaled
|
||||
clutter_actor_get_abs_size
|
||||
clutter_actor_apply_transform_to_point
|
||||
clutter_actor_transform_stage_point
|
||||
clutter_actor_apply_relative_transform_to_point
|
||||
clutter_actor_get_transformed_position
|
||||
clutter_actor_get_transformed_size
|
||||
clutter_actor_get_paint_opacity
|
||||
clutter_actor_get_abs_allocation_vertices
|
||||
|
||||
<SUBSECTION>
|
||||
ClutterVertex
|
||||
clutter_actor_get_vertices
|
||||
clutter_actor_get_relative_vertices
|
||||
clutter_actor_box_get_from_vertices
|
||||
|
||||
<SUBSECTION>
|
||||
@ -444,7 +457,11 @@ clutter_actor_get_anchor_pointu
|
||||
clutter_actor_move_anchor_pointu
|
||||
clutter_actor_set_clipu
|
||||
clutter_actor_get_clipu
|
||||
clutter_actor_set_rotationu
|
||||
clutter_actor_get_rotationu
|
||||
clutter_actor_move_byu
|
||||
clutter_actor_get_transformed_positionu
|
||||
clutter_actor_get_transformed_sizeu
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_actor_set_scalex
|
||||
@ -516,8 +533,9 @@ ClutterStage
|
||||
ClutterStageClass
|
||||
CLUTTER_STAGE_WIDTH
|
||||
CLUTTER_STAGE_HEIGHT
|
||||
clutter_stage_new
|
||||
clutter_stage_get_default
|
||||
clutter_stage_new
|
||||
clutter_stage_is_default
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_stage_set_color
|
||||
@ -528,6 +546,7 @@ clutter_stage_show_cursor
|
||||
clutter_stage_hide_cursor
|
||||
clutter_stage_get_actor_at_pos
|
||||
clutter_stage_ensure_current
|
||||
clutter_stage_queue_redraw
|
||||
clutter_stage_event
|
||||
clutter_stage_set_key_focus
|
||||
clutter_stage_get_key_focus
|
||||
@ -564,9 +583,9 @@ CLUTTER_TYPE_STAGE
|
||||
CLUTTER_STAGE_CLASS
|
||||
CLUTTER_IS_STAGE_CLASS
|
||||
CLUTTER_STAGE_GET_CLASS
|
||||
CLUTTER_STAGE_TYPE
|
||||
CLUTTER_TYPE_PERSPECTIVE
|
||||
CLUTTER_TYPE_FOG
|
||||
CLUTTER_STAGE_TYPE
|
||||
<SUBSECTION Private>
|
||||
ClutterStagePrivate
|
||||
clutter_stage_get_type
|
||||
@ -821,6 +840,8 @@ clutter_backend_get_double_click_time
|
||||
clutter_backend_set_double_click_time
|
||||
clutter_backend_get_double_click_distance
|
||||
clutter_backend_set_double_click_distance
|
||||
clutter_backend_set_font_options
|
||||
clutter_backend_get_font_options
|
||||
<SUBSECTION Standard>
|
||||
CLUTTER_BACKEND
|
||||
CLUTTER_IS_BACKEND
|
||||
@ -1014,6 +1035,7 @@ clutter_key_event_symbol
|
||||
clutter_key_event_code
|
||||
clutter_key_event_unicode
|
||||
clutter_keysym_to_unicode
|
||||
|
||||
<SUBSECTION Standard>
|
||||
CLUTTER_TYPE_EVENT
|
||||
<SUBSECTION Private>
|
||||
@ -1028,6 +1050,7 @@ ClutterInitError
|
||||
clutter_init
|
||||
clutter_init_with_args
|
||||
clutter_get_option_group
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_main
|
||||
clutter_main_quit
|
||||
@ -1044,6 +1067,9 @@ clutter_set_motion_events_enabled
|
||||
clutter_get_motion_events_enabled
|
||||
clutter_set_motion_events_frequency
|
||||
clutter_get_motion_events_frequency
|
||||
clutter_clear_glyph_cache
|
||||
clutter_set_use_mipmapped_text
|
||||
clutter_get_use_mipmapped_text
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_threads_set_lock_functions
|
||||
@ -1102,10 +1128,10 @@ clutter_x11_remove_filter
|
||||
<SECTION>
|
||||
<FILE>clutter-win32</FILE>
|
||||
<TITLE>Win32 Specific Support</TITLE>
|
||||
clutter_win32_get_stage_from_window
|
||||
clutter_win32_get_stage_window
|
||||
clutter_win32_disable_event_retrieval
|
||||
clutter_win32_set_stage_foreign
|
||||
clutter_win32_get_stage_from_window
|
||||
clutter_win32_get_stage_window
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
@ -14,135 +14,524 @@
|
||||
<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>
|
||||
|
||||
<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>
|
||||
machinery for subclassing a #GObject should be used:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
static void
|
||||
foo_actor_query_coords (ClutterActor *actor,
|
||||
ClutterActorBox *box)
|
||||
#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
|
||||
{
|
||||
FooActor *foo_actor = FOO_ACTOR (actor);
|
||||
GList *child;
|
||||
ClutterActor parent_instance;
|
||||
} FooActor;
|
||||
|
||||
/* Clutter uses high-precision units which can be converted from
|
||||
* and into pixels, typographic points, percentages, etc.
|
||||
*/
|
||||
ClutterUnit width, height;
|
||||
typedef struct _FooActorClass
|
||||
{
|
||||
ClutterActorClass parent_class;
|
||||
} FooActorClass;
|
||||
|
||||
/* initialize our size */
|
||||
width = height = 0;
|
||||
G_DEFINE_TYPE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
for (l = foo_actor->children; l != NULL; l = l->next)
|
||||
static void
|
||||
foo_actor_class_init (FooActorClass *klass)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
</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>
|
||||
|
||||
<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
|
||||
to the minimum size. #ClutterActor will warn in case this assumption
|
||||
is not respected by an implementation.</para></note>
|
||||
|
||||
<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
|
||||
and return its preferred size depending on it and on the natural
|
||||
size.</para></note>
|
||||
|
||||
<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>
|
||||
|
||||
<note><para>All the sizes are expressed using #ClutterUnit<!-- -->s, the
|
||||
internal high-precision unit type, which guarantees sub-pixel precision.
|
||||
#ClutterUnit currently has the same limitations that #ClutterFixed has,
|
||||
see the <link linkend="clutter-Fixed-Point-Support">fixed point page</link>.
|
||||
</para></note>
|
||||
|
||||
<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,
|
||||
ClutterUnit for_height,
|
||||
ClutterUnit *min_width_p,
|
||||
ClutterUnit *natural_width_p)
|
||||
{
|
||||
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_actor = child->data;
|
||||
ClutterActor *child = l->data;
|
||||
ClutterUnit child_x, child_min, child_natural;
|
||||
|
||||
/* we consider only visible actors */
|
||||
if (CLUTTER_ACTOR_IS_VISIBLE (child_actor))
|
||||
child_x = clutter_actor_get_xu (child);
|
||||
|
||||
clutter_actor_get_preferred_width (child, for_height,
|
||||
&child_min,
|
||||
&child_natural);
|
||||
|
||||
if (l == children)
|
||||
{
|
||||
ClutterActorBox child_box = { 0, };
|
||||
/* 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;
|
||||
|
||||
clutter_actor_query_coords (child_actor, &child_box);
|
||||
|
||||
width += child_box.x2 - child_box.x2;
|
||||
height += child_box.y2 - child_box.y1;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
box->x2 = box->x1 + width
|
||||
box->y2 = box->y1 + height;
|
||||
/* 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.
|
||||
*/
|
||||
if (min_left < 0)
|
||||
min_left = 0;
|
||||
|
||||
if (natural_left < 0)
|
||||
natural_left = 0;
|
||||
|
||||
if (min_right < 0)
|
||||
min_right = 0;
|
||||
|
||||
if (natural_right < 0)
|
||||
natural_right = 0;
|
||||
|
||||
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>
|
||||
</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()
|
||||
will usually be invoked with a boolean flag meaning that the parent
|
||||
has been moved.</para></note>
|
||||
|
||||
<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
|
||||
allocated area will fade out; the children falling inside the
|
||||
same area will fade in.</para>
|
||||
<programlisting language="C">
|
||||
static void
|
||||
foo_actor_allocate (ClutterActor *actor,
|
||||
const ClutterActorBox *box,
|
||||
gboolean absolute_origin_changed)
|
||||
{
|
||||
FooActor *foo_actor = FOO_ACTOR (actor);
|
||||
ClutterUnit current_width;
|
||||
GList *l;
|
||||
|
||||
/* chain up to set the allocation of the actor */
|
||||
CLUTTER_ACTOR_CLASS (foo_actor_parent_class)->allocate (actor, box, absolute_origin_changed);
|
||||
|
||||
current_width = foo_actor->padding;
|
||||
|
||||
for (l = foo_actor->children;
|
||||
l != NULL;
|
||||
l = l->next)
|
||||
{
|
||||
FooActorChild *child = l->data;
|
||||
ClutterUnit natural_width, natural_height;
|
||||
ClutterActorBox child_box = { 0, };
|
||||
|
||||
/* each child will get as much space as they require */
|
||||
clutter_actor_get_preferred_size (CLUTTER_ACTOR (child),
|
||||
NULL, NULL,
|
||||
&natural_width, &natural_height);
|
||||
|
||||
/* if the child is overflowing, we just fade it out */
|
||||
if (current_width + natual_width > box->x2 - box->x1)
|
||||
foo_actor_fade_child (foo_actor, child, 0);
|
||||
else
|
||||
{
|
||||
current_width += natural_width + priv->padding;
|
||||
|
||||
child_box.x1 = current_width;
|
||||
child_box.y1 = 0;
|
||||
child_box.x2 = child_box.x1 + natural_width;
|
||||
child_box.y2 = child_box.y1 + natural_height;
|
||||
|
||||
/* update the allocation */
|
||||
clutter_actor_allocate (CLUTTER_ACTOR (child),
|
||||
&child_box,
|
||||
absolute_origin_changed);
|
||||
|
||||
/* fade the child in if it wasn't visible */
|
||||
foo_actor_fade_child (foo_actor, child, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<para>An actor should always paint inside its allocation. It is,
|
||||
however, possible to paint outside the negotiated size by overriding
|
||||
the <classname>ClutterActor</classname>::get_paint_area() virtual
|
||||
function and setting the passed #ClutterActorBox with their
|
||||
<emphasis>untransformed</emphasis> paint area. This allows writing
|
||||
actors that can effectively paint on an area different in size and
|
||||
position from the allocation area.</para>
|
||||
|
||||
<para>The <classname>ClutterActor</classname>::get_paint_area() method of
|
||||
a #ClutterActor is internally invoked when clutter_actor_get_paint_area()
|
||||
is called on an instance of that actor class. The get_paint_area()
|
||||
virtual function must return the untransformed area used by the
|
||||
actor to paint itself; clutter_actor_get_paint_area() will then
|
||||
proceed to transform the area coordinates into the frame of reference
|
||||
of the actor's parent (taking into account anchor point, scaling
|
||||
and rotation).</para>
|
||||
|
||||
<note><para>The default paint area is the allocation area of the
|
||||
actor.</para></note>
|
||||
|
||||
<example id="container-actor-paint-area-example">
|
||||
<title>Implementation of get_paint_area()</title>
|
||||
<para>In this example, <classname>FooActor</classname> implements
|
||||
the get_paint_area() virtual function to return an area equivalent
|
||||
to those of its children plus a border which is not taken into
|
||||
account by the size negotiation process.</para>
|
||||
<programlisting>
|
||||
static void
|
||||
foo_actor_get_paint_area (ClutterActor *actor,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
FooActor *foo_actor = FOO_ACTOR (actor);
|
||||
|
||||
if (!foo_actor->children)
|
||||
{
|
||||
/* if we don't have any children we return the
|
||||
* allocation given to us
|
||||
*/
|
||||
clutter_actor_get_allocation_box (actor, box);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClutterActorBox all_box = { 0, };
|
||||
GList *l;
|
||||
|
||||
/* our paint area is the union of the children
|
||||
* paint areas, plus a border
|
||||
*/
|
||||
for (l = foo_actor->children; l != NULL; l = l>next)
|
||||
{
|
||||
ClutterActor *child = l->data;
|
||||
ClutterActorBox child_box = { 0, };
|
||||
|
||||
clutter_actor_get_paint_area (child, &child_box);
|
||||
|
||||
if (l == foo_actor->children)
|
||||
all_box = child_box;
|
||||
else
|
||||
{
|
||||
if (child_box.x1 < all_box.x1)
|
||||
all_box.x1 = child_box.x1;
|
||||
|
||||
if (child_box.y1 < all_box.y1)
|
||||
all_box.y1 = child_box.y1;
|
||||
|
||||
if (child_box.x2 < all_box.x2)
|
||||
all_box.x2 = child_box.x2;
|
||||
|
||||
if (child_box.y2 < all_box.y2)
|
||||
all_box.y2 = child_box.y2;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply the border width around the box */
|
||||
all_box.x1 -= (foo_actor->border_width / 2);
|
||||
all_box.y1 -= (foo_actor->border_width / 2);
|
||||
all_box.x2 += (foo_actor->border_width / 2);
|
||||
all_box.y2 += (foo_actor->border_width / 2);
|
||||
|
||||
*box = all_box;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
</refsect1> <!-- actor-size-allocation -->
|
||||
|
||||
<refsect1 id="actor-painting-and-picking">
|
||||
<title>Painting and picking</title>
|
||||
|
||||
<para>The <classname>ClutterActor</classname>::paint() method should be
|
||||
overridden if the actor needs to control its drawing process, either by
|
||||
using the Clutter GL and GLES abstraction library (COGL) or by directly
|
||||
using the GL or GLES API.</para>
|
||||
|
||||
<note><para>Actors performing transformations should push the GL matrix
|
||||
first and then pop the GL matrix before returning.</para></note>
|
||||
|
||||
<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>
|
||||
<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
|
||||
with rounded corners with a custom color. The COGL API is used, to
|
||||
allow portability between GL and GLES platforms.</para>
|
||||
<programlisting>
|
||||
static void
|
||||
foo_actor_paint (ClutterActor *actor)
|
||||
{
|
||||
FooActor *foo_actor = FOO_ACTOR (actor);
|
||||
ClutterColor color = { 0, };
|
||||
ClutterUnit w, h, r;
|
||||
|
||||
<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>
|
||||
cogl_push_matrix ();
|
||||
|
||||
<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>
|
||||
/* FooActor has a specific background color */
|
||||
color.red = foo_actor->bg_color.red;
|
||||
color.green = foo_actor->bg_color.green;
|
||||
color.blue = foo_actor->bg_color.blue;
|
||||
|
||||
<example id="clutter-actor-paint-example">
|
||||
<programlisting>
|
||||
/* the alpha component must take into account the absolute
|
||||
* opacity of the actor on the screen at this point in the
|
||||
* scenegraph; this value is obtained by calling
|
||||
* clutter_actor_get_paint_opacity().
|
||||
*/
|
||||
color.alpha = clutter_actor_get_paint_opacity (actor);
|
||||
|
||||
/* set the color of the pen */
|
||||
cogl_color (&color);
|
||||
|
||||
/* get the size of the actor with sub-pixel precision */
|
||||
w = CLUTTER_UNITS_TO_FIXED (clutter_actor_get_widthu (actor));
|
||||
h = CLUTTER_UNITS_TO_FIXED (clutter_actor_get_heightu (actor));
|
||||
|
||||
/* this is the arc radius for the rounded rectangle corners */
|
||||
r = CLUTTER_UNITS_TO_FIXED (foo_actor->radius);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
cogl_round_rectangle (0, 0, w, h, r, 5);
|
||||
|
||||
/* and fill it with the current color */
|
||||
cogl_fill ();
|
||||
|
||||
cogl_pop_matrix ();
|
||||
}
|
||||
</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
|
||||
container invoking clutter_actor_paint() on every visible child. To
|
||||
allow transformations on itself to affect the children, the GL modelview
|
||||
matrix is pushed at the beginning of the paint sequence, and the popped
|
||||
at the end.</para>
|
||||
<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)
|
||||
for (child = foo_actor->children;
|
||||
child != NULL;
|
||||
child = child->next)
|
||||
{
|
||||
ClutterActor *child_actor = child->data;
|
||||
|
||||
if (CLUTTER_ACTOR_IS_MAPPED (child_actor))
|
||||
/* paint only visible children */
|
||||
if (CLUTTER_ACTOR_IS_VISIBLE (child_actor))
|
||||
clutter_actor_paint (child_actor);
|
||||
}
|
||||
|
||||
cogl_pop_matrix ();
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<para>When painting a blended actor, cogl_enable() should be called with
|
||||
the %CGL_BLEND flag; or, alternatively, glEnable() with %GL_BLEND on
|
||||
OpenGL.</para>
|
||||
<note><para>A container imposing a layout on its children may
|
||||
opt to use the paint area as returned by clutter_actor_get_paint_area()
|
||||
instead of the allocation.</para></note>
|
||||
|
||||
<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>
|
||||
<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="clutter-actor-pick-example">
|
||||
<programlisting>
|
||||
<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
|
||||
instead of the paint area.</para>
|
||||
<programlisting>
|
||||
static void
|
||||
foo_actor_pick (ClutterActor *actor,
|
||||
const ClutterColor *pick_color)
|
||||
{
|
||||
FooActor *foo_actor = FOO_ACTOR (actor);
|
||||
guint width, height;
|
||||
ClutterUnit w, h, r;
|
||||
|
||||
/* it is possible to avoid a costly paint by checking whether the
|
||||
* actor should really be painted in pick mode
|
||||
@ -150,32 +539,56 @@ foo_actor_pick (ClutterActor *actor,
|
||||
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).
|
||||
*/
|
||||
w = CLUTTER_UNITS_TO_FIXED (clutter_actor_get_widthu (actor));
|
||||
h = CLUTTER_UNITS_TO_FIXED (clutter_actor_get_heightu (actor));
|
||||
|
||||
/* this is the arc radius for the rounded rectangle corners */
|
||||
r = CLUTTER_UNITS_TO_FIXED (foo_actor->radius);
|
||||
|
||||
/* use the passed color to paint ourselves */
|
||||
cogl_color (pick_color);
|
||||
|
||||
clutter_actor_get_size (actor, &width, &height);
|
||||
/* paint a round rectangle */
|
||||
cogl_round_rectangle (0, 0, w, h, r, 5);
|
||||
|
||||
/* 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 ();
|
||||
/* and fill it with the current color */
|
||||
cogl_fill ();
|
||||
|
||||
cogl_pop_matrix ();
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<section id="implementing-clutter-container">
|
||||
<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
|
||||
*/
|
||||
if (CLUTTER_ACTOR_IS_VISIBLE (foo_actor->child))
|
||||
clutter_actor_paint (foo_actor->child);
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
</refsect1> <!-- actor-painting-and-picking -->
|
||||
|
||||
<refsect1 id="implementing-clutter-container">
|
||||
<title>Implementing Containers</title>
|
||||
|
||||
<para>
|
||||
@ -192,6 +605,13 @@ foo_actor_pick (ClutterActor *actor,
|
||||
</para>
|
||||
|
||||
<example id="clutter-actor-set-parent-example">
|
||||
<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>
|
||||
<programlisting>
|
||||
void
|
||||
foo_actor_add_baz (FooActor *foo_actor,
|
||||
@ -208,14 +628,20 @@ foo_actor_add_baz (FooActor *foo_actor,
|
||||
|
||||
foo_actor->baz = baz_actor;
|
||||
|
||||
/* this will cause the initial floating reference to disappear,
|
||||
* and add a new reference on baz_actor. foo_actor has now taken
|
||||
* ownership of baz_actor
|
||||
/* 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).
|
||||
*/
|
||||
clutter_actor_set_parent (CLUTTER_ACTOR (baz_actor),
|
||||
CLUTTER_ACTOR (foo_actor));
|
||||
|
||||
/* emit a signal and notification */
|
||||
g_signal_emit (foo_actor, foo_actor_signals[BAZ_CHANGED], 0, baz_actor);
|
||||
g_object_notify (G_OBJECT (foo_actor), "baz");
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
@ -228,43 +654,56 @@ foo_actor_add_baz (FooActor *foo_actor,
|
||||
<varlistentry>
|
||||
<term>ClutterContainer::add</term>
|
||||
<listitem>
|
||||
<para></para>
|
||||
<para>The container actor should hold a pointer to the passed
|
||||
#ClutterActor, call clutter_actor_set_parent() on it and then
|
||||
emit the #ClutterContainer::actor-added signal to notify
|
||||
handlers of the newly added actor.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>ClutterContainer::remove</term>
|
||||
<listitem>
|
||||
<para></para>
|
||||
<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>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>ClutterContainer::foreach</term>
|
||||
<listitem>
|
||||
<para></para>
|
||||
<para>The container should invoke the callback on every
|
||||
child it is holding.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>ClutterContainer::raise</term>
|
||||
<listitem>
|
||||
<para></para>
|
||||
<para>The container should move the passed child on top
|
||||
of the given sibling, or on top of the paint stack in
|
||||
case the sibling is NULL.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>ClutterContainer::lower</term>
|
||||
<listitem>
|
||||
<para></para>
|
||||
<para>The container should move the passed child below
|
||||
the given sibling, or on the bottom of the paint stack
|
||||
in case the sibling is NULL.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>ClutterContainer::sort_depth_order</term>
|
||||
<listitem>
|
||||
<para></para>
|
||||
<para>The container should sort the paint stack depending
|
||||
on the relative depths of each child.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
</refsect1> <!-- implementing-clutter-container -->
|
||||
|
||||
</chapter>
|
||||
|
Loading…
Reference in New Issue
Block a user