<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">

<chapter id="actors"
         xmlns:xi="http://www.w3.org/2003/XInclude">
  <title>Actors</title>

  <epigraph>
    <attribution>Edmon Gween, actor, on his deathbed</attribution>
    <para>An actor's a guy who if you ain't talkin' about him, ain't
    listening.</para>
  </epigraph>

  <section id="actors-introduction">
    <title>Introduction</title>

    <para>When building a User Interface with Clutter, the visible part
    of the UI &mdash; that is, what is displayed on the screen &mdash; is
    commonly referred to as "the scene graph". Like every graph, a scene
    graph is composed by nodes.</para>

    <para>Every node on the Clutter scene graph is an
    <emphasis>actor</emphasis>. Every actor has a single relationship
    with the others: it can be the parent of another actor, or a child of
    another actor.</para>

    <note><para>The stage is an actor that can have children but cannot have
    any parent.</para></note>

    <para>Actors have different attributes: a position, a size, a
    scale factor, a rotation angle on each axis (relative to a specific
    center on the normal plane for that axis), an opacity factor.</para>

    <para>The scene graph is not fixed: it can be changed, not only
    by adding or removing actors, but also by changing the parent-child
    relationship: it is possible, for instance, to move an entire
    section of the scene graph from one parent actor to another.</para>

  </section>

  <section id="actors-composite">
    <title>Implementing a simple custom actor</title>

    <section id="actors-composite-problem">
      <title>Problem</title>

      <para>You want to implement your own <type>ClutterActor</type>;
      for example, a very simple button widget. But you want to base it
      on existing Clutter primitives (rectangles, text) to minimise
      the work required.</para>
    </section>

    <section id="actors-composite-solution">
      <title>Solution</title>

      <para>Implement a custom actor composed from a <type>ClutterBox</type>
      packed with other <type>ClutterActors</type>. The custom actor
      provides a facade over these internal actors, simplifying
      access to their properties and behavior.</para>

      <para>In this recipe, we subclass <type>ClutterActor</type> using this
      approach to create a very simple button widget, <type>CbButton</type>.
      It is not a complete button implementation: see
      <ulink url="http://git.clutter-project.org/mx/tree/mx/mx-button.c">
      <type>MxButton</type></ulink> for a more comprehensive example
      (and the basis for this recipe). But this recipe does cover the most
      important parts of a <type>ClutterActor</type> 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. You might also find
        <ulink url="http://diuf.unifr.ch/pai/wiki/doku.php/research:projects:gobject_tutorial">this
        tutorial</ulink> a useful introduction.</para>
      </tip>

      <para>The code for this solution is structured like standard GObject
      C library code:</para>

      <itemizedlist>
        <listitem>
          <para>The header file <filename>cb-button.h</filename>
          declares the class' public API (function prototypes, macros,
          structs).</para>
        </listitem>
        <listitem>
          <para>The code file <filename>cb-button.c</filename>
          contains the class implementation.</para>
        </listitem>
      </itemizedlist>

      <para>One more example file, <filename>actors-composite-main.c</filename>,
      shows how to use <type>CbButton</type> in an application.</para>

      <para>Each of these files is described in more detail below.</para>

      <note>
        <para>In a more realistic context, <type>CbButton</type> 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.</para>

        <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">
        <title><filename>cb-button.h</filename>: header file</title>

        <para>This defines the public API for the class, including
        GObject type macros, class and object structures, and
        function prototypes.</para>

        <programlisting>
<xi:include href="examples/cb-button.h" parse="text">
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

      <example id="actors-composite-cb-button-c">
        <title><filename>cb-button.c</filename>: <type>ClutterActor</type>
        and GObject implementation</title>

        <para>This is the main C code file which implements both
        the GObject and Clutter elements of <type>CbButton</type>.
        The example below is liberally commented, and also gives some samples
        of annotations to generate
        <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
        parts of it.</para>

        <programlisting>
<xi:include href="examples/cb-button.c" parse="text">
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

      <example id="actors-composite-actors-composite-main-c">
        <title><filename>actors-composite-main.c</filename>: trivial
        application demonstrating usage of <type>CbButton</type></title>

        <para>Note how any of the <type>ClutterActor</type>
        functions (like <function>clutter_actor_set_size()</function>
        and <function>clutter_actor_add_constraint()</function>) can
        be applied to instances of our <type>ClutterActor</type>
        implementation.</para>

        <programlisting>
