diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 867924909..9130af229 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -138,6 +138,7 @@ source_c = \ $(srcdir)/clutter-animation.c \ $(srcdir)/clutter-animator.c \ $(srcdir)/clutter-backend.c \ + $(srcdir)/clutter-base-types.c \ $(srcdir)/clutter-bezier.c \ $(srcdir)/clutter-bind-constraint.c \ $(srcdir)/clutter-binding-pool.c \ diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 0b1de9c9f..cb41e9257 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -13272,247 +13272,6 @@ clutter_actor_transform_stage_point (ClutterActor *self, return TRUE; } -/* - * ClutterGeometry - */ - -static ClutterGeometry* -clutter_geometry_copy (const ClutterGeometry *geometry) -{ - return g_slice_dup (ClutterGeometry, geometry); -} - -static void -clutter_geometry_free (ClutterGeometry *geometry) -{ - if (G_LIKELY (geometry != NULL)) - g_slice_free (ClutterGeometry, geometry); -} - -/** - * clutter_geometry_union: - * @geometry_a: a #ClutterGeometry - * @geometry_b: another #ClutterGeometry - * @result: (out): location to store the result - * - * Find the union of two rectangles represented as #ClutterGeometry. - * - * Since: 1.4 - */ -void -clutter_geometry_union (const ClutterGeometry *geometry_a, - const ClutterGeometry *geometry_b, - ClutterGeometry *result) -{ - /* We don't try to handle rectangles that can't be represented - * as a signed integer box */ - gint x_1 = MIN (geometry_a->x, geometry_b->x); - gint y_1 = MIN (geometry_a->y, geometry_b->y); - gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width, - geometry_b->x + (gint)geometry_b->width); - gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height, - geometry_b->y + (gint)geometry_b->height); - result->x = x_1; - result->y = y_1; - result->width = x_2 - x_1; - result->height = y_2 - y_1; -} - -/** - * clutter_geometry_intersects: - * @geometry0: The first geometry to test - * @geometry1: The second geometry to test - * - * Determines if @geometry0 and geometry1 intersect returning %TRUE if - * they do else %FALSE. - * - * Return value: %TRUE of @geometry0 and geometry1 intersect else - * %FALSE. - * - * Since: 1.4 - */ -gboolean -clutter_geometry_intersects (const ClutterGeometry *geometry0, - const ClutterGeometry *geometry1) -{ - if (geometry1->x >= (geometry0->x + (gint)geometry0->width) || - geometry1->y >= (geometry0->y + (gint)geometry0->height) || - (geometry1->x + (gint)geometry1->width) <= geometry0->x || - (geometry1->y + (gint)geometry1->height) <= geometry0->y) - return FALSE; - else - return TRUE; -} - -static gboolean -clutter_geometry_progress (const GValue *a, - const GValue *b, - gdouble progress, - GValue *retval) -{ - const ClutterGeometry *a_geom = g_value_get_boxed (a); - const ClutterGeometry *b_geom = g_value_get_boxed (b); - ClutterGeometry res = { 0, }; - gint a_width = a_geom->width; - gint b_width = b_geom->width; - gint a_height = a_geom->height; - gint b_height = b_geom->height; - - res.x = a_geom->x + (b_geom->x - a_geom->x) * progress; - res.y = a_geom->y + (b_geom->y - a_geom->y) * progress; - - res.width = a_width + (b_width - a_width) * progress; - res.height = a_height + (b_height - a_height) * progress; - - g_value_set_boxed (retval, &res); - - return TRUE; -} - -G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry, - clutter_geometry_copy, - clutter_geometry_free, - CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress)); - -/* - * ClutterVertices - */ - -/** - * clutter_vertex_new: - * @x: X coordinate - * @y: Y coordinate - * @z: Z coordinate - * - * Creates a new #ClutterVertex for the point in 3D space - * identified by the 3 coordinates @x, @y, @z - * - * Return value: the newly allocate #ClutterVertex. Use - * clutter_vertex_free() to free the resources - * - * Since: 1.0 - */ -ClutterVertex * -clutter_vertex_new (gfloat x, - gfloat y, - gfloat z) -{ - ClutterVertex *vertex; - - vertex = g_slice_new (ClutterVertex); - clutter_vertex_init (vertex, x, y, z); - - return vertex; -} - -/** - * clutter_vertex_init: - * @vertex: a #ClutterVertex - * @x: X coordinate - * @y: Y coordinate - * @z: Z coordinate - * - * Initializes @vertex with the given coordinates. - * - * Since: 1.10 - */ -void -clutter_vertex_init (ClutterVertex *vertex, - gfloat x, - gfloat y, - gfloat z) -{ - g_return_if_fail (vertex != NULL); - - vertex->x = x; - vertex->y = y; - vertex->z = z; -} - -/** - * clutter_vertex_copy: - * @vertex: a #ClutterVertex - * - * Copies @vertex - * - * Return value: a newly allocated copy of #ClutterVertex. Use - * clutter_vertex_free() to free the allocated resources - * - * Since: 1.0 - */ -ClutterVertex * -clutter_vertex_copy (const ClutterVertex *vertex) -{ - if (G_LIKELY (vertex != NULL)) - return g_slice_dup (ClutterVertex, vertex); - - return NULL; -} - -/** - * clutter_vertex_free: - * @vertex: a #ClutterVertex - * - * Frees a #ClutterVertex allocated using clutter_vertex_copy() - * - * Since: 1.0 - */ -void -clutter_vertex_free (ClutterVertex *vertex) -{ - if (G_UNLIKELY (vertex != NULL)) - g_slice_free (ClutterVertex, vertex); -} - -/** - * clutter_vertex_equal: - * @vertex_a: a #ClutterVertex - * @vertex_b: a #ClutterVertex - * - * Compares @vertex_a and @vertex_b for equality - * - * Return value: %TRUE if the passed #ClutterVertex are equal - * - * Since: 1.0 - */ -gboolean -clutter_vertex_equal (const ClutterVertex *vertex_a, - const ClutterVertex *vertex_b) -{ - g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE); - - if (vertex_a == vertex_b) - return TRUE; - - return vertex_a->x == vertex_b->x && - vertex_a->y == vertex_b->y && - vertex_a->z == vertex_b->z; -} - -static gboolean -clutter_vertex_progress (const GValue *a, - const GValue *b, - gdouble progress, - GValue *retval) -{ - const ClutterVertex *av = g_value_get_boxed (a); - const ClutterVertex *bv = g_value_get_boxed (b); - ClutterVertex res = { 0, }; - - res.x = av->x + (bv->x - av->x) * progress; - res.y = av->y + (bv->y - av->y) * progress; - res.z = av->z + (bv->z - av->z) * progress; - - g_value_set_boxed (retval, &res); - - return TRUE; -} - -G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex, - clutter_vertex_copy, - clutter_vertex_free, - CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress)); - /** * clutter_actor_is_rotated: * @self: a #ClutterActor @@ -16237,64 +15996,6 @@ clutter_actor_get_y_align (ClutterActor *self) return _clutter_actor_get_layout_info_or_defaults (self)->y_align; } - -/** - * clutter_margin_new: - * - * Creates a new #ClutterMargin. - * - * Return value: (transfer full): a newly allocated #ClutterMargin. Use - * clutter_margin_free() to free the resources associated with it when - * done. - * - * Since: 1.10 - */ -ClutterMargin * -clutter_margin_new (void) -{ - return g_slice_new0 (ClutterMargin); -} - -/** - * clutter_margin_copy: - * @margin_: a #ClutterMargin - * - * Creates a new #ClutterMargin and copies the contents of @margin_ into - * the newly created structure. - * - * Return value: (transfer full): a copy of the #ClutterMargin. - * - * Since: 1.10 - */ -ClutterMargin * -clutter_margin_copy (const ClutterMargin *margin_) -{ - if (G_LIKELY (margin_ != NULL)) - return g_slice_dup (ClutterMargin, margin_); - - return NULL; -} - -/** - * clutter_margin_free: - * @margin_: a #ClutterMargin - * - * Frees the resources allocated by clutter_margin_new() and - * clutter_margin_copy(). - * - * Since: 1.10 - */ -void -clutter_margin_free (ClutterMargin *margin_) -{ - if (G_LIKELY (margin_ != NULL)) - g_slice_free (ClutterMargin, margin_); -} - -G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin, - clutter_margin_copy, - clutter_margin_free) - /** * clutter_actor_set_margin: * @self: a #ClutterActor diff --git a/clutter/clutter-base-types.c b/clutter/clutter-base-types.c new file mode 100644 index 000000000..8a91b6eeb --- /dev/null +++ b/clutter/clutter-base-types.c @@ -0,0 +1,1027 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * + * Copyright (C) 2006 OpenedHand + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +/** + * SECTION:clutter-base-types + * @Title: Base data types + * @Short_Description: Common data types used by Clutter + * + * Clutter defines a set of data structures that are commonly used across the + * whole API. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-types.h" +#include "clutter-private.h" + +#include + + + +/* + * ClutterGeometry + */ + +static ClutterGeometry* +clutter_geometry_copy (const ClutterGeometry *geometry) +{ + return g_slice_dup (ClutterGeometry, geometry); +} + +static void +clutter_geometry_free (ClutterGeometry *geometry) +{ + if (G_LIKELY (geometry != NULL)) + g_slice_free (ClutterGeometry, geometry); +} + +/** + * clutter_geometry_union: + * @geometry_a: a #ClutterGeometry + * @geometry_b: another #ClutterGeometry + * @result: (out): location to store the result + * + * Find the union of two rectangles represented as #ClutterGeometry. + * + * Since: 1.4 + */ +void +clutter_geometry_union (const ClutterGeometry *geometry_a, + const ClutterGeometry *geometry_b, + ClutterGeometry *result) +{ + /* We don't try to handle rectangles that can't be represented + * as a signed integer box */ + gint x_1 = MIN (geometry_a->x, geometry_b->x); + gint y_1 = MIN (geometry_a->y, geometry_b->y); + gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width, + geometry_b->x + (gint)geometry_b->width); + gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height, + geometry_b->y + (gint)geometry_b->height); + result->x = x_1; + result->y = y_1; + result->width = x_2 - x_1; + result->height = y_2 - y_1; +} + +/** + * clutter_geometry_intersects: + * @geometry0: The first geometry to test + * @geometry1: The second geometry to test + * + * Determines if @geometry0 and geometry1 intersect returning %TRUE if + * they do else %FALSE. + * + * Return value: %TRUE of @geometry0 and geometry1 intersect else + * %FALSE. + * + * Since: 1.4 + */ +gboolean +clutter_geometry_intersects (const ClutterGeometry *geometry0, + const ClutterGeometry *geometry1) +{ + if (geometry1->x >= (geometry0->x + (gint)geometry0->width) || + geometry1->y >= (geometry0->y + (gint)geometry0->height) || + (geometry1->x + (gint)geometry1->width) <= geometry0->x || + (geometry1->y + (gint)geometry1->height) <= geometry0->y) + return FALSE; + else + return TRUE; +} + +static gboolean +clutter_geometry_progress (const GValue *a, + const GValue *b, + gdouble progress, + GValue *retval) +{ + const ClutterGeometry *a_geom = g_value_get_boxed (a); + const ClutterGeometry *b_geom = g_value_get_boxed (b); + ClutterGeometry res = { 0, }; + gint a_width = a_geom->width; + gint b_width = b_geom->width; + gint a_height = a_geom->height; + gint b_height = b_geom->height; + + res.x = a_geom->x + (b_geom->x - a_geom->x) * progress; + res.y = a_geom->y + (b_geom->y - a_geom->y) * progress; + + res.width = a_width + (b_width - a_width) * progress; + res.height = a_height + (b_height - a_height) * progress; + + g_value_set_boxed (retval, &res); + + return TRUE; +} + +G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry, + clutter_geometry_copy, + clutter_geometry_free, + CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress)); + + + +/* + * ClutterVertices + */ + +/** + * clutter_vertex_new: + * @x: X coordinate + * @y: Y coordinate + * @z: Z coordinate + * + * Creates a new #ClutterVertex for the point in 3D space + * identified by the 3 coordinates @x, @y, @z + * + * Return value: the newly allocate #ClutterVertex. Use + * clutter_vertex_free() to free the resources + * + * Since: 1.0 + */ +ClutterVertex * +clutter_vertex_new (gfloat x, + gfloat y, + gfloat z) +{ + ClutterVertex *vertex; + + vertex = g_slice_new (ClutterVertex); + clutter_vertex_init (vertex, x, y, z); + + return vertex; +} + +/** + * clutter_vertex_init: + * @vertex: a #ClutterVertex + * @x: X coordinate + * @y: Y coordinate + * @z: Z coordinate + * + * Initializes @vertex with the given coordinates. + * + * Since: 1.10 + */ +void +clutter_vertex_init (ClutterVertex *vertex, + gfloat x, + gfloat y, + gfloat z) +{ + g_return_if_fail (vertex != NULL); + + vertex->x = x; + vertex->y = y; + vertex->z = z; +} + +/** + * clutter_vertex_copy: + * @vertex: a #ClutterVertex + * + * Copies @vertex + * + * Return value: a newly allocated copy of #ClutterVertex. Use + * clutter_vertex_free() to free the allocated resources + * + * Since: 1.0 + */ +ClutterVertex * +clutter_vertex_copy (const ClutterVertex *vertex) +{ + if (G_LIKELY (vertex != NULL)) + return g_slice_dup (ClutterVertex, vertex); + + return NULL; +} + +/** + * clutter_vertex_free: + * @vertex: a #ClutterVertex + * + * Frees a #ClutterVertex allocated using clutter_vertex_copy() + * + * Since: 1.0 + */ +void +clutter_vertex_free (ClutterVertex *vertex) +{ + if (G_UNLIKELY (vertex != NULL)) + g_slice_free (ClutterVertex, vertex); +} + +/** + * clutter_vertex_equal: + * @vertex_a: a #ClutterVertex + * @vertex_b: a #ClutterVertex + * + * Compares @vertex_a and @vertex_b for equality + * + * Return value: %TRUE if the passed #ClutterVertex are equal + * + * Since: 1.0 + */ +gboolean +clutter_vertex_equal (const ClutterVertex *vertex_a, + const ClutterVertex *vertex_b) +{ + g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE); + + if (vertex_a == vertex_b) + return TRUE; + + return vertex_a->x == vertex_b->x && + vertex_a->y == vertex_b->y && + vertex_a->z == vertex_b->z; +} + +static gboolean +clutter_vertex_progress (const GValue *a, + const GValue *b, + gdouble progress, + GValue *retval) +{ + const ClutterVertex *av = g_value_get_boxed (a); + const ClutterVertex *bv = g_value_get_boxed (b); + ClutterVertex res = { 0, }; + + res.x = av->x + (bv->x - av->x) * progress; + res.y = av->y + (bv->y - av->y) * progress; + res.z = av->z + (bv->z - av->z) * progress; + + g_value_set_boxed (retval, &res); + + return TRUE; +} + +G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex, + clutter_vertex_copy, + clutter_vertex_free, + CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress)); + + + +/* + * ClutterMargin + */ + +/** + * clutter_margin_new: + * + * Creates a new #ClutterMargin. + * + * Return value: (transfer full): a newly allocated #ClutterMargin. Use + * clutter_margin_free() to free the resources associated with it when + * done. + * + * Since: 1.10 + */ +ClutterMargin * +clutter_margin_new (void) +{ + return g_slice_new0 (ClutterMargin); +} + +/** + * clutter_margin_copy: + * @margin_: a #ClutterMargin + * + * Creates a new #ClutterMargin and copies the contents of @margin_ into + * the newly created structure. + * + * Return value: (transfer full): a copy of the #ClutterMargin. + * + * Since: 1.10 + */ +ClutterMargin * +clutter_margin_copy (const ClutterMargin *margin_) +{ + if (G_LIKELY (margin_ != NULL)) + return g_slice_dup (ClutterMargin, margin_); + + return NULL; +} + +/** + * clutter_margin_free: + * @margin_: a #ClutterMargin + * + * Frees the resources allocated by clutter_margin_new() and + * clutter_margin_copy(). + * + * Since: 1.10 + */ +void +clutter_margin_free (ClutterMargin *margin_) +{ + if (G_LIKELY (margin_ != NULL)) + g_slice_free (ClutterMargin, margin_); +} + +G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin, + clutter_margin_copy, + clutter_margin_free) + + + +/* + * ClutterPoint + */ + +ClutterPoint * +clutter_point_new (void) +{ + return g_slice_new0 (ClutterPoint); +} + +ClutterPoint * +clutter_point_init (ClutterPoint *point, + float x, + float y) +{ + g_return_val_if_fail (point != NULL, NULL); + + point->x = x; + point->y = y; + + return point; +} + +ClutterPoint * +clutter_point_copy (const ClutterPoint *point) +{ + return g_slice_dup (ClutterPoint, point); +} + +void +clutter_point_free (ClutterPoint *point) +{ + if (point != NULL) + g_slice_free (ClutterPoint, point); +} + +gboolean +clutter_point_equals (const ClutterPoint *a, + const ClutterPoint *b) +{ + if (a == b) + return TRUE; + + if (a == NULL || b == NULL) + return FALSE; + + return a->x == b->x && a->y == b->y; +} + +static gboolean +clutter_point_progress (const GValue *a, + const GValue *b, + gdouble progress, + GValue *retval) +{ + const ClutterPoint *ap = g_value_get_boxed (a); + const ClutterPoint *bp = g_value_get_boxed (b); + ClutterPoint res = CLUTTER_POINT_INIT (0, 0); + + res.x = ap->x + (bp->x - ap->x) * progress; + res.y = ap->y + (bp->y - ap->y) * progress; + + g_value_set_boxed (retval, &res); + + return TRUE; +} + +G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterPoint, clutter_point, + clutter_point_copy, + clutter_point_free, + CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_point_progress)) + + + +/* + * ClutterSize + */ + +ClutterSize * +clutter_size_new (void) +{ + return g_slice_new0 (ClutterSize); +} + +ClutterSize * +clutter_size_init (ClutterSize *size, + float width, + float height) +{ + g_return_val_if_fail (size != NULL, NULL); + + size->width = width; + size->height = height; + + return size; +} + +ClutterSize * +clutter_size_copy (const ClutterSize *size) +{ + return g_slice_dup (ClutterSize, size); +} + +void +clutter_size_free (ClutterSize *size) +{ + if (size != NULL) + g_slice_free (ClutterSize, size); +} + +gboolean +clutter_size_equals (const ClutterSize *a, + const ClutterSize *b) +{ + if (a == b) + return TRUE; + + if (a == NULL || b == NULL) + return FALSE; + + return a->width == b->width && a->height == b->height; +} + +static gboolean +clutter_size_progress (const GValue *a, + const GValue *b, + gdouble progress, + GValue *retval) +{ + const ClutterSize *as = g_value_get_boxed (a); + const ClutterSize *bs = g_value_get_boxed (b); + ClutterSize res = CLUTTER_SIZE_INIT (0, 0); + + res.width = as->width + (bs->width - as->width) * progress; + res.height = as->height + (bs->height - as->height) * progress; + + g_value_set_boxed (retval, &res); + + return TRUE; +} + +G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterSize, clutter_size, + clutter_size_copy, + clutter_size_free, + CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_size_progress)) + + + +/* + * ClutterRect + */ + +static gboolean clutter_rect_progress (const GValue *a, + const GValue *b, + gdouble progress, + GValue *res); + +G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterRect, clutter_rect, + clutter_rect_copy, + clutter_rect_free, + CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_rect_progress)) + +static inline void +clutter_rect_normalize_internal (ClutterRect *rect) +{ + if (rect->size.width >= 0.f && rect->size.height >= 0.f) + return; + + if (rect->size.width < 0.f) + { + float size = fabsf (rect->size.width); + + rect->origin.x -= size; + rect->size.width = size; + } + + if (rect->size.height < 0.f) + { + float size = fabsf (rect->size.height); + + rect->origin.y -= size; + rect->size.height = size; + } +} + +/** + * clutter_rect_new: + * + * Creates a new, empty #ClutterRect. + * + * You can use clutter_rect_init() to initialize the returned rectangle, + * for instance: + * + * |[ + * ClutterRect *rect; + * + * rect = clutter_rect_init (clutter_rect_new (), x, y, width, height); + * ]| + * + * Return value: (transfer full): the newly allocated #ClutterRect. + * Use clutter_rect_free() to free its resources + * + * Since: 1.12 + */ +ClutterRect * +clutter_rect_new (void) +{ + return g_slice_new0 (ClutterRect); +} + +/** + * clutter_rect_init: + * @rect: a #ClutterRect + * @x: X coordinate of the origin + * @y: Y coordinate of the origin + * @width: width of the rectangle + * @height: height of the rectangle + * + * Initializes a #ClutterRect with the given origin and size. + * + * Return value: (transfer none): the updated rectangle + * + * Since: 1.12 + */ +ClutterRect * +clutter_rect_init (ClutterRect *rect, + float x, + float y, + float width, + float height) +{ + g_return_val_if_fail (rect != NULL, NULL); + + rect->origin.x = x; + rect->origin.y = y; + + rect->size.width = width; + rect->size.height = height; + + return rect; +} + +/** + * clutter_rect_copy: + * @rect: a #ClutterRect + * + * Copies @rect into a new #ClutterRect instance. + * + * Return value: (transfer full): the newly allocate copy of @rect. + * Use clutter_rect_free() to free the associated resources + * + * Since: 1.12 + */ +ClutterRect * +clutter_rect_copy (const ClutterRect *rect) +{ + if (rect != NULL) + { + ClutterRect *res; + + res = g_slice_dup (ClutterRect, rect); + clutter_rect_normalize_internal (res); + + return res; + } + + return NULL; +} + +/** + * clutter_rect_free: + * @rect: a #ClutterRect + * + * Frees the resources allocated by @rect. + * + * Since: 1.12 + */ +void +clutter_rect_free (ClutterRect *rect) +{ + if (rect != NULL) + g_slice_free (ClutterRect, rect); +} + +/** + * clutter_rect_equals: + * @a: a #ClutterRect + * @b: a #ClutterRect + * + * Checks whether @a and @b are equals. + * + * This function will normalize both @a and @b before comparing + * their origin and size. + * + * Return value: %TRUE if the rectangles match in origin and size. + * + * Since: 1.12 + */ +gboolean +clutter_rect_equals (ClutterRect *a, + ClutterRect *b) +{ + if (a == b) + return TRUE; + + if (a == NULL || b == NULL) + return FALSE; + + clutter_rect_normalize_internal (a); + clutter_rect_normalize_internal (b); + + return clutter_point_equals (&a->origin, &b->origin) && + clutter_size_equals (&a->size, &b->size); +} + +/** + * clutter_rect_normalize: + * @rect: a #ClutterRect + * + * Normalizes a #ClutterRect. + * + * A #ClutterRect is defined by the area covered by its size; this means + * that a #ClutterRect with #ClutterRect.origin in [ 0, 0 ] and a + * #ClutterRect.size of [ 10, 10 ] is equivalent to a #ClutterRect with + * #ClutterRect.origin in [ 10, 10 ] and a #ClutterRect.size of [ -10, -10 ]. + * + * This function is useful to ensure that a rectangle has positive width + * and height; it will modify the passed @rect and normalize its size. + * + * Since: 1.12 + */ +ClutterRect * +clutter_rect_normalize (ClutterRect *rect) +{ + g_return_val_if_fail (rect != NULL, NULL); + + clutter_rect_normalize_internal (rect); + + return rect; +} + +/** + * clutter_rect_get_center: + * @rect: a #ClutterRect + * @center: (out caller-allocates): a #ClutterPoint + * + * Retrieves the center of @rect, after normalizing the rectangle, + * and updates @center with the correct coordinates. + * + * Since: 1.12 + */ +void +clutter_rect_get_center (ClutterRect *rect, + ClutterPoint *center) +{ + g_return_if_fail (rect != NULL); + g_return_if_fail (center != NULL); + + clutter_rect_normalize_internal (rect); + + center->x = rect->origin.x + (rect->size.width / 2.0f); + center->y = rect->origin.y + (rect->size.height / 2.0f); +} + +/** + * clutter_rect_contains_point: + * @rect: a #ClutterRect + * @point: the point to check + * + * Checks whether @point is contained by @rect, after normalizing the + * rectangle. + * + * Return value: %TRUE if the @point is contained by @rect. + * + * Since: 1.12 + */ +gboolean +clutter_rect_contains_point (ClutterRect *rect, + ClutterPoint *point) +{ + g_return_val_if_fail (rect != NULL, FALSE); + g_return_val_if_fail (point != NULL, FALSE); + + clutter_rect_normalize_internal (rect); + + return (point->x >= rect->origin.x) && + (point->y >= rect->origin.y) && + (point->x <= (rect->origin.x + rect->size.width)) && + (point->y <= (rect->origin.y + rect->size.height)); +} + +/** + * clutter_rect_union: + * @a: a #ClutterRect + * @b: a #ClutterRect + * @res: (out caller-allocates): a #ClutterRect + * + * Computes the smallest possible rectangle capable of fully containing + * both @a and @b, and places it into @res. + * + * This function will normalize both @a and @b prior to computing their + * union. + * + * Since: 1.12 + */ +void +clutter_rect_union (ClutterRect *a, + ClutterRect *b, + ClutterRect *res) +{ + g_return_if_fail (a != NULL); + g_return_if_fail (b != NULL); + g_return_if_fail (res != NULL); + + clutter_rect_normalize_internal (a); + clutter_rect_normalize_internal (b); + + res->origin.x = MIN (a->origin.x, b->origin.x); + res->origin.y = MIN (a->origin.y, b->origin.y); + + res->size.width = MAX (a->size.width, b->size.width); + res->size.height = MAX (a->size.height, b->size.height); +} + +/** + * clutter_rect_intersection: + * @a: a #ClutterRect + * @b: a #ClutterRect + * @res: (out caller-allocates) (allow-none): a #ClutterRect, or %NULL + * + * Computes the intersection of @a and @b, and places it in @res, if @res + * is not %NULL. + * + * This function will normalize both @a and @b prior to computing their + * intersection. + * + * This function can be used to simply check if the intersection of @a and @b + * is not empty, by using %NULL for @res. + * + * Return value: %TRUE if the intersection of @a and @b is not empty + * + * Since: 1.12 + */ +gboolean +clutter_rect_intersection (ClutterRect *a, + ClutterRect *b, + ClutterRect *res) +{ + float x_1, y_1, x_2, y_2; + + g_return_val_if_fail (a != NULL, FALSE); + g_return_val_if_fail (b != NULL, FALSE); + + clutter_rect_normalize_internal (a); + clutter_rect_normalize_internal (b); + + x_1 = MAX (a->origin.x, b->origin.y); + y_1 = MAX (a->origin.y, b->origin.y); + x_2 = MIN (a->origin.x + a->size.width, b->origin.x + b->size.width); + y_2 = MIN (a->origin.y + a->size.height, b->origin.y + b->size.height); + + if (x_1 >= x_2 || y_1 >= y_2) + { + if (res != NULL) + clutter_rect_init (res, 0.f, 0.f, 0.f, 0.f); + + return FALSE; + } + + if (res != NULL) + clutter_rect_init (res, x_1, y_1, x_2 - x_1, y_2 - y_1); + + return TRUE; +} + +/** + * clutter_rect_offset: + * @rect: a #ClutterRect + * @d_x: the horizontal offset value + * @d_y: the vertical offset value + * + * Offsets the origin of @rect by the given values, after normalizing + * the rectangle. + * + * Since: 1.12 + */ +void +clutter_rect_offset (ClutterRect *rect, + float d_x, + float d_y) +{ + g_return_if_fail (rect != NULL); + + clutter_rect_normalize_internal (rect); + + rect->origin.x += d_x; + rect->origin.y += d_y; +} + +/** + * clutter_rect_inset: + * @rect: a #ClutterRect + * @d_x: an horizontal value; a positive @d_x will create an inset rectangle, + * and a negative value will create a larger rectangle + * @d_y: a vertical value; a positive @d_x will create an inset rectangle, + * and a negative value will create a larger rectangle + * + * Normalizes the @rect and offsets its origin by the @d_x and @d_y values; + * the size is adjusted by (2 * @d_x, 2 * @d_y). + * + * If @d_x and @d_y are positive the size of the rectangle is decreased; if + * the values are negative, the size of the rectangle is increased. + * + * If the resulting rectangle has a negative width or height, the size is + * set to 0. + * + * Since: 1.12 + */ +void +clutter_rect_inset (ClutterRect *rect, + float d_x, + float d_y) +{ + g_return_if_fail (rect != NULL); + + clutter_rect_normalize_internal (rect); + + rect->origin.x += d_x; + rect->origin.y += d_y; + + if (d_x >= 0.f) + rect->size.width -= (d_x * 2.f); + else + rect->size.width += (d_x * -2.f); + + if (d_y >= 0.f) + rect->size.height -= (d_y * 2.f); + else + rect->size.height += (d_y * -2.f); + + if (rect->size.width < 0.f) + rect->size.width = 0.f; + + if (rect->size.height < 0.f) + rect->size.height = 0.f; +} + +/** + * clutter_rect_clamp_to_pixel: + * @rect: a #ClutterRect + * + * Rounds the origin of @rect downwards to the nearest integer, and rounds + * the size of @rect upwards to the nearest integer, so that @rect is + * updated to the smallest rectangle capable of fully containing the + * original, fractional rectangle. + * + * Since: 1.12 + */ +void +clutter_rect_clamp_to_pixel (ClutterRect *rect) +{ + g_return_if_fail (rect != NULL); + + clutter_rect_normalize_internal (rect); + + rect->origin.x = floorf (rect->origin.x); + rect->origin.y = floorf (rect->origin.y); + + rect->size.width = ceilf (rect->size.width); + rect->size.height = ceilf (rect->size.height); +} + +/** + * clutter_rect_get_x: + * @rect: a #ClutterRect + * + * Retrieves the X coordinate of the origin of @rect. + * + * Return value: the X coordinate of the origin of the rectangle + * + * Since: 1.12 + */ +float +clutter_rect_get_x (ClutterRect *rect) +{ + g_return_val_if_fail (rect != NULL, 0.f); + + clutter_rect_normalize_internal (rect); + + return rect->origin.x; +} + +/** + * clutter_rect_get_y: + * @rect: a #ClutterRect + * + * Retrieves the Y coordinate of the origin of @rect. + * + * Return value: the Y coordinate of the origin of the rectangle + * + * Since: 1.12 + */ +float +clutter_rect_get_y (ClutterRect *rect) +{ + g_return_val_if_fail (rect != NULL, 0.f); + + clutter_rect_normalize_internal (rect); + + return rect->origin.y; +} + +/** + * clutter_rect_get_width: + * @rect: a #ClutterRect + * + * Retrieves the width of @rect. + * + * Return value: the width of the rectangle + * + * Since: 1.12 + */ +float +clutter_rect_get_width (ClutterRect *rect) +{ + g_return_val_if_fail (rect != NULL, 0.f); + + clutter_rect_normalize_internal (rect); + + return rect->size.width; +} + +/** + * clutter_rect_get_height: + * @rect: a #ClutterRect + * + * Retrieves the height of @rect. + * + * Return value: the height of the rectangle + * + * Since: 1.12 + */ +float +clutter_rect_get_height (ClutterRect *rect) +{ + g_return_val_if_fail (rect != NULL, 0.f); + + clutter_rect_normalize_internal (rect); + + return rect->size.height; +} + +static gboolean +clutter_rect_progress (const GValue *a, + const GValue *b, + gdouble progress, + GValue *retval) +{ + const ClutterRect *rect_a = g_value_get_boxed (a); + const ClutterRect *rect_b = g_value_get_boxed (b); + ClutterRect res = CLUTTER_RECT_INIT_ZERO; + +#define INTERPOLATE(r_a,r_b,member,field,factor) ((r_a)->member.field + (((r_b)->member.field - ((r_b)->member.field)) * (factor))) + + res.origin.x = INTERPOLATE (rect_a, rect_b, origin, x, progress); + res.origin.y = INTERPOLATE (rect_a, rect_b, origin, y, progress); + + res.size.width = INTERPOLATE (rect_a, rect_b, size, width, progress); + res.size.height = INTERPOLATE (rect_a, rect_b, size, height, progress); + +#undef INTERPOLATE + + g_value_set_boxed (retval, &res); + + return TRUE; +} diff --git a/clutter/clutter-types.h b/clutter/clutter-types.h index dde9b4030..07c47abec 100644 --- a/clutter/clutter-types.h +++ b/clutter/clutter-types.h @@ -43,6 +43,9 @@ G_BEGIN_DECLS #define CLUTTER_TYPE_PAINT_VOLUME (clutter_paint_volume_get_type ()) #define CLUTTER_TYPE_PERSPECTIVE (clutter_perspective_get_type ()) #define CLUTTER_TYPE_VERTEX (clutter_vertex_get_type ()) +#define CLUTTER_TYPE_POINT (clutter_point_get_type ()) +#define CLUTTER_TYPE_SIZE (clutter_size_get_type ()) +#define CLUTTER_TYPE_RECT (clutter_rect_get_type ()) typedef struct _ClutterActor ClutterActor; @@ -73,15 +76,18 @@ typedef struct _ClutterPath ClutterPath; typedef struct _ClutterActorBox ClutterActorBox; typedef struct _ClutterColor ClutterColor; -typedef struct _ClutterFog ClutterFog; typedef struct _ClutterGeometry ClutterGeometry; typedef struct _ClutterKnot ClutterKnot; typedef struct _ClutterMargin ClutterMargin; typedef struct _ClutterPerspective ClutterPerspective; +typedef struct _ClutterPoint ClutterPoint; +typedef struct _ClutterRect ClutterRect; +typedef struct _ClutterSize ClutterSize; typedef struct _ClutterVertex ClutterVertex; -typedef struct _ClutterBehaviour ClutterBehaviour; -typedef struct _ClutterShader ClutterShader; +typedef struct _ClutterFog ClutterFog; /* deprecated */ +typedef struct _ClutterBehaviour ClutterBehaviour; /* deprecated */ +typedef struct _ClutterShader ClutterShader; /* deprecated */ typedef union _ClutterEvent ClutterEvent; @@ -105,13 +111,137 @@ typedef union _ClutterEvent ClutterEvent; */ typedef struct _ClutterPaintVolume ClutterPaintVolume; +/** + * ClutterPoint: + * @x: X coordinate, in pixels + * @y: Y coordinate, in pixels + * + * A point in 2D space. + * + * Since: 1.12 + */ +struct _ClutterPoint +{ + float x; + float y; +}; + +#define CLUTTER_POINT_INIT(x,y) { (x), (y) } +#define CLUTTER_POINT_INIT_ZERO CLUTTER_POINT_INIT (0.f, 0.f) + +GType clutter_point_get_type (void) G_GNUC_CONST; + +ClutterPoint * clutter_point_new (void); +ClutterPoint * clutter_point_init (ClutterPoint *point, + float x, + float y); +ClutterPoint * clutter_point_copy (const ClutterPoint *point); +void clutter_point_free (ClutterPoint *point); +gboolean clutter_point_equals (const ClutterPoint *a, + const ClutterPoint *b); + +/** + * ClutterSize: + * @width: the width, in pixels + * @height: the height, in pixels + * + * A size, in 2D space. + * + * Since: 1.12 + */ +struct _ClutterSize +{ + float width; + float height; +}; + +#define CLUTTER_SIZE_INIT(width,height) { (width), (height) } +#define CLUTTER_SIZE_INIT_ZERO CLUTTER_SIZE_INIT (0.f, 0.f) + +GType clutter_size_get_type (void) G_GNUC_CONST; + +ClutterSize * clutter_size_new (void); +ClutterSize * clutter_size_init (ClutterSize *size, + float width, + float height); +ClutterSize * clutter_size_copy (const ClutterSize *size); +void clutter_size_free (ClutterSize *size); +gboolean clutter_size_equals (const ClutterSize *a, + const ClutterSize *b); + +/** + * ClutterRect: + * @origin: the origin of the rectangle + * @size: the size of the rectangle + * + * The location and size of a rectangle. + * + * The width and height of a #ClutterRect can be negative; Clutter considers + * a rectangle with an origin of [ 0.0, 0.0 ] and a size of [ 10.0, 10.0 ] to + * be equivalent to a rectangle with origin of [ 10.0, 10.0 ] and size of + * [ -10.0, -10.0 ]. + * + * Application code can normalize rectangles using clutter_rect_normalize(): + * this function will ensure that the width and height of a #ClutterRect are + * positive values. All functions taking a #ClutterRect as an argument will + * implicitly normalize it before computing eventual results. For this reason + * it is safer to access the contents of a #ClutterRect by using the provided + * API at all times, instead of directly accessing the structure members. + * + * Since: 1.12 + */ +struct _ClutterRect +{ + ClutterPoint origin; + ClutterSize size; +}; + +#define CLUTTER_RECT_INIT(x,y,width,height) { { (x), (y) }, { (width), (height) } } +#define CLUTTER_RECT_INIT_ZERO CLUTTER_RECT_INIT (0.f, 0.f, 0.f, 0.f) + +GType clutter_rect_get_type (void) G_GNUC_CONST; + +ClutterRect * clutter_rect_new (void); +ClutterRect * clutter_rect_init (ClutterRect *rect, + float x, + float y, + float width, + float height); +ClutterRect * clutter_rect_copy (const ClutterRect *rect); +void clutter_rect_free (ClutterRect *rect); +gboolean clutter_rect_equals (ClutterRect *a, + ClutterRect *b); + +ClutterRect * clutter_rect_normalize (ClutterRect *rect); +void clutter_rect_get_center (ClutterRect *rect, + ClutterPoint *center); +gboolean clutter_rect_contains_point (ClutterRect *rect, + ClutterPoint *point); +void clutter_rect_union (ClutterRect *a, + ClutterRect *b, + ClutterRect *res); +gboolean clutter_rect_intersection (ClutterRect *a, + ClutterRect *b, + ClutterRect *res); +void clutter_rect_offset (ClutterRect *rect, + float d_x, + float d_y); +void clutter_rect_inset (ClutterRect *rect, + float d_x, + float d_y); +void clutter_rect_clamp_to_pixel (ClutterRect *rect); +float clutter_rect_get_x (ClutterRect *rect); +float clutter_rect_get_y (ClutterRect *rect); +float clutter_rect_get_width (ClutterRect *rect); +float clutter_rect_get_height (ClutterRect *rect); + /** * ClutterVertex: * @x: X coordinate of the vertex * @y: Y coordinate of the vertex * @z: Z coordinate of the vertex * - * Vertex of an actor in 3D space, expressed in pixels + * A point in 3D space, expressed in pixels * * Since: 0.4 */ diff --git a/clutter/clutter.symbols b/clutter/clutter.symbols index 418db4161..4f93ba9b2 100644 --- a/clutter/clutter.symbols +++ b/clutter/clutter.symbols @@ -977,11 +977,35 @@ clutter_pick_debug_flags DATA clutter_pipeline_node_get_type clutter_pipeline_node_new clutter_pick_mode_get_type +clutter_point_copy +clutter_point_equals +clutter_point_free +clutter_point_get_type +clutter_point_init +clutter_point_new clutter_profile_flags DATA clutter_property_transition_get_property_name clutter_property_transition_get_type clutter_property_transition_new clutter_property_transition_set_property_name +clutter_rect_clamp_to_pixel +clutter_rect_contains_point +clutter_rect_copy +clutter_rect_equals +clutter_rect_free +clutter_rect_get_center +clutter_rect_get_height +clutter_rect_get_type +clutter_rect_get_width +clutter_rect_get_x +clutter_rect_get_y +clutter_rect_init +clutter_rect_inset +clutter_rect_intersection +clutter_rect_new +clutter_rect_normalize +clutter_rect_offset +clutter_rect_union clutter_rectangle_get_border_color clutter_rectangle_get_border_width clutter_rectangle_get_color @@ -1071,6 +1095,12 @@ clutter_shader_set_is_enabled clutter_shader_set_uniform clutter_shader_set_vertex_source clutter_shader_type_get_type +clutter_size_copy +clutter_size_equals +clutter_size_free +clutter_size_get_type +clutter_size_init +clutter_size_new clutter_snap_constraint_get_edges clutter_snap_constraint_get_offset clutter_snap_constraint_get_source