docs: Complete composite actor recipe

Add some extra detail to the Discussion section of the
composite actor recipe, concentrating on the pros and
cons of this approach.

Also explain more about the Clutter parts of the implementation.

Also general tidy up of language and style.
This commit is contained in:
Elliot Smith 2011-01-31 10:53:52 +00:00
parent 238fd52c4b
commit 08f5dc08d0

View File

@ -44,9 +44,10 @@
<section id="actors-composite-problem"> <section id="actors-composite-problem">
<title>Problem</title> <title>Problem</title>
<para>You want to implement your own <type>ClutterActor</type>. For <para>You want to implement your own <type>ClutterActor</type>;
example, a widget (button, scrollbar, checkbox etc.) composed of for example, a very simple button widget. But you want to base it
several Clutter primitives.</para> on existing Clutter primitives (rectangles, text) to minimise
the work required.</para>
</section> </section>
<section id="actors-composite-solution"> <section id="actors-composite-solution">
@ -54,19 +55,25 @@
<para>Implement a custom actor composed from a <type>ClutterBox</type> <para>Implement a custom actor composed from a <type>ClutterBox</type>
packed with other <type>ClutterActors</type>. The custom actor packed with other <type>ClutterActors</type>. The custom actor
effectively provides a facade for these internal actors, simplifying provides a facade over these internal actors, simplifying
access to their properties and behavior.</para> access to their properties and behavior.</para>
<para>In this recipe, we make the simplest possible button widget <para>In this recipe, we subclass <type>ClutterActor</type> using this
(<type>CbButton</type>) to demonstrate the basic principles of approach to create a very simple button widget, <type>CbButton</type>.
implementing a <type>ClutterActor</type>. It is not a complete It is not a complete button implementation: see
button implementation: see <ulink url="http://git.clutter-project.org/mx/tree/mx/mx-button.c">
<ulink url="http://git.clutter-project.org/mx/tree/mx/mx-button.c"><type>MxButton</type></ulink> <type>MxButton</type></ulink> for a more comprehensive example
for a more (and the basis for this recipe). But this recipe does cover the most
comprehensive example (and the basis for this recipe). But important parts of a <type>ClutterActor</type> implementation,
it does cover the most important parts of a <type>ClutterActor</type> as well some useful <type>GObject</type>-related code.</para>
implementation, as well some useful <type>GObject</type>-related
code.</para> <tip>
<para>As Clutter is a GObject-based library, it relies
heavily on GObject concepts and idioms. If you are unfamiliar with
GObject, please read
<ulink url="http://library.gnome.org/devel/gobject/unstable/">the GObject
Reference Manual</ulink> before proceeding.</para>
</tip>
<para>The code for this solution is structured like standard GObject <para>The code for this solution is structured like standard GObject
C library code:</para> C library code:</para>
@ -88,13 +95,19 @@
<para>Each of these files is described in more detail below.</para> <para>Each of these files is described in more detail below.</para>
<tip> <note>
<para>As Clutter is a GObject-based library, it relies <para>In a more realistic context, <type>CbButton</type> would
heavily on GObject concepts and idioms. If you are unfamiliar with GObject, have some build infrastructure (for example, autotooling)
please read so it could be compiled, installed, and reused in a variety of
<ulink url="http://library.gnome.org/devel/gobject/unstable/">the GObject applications. However, for the purposes of cookbook examples,
Reference Manual</ulink> before proceeding.</para> these issues are ignored here.</para>
</tip>
<para>If you <emphasis>are</emphasis> planning on building
your own widgets using Clutter as part of an application, or
to create your own library, the
<ulink url="http://git.clutter-project.org/mx/">Mx toolkit</ulink>
provides an excellent example of how to autotool your project.</para>
</note>
<example id="actors-composite-cb-button-h"> <example id="actors-composite-cb-button-h">
<title><filename>cb-button.h</filename>: header file</title> <title><filename>cb-button.h</filename>: header file</title>
@ -115,10 +128,12 @@
and GObject implementation</title> and GObject implementation</title>
<para>This is the main C code file which implements both <para>This is the main C code file which implements both
the GObject and Clutter parts of <type>CbButton</type>. the GObject and Clutter elements of <type>CbButton</type>.
The example below is commented liberally, and gives some samples The example below is liberally commented, and also gives some samples
of gtk-doc annotations to generate API docs for the of annotations to generate
widget. The <link linkend="actors-composite-discussion">discussion <ulink url="http://www.gtk.org/gtk-doc/">gtk-docs</ulink> for the
widget. The
<link linkend="actors-composite-discussion-clutter-virtual-functions">discussion
section</link> comments more specifically about the Clutter-specific section</link> comments more specifically about the Clutter-specific
parts of it.</para> parts of it.</para>
@ -151,40 +166,145 @@
<section id="actors-composite-discussion"> <section id="actors-composite-discussion">
<title>Discussion</title> <title>Discussion</title>
<para>Explain about GObject a bit???</para> <para>The actor implemented here is based on
simple composition: bundling several actors together and wrapping
<para>Note size requisition in the example application???</para> their behavior and properties. In the example here, we make use of a
<para>The actor implemented here is put together through
simple composition. This has the advantage of simplifying the
code for the subclass: we can just wrap a facade round
existing Clutter classes, rather than writing code to implement
everything ourselves. In the example here, we make use of a
<type>ClutterLayoutManager</type> to handle positioning of <type>ClutterLayoutManager</type> to handle positioning of
the <type>ClutterText</type>; we change the background color of the <type>ClutterText</type>; we change the background color of
the button by changing the color of the the button by changing the color of the
<type>ClutterBox</type>; we use a <type>ClutterClickAction</type> <type>ClutterBox</type>; and we use a <type>ClutterClickAction</type>
to simplify implementation of a click signal.</para> to simplify implementation of a click signal.</para>
<para>On the other hand, it puts some constraints on the outline of <para>You may find that this approach is appropriate if you need
the actor: it makes it harder to use a custom outline, for to implement a simple rectangular actor. However, it puts some
example, to round the corners of the button. This approach may constraints on the outline of the actor, making it harder to
not be suitable where you need to do a lot of custom animation use a custom outline: for example, a rectangle with rounded corners
and drawing.</para> or a shape which can't be approximated by a rectangle. Such cases
require both <function>pick()</function> and <function>paint()</function>
implementations using Cogl (or similar): see
<link linkend="actors-non-rectangular">this recipe</link>
for more details.</para>
<para>This isn't the whole story: if you aren't using this simple <para>The composition approach may also be inappropriate where
composition approach, you may need to do more: see the notes in you need to do a lot of custom animation and drawing; and it is
the Clutter reference manual. Also, if you're implementing a likely to be inappropriate for implementing a container
container, you'll need to do more.</para> actor. See the notes on implementing a new actor in the Clutter
reference manual for more details of what may be required
in these cases.</para>
<para>use Mx for inspiration???</para> <section id="actors-composite-discussion-clutter-virtual-functions">
<title>Implementing <type>ClutterActor</type> virtual functions</title>
<para>GObject implementation parts vs. Clutter implementation???</para> <para>While most of the <type>CbButton</type> implementation
revolves around GObject, there are some elements of it
specific to Clutter. Due to the simplicity of
the <type>CbButton</type> actor, the implementation of
these functions is fairly trivial, as explained below:</para>
<para>something about how the ClutterBox is parented onto the <itemizedlist>
ClutterActor subclass we are implementing; we just create
an allocation for the ClutterBox based on the allocation of its <listitem>
parent???</para>
<formalpara>
<title>Size requisition:
<function>cb_button_get_preferred_height()</function>
and <function>cb_button_get_preferred_width()</function></title>
<para>During the size requisition phase, Clutter asks each
actor the minimum size it should be to remain useful,
and the maximum size it would be if unconstrained. This is done
by calling the <function>get_preferred_height()</function>
and <function>get_preferred_width()</function> functions
on each actor in turn.</para>
</formalpara>
<para>If an actor will only ever be explictly sized
(via <function>clutter_actor_set_size()</function>,
<function>clutter_actor_set_height()</function> and/or
<function>clutter_actor_set_width()</function>),
there is no need to implement the <function>get_preferred_*()</function>
functions. (Some actors like <type>ClutterRectangle</type>
work this way and require explicit sizing.)</para>
<para>However, if an actor's size should be negotiated during
the size requisition phase, you can implement these functions,
using the size of the child actors as a basis for the
preferred height and width. In the case of
<type>CbButton</type>, a preferred height and width can be
computed; these are based on the height and width of
the child <type>ClutterBox</type>, plus 20 pixels on each
axis. Because the size of the box is itself dependent on
the size of the <type>ClutterText</type> inside it, the net
result is that the <type>CbButton</type> preferred size
is the size of the text actor inside it, plus 20 pixels on each
axis.</para>
</listitem>
<listitem>
<formalpara>
<title>Allocation:
<function>cb_button_allocate()</function></title>
<para>The requests gathered during size requisition
are then negotiated by Clutter, each actor
receiving some allocation of the available space. At the
end of this process, each actor is allocated a
<emphasis>box</emphasis>, representing the space available
to it on the stage.</para>
</formalpara>
<para>An actor implementation is responsible for distributing
space from its allocation box to its children as it sees
fit. In the case of <type>CbButton</type>, there is only a single
<type>ClutterBox</type> actor which needs allocation;
<function>cb_button_allocate()</function> therefore
allocates all of the button's space to its child
<type>ClutterBox</type>.</para>
</listitem>
<listitem>
<formalpara>
<title>Painting and picking:
<function>cb_button_paint()</function></title>
<para>Clutter works its way through the actors on the
stage, following the actor hierarchy (top level
actors directly inside the stage first);
<function>clutter_actor_paint()</function>
is called on each actor. This, in turn, calls the actor's
<function>paint()</function> implementation. If the actor
is a container, it may iterate over its children,
calling <function>paint()</function> on each; the children
may call <function>paint()</function> on their children...;
and so on, until the leaves of the actor hierarchy are
reached.</para>
</formalpara>
<para>As our actor consists of a single <type>ClutterBox</type>
child, its <function>paint()</function> implementation simply
has to retrieve the reference to that <type>ClutterBox</type>
(from its private structure) and call
<function>clutter_actor_paint()</function>
on it. Painting of the <type>ClutterBox's</type> child
(the <type>ClutterText</type>) is handled by the
<type>ClutterBox</type>.</para>
<para>In cases where an actor is non-rectangular, you also
need to implement a <function>pick()</function> function.
(This is used to determine which actor was the recipient of
an event occurring within the stage.) However, because
the actor in this recipe is a simple rectangle, there is no
need to implement <function>pick()</function>.</para>
</listitem>
</itemizedlist>
</section>
</section> </section>