<xi:include href="examples/actors-composite-main.c" parse="text">
<xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

    </section>

    <section id="actors-composite-discussion">
      <title>Discussion</title>

      <para>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
      <type>ClutterLayoutManager</type> to handle positioning of
      the <type>ClutterText</type>; we change the background color of
      the button by changing the color of the
      <type>ClutterBox</type>; and we use a <type>ClutterClickAction</type>
      to simplify implementation of a click signal.</para>

      <para>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 <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>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.</para>

      <section id="actors-composite-discussion-clutter-virtual-functions">
        <title>Implementing <type>ClutterActor</type> virtual functions</title>

        <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>

        <itemizedlist>

          <listitem>

            <formalpara>
              <title>Object destruction:
              <function>cb_button_destroy()</function></title>

              <para><type>ClutterActor</type> subclasses based
              on composition should implement the <function>destroy()</function>
              virtual function. This is called on an actor when its
              container is destroyed to clean up the resources
              allocated to the actor; it also emits a
              <emphasis>destroy</emphasis> signal which other code can
              hook onto.</para>
            </formalpara>

            <para>In the case of <type>CbButton</type>, the
            <function>destroy()</function> implementation calls
            <function>clutter_actor_destroy()</function> on the child
            <type>ClutterBox</type>, then sets that child to
            <constant>NULL</constant>. Finally, it checks for a
            <function>destroy()</function> implementation on the parent
            class, then calls it if one exists.</para>

          </listitem>

          <listitem>

            <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>

  <section id="actors-allocation-notify">
    <title>Knowing when an actor's position or size changes</title>

    <section>
      <title>Problem</title>

      <para>You want to know when the position or the size, or
      both, of an actor change, for instance to update an unrelated
      actor or some internal state.</para>
    </section>

    <section>
      <title>Solution</title>

      <para>You can use the <emphasis>notify</emphasis> signal,
      detailed with the coordinate or the dimension you want
      to know has changed:</para>

      <informalexample>
        <programlisting>
g_signal_connect (actor, "notify::x",
                  G_CALLBACK (on_x_changed),
                  NULL);
g_signal_connect (actor, "notify::height",
                  G_CALLBACK (on_height_changed),
                  NULL);
g_signal_connect (actor, "notify::depth",
                  G_CALLBACK (on_depth_changed),
                  NULL);
        </programlisting>
      </informalexample>

      <para>If you want to know if any of the coordinates or dimensions of
      an actor have been changed, except for depth, you can use the
      <emphasis>allocation-changed</emphasis> signal:</para>

      <informalexample>
        <programlisting>
g_signal_connect (actor, "allocation-changed",
                  G_CALLBACK (on_allocation_changed),
                  NULL);
        </programlisting>
      </informalexample>

      <para>The signature for the handler of the "notify" signal is:</para>

      <informalexample>
        <programlisting>
void
on_notify (GObject    *gobject,
           GParamSpec *pspec,
           gpointer    user_data);
        </programlisting>
      </informalexample>

      <para>While the signature for the handler of the "allocation-changed"
      signal is:</para>

      <informalexample>
        <programlisting>
void
on_allocation_changed (ClutterActor           *actor,
                       const ClutterActorBox  *allocation,
                       ClutterAllocationFlags  flags,
                       gpointer                user_data);
        </programlisting>
      </informalexample>

    </section>

    <section>
      <title>Discussion</title>

      <para>Any change the position and size of an actor will cause a
      change in the allocation of the actor itself. This will update the
      values of the <property>x</property>, <property>y</property>,
      <property>width</property> and <property>height</property>
      properties as well.</para>

      <para>The first technique allows a greater deal of granularity,
      allowing you to know what exactly changed. Inside the callback
      for the signal you can query the value of the property:</para>

      <informalexample>
        <programlisting>
void
on_x_changed (GObject    *gobject,
              GParamSpec *pspec,
              gpointer    user_data)
{
  gint x_value = 0;

  /* Round the X coordinate to the nearest pixel */
  x_value = floorf (clutter_actor_get_x (CLUTTER_ACTOR (gobject))) + 0.5;

  g_print ("The new X coordinate is '%d' pixels\n", x_value);
}
        </programlisting>
      </informalexample>

      <para>The second technique is more indicated if you want to
      get notification that any of the positional or dimensional
      attributes changed, except for the depth:</para>

      <informalexample>
        <programlisting>
