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