From e10d255b83071014219a54e2f3d5c31444df340f Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 23 Jan 2009 11:11:24 +0000 Subject: [PATCH] Add a scale center property to ClutterActor This sets the center point from which the scaling will occur. This can be used insetad of the anchor point to avoid moving the actor. Like the anchor point, it can be specified as either a coordinate in units or a gravity enum. To set the center you can use two new variants of set_scale: clutter_actor_set_scale_full (ClutterActor *self, gdouble scale_x, gdouble scale_y, int center_x, int center_y); or clutter_actor_set_scale_with_gravity (ClutterActor *self, gdouble scale_x, gdouble scale_y, ClutterGravity gravity); The ClutterFixed variants of the set_scale functions have been removed and the scale value is now always stored as a double. --- clutter/clutter-actor.c | 279 +++++++++++++++++++++++------- clutter/clutter-actor.h | 27 ++- clutter/clutter-behaviour-scale.c | 4 +- 3 files changed, 245 insertions(+), 65 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 999c7f686..3bb885f4b 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -279,8 +279,10 @@ struct _ClutterActorPrivate gchar *name; guint32 id; /* Unique ID */ - ClutterFixed scale_x; - ClutterFixed scale_y; + gdouble scale_x; + gdouble scale_y; + + AnchorCoord scale_center; ShaderData *shader_data; @@ -341,6 +343,9 @@ enum PROP_SCALE_X, PROP_SCALE_Y, + PROP_SCALE_CENTER_X, + PROP_SCALE_CENTER_Y, + PROP_SCALE_GRAVITY, PROP_ROTATION_ANGLE_X, PROP_ROTATION_ANGLE_Y, @@ -1424,7 +1429,8 @@ _clutter_actor_apply_modelview_transform (ClutterActor *self) * 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); + TRANSFORM_ABOUT_ANCHOR_COORD (self, &priv->scale_center, + cogl_scale (priv->scale_x, priv->scale_y)); if (priv->rzang) { @@ -1726,16 +1732,48 @@ clutter_actor_set_property (GObject *object, clutter_actor_hide (actor); break; case PROP_SCALE_X: - clutter_actor_set_scalex - (actor, - CLUTTER_FLOAT_TO_FIXED (g_value_get_double (value)), - priv->scale_y); + clutter_actor_set_scale (actor, + g_value_get_double (value), + priv->scale_y); break; case PROP_SCALE_Y: - clutter_actor_set_scalex - (actor, - priv->scale_x, - CLUTTER_FLOAT_TO_FIXED (g_value_get_double (value))); + clutter_actor_set_scale (actor, + priv->scale_x, + g_value_get_double (value)); + break; + case PROP_SCALE_CENTER_X: + { + int center_x = g_value_get_int (value); + ClutterUnit center_y; + + clutter_anchor_coord_get_units (actor, &priv->scale_center, + NULL, ¢er_y, NULL); + clutter_actor_set_scale_fullu (actor, + priv->scale_x, + priv->scale_y, + CLUTTER_UNITS_FROM_DEVICE (center_x), + center_y); + } + break; + case PROP_SCALE_CENTER_Y: + { + ClutterUnit center_x; + gint center_y = g_value_get_int (value); + + clutter_anchor_coord_get_units (actor, &priv->scale_center, + ¢er_x, NULL, NULL); + clutter_actor_set_scale_fullu (actor, + priv->scale_x, + priv->scale_y, + center_x, + CLUTTER_UNITS_FROM_DEVICE (center_y)); + } + break; + case PROP_SCALE_GRAVITY: + clutter_actor_set_scale_with_gravity (actor, + priv->scale_x, + priv->scale_y, + g_value_get_enum (value)); break; case PROP_CLIP: { @@ -1961,10 +1999,27 @@ clutter_actor_get_property (GObject *object, } break; case PROP_SCALE_X: - g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->scale_x)); + g_value_set_double (value, priv->scale_x); break; case PROP_SCALE_Y: - g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->scale_y)); + g_value_set_double (value, priv->scale_y); + break; + case PROP_SCALE_CENTER_X: + { + gint center; + clutter_actor_get_scale_center (actor, ¢er, NULL); + g_value_set_int (value, center); + } + break; + case PROP_SCALE_CENTER_Y: + { + gint center; + clutter_actor_get_scale_center (actor, NULL, ¢er); + g_value_set_int (value, center); + } + break; + case PROP_SCALE_GRAVITY: + g_value_set_enum (value, clutter_actor_get_scale_gravity (actor)); break; case PROP_REACTIVE: g_value_set_boolean (value, clutter_actor_get_reactive (actor)); @@ -2553,6 +2608,51 @@ clutter_actor_class_init (ClutterActorClass *klass) G_MAXDOUBLE, 1.0, CLUTTER_PARAM_READWRITE)); + + /** + * ClutterActor:scale-center-x: + * + * The horizontal center point for scaling + * + * Since: 1.0 + */ + pspec = g_param_spec_int ("scale-center-x", + "Scale-Center-X", + "Horizontal scale center", + G_MININT, G_MAXINT, 0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_SCALE_CENTER_X, pspec); + + /** + * ClutterActor:scale-center-y: + * + * The vertical center point for scaling + * + * Since: 1.0 + */ + pspec = g_param_spec_int ("scale-center-y", + "Scale-Center-Y", + "Vertical scale center", + G_MININT, G_MAXINT, 0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_SCALE_CENTER_Y, pspec); + + /** + * ClutterActor:scale-gravity: + * + * The center point for scaling expressed as a #ClutterGravity + * + * Since: 1.0 + */ + pspec = g_param_spec_enum ("scale-gravity", + "Scale-Gravity", + "The center of scaling", + CLUTTER_TYPE_GRAVITY, + CLUTTER_GRAVITY_NONE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, + PROP_SCALE_GRAVITY, pspec); + /** * ClutterActor:rotation-angle-x: * @@ -5018,20 +5118,20 @@ clutter_actor_get_yu (ClutterActor *self) } /** - * clutter_actor_set_scalex: + * clutter_actor_set_scale: * @self: A #ClutterActor - * @scale_x: #ClutterFixed factor to scale actor by horizontally. - * @scale_y: #ClutterFixed factor to scale actor by vertically. - * - * Fixed point version of clutter_actor_set_scale(). + * @scale_x: double factor to scale actor by horizontally. + * @scale_y: double factor to scale actor by vertically. * * Scales an actor with the given factors. The scaling is always * relative to the anchor point. + * + * Since: 0.2 */ void -clutter_actor_set_scalex (ClutterActor *self, - ClutterFixed scale_x, - ClutterFixed scale_y) +clutter_actor_set_scale (ClutterActor *self, + gdouble scale_x, + gdouble scale_y) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -5045,59 +5145,86 @@ clutter_actor_set_scalex (ClutterActor *self, g_object_notify (G_OBJECT (self), "scale-y"); g_object_thaw_notify (G_OBJECT (self)); - g_object_unref (self); if (CLUTTER_ACTOR_IS_VISIBLE (self)) clutter_actor_queue_redraw (self); + + g_object_unref (self); } -/** - * clutter_actor_set_scale: - * @self: A #ClutterActor - * @scale_x: double factor to scale actor by horizontally. - * @scale_y: double factor to scale actor by vertically. - * - * Scales an actor with the given factors. The scaling is always - * relative to the anchor point. - * - * Since: 0.2 - */ void -clutter_actor_set_scale (ClutterActor *self, - gdouble scale_x, - gdouble scale_y) +clutter_actor_set_scale_full (ClutterActor *self, + gdouble scale_x, + gdouble scale_y, + int center_x, + int center_y) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); - clutter_actor_set_scalex (self, - CLUTTER_FLOAT_TO_FIXED (scale_x), - CLUTTER_FLOAT_TO_FIXED (scale_y)); + clutter_actor_set_scale_fullu (self, scale_x, scale_y, + CLUTTER_UNITS_FROM_DEVICE (center_x), + CLUTTER_UNITS_FROM_DEVICE (center_y)); } -/** - * clutter_actor_get_scalex: - * @self: A #ClutterActor - * @scale_x: Location to store horizonal scale factor, or %NULL. - * @scale_y: Location to store vertical scale factor, or %NULL. - * - * Fixed point version of clutter_actor_get_scale(). - * - * Retrieves the scale factors of an actor. - * - * Since: 0.2 - */ void -clutter_actor_get_scalex (ClutterActor *self, - ClutterFixed *scale_x, - ClutterFixed *scale_y) +clutter_actor_set_scale_fullu (ClutterActor *self, + gdouble scale_x, + gdouble scale_y, + ClutterUnit center_x, + ClutterUnit center_y) { + ClutterActorPrivate *priv; + g_return_if_fail (CLUTTER_IS_ACTOR (self)); - if (scale_x) - *scale_x = self->priv->scale_x; + priv = self->priv; - if (scale_y) - *scale_y = self->priv->scale_y; + g_object_ref (self); + g_object_freeze_notify (G_OBJECT (self)); + + clutter_actor_set_scale (self, scale_x, scale_y); + + if (priv->scale_center.is_fractional) + g_object_notify (G_OBJECT (self), "scale-gravity"); + g_object_notify (G_OBJECT (self), "scale-center-x"); + g_object_notify (G_OBJECT (self), "scale-center-y"); + + clutter_anchor_coord_set_units (&priv->scale_center, center_x, center_y, 0); + + g_object_thaw_notify (G_OBJECT (self)); + g_object_unref (self); +} + +void +clutter_actor_set_scale_with_gravity (ClutterActor *self, + gdouble scale_x, + gdouble scale_y, + ClutterGravity gravity) +{ + ClutterActorPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + priv = self->priv; + + if (gravity == CLUTTER_GRAVITY_NONE) + clutter_actor_set_scale_full (self, scale_x, scale_y, 0, 0); + else + { + g_object_ref (self); + g_object_freeze_notify (G_OBJECT (self)); + + clutter_actor_set_scale (self, scale_x, scale_y); + + g_object_notify (G_OBJECT (self), "scale-gravity"); + g_object_notify (G_OBJECT (self), "scale-center-x"); + g_object_notify (G_OBJECT (self), "scale-center-y"); + + clutter_anchor_coord_set_gravity (&priv->scale_center, gravity); + + g_object_thaw_notify (G_OBJECT (self)); + g_object_unref (self); + } } /** @@ -5124,6 +5251,42 @@ clutter_actor_get_scale (ClutterActor *self, *scale_y = CLUTTER_FIXED_TO_FLOAT (self->priv->scale_y); } +void +clutter_actor_get_scale_center (ClutterActor *self, + gint *center_x, + gint *center_y) +{ + ClutterUnit xu, yu; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + clutter_actor_get_scale_centeru (self, &xu, &yu); + + if (center_x) + *center_x = CLUTTER_UNITS_TO_DEVICE (xu); + if (center_y) + *center_y = CLUTTER_UNITS_TO_DEVICE (yu); +} + +void +clutter_actor_get_scale_centeru (ClutterActor *self, + ClutterUnit *center_x, + ClutterUnit *center_y) +{ + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + clutter_anchor_coord_get_units (self, &self->priv->scale_center, + center_x, center_y, NULL); +} + +ClutterGravity +clutter_actor_get_scale_gravity (ClutterActor *self) +{ + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE); + + return clutter_anchor_coord_get_gravity (&self->priv->scale_center); +} + /** * clutter_actor_set_opacity: * @self: A #ClutterActor diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index d9748fcb8..8faa64cf4 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -474,18 +474,33 @@ void clutter_actor_set_depthu (ClutterActor ClutterUnit depth); ClutterUnit clutter_actor_get_depthu (ClutterActor *self); -void clutter_actor_set_scalex (ClutterActor *self, - ClutterFixed scale_x, - ClutterFixed scale_y); void clutter_actor_set_scale (ClutterActor *self, gdouble scale_x, gdouble scale_y); -void clutter_actor_get_scalex (ClutterActor *self, - ClutterFixed *scale_x, - ClutterFixed *scale_y); +void clutter_actor_set_scale_full (ClutterActor *self, + gdouble scale_x, + gdouble scale_y, + int center_x, + int center_y); +void clutter_actor_set_scale_fullu (ClutterActor *self, + gdouble scale_x, + gdouble scale_y, + ClutterUnit center_x, + ClutterUnit center_y); +void clutter_actor_set_scale_with_gravity (ClutterActor *self, + gdouble scale_x, + gdouble scale_y, + ClutterGravity gravity); void clutter_actor_get_scale (ClutterActor *self, gdouble *scale_x, gdouble *scale_y); +void clutter_actor_get_scale_center (ClutterActor *self, + gint *center_x, + gint *center_y); +void clutter_actor_get_scale_centeru (ClutterActor *self, + ClutterUnit *center_x, + ClutterUnit *center_y); +ClutterGravity clutter_actor_get_scale_gravity (ClutterActor *self); void clutter_actor_move_by (ClutterActor *self, gint dx, diff --git a/clutter/clutter-behaviour-scale.c b/clutter/clutter-behaviour-scale.c index 89b56958f..449f31bed 100644 --- a/clutter/clutter-behaviour-scale.c +++ b/clutter/clutter-behaviour-scale.c @@ -85,7 +85,9 @@ scale_frame_foreach (ClutterBehaviour *behaviour, { ScaleFrameClosure *closure = data; - clutter_actor_set_scalex (actor, closure->scale_x, closure->scale_y); + clutter_actor_set_scale (actor, + CLUTTER_FIXED_TO_DOUBLE (closure->scale_x), + CLUTTER_FIXED_TO_DOUBLE (closure->scale_y)); } static void