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,
248 cairo_close_path (cr);
252 _gtk_rounded_box_guess_length (const GtkRoundedBox *box,
256 GtkCssCorner before, after;
259 after = (side + 1) % 4;
262 length = box->box.height
263 - box->corner[before].vertical
264 - box->corner[after].vertical;
266 length = box->box.width
267 - box->corner[before].horizontal
268 - box->corner[after].horizontal;
270 length += G_PI * 0.125 * (box->corner[before].horizontal
271 + box->corner[before].vertical
272 + box->corner[after].horizontal
273 + box->corner[after].vertical);
279 _gtk_rounded_box_path_side (const GtkRoundedBox *box,
287 box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
288 box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
289 box->corner[GTK_CSS_TOP_LEFT].horizontal,
290 box->corner[GTK_CSS_TOP_LEFT].vertical,
291 5 * G_PI / 4, 3 * G_PI / 2);
293 box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
294 box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
295 box->corner[GTK_CSS_TOP_RIGHT].horizontal,
296 box->corner[GTK_CSS_TOP_RIGHT].vertical,
297 - G_PI / 2, -G_PI / 4);
301 box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
302 box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
303 box->corner[GTK_CSS_TOP_RIGHT].horizontal,
304 box->corner[GTK_CSS_TOP_RIGHT].vertical,
307 box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
308 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
309 box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
310 box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
315 box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
316 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
317 box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
318 box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
321 box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
322 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
323 box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
324 box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
325 G_PI / 2, 3 * G_PI / 4);
329 box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
330 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
331 box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
332 box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
335 box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
336 box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
337 box->corner[GTK_CSS_TOP_LEFT].horizontal,
338 box->corner[GTK_CSS_TOP_LEFT].vertical,
342 g_assert_not_reached ();
348 _gtk_rounded_box_path_top (const GtkRoundedBox *outer,
349 const GtkRoundedBox *inner,
352 cairo_new_sub_path (cr);
355 outer->box.x + outer->corner[GTK_CSS_TOP_LEFT].horizontal,
356 outer->box.y + outer->corner[GTK_CSS_TOP_LEFT].vertical,
357 outer->corner[GTK_CSS_TOP_LEFT].horizontal,
358 outer->corner[GTK_CSS_TOP_LEFT].vertical,
359 5 * G_PI / 4, 3 * G_PI / 2);
361 outer->box.x + outer->box.width - outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
362 outer->box.y + outer->corner[GTK_CSS_TOP_RIGHT].vertical,
363 outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
364 outer->corner[GTK_CSS_TOP_RIGHT].vertical,
365 - G_PI / 2, -G_PI / 4);
367 _cairo_ellipsis_negative (cr,
368 inner->box.x + inner->box.width - inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
369 inner->box.y + inner->corner[GTK_CSS_TOP_RIGHT].vertical,
370 inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
371 inner->corner[GTK_CSS_TOP_RIGHT].vertical,
372 -G_PI / 4, - G_PI / 2);
373 _cairo_ellipsis_negative (cr,
374 inner->box.x + inner->corner[GTK_CSS_TOP_LEFT].horizontal,
375 inner->box.y + inner->corner[GTK_CSS_TOP_LEFT].vertical,
376 inner->corner[GTK_CSS_TOP_LEFT].horizontal,
377 inner->corner[GTK_CSS_TOP_LEFT].vertical,
378 3 * G_PI / 2, 5 * G_PI / 4);
380 cairo_close_path (cr);
384 _gtk_rounded_box_path_right (const GtkRoundedBox *outer,
385 const GtkRoundedBox *inner,
388 cairo_new_sub_path (cr);
391 outer->box.x + outer->box.width - outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
392 outer->box.y + outer->corner[GTK_CSS_TOP_RIGHT].vertical,
393 outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
394 outer->corner[GTK_CSS_TOP_RIGHT].vertical,
397 outer->box.x + outer->box.width - outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
398 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
399 outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
400 outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
403 _cairo_ellipsis_negative (cr,
404 inner->box.x + inner->box.width - inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
405 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
406 inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
407 inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
409 _cairo_ellipsis_negative (cr,
410 inner->box.x + inner->box.width - inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
411 inner->box.y + inner->corner[GTK_CSS_TOP_RIGHT].vertical,
412 inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
413 inner->corner[GTK_CSS_TOP_RIGHT].vertical,
416 cairo_close_path (cr);
420 _gtk_rounded_box_path_bottom (const GtkRoundedBox *outer,
421 const GtkRoundedBox *inner,
424 cairo_new_sub_path (cr);
427 outer->box.x + outer->box.width - outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
428 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
429 outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
430 outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
433 outer->box.x + outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
434 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
435 outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
436 outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
437 G_PI / 2, 3 * G_PI / 4);
439 _cairo_ellipsis_negative (cr,
440 inner->box.x + inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
441 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
442 inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
443 inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
444 3 * G_PI / 4, G_PI / 2);
445 _cairo_ellipsis_negative (cr,
446 inner->box.x + inner->box.width - inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
447 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
448 inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
449 inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
452 cairo_close_path (cr);
456 _gtk_rounded_box_path_left (const GtkRoundedBox *outer,
457 const GtkRoundedBox *inner,
460 cairo_new_sub_path (cr);
463 outer->box.x + outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
464 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
465 outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
466 outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
469 outer->box.x + outer->corner[GTK_CSS_TOP_LEFT].horizontal,
470 outer->box.y + outer->corner[GTK_CSS_TOP_LEFT].vertical,
471 outer->corner[GTK_CSS_TOP_LEFT].horizontal,
472 outer->corner[GTK_CSS_TOP_LEFT].vertical,
475 _cairo_ellipsis_negative (cr,
476 inner->box.x + inner->corner[GTK_CSS_TOP_LEFT].horizontal,
477 inner->box.y + inner->corner[GTK_CSS_TOP_LEFT].vertical,
478 inner->corner[GTK_CSS_TOP_LEFT].horizontal,
479 inner->corner[GTK_CSS_TOP_LEFT].vertical,
481 _cairo_ellipsis_negative (cr,
482 inner->box.x + inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
483 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
484 inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
485 inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
488 cairo_close_path (cr);
492 _gtk_rounded_box_clip_path (const GtkRoundedBox *box,
496 box->box.x, box->box.y,
497 box->box.width, box->box.height);