<chapter id="clutter-subclassing-ClutterActor">
  <chapterinfo>
    <author>
      <firstname>Emmanuele</firstname>
      <surname>Bassi</surname>
      <affiliation>
        <address>
          <email>ebassi@openedhand.com</email>
        </address>
      </affiliation>
    </author>
  </chapterinfo>

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

    <programlisting>
static void
foo_actor_query_coords (ClutterActor    *actor,
                        ClutterActorBox *box)
{
  FooActor *foo_actor = FOO_ACTOR (actor);
  GList *child;

  /* Clutter uses high-precision units which can be converted from
   * and into pixels, typographic points, percentages, etc.
   */
  ClutterUnit width, height;

  /* initialize our size */
  width = height = 0;

  for (l = foo_actor-&gt;children; l != NULL; l = l-&gt;next)
    {
      ClutterActor *child_actor = child-&gt;data;

      /* we consider only visible actors */
      if (CLUTTER_ACTOR_IS_VISIBLE (child_actor))
        {
          ClutterActorBox child_box = { 0, };

          clutter_actor_query_coords (child_actor, &amp;child_box);
          
          width  += child_box.x2 - child_box.x2;
          height += child_box.y2 - child_box.y1;
        }
    }

  box-&gt;x2 = box-&gt;x1 + width
  box-&gt;y2 = box-&gt;y1 + height;
}
    </programlisting>
  </example>
  
  <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>

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

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

  <example id="clutter-actor-paint-example">
    <programlisting>
static void
foo_actor_paint (ClutterActor *actor)
{
  FooActor *foo_actor = FOO_ACTOR (actor);
  GList *child;

  /* by including &lt;clutter/cogl.h&gt; 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-&gt;children; child != NULL; child = child-&gt;next)
    {
      ClutterActor *child_actor = child-&gt;data;

      if (CLUTTER_ACTOR_IS_MAPPED (child_actor))
        clutter_actor_paint (child_actor);
    }

  cogl_pop_matrix ();
}
    </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>

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

  <example id="clutter-actor-pick-example">
    <programlisting>
static void
foo_actor_pick (ClutterActor       *actor,
                const ClutterColor *pick_color)
{
  FooActor *foo_actor = FOO_ACTOR (actor);
  guint width, height;

  /* it is possible to avoid a costly paint by checking whether the
   * actor should really be painted in pick mode
   */
  if (!clutter_actor_should_pick_paint (actor))
    return;

  /* by including &lt;clutter/cogl.h&gt; 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_color (pick_color);

  clutter_actor_get_size (actor, &amp;width, &amp;height); 

  /* 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 ();

  cogl_pop_matrix ();
}
    </programlisting>
  </example>

  <section id="implementing-clutter-container">
    <title>Implementing Containers</title>

    <para>
    The #ClutterContainer interface should be implemented by subclasses
    of #ClutterActor who wants to provide a general API for adding child
    actors.
    </para>

    <para>
    If the #ClutterActor subclass only handles internal children, or it's
    not suitable for having generic actors added to it, it should not
    implement the #ClutterContainer interface, but simply use
    clutter_actor_set_parent():
    </para>

    <example id="clutter-actor-set-parent-example">
      <programlisting>
void
foo_actor_add_baz (FooActor *foo_actor,
                   BazActor *baz_actor)
{
  g_return_if_fail (FOO_IS_ACTOR (foo_actor));
  g_return_if_fail (BAZ_IS_ACTOR (baz_actor));

  /* unparent the previous BazActor; this will automatically call
   * g_object_unref() on the actor
   */
  if (foo_actor-&gt;baz)
    clutter_actor_unparent (foo_actor-&gt;baz);

  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
   */
  clutter_actor_set_parent (CLUTTER_ACTOR (baz_actor),
                            CLUTTER_ACTOR (foo_actor));

  g_signal_emit (foo_actor, foo_actor_signals[BAZ_CHANGED], 0, baz_actor);
}
      </programlisting>
    </example>

    <para>
    In order to implement the #ClutterContainer interface, these virtual
    functions must be defined:

      <variablelist>
        <varlistentry>
          <term>ClutterContainer::add</term>
          <listitem>
            <para></para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>ClutterContainer::remove</term>
          <listitem>
            <para></para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>ClutterContainer::foreach</term>
          <listitem>
            <para></para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>ClutterContainer::raise</term>
          <listitem>
            <para></para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>ClutterContainer::lower</term>
          <listitem>
            <para></para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>ClutterContainer::sort_depth_order</term>
          <listitem>
            <para></para>
          </listitem>
        </varlistentry>
      </variablelist>

    </para>

  </section>

</chapter>