4. Connecting ClutterState states in ClutterScript

4.1. Problem

You have declared an actor using JSON, and want to connect signals to ClutterState transitions.

4.2. Solution

Connect the ClutterState states to the signals using the states and target-state keys of the signals definition, and call clutter_script_connect_signals(); for instance, the following JSON declares that the enter-event signal should transition to the hover state and the leave-event should transition to the base state:

{
  "id" : "rectangle",
  "type" : "ClutterRectangle",
  "width" : 200,
  "height" : 200,
  "reactive" : true,

  "signals" : [
    { "name" : "enter-event", "states" : "rectangle-states", "target-state" : "hover" },
    { "name" : "leave-event", "states" : "rectangle-states", "target-state" : "base" }
  ]
}

The rectangle-states state machine holds the various states.

4.3. Discussion

Connecting a ClutterState state transition to a signal defined inside a ClutterScript JSON without requiring a real function to wrap clutter_state_set_state() allows to minimize the amount of code that has to be written, and ties the state to the UI element being defined.

The connection between a signal and a ClutterState state is similar to the connection between a signal and a handler function. Each definition must contain the name of the signal; the script id of the ClutterState object that is used to store the target state definition; and the target state of the transition.

The states key can also contain a full definition of the ClutterState.

The target-state key works exactly like the argument of clutter_state_set_state(): it will transition the ClutterState from the current state to the desired state.

The ClutterState instance that will be used to resolve the target state can be defined in JSON like any other object, but it is also possible to create a ClutterState in code, and associate it to a ClutterScript instance prior to parsing the signal connection JSON, through the clutter_script_add_states() function of ClutterScript.

The warp boolean key can be used to perform a transition to the target state without an animation, similarly to what clutter_state_warp_to_state() does, for instance:

{
  "signals" : [
    {
      "name" : "enter-event",
      "states" : "rectangle-states",
      "target-state" : "hover",
      "warp" : true
    }
  ]
}

will not animate the transition between the current state and the target hover state when the signal is emitted.

4.4. Full examples

Example 8.5. ClutterScript JSON with state definitions

[
  {
    "id" : "stage",
    "type" : "ClutterStage",
    "width" : 300,
    "height" : 300,
    "color" : "#335",

    "signals" : [
      { "name" : "destroy", "handler" : "clutter_main_quit" }
    ],

    "children" : [ "rectangle" ]
  },

  {
    "id" : "rectangle-states",
    "type" : "ClutterState",
    "duration" : 1000,

    "transitions" : [
      {
        "source" : null,
        "target" : "base",

        "keys" : [
          [ "rectangle", "scale-x", "ease-in-cubic", 0.7 ],
          [ "rectangle", "scale-y", "ease-in-cubic", 0.7 ],
          [ "rectangle", "rotation-angle-z", "ease-out-cubic", 0.0 ]
        ]
      },
      {
        "source" : null,
        "target" : "hover",

        "keys" : [
          [ "rectangle", "scale-x", "ease-in-cubic", 1.2 ],
          [ "rectangle", "scale-y", "ease-in-cubic", 1.2 ]
        ]
      },
      {
        "source" : null,
        "target" : "clicked",

        "keys" : [
          [ "rectangle", "rotation-angle-z", "ease-out-bounce", 90.0 ]
        ]
      }
    ]
  },

  {
    "id" : "rectangle",
    "type" : "ClutterRectangle",
    "width" : 200,
    "height" : 200,
    "x" : 50,
    "y" : 50,
    "color" : "#a90",
    "rotation-center-z-gravity" : "center",
    "scale-gravity" : "center",
    "scale-x" : 0.7,
    "scale-y" : 0.7,
    "reactive" : true,

    "signals" : [
      {
        "name" : "enter-event",
        "states" : "rectangle-states",
        "target-state" : "hover"
      },
      {
        "name" : "leave-event",
        "states" : "rectangle-states",
        "target-state" : "base"
      }
    ],

    "actions" : [
      {
        "type" : "ClutterClickAction",
        "signals" : [
          {
            "name" : "clicked",
            "states" : "rectangle-states",
            "target-state" : "clicked"
          }
        ]
      }
    ]
  }
]


Example 8.6. Loading a JSON file into a ClutterScript and connecting states

#include <stdlib.h>
#include <clutter/clutter.h>

int
main (int argc, char *argv[])
{
  ClutterActor *stage;
  ClutterScript *ui;

  gchar *filename = "script-states.json";
  GError *error = NULL;

  if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
    return 1;

  ui = clutter_script_new ();

  clutter_script_load_from_file (ui, filename, &error);

  if (error != NULL)
    {
      g_critical ("Error loading ClutterScript file %s\n%s", filename, error->message);
      g_error_free (error);
      exit (EXIT_FAILURE);
    }

  clutter_script_get_objects (ui,
                              "stage", &stage,
                              NULL);

  /* make the objects in the script available to all signals
   * by passing the script as the second argument
   * to clutter_script_connect_signals()
   */
  clutter_script_connect_signals (ui, ui);

  clutter_actor_show (stage);

  clutter_main ();

  g_object_unref (ui);

  return EXIT_SUCCESS;
}