## ClutterBindConstraint

ClutterBindConstraint — A constraint binding the position or size of an actor

## Synopsis

                        ClutterBindConstraint;
    enum                ClutterBindCoordinate;
    ClutterConstraint * clutter_bind_constraint_new         (ClutterActor *source,
                                                             ClutterBindCoordinate coordinate,
                                                             gfloat offset);
    void                clutter_bind_constraint_set_source  (ClutterBindConstraint *constraint,
                                                             ClutterActor *source);
    ClutterActor *      clutter_bind_constraint_get_source  (ClutterBindConstraint *constraint);
    void                clutter_bind_constraint_set_coordinate
                                                            (ClutterBindConstraint *constraint,
                                                             ClutterBindCoordinate coordinate);
    ClutterBindCoordinate clutter_bind_constraint_get_coordinate
                                                            (ClutterBindConstraint *constraint);
    void                clutter_bind_constraint_set_offset  (ClutterBindConstraint *constraint,
                                                             gfloat offset);
    gfloat              clutter_bind_constraint_get_offset  (ClutterBindConstraint *constraint);

## Object Hierarchy

      GObject
       +----GInitiallyUnowned
             +----ClutterActorMeta
                   +----ClutterConstraint
                         +----ClutterBindConstraint

## Properties

      "coordinate"               ClutterBindCoordinate  : Read / Write / Construct
      "offset"                   gfloat                : Read / Write / Construct
      "source"                   ClutterActor*         : Read / Write / Construct

## Description

ClutterBindConstraint is a ClutterConstraint that binds the position or the size of the ClutterActor to which it is applied to the the position or the size of another ClutterActor, or "source".

An offset can be applied to the constraint, to avoid overlapping. The offset can also be animated. For instance, the following code will set up three actors to be bound to the same origin:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    /* source */
    rect[0] = clutter_rectangle_new_with_color (&red_color);
    clutter_actor_set_position (rect[0], x_pos, y_pos);
    clutter_actor_set_size (rect[0], 100, 100);

    /* second rectangle */
    rect[1] = clutter_rectangle_new_with_color (&green_color);
    clutter_actor_set_size (rect[1], 100, 100);
    clutter_actor_set_opacity (rect[1], 0);

    constraint = clutter_bind_constraint_new (rect[0], CLUTTER_BIND_X, 0.0);
    clutter_actor_add_constraint_with_name (rect[1], "green-x", constraint);
    constraint = clutter_bind_constraint_new (rect[0], CLUTTER_BIND_Y, 0.0);
    clutter_actor_add_constraint_with_name (rect[1], "green-y", constraint);

    /* third rectangle */
    rect[2] = clutter_rectangle_new_with_color (&blue_color);
    clutter_actor_set_size (rect[2], 100, 100);
    clutter_actor_set_opacity (rect[2], 0);

    constraint = clutter_bind_constraint_new (rect[0], CLUTTER_BIND_X, 0.0);
    clutter_actor_add_constraint_with_name (rect[2], "blue-x", constraint);
    constraint = clutter_bind_constraint_new (rect[0], CLUTTER_BIND_Y, 0.0);
    clutter_actor_add_constraint_with_name (rect[2], "blue-y", constraint);

The following code animates the second and third rectangles to "expand" them horizontally from underneath the first rectangle:

    1
    2
    3
    4
    5
    6
    7
    8

    clutter_actor_animate (rect[1], CLUTTER_EASE_OUT_CUBIC, 250,
                           "@constraints.green-x.offset", 100.0,
                           "opacity", 255,
                           NULL);
    clutter_actor_animate (rect[2], CLUTTER_EASE_OUT_CUBIC, 250,
                           "@constraints.blue-x.offset", 200.0,
                           "opacity", 255,
                           NULL);

