1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2011 Benjamin Otte <otte@gnome.org>
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.
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.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include "gtkroundedboxprivate.h"
27 * _gtk_rounded_box_init_rect:
28 * @box: box to initialize
29 * @x: x coordinate of box
30 * @y: y coordinate of box
31 * @width: width of box
32 * @height: height of box
34 * Initializes the given @box to represent the given rectangle.
38 _gtk_rounded_box_init_rect (GtkRoundedBox *box,
44 memset (box, 0, sizeof (GtkRoundedBox));
48 box->box.width = width;
49 box->box.height = height;
52 /* clamp border radius, following CSS specs */
54 gtk_rounded_box_clamp_border_radius (GtkRoundedBox *box)
58 /* note: division by zero leads to +INF, which is > factor, so will be ignored */
59 factor = MIN (factor, box->box.width / (box->corner[GTK_CSS_TOP_LEFT].horizontal +
60 box->corner[GTK_CSS_TOP_RIGHT].horizontal));
61 factor = MIN (factor, box->box.height / (box->corner[GTK_CSS_TOP_RIGHT].vertical +
62 box->corner[GTK_CSS_BOTTOM_RIGHT].vertical));
63 factor = MIN (factor, box->box.width / (box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal +
64 box->corner[GTK_CSS_BOTTOM_LEFT].horizontal));
65 factor = MIN (factor, box->box.height / (box->corner[GTK_CSS_TOP_LEFT].vertical +
66 box->corner[GTK_CSS_BOTTOM_LEFT].vertical));
68 box->corner[GTK_CSS_TOP_LEFT].horizontal *= factor;
69 box->corner[GTK_CSS_TOP_LEFT].vertical *= factor;
70 box->corner[GTK_CSS_TOP_RIGHT].horizontal *= factor;
71 box->corner[GTK_CSS_TOP_RIGHT].vertical *= factor;
72 box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal *= factor;
73 box->corner[GTK_CSS_BOTTOM_RIGHT].vertical *= factor;
74 box->corner[GTK_CSS_BOTTOM_LEFT].horizontal *= factor;
75 box->corner[GTK_CSS_BOTTOM_LEFT].vertical *= factor;
79 _gtk_rounded_box_apply_border_radius (GtkRoundedBox *box,
80 GtkThemingEngine *engine,
82 GtkJunctionSides junction)
84 GtkCssBorderCornerRadius *corner[4];
87 gtk_theming_engine_get (engine, state,
88 /* Can't use border-radius as it's an int for
90 "border-top-left-radius", &corner[GTK_CSS_TOP_LEFT],
91 "border-top-right-radius", &corner[GTK_CSS_TOP_RIGHT],
92 "border-bottom-right-radius", &corner[GTK_CSS_BOTTOM_RIGHT],
93 "border-bottom-left-radius", &corner[GTK_CSS_BOTTOM_LEFT],
96 if (corner[GTK_CSS_TOP_LEFT] && (junction & GTK_JUNCTION_CORNER_TOPLEFT) == 0)
97 box->corner[GTK_CSS_TOP_LEFT] = *corner[GTK_CSS_TOP_LEFT];
98 if (corner[GTK_CSS_TOP_RIGHT] && (junction & GTK_JUNCTION_CORNER_TOPRIGHT) == 0)
99 box->corner[GTK_CSS_TOP_RIGHT] = *corner[GTK_CSS_TOP_RIGHT];
100 if (corner[GTK_CSS_BOTTOM_RIGHT] && (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT) == 0)
101 box->corner[GTK_CSS_BOTTOM_RIGHT] = *corner[GTK_CSS_BOTTOM_RIGHT];
102 if (corner[GTK_CSS_BOTTOM_LEFT] && (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT) == 0)
103 box->corner[GTK_CSS_BOTTOM_LEFT] = *corner[GTK_CSS_BOTTOM_LEFT];
105 gtk_rounded_box_clamp_border_radius (box);
107 for (i = 0; i < 4; i++)
112 gtk_css_border_radius_grow (GtkCssBorderCornerRadius *corner,
116 corner->horizontal += horizontal;
117 corner->vertical += vertical;
119 if (corner->horizontal <= 0 || corner->vertical <= 0)
121 corner->horizontal = 0;
122 corner->vertical = 0;
126 _gtk_rounded_box_grow (GtkRoundedBox *box,
132 if (box->box.width + left + right < 0)
134 box->box.x -= left * box->box.width / (left + right);
140 box->box.width += left + right;
143 if (box->box.height + bottom + right < 0)
145 box->box.y -= top * box->box.height / (top + bottom);
151 box->box.height += top + bottom;
154 gtk_css_border_radius_grow (&box->corner[GTK_CSS_TOP_LEFT], left, top);
155 gtk_css_border_radius_grow (&box->corner[GTK_CSS_TOP_RIGHT], right, bottom);
156 gtk_css_border_radius_grow (&box->corner[GTK_CSS_BOTTOM_RIGHT], right, top);
157 gtk_css_border_radius_grow (&box->corner[GTK_CSS_BOTTOM_LEFT], left, bottom);
161 _gtk_rounded_box_shrink (GtkRoundedBox *box,
167 _gtk_rounded_box_grow (box, -top, -right, -bottom, -left);
171 _gtk_rounded_box_move (GtkRoundedBox *box,
180 _cairo_ellipsis (cairo_t *cr,
181 double xc, double yc,
182 double xradius, double yradius,
183 double angle1, double angle2)
185 if (xradius <= 0.0 || yradius <= 0.0)
187 cairo_line_to (cr, xc, yc);
192 cairo_translate (cr, xc, yc);
193 cairo_scale (cr, xradius, yradius);
194 cairo_arc (cr, 0, 0, 1.0, angle1, angle2);
199 _cairo_ellipsis_negative (cairo_t *cr,
200 double xc, double yc,
201 double xradius, double yradius,
202 double angle1, double angle2)
204 if (xradius <= 0.0 || yradius <= 0.0)
206 cairo_line_to (cr, xc, yc);
211 cairo_translate (cr, xc, yc);
212 cairo_scale (cr, xradius, yradius);
213 cairo_arc_negative (cr, 0, 0, 1.0, angle1, angle2);
218 _gtk_rounded_box_path (const GtkRoundedBox *box,
221 cairo_new_sub_path (cr);
224 box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
225 box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
226 box->corner[GTK_CSS_TOP_LEFT].horizontal,
227 box->corner[GTK_CSS_TOP_LEFT].vertical,
230 box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
231 box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
232 box->corner[GTK_CSS_TOP_RIGHT].horizontal,
233 box->corner[GTK_CSS_TOP_RIGHT].vertical,
236 box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
237 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
238 box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
239 box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
242 box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
243 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
244 box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
245 box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
250 _gtk_rounded_box_guess_length (const GtkRoundedBox *box,
254 GtkCssCorner before, after;
257 after = (side + 1) % 4;
260 length = box->box.height
261 - box->corner[before].vertical
262 - box->corner[after].vertical;
264 length = box->box.width
265 - box->corner[before].horizontal
266 - box->corner[after].horizontal;
268 length += G_PI * 0.125 * (box->corner[before].horizontal
269 + box->corner[before].vertical
270 + box->corner[after].horizontal
271 + box->corner[after].vertical);
277 _gtk_rounded_box_path_side (const GtkRoundedBox *box,
285 box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
286 box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
287 box->corner[GTK_CSS_TOP_LEFT].horizontal,
288 box->corner[GTK_CSS_TOP_LEFT].vertical,
289 5 * G_PI / 4, 3 * G_PI / 2);
291 box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
292 box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
293 box->corner[GTK_CSS_TOP_RIGHT].horizontal,
294 box->corner[GTK_CSS_TOP_RIGHT].vertical,
295 - G_PI / 2, -G_PI / 4);
299 box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
300 box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
301 box->corner[GTK_CSS_TOP_RIGHT].horizontal,
302 box->corner[GTK_CSS_TOP_RIGHT].vertical,
305 box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
306 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
307 box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
308 box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
313 box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
314 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
315 box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
316 box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
319 box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
320 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
321 box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
322 box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
323 G_PI / 2, 3 * G_PI / 4);
327 box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
328 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
329 box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
330 box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
333 box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
334 box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
335 box->corner[GTK_CSS_TOP_LEFT].horizontal,
336 box->corner[GTK_CSS_TOP_LEFT].vertical,
340 g_assert_not_reached ();
346 _gtk_rounded_box_path_top (const GtkRoundedBox *outer,
347 const GtkRoundedBox *inner,
350 cairo_new_sub_path (cr);
353 outer->box.x + outer->corner[GTK_CSS_TOP_LEFT].horizontal,
354 outer->box.y + outer->corner[GTK_CSS_TOP_LEFT].vertical,
355 outer->corner[GTK_CSS_TOP_LEFT].horizontal,
356 outer->corner[GTK_CSS_TOP_LEFT].vertical,
357 5 * G_PI / 4, 3 * G_PI / 2);
359 outer->box.x + outer->box.width - outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
360 outer->box.y + outer->corner[GTK_CSS_TOP_RIGHT].vertical,
361 outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
362 outer->corner[GTK_CSS_TOP_RIGHT].vertical,
363 - G_PI / 2, -G_PI / 4);
365 _cairo_ellipsis_negative (cr,
366 inner->box.x + inner->box.width - inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
367 inner->box.y + inner->corner[GTK_CSS_TOP_RIGHT].vertical,
368 inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
369 inner->corner[GTK_CSS_TOP_RIGHT].vertical,
370 -G_PI / 4, - G_PI / 2);
371 _cairo_ellipsis_negative (cr,
372 inner->box.x + inner->corner[GTK_CSS_TOP_LEFT].horizontal,
373 inner->box.y + inner->corner[GTK_CSS_TOP_LEFT].vertical,
374 inner->corner[GTK_CSS_TOP_LEFT].horizontal,
375 inner->corner[GTK_CSS_TOP_LEFT].vertical,
376 3 * G_PI / 2, 5 * G_PI / 4);
378 cairo_close_path (cr);
382 _gtk_rounded_box_path_right (const GtkRoundedBox *outer,
383 const GtkRoundedBox *inner,
386 cairo_new_sub_path (cr);
389 outer->box.x + outer->box.width - outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
390 outer->box.y + outer->corner[GTK_CSS_TOP_RIGHT].vertical,
391 outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
392 outer->corner[GTK_CSS_TOP_RIGHT].vertical,
395 outer->box.x + outer->box.width - outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
396 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
397 outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
398 outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
401 _cairo_ellipsis_negative (cr,
402 inner->box.x + inner->box.width - inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
403 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
404 inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
405 inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
407 _cairo_ellipsis_negative (cr,
408 inner->box.x + inner->box.width - inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
409 inner->box.y + inner->corner[GTK_CSS_TOP_RIGHT].vertical,
410 inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
411 inner->corner[GTK_CSS_TOP_RIGHT].vertical,
414 cairo_close_path (cr);
418 _gtk_rounded_box_path_bottom (const GtkRoundedBox *outer,
419 const GtkRoundedBox *inner,
422 cairo_new_sub_path (cr);
425 outer->box.x + outer->box.width - outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
426 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
427 outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
428 outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
431 outer->box.x + outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
432 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
433 outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
434 outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
435 G_PI / 2, 3 * G_PI / 4);
437 _cairo_ellipsis_negative (cr,
438 inner->box.x + inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
439 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
440 inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
441 inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
442 3 * G_PI / 4, G_PI / 2);
443 _cairo_ellipsis_negative (cr,
444 inner->box.x + inner->box.width - inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
445 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
446 inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
447 inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
450 cairo_close_path (cr);
454 _gtk_rounded_box_path_left (const GtkRoundedBox *outer,
455 const GtkRoundedBox *inner,
458 cairo_new_sub_path (cr);
461 outer->box.x + outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
462 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
463 outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
464 outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
467 outer->box.x + outer->corner[GTK_CSS_TOP_LEFT].horizontal,
468 outer->box.y + outer->corner[GTK_CSS_TOP_LEFT].vertical,
469 outer->corner[GTK_CSS_TOP_LEFT].horizontal,
470 outer->corner[GTK_CSS_TOP_LEFT].vertical,
473 _cairo_ellipsis_negative (cr,
474 inner->box.x + inner->corner[GTK_CSS_TOP_LEFT].horizontal,
475 inner->box.y + inner->corner[GTK_CSS_TOP_LEFT].vertical,
476 inner->corner[GTK_CSS_TOP_LEFT].horizontal,
477 inner->corner[GTK_CSS_TOP_LEFT].vertical,
479 _cairo_ellipsis_negative (cr,
480 inner->box.x + inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
481 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
482 inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
483 inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
486 cairo_close_path (cr);
490 _gtk_rounded_box_clip_path (const GtkRoundedBox *box,
494 box->box.x, box->box.y,
495 box->box.width, box->box.height);