You want to create a user interface as quickly as possible; you also need to change it easily as requirements shift.
This need can arise when:
you are prototyping a user interface, and you need to quickly test new ideas.
the user interface you are building is likely to contain many elements and relationships between them.
Define the user interface in an external JSON file. Then create a ClutterScript object and load the JSON into it from the file.
This keeps the UI definition separate from the application logic and makes it easier to manage.
Note
See the introduction for the reasons why ClutterScript is a good solution, and for an overview of how JSON definitions work.
Here's an example JSON definition to put in the file:
[ { "id" : "stage", "type" : "ClutterStage", "width" : 400, "height" : 400, "color" : "#333355ff", "children" : [ "box" ] }, { "id" : "box", "type" : "ClutterBox", "width" : 400, "height" : 400, "layout-manager" : { "type" : "ClutterBinLayout", "x-align" : "center", "y-align" : "center" }, "children" : [ { "id" : "rectangle", "type" : "ClutterRectangle", "width" : 200, "height" : 200, "color" : "red" } ] } ]
In the application, load the JSON from the file with
clutter_script_load_from_file()
. (You can
also load JSON from a string (gchar*) with
clutter_script_load_from_data()
.)
Then retrieve objects by ID to use them in your code:
Example 8.2. Loading JSON from a file and retrieving objects defined by it
#include <stdlib.h> #include <clutter/clutter.h> int main (int argc, char *argv[]) { ClutterActor *stage; ClutterScript *ui; gchar *filename = "script-ui.json"; GError *error = NULL; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; ui = clutter_script_new (); /* load a JSON file into the script */ 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); } /* retrieve objects from the script */ clutter_script_get_objects (ui, "stage", &stage, NULL); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; }
Although we only retrieved the stage in the example above,
clutter_script_get_objects()
can
retrieve multiple objects with a single call:
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);
You can also use clutter_script_get_object()
to retrieve a single object, though you may have to cast
it to the right type before use; for example:
ClutterStage *stage = CLUTTER_STAGE (clutter_script_get_object (script, "stage));
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.
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.