Example 10. Animating the offset property of ClutterBindConstraint

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

    #define RECT_SIZE       128

    #define H_PADDING       32
    #define V_PADDING       32

    enum
    {
      NorthWest,    North,  NorthEast,
      West,         Center, East,
      SouthWest,    South,  SouthEast,

      N_RECTS
    };

    static ClutterActor *rects[N_RECTS] = { NULL, };
    static const gchar *colors[N_RECTS] = {
      "#8ae234", "#73d216", "#4e9a06",
      "#729fcf", "#3465a4", "#204a87",
      "#ef2929", "#cc0000", "#a40000"
    };
    static const gchar *names[N_RECTS] = {
      "North West", "North",  "North East",
      "West",       "Center", "East",
      "South West", "South",  "South East"
    };

    static const gchar *desaturare_glsl_shader =
    "uniform sampler2D tex;\n"
    "uniform float factor;\n"
    "\n"
    "vec3 desaturate (const vec3 color, const float desaturation)\n"
    "{\n"
    "  const vec3 gray_conv = vec3 (0.299, 0.587, 0.114);\n"
    "  vec3 gray = vec3 (dot (gray_conv, color));\n"
    "  return vec3 (mix (color.rgb, gray, desaturation));\n"
    "}\n"
    "\n"
    "void main ()\n"
    "{\n"
    "  vec4 color = cogl_color_in * texture2D (tex, vec2 (cogl_tex_coord_in[0].xy));\n"
    "  color.rgb = desaturate (color.rgb, factor);\n"
    "  cogl_color_out = color;\n"
    "}\n";

    static gboolean      is_expanded = FALSE;

    static gboolean
    on_button_release (ClutterActor *actor,
                       ClutterEvent *event,
                       gpointer      data G_GNUC_UNUSED)
    {
      if (!is_expanded)
        {
          gfloat north_offset, south_offset;
          gfloat west_offset, east_offset;

          /* expand the 8 rectangles by animating the offset of the
           * bind constraints
           */

          north_offset = (clutter_actor_get_height (rects[Center]) + V_PADDING)
                       * -1.0f;
          south_offset = (clutter_actor_get_height (rects[Center]) + V_PADDING);

          west_offset = (clutter_actor_get_width (rects[Center]) + H_PADDING)
                      * -1.0f;
          east_offset = (clutter_actor_get_width (rects[Center]) + H_PADDING);

          clutter_actor_animate (rects[NorthWest], CLUTTER_EASE_OUT_EXPO, 500,
                                 "opacity", 255,
                                 "@constraints.x-bind.offset", west_offset,
                                 "@constraints.y-bind.offset", north_offset,
                                 "reactive", TRUE,
                                 NULL);
          clutter_actor_animate (rects[North], CLUTTER_EASE_OUT_EXPO, 500,
                                 "opacity", 255,
                                 "@constraints.y-bind.offset", north_offset,
                                 "reactive", TRUE,
                                 NULL);
          clutter_actor_animate (rects[NorthEast], CLUTTER_EASE_OUT_EXPO, 500,
                                 "opacity", 255,
                                 "@constraints.x-bind.offset", east_offset,
                                 "@constraints.y-bind.offset", north_offset,
                                 "reactive", TRUE,
                                 NULL);

          clutter_actor_animate (rects[West], CLUTTER_EASE_OUT_EXPO, 500,
                                 "opacity", 255,
                                 "@constraints.x-bind.offset", west_offset,
                                 "reactive", TRUE,
                                 NULL);
          /* turn on the desaturation effect and set the center
           * rectangle not reactive
           */
          clutter_actor_animate (rects[Center], CLUTTER_LINEAR, 500,
                                 "@effects.desaturate.enabled", TRUE,
                                 "reactive", FALSE,
                                 NULL);
          clutter_actor_animate (rects[East], CLUTTER_EASE_OUT_EXPO, 500,
                                 "opacity", 255,
                                 "@constraints.x-bind.offset", east_offset,
                                 "reactive", TRUE,
                                 NULL);

          clutter_actor_animate (rects[SouthWest], CLUTTER_EASE_OUT_EXPO, 500,
                                 "opacity", 255,
                                 "@constraints.x-bind.offset", west_offset,
                                 "@constraints.y-bind.offset", south_offset,
                                 "reactive", TRUE,
                                 NULL);
          clutter_actor_animate (rects[South], CLUTTER_EASE_OUT_EXPO, 500,
                                 "opacity", 255,
                                 "@constraints.y-bind.offset", south_offset,
                                 "reactive", TRUE,
                                 NULL);
          clutter_actor_animate (rects[SouthEast], CLUTTER_EASE_OUT_EXPO, 500,
                                 "opacity", 255,
                                 "@constraints.x-bind.offset", east_offset,
                                 "@constraints.y-bind.offset", south_offset,
                                 "reactive", TRUE,
                                 NULL);
        }
      else
        {
          gint i;

          clutter_actor_animate (rects[Center], CLUTTER_LINEAR, 500,
                                 "@effects.desaturate.enabled", FALSE,
                                 "reactive", TRUE,
                                 NULL);

          for (i = NorthWest; i < N_RECTS; i++)
            {
              if (i == Center)
                continue;

              /* put the 8 rectangles back into their initial state */
              clutter_actor_animate (rects[i], CLUTTER_EASE_OUT_EXPO, 500,
                                     "opacity", 0,
                                     "@constraints.x-bind.offset", 0.0f,
                                     "@constraints.y-bind.offset", 0.0f,
                                     "reactive", FALSE,
                                     NULL);
            }
        }

      is_expanded = !is_expanded;

      g_print ("Selected: [%s]\n", clutter_actor_get_name (actor));

      return TRUE;
    }

    G_MODULE_EXPORT int
    test_constraints_main (int argc, char *argv[])
    {
      ClutterActor *stage, *rect;
      ClutterConstraint *constraint;
      ClutterEffect *effect;
      ClutterColor rect_color;
      gint i;

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

      stage = clutter_stage_new ();
      g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
      clutter_stage_set_title (CLUTTER_STAGE (stage), "Constraints");
      clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
      clutter_actor_set_size (stage, 800, 600);

      /* main rectangle */
      clutter_color_from_string (&rect_color, "#3465a4");
      rect = clutter_rectangle_new ();
      g_signal_connect (rect, "button-release-event",
                        G_CALLBACK (on_button_release),
                        NULL);
      clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &rect_color);
      clutter_actor_set_size (rect, RECT_SIZE, RECT_SIZE);
      clutter_actor_set_reactive (rect, TRUE);
      clutter_actor_set_name (rect, names[Center]);
      clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);

      /* align the center rectangle to the center of the stage */
      constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5);
      clutter_actor_add_constraint_with_name (rect, "x-align", constraint);

      constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5);
      clutter_actor_add_constraint_with_name (rect, "y-align", constraint);

      /* this is the equivalent of the DesaturateEffect; we cannot animate
       * the factor because the animation API only understands GObject
       * properties; so we use the ActorMeta:enabled property to toggle
       * the shader
       */
      effect = clutter_shader_effect_new (CLUTTER_FRAGMENT_SHADER);
      clutter_shader_effect_set_shader_source (CLUTTER_SHADER_EFFECT (effect),
                                               desaturare_glsl_shader);
      clutter_shader_effect_set_uniform (CLUTTER_SHADER_EFFECT (effect),
                                         "tex", G_TYPE_INT, 1, 0);
      clutter_shader_effect_set_uniform (CLUTTER_SHADER_EFFECT (effect),
                                         "factor", G_TYPE_FLOAT, 1, 0.66);
      clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE);
      clutter_actor_add_effect_with_name (rect, "desaturate", effect);

      rects[Center] = rect;

      /* build the other rectangles, and bind their position and size
       * to the center rectangle. we are going to animate the offset
       * of the BindConstraints
       */
      for (i = 0; i < N_RECTS; i++)
        {
          if (i == Center)
            continue;

          clutter_color_from_string (&rect_color, colors[i]);
          rect = clutter_rectangle_new ();
          clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &rect_color);
          clutter_actor_set_opacity (rect, 0);
          clutter_actor_set_name (rect, names[i]);
          clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);

          constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_X, 0.0);
          clutter_actor_add_constraint_with_name (rect, "x-bind", constraint);

          constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_Y, 0.0);
          clutter_actor_add_constraint_with_name (rect, "y-bind", constraint);

          constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_SIZE, 0.0);
          clutter_actor_add_constraint_with_name (rect, "size-bind", constraint);

          g_signal_connect (rect, "button-release-event",
                            G_CALLBACK (on_button_release),
                            NULL);

          rects[i] = rect;
        }

      clutter_actor_show (stage);

      clutter_main ();

      return EXIT_SUCCESS;
    }

