Merge branch 'scale-center'

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
This commit is contained in:
Neil Roberts 2009-01-28 09:08:19 +00:00
commit 3e68b23ea8
8 changed files with 1607 additions and 437 deletions

File diff suppressed because it is too large Load Diff

View File

@ -390,33 +390,26 @@ void clutter_actor_set_rotation (ClutterActor
gint x,
gint y,
gint z);
void clutter_actor_set_rotationx (ClutterActor *self,
ClutterRotateAxis axis,
ClutterFixed angle,
gint x,
gint y,
gint z);
void clutter_actor_set_rotationu (ClutterActor *self,
ClutterRotateAxis axis,
gdouble angle,
ClutterUnit x,
ClutterUnit y,
ClutterUnit z);
void clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
gdouble angle,
ClutterGravity gravity);
gdouble clutter_actor_get_rotation (ClutterActor *self,
ClutterRotateAxis axis,
gint *x,
gint *y,
gint *z);
ClutterFixed clutter_actor_get_rotationx (ClutterActor *self,
ClutterRotateAxis axis,
gint *x,
gint *y,
gint *z);
gdouble clutter_actor_get_rotationu (ClutterActor *self,
ClutterRotateAxis axis,
ClutterUnit *x,
ClutterUnit *y,
ClutterUnit *z);
ClutterGravity clutter_actor_get_z_rotation_gravity (ClutterActor *self);
void clutter_actor_set_opacity (ClutterActor *self,
guint8 opacity);
@ -474,18 +467,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,
@ -526,6 +534,7 @@ void clutter_actor_move_anchor_point (ClutterActor *self,
void clutter_actor_get_anchor_point (ClutterActor *self,
gint *anchor_x,
gint *anchor_y);
ClutterGravity clutter_actor_get_anchor_point_gravity (ClutterActor *self);
void clutter_actor_set_anchor_pointu (ClutterActor *self,
ClutterUnit anchor_x,
ClutterUnit anchor_y);

View File

@ -95,11 +95,11 @@ alpha_notify_foreach (ClutterBehaviour *behaviour,
rotate_behaviour = CLUTTER_BEHAVIOUR_ROTATE (behaviour);
priv = rotate_behaviour->priv;
clutter_actor_set_rotationx (actor, priv->axis,
angle,
priv->center_x,
priv->center_y,
priv->center_z);
clutter_actor_set_rotation (actor, priv->axis,
CLUTTER_FIXED_TO_DOUBLE (angle),
priv->center_x,
priv->center_y,
priv->center_z);
}
static inline

View File

@ -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

View File

@ -352,7 +352,9 @@ clutter_actor_set_y
clutter_actor_get_y
clutter_actor_move_by
clutter_actor_set_rotation
clutter_actor_set_z_rotation_from_gravity
clutter_actor_get_rotation
clutter_actor_get_z_rotation_gravity
clutter_actor_is_rotated
clutter_actor_set_opacity
clutter_actor_get_opacity
@ -381,7 +383,11 @@ clutter_actor_get_stage
clutter_actor_set_depth
clutter_actor_get_depth
clutter_actor_set_scale
clutter_actor_set_scale_full
clutter_actor_set_scale_with_gravity
clutter_actor_get_scale
clutter_actor_get_scale_center
clutter_actor_get_scale_gravity
clutter_actor_is_scaled
clutter_actor_apply_transform_to_point
clutter_actor_transform_stage_point
@ -400,6 +406,7 @@ clutter_actor_box_get_from_vertices
clutter_actor_set_anchor_point
clutter_actor_get_anchor_point
clutter_actor_set_anchor_point_from_gravity
clutter_actor_get_anchor_point_gravity
clutter_actor_move_anchor_point
clutter_actor_move_anchor_point_from_gravity
@ -427,6 +434,8 @@ clutter_actor_set_positionu
clutter_actor_get_positionu
clutter_actor_set_sizeu
clutter_actor_get_sizeu
clutter_actor_set_scale_fullu
clutter_actor_get_scale_centeru
clutter_actor_set_anchor_pointu
clutter_actor_get_anchor_pointu
clutter_actor_move_anchor_pointu
@ -438,12 +447,6 @@ clutter_actor_move_byu
clutter_actor_get_transformed_positionu
clutter_actor_get_transformed_sizeu
<SUBSECTION>
clutter_actor_set_scalex
clutter_actor_get_scalex
clutter_actor_set_rotationx
clutter_actor_get_rotationx
<SUBSECTION>
clutter_actor_grab_key_focus
clutter_actor_get_pango_context

View File

@ -25,6 +25,7 @@ test_conformance_SOURCES = \
test-binding-pool.c \
test-clutter-text.c \
test-text-cache.c \
test-anchors.c \
$(NULL)
# For convenience, this provides a way to easily run individual unit tests:

View File

@ -0,0 +1,698 @@
#include <clutter/clutter.h>
#include <stdlib.h>
#include <string.h>
#include "test-conform-common.h"
#define NOTIFY_ANCHOR_X (1 << 0)
#define NOTIFY_ANCHOR_Y (1 << 1)
#define NOTIFY_ANCHOR_GRAVITY (1 << 2)
#define NOTIFY_SCALE_X (1 << 3)
#define NOTIFY_SCALE_Y (1 << 4)
#define NOTIFY_SCALE_CENTER_X (1 << 5)
#define NOTIFY_SCALE_CENTER_Y (1 << 6)
#define NOTIFY_SCALE_GRAVITY (1 << 7)
#define NOTIFY_ROTATION_ANGLE_X (1 << 8)
#define NOTIFY_ROTATION_ANGLE_Y (1 << 9)
#define NOTIFY_ROTATION_ANGLE_Z (1 << 10)
#define NOTIFY_ROTATION_CENTER_X (1 << 11)
#define NOTIFY_ROTATION_CENTER_Y (1 << 12)
#define NOTIFY_ROTATION_CENTER_Z (1 << 13)
#define NOTIFY_ROTATION_CENTER_Z_GRAVITY (1 << 14)
#define RECT_WIDTH 100
#define RECT_HEIGHT 80
/* Allow the transformed position by off by a certain number of
pixels */
#define POSITION_TOLERANCE 2
typedef struct _TestState
{
gulong notifications;
ClutterActor *rect;
} TestState;
static const struct
{
ClutterGravity gravity;
gint x_pos, y_pos;
} gravities[] =
{
{ CLUTTER_GRAVITY_NORTH, RECT_WIDTH / 2, 0 },
{ CLUTTER_GRAVITY_NORTH_EAST, RECT_WIDTH, 0 },
{ CLUTTER_GRAVITY_EAST, RECT_WIDTH, RECT_HEIGHT / 2 },
{ CLUTTER_GRAVITY_SOUTH_EAST, RECT_WIDTH, RECT_HEIGHT },
{ CLUTTER_GRAVITY_SOUTH, RECT_WIDTH / 2, RECT_HEIGHT },
{ CLUTTER_GRAVITY_SOUTH_WEST, 0, RECT_HEIGHT },
{ CLUTTER_GRAVITY_WEST, 0, RECT_HEIGHT / 2 },
{ CLUTTER_GRAVITY_NORTH_WEST, 0, 0 },
{ CLUTTER_GRAVITY_CENTER, RECT_WIDTH / 2, RECT_HEIGHT / 2 }
};
static const char * const
properties[] =
{ "anchor-x",
"anchor-y",
"anchor-gravity",
"scale-x",
"scale-y",
"scale-center-x",
"scale-center-y",
"scale-gravity",
"rotation-angle-x",
"rotation-angle-y",
"rotation-angle-z",
"rotation-center-x",
"rotation-center-y",
"rotation-center-z",
"rotation-center-z-gravity" };
static void
notify_cb (GObject *object, GParamSpec *pspec, TestState *state)
{
int i;
int new_flags = 0;
int flag = 1;
for (i = 0; i < G_N_ELEMENTS (properties); i++)
{
if (!strcmp (properties[i], pspec->name))
new_flags |= flag;
flag <<= 1;
}
g_assert ((new_flags & state->notifications) == 0);
state->notifications |= new_flags;
}
#define assert_notifications(flags) \
do \
{ \
g_assert (state->notifications == (flags)); \
state->notifications = 0; \
} while (0)
/* Helper macro to assert the transformed position. This needs to be a
macro so that the assertion failure will report the right line
number */
#define assert_coords(state, x_1, y_1, x_2, y_2) \
do \
{ \
ClutterVertex verts[4]; \
clutter_actor_get_abs_allocation_vertices ((state)->rect, verts); \
check_coords ((state), (x_1), (y_1), (x_2), (y_2), verts); \
g_assert (approx_equal ((x_1), \
CLUTTER_UNITS_TO_DEVICE (verts[0].x))); \
g_assert (approx_equal ((y_1), \
CLUTTER_UNITS_TO_DEVICE (verts[0].y))); \
g_assert (approx_equal ((x_2), \
CLUTTER_UNITS_TO_DEVICE (verts[3].x))); \
g_assert (approx_equal ((y_2), \
CLUTTER_UNITS_TO_DEVICE (verts[3].y))); \
} while (0)
#define assert_position(state, x, y) \
assert_coords((state), (x), (y), (x) + RECT_WIDTH, (y) + RECT_HEIGHT)
#define assert_vertex_and_free(v, xc, yc, zc) \
do \
{ \
g_assert (approx_equal (CLUTTER_UNITS_TO_DEVICE (v->x), xc) \
&& approx_equal (CLUTTER_UNITS_TO_DEVICE (v->y), yc) \
&& approx_equal (CLUTTER_UNITS_TO_DEVICE (v->z), zc)); \
g_boxed_free (CLUTTER_TYPE_VERTEX, v); \
} while (0)
static inline gboolean
approx_equal (int a, int b)
{
return abs (a - b) <= POSITION_TOLERANCE;
}
static void
check_coords (TestState *state,
gint x_1, gint y_1, gint x_2, gint y_2,
const ClutterVertex *verts)
{
if (g_test_verbose ())
g_print ("checking that (%i,%i,%i,%i) \xe2\x89\x88 (%i,%i,%i,%i): %s\n",
x_1, y_1, x_2, y_2,
CLUTTER_UNITS_TO_DEVICE (verts[0].x),
CLUTTER_UNITS_TO_DEVICE (verts[0].y),
CLUTTER_UNITS_TO_DEVICE (verts[3].x),
CLUTTER_UNITS_TO_DEVICE (verts[3].y),
approx_equal (x_1, CLUTTER_UNITS_TO_DEVICE (verts[0].x))
&& approx_equal (y_1, CLUTTER_UNITS_TO_DEVICE (verts[0].y))
&& approx_equal (x_2, CLUTTER_UNITS_TO_DEVICE (verts[3].x))
&& approx_equal (y_2, CLUTTER_UNITS_TO_DEVICE (verts[3].y))
? "yes" : "NO");
}
static void
test_anchor_point (TestState *state)
{
ClutterActor *rect = state->rect;
gint anchor_x, anchor_y;
ClutterGravity anchor_gravity;
int i;
/* Assert the default settings */
g_assert (clutter_actor_get_x (rect) == 100);
g_assert (clutter_actor_get_y (rect) == 200);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"anchor-x", &anchor_x, "anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == 0);
g_assert (anchor_y == 0);
g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE);
/* Change the anchor point */
clutter_actor_set_anchor_point (rect, 20, 30);
g_object_get (rect,
"anchor-x", &anchor_x, "anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == 20);
g_assert (anchor_y == 30);
g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE);
assert_position (state, 80, 170);
assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y);
/* Move the anchor point */
clutter_actor_move_anchor_point (rect, 40, 50);
g_object_get (rect,
"anchor-x", &anchor_x, "anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == 40);
g_assert (anchor_y == 50);
g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE);
assert_position (state, 80, 170);
assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y);
/* Put the actor back to its default position */
clutter_actor_set_position (rect, 100, 200);
/* Change the anchor point with each of the gravities */
for (i = 0; i < G_N_ELEMENTS (gravities); i++)
{
if (g_test_verbose ())
{
GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY);
GEnumValue *value = g_enum_get_value (gravity_class,
gravities[i].gravity);
g_print ("Setting gravity to %s\n",
value ? value->value_name : "?");
g_type_class_unref (gravity_class);
}
g_object_set (rect, "anchor-gravity", gravities[i].gravity, NULL);
g_object_get (rect,
"anchor-x", &anchor_x, "anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == gravities[i].x_pos);
g_assert (anchor_y == gravities[i].y_pos);
g_assert (anchor_gravity == gravities[i].gravity);
assert_position (state,
100 - gravities[i].x_pos,
200 - gravities[i].y_pos);
assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y
| NOTIFY_ANCHOR_GRAVITY);
}
/* Verify that the anchor point moves if the actor changes size when
it is set from the gravity */
clutter_actor_set_size (rect, RECT_WIDTH * 2, RECT_HEIGHT * 2);
g_object_get (rect,
"anchor-x", &anchor_x, "anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == RECT_WIDTH);
g_assert (anchor_y == RECT_HEIGHT);
g_assert (anchor_gravity == CLUTTER_GRAVITY_CENTER);
assert_coords (state, 100 - RECT_WIDTH, 200 - RECT_HEIGHT,
100 + RECT_WIDTH, 200 + RECT_HEIGHT);
assert_notifications (0);
clutter_actor_set_size (rect, RECT_WIDTH, RECT_HEIGHT);
/* Change the anchor point using units again to assert that the
gravity property changes */
clutter_actor_set_anchor_point (rect, 20, 30);
g_object_get (rect,
"anchor-x", &anchor_x, "anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == 20);
g_assert (anchor_y == 30);
g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE);
assert_position (state, 80, 170);
assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y
| NOTIFY_ANCHOR_GRAVITY);
/* Verify that the anchor point doesn't move if the actor changes
size when it is set from units */
clutter_actor_set_size (rect, RECT_WIDTH * 2, RECT_HEIGHT * 2);
g_object_get (rect,
"anchor-x", &anchor_x, "anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == 20);
g_assert (anchor_y == 30);
g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE);
assert_coords (state, 80, 170, 80 + RECT_WIDTH * 2, 170 + RECT_HEIGHT * 2);
assert_notifications (0);
clutter_actor_set_size (rect, RECT_WIDTH, RECT_HEIGHT);
/* Put the anchor back */
clutter_actor_set_anchor_point_from_gravity (rect, CLUTTER_GRAVITY_NONE);
assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y);
}
static void
test_scale_center (TestState *state)
{
ClutterActor *rect = state->rect;
gdouble scale_x, scale_y;
gint center_x, center_y;
ClutterGravity gravity;
int i;
/* Assert the default settings */
g_assert (clutter_actor_get_x (rect) == 100);
g_assert (clutter_actor_get_y (rect) == 200);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"scale-center-x", &center_x, "scale-center-y", &center_y,
"scale-x", &scale_x, "scale-y", &scale_y,
"scale-gravity", &gravity,
NULL);
g_assert (center_x == 0);
g_assert (center_y == 0);
g_assert (scale_x == 1.0);
g_assert (scale_y == 1.0);
g_assert (gravity == CLUTTER_GRAVITY_NONE);
/* Try changing the scale without affecting the center */
g_object_set (rect, "scale-x", 2.0, "scale-y", 3.0, NULL);
g_assert (clutter_actor_get_x (rect) == 100);
g_assert (clutter_actor_get_y (rect) == 200);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"scale-center-x", &center_x, "scale-center-y", &center_y,
"scale-x", &scale_x, "scale-y", &scale_y,
"scale-gravity", &gravity,
NULL);
g_assert (center_x == 0);
g_assert (center_y == 0);
g_assert (scale_x == 2.0);
g_assert (scale_y == 3.0);
g_assert (gravity == CLUTTER_GRAVITY_NONE);
assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y);
assert_coords (state, 100, 200, 100 + RECT_WIDTH * 2, 200 + RECT_HEIGHT * 3);
/* Change the scale and center */
g_object_set (rect, "scale-x", 4.0, "scale-y", 2.0,
"scale-center-x", 10, "scale-center-y", 20, NULL);
g_assert (clutter_actor_get_x (rect) == 100);
g_assert (clutter_actor_get_y (rect) == 200);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"scale-center-x", &center_x, "scale-center-y", &center_y,
"scale-x", &scale_x, "scale-y", &scale_y,
"scale-gravity", &gravity,
NULL);
g_assert (center_x == 10);
g_assert (center_y == 20);
g_assert (scale_x == 4.0);
g_assert (scale_y == 2.0);
g_assert (gravity == CLUTTER_GRAVITY_NONE);
assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y
| NOTIFY_SCALE_CENTER_X | NOTIFY_SCALE_CENTER_Y);
assert_coords (state, 100 + 10 - 10 * 4, 200 + 20 - 20 * 2,
100 + 10 + (RECT_WIDTH - 10) * 4,
200 + 20 + (RECT_HEIGHT - 20) * 2);
/* Change the anchor point with each of the gravities */
for (i = 0; i < G_N_ELEMENTS (gravities); i++)
{
if (g_test_verbose ())
{
GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY);
GEnumValue *value = g_enum_get_value (gravity_class,
gravities[i].gravity);
g_print ("Setting scale center to %s\n",
value ? value->value_name : "?");
g_type_class_unref (gravity_class);
}
g_object_set (rect, "scale-gravity", gravities[i].gravity, NULL);
g_assert (clutter_actor_get_x (rect) == 100);
g_assert (clutter_actor_get_y (rect) == 200);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"scale-center-x", &center_x, "scale-center-y", &center_y,
"scale-x", &scale_x, "scale-y", &scale_y,
"scale-gravity", &gravity,
NULL);
g_assert (center_x == gravities[i].x_pos);
g_assert (center_y == gravities[i].y_pos);
g_assert (scale_x == 4.0);
g_assert (scale_y == 2.0);
g_assert (gravity == gravities[i].gravity);
assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y
| NOTIFY_SCALE_CENTER_X | NOTIFY_SCALE_CENTER_Y
| NOTIFY_SCALE_GRAVITY);
assert_coords (state,
100 - gravities[i].x_pos * 3,
200 - gravities[i].y_pos,
100 + (gravities[i].x_pos
+ (RECT_WIDTH - gravities[i].x_pos) * 4),
200 + (gravities[i].y_pos
+ (RECT_HEIGHT - gravities[i].y_pos) * 2));
}
/* Change the scale center using units again to assert that the
gravity property changes */
clutter_actor_set_scale_full (rect, 4, 2, 10, 20);
g_object_get (rect,
"scale-center-x", &center_x, "scale-center-y", &center_y,
"scale-x", &scale_x, "scale-y", &scale_y,
"scale-gravity", &gravity,
NULL);
g_assert (center_x == 10);
g_assert (center_y == 20);
g_assert (scale_x == 4.0);
g_assert (scale_y == 2.0);
g_assert (gravity == CLUTTER_GRAVITY_NONE);
assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y
| NOTIFY_SCALE_CENTER_X | NOTIFY_SCALE_CENTER_Y
| NOTIFY_SCALE_GRAVITY);
assert_coords (state, 100 + 10 - 10 * 4, 200 + 20 - 20 * 2,
100 + 10 + (RECT_WIDTH - 10) * 4,
200 + 20 + (RECT_HEIGHT - 20) * 2);
/* Put the scale back to normal */
clutter_actor_set_scale_full (rect, 1, 1, 0, 0);
assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y
| NOTIFY_SCALE_CENTER_X | NOTIFY_SCALE_CENTER_Y);
}
static void
test_rotate_center (TestState *state)
{
ClutterActor *rect = state->rect;
gdouble angle_x, angle_y, angle_z;
ClutterVertex *center_x, *center_y, *center_z;
ClutterGravity z_center_gravity;
guint stage_width, stage_height;
gint rect_x, rect_y;
int i;
/* Position the rectangle at the center of the stage so that
rotations by 90° along the X or Y axis will cause the actor to be
appear as a flat line. This makes verifying the transformations
easier */
clutter_actor_get_size (clutter_actor_get_stage (rect),
&stage_width, &stage_height);
rect_x = stage_width / 2;
rect_y = stage_height / 2;
clutter_actor_set_position (rect, rect_x, rect_y);
/* Assert the default settings */
g_assert (clutter_actor_get_x (rect) == rect_x);
g_assert (clutter_actor_get_y (rect) == rect_y);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"rotation-angle-x", &angle_x,
"rotation-angle-y", &angle_y,
"rotation-angle-z", &angle_z,
"rotation-center-x", &center_x,
"rotation-center-y", &center_y,
"rotation-center-z", &center_z,
"rotation-center-z-gravity", &z_center_gravity,
NULL);
g_assert (angle_x == 0.0);
g_assert (angle_y == 0.0);
g_assert (angle_z == 0.0);
assert_vertex_and_free (center_x, 0, 0, 0);
assert_vertex_and_free (center_y, 0, 0, 0);
assert_vertex_and_free (center_z, 0, 0, 0);
g_assert (z_center_gravity == CLUTTER_GRAVITY_NONE);
/* Change each of the rotation angles without affecting the center
point */
for (i = CLUTTER_X_AXIS; i <= CLUTTER_Z_AXIS; i++)
{
char prop_name[] = "rotation-angle- ";
prop_name[sizeof (prop_name) - 2] = i - CLUTTER_X_AXIS + 'x';
if (g_test_verbose ())
g_print ("Setting %s to 90 degrees\n", prop_name);
g_object_set (rect, prop_name, 90.0, NULL);
assert_notifications (NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS));
g_assert (clutter_actor_get_x (rect) == rect_x);
g_assert (clutter_actor_get_y (rect) == rect_y);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"rotation-angle-x", &angle_x,
"rotation-angle-y", &angle_y,
"rotation-angle-z", &angle_z,
"rotation-center-x", &center_x,
"rotation-center-y", &center_y,
"rotation-center-z", &center_z,
"rotation-center-z-gravity", &z_center_gravity,
NULL);
if (i == CLUTTER_X_AXIS)
{
g_assert (angle_x == 90.0);
assert_coords (state, rect_x, rect_y,
CLUTTER_UNITS_TO_DEVICE (verts[3].x), rect_y);
}
else
g_assert (angle_x == 0.0);
if (i == CLUTTER_Y_AXIS)
{
g_assert (angle_y == 90.0);
assert_coords (state, rect_x, rect_y,
rect_x, CLUTTER_UNITS_TO_DEVICE (verts[3].y));
}
else
g_assert (angle_y == 0.0);
if (i == CLUTTER_Z_AXIS)
{
g_assert (angle_z == 90.0);
assert_coords (state, rect_x, rect_y,
rect_x - RECT_HEIGHT, rect_y + RECT_WIDTH);
}
else
g_assert (angle_z == 0.0);
assert_vertex_and_free (center_x, 0, 0, 0);
assert_vertex_and_free (center_y, 0, 0, 0);
assert_vertex_and_free (center_z, 0, 0, 0);
g_assert (z_center_gravity == CLUTTER_GRAVITY_NONE);
g_object_set (rect, prop_name, 0.0, NULL);
assert_notifications (NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS));
}
clutter_actor_set_position (rect, rect_x -= 10, rect_y -= 20);
/* Same test but also change the center position */
for (i = CLUTTER_X_AXIS; i <= CLUTTER_Z_AXIS; i++)
{
char prop_name[] = "rotation-angle- ";
prop_name[sizeof (prop_name) - 2] = i - CLUTTER_X_AXIS + 'x';
if (g_test_verbose ())
g_print ("Setting %s to 90 degrees with center 10,20,0\n", prop_name);
clutter_actor_set_rotation (rect, i, 90.0, 10, 20, 0);
assert_notifications ((NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS))
| (NOTIFY_ROTATION_CENTER_X
<< (i - CLUTTER_X_AXIS)));
g_assert (clutter_actor_get_x (rect) == rect_x);
g_assert (clutter_actor_get_y (rect) == rect_y);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"rotation-angle-x", &angle_x,
"rotation-angle-y", &angle_y,
"rotation-angle-z", &angle_z,
"rotation-center-x", &center_x,
"rotation-center-y", &center_y,
"rotation-center-z", &center_z,
"rotation-center-z-gravity", &z_center_gravity,
NULL);
if (i == CLUTTER_X_AXIS)
{
g_assert (angle_x == 90.0);
assert_coords (state,
CLUTTER_UNITS_TO_DEVICE (verts[0].x), rect_y + 20,
CLUTTER_UNITS_TO_DEVICE (verts[3].x), rect_y + 20);
assert_vertex_and_free (center_x, 10, 20, 0);
}
else
{
g_assert (angle_x == 0.0);
assert_vertex_and_free (center_x, 0, 0, 0);
}
if (i == CLUTTER_Y_AXIS)
{
g_assert (angle_y == 90.0);
assert_coords (state,
rect_x + 10, CLUTTER_UNITS_TO_DEVICE (verts[0].y),
rect_x + 10, CLUTTER_UNITS_TO_DEVICE (verts[3].y));
assert_vertex_and_free (center_y, 10, 20, 0);
}
else
{
g_assert (angle_y == 0.0);
assert_vertex_and_free (center_y, 0, 0, 0);
}
if (i == CLUTTER_Z_AXIS)
{
g_assert (angle_z == 90.0);
assert_coords (state,
rect_x + 10 + 20,
rect_y + 20 - 10,
rect_x + 10 + 20 - RECT_HEIGHT,
rect_y + 20 + RECT_WIDTH - 10);
assert_vertex_and_free (center_z, 10, 20, 0);
}
else
{
g_assert (angle_z == 0.0);
assert_vertex_and_free (center_z, 0, 0, 0);
}
g_assert (z_center_gravity == CLUTTER_GRAVITY_NONE);
clutter_actor_set_rotation (rect, i, 0, 0, 0, 0);
assert_notifications ((NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS))
| (NOTIFY_ROTATION_CENTER_X
<< (i - CLUTTER_X_AXIS)));
}
/* Try rotating the z with all of the gravities */
for (i = 0; i < G_N_ELEMENTS (gravities); i++)
{
if (g_test_verbose ())
{
GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY);
GEnumValue *value = g_enum_get_value (gravity_class,
gravities[i].gravity);
g_print ("Setting z rotation to 90 degrees with center at %s\n",
value ? value->value_name : "?");
g_type_class_unref (gravity_class);
}
clutter_actor_set_z_rotation_from_gravity (rect, 90,
gravities[i].gravity);
assert_notifications (NOTIFY_ROTATION_ANGLE_Z
| NOTIFY_ROTATION_CENTER_Z
| NOTIFY_ROTATION_CENTER_Z_GRAVITY);
g_assert (clutter_actor_get_x (rect) == rect_x);
g_assert (clutter_actor_get_y (rect) == rect_y);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"rotation-angle-x", &angle_x,
"rotation-angle-y", &angle_y,
"rotation-angle-z", &angle_z,
"rotation-center-x", &center_x,
"rotation-center-y", &center_y,
"rotation-center-z", &center_z,
"rotation-center-z-gravity", &z_center_gravity,
NULL);
g_assert (angle_x == 0.0);
g_assert (angle_y == 0.0);
g_assert (angle_z == 90.0);
assert_vertex_and_free (center_x, 0, 0, 0);
assert_vertex_and_free (center_y, 0, 0, 0);
assert_vertex_and_free (center_z,
gravities[i].x_pos, gravities[i].y_pos, 0);
assert_coords (state,
rect_x + gravities[i].x_pos + gravities[i].y_pos,
rect_y + gravities[i].y_pos - gravities[i].x_pos,
rect_x + gravities[i].x_pos + gravities[i].y_pos
- RECT_HEIGHT,
rect_y + gravities[i].y_pos + RECT_WIDTH
- gravities[i].x_pos);
g_assert (z_center_gravity == gravities[i].gravity);
g_assert (clutter_actor_get_z_rotation_gravity (rect)
== gravities[i].gravity);
/* Put the rotation back */
clutter_actor_set_z_rotation_from_gravity (rect, 0, CLUTTER_GRAVITY_NONE);
assert_notifications (NOTIFY_ROTATION_ANGLE_Z
| NOTIFY_ROTATION_CENTER_Z
| NOTIFY_ROTATION_CENTER_Z_GRAVITY);
}
}
static gboolean
idle_cb (gpointer data)
{
test_anchor_point (data);
test_scale_center (data);
test_rotate_center (data);
clutter_main_quit ();
return FALSE;
}
void
test_anchors (TestConformSimpleFixture *fixture,
gconstpointer data)
{
TestState state;
ClutterActor *stage;
stage = clutter_stage_get_default ();
state.rect = clutter_rectangle_new ();
clutter_container_add (CLUTTER_CONTAINER (stage), state.rect, NULL);
clutter_actor_set_position (state.rect, 100, 200);
clutter_actor_set_size (state.rect, RECT_WIDTH, RECT_HEIGHT);
/* Record notifications on the actor properties */
state.notifications = 0;
g_signal_connect (state.rect, "notify",
G_CALLBACK (notify_cb), &state);
/* Run the tests in a low priority idle function so that we can be
sure the stage is correctly setup */
g_idle_add_full (G_PRIORITY_LOW, idle_cb, &state, NULL);
clutter_actor_show (stage);
clutter_main ();
g_idle_remove_by_data (&state);
clutter_actor_destroy (state.rect);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -108,5 +108,7 @@ main (int argc, char **argv)
TEST_CONFORM_SIMPLE ("/binding-pool", test_binding_pool);
TEST_CONFORM_SIMPLE ("/actor", test_anchors);
return g_test_run ();
}