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

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

  <epigraph>
    <attribution>Alfred Hitchcock</attribution>
    <para>When an actor comes to me and wants to discuss his character,
    I say, "It's in the script". If he says, "But what's my motivation?",
    I say, "Your salary".</para>
  </epigraph>

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

    <para>User interfaces can become difficult to maintain when
    described entirely in code: declarations of UI
    elements become entwined with procedural code for
    handling interactions. This can make refactoring tough, as
    you have to find the right place in the code to modify the UI
    ("Where did I set the color of that rectangle?") and make sure
    your UI modifications don't break any behaviour.</para>

    <para>Many frameworks separate presentation from programming
    logic, making it easier to change the appearance of the UI
    without affecting its behaviour (and vice versa). For example,
    in web development you can use HTML and CSS to define
    presentation, and JavaScript to implement application logic.</para>

    <para><type>ClutterScript</type> enables a similar separation:
    you can define the UI declaratively using
    <ulink href="http://www.json.org/">JSON</ulink>, load
    the UI from the JSON, then handle interactions with it through Clutter code
    (in C, Python, Vala or some other language). This has several
    benefits, including:</para>

    <itemizedlist>
      <listitem>
        <para>Separation of UI element declarations from control logic
        (see above).</para>
      </listitem>
      <listitem>
        <para>More concise code: typically, describing a UI in JSON
        requires far fewer characters than the equivalent procedural
        code (at least, once you have more than three or four actors in
        your application).</para>
      </listitem>
      <listitem>
        <para>If you write your JSON in external files, you can make the
        structure of the UI evident in the layout of the file. For
        example, child elements can be indented within the parent
        element. This can make identifying relationships between
        elements simpler and less error-prone.</para>
      </listitem>
      <listitem>
        <para>Creating and configuring some objects (e.g. animations,
        layouts) can be much simpler in JSON.</para>
      </listitem>
      <listitem>
        <para>Less compilation (if you're using a compiled language):
        because you can change the UI by editing external JSON files,
        you can make changes to it without needing to recompile
        the whole application.</para>
      </listitem>
    </itemizedlist>

    <para>The following sections are intended
    to give an overview of  how <type>ClutterScript</type> works, and
    how to use it in an application. The recipes in this chapter
    then provide more detail about particular aspects of
    <type>ClutterScript</type>, such as how to connect signals to handlers,
    how to merge multiple JSON definitions in a single script, etc.
    There is also a lot of useful information in the <type>ClutterScript</type>
    API reference.</para>

    <section>
      <title>Basic principles of <type>ClutterScript</type></title>

      <para>Clutter is built on top of
      <ulink href="http://library.gnome.org/devel/gobject/">GObject</ulink>,
      an object system for C. <type>ClutterScript</type>
      provides a way to create instances of GObjects and
      set their properties. For example:</para>

      <example>
        <title>Example UI definition in JSON for use with
        <type>ClutterScript</type></title>

        <programlistingco>
          <programlisting>
[   <co id="script-ui-introduction-json-list-bracket" />
  {   <co id="script-ui-introduction-json-object-bracket" />
    "id" : "stage",   <co id="script-ui-introduction-json-id" />
    "type" : "ClutterStage",   <co id="script-ui-introduction-json-type" />
    "width" : 400,
    "height" : 400,
    "color" : "#333355ff",   <co id="script-ui-introduction-json-color-html" />
    "children" : [ "box" ]   <co id="script-ui-introduction-json-child-by-id" />
  },

  {
    "id" : "box",
    "type" : "ClutterBox",
    "width" : 400,
    "height" : 400,

    "layout-manager" : {   <co id="script-ui-introduction-json-no-id" />
      "type" : "ClutterBinLayout",
      "x-align" : "center",   <co id="script-ui-introduction-json-nickname" />
      "y-align" : "center"
    },

    "children" : [   <co id="script-ui-introduction-json-child-by-embedding" />
      {
        "id" : "rectangle",
        "type" : "ClutterRectangle",
        "width" : 200,
        "height" : 200,
        "color" : "red"   <co id="script-ui-introduction-json-color-word" />
      }
    ]
  }
]
          </programlisting>

          <note>
            <para>N.B. The numbers in brackets in the example further
            explain the JSON structure, and are not part of the UI
            definition.</para>
          </note>

          <calloutlist>
            <callout arearefs="script-ui-introduction-json-list-bracket">
              <para>All the objects defined for the UI sit inside a JSON
              list structure, marked with square brackets.</para>
            </callout>
            <callout arearefs="script-ui-introduction-json-object-bracket">
              <para>A pair of braces surrounds each object definition;
              inside the braces, key-value pairs set properties on the
              object. See the
              <link linkend="script-introduction-data-types">section on
              datatypes</link> for more about the acceptable values.</para>
            </callout>
            <callout arearefs="script-ui-introduction-json-id
            script-ui-introduction-json-no-id">
              <para>An <varname>id</varname> is required for objects which
              are referred to elsewhere in the JSON or which need to be
              accessible from code (see
              <link linkend="script-ui">this recipe</link> for the basics of
              using object IDs from code).</para>
              <para>In cases where an object doesn't need to be accessible
              from code and is not referenced elsewhere in the JSON file,
              the <varname>id</varname> can be omitted.</para>
            </callout>
            <callout arearefs="script-ui-introduction-json-type">
              <para>The <varname>type</varname> key is mandatory, and
              specifies the type of the object; usually this will be
              one of the Clutter object types.</para>
            </callout>
            <callout arearefs="script-ui-introduction-json-color-html
            script-ui-introduction-json-color-word">
              <para>Colors can be set using hexadecimal color code strings,
              as used in HTML and CSS; or by using color words. The
              range of acceptable values is as for the
              <function>pango_color_from_string()</function> function.</para>
            </callout>
            <callout arearefs="script-ui-introduction-json-child-by-id
            script-ui-introduction-json-child-by-embedding">
              <para>Children can be associated with a parent through
              the <varname>children</varname> property. Children are
              either added to the <varname>children</varname> list by ID;
              or by directly embedding the child JSON object as an element
              within the list. The two can be mixed in a single
              list of <varname>children</varname>.</para>
            </callout>
            <callout arearefs="script-ui-introduction-json-nickname">
              <para>This uses the nickname for a value in an enumeration
              (in this case, the nickname for
              <constant>CLUTTER_BIN_ALIGNMENT_CENTER</constant>).</para>
              <para>To get the nickname for an enumeration value, take
              the component which is unique to that value in the
              enumeration, lowercase it, and replace any underscores
              with hyphens. Some examples:</para>
              <itemizedlist>
                <listitem>
                  <para><constant>CLUTTER_ALIGN_X_AXIS</constant> has
                  the nickname <code>x-axis</code></para>
                </listitem>
                <listitem>
                  <para><constant>CLUTTER_GRAVITY_NORTH</constant> has
                  the nickname <code>north</code></para>
                </listitem>
                <listitem>
                  <para><constant>CLUTTER_REQUEST_HEIGHT_FOR_WIDTH</constant>
                  has the nickname <code>height-for-width</code></para>
                </listitem>
              </itemizedlist>
            </callout>
          </calloutlist>

        </programlistingco>
      </example>

      <para>Once you grasp that Clutter objects are GObjects, and you
      are setting their properties, you can work out what is "scriptable"
      by referring to the <emphasis>Properties</emphasis> sections
      of the API reference for each Clutter type. Any of the properties
      described there can be set using <type>ClutterScript</type>.</para>

      <para>Having said this, there are some special properties which
      aren't obvious, but which can be set via JSON;
      <emphasis>layout properties</emphasis> are one example. These aren't
      listed as properties of <type>ClutterActor</type> but can be set
      as part of a <type>ClutterActor</type> object definition
      (using the <code>layout::&lt;property name&gt;</code>
      syntax for the key). Some of these are covered in recipes later in
      this chapter.</para>

    </section>

    <section id="script-introduction-data-types">
      <title>Data types</title>

      <para><type>ClutterScript</type> uses the standard JSON format.
      It is very important that you respect the data type of the property
      you are setting, ensuring that you use the right JSON data type.
      You may get unexpected results or errors if you try to set a property
      using the wrong data type: for example, setting a property
      to an integer <type>number</type> in the JSON, when the Clutter property
      is expecting a <type>gfloat</type>, may cause errors.</para>

      <para>To assist in using the right data types in your JSON
      definitions, the table below shows how Clutter and GLib data
      types map to JSON:</para>

      <informaltable>
        <thead>
          <tr>
            <th>C data type (Clutter/GLib)</th>
            <th>Maps to JSON</th>
            <th>Example (C =&gt; JSON)</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>floating point number (gfloat, gdouble)</td>
            <td>number (int frac, int exp, int frac exp)</td>
            <td>
              <para><code>1.0</code> =&gt; <code>1.0</code></para>
              <para><code>1e-1</code> =&gt; <code>1e-1</code></para>
              <para><code>1E-1</code> =&gt; <code>1E-1</code></para>
              <para><code>0.1E-1</code> =&gt; <code>0.1E-1</code></para>
            </td>
          </tr>
          <tr>
            <td>integer (guint8, gint)</td>
            <td>number (int)</td>
            <td>
              <para><code>1</code> =&gt; <code>1</code></para>
              <para><code>0x00</code> =&gt; <code>0</code> (no hex in JSON)</para>
              <para><code>01</code> =&gt; <code>1</code> (no octal in JSON)</para>
            </td>
          </tr>
          <tr>
            <td>gboolean</td>
            <td>true/false</td>
            <td>
              <para><code>TRUE</code> =&gt; <code>true</code></para>
              <para><code>FALSE</code> =&gt; <code>false</code></para>
            </td>
          </tr>
          <tr>
            <td>gchar</td>
            <td>string</td>
            <td><code>"hello world"</code> =&gt; <code>"hello world"</code></td>
          </tr>
          <tr>
            <td>enum (e.g. Clutter constants)</td>
            <td>string</td>
            <td>
              <code>CLUTTER_ALIGN_X_AXIS</code> =&gt;
              <code>"CLUTTER_ALIGN_X_AXIS"</code> or <code>"x-axis"</code>
              (the latter is the GEnum nickname for the constant)
            </td>
          </tr>
          <tr>
            <td>ClutterColor</td>
            <td>color string</td>
            <td>
              <code>clutter_color_new (255, 0, 0, 255)</code> =&gt;
              <code>"red"</code> or <code>"#f00f"</code> or
              <code>"#ff0000ff"</code>; alternatively,
              <code>"#f00"</code> or <code>"#ff0000"</code>
              (implicitly sets alpha value to 255)
            </td>
          </tr>
          <tr>
            <td>ClutterActor (or other Clutter type)</td>
            <td>object</td>
            <td>
              <code>clutter_rectangle_new ()</code> =&gt;
              <code>{ "type" : "ClutterRectangle" }</code>
            </td>
          </tr>
          <tr>
            <td>Property which takes a list or array of values</td>
            <td>array of objects and/or IDs</td>
            <td>
              <code>clutter_container_add_actor (stage, rectangle)</code> =&gt;
              <programlisting>
{
  "id" : "stage",
  "type" : "ClutterStage",
  ...,

  "children" : [
    {
      "id" : "rectangle",
      "type" : "ClutterRectangle",
      ...
    }
  ]
}
              </programlisting>
            </td>
          </tr>
          <tr>
            <td><code>NULL</code></td>
            <td><code>null</code></td>
            <td>-</td>
          </tr>
        </tbody>
      </informaltable>

    </section>

  </section>

  <section id="script-ui">
    <title>Defining a user interface with JSON</title>

    <section>
      <title>Problem</title>

      <para>You want to create a user interface as quickly as
      possible; you also need to change it easily as requirements shift.</para>

      <para>This need can arise when:</para>

      <itemizedlist>
        <listitem>
          <para>you are prototyping a user interface, and you need to
          quickly test new ideas.</para>
        </listitem>
        <listitem>
          <para>the user interface you are building is likely to contain many
          elements and relationships between them.</para>
        </listitem>
      </itemizedlist>
    </section>

    <section>
      <title>Solution</title>

      <para>Define the user interface in an external JSON file. Then
      create a <type>ClutterScript</type> object and load the JSON
      into it from the file.</para>

      <para>This keeps the UI definition separate from the application
      logic and makes it easier to manage.</para>

      <note>
        <para>See <link linkend="script-introduction">the introduction</link>
        for the reasons why <type>ClutterScript</type> is a good solution,
        and for an overview of how JSON definitions work.</para>
      </note>

      <para>Here's an example JSON definition to put in the file:</para>

      <informalexample>
        <programlisting>
<xi:include href="examples/script-ui.json" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </informalexample>

      <para>In the application, load the JSON from the file with
      <function>clutter_script_load_from_file()</function>. (You can
      also load JSON from a string (<type>gchar*</type>) with
      <function>clutter_script_load_from_data()</function>.)</para>

      <para>Then retrieve objects by ID to use them in your code:</para>

      <example>
        <title>Loading JSON from a file and retrieving objects
        defined by it</title>
        <programlisting>
<xi:include href="examples/script-ui.c" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

      <para>Although we only retrieved the stage in the example above,
      <function>clutter_script_get_objects()</function> can
      retrieve multiple objects with a single call:</para>

      <informalexample>
        <programlisting>
<![CDATA[
ClutterScript *script;
script = clutter_script_new ();

/* ...load JSON file etc. */

ClutterStage *stage;
ClutterActor *actor1;
ClutterActor *actor2;

/* use a NULL-terminated argument list of id,variable pairs */
clutter_script_get_objects (script,
                            "stage", &stage,
                            "actor1", &actor1,
                            "actor2", &actor2,
                            NULL);
]]>
        </programlisting>
      </informalexample>

      <para>You can also use <function>clutter_script_get_object()</function>
      to retrieve a single object, though you may have to cast
      it to the right type before use; for example:</para>

      <informalexample>
        <programlisting>
ClutterStage *stage = CLUTTER_STAGE (clutter_script_get_object (script, "stage));
        </programlisting>
      </informalexample>

    </section>

    <section>
      <title>Discussion</title>

      <para>In the sample code, the stage is part of the JSON definition.
      However, it doesn't have to be: it is possible to create the
      stage in application code; then load more components from one
      or more JSON definitions and attach them to the stage you
      constructed in code.</para>

      <para>However, keeping most of the user interface definition
      in external JSON files makes it easier to change
      the UI without having to touch any code. If you have some user
      interface elements constructed in code and some in JSON, it can
      make refactoring more difficult.</para>

    </section>

  </section>

  <section id="script-signals">
    <title>Connecting to signals in <type>ClutterScript</type></title>

    <section>
      <title>Problem</title>

      <para>You have declared an actor using JSON, and want to add
      handlers for signals emitted by it.</para>
    </section>

    <section>
      <title>Solution</title>

      <para>Add a <varname>signals</varname> property to the actor's
      JSON definition.</para>

      <para>Here's how to connect a <type>ClutterStage's</type>
      <code>destroy</code> signal to the
      <function>clutter_main_quit()</function> function:</para>

      <informalexample>
        <programlisting>
{
  "id" : "stage",
  "type" : "ClutterStage",
  "width" : 300,
  "height" : 300,

  <emphasis>"signals" : [
    { "name" : "destroy", "handler" : "clutter_main_quit" }
  ]</emphasis>
}
        </programlisting>
      </informalexample>

      <para>The highlighted part of the code is where the
      signal is connected. In this case, a Clutter function is used
      as the handler; in most cases, you'll want to define your own
      handlers, rather than using functions from other libraries,
      as follows:</para>

      <informalexample>
        <programlisting>
{
  "id" : "rectangle",
  "type" : "ClutterRectangle",
  "width" : 200,
  "height" : 200,
  "reactive" : true,

  <emphasis>"signals" : [
    { "name" : "motion-event", "handler" : "foo_pointer_motion_cb" }
  ]</emphasis>
}
        </programlisting>
      </informalexample>

      <para>This signal handler definition sets
      <function>foo_pointer_motion_cb()</function>
      as the handler for the <code>motion-event</code>
      signal on the rectangle. (NB the rectangle has
      <varname>reactive</varname> set to true, otherwise it
      can't emit this signal.)</para>

      <para>As per standard event handling in Clutter,
      you define the handler function next. For example:</para>

      <informalexample>
        <programlisting>
<![CDATA[
/* handler which just prints the position of the pointer at each motion event */
gboolean
foo_pointer_motion_cb (ClutterActor *actor,
                       ClutterEvent *event,
                       gpointer      user_data)
{
  gfloat x, y;
  clutter_event_get_coords (event, &x, &y);

  g_print ("Pointer movement at %.0f,%.0f\n", x, y);

  return TRUE;
}
]]>
        </programlisting>
      </informalexample>

      <note>
        <para>See the
        <link linkend="script-signals-discussion-writing-handlers">Discussion</link>
        section for more about writing handler functions.</para>
      </note>

      <para>To make the signal connections active in your code,
      call the <function>clutter_script_connect_signals()</function>
      function after loading the JSON:</para>

      <informalexample>
        <programlisting>
<![CDATA[
GError *error = NULL;

/* load JSON from a file */
ClutterScript *ui = clutter_script_new ();
clutter_script_load_from_file (ui, filename, &error);

/* ...handle errors etc... */

/* connect the signals defined in the JSON file
 *
 * the first argument is the script into which the JSON
 * definition was loaded
 *
 * the second argument is passed as user_data to all
 * handlers: in this case, we pass the script as user_data
 * to all handlers, so that all the objects in the UI
 * are available to callback functions
 */
clutter_script_connect_signals (ui, ui);
]]>
        </programlisting>
      </informalexample>

    </section>

    <section id="script-signals-discussion">
      <title>Discussion</title>

      <section>
        <title>Options for connecting signals to handlers</title>

        <para>Every connection between a signal and handler requires
        a JSON object with <varname>name</varname> and
        <varname>handler</varname> keys. The <varname>name</varname>
        is the name of the signal you're connecting a handler to; the
        <varname>handler</varname> is the name of the function which
        will handle the signal.</para>

        <para>You can also specify these optional keys for a handler
        object:</para>

        <orderedlist>
          <listitem>
            <para><code>"after" : true</code> configures the handler
            to run after the default handler for the signal. (Default is
            <code>"after" : false</code>).</para>
          </listitem>
          <listitem>
            <para><varname>"swapped" : true</varname> specifies that
            the instance and the user data passed to the
            handler function are swapped around; i.e. the instance emitting
            the signal is passed in as the user data argument (usually the
            last argument), and any user data is passed in as the first
            argument. (Default is <code>"swapped" : false</code>).</para>
          </listitem>
        </orderedlist>

        <note>
          <para>While the connections to signals were specified in JSON
          above, it is still possible to connect handlers to signals in
          code (e.g. if you need to conditionally connect a handler). Just
          retrieve the object from the <type>ClutterScript</type> and
          connect to its signals with
          <function>g_signal_connect()</function>.</para>
        </note>

      </section>

      <section id="script-signals-discussion-writing-handlers">
        <title>Writing handler functions</title>

        <para>The handler function has the usual signature required
        for the signal. However, the function cannot be static, otherwise
        the function is invisible to GModule (the mechanism used by
        <type>ClutterScript</type> to look up functions named
        in the JSON definition). Consequently, callback functions should be
        namespaced in such a way that they won't clash with function
        definitions in other parts of your code or in libraries you link
        to.</para>

        <para>You should also ensure that you use the
        <option>-export-dynamic</option> flag when you compile your
        application: either by passing it on the command line (if you're
        calling <command>gcc</command> directly); or by adding
        it to the appropriate <varname>LDFLAGS</varname> variable in
        your <filename>Makefile</filename> (if you're using
        <command>make</command>); or by whatever other mechanism is
        appropriate for your build environment.</para>

      </section>

      <section>
        <title>Passing objects to handler functions</title>

        <para>In a typical Clutter application, handler functions
        require access to objects other than the one which emitted a
        signal. For example, a button may move another actor when
        clicked. Typically, you would pass any required objects
        to the handler function as user data, like this:</para>

        <informalexample>
          <programlisting>
g_signal_connect (button,
                  "clicked",
                  G_CALLBACK (_button_clicked_cb),
                  actor_to_move);
          </programlisting>
        </informalexample>

        <para>Note how <varname>actor_to_move</varname> is passed
        as user data to the handler.</para>

        <para>However, the JSON definition doesn't allow you to specify
        that different user data be passed to different handlers. So,
        to get at all required objects in the handler, a simple
        solution is to pass the <type>ClutterScript</type> to
        <emphasis>every</emphasis> handler function; then inside
        <emphasis>each</emphasis> handler function, retrieve
        the required objects from the script.</para>

        <para>This was done in the code example above, by passing
        the <type>ClutterScript</type> instance as two arguments to
        <function>clutter_script_connect_signals()</function>:
        the first argument specifies the script which defines the
        signal handlers; the second specifies the user data passed to every
        handler function. This ensures that each handler has access
        to all of the elements defined in the JSON file.</para>

        <note>
          <para>Alternatively, you could create some other structure to
          hold the objects you need and pass it to all handler functions.
          But this would effectively be a reimplementation of some aspects
          of <type>ClutterScript</type>.</para>
        </note>

      </section>

    </section>

    <section>
      <title>Full examples</title>

      <example id="script-signals-examples-1">
        <title><type>ClutterScript</type> JSON with signal handler
        definitions</title>
        <programlisting>
<xi:include href="examples/script-signals.json" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

      <example id="script-signals-examples-2">
        <title>Loading a JSON file into a <type>ClutterScript</type>
        and connecting signal handlers</title>
        <programlisting>
<xi:include href="examples/script-signals.c" parse="text">
  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
</xi:include>
        </programlisting>
      </example>

    </section>

  </section>

</chapter>
