actor: Add pivot point
The pivot point is a point in normalized coordinates space around which all transformations revolve. It supercedes the anchor point and the per-transformation center points as well as the gravity settings, and tries to sort out the mess that is the modelview matrix set up in ClutterActor. https://bugzilla.gnome.org/show_bug.cgi?id=677853
This commit is contained in:
parent
b20e9b78e5
commit
1fd0f4b9a5
@ -201,6 +201,9 @@ struct _ClutterTransformInfo
|
||||
|
||||
/* z_position */
|
||||
gfloat z_position;
|
||||
|
||||
/* transformation center */
|
||||
ClutterPoint pivot;
|
||||
};
|
||||
|
||||
const ClutterTransformInfo * _clutter_actor_get_transform_info_or_defaults (ClutterActor *self);
|
||||
|
@ -870,6 +870,8 @@ enum
|
||||
PROP_REALIZED,
|
||||
PROP_REACTIVE,
|
||||
|
||||
PROP_PIVOT_POINT,
|
||||
|
||||
PROP_SCALE_X,
|
||||
PROP_SCALE_Y,
|
||||
PROP_SCALE_CENTER_X,
|
||||
@ -2946,9 +2948,18 @@ clutter_actor_real_apply_transform (ClutterActor *self,
|
||||
{
|
||||
CoglMatrix *transform = &priv->transform;
|
||||
const ClutterTransformInfo *info;
|
||||
float pivot_x = 0.f, pivot_y = 0.f;
|
||||
|
||||
info = _clutter_actor_get_transform_info_or_defaults (self);
|
||||
|
||||
if (!clutter_point_equals (&info->pivot, clutter_point_zero ()))
|
||||
{
|
||||
pivot_x = (priv->allocation.x2 - priv->allocation.x1)
|
||||
* info->pivot.x;
|
||||
pivot_y = (priv->allocation.y2 - priv->allocation.y1)
|
||||
* info->pivot.y;
|
||||
}
|
||||
|
||||
cogl_matrix_init_identity (transform);
|
||||
|
||||
cogl_matrix_translate (transform,
|
||||
@ -2959,6 +2970,10 @@ clutter_actor_real_apply_transform (ClutterActor *self,
|
||||
if (info->z_position != 0.f)
|
||||
cogl_matrix_translate (transform, 0, 0, info->z_position);
|
||||
|
||||
/* pivot point, used as the transformation center */
|
||||
if (pivot_x != 0.f || pivot_y != 0.f)
|
||||
cogl_matrix_translate (transform, pivot_x, pivot_y, 0.f);
|
||||
|
||||
/*
|
||||
* because the rotation involves translations, we must scale
|
||||
* before applying the rotations (if we apply the scale after
|
||||
@ -3005,6 +3020,10 @@ clutter_actor_real_apply_transform (ClutterActor *self,
|
||||
cogl_matrix_translate (transform, -x, -y, -z);
|
||||
}
|
||||
|
||||
/* roll back the pivot translation */
|
||||
if (pivot_x != 0.f || pivot_y != 0.f)
|
||||
cogl_matrix_translate (transform, -pivot_x, -pivot_y, 0.f);
|
||||
|
||||
priv->transform_valid = TRUE;
|
||||
}
|
||||
|
||||
@ -4066,15 +4085,17 @@ clutter_actor_remove_child_internal (ClutterActor *self,
|
||||
}
|
||||
|
||||
static const ClutterTransformInfo default_transform_info = {
|
||||
0.0, { 0, }, /* rotation-x */
|
||||
0.0, { 0, }, /* rotation-y */
|
||||
0.0, { 0, }, /* rotation-z */
|
||||
0.0, { 0, }, /* rotation-x */
|
||||
0.0, { 0, }, /* rotation-y */
|
||||
0.0, { 0, }, /* rotation-z */
|
||||
|
||||
1.0, 1.0, { 0, }, /* scale */
|
||||
1.0, 1.0, { 0, }, /* scale */
|
||||
|
||||
{ 0, }, /* anchor */
|
||||
{ 0, }, /* anchor */
|
||||
|
||||
0.0, /* depth */
|
||||
0.0, /* z-position */
|
||||
|
||||
CLUTTER_POINT_INIT_ZERO, /* pivot */
|
||||
};
|
||||
|
||||
/*< private >
|
||||
@ -4146,6 +4167,22 @@ _clutter_actor_get_transform_info (ClutterActor *self)
|
||||
return info;
|
||||
}
|
||||
|
||||
static inline void
|
||||
clutter_actor_set_pivot_point_internal (ClutterActor *self,
|
||||
const ClutterPoint *pivot)
|
||||
{
|
||||
ClutterTransformInfo *info;
|
||||
|
||||
info = _clutter_actor_get_transform_info (self);
|
||||
info->pivot = *pivot;
|
||||
|
||||
self->priv->transform_valid = FALSE;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PIVOT_POINT]);
|
||||
|
||||
clutter_actor_queue_redraw (self);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* clutter_actor_set_rotation_angle_internal:
|
||||
* @self: a #ClutterActor
|
||||
@ -4593,6 +4630,17 @@ clutter_actor_set_property (GObject *object,
|
||||
clutter_actor_hide (actor);
|
||||
break;
|
||||
|
||||
case PROP_PIVOT_POINT:
|
||||
{
|
||||
const ClutterPoint *pivot = g_value_get_boxed (value);
|
||||
|
||||
if (pivot == NULL)
|
||||
pivot = clutter_point_zero ();
|
||||
|
||||
clutter_actor_set_pivot_point (actor, pivot->x, pivot->y);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_SCALE_X:
|
||||
clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
|
||||
g_value_get_double (value));
|
||||
@ -4970,6 +5018,15 @@ clutter_actor_get_property (GObject *object,
|
||||
g_value_set_boolean (value, priv->clip_to_allocation);
|
||||
break;
|
||||
|
||||
case PROP_PIVOT_POINT:
|
||||
{
|
||||
const ClutterTransformInfo *info;
|
||||
|
||||
info = _clutter_actor_get_transform_info_or_defaults (actor);
|
||||
g_value_set_boxed (value, &info->pivot);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_SCALE_X:
|
||||
{
|
||||
const ClutterTransformInfo *info;
|
||||
@ -6219,6 +6276,28 @@ clutter_actor_class_init (ClutterActorClass *klass)
|
||||
NULL,
|
||||
CLUTTER_PARAM_READWRITE);
|
||||
|
||||
/**
|
||||
* ClutterActor:pivot-point:
|
||||
*
|
||||
* The point around which the scaling and rotation transformations occur.
|
||||
*
|
||||
* The pivot point is expressed in normalized coordinates space, with (0, 0)
|
||||
* being the top left corner of the actor and (1, 1) the bottom right corner
|
||||
* of the actor.
|
||||
*
|
||||
* The #ClutterActor:pivot property is animatable.
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
obj_props[PROP_PIVOT_POINT] =
|
||||
g_param_spec_boxed ("pivot-point",
|
||||
P_("Pivot Point"),
|
||||
P_("The point around which the scaling and rotation occur"),
|
||||
CLUTTER_TYPE_POINT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
CLUTTER_PARAM_ANIMATABLE);
|
||||
|
||||
/**
|
||||
* ClutterActor:scale-x:
|
||||
*
|
||||
@ -10935,6 +11014,74 @@ clutter_actor_get_z_position (ClutterActor *self)
|
||||
return _clutter_actor_get_transform_info_or_defaults (self)->z_position;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_set_pivot_point:
|
||||
* @self: a #ClutterActor
|
||||
* @pivot_x: the normalized X coordinate of the pivot point
|
||||
* @pivot_y: the normalized Y coordinate of the pivot point
|
||||
*
|
||||
* Sets the position of the #ClutterActor:pivot-point around which the
|
||||
* scaling and rotation transformations occur.
|
||||
*
|
||||
* The pivot point's coordinates are in normalized space, with the (0, 0)
|
||||
* point being the top left corner of the actor, and the (1, 1) point being
|
||||
* the bottom right corner.
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
void
|
||||
clutter_actor_set_pivot_point (ClutterActor *self,
|
||||
gfloat pivot_x,
|
||||
gfloat pivot_y)
|
||||
{
|
||||
ClutterPoint pivot = CLUTTER_POINT_INIT (pivot_x, pivot_y);
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
||||
|
||||
if (_clutter_actor_get_transition (self, obj_props[PROP_PIVOT_POINT]) == NULL)
|
||||
{
|
||||
const ClutterTransformInfo *info;
|
||||
|
||||
info = _clutter_actor_get_transform_info_or_defaults (self);
|
||||
|
||||
_clutter_actor_create_transition (self, obj_props[PROP_PIVOT_POINT],
|
||||
&info->pivot,
|
||||
&pivot);
|
||||
}
|
||||
else
|
||||
_clutter_actor_update_transition (self, obj_props[PROP_PIVOT_POINT], &pivot);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_get_pivot_point:
|
||||
* @self: a #ClutterActor
|
||||
* @pivot_x: (out) (allow-none): return location for the normalized X
|
||||
* coordinate of the pivot point, or %NULL
|
||||
* @pivot_y: (out) (allow-none): return location for the normalized Y
|
||||
* coordinate of the pivot point, or %NULL
|
||||
*
|
||||
* Retrieves the coordinates of the #ClutterActor:pivot-point.
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
void
|
||||
clutter_actor_get_pivot_point (ClutterActor *self,
|
||||
gfloat *pivot_x,
|
||||
gfloat *pivot_y)
|
||||
{
|
||||
const ClutterTransformInfo *info;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
||||
|
||||
info = _clutter_actor_get_transform_info_or_defaults (self);
|
||||
|
||||
if (pivot_x != NULL)
|
||||
*pivot_y = info->pivot.x;
|
||||
|
||||
if (pivot_y != NULL)
|
||||
*pivot_y = info->pivot.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_set_depth:
|
||||
* @self: a #ClutterActor
|
||||
@ -13764,6 +13911,10 @@ clutter_actor_set_animatable_property (ClutterActor *actor,
|
||||
clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
|
||||
break;
|
||||
|
||||
case PROP_PIVOT_POINT:
|
||||
clutter_actor_set_pivot_point_internal (actor, g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_SCALE_X:
|
||||
clutter_actor_set_scale_factor_internal (actor,
|
||||
g_value_get_double (value),
|
||||
|
@ -625,6 +625,14 @@ gboolean clutter_actor_iter_is_valid
|
||||
/* Transformations */
|
||||
gboolean clutter_actor_is_rotated (ClutterActor *self);
|
||||
gboolean clutter_actor_is_scaled (ClutterActor *self);
|
||||
CLUTTER_AVAILABLE_IN_1_12
|
||||
void clutter_actor_set_pivot_point (ClutterActor *self,
|
||||
gfloat pivot_x,
|
||||
gfloat pivot_y);
|
||||
CLUTTER_AVAILABLE_IN_1_12
|
||||
void clutter_actor_get_pivot_point (ClutterActor *self,
|
||||
gfloat *pivot_x,
|
||||
gfloat *pivot_y);
|
||||
void clutter_actor_set_rotation (ClutterActor *self,
|
||||
ClutterRotateAxis axis,
|
||||
gdouble angle,
|
||||
|
@ -130,6 +130,7 @@ clutter_actor_get_paint_visibility
|
||||
clutter_actor_get_paint_volume
|
||||
clutter_actor_get_pango_context
|
||||
clutter_actor_get_parent
|
||||
clutter_actor_get_pivot_point
|
||||
clutter_actor_get_position
|
||||
clutter_actor_get_preferred_height
|
||||
clutter_actor_get_preferred_size
|
||||
@ -252,6 +253,7 @@ clutter_actor_set_name
|
||||
clutter_actor_set_offscreen_redirect
|
||||
clutter_actor_set_opacity
|
||||
clutter_actor_set_parent
|
||||
clutter_actor_set_pivot_point
|
||||
clutter_actor_set_position
|
||||
clutter_actor_set_reactive
|
||||
clutter_actor_set_request_mode
|
||||
|
Loading…
Reference in New Issue
Block a user