The example above creates eight rectangles and binds them to a rectangle positioned in the center of the stage; when the user presses the center rectangle, the "offset" property is animated through the `clutter_actor_animate()` function to lay out the eight rectangles around the center one. Pressing one of the outer rectangles will animate the offset back to 0.

ClutterBindConstraint is available since Clutter 1.4

## Details

### ClutterBindConstraint

    typedef struct _ClutterBindConstraint ClutterBindConstraint;

ClutterBindConstraint is an opaque structure whose members cannot be directly accessed

Since 1.4

### enum ClutterBindCoordinate

    typedef enum {
     /*< prefix=CLUTTER_BIND >*/
      CLUTTER_BIND_X,
      CLUTTER_BIND_Y,
      CLUTTER_BIND_WIDTH,
      CLUTTER_BIND_HEIGHT,
      CLUTTER_BIND_POSITION,
      CLUTTER_BIND_SIZE
    } ClutterBindCoordinate;

Specifies which property should be used in a binding

`CLUTTER_BIND_X` | Bind the X coordinate
`CLUTTER_BIND_Y` | Bind the Y coordinate
`CLUTTER_BIND_WIDTH` | Bind the width
`CLUTTER_BIND_HEIGHT` | Bind the height
`CLUTTER_BIND_POSITION` | Equivalent to to `CLUTTER_BIND_X` and `CLUTTER_BIND_Y`
`CLUTTER_BIND_SIZE` | Equivalent to `CLUTTER_BIND_WIDTH` and `CLUTTER_BIND_HEIGHT`

