script: Allow connecting signal to ClutterState states

One of the uses of a ClutterState state machine along with ClutterScript
is to provide a quick way to transition from state to state in response
to signal emitted on specific instances.

Connecting a real function, in code, to a specific signal does not
improve the ease of use of ClutterScript to define scenes.

By adding a new signal definition to the current one we can have both a
simple way to define application logic in code and in the UI definition
file.

The new syntax is trivial:

  {
    "name" : <signal name>,
    "state" : <state machine script id>,
    "target-state" : <target state>
  }

The ClutterState instance is identified by its script id, and the target
state is resolved at run-time, so it can be defined both in
ClutterScript or in code. Ideally, we should find a way to associate a
default ClutterState instance to the ClutterScript one that parses the
definition; this way we would be able to remove the "state" member, or
even "style" the behaviour of an object by replacing the ClutterState
instance.

The implementation uses a signal emission hook, to avoid knowing the
signal signature; we check the emitter of the signal against the object
that defined the signal, to avoid erroneous state changes.
This commit is contained in:
Emmanuele Bassi
2011-02-07 13:48:58 +00:00
parent 2c2bdc1d2c
commit dd8cf63a62
3 changed files with 182 additions and 53 deletions

View File

@ -560,12 +560,9 @@ parse_signals (ClutterScript *script,
for (i = 0; i < array_len; i++)
{
JsonNode *val = json_array_get_element (array, i);
SignalInfo *sinfo = NULL;
JsonObject *object;
SignalInfo *sinfo;
const gchar *name;
const gchar *handler;
const gchar *connect;
GConnectFlags flags = 0;
if (JSON_NODE_TYPE (val) != JSON_NODE_OBJECT)
{
@ -595,56 +592,97 @@ parse_signals (ClutterScript *script,
}
}
/* mandatory: "handler" */
if (!json_object_has_member (object, "handler"))
/* mandatory: "state" */
if (json_object_has_member (object, "state"))
{
_clutter_script_warn_missing_attribute (script, NULL, "handler");
continue;
const gchar *state;
const gchar *target;
state = json_object_get_string_member (object, "state");
if (state == NULL)
{
_clutter_script_warn_invalid_value (script,
"state", "string",
val);
continue;
}
target = json_object_get_string_member (object, "target-state");
if (target == NULL)
{
_clutter_script_warn_invalid_value (script,
"target-state", "string",
val);
continue;
}
CLUTTER_NOTE (SCRIPT,
"Added signal '%s' (state:%s, target:%s)",
name,
state, target);
sinfo = g_slice_new0 (SignalInfo);
sinfo->is_handler = FALSE;
sinfo->name = g_strdup (name);
sinfo->state = g_strdup (state);
sinfo->target = g_strdup (target);
}
else
/* mandatory: "handler" */
if (json_object_has_member (object, "handler"))
{
const gchar *handler;
const gchar *connect;
GConnectFlags flags = 0;
handler = json_object_get_string_member (object, "handler");
if (!handler)
if (handler == NULL)
{
_clutter_script_warn_invalid_value (script,
"handler", "string",
val);
continue;
}
/* optional: "object" */
if (json_object_has_member (object, "object"))
connect = json_object_get_string_member (object, "object");
else
connect = NULL;
/* optional: "after" */
if (json_object_has_member (object, "after"))
{
if (json_object_get_boolean_member (object, "after"))
flags |= G_CONNECT_AFTER;
}
/* optional: "swapped" */
if (json_object_has_member (object, "swapped"))
{
if (json_object_get_boolean_member (object, "swapped"))
flags |= G_CONNECT_SWAPPED;
}
CLUTTER_NOTE (SCRIPT,
"Added signal '%s' (handler:%s, object:%s, flags:%d)",
name,
handler, connect, flags);
sinfo = g_slice_new0 (SignalInfo);
sinfo->is_handler = TRUE;
sinfo->name = g_strdup (name);
sinfo->handler = g_strdup (handler);
sinfo->object = g_strdup (connect);
sinfo->flags = flags;
}
/* optional: "object" */
if (json_object_has_member (object, "object"))
connect = json_object_get_string_member (object, "object");
if (sinfo != NULL)
retval = g_list_prepend (retval, sinfo);
else
connect = NULL;
/* optional: "after" */
if (json_object_has_member (object, "after"))
{
if (json_object_get_boolean_member (object, "after"))
flags |= G_CONNECT_AFTER;
}
/* optional: "swapped" */
if (json_object_has_member (object, "swapped"))
{
if (json_object_get_boolean_member (object, "swapped"))
flags |= G_CONNECT_SWAPPED;
}
CLUTTER_NOTE (SCRIPT,
"Parsing signal '%s' (handler:%s, object:%s, flags:%d)",
name,
handler, connect, flags);
sinfo = g_slice_new0 (SignalInfo);
sinfo->name = g_strdup (name);
sinfo->handler = g_strdup (handler);
sinfo->object = g_strdup (connect);
sinfo->flags = flags;
retval = g_list_prepend (retval, sinfo);
_clutter_script_warn_missing_attribute (script,
NULL,
"handler or state");
}
return retval;