void
on_allocation_changed (ClutterActor           *actor,
                       const ClutterActorBox  *allocation,
                       ClutterAllocationFlags  flags,
                       gpointer                user_data)
{
  g_print ("The bounding box is now: (%.2f, %.2f) (%.2f x %.2f)\n",
           clutter_actor_box_get_x (allocation),
           clutter_actor_box_get_y (allocation),
           clutter_actor_box_get_width (allocation),
           clutter_actor_box_get_height (allocation));
}
        </programlisting>
      </informalexample>

      <para>All actors will update these properties when their size
      or position change.</para>

      <para>Note that the stage, on the other hand, will not notify on
      position changes, so it is not possible to use the
      <property>x</property> and <property>y</property>
      properties to know that the platform-specific window embedding the
      stage has been moved &mdash; if the platform supports a windowing
      system. In order to achieve that you will have to use backend-specific
      API to extract the surface used by the stage and then platform-specific
      API to retrieve its coordinates.</para>

    </section>

  </section>

  <section id="actors-paint-wrappers">
    <title>Overriding the paint sequence</title>

    <section>
      <title>Problem</title>

      <para>You want to override the way an actor paints itself
      without creating a subclass.</para>
    </section>

    <section>
      <title>Solution</title>

      <para>You can use the <emphasis>paint</emphasis> signal to
      invoke a callback that will be executed before the actor's
      paint implementation:</para>

      <informalexample>
        <programlisting>
g_signal_connect (actor, "paint", G_CALLBACK (on_paint), NULL);
        </programlisting>
      </informalexample>

      <para>You can paint something after the actor's paint implementation
      by using the <function>g_signal_connect_after()</function> function
      instead of <function>g_signal_connect()</function>:</para>

      <informalexample>
        <programlisting>
g_signal_connect_after (actor, "paint", G_CALLBACK (on_paint_after), NULL);
        </programlisting>
      </informalexample>

      <para>The signature for the handler of the "paint" signal is:</para>

      <informalexample>
        <programlisting>
void on_paint (ClutterActor *actor, gpointer user_data);
        </programlisting>
      </informalexample>

    </section>

    <section>
      <title>Discussion</title>

      <para>The paint cycle in Clutter works its way recursively from the
      stage through every child.</para>

      <para>Whenever an Actor is going to be painted it will be positioned in
      a new frame of reference according to the list of transformations
      (scaling, rotation and additional translations). After that, the "paint"
      signal will be emitted.</para>

      <para>The "paint" signal is defined as <emphasis>run-last</emphasis>,
      that is the signal handlers connected to it using
      <function>g_signal_connetc()</function> will be called first; then the
      default handler defined by the Actor's sub-class will be called;
      finally, all the signal handlers connected to the signal using
      <function>g_signal_connect_after()</function> will be called.</para>

      <para>This allows pre- and post-default paint handlers, and it also
      allows completely overriding the way an Actor draws itself by default;
      for instance:</para>

      <informalexample>
        <programlisting>
void
on_paint (ClutterActor *actor)
{
  do_my_paint (actor);

  g_signal_stop_emission_by_name (actor, "paint");
}
        </programlisting>
      </informalexample>

      <para>The code above will prevent the default paint implementation of
      the actor from running.</para>
    </section>

  </section>

  <section id="actors-opacity">
    <title>Making an actor transparent by changing its opacity</title>

    <section>
      <title>Problem</title>

      <para>You want an actor to be transparent so that other
      actors are visible through it.</para>
    </section>

    <section>
      <title>Solution</title>

      <para>Change the actor's <emphasis>opacity</emphasis> so that
      it is partially (or even fully) transparent:</para>

      <informalexample>
        <programlisting>
/* 25% transparency */
clutter_actor_set_opacity (actor, 191);

/* 50% transparency */
clutter_actor_set_opacity (actor, 122);

