mutter/tests/conform/test-anchors.c

700 lines
26 KiB
C
Raw Normal View History

#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;
Remove Units from the public API With the recent change to internal floating point values, ClutterUnit has become a redundant type, defined to be a float. All integer entry points are being internally converted to floating point values to be passed to the GL pipeline with the least amount of conversion. ClutterUnit is thus exposed as just a "pixel with fractionary bits", and not -- as users might think -- as generic, resolution and device independent units. not that it was the case, but a definitive amount of people was convinced it did provide this "feature", and was flummoxed about the mere existence of this type. So, having ClutterUnit exposed in the public API doubles the entry points and has the following disadvantages: - we have to maintain twice the amount of entry points in ClutterActor - we still do an integer-to-float implicit conversion - we introduce a weird impedance between pixels and "pixels with fractionary bits" - language bindings will have to choose what to bind, and resort to manually overriding the API + *except* for language bindings based on GObject-Introspection, as they cannot do manual overrides, thus will replicate the entire set of entry points For these reason, we should coalesces every Actor entry point for pixels and for ClutterUnit into a single entry point taking a float, like: void clutter_actor_set_x (ClutterActor *self, gfloat x); void clutter_actor_get_size (ClutterActor *self, gfloat *width, gfloat *height); gfloat clutter_actor_get_height (ClutterActor *self); etc. The issues I have identified are: - we'll have a two cases of compiler warnings: - printf() format of the return values from %d to %f - clutter_actor_get_size() taking floats instead of unsigned ints - we'll have a problem with varargs when passing an integer instead of a floating point value, except on 64bit platforms where the size of a float is the same as the size of an int To be clear: the *intent* of the API should not change -- we still use pixels everywhere -- but: - we remove ambiguity in the API with regard to pixels and units - we remove entry points we get to maintain for the whole 1.0 version of the API - we make things simpler to bind for both manual language bindings and automatic (gobject-introspection based) ones - we have the simplest API possible while still exposing the capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
gfloat stage_width, stage_height;
gfloat 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),
Remove Units from the public API With the recent change to internal floating point values, ClutterUnit has become a redundant type, defined to be a float. All integer entry points are being internally converted to floating point values to be passed to the GL pipeline with the least amount of conversion. ClutterUnit is thus exposed as just a "pixel with fractionary bits", and not -- as users might think -- as generic, resolution and device independent units. not that it was the case, but a definitive amount of people was convinced it did provide this "feature", and was flummoxed about the mere existence of this type. So, having ClutterUnit exposed in the public API doubles the entry points and has the following disadvantages: - we have to maintain twice the amount of entry points in ClutterActor - we still do an integer-to-float implicit conversion - we introduce a weird impedance between pixels and "pixels with fractionary bits" - language bindings will have to choose what to bind, and resort to manually overriding the API + *except* for language bindings based on GObject-Introspection, as they cannot do manual overrides, thus will replicate the entire set of entry points For these reason, we should coalesces every Actor entry point for pixels and for ClutterUnit into a single entry point taking a float, like: void clutter_actor_set_x (ClutterActor *self, gfloat x); void clutter_actor_get_size (ClutterActor *self, gfloat *width, gfloat *height); gfloat clutter_actor_get_height (ClutterActor *self); etc. The issues I have identified are: - we'll have a two cases of compiler warnings: - printf() format of the return values from %d to %f - clutter_actor_get_size() taking floats instead of unsigned ints - we'll have a problem with varargs when passing an integer instead of a floating point value, except on 64bit platforms where the size of a float is the same as the size of an int To be clear: the *intent* of the API should not change -- we still use pixels everywhere -- but: - we remove ambiguity in the API with regard to pixels and units - we remove entry points we get to maintain for the whole 1.0 version of the API - we make things simpler to bind for both manual language bindings and automatic (gobject-introspection based) ones - we have the simplest API possible while still exposing the capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
&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 */
Remove Units from the public API With the recent change to internal floating point values, ClutterUnit has become a redundant type, defined to be a float. All integer entry points are being internally converted to floating point values to be passed to the GL pipeline with the least amount of conversion. ClutterUnit is thus exposed as just a "pixel with fractionary bits", and not -- as users might think -- as generic, resolution and device independent units. not that it was the case, but a definitive amount of people was convinced it did provide this "feature", and was flummoxed about the mere existence of this type. So, having ClutterUnit exposed in the public API doubles the entry points and has the following disadvantages: - we have to maintain twice the amount of entry points in ClutterActor - we still do an integer-to-float implicit conversion - we introduce a weird impedance between pixels and "pixels with fractionary bits" - language bindings will have to choose what to bind, and resort to manually overriding the API + *except* for language bindings based on GObject-Introspection, as they cannot do manual overrides, thus will replicate the entire set of entry points For these reason, we should coalesces every Actor entry point for pixels and for ClutterUnit into a single entry point taking a float, like: void clutter_actor_set_x (ClutterActor *self, gfloat x); void clutter_actor_get_size (ClutterActor *self, gfloat *width, gfloat *height); gfloat clutter_actor_get_height (ClutterActor *self); etc. The issues I have identified are: - we'll have a two cases of compiler warnings: - printf() format of the return values from %d to %f - clutter_actor_get_size() taking floats instead of unsigned ints - we'll have a problem with varargs when passing an integer instead of a floating point value, except on 64bit platforms where the size of a float is the same as the size of an int To be clear: the *intent* of the API should not change -- we still use pixels everywhere -- but: - we remove ambiguity in the API with regard to pixels and units - we remove entry points we get to maintain for the whole 1.0 version of the API - we make things simpler to bind for both manual language bindings and automatic (gobject-introspection based) ones - we have the simplest API possible while still exposing the capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
g_assert_cmpfloat (clutter_actor_get_x (rect), ==, rect_x);
g_assert_cmpfloat (clutter_actor_get_y (rect), ==, rect_y);
g_assert_cmpfloat (clutter_actor_get_width (rect), ==, RECT_WIDTH);
g_assert_cmpfloat (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");
}