Since 1.4

### clutter_bind_constraint_new ()

    ClutterConstraint * clutter_bind_constraint_new         (ClutterActor *source,
                                                             ClutterBindCoordinate coordinate,
                                                             gfloat offset);

Creates a new constraint, binding a ClutterActor's position to the given `coordinate` of the position of `source`

`source` : | the ClutterActor to use as the source of the binding, or `NULL`. [allow-none]
`coordinate` : | the coordinate to bind
`offset` : | the offset to apply to the binding, in pixels
Returns : | the newly created ClutterBindConstraint

Since 1.4

### clutter_bind_constraint_set_source ()

    void                clutter_bind_constraint_set_source  (ClutterBindConstraint *constraint,
                                                             ClutterActor *source);

Sets the source ClutterActor for the constraint

`constraint` : | a ClutterBindConstraint
`source` : | a ClutterActor, or `NULL` to unset the source. [allow-none]

Since 1.4

### clutter_bind_constraint_get_source ()

    ClutterActor *      clutter_bind_constraint_get_source  (ClutterBindConstraint *constraint);

Retrieves the ClutterActor set using `clutter_bind_constraint_set_source()`

`constraint` : | a ClutterBindConstraint
Returns : | a pointer to the source actor. [transfer none]

Since 1.4

### clutter_bind_constraint_set_coordinate ()

    void                clutter_bind_constraint_set_coordinate
                                                            (ClutterBindConstraint *constraint,
                                                             ClutterBindCoordinate coordinate);

Sets the coordinate to bind in the constraint

`constraint` : | a ClutterBindConstraint
`coordinate` : | the coordinate to bind

Since 1.4

### clutter_bind_constraint_get_coordinate ()

    ClutterBindCoordinate clutter_bind_constraint_get_coordinate
                                                            (ClutterBindConstraint *constraint);

Retrieves the bound coordinate of the constraint

`constraint` : | a ClutterBindConstraint
Returns : | the bound coordinate

Since 1.4

### clutter_bind_constraint_set_offset ()

    void                clutter_bind_constraint_set_offset  (ClutterBindConstraint *constraint,
                                                             gfloat offset);

Sets the offset to be applied to the constraint

`constraint` : | a ClutterBindConstraint
`offset` : | the offset to apply, in pixels

Since 1.4

### clutter_bind_constraint_get_offset ()

    gfloat              clutter_bind_constraint_get_offset  (ClutterBindConstraint *constraint);

Retrieves the offset set using `clutter_bind_constraint_set_offset()`

`constraint` : | a ClutterBindConstraint
Returns : | the offset, in pixels

Since 1.4

## Property Details

### The `"coordinate"` property

      "coordinate"               ClutterBindCoordinate  : Read / Write / Construct

The coordinate to be bound

Default value: CLUTTER_BIND_X

Since 1.4

### The `"offset"` property

      "offset"                   gfloat                : Read / Write / Construct

The offset, in pixels, to be applied to the binding

Default value: 0

Since 1.4

### The `"source"` property

      "source"                   ClutterActor*         : Read / Write / Construct

The ClutterActor used as the source for the binding.

The ClutterActor must not be contained inside the actor associated to the constraint.

Since 1.4