/* completely transparent */
clutter_actor_set_opacity (actor, 0);
        </programlisting>
      </informalexample>

      <para>Any actor covered or overlapped by the transparent actor
      should be visible through it; the Discussion section gives
      some examples of how visible you can expect the covered or
      overlapped actor to be.</para>

    </section>

    <section>
      <title>Discussion</title>

      <para>Opacity is a property of every <type>ClutterActor</type>.
      It is a float on a scale from 0 (invisible) to 255 (completely
      opaque). Actors with <code>0 &lt; opacity &lt; 255</code> will
      have a varying amount of solidity on the stage, so other actors
      may be visible through them.</para>

      <para>For example, below are 4 yellow rectangles overlapping
      a white rectangle on a blue stage:</para>

      <screenshot>
        <mediaobject>
          <imageobject>
            <imagedata format="PNG"
                       fileref="images/actors-opacity.png" />
          </imageobject>
          <alt>
            <para>The effect of different opacities levels on
            an actor's appearance</para>
          </alt>
        </mediaobject>
      </screenshot>

      <para>The rectangles have the following opacities:</para>

      <itemizedlist>
        <listitem>
          <para>top-left: <code>255</code> (0% transparency)</para>
        </listitem>
        <listitem>
          <para>top-right: <code>191</code> (25% transparency)</para>
        </listitem>
        <listitem>
          <para>bottom-right: <code>122</code> (50% transparency)</para>
        </listitem>
        <listitem>
          <para>bottom-left: <code>61</code> (75% transparency)</para>
        </listitem>
      </itemizedlist>

      <para>Notice how both the stage and the white rectangle are
      visible through the yellow rectangles.</para>

      <para>As opacity is a property of every actor, it can
      be animated like any other GObject property, using any of
      the approaches in the animation API.</para>

      <para>The following sections cover some other considerations
      when working with actor opacity.</para>

      <section>
        <title>Container and color opacity</title>

        <para>If a container has its opacity set, any children of the
        container have their opacity combined with their parent's opacity.
        For example, if a parent has an opacity of <code>122</code>
        (50% transparent) and the child also has an opacity of
        <code>122</code>, the child's <emphasis>effective</emphasis>
        opacity is 25% (<code>opacity = 61</code>, and it is
        75% transparent).</para>

        <para>To demonstrate the visual effect of this, here are
        three rectangles with the same color but different opacity settings,
        inside parents which also have different opacity settings:</para>

        <screenshot>
          <mediaobject>
            <imageobject>
              <imagedata format="PNG"
                         fileref="images/actors-opacity-container-affects-opacity.png" />
            </imageobject>
            <alt>
              <para>How a container's opacity affects the opacity of
              its children</para>
            </alt>
          </mediaobject>
        </screenshot>

        <itemizedlist>
          <listitem>
            <para>The left-hand rectangle has <code>opacity = 255</code>
            and is in a <type>ClutterGroup</type> with
            <code>opacity = 255</code>. This means it is fully opaque.</para>
          </listitem>
          <listitem>
            <para>The middle rectangle has <code>opacity = 255</code>
            and is in a <type>ClutterGroup</type> with
            <code>opacity = 122</code>. Notice that the parent opacity
            makes the rectangle appear darker, as the stage colour is showing
            through from behind.</para>
          </listitem>
          <listitem>
            <para>The right-hand rectangle has <code>opacity = 122</code>
            and is in a <type>ClutterGroup</type> with
            <code>opacity = 122</code>. Notice that the rectangle appears
            to be even darker, as the stage colour is showing
            through both the rectangle and its parent.</para>
          </listitem>
        </itemizedlist>

        <para>Similarly, <type>ClutterColor</type> also contains an
        <varname>alpha</varname> property which governs the transparency
        of the color. Where an actor can have a color set (e.g.
        <type>ClutterRectangle</type>) the alpha value of the color also
        affects the transparency of the actor, for example:</para>

        <informalexample>
          <programlisting>
<![CDATA[
/* color with 50% transparency */
ClutterColor half_transparent_color = { 255, 0, 0, 122 };

ClutterRectangle *actor = clutter_rectangle_new ();

/* set actor's transparency to 50% */
clutter_actor_set_opacity (actor, 122);

/* rectangle will be 25% opaque/75% transparent */
clutter_rectangle_set_color (CLUTTER_RECTANGLE (actor),
                           &half_transparent_color);
]]>
          </programlisting>
        </informalexample>

      </section>

      <section>
        <title>Depth and depth order</title>

        <para>Each actor has two more aspects which affect its
        apparent opacity:</para>

        <itemizedlist>
          <listitem>
            <para>An actor's <emphasis>depth</emphasis> can have an
            effect if the stage has fog (a depth cueing effect) turned on.
            As an actor's depth increases, the actor apparently "recedes" from
            view and gradually blends into the colour of the stage. This
            produces an effect similar to making the actor transparent.
            See the <type>ClutterStage</type> documentation for
            more details about fog.</para>

            <para>Depth also needs to be considered if you want
            one actor to be visible through another: the actor you want
            to see through a transparent actor must be "deeper" than (or at
            the same depth as) the transparent actor.</para>
          </listitem>
          <listitem>
            <para>The <emphasis>depth order</emphasis> governs how
            actors within a <type>ClutterContainer</type> implementation
            are placed with respect to each other.</para>

            <note>
              <para>Depth ordering is not the same thing as depth: depth
              ordering records relationships between actors at the same
              depth.</para>
            </note>

            <para>If you have two overlapping actors <code>actorA</code> and
            <code>actorB</code> in a container, and you want <code>actorA</code>
            (opaque) to be visible through <code>actorB</code> (transparent),
            you should ensure that <code>actorB</code> is "above" <code>actorA</code>
            in the depth ordering. You could do this as follows:</para>

            <informalexample>
              <programlisting>
