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)
98 box->corner[GTK_CSS_TOP_LEFT].horizontal = _gtk_css_number_get (&corner[GTK_CSS_TOP_LEFT]->horizontal,
100 box->corner[GTK_CSS_TOP_LEFT].vertical = _gtk_css_number_get (&corner[GTK_CSS_TOP_LEFT]->vertical,
103 if (corner[GTK_CSS_TOP_RIGHT] && (junction & GTK_JUNCTION_CORNER_TOPRIGHT) == 0)
105 box->corner[GTK_CSS_TOP_RIGHT].horizontal = _gtk_css_number_get (&corner[GTK_CSS_TOP_RIGHT]->horizontal,
107 box->corner[GTK_CSS_TOP_RIGHT].vertical = _gtk_css_number_get (&corner[GTK_CSS_TOP_RIGHT]->vertical,
110 if (corner[GTK_CSS_BOTTOM_RIGHT] && (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT) == 0)
112 box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal = _gtk_css_number_get (&corner[GTK_CSS_BOTTOM_RIGHT]->horizontal,
114 box->corner[GTK_CSS_BOTTOM_RIGHT].vertical = _gtk_css_number_get (&corner[GTK_CSS_BOTTOM_RIGHT]->vertical,
117 if (corner[GTK_CSS_BOTTOM_LEFT] && (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT) == 0)
119 box->corner[GTK_CSS_BOTTOM_LEFT].horizontal = _gtk_css_number_get (&corner[GTK_CSS_BOTTOM_LEFT]->horizontal,
121 box->corner[GTK_CSS_BOTTOM_LEFT].vertical = _gtk_css_number_get (&corner[GTK_CSS_BOTTOM_LEFT]->vertical,
125 gtk_rounded_box_clamp_border_radius (box);
127 for (i = 0; i < 4; i++)
132 gtk_css_border_radius_grow (GtkRoundedBoxCorner *corner,
136 corner->horizontal += horizontal;
137 corner->vertical += vertical;
139 if (corner->horizontal <= 0 || corner->vertical <= 0)
141 corner->horizontal = 0;
142 corner->vertical = 0;
146 _gtk_rounded_box_grow (GtkRoundedBox *box,
152 if (box->box.width + left + right < 0)
154 box->box.x -= left * box->box.width / (left + right);
160 box->box.width += left + right;
163 if (box->box.height + bottom + right < 0)
165 box->box.y -= top * box->box.height / (top + bottom);
171 box->box.height += top + bottom;
174 gtk_css_border_radius_grow (&box->corner[GTK_CSS_TOP_LEFT], left, top);
175 gtk_css_border_radius_grow (&box->corner[GTK_CSS_TOP_RIGHT], right, bottom);
176 gtk_css_border_radius_grow (&box->corner[GTK_CSS_BOTTOM_RIGHT], right, top);
177 gtk_css_border_radius_grow (&box->corner[GTK_CSS_BOTTOM_LEFT], left, bottom);
181 _gtk_rounded_box_shrink (GtkRoundedBox *box,
187 _gtk_rounded_box_grow (box, -top, -right, -bottom, -left);
191 _gtk_rounded_box_move (GtkRoundedBox *box,
200 _cairo_ellipsis (cairo_t *cr,
201 double xc, double yc,
202 double xradius, double yradius,
203 double angle1, double angle2)
205 if (xradius <= 0.0 || yradius <= 0.0)
207 cairo_line_to (cr, xc, yc);
212 cairo_translate (cr, xc, yc);
213 cairo_scale (cr, xradius, yradius);
214 cairo_arc (cr, 0, 0, 1.0, angle1, angle2);
219 _cairo_ellipsis_negative (cairo_t *cr,
220 double xc, double yc,
221 double xradius, double yradius,
222 double angle1, double angle2)
224 if (xradius <= 0.0 || yradius <= 0.0)
226 cairo_line_to (cr, xc, yc);
231 cairo_translate (cr, xc, yc);
232 cairo_scale (cr, xradius, yradius);
233 cairo_arc_negative (cr, 0, 0, 1.0, angle1, angle2);
238 _gtk_rounded_box_path (const GtkRoundedBox *box,
241 cairo_new_sub_path (cr);
244 box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
245 box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
246 box->corner[GTK_CSS_TOP_LEFT].horizontal,
247 box->corner[GTK_CSS_TOP_LEFT].vertical,
250 box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
251 box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
252 box->corner[GTK_CSS_TOP_RIGHT].horizontal,
253 box->corner[GTK_CSS_TOP_RIGHT].vertical,
256 box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
257 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
258 box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
259 box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
262 box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
263 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
264 box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
265 box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
268 cairo_close_path (cr);
272 _gtk_rounded_box_guess_length (const GtkRoundedBox *box,
276 GtkCssCorner before, after;
279 after = (side + 1) % 4;
282 length = box->box.height
283 - box->corner[before].vertical
284 - box->corner[after].vertical;
286 length = box->box.width
287 - box->corner[before].horizontal
288 - box->corner[after].horizontal;
290 length += G_PI * 0.125 * (box->corner[before].horizontal
291 + box->corner[before].vertical
292 + box->corner[after].horizontal
293 + box->corner[after].vertical);
299 _gtk_rounded_box_path_side (const GtkRoundedBox *box,
307 box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
308 box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
309 box->corner[GTK_CSS_TOP_LEFT].horizontal,
310 box->corner[GTK_CSS_TOP_LEFT].vertical,
311 5 * G_PI / 4, 3 * G_PI / 2);
313 box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
314 box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
315 box->corner[GTK_CSS_TOP_RIGHT].horizontal,
316 box->corner[GTK_CSS_TOP_RIGHT].vertical,
317 - G_PI / 2, -G_PI / 4);
321 box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
322 box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
323 box->corner[GTK_CSS_TOP_RIGHT].horizontal,
324 box->corner[GTK_CSS_TOP_RIGHT].vertical,
327 box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
328 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
329 box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
330 box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
335 box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
336 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
337 box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
338 box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
341 box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
342 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
343 box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
344 box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
345 G_PI / 2, 3 * G_PI / 4);
349 box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
350 box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
351 box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
352 box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
355 box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
356 box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
357 box->corner[GTK_CSS_TOP_LEFT].horizontal,
358 box->corner[GTK_CSS_TOP_LEFT].vertical,
362 g_assert_not_reached ();
368 _gtk_rounded_box_path_top (const GtkRoundedBox *outer,
369 const GtkRoundedBox *inner,
372 cairo_new_sub_path (cr);
375 outer->box.x + outer->corner[GTK_CSS_TOP_LEFT].horizontal,
376 outer->box.y + outer->corner[GTK_CSS_TOP_LEFT].vertical,
377 outer->corner[GTK_CSS_TOP_LEFT].horizontal,
378 outer->corner[GTK_CSS_TOP_LEFT].vertical,
379 5 * G_PI / 4, 3 * G_PI / 2);
381 outer->box.x + outer->box.width - outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
382 outer->box.y + outer->corner[GTK_CSS_TOP_RIGHT].vertical,
383 outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
384 outer->corner[GTK_CSS_TOP_RIGHT].vertical,
385 - G_PI / 2, -G_PI / 4);
387 _cairo_ellipsis_negative (cr,
388 inner->box.x + inner->box.width - inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
389 inner->box.y + inner->corner[GTK_CSS_TOP_RIGHT].vertical,
390 inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
391 inner->corner[GTK_CSS_TOP_RIGHT].vertical,
392 -G_PI / 4, - G_PI / 2);
393 _cairo_ellipsis_negative (cr,
394 inner->box.x + inner->corner[GTK_CSS_TOP_LEFT].horizontal,
395 inner->box.y + inner->corner[GTK_CSS_TOP_LEFT].vertical,
396 inner->corner[GTK_CSS_TOP_LEFT].horizontal,
397 inner->corner[GTK_CSS_TOP_LEFT].vertical,
398 3 * G_PI / 2, 5 * G_PI / 4);
400 cairo_close_path (cr);
404 _gtk_rounded_box_path_right (const GtkRoundedBox *outer,
405 const GtkRoundedBox *inner,
408 cairo_new_sub_path (cr);
411 outer->box.x + outer->box.width - outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
412 outer->box.y + outer->corner[GTK_CSS_TOP_RIGHT].vertical,
413 outer->corner[GTK_CSS_TOP_RIGHT].horizontal,
414 outer->corner[GTK_CSS_TOP_RIGHT].vertical,
417 outer->box.x + outer->box.width - outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
418 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
419 outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
420 outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
423 _cairo_ellipsis_negative (cr,
424 inner->box.x + inner->box.width - inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
425 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
426 inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
427 inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
429 _cairo_ellipsis_negative (cr,
430 inner->box.x + inner->box.width - inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
431 inner->box.y + inner->corner[GTK_CSS_TOP_RIGHT].vertical,
432 inner->corner[GTK_CSS_TOP_RIGHT].horizontal,
433 inner->corner[GTK_CSS_TOP_RIGHT].vertical,
436 cairo_close_path (cr);
440 _gtk_rounded_box_path_bottom (const GtkRoundedBox *outer,
441 const GtkRoundedBox *inner,
444 cairo_new_sub_path (cr);
447 outer->box.x + outer->box.width - outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
448 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
449 outer->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
450 outer->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
453 outer->box.x + outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
454 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
455 outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
456 outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
457 G_PI / 2, 3 * G_PI / 4);
459 _cairo_ellipsis_negative (cr,
460 inner->box.x + inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
461 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
462 inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
463 inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
464 3 * G_PI / 4, G_PI / 2);
465 _cairo_ellipsis_negative (cr,
466 inner->box.x + inner->box.width - inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
467 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
468 inner->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
469 inner->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
472 cairo_close_path (cr);
476 _gtk_rounded_box_path_left (const GtkRoundedBox *outer,
477 const GtkRoundedBox *inner,
480 cairo_new_sub_path (cr);
483 outer->box.x + outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
484 outer->box.y + outer->box.height - outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
485 outer->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
486 outer->corner[GTK_CSS_BOTTOM_LEFT].vertical,
489 outer->box.x + outer->corner[GTK_CSS_TOP_LEFT].horizontal,
490 outer->box.y + outer->corner[GTK_CSS_TOP_LEFT].vertical,
491 outer->corner[GTK_CSS_TOP_LEFT].horizontal,
492 outer->corner[GTK_CSS_TOP_LEFT].vertical,
495 _cairo_ellipsis_negative (cr,
496 inner->box.x + inner->corner[GTK_CSS_TOP_LEFT].horizontal,
497 inner->box.y + inner->corner[GTK_CSS_TOP_LEFT].vertical,
498 inner->corner[GTK_CSS_TOP_LEFT].horizontal,
499 inner->corner[GTK_CSS_TOP_LEFT].vertical,
501 _cairo_ellipsis_negative (cr,
502 inner->box.x + inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
503 inner->box.y + inner->box.height - inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
504 inner->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
505 inner->corner[GTK_CSS_BOTTOM_LEFT].vertical,
508 cairo_close_path (cr);
512 _gtk_rounded_box_clip_path (const GtkRoundedBox *box,
516 box->box.x, box->box.y,
517 box->box.width, box->box.height);