Constraints

last time, I described the Effects in Clutter as anything that should affect the way an actor paints itself without sub-classing.

this kind of modification of the behaviour of an Actor can also be applied to other areas, and leads to defining three different kinds of modifiers:

  • Effects, which modify the way an actor paints itself
  • Actions, which modify the way an actor responds to user events
  • Constraints, which modify the way an actor is positioned or sized

being capable of being dragged using the pointer can be defined as an action: it changes the way an Actor responds to user events (button press, motion, button release). in the same way, update the X position using the X position of another actor is a constraint placed on an Actor.

Clutter already has signals, properties and virtual functions for dealing with these modifiers, and they can be seen as the building blocks. What’s missing is a set of classes that wrap those building blocks into something that leads to run-time composition of effects, actions and constraints on top of an existing Actor class.

last week I started working on the implementation of these modifiers, and now I’m pretty close to a finalized API for Clutter 1.4. the usage of an action is pretty simple:

  ClutterAction *action = clutter_drag_action_new ();
  g_signal_connect (action, "drag-motion",
                    G_CALLBACK (on_drag_motion),
                    NULL);

  clutter_actor_add_action (some_actor, action)
  clutter_actor_set_reactive (actor, TRUE);

the simplest implementation of a ClutterDragAction::drag-motion signal handler is:

  static void
  on_drag_motion (ClutterDragAction *action,
                  ClutterActor      *actor,
                  float              delta_x,
                  float              delta_y)
  {
    clutter_actor_move_by (actor, delta_x, delta_y);
  }

there’s no fundamental difference for the constraints API; for instance, this positions an actor in the middle of another:

  ClutterConstraint *constraint;

  constraint = clutter_align_constraint_new (parent, CLUTTER_ALIGN_X_AXIS, 0.5);
  clutter_actor_add_constraint (some_actor, constraint);

  constraint = clutter_align_constraint_new (parent, CLUTTER_ALIGN_Y_AXIS, 0.5);
  clutter_actor_add_constraint (some_actor, constraint);

it’s important to note that parent in this case can be any actor, and not necessarily the scene graph parent of some_actor.

this example binds the X coordinate of an actor to the X coordinate of another one, while keeping it Y aligned at the center of its parent:

  ClutterConstraint *constraint;

  constraint = clutter_bind_constraint_new (source, CLUTTER_BIND_X, 0.0);
  clutter_actor_add_constraint_with_name (some_actor, "x-bind", source);

  constraint = clutter_align_constraint_new (parent, CLUTTER_ALIGN_Y_AXIS, 0.5);
  clutter_actor_add_constraint_with_name (some_actor, "y-bind", constraint);

Update: I’ve updated the example to use the newly added add_constraint_with_name() instead of set_name()+add_constraint(); I also changed the constraint names.

now, I’ve added a call to clutter_actor_meta_set_name() in the mix because I might decide to animate the offset property of the ClutterBindConstraint using a specific syntax for ClutterAnimation ((the change is contained in ClutterActor so I’m not over-complicating the parsing code in the animation class itself; which also means that ClutterAnimator and the upcoming ClutterState classes will be able to use the same syntax to address action, effect and constraint properties)):

  float new_offset = clutter_actor_get_width (source) + h_padding;
  clutter_actor_animate (some_actor, CLUTTER_EASE_OUT_CUBIC, 500,
                         "@constraints.x-bind.offset", new_offset,
                         "opacity", 128,
                         NULL);

the new syntax is still type checked, so you’ll get warnings if you’re using the wrong type or the wrong interval ((I’m still considering using a dotted notation; I might switch to a colon notation, or a slash notation. and yes: I know that it looks like the syntax for key access in CoreAnimation; it turns out that there aren’t many new ways to access an item in a path)).

caveat: obviously, a constraint only applies to an actor that is in a fixed positioning layout manager.

the new classes and API are available in the wip/actor-actions branch here and wip/constraints branch here; there are also a couple of interactive tests that show you how actions and constraints can be used with existing actors. if all goes according to plan, I’ll merge them by the end of the week — following Frederic’s blog post, I want to make a 1.3 snapshot release in time for GNOME 2.31.2.