Merge branch 'scale-center'
authorNeil Roberts <neil@linux.intel.com>
Wed, 28 Jan 2009 09:08:19 +0000 (09:08 +0000)
committerNeil Roberts <neil@linux.intel.com>
Wed, 28 Jan 2009 15:39:51 +0000 (15:39 +0000)
Bug 1349 - Using the anchor point to set the scale center is messy

The branch adds an extra center point for scaling which can be used
for example to set a scale about the center without affecting the
position of the actor.

The scale center can be specified as a unit offset from the origin or
as a gravity. If specified as a gravity it will be stored as a
fraction of the actor's size so that the position will track when the
actor changes size.

The anchor point and rotation centers have been modified so they can
be set with a gravity in the same way. However, only the Z rotation
exposes a property to set using a gravity because the other two
require a Z coordinate which doesn't make sense to interpret as a
fraction of the actor's width or height.

Conflicts:

clutter/clutter-actor.c

1  2 
clutter/clutter-actor.c
doc/reference/clutter/clutter-sections.txt

@@@ -1372,54 -1434,30 +1437,32 @@@ _clutter_actor_apply_modelview_transfor
     * entire object will move on the screen as a result of rotating it).
     */
    if (priv->scale_x != 1.0 || priv->scale_y != 1.0)
-     cogl_scale (priv->scale_x, priv->scale_y, 1.0);
-    if (priv->rzang)
-     {
-       cogl_translate (CLUTTER_UNITS_TO_FLOAT (priv->rzx),
-                      CLUTTER_UNITS_TO_FLOAT (priv->rzy),
-                      0);
+     TRANSFORM_ABOUT_ANCHOR_COORD (self, &priv->scale_center,
 -                                  cogl_scale (priv->scale_x, priv->scale_y));
++                                  cogl_scale (priv->scale_x,
++                                              priv->scale_y,
++                                              1.0));
  
-       cogl_rotate (priv->rzang, 0, 0, 1.0);
-       cogl_translate (CLUTTER_UNITS_TO_FLOAT (-priv->rzx),
-                      CLUTTER_UNITS_TO_FLOAT (-priv->rzy),
-                      0);
-     }
+   if (priv->rzang)
+     TRANSFORM_ABOUT_ANCHOR_COORD (self, &priv->rz_center,
+                                   cogl_rotate (priv->rzang,
+                                                0, 0, 1.0));
  
    if (priv->ryang)
-     {
-       cogl_translate (CLUTTER_UNITS_TO_FLOAT (priv->ryx),
-                      0,
-                      CLUTTER_UNITS_TO_FLOAT (priv->z + priv->ryz));
-       cogl_rotate (priv->ryang, 0, 1.0, 0);
-       cogl_translate (CLUTTER_UNITS_TO_FLOAT (-priv->ryx),
-                      0,
-                      CLUTTER_UNITS_TO_FLOAT (-(priv->z + priv->ryz)));
-     }
+     TRANSFORM_ABOUT_ANCHOR_COORD (self, &priv->ry_center,
+                                   cogl_rotate (priv->ryang,
+                                                0, 1.0, 0));
  
    if (priv->rxang)
-     {
-       cogl_translate (0,
-                      CLUTTER_UNITS_TO_FLOAT (priv->rxy),
-                      CLUTTER_UNITS_TO_FLOAT (priv->z + priv->rxz));
-       cogl_rotate (priv->rxang, 1.0, 0, 0);
+     TRANSFORM_ABOUT_ANCHOR_COORD (self, &priv->rx_center,
+                                   cogl_rotate (priv->rxang,
+                                                1.0, 0, 0));
  
-       cogl_translate (0,
-                      CLUTTER_UNITS_TO_FLOAT (-priv->rxy),
-                      CLUTTER_UNITS_TO_FLOAT (-(priv->z + priv->rxz)));
+   if (!is_stage && !clutter_anchor_coord_is_zero (&priv->anchor))
+     {
+       ClutterUnit x, y, z;
+       clutter_anchor_coord_get_units (self, &priv->anchor, &x, &y, &z);
+       cogl_translate (-x, -y, -z);
      }
-   if (!is_stage && (priv->anchor_x || priv->anchor_y))
-     cogl_translate (CLUTTER_UNITS_TO_FLOAT (-priv->anchor_x),
-                    CLUTTER_UNITS_TO_FLOAT (-priv->anchor_y),
-                    0);
-   if (priv->z)
-     cogl_translate (0, 0, priv->z);
  }
  
  /* Recursively applies the transforms associated with this actor and
@@@ -7798,25 -8073,161 +8095,183 @@@ clutter_actor_create_pango_context (Clu
    return retval;
  }
  
 +/* Allows overriding the parent traversed when querying an actors paint
 + * opacity. Used by ClutterClone. */
 +void
 +_clutter_actor_set_opacity_parent (ClutterActor *self,
 +                                   ClutterActor *parent)
 +{
 +  g_return_if_fail (CLUTTER_IS_ACTOR (self));
 +
 +  self->priv->opacity_parent = parent;
 +}
 +
 +/* Allows you to disable applying the actors model view transform during
 + * a paint. Used by ClutterClone. */
 +void
 +_clutter_actor_set_enable_model_view_transform (ClutterActor *self,
 +                                                gboolean      enable)
 +{
 +  g_return_if_fail (CLUTTER_IS_ACTOR (self));
 +
 +  self->priv->enable_model_view_transform = enable;
 +}
 +
