1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 
5 #include <math.h>
6 
7 #include "clutter-types.h"
8 #include "clutter-interval.h"
9 #include "clutter-private.h"
10 
11 /**
12  * clutter_actor_box_new:
13  * @x_1: X coordinate of the top left point
14  * @y_1: Y coordinate of the top left point
15  * @x_2: X coordinate of the bottom right point
16  * @y_2: Y coordinate of the bottom right point
17  *
18  * Allocates a new #ClutterActorBox using the passed coordinates
19  * for the top left and bottom right points.
20  *
21  * This function is the logical equivalent of:
22  *
23  * |[
24  *   clutter_actor_box_init (clutter_actor_box_alloc (),
25  *                           x_1, y_1,
26  *                           x_2, y_2);
27  * ]|
28  *
29  * Return value: (transfer full): the newly allocated #ClutterActorBox.
30  *   Use clutter_actor_box_free() to free the resources
31  *
32  * Since: 1.0
33  */
34 ClutterActorBox *
clutter_actor_box_new(gfloat x_1,gfloat y_1,gfloat x_2,gfloat y_2)35 clutter_actor_box_new (gfloat x_1,
36                        gfloat y_1,
37                        gfloat x_2,
38                        gfloat y_2)
39 {
40   return clutter_actor_box_init (clutter_actor_box_alloc (),
41                                  x_1, y_1,
42                                  x_2, y_2);
43 }
44 
45 /**
46  * clutter_actor_box_alloc:
47  *
48  * Allocates a new #ClutterActorBox.
49  *
50  * Return value: (transfer full): the newly allocated #ClutterActorBox.
51  *   Use clutter_actor_box_free() to free its resources
52  *
53  * Since: 1.12
54  */
55 ClutterActorBox *
clutter_actor_box_alloc(void)56 clutter_actor_box_alloc (void)
57 {
58   return g_slice_new0 (ClutterActorBox);
59 }
60 
61 /**
62  * clutter_actor_box_init:
63  * @box: a #ClutterActorBox
64  * @x_1: X coordinate of the top left point
65  * @y_1: Y coordinate of the top left point
66  * @x_2: X coordinate of the bottom right point
67  * @y_2: Y coordinate of the bottom right point
68  *
69  * Initializes @box with the given coordinates.
70  *
71  * Return value: (transfer none): the initialized #ClutterActorBox
72  *
73  * Since: 1.10
74  */
75 ClutterActorBox *
clutter_actor_box_init(ClutterActorBox * box,gfloat x_1,gfloat y_1,gfloat x_2,gfloat y_2)76 clutter_actor_box_init (ClutterActorBox *box,
77                         gfloat           x_1,
78                         gfloat           y_1,
79                         gfloat           x_2,
80                         gfloat           y_2)
81 {
82   g_return_val_if_fail (box != NULL, NULL);
83 
84   box->x1 = x_1;
85   box->y1 = y_1;
86   box->x2 = x_2;
87   box->y2 = y_2;
88 
89   return box;
90 }
91 
92 /**
93  * clutter_actor_box_init_rect:
94  * @box: a #ClutterActorBox
95  * @x: X coordinate of the origin
96  * @y: Y coordinate of the origin
97  * @width: width of the box
98  * @height: height of the box
99  *
100  * Initializes @box with the given origin and size.
101  *
102  * Since: 1.10
103  */
104 void
clutter_actor_box_init_rect(ClutterActorBox * box,gfloat x,gfloat y,gfloat width,gfloat height)105 clutter_actor_box_init_rect (ClutterActorBox *box,
106                              gfloat           x,
107                              gfloat           y,
108                              gfloat           width,
109                              gfloat           height)
110 {
111   g_return_if_fail (box != NULL);
112 
113   box->x1 = x;
114   box->y1 = y;
115   box->x2 = box->x1 + width;
116   box->y2 = box->y1 + height;
117 }
118 
119 /**
120  * clutter_actor_box_copy:
121  * @box: a #ClutterActorBox
122  *
123  * Copies @box
124  *
125  * Return value: a newly allocated copy of #ClutterActorBox. Use
126  *   clutter_actor_box_free() to free the allocated resources
127  *
128  * Since: 1.0
129  */
130 ClutterActorBox *
clutter_actor_box_copy(const ClutterActorBox * box)131 clutter_actor_box_copy (const ClutterActorBox *box)
132 {
133   if (G_LIKELY (box != NULL))
134     return g_slice_dup (ClutterActorBox, box);
135 
136   return NULL;
137 }
138 
139 /**
140  * clutter_actor_box_free:
141  * @box: a #ClutterActorBox
142  *
143  * Frees a #ClutterActorBox allocated using clutter_actor_box_new()
144  * or clutter_actor_box_copy()
145  *
146  * Since: 1.0
147  */
148 void
clutter_actor_box_free(ClutterActorBox * box)149 clutter_actor_box_free (ClutterActorBox *box)
150 {
151   if (G_LIKELY (box != NULL))
152     g_slice_free (ClutterActorBox, box);
153 }
154 
155 /**
156  * clutter_actor_box_equal:
157  * @box_a: a #ClutterActorBox
158  * @box_b: a #ClutterActorBox
159  *
160  * Checks @box_a and @box_b for equality
161  *
162  * Return value: %TRUE if the passed #ClutterActorBox are equal
163  *
164  * Since: 1.0
165  */
166 gboolean
clutter_actor_box_equal(const ClutterActorBox * box_a,const ClutterActorBox * box_b)167 clutter_actor_box_equal (const ClutterActorBox *box_a,
168                          const ClutterActorBox *box_b)
169 {
170   g_return_val_if_fail (box_a != NULL && box_b != NULL, FALSE);
171 
172   if (box_a == box_b)
173     return TRUE;
174 
175   return box_a->x1 == box_b->x1 && box_a->y1 == box_b->y1 &&
176          box_a->x2 == box_b->x2 && box_a->y2 == box_b->y2;
177 }
178 
179 /**
180  * clutter_actor_box_get_x:
181  * @box: a #ClutterActorBox
182  *
183  * Retrieves the X coordinate of the origin of @box
184  *
185  * Return value: the X coordinate of the origin
186  *
187  * Since: 1.0
188  */
189 gfloat
clutter_actor_box_get_x(const ClutterActorBox * box)190 clutter_actor_box_get_x (const ClutterActorBox *box)
191 {
192   g_return_val_if_fail (box != NULL, 0.);
193 
194   return box->x1;
195 }
196 
197 /**
198  * clutter_actor_box_get_y:
199  * @box: a #ClutterActorBox
200  *
201  * Retrieves the Y coordinate of the origin of @box
202  *
203  * Return value: the Y coordinate of the origin
204  *
205  * Since: 1.0
206  */
207 gfloat
clutter_actor_box_get_y(const ClutterActorBox * box)208 clutter_actor_box_get_y (const ClutterActorBox *box)
209 {
210   g_return_val_if_fail (box != NULL, 0.);
211 
212   return box->y1;
213 }
214 
215 /**
216  * clutter_actor_box_get_width:
217  * @box: a #ClutterActorBox
218  *
219  * Retrieves the width of the @box
220  *
221  * Return value: the width of the box
222  *
223  * Since: 1.0
224  */
225 gfloat
clutter_actor_box_get_width(const ClutterActorBox * box)226 clutter_actor_box_get_width (const ClutterActorBox *box)
227 {
228   g_return_val_if_fail (box != NULL, 0.);
229 
230   return box->x2 - box->x1;
231 }
232 
233 /**
234  * clutter_actor_box_get_height:
235  * @box: a #ClutterActorBox
236  *
237  * Retrieves the height of the @box
238  *
239  * Return value: the height of the box
240  *
241  * Since: 1.0
242  */
243 gfloat
clutter_actor_box_get_height(const ClutterActorBox * box)244 clutter_actor_box_get_height (const ClutterActorBox *box)
245 {
246   g_return_val_if_fail (box != NULL, 0.);
247 
248   return box->y2 - box->y1;
249 }
250 
251 /**
252  * clutter_actor_box_get_origin:
253  * @box: a #ClutterActorBox
254  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
255  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
256  *
257  * Retrieves the origin of @box
258  *
259  * Since: 1.0
260  */
261 void
clutter_actor_box_get_origin(const ClutterActorBox * box,gfloat * x,gfloat * y)262 clutter_actor_box_get_origin (const ClutterActorBox *box,
263                               gfloat                *x,
264                               gfloat                *y)
265 {
266   g_return_if_fail (box != NULL);
267 
268   if (x)
269     *x = box->x1;
270 
271   if (y)
272     *y = box->y1;
273 }
274 
275 /**
276  * clutter_actor_box_get_size:
277  * @box: a #ClutterActorBox
278  * @width: (out) (allow-none): return location for the width, or %NULL
279  * @height: (out) (allow-none): return location for the height, or %NULL
280  *
281  * Retrieves the size of @box
282  *
283  * Since: 1.0
284  */
285 void
clutter_actor_box_get_size(const ClutterActorBox * box,gfloat * width,gfloat * height)286 clutter_actor_box_get_size (const ClutterActorBox *box,
287                             gfloat                *width,
288                             gfloat                *height)
289 {
290   g_return_if_fail (box != NULL);
291 
292   if (width)
293     *width = box->x2 - box->x1;
294 
295   if (height)
296     *height = box->y2 - box->y1;
297 }
298 
299 /**
300  * clutter_actor_box_get_area:
301  * @box: a #ClutterActorBox
302  *
303  * Retrieves the area of @box
304  *
305  * Return value: the area of a #ClutterActorBox, in pixels
306  *
307  * Since: 1.0
308  */
309 gfloat
clutter_actor_box_get_area(const ClutterActorBox * box)310 clutter_actor_box_get_area (const ClutterActorBox *box)
311 {
312   g_return_val_if_fail (box != NULL, 0.);
313 
314   return (box->x2 - box->x1) * (box->y2 - box->y1);
315 }
316 
317 /**
318  * clutter_actor_box_contains:
319  * @box: a #ClutterActorBox
320  * @x: X coordinate of the point
321  * @y: Y coordinate of the point
322  *
323  * Checks whether a point with @x, @y coordinates is contained
324  * withing @box
325  *
326  * Return value: %TRUE if the point is contained by the #ClutterActorBox
327  *
328  * Since: 1.0
329  */
330 gboolean
clutter_actor_box_contains(const ClutterActorBox * box,gfloat x,gfloat y)331 clutter_actor_box_contains (const ClutterActorBox *box,
332                             gfloat                 x,
333                             gfloat                 y)
334 {
335   g_return_val_if_fail (box != NULL, FALSE);
336 
337   return (x > box->x1 && x < box->x2) &&
338          (y > box->y1 && y < box->y2);
339 }
340 
341 /**
342  * clutter_actor_box_from_vertices:
343  * @box: a #ClutterActorBox
344  * @verts: (array fixed-size=4): array of four #ClutterVertex
345  *
346  * Calculates the bounding box represented by the four vertices; for details
347  * of the vertex array see clutter_actor_get_abs_allocation_vertices().
348  *
349  * Since: 1.0
350  */
351 void
clutter_actor_box_from_vertices(ClutterActorBox * box,const ClutterVertex verts[])352 clutter_actor_box_from_vertices (ClutterActorBox     *box,
353                                  const ClutterVertex  verts[])
354 {
355   gfloat x_1, x_2, y_1, y_2;
356 
357   g_return_if_fail (box != NULL);
358   g_return_if_fail (verts != NULL);
359 
360   /* 4-way min/max */
361   x_1 = verts[0].x;
362   y_1 = verts[0].y;
363 
364   if (verts[1].x < x_1)
365     x_1 = verts[1].x;
366 
367   if (verts[2].x < x_1)
368     x_1 = verts[2].x;
369 
370   if (verts[3].x < x_1)
371     x_1 = verts[3].x;
372 
373   if (verts[1].y < y_1)
374     y_1 = verts[1].y;
375 
376   if (verts[2].y < y_1)
377     y_1 = verts[2].y;
378 
379   if (verts[3].y < y_1)
380     y_1 = verts[3].y;
381 
382   x_2 = verts[0].x;
383   y_2 = verts[0].y;
384 
385   if (verts[1].x > x_2)
386     x_2 = verts[1].x;
387 
388   if (verts[2].x > x_2)
389     x_2 = verts[2].x;
390 
391   if (verts[3].x > x_2)
392     x_2 = verts[3].x;
393 
394   if (verts[1].y > y_2)
395     y_2 = verts[1].y;
396 
397   if (verts[2].y > y_2)
398     y_2 = verts[2].y;
399 
400   if (verts[3].y > y_2)
401     y_2 = verts[3].y;
402 
403   box->x1 = x_1;
404   box->x2 = x_2;
405   box->y1 = y_1;
406   box->y2 = y_2;
407 }
408 
409 /**
410  * clutter_actor_box_interpolate:
411  * @initial: the initial #ClutterActorBox
412  * @final: the final #ClutterActorBox
413  * @progress: the interpolation progress
414  * @result: (out): return location for the interpolation
415  *
416  * Interpolates between @initial and @final #ClutterActorBox<!-- -->es
417  * using @progress
418  *
419  * Since: 1.2
420  */
421 void
clutter_actor_box_interpolate(const ClutterActorBox * initial,const ClutterActorBox * final,gdouble progress,ClutterActorBox * result)422 clutter_actor_box_interpolate (const ClutterActorBox *initial,
423                                const ClutterActorBox *final,
424                                gdouble                progress,
425                                ClutterActorBox       *result)
426 {
427   g_return_if_fail (initial != NULL);
428   g_return_if_fail (final != NULL);
429   g_return_if_fail (result != NULL);
430 
431   result->x1 = initial->x1 + (final->x1 - initial->x1) * progress;
432   result->y1 = initial->y1 + (final->y1 - initial->y1) * progress;
433   result->x2 = initial->x2 + (final->x2 - initial->x2) * progress;
434   result->y2 = initial->y2 + (final->y2 - initial->y2) * progress;
435 }
436 
437 /**
438  * clutter_actor_box_clamp_to_pixel:
439  * @box: (inout): the #ClutterActorBox to clamp
440  *
441  * Clamps the components of @box to the nearest integer
442  *
443  * Since: 1.2
444  */
445 void
clutter_actor_box_clamp_to_pixel(ClutterActorBox * box)446 clutter_actor_box_clamp_to_pixel (ClutterActorBox *box)
447 {
448   g_return_if_fail (box != NULL);
449 
450   box->x1 = floorf (box->x1);
451   box->y1 = floorf (box->y1);
452   box->x2 = ceilf (box->x2);
453   box->y2 = ceilf (box->y2);
454 }
455 
456 /**
457  * clutter_actor_box_union:
458  * @a: (in): the first #ClutterActorBox
459  * @b: (in): the second #ClutterActorBox
460  * @result: (out): the #ClutterActorBox representing a union
461  *   of @a and @b
462  *
463  * Unions the two boxes @a and @b and stores the result in @result.
464  *
465  * Since: 1.4
466  */
467 void
clutter_actor_box_union(const ClutterActorBox * a,const ClutterActorBox * b,ClutterActorBox * result)468 clutter_actor_box_union (const ClutterActorBox *a,
469                          const ClutterActorBox *b,
470                          ClutterActorBox       *result)
471 {
472   g_return_if_fail (a != NULL);
473   g_return_if_fail (b != NULL);
474   g_return_if_fail (result != NULL);
475 
476   result->x1 = MIN (a->x1, b->x1);
477   result->y1 = MIN (a->y1, b->y1);
478 
479   result->x2 = MAX (a->x2, b->x2);
480   result->y2 = MAX (a->y2, b->y2);
481 }
482 
483 static gboolean
clutter_actor_box_progress(const GValue * a,const GValue * b,gdouble factor,GValue * retval)484 clutter_actor_box_progress (const GValue *a,
485                             const GValue *b,
486                             gdouble       factor,
487                             GValue       *retval)
488 {
489   ClutterActorBox res = { 0, };
490 
491   clutter_actor_box_interpolate (g_value_get_boxed (a),
492                                  g_value_get_boxed (b),
493                                  factor,
494                                  &res);
495 
496   g_value_set_boxed (retval, &res);
497 
498   return TRUE;
499 }
500 
501 /**
502  * clutter_actor_box_set_origin:
503  * @box: a #ClutterActorBox
504  * @x: the X coordinate of the new origin
505  * @y: the Y coordinate of the new origin
506  *
507  * Changes the origin of @box, maintaining the size of the #ClutterActorBox.
508  *
509  * Since: 1.6
510  */
511 void
clutter_actor_box_set_origin(ClutterActorBox * box,gfloat x,gfloat y)512 clutter_actor_box_set_origin (ClutterActorBox *box,
513                               gfloat           x,
514                               gfloat           y)
515 {
516   gfloat width, height;
517 
518   g_return_if_fail (box != NULL);
519 
520   width = box->x2 - box->x1;
521   height = box->y2 - box->y1;
522 
523   clutter_actor_box_init_rect (box, x, y, width, height);
524 }
525 
526 /**
527  * clutter_actor_box_set_size:
528  * @box: a #ClutterActorBox
529  * @width: the new width
530  * @height: the new height
531  *
532  * Sets the size of @box, maintaining the origin of the #ClutterActorBox.
533  *
534  * Since: 1.6
535  */
536 void
clutter_actor_box_set_size(ClutterActorBox * box,gfloat width,gfloat height)537 clutter_actor_box_set_size (ClutterActorBox *box,
538                             gfloat           width,
539                             gfloat           height)
540 {
541   g_return_if_fail (box != NULL);
542 
543   box->x2 = box->x1 + width;
544   box->y2 = box->y1 + height;
545 }
546 
547 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterActorBox, clutter_actor_box,
548                                clutter_actor_box_copy,
549                                clutter_actor_box_free,
550                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_actor_box_progress));
551