1 | /* GDK - The GIMP Drawing Kit |
2 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | /* |
19 | * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS |
20 | * file for a list of people on the GTK+ Team. See the ChangeLog |
21 | * files for a list of changes. These files are distributed with |
22 | * GTK+ at ftp://ftp.gtk.org/pub/gtk/. |
23 | */ |
24 | |
25 | #include "config.h" |
26 | |
27 | #include "gdkrectangle.h" |
28 | #include <cairo-gobject.h> |
29 | |
30 | |
31 | /** |
32 | * GdkRectangle: |
33 | * @x: the x coordinate of the top left corner |
34 | * @y: the y coordinate of the top left corner |
35 | * @width: the width of the rectangle |
36 | * @height: the height of the rectangle |
37 | * |
38 | * A `GdkRectangle` data type for representing rectangles. |
39 | * |
40 | * `GdkRectangle` is identical to `cairo_rectangle_t`. Together with Cairo’s |
41 | * `cairo_region_t` data type, these are the central types for representing |
42 | * sets of pixels. |
43 | * |
44 | * The intersection of two rectangles can be computed with |
45 | * [method@Gdk.Rectangle.intersect]; to find the union of two rectangles use |
46 | * [method@Gdk.Rectangle.union]. |
47 | * |
48 | * The `cairo_region_t` type provided by Cairo is usually used for managing |
49 | * non-rectangular clipping of graphical operations. |
50 | * |
51 | * The Graphene library has a number of other data types for regions and |
52 | * volumes in 2D and 3D. |
53 | */ |
54 | |
55 | |
56 | /** |
57 | * gdk_rectangle_union: |
58 | * @src1: a `GdkRectangle` |
59 | * @src2: a `GdkRectangle` |
60 | * @dest: (out): return location for the union of @src1 and @src2 |
61 | * |
62 | * Calculates the union of two rectangles. |
63 | * |
64 | * The union of rectangles @src1 and @src2 is the smallest rectangle which |
65 | * includes both @src1 and @src2 within it. It is allowed for @dest to be |
66 | * the same as either @src1 or @src2. |
67 | * |
68 | * Note that this function does not ignore 'empty' rectangles (ie. with |
69 | * zero width or height). |
70 | */ |
71 | void |
72 | gdk_rectangle_union (const GdkRectangle *src1, |
73 | const GdkRectangle *src2, |
74 | GdkRectangle *dest) |
75 | { |
76 | int dest_x, dest_y; |
77 | |
78 | g_return_if_fail (src1 != NULL); |
79 | g_return_if_fail (src2 != NULL); |
80 | g_return_if_fail (dest != NULL); |
81 | |
82 | dest_x = MIN (src1->x, src2->x); |
83 | dest_y = MIN (src1->y, src2->y); |
84 | dest->width = MAX (src1->x + src1->width, src2->x + src2->width) - dest_x; |
85 | dest->height = MAX (src1->y + src1->height, src2->y + src2->height) - dest_y; |
86 | dest->x = dest_x; |
87 | dest->y = dest_y; |
88 | } |
89 | |
90 | /** |
91 | * gdk_rectangle_intersect: |
92 | * @src1: a `GdkRectangle` |
93 | * @src2: a `GdkRectangle` |
94 | * @dest: (out caller-allocates) (optional): return location for the |
95 | * intersection of @src1 and @src2 |
96 | * |
97 | * Calculates the intersection of two rectangles. |
98 | * |
99 | * It is allowed for @dest to be the same as either @src1 or @src2. |
100 | * If the rectangles do not intersect, @dest’s width and height is set |
101 | * to 0 and its x and y values are undefined. If you are only interested |
102 | * in whether the rectangles intersect, but not in the intersecting area |
103 | * itself, pass %NULL for @dest. |
104 | * |
105 | * Returns: %TRUE if the rectangles intersect. |
106 | */ |
107 | gboolean |
108 | gdk_rectangle_intersect (const GdkRectangle *src1, |
109 | const GdkRectangle *src2, |
110 | GdkRectangle *dest) |
111 | { |
112 | int dest_x, dest_y; |
113 | int dest_x2, dest_y2; |
114 | int return_val; |
115 | |
116 | g_return_val_if_fail (src1 != NULL, FALSE); |
117 | g_return_val_if_fail (src2 != NULL, FALSE); |
118 | |
119 | return_val = FALSE; |
120 | |
121 | dest_x = MAX (src1->x, src2->x); |
122 | dest_y = MAX (src1->y, src2->y); |
123 | dest_x2 = MIN (src1->x + src1->width, src2->x + src2->width); |
124 | dest_y2 = MIN (src1->y + src1->height, src2->y + src2->height); |
125 | |
126 | if (dest_x2 > dest_x && dest_y2 > dest_y) |
127 | { |
128 | if (dest) |
129 | { |
130 | dest->x = dest_x; |
131 | dest->y = dest_y; |
132 | dest->width = dest_x2 - dest_x; |
133 | dest->height = dest_y2 - dest_y; |
134 | } |
135 | return_val = TRUE; |
136 | } |
137 | else if (dest) |
138 | { |
139 | dest->width = 0; |
140 | dest->height = 0; |
141 | } |
142 | |
143 | return return_val; |
144 | } |
145 | |
146 | /** |
147 | * gdk_rectangle_contains_point: |
148 | * @rect: a `GdkRectangle` |
149 | * @x: X coordinate |
150 | * @y: Y coordinate |
151 | * |
152 | * Returns %TRUE if @rect contains the point described by @x and @y. |
153 | * |
154 | * Returns: %TRUE if @rect contains the point |
155 | **/ |
156 | gboolean |
157 | gdk_rectangle_contains_point (const GdkRectangle *rect, |
158 | int x, |
159 | int y) |
160 | { |
161 | g_return_val_if_fail (rect != NULL, FALSE); |
162 | |
163 | return x >= rect->x && |
164 | x < rect->x + rect->width && |
165 | y >= rect->y && |
166 | y < rect->y + rect->height; |
167 | } |
168 | |
169 | /** |
170 | * gdk_rectangle_equal: |
171 | * @rect1: a `GdkRectangle` |
172 | * @rect2: a `GdkRectangle` |
173 | * |
174 | * Checks if the two given rectangles are equal. |
175 | * |
176 | * Returns: %TRUE if the rectangles are equal. |
177 | */ |
178 | gboolean |
179 | gdk_rectangle_equal (const GdkRectangle *rect1, |
180 | const GdkRectangle *rect2) |
181 | { |
182 | return rect1->x == rect2->x |
183 | && rect1->y == rect2->y |
184 | && rect1->width == rect2->width |
185 | && rect1->height == rect2->height; |
186 | } |
187 | |
188 | static GdkRectangle * |
189 | gdk_rectangle_copy (const GdkRectangle *rectangle) |
190 | { |
191 | GdkRectangle *result = g_new (GdkRectangle, 1); |
192 | *result = *rectangle; |
193 | |
194 | return result; |
195 | } |
196 | |
197 | /* Transforms between identical boxed types. |
198 | */ |
199 | static void |
200 | gdk_rectangle_value_transform_rect (const GValue *src_value, GValue *dest_value) |
201 | { |
202 | g_value_set_boxed (value: dest_value, v_boxed: g_value_get_boxed (value: src_value)); |
203 | } |
204 | |
205 | /* Allow GValue transformation between the identical structs |
206 | * cairo_rectangle_int_t and GdkRectangle. |
207 | */ |
208 | static void |
209 | gdk_rectangle_register_value_transform_funcs (GType gtype_gdk_rectangle) |
210 | { |
211 | /* This function is called from the first call to gdk_rectangle_get_type(), |
212 | * before g_once_init_leave() has been called. |
213 | * If gdk_rectangle_get_type() is called from here (e.g. via |
214 | * GDK_TYPE_RECTANGLE), the program will wait indefinitely at |
215 | * g_once_init_enter() in gdk_rectangle_get_type(). |
216 | */ |
217 | g_value_register_transform_func (CAIRO_GOBJECT_TYPE_RECTANGLE_INT, |
218 | dest_type: gtype_gdk_rectangle, |
219 | transform_func: gdk_rectangle_value_transform_rect); |
220 | g_value_register_transform_func (src_type: gtype_gdk_rectangle, |
221 | CAIRO_GOBJECT_TYPE_RECTANGLE_INT, |
222 | transform_func: gdk_rectangle_value_transform_rect); |
223 | } |
224 | |
225 | G_DEFINE_BOXED_TYPE_WITH_CODE (GdkRectangle, gdk_rectangle, |
226 | gdk_rectangle_copy, |
227 | g_free, |
228 | gdk_rectangle_register_value_transform_funcs (g_define_type_id)) |
229 | |
230 | |