+ static void
+ clutter_anchor_coord_get_units (ClutterActor      *self,
+                                 const AnchorCoord *coord,
+                                 ClutterUnit       *x,
+                                 ClutterUnit       *y,
+                                 ClutterUnit       *z)
+ {
+   if (G_UNLIKELY (coord->is_fractional))
+     {
+       ClutterUnit actor_width, actor_height;
+       clutter_actor_get_sizeu (self, &actor_width, &actor_height);
+       if (x)
+         *x = actor_width * coord->v.fraction.x;
+       if (y)
+         *y = actor_height * coord->v.fraction.y;
+       if (z)
+         *z = 0;
+     }
+   else
+     {
+       if (x)
+         *x = coord->v.units.x;
+       if (y)
+         *y = coord->v.units.y;
+       if (z)
+         *z = coord->v.units.z;
+     }
+ }
+ static void
+ clutter_anchor_coord_set_units (AnchorCoord            *coord,
+                                 ClutterUnit             x,
+                                 ClutterUnit             y,
+                                 ClutterUnit             z)
+ {
+   coord->is_fractional = FALSE;
+   coord->v.units.x = x;
+   coord->v.units.y = y;
+   coord->v.units.z = z;
+ }
+ static ClutterGravity
+ clutter_anchor_coord_get_gravity (AnchorCoord *coord)
+ {
+   if (coord->is_fractional)
+     {
+       if (coord->v.fraction.x == 0.0)
+         {
+           if (coord->v.fraction.y == 0.0)
+             return CLUTTER_GRAVITY_NORTH_WEST;
+           else if (coord->v.fraction.y == 0.5)
+             return CLUTTER_GRAVITY_WEST;
+           else if (coord->v.fraction.y == 1.0)
+             return CLUTTER_GRAVITY_SOUTH_WEST;
+           else
+             return CLUTTER_GRAVITY_NONE;
+         }
+       else if (coord->v.fraction.x == 0.5)
+         {
+           if (coord->v.fraction.y == 0.0)
+             return CLUTTER_GRAVITY_NORTH;
+           else if (coord->v.fraction.y == 0.5)
+             return CLUTTER_GRAVITY_CENTER;
+           else if (coord->v.fraction.y == 1.0)
+             return CLUTTER_GRAVITY_SOUTH;
+           else
+             return CLUTTER_GRAVITY_NONE;
+         }
+       else if (coord->v.fraction.x == 1.0)
+         {
+           if (coord->v.fraction.y == 0.0)
+             return CLUTTER_GRAVITY_NORTH_EAST;
+           else if (coord->v.fraction.y == 0.5)
+             return CLUTTER_GRAVITY_EAST;
+           else if (coord->v.fraction.y == 1.0)
+             return CLUTTER_GRAVITY_SOUTH_EAST;
+           else
+             return CLUTTER_GRAVITY_NONE;
+         }
+       else
+         return CLUTTER_GRAVITY_NONE;
+     }
+   else
+     return CLUTTER_GRAVITY_NONE;
+ }
+ static void
+ clutter_anchor_coord_set_gravity (AnchorCoord *coord,
+                                   ClutterGravity gravity)
+ {
+   switch (gravity)
+     {
+     case CLUTTER_GRAVITY_NORTH:
+       coord->v.fraction.x = 0.5;
+       coord->v.fraction.y = 0.0;
+       break;
+     case CLUTTER_GRAVITY_NORTH_EAST:
+       coord->v.fraction.x = 1.0;
+       coord->v.fraction.y = 0.0;
+       break;
+     case CLUTTER_GRAVITY_EAST:
+       coord->v.fraction.x = 1.0;
+       coord->v.fraction.y = 0.5;
+       break;
+     case CLUTTER_GRAVITY_SOUTH_EAST:
+       coord->v.fraction.x = 1.0;
+       coord->v.fraction.y = 1.0;
+       break;
+     case CLUTTER_GRAVITY_SOUTH:
+       coord->v.fraction.x = 0.5;
+       coord->v.fraction.y = 1.0;
+       break;
+     case CLUTTER_GRAVITY_SOUTH_WEST:
+       coord->v.fraction.x = 0.0;
+       coord->v.fraction.y = 1.0;
+       break;
+     case CLUTTER_GRAVITY_WEST:
+       coord->v.fraction.x = 0.0;
+       coord->v.fraction.y = 0.5;
+       break;
+     case CLUTTER_GRAVITY_NORTH_WEST:
+       coord->v.fraction.x = 0.0;
+       coord->v.fraction.y = 0.0;
+       break;
+     case CLUTTER_GRAVITY_CENTER:
+       coord->v.fraction.x = 0.5;
+       coord->v.fraction.y = 0.5;
+       break;
+     default:
+       coord->v.fraction.x = 0.0;
+       coord->v.fraction.y = 0.0;
+       break;
+     }
+   coord->is_fractional = TRUE;
+ }
+ static gboolean
+ clutter_anchor_coord_is_zero (const AnchorCoord *coord)
+ {
+   if (coord->is_fractional)
+     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
+   else
+     return (coord->v.units.x == 0.0
+             && coord->v.units.y == 0.0
+             && coord->v.units.z == 0.0);
+ }