]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssshadowvalue.c
shadow: Make color a GtkCssValue
[~andy/gtk] / gtk / gtkcssshadowvalue.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2011 Red Hat, Inc.
3  *
4  * Author: Cosimo Cecchi <cosimoc@gnome.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "config.h"
21
22 #include "gtkcssshadowvalueprivate.h"
23
24 #include "gtkcssrgbavalueprivate.h"
25 #include "gtkstylecontextprivate.h"
26 #include "gtksymboliccolorprivate.h"
27 #include "gtkthemingengineprivate.h"
28 #include "gtkpango.h"
29
30 struct _GtkCssValue {
31   GTK_CSS_VALUE_BASE
32   guint inset :1;
33
34   gint16 hoffset;
35   gint16 voffset;
36   gint16 radius;
37   gint16 spread;
38
39   GtkCssValue *color;
40 };
41
42 static void
43 gtk_css_value_shadow_free (GtkCssValue *shadow)
44 {
45   _gtk_css_value_unref (shadow->color);
46
47   g_slice_free (GtkCssValue, shadow);
48 }
49
50 static gboolean
51 gtk_css_value_shadow_equal (const GtkCssValue *shadow1,
52                             const GtkCssValue *shadow2)
53 {
54   /* FIXME */
55   return shadow1 == shadow2;
56 }
57
58 static GtkCssValue *
59 gtk_css_value_shadow_transition (GtkCssValue *start,
60                                  GtkCssValue *end,
61                                  double       progress)
62 {
63   return NULL;
64 }
65
66 static void
67 gtk_css_value_shadow_print (const GtkCssValue *shadow,
68                             GString           *string)
69 {
70   if (shadow->inset)
71     g_string_append (string, "inset ");
72
73   g_string_append_printf (string, "%d %d ",
74                           (gint) shadow->hoffset,
75                           (gint) shadow->voffset);
76
77   if (shadow->radius != 0)
78     g_string_append_printf (string, "%d ", (gint) shadow->radius);
79
80   if (shadow->spread != 0)
81     g_string_append_printf (string, "%d ", (gint) shadow->spread);
82
83   _gtk_css_value_print (shadow->color, string);
84 }
85
86 static const GtkCssValueClass GTK_CSS_VALUE_SHADOW = {
87   gtk_css_value_shadow_free,
88   gtk_css_value_shadow_equal,
89   gtk_css_value_shadow_transition,
90   gtk_css_value_shadow_print
91 };
92
93 static GtkCssValue *
94 gtk_css_shadow_value_new (gdouble hoffset,
95                           gdouble voffset,
96                           gdouble radius,
97                           gdouble spread,
98                           gboolean inset,
99                           GtkCssValue *color)
100 {
101   GtkCssValue *retval;
102
103   retval = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_SHADOW);
104
105   retval->hoffset = hoffset;
106   retval->voffset = voffset;
107   retval->radius = radius;
108   retval->spread = spread;
109   retval->inset = inset;
110   retval->color = color;
111
112   return retval;
113 }                  
114
115 GtkCssValue *
116 _gtk_css_shadow_value_parse (GtkCssParser *parser)
117 {
118   gboolean have_inset, have_color, have_lengths;
119   gdouble hoffset, voffset, blur, spread;
120   GtkSymbolicColor *color;
121   guint i;
122
123   have_inset = have_lengths = have_color = FALSE;
124
125   for (i = 0; i < 3; i++)
126     {
127       if (!have_inset && 
128           _gtk_css_parser_try (parser, "inset", TRUE))
129         {
130           have_inset = TRUE;
131           continue;
132         }
133         
134       if (!have_lengths &&
135           _gtk_css_parser_try_double (parser, &hoffset))
136         {
137           have_lengths = TRUE;
138
139           if (!_gtk_css_parser_try_double (parser, &voffset))
140             {
141               _gtk_css_parser_error (parser, "Horizontal and vertical offsets are required");
142               if (have_color)
143                 gtk_symbolic_color_unref (color);
144               return NULL;
145             }
146
147           if (!_gtk_css_parser_try_double (parser, &blur))
148             blur = 0;
149
150           if (!_gtk_css_parser_try_double (parser, &spread))
151             spread = 0;
152
153           continue;
154         }
155
156       if (!have_color)
157         {
158           have_color = TRUE;
159
160           /* XXX: the color is optional and UA-defined if it's missing,
161            * but it doesn't really make sense for us...
162            */
163           color = _gtk_css_parser_read_symbolic_color (parser);
164
165           if (color == NULL)
166             return NULL;
167         }
168     }
169
170   if (!have_color || !have_lengths)
171     {
172       _gtk_css_parser_error (parser, "Must specify at least color and offsets");
173       if (have_color)
174         gtk_symbolic_color_unref (color);
175       return NULL;
176     }
177
178   return gtk_css_shadow_value_new (hoffset, voffset,
179                                    blur, spread, have_inset,
180                                    _gtk_css_value_new_take_symbolic_color (color));
181 }
182
183 GtkCssValue *
184 _gtk_css_shadow_value_compute (GtkCssValue     *shadow,
185                                GtkStyleContext *context)
186 {
187   GtkCssValue *color;
188
189   color = _gtk_css_rgba_value_compute_from_symbolic (shadow->color,
190                                                      _gtk_css_value_new_take_symbolic_color (
191                                                        gtk_symbolic_color_ref (
192                                                          _gtk_symbolic_color_get_current_color ())),
193                                                      context,
194                                                      FALSE);
195
196   return gtk_css_shadow_value_new (shadow->hoffset, shadow->voffset,
197                                    shadow->radius, shadow->spread, shadow->inset,
198                                    color);
199 }
200
201 void
202 _gtk_css_shadow_value_paint_layout (const GtkCssValue *shadow,
203                                     cairo_t           *cr,
204                                     PangoLayout       *layout)
205 {
206   g_return_if_fail (shadow->class == &GTK_CSS_VALUE_SHADOW);
207
208   if (!cairo_has_current_point (cr))
209     cairo_move_to (cr, 0, 0);
210
211   cairo_save (cr);
212
213   cairo_rel_move_to (cr, shadow->hoffset, shadow->voffset);
214   gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));
215   _gtk_pango_fill_layout (cr, layout);
216
217   cairo_rel_move_to (cr, -shadow->hoffset, -shadow->voffset);
218   cairo_restore (cr);
219 }
220
221 void
222 _gtk_css_shadow_value_paint_icon (const GtkCssValue *shadow,
223                                   cairo_t           *cr)
224 {
225   cairo_pattern_t *pattern;
226
227   g_return_if_fail (shadow->class == &GTK_CSS_VALUE_SHADOW);
228
229   cairo_save (cr);
230   pattern = cairo_pattern_reference (cairo_get_source (cr));
231   gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));
232
233   cairo_translate (cr, shadow->hoffset, shadow->voffset);
234   cairo_mask (cr, pattern);
235
236   cairo_restore (cr);
237   cairo_pattern_destroy (pattern);
238 }
239
240 void
241 _gtk_css_shadow_value_paint_spinner (const GtkCssValue *shadow,
242                                      cairo_t           *cr,
243                                      gdouble            radius,
244                                      gdouble            progress)
245 {
246   g_return_if_fail (shadow->class == &GTK_CSS_VALUE_SHADOW);
247
248   cairo_save (cr);
249
250   cairo_translate (cr, shadow->hoffset, shadow->voffset);
251   _gtk_theming_engine_paint_spinner (cr,
252                                      radius, progress,
253                                      _gtk_css_rgba_value_get_rgba (shadow->color));
254
255   cairo_restore (cr);
256 }
257
258 void
259 _gtk_css_shadow_value_paint_box (const GtkCssValue   *shadow,
260                                  cairo_t             *cr,
261                                  const GtkRoundedBox *padding_box)
262 {
263   GtkRoundedBox box;
264
265   g_return_if_fail (shadow->class == &GTK_CSS_VALUE_SHADOW);
266
267   cairo_save (cr);
268   cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
269
270   _gtk_rounded_box_path (padding_box, cr);
271   cairo_clip (cr);
272
273   box = *padding_box;
274   _gtk_rounded_box_move (&box, shadow->hoffset, shadow->voffset);
275   _gtk_rounded_box_shrink (&box,
276                            shadow->spread, shadow->spread,
277                            shadow->spread, shadow->spread);
278
279   _gtk_rounded_box_path (&box, cr);
280   _gtk_rounded_box_clip_path (padding_box, cr);
281
282   gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));
283   cairo_fill (cr);
284
285   cairo_restore (cr);
286 }