/*
* raise actorB so it is above actorA in the depth order;
* NB actorA and actorB both need to be in the same container
* for this to work
*/
clutter_actor_raise (actorB, actorA);
              </programlisting>
            </informalexample>

            <para><function>clutter_actor_raise()</function>,
            <function>clutter_actor_lower()</function> and related
            <type>ClutterActor</type> functions set
            depth ordering on actors; see also <type>ClutterContainer</type>'s
            <function>clutter_container_raise_child()</function> and
            <function>clutter_container_lower_child()</function>
            functions.</para>
          </listitem>
        </itemizedlist>

      </section>

    </section>

  </section>

  <section id="actors-non-rectangular">
    <title>Creating an actor with a non-rectangular shape</title>

    <section>
      <title>Problem</title>

      <para>You want to create a <type>ClutterActor</type> subclass,
      but don't want it to be rectangular; for example, you want a
      star-shaped actor.</para>
    </section>

    <section>
      <title>Solution</title>

      <para>Use Cogl primitives to draw the actor.</para>

      <para>Below is an example of the pick and paint implementations for a
      star-shaped <type>StarActor</type> class (an extension of
      <type>ClutterActor</type>).</para>

      <para>Like <type>ClutterRectangle</type>, it has a private
      struct internally, which contains a <type>ClutterColor</type>
      denoting the color it should be painted. This is used to set the Cogl
      source color.</para>

      <informalexample>
        <programlisting>
<![CDATA[
static void
star_actor_paint (ClutterActor *actor)
{
  ClutterActorBox allocation = { 0, };
  gfloat width, height;
  guint tmp_alpha;

  /* priv is a private internal struct */
  ClutterColor color = STAR_ACTOR (actor)->priv->color;

  clutter_actor_get_allocation_box (actor, &allocation);
  clutter_actor_box_get_size (&allocation, &width, &height);

  tmp_alpha = clutter_actor_get_paint_opacity (actor)
                * color.alpha
                / 255;

  cogl_path_new ();

  cogl_set_source_color4ub (color.red,
                            color.green,
                            color.blue,
                            tmp_alpha);

  /* create and store a path describing a star */
  cogl_path_move_to (width * 0.5, 0);
  cogl_path_line_to (width, height * 0.75);
  cogl_path_line_to (0, height * 0.75);
  cogl_path_move_to (width * 0.5, height);
  cogl_path_line_to (0, height * 0.25);
  cogl_path_line_to (width, height * 0.25);
  cogl_path_line_to (width * 0.5, height);

  cogl_path_fill ();
}

static void
star_actor_pick (ClutterActor *actor,
                 const ClutterColor *pick_color)
{
  if (!clutter_actor_should_pick_paint (actor))
    return;

  ClutterActorBox allocation = { 0, };
  gfloat width, height;

  clutter_actor_get_allocation_box (actor, &allocation);
  clutter_actor_box_get_size (&allocation, &width, &height);

  cogl_path_new ();

  cogl_set_source_color4ub (pick_color->red,
                            pick_color->green,
                            pick_color->blue,
                            pick_color->alpha);

  /* create and store a path describing a star */
  cogl_path_move_to (width * 0.5, 0);
  cogl_path_line_to (width, height * 0.75);
  cogl_path_line_to (0, height * 0.75);
  cogl_path_move_to (width * 0.5, height);
  cogl_path_line_to (0, height * 0.25);
  cogl_path_line_to (width, height * 0.25);
  cogl_path_line_to (width * 0.5, height);

  cogl_path_fill ();
}
]]>
        </programlisting>
      </informalexample>

      <para>If you need more information about how to implement your own
      <type>ClutterActor</type>, see the Clutter reference
      manual.</para>

      <para>Note that the code in these two functions is virtually identical:
      the Discussion section suggests how to remove this redundancy.</para>
    </section>

    <section>
      <title>Discussion</title>

      <para>The above is one approach to creating a non-rectangular
      actor. But it's also possible to get a similar effect by
      subclassing an existing actor (like <type>ClutterRectangle</type>)
      and giving it a non-rectangular appearance. You could do this by
      making the underlying rectangle transparent and then drawing on
      top of it (e.g. using Cairo or Cogl).</para>

      <para>However, if you then made such an actor reactive, events
      like mouse button presses would be triggered from anywhere on
      the underlying rectangle. This is true even if the visible part
      of the actor only partially fills the rectangle (underneath, it's
      still a rectangle).</para>

      <para>The advantage of using Cogl paths is that the reactive area
      of the actor is defined by the Cogl path. So if you have a
      star-shaped actor, only clicks (or other events) directly on the
      star will have any effect on it.</para>

      <section>
        <title>Cogl path coordinates</title>

        <para>In the example shown, <function>cogl_path_move_to()</function>
        and <function>cogl_path_line_to()</function> are used. These
        take absolute <code>x</code> and <code>y</code> coordinates as
        arguments, relative to the GL 'modelview' transform matrix; in
        the case of an actor's <function>paint</function> implementation,
        relative to the bounding box for the actor. So if an actor has
        width and height of 50 pixels, and you used
        <function>cogl_move_to (25, 25)</function> in its
        <function>paint</function> implementation, the "pen"
        moves to the centre of the actor, regardless of where the actor
        is positioned on the stage. Similarly, using
        <function>cogl_path_line_to()</function> creates a line segment
        from the current pen position to the absolute coordinates
        (<code>x</code>, <code>y</code>) specified.</para>

        <para>The Cogl API also provides various "rel" variants of the path
        functions (e.g. <function>cogl_path_rel_line_to()</function>), which
        create path segments relative to the current pen position (i.e.
        <code>pen_x + x</code>, <code>pen_y + y</code>).</para>

        <para>It's important to note that the path isn't drawn until you
        call <function>cogl_path_stroke()</function> (to draw the path segments)
        or <function>cogl_path_fill()</function> (to fill the area enclosed by
        the path). The path is cleared once it's been drawn.
        Using the <function>*_preserve</function> variants of these functions draws
        the path and retains it (so it could be drawn again).</para>

      </section>

      <section>
        <title>Other Cogl primitives</title>

        <para>Note that the Cogl primitives API provides other types of path
        segment beyond straight lines that we didn't use here, including:</para>

        <itemizedlist>
          <listitem>
            <para>Bezier curves (<function>cogl_path_curve_to()</function>)</para>
          </listitem>
          <listitem>
            <para>Arcs (<function>cogl_path_arc()</function>)</para>
          </listitem>
          <listitem>
            <para>Polygons (<function>cogl_path_polygon()</function>)</para>
          </listitem>
          <listitem>
            <para>Rectangles (<function>cogl_path_rectangle()</function>)</para>
          </listitem>
          <listitem>
            <para>Rectangles with rounded corners
            (<function>cogl_path_round_rectangle()</function>)</para>
          </listitem>
          <listitem>
            <para>Ellipses (<function>cogl_path_ellipse()</function>)</para>
          </listitem>
        </itemizedlist>

        <para>If you need more flexibility than is available in the Cogl path
        API, you can make direct use of the <type>CoglVertexBuffer</type>
        API instead. This is a lower-level API, but could potentially
        be used to draw more complex shapes.</para>
      </section>

      <section>
        <title>Using <type>ClutterPath</type> to store the path</title>

        <para>The disadvantage of the code above is that the paths are stored in two
        places: once for <function>pick</function>, and once for
        <function>paint</function>. It would make sense to store the
        path in one place and reference it from both of these functions to
        prevent duplication.</para>

        <para>Clutter provides a <type>ClutterPath</type> API for storing
        generic path descriptions. It can be used to describe paths
        which translate to Cogl or Cairo paths, and can also be used to
        describe animation paths.</para>

        <para>We can use a <type>ClutterPath</type> instance stored
        inside the actor to define the path for <function>pick</function> and
        <function>paint</function>; then, inside those functions, we
        translate the <type>ClutterPath</type> into Cogl path function calls
        (NB <type>ClutterPath</type> is effectively a declarative method
        for defining a path, while the Cogl path API is imperative).</para>

        <para>First we add a <varname>path</varname> member to the private
        struct for the <type>StarActor</type> class (using standard
        GObject mechanisms). The <function>init</function> implementation for
        <type>StarActor</type> creates an empty path:</para>

        <informalexample>
          <programlisting>
static void
star_actor_init (StarActor *self)
{
  self->priv = STAR_ACTOR_GET_PRIVATE (self);

  self->priv->path = clutter_path_new ();

  clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
}
          </programlisting>
        </informalexample>

        <para>One consideration is that the path coordinates need to
        fit inside the actor's bounding box. So as the actor's allocation
        changes, <varname>path</varname> also needs to change. We can do this
        by implementing <function>allocate</function> for the
        <type>StarActor</type> class:</para>

        <informalexample>
          <programlisting>
<![CDATA[
static void
star_actor_allocate (ClutterActor           *actor,
                     const ClutterActorBox  *box,
                     ClutterAllocationFlags  flags)
{
  ClutterPath *path = STAR_ACTOR (actor)->priv->path;
  gfloat width, height;

  clutter_actor_box_get_size (box, &width, &height);

  /* create and store a path describing a star */
  clutter_path_clear (path);

  clutter_path_add_move_to (path, width * 0.5, 0);
  clutter_path_add_line_to (path, width, height * 0.75);
  clutter_path_add_line_to (path, 0, height * 0.75);
  clutter_path_add_move_to (path, width * 0.5, height);
  clutter_path_add_line_to (path, 0, height * 0.25);
  clutter_path_add_line_to (path, width, height * 0.25);
  clutter_path_add_line_to (path, width * 0.5, height);

  CLUTTER_ACTOR_CLASS (star_actor_parent_class)->allocate (actor, box, flags);
}
]]>
          </programlisting>
        </informalexample>

      <para>This clears then adds segments to the
      <type>ClutterPath</type> stored with the
      <type>StarActor</type> instance. The positioning and
      lengths of the segments are relative to the size of the actor when
      its allocation changes.</para>

      <para>The <function>pick</function> and <function>paint</function>
      functions now reference the <type>ClutterPath</type> (only the
      <function>pick</function> is shown below); and
      to turn the path into drawing operations, we implement a
      <function>star_actor_convert_clutter_path_node()</function> function
      which takes a <type>ClutterPathNode</type> and converts it
      into its Cogl equivalent:</para>

      <informalexample>
        <programlisting>
<![CDATA[
static void
star_actor_convert_clutter_path_node (const ClutterPathNode *node,
                                      gpointer               data)
{
  g_return_if_fail (node != NULL);

  ClutterKnot knot;

  switch (node->type)
    {
    case CLUTTER_PATH_MOVE_TO:
      knot = node->points[0];
      cogl_path_move_to (knot.x, knot.y);
      break;
    case CLUTTER_PATH_LINE_TO:
      knot = node->points[0];
      cogl_path_line_to (knot.x, knot.y);
      break;
    default:
      break;
    }
}

static void
star_actor_pick (ClutterActor       *actor,
                 const ClutterColor *pick_color)
{
  if (!clutter_actor_should_pick_paint (actor))
    return;

  ClutterActorBox allocation = { 0, };
  gfloat width, height;
  ClutterPath *path = STAR_ACTOR (actor)->priv->path;

  clutter_actor_get_allocation_box (actor, &allocation);
  clutter_actor_box_get_size (&allocation, &width, &height);

  cogl_path_new ();

  cogl_set_source_color4ub (pick_color->red,
                            pick_color->green,
                            pick_color->blue,
                            pick_color->alpha);

  clutter_path_foreach (path, star_actor_convert_clutter_path_node, NULL);

  cogl_path_fill ();
}
]]>
        </programlisting>
      </informalexample>

      <note>
        <para>The conversion function only covers
        <type>ClutterPathNode</type> types encountered in this
        actor.</para>
      </note>

      <para>Instead of converting to Cogl path operations, another alternative
      would be to use the <function>clutter_path_to_cairo_path()</function>
      function to write directly from the <type>ClutterPath</type>
      onto a Cairo context.</para>

      </section>
    </section>

  </section>

</chapter>
