]> Pileus Git - ~andy/gtk/blob - gtk/gtkroundedbox.c
gtk: Add GtkRoundedBox
[~andy/gtk] / gtk / gtkroundedbox.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2011 Benjamin Otte <otte@gnome.org>
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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include "gtkroundedboxprivate.h"
23
24 #include <string.h>
25
26 /**
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
33  *
34  * Initializes the given @box to represent the given rectangle.
35  * The
36  **/
37 void
38 _gtk_rounded_box_init_rect (GtkRoundedBox *box,
39                             double         x,
40                             double         y,
41                             double         width,
42                             double         height)
43 {
44   box->box.x = x;
45   box->box.y = y;
46   box->box.width = width;
47   box->box.height = height;
48   memset (&box->border_radius, 0, sizeof (GtkCssBorderRadius));
49 }
50
51 void
52 _gtk_rounded_box_apply_border_radius (GtkRoundedBox    *box,
53                                       GtkThemingEngine *engine,
54                                       GtkStateFlags     state,
55                                       GtkJunctionSides  junction)
56 {
57   GtkCssBorderCornerRadius *top_left_radius, *top_right_radius;
58   GtkCssBorderCornerRadius *bottom_left_radius, *bottom_right_radius;
59
60   gtk_theming_engine_get (engine, state,
61                           /* Can't use border-radius as it's an int for
62                            * backwards compat */
63                           "border-top-left-radius", &top_left_radius,
64                           "border-top-right-radius", &top_right_radius,
65                           "border-bottom-right-radius", &bottom_right_radius,
66                           "border-bottom-left-radius", &bottom_left_radius,
67                           NULL);
68
69   if (top_left_radius && (junction & GTK_JUNCTION_CORNER_TOPLEFT) == 0)
70     box->border_radius.top_left = *top_left_radius;
71   if (top_right_radius && (junction & GTK_JUNCTION_CORNER_TOPRIGHT) == 0)
72     box->border_radius.top_right = *top_right_radius;
73   if (bottom_right_radius && (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT) == 0)
74     box->border_radius.bottom_right = *bottom_right_radius;
75   if (bottom_left_radius && (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT) == 0)
76     box->border_radius.bottom_left = *bottom_left_radius;
77
78   g_free (top_left_radius);
79   g_free (top_right_radius);
80   g_free (bottom_right_radius);
81   g_free (bottom_left_radius);
82 }
83
84 void
85 _gtk_rounded_box_grow (GtkRoundedBox *box,
86                        double         top,
87                        double         right,
88                        double         bottom,
89                        double         left)
90 {
91
92   box->box.x -= left;
93   box->box.width += left + right;
94   g_warn_if_fail (box->box.width > 0);
95   box->box.y -= top;
96   box->box.height += top + bottom;
97   g_warn_if_fail (box->box.height > 0);
98
99   if (box->border_radius.top_left.horizontal)
100     box->border_radius.top_left.horizontal = MAX (0, box->border_radius.top_left.horizontal + left);
101   if (box->border_radius.top_left.vertical)
102     box->border_radius.top_left.vertical = MAX (0, box->border_radius.top_left.vertical + top);
103   if (box->border_radius.top_right.horizontal)
104     box->border_radius.top_right.horizontal = MAX (0, box->border_radius.top_right.horizontal + right);
105   if (box->border_radius.top_right.vertical)
106     box->border_radius.top_right.vertical = MAX (0, box->border_radius.top_right.vertical + top);
107   if (box->border_radius.bottom_right.horizontal)
108     box->border_radius.bottom_right.horizontal = MAX (0, box->border_radius.bottom_right.horizontal + right);
109   if (box->border_radius.bottom_right.vertical)
110     box->border_radius.bottom_right.vertical = MAX (0, box->border_radius.bottom_right.vertical + bottom);
111   if (box->border_radius.bottom_left.horizontal)
112     box->border_radius.bottom_left.horizontal = MAX (0, box->border_radius.bottom_left.horizontal + left);
113   if (box->border_radius.bottom_left.vertical)
114     box->border_radius.bottom_left.vertical = MAX (0, box->border_radius.bottom_left.vertical + bottom);
115 }
116
117 void
118 _gtk_rounded_box_shrink (GtkRoundedBox *box,
119                          double         top,
120                          double         right,
121                          double         bottom,
122                          double         left)
123 {
124   _gtk_rounded_box_grow (box, -top, -right, -bottom, -left);
125 }
126
127 void
128 _gtk_rounded_box_move (GtkRoundedBox *box,
129                        double         dx,
130                        double         dy)
131 {
132   box->box.x += dx;
133   box->box.y += dy;
134 }
135
136 static void
137 _cairo_ellipsis (cairo_t *cr,
138                  double xc, double yc,
139                  double xradius, double yradius,
140                  double angle1, double angle2)
141 {
142   if (xradius <= 0.0 || yradius <= 0.0)
143     {
144       cairo_line_to (cr, xc, yc);
145       return;
146     }
147
148   cairo_save (cr);
149   cairo_translate (cr, xc, yc);
150   cairo_scale (cr, xradius, yradius);
151   cairo_arc (cr, 0, 0, 1.0, angle1, angle2);
152   cairo_restore (cr);
153 }
154
155 void
156 _gtk_rounded_box_path (const GtkRoundedBox *box,
157                        cairo_t             *cr)
158 {
159   cairo_new_sub_path (cr);
160
161   _cairo_ellipsis (cr,
162                    box->box.x + box->border_radius.top_left.horizontal,
163                    box->box.y + box->border_radius.top_left.vertical,
164                    box->border_radius.top_left.horizontal,
165                    box->border_radius.top_left.vertical,
166                    G_PI, 3 * G_PI / 2);
167   _cairo_ellipsis (cr, 
168                    box->box.x + box->box.width - box->border_radius.top_right.horizontal,
169                    box->box.y + box->border_radius.top_right.vertical,
170                    box->border_radius.top_right.horizontal,
171                    box->border_radius.top_right.vertical,
172                    - G_PI / 2, 0);
173   _cairo_ellipsis (cr,
174                    box->box.x + box->box.width - box->border_radius.bottom_right.horizontal,
175                    box->box.y + box->box.height - box->border_radius.bottom_right.vertical,
176                    box->border_radius.bottom_right.horizontal,
177                    box->border_radius.bottom_right.vertical,
178                    0, G_PI / 2);
179   _cairo_ellipsis (cr,
180                    box->box.x + box->border_radius.bottom_left.horizontal,
181                    box->box.y + box->box.height - box->border_radius.bottom_left.vertical,
182                    box->border_radius.bottom_left.horizontal,
183                    box->border_radius.bottom_left.vertical,
184                    G_PI / 2, G_PI);
185 }
186
187 void
188 _gtk_rounded_box_clip_path (const GtkRoundedBox *box,
189                             cairo_t             *cr)
190 {
191   cairo_rectangle (cr,
192                    box->box.x, box->box.y,
193                    box->box.width, box->box.height);
194 }
195