2010-08-26 10:07:54 +00:00
|
|
|
<!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>
|
2010-08-26 11:51:33 +00:00
|
|
|
<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>
|
2010-08-26 10:07:54 +00:00
|
|
|
</epigraph>
|
|
|
|
|
|
|
|
<section id="script-introduction">
|
|
|
|
<title>Introduction</title>
|
|
|
|
|
2010-08-26 11:51:33 +00:00
|
|
|
<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
|
2010-08-27 10:20:29 +00:00
|
|
|
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>
|
2010-08-26 11:51:33 +00:00
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<para>Many frameworks separate presentation from programming
|
2010-08-26 11:51:33 +00:00
|
|
|
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
|
2010-08-27 10:20:29 +00:00
|
|
|
<ulink href="http://www.json.org/">JSON</ulink>, load
|
|
|
|
the UI from the JSON, then handle interactions with it through Clutter code
|
2010-08-26 11:51:33 +00:00
|
|
|
(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
|
2010-08-27 10:20:29 +00:00
|
|
|
code (at least, once you have more than three or four actors in
|
|
|
|
your application).</para>
|
2010-08-26 11:51:33 +00:00
|
|
|
</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,
|
2010-08-27 10:20:29 +00:00
|
|
|
layouts) can be much simpler in JSON.</para>
|
2010-08-26 11:51:33 +00:00
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>Less compilation (if you're using a compiled language):
|
2010-08-27 10:20:29 +00:00
|
|
|
because you can change the UI by editing external JSON files,
|
2010-08-26 11:51:33 +00:00
|
|
|
you can make changes to it without needing to recompile
|
|
|
|
the whole application.</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<para>The following sections are intended
|
2010-08-26 11:51:33 +00:00
|
|
|
to give an overview of how <type>ClutterScript</type> works, and
|
2010-08-27 10:20:29 +00:00
|
|
|
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>
|
2010-08-26 11:51:33 +00:00
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Basic principles of <type>ClutterScript</type></title>
|
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<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
|
2010-08-26 11:51:33 +00:00
|
|
|
set their properties. For example:</para>
|
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<example>
|
|
|
|
<title>Example UI definition in JSON for use with
|
|
|
|
<type>ClutterScript</type></title>
|
|
|
|
|
|
|
|
<programlistingco>
|
|
|
|
<programlisting>
|
2010-08-26 11:51:33 +00:00
|
|
|
[ <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",
|
2010-08-27 14:29:09 +00:00
|
|
|
"x-align" : "center", <co id="script-ui-introduction-json-nickname" />
|
|
|
|
"y-align" : "center"
|
2010-08-26 11:51:33 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
"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" />
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
2010-08-27 10:20:29 +00:00
|
|
|
</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>
|
2010-08-27 14:29:09 +00:00
|
|
|
<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>
|
2010-08-27 10:20:29 +00:00
|
|
|
</calloutlist>
|
|
|
|
|
|
|
|
</programlistingco>
|
|
|
|
</example>
|
2010-08-26 11:51:33 +00:00
|
|
|
|
|
|
|
<para>Once you grasp that Clutter objects are GObjects, and you
|
2010-08-27 10:20:29 +00:00
|
|
|
are setting their properties, you can work out what is "scriptable"
|
2010-08-26 11:51:33 +00:00
|
|
|
by referring to the <emphasis>Properties</emphasis> sections
|
2010-08-27 10:20:29 +00:00
|
|
|
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::<property name></code>
|
|
|
|
syntax for the key). Some of these are covered in recipes later in
|
|
|
|
this chapter.</para>
|
2010-08-26 11:51:33 +00:00
|
|
|
|
|
|
|
</section>
|
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<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 => 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> => <code>1.0</code></para>
|
|
|
|
<para><code>1e-1</code> => <code>1e-1</code></para>
|
|
|
|
<para><code>1E-1</code> => <code>1E-1</code></para>
|
|
|
|
<para><code>0.1E-1</code> => <code>0.1E-1</code></para>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>integer (guint8, gint)</td>
|
|
|
|
<td>number (int)</td>
|
|
|
|
<td>
|
|
|
|
<para><code>1</code> => <code>1</code></para>
|
|
|
|
<para><code>0x00</code> => <code>0</code> (no hex in JSON)</para>
|
|
|
|
<para><code>01</code> => <code>1</code> (no octal in JSON)</para>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>gboolean</td>
|
|
|
|
<td>true/false</td>
|
|
|
|
<td>
|
|
|
|
<para><code>TRUE</code> => <code>true</code></para>
|
|
|
|
<para><code>FALSE</code> => <code>false</code></para>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>gchar</td>
|
|
|
|
<td>string</td>
|
|
|
|
<td><code>"hello world"</code> => <code>"hello world"</code></td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>enum (e.g. Clutter constants)</td>
|
|
|
|
<td>string</td>
|
2010-08-27 14:10:17 +00:00
|
|
|
<td>
|
|
|
|
<code>CLUTTER_ALIGN_X_AXIS</code> =>
|
|
|
|
<code>"CLUTTER_ALIGN_X_AXIS"</code> or <code>"x-axis"</code>
|
|
|
|
(the latter is the GEnum nickname for the constant)
|
|
|
|
</td>
|
2010-08-27 10:20:29 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>ClutterColor</td>
|
|
|
|
<td>color string</td>
|
|
|
|
<td>
|
|
|
|
<code>clutter_color_new (255, 0, 0, 255)</code> =>
|
|
|
|
<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> =>
|
|
|
|
<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> =>
|
|
|
|
<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>
|
2010-08-26 11:51:33 +00:00
|
|
|
|
|
|
|
</section>
|
|
|
|
|
2010-08-26 10:07:54 +00:00
|
|
|
</section>
|
|
|
|
|
|
|
|
<section id="script-ui">
|
2010-08-27 10:20:29 +00:00
|
|
|
<title>Defining a user interface with JSON</title>
|
2010-08-26 10:07:54 +00:00
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Problem</title>
|
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<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>
|
2010-08-26 10:07:54 +00:00
|
|
|
</section>
|
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Solution</title>
|
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<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>
|
2010-08-26 10:07:54 +00:00
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<para>This keeps the UI definition separate from the application
|
|
|
|
logic and makes it easier to manage.</para>
|
2010-08-26 10:07:54 +00:00
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<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>
|
2010-08-26 11:51:33 +00:00
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<para>Here's an example JSON definition to put in the file:</para>
|
2010-08-26 11:51:33 +00:00
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<informalexample>
|
2010-08-26 11:51:33 +00:00
|
|
|
<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>
|
2010-08-27 10:20:29 +00:00
|
|
|
</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>
|
2010-08-26 11:51:33 +00:00
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<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>
|
2010-08-26 11:51:33 +00:00
|
|
|
<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>
|
|
|
|
|
2010-08-27 10:20:29 +00:00
|
|
|
<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>
|
|
|
|
|
2010-08-26 10:07:54 +00:00
|
|
|
</section>
|
|
|
|
|
|
|
|
</section>
|
|
|
|
|
2010-08-31 13:39:03 +00:00
|
|
|
<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>
|
|
|
|
|
2010-08-26 10:07:54 +00:00
|
|
|
</chapter>
|