1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2011 Red Hat, Inc.
4 * Author: Cosimo Cecchi <cosimoc@gnome.org>
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.
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.
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/>.
22 #include "gtkcssshadowvalueprivate.h"
24 #include "gtkcssnumbervalueprivate.h"
25 #include "gtkcssrgbavalueprivate.h"
26 #include "gtkstylecontextprivate.h"
27 #include "gtksymboliccolorprivate.h"
28 #include "gtkthemingengineprivate.h"
43 static GtkCssValue * gtk_css_shadow_value_new (GtkCssValue *hoffset,
51 gtk_css_value_shadow_free (GtkCssValue *shadow)
53 _gtk_css_value_unref (shadow->hoffset);
54 _gtk_css_value_unref (shadow->voffset);
55 _gtk_css_value_unref (shadow->radius);
56 _gtk_css_value_unref (shadow->spread);
57 _gtk_css_value_unref (shadow->color);
59 g_slice_free (GtkCssValue, shadow);
63 gtk_css_value_shadow_equal (const GtkCssValue *shadow1,
64 const GtkCssValue *shadow2)
66 return shadow1->inset == shadow2->inset
67 && _gtk_css_value_equal (shadow1->hoffset, shadow2->hoffset)
68 && _gtk_css_value_equal (shadow1->voffset, shadow2->voffset)
69 && _gtk_css_value_equal (shadow1->radius, shadow2->radius)
70 && _gtk_css_value_equal (shadow1->spread, shadow2->spread)
71 && _gtk_css_value_equal (shadow1->color, shadow2->color);
75 gtk_css_value_shadow_transition (GtkCssValue *start,
79 if (start->inset != end->inset)
82 return gtk_css_shadow_value_new (_gtk_css_value_transition (start->hoffset, end->hoffset, progress),
83 _gtk_css_value_transition (start->voffset, end->voffset, progress),
84 _gtk_css_value_transition (start->radius, end->radius, progress),
85 _gtk_css_value_transition (start->spread, end->spread, progress),
87 _gtk_css_value_transition (start->color, end->color, progress));
91 gtk_css_value_shadow_print (const GtkCssValue *shadow,
94 _gtk_css_value_print (shadow->hoffset, string);
95 g_string_append_c (string, ' ');
96 _gtk_css_value_print (shadow->voffset, string);
97 g_string_append_c (string, ' ');
98 if (_gtk_css_number_value_get (shadow->radius, 100) != 0 ||
99 _gtk_css_number_value_get (shadow->spread, 100) != 0)
101 _gtk_css_value_print (shadow->radius, string);
102 g_string_append_c (string, ' ');
105 if (_gtk_css_number_value_get (shadow->spread, 100) != 0)
107 _gtk_css_value_print (shadow->spread, string);
108 g_string_append_c (string, ' ');
111 _gtk_css_value_print (shadow->color, string);
114 g_string_append (string, " inset");
118 static const GtkCssValueClass GTK_CSS_VALUE_SHADOW = {
119 gtk_css_value_shadow_free,
120 gtk_css_value_shadow_equal,
121 gtk_css_value_shadow_transition,
122 gtk_css_value_shadow_print
126 gtk_css_shadow_value_new (GtkCssValue *hoffset,
127 GtkCssValue *voffset,
135 retval = _gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_SHADOW);
137 retval->hoffset = hoffset;
138 retval->voffset = voffset;
139 retval->radius = radius;
140 retval->spread = spread;
141 retval->inset = inset;
142 retval->color = color;
148 _gtk_css_shadow_value_new_for_transition (GtkCssValue *target)
150 GdkRGBA transparent = { 0, 0, 0, 0 };
152 g_return_val_if_fail (target->class == >K_CSS_VALUE_SHADOW, NULL);
154 return gtk_css_shadow_value_new (_gtk_css_number_value_new (0, GTK_CSS_PX),
155 _gtk_css_number_value_new (0, GTK_CSS_PX),
156 _gtk_css_number_value_new (0, GTK_CSS_PX),
157 _gtk_css_number_value_new (0, GTK_CSS_PX),
159 _gtk_css_rgba_value_new_from_rgba (&transparent));
163 value_is_done_parsing (GtkCssParser *parser)
165 return _gtk_css_parser_is_eof (parser) ||
166 _gtk_css_parser_begins_with (parser, ',') ||
167 _gtk_css_parser_begins_with (parser, ';') ||
168 _gtk_css_parser_begins_with (parser, '}');
172 _gtk_css_shadow_value_parse (GtkCssParser *parser)
182 GtkCssValue *values[N_VALUES] = { NULL, };
186 inset = _gtk_css_parser_try (parser, "inset", TRUE);
190 if (values[HOFFSET] == NULL &&
191 _gtk_css_parser_has_number (parser))
193 values[HOFFSET] = _gtk_css_number_value_parse (parser,
195 | GTK_CSS_NUMBER_AS_PIXELS);
196 if (values[HOFFSET] == NULL)
199 values[VOFFSET] = _gtk_css_number_value_parse (parser,
201 | GTK_CSS_NUMBER_AS_PIXELS);
202 if (values[VOFFSET] == NULL)
205 if (_gtk_css_parser_has_number (parser))
207 values[RADIUS] = _gtk_css_number_value_parse (parser,
209 | GTK_CSS_POSITIVE_ONLY
210 | GTK_CSS_NUMBER_AS_PIXELS);
211 if (values[RADIUS] == NULL)
215 values[RADIUS] = _gtk_css_number_value_new (0.0, GTK_CSS_PX);
217 if (_gtk_css_parser_has_number (parser))
219 values[SPREAD] = _gtk_css_number_value_parse (parser,
221 | GTK_CSS_NUMBER_AS_PIXELS);
222 if (values[SPREAD] == NULL)
226 values[SPREAD] = _gtk_css_number_value_new (0.0, GTK_CSS_PX);
228 else if (!inset && _gtk_css_parser_try (parser, "inset", TRUE))
230 if (values[HOFFSET] == NULL)
235 else if (values[COLOR] == NULL)
237 GtkSymbolicColor *symbolic;
239 if (_gtk_css_parser_try (parser, "currentcolor", TRUE))
240 symbolic = gtk_symbolic_color_ref (_gtk_symbolic_color_get_current_color ());
242 symbolic = _gtk_css_parser_read_symbolic_color (parser);
243 if (symbolic == NULL)
246 values[COLOR] = _gtk_css_value_new_take_symbolic_color (symbolic);
250 /* We parsed everything and there's still stuff left?
251 * Pretend we didn't notice and let the normal code produce
252 * a 'junk at end of value' error */
256 while (values[HOFFSET] == NULL || !value_is_done_parsing (parser));
258 if (values[COLOR] == NULL)
259 values[COLOR] = _gtk_css_value_new_take_symbolic_color (
260 gtk_symbolic_color_ref (
261 _gtk_symbolic_color_get_current_color ()));
263 return gtk_css_shadow_value_new (values[HOFFSET], values[VOFFSET],
264 values[RADIUS], values[SPREAD],
265 inset, values[COLOR]);
268 for (i = 0; i < N_VALUES; i++)
271 _gtk_css_value_unref (values[i]);
278 _gtk_css_shadow_value_compute (GtkCssValue *shadow,
279 GtkStyleContext *context)
283 color = _gtk_css_rgba_value_compute_from_symbolic (shadow->color,
284 _gtk_css_value_new_take_symbolic_color (
285 gtk_symbolic_color_ref (
286 _gtk_symbolic_color_get_current_color ())),
290 return gtk_css_shadow_value_new (_gtk_css_number_value_compute (shadow->hoffset, context),
291 _gtk_css_number_value_compute (shadow->voffset, context),
292 _gtk_css_number_value_compute (shadow->radius, context),
293 _gtk_css_number_value_compute (shadow->spread, context),
299 _gtk_css_shadow_value_paint_layout (const GtkCssValue *shadow,
303 g_return_if_fail (shadow->class == >K_CSS_VALUE_SHADOW);
305 if (!cairo_has_current_point (cr))
306 cairo_move_to (cr, 0, 0);
310 cairo_rel_move_to (cr,
311 _gtk_css_number_value_get (shadow->hoffset, 0),
312 _gtk_css_number_value_get (shadow->voffset, 0));
313 gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));
314 _gtk_pango_fill_layout (cr, layout);
316 cairo_rel_move_to (cr,
317 - _gtk_css_number_value_get (shadow->hoffset, 0),
318 - _gtk_css_number_value_get (shadow->voffset, 0));
323 _gtk_css_shadow_value_paint_icon (const GtkCssValue *shadow,
326 cairo_pattern_t *pattern;
328 g_return_if_fail (shadow->class == >K_CSS_VALUE_SHADOW);
331 pattern = cairo_pattern_reference (cairo_get_source (cr));
332 gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));
335 _gtk_css_number_value_get (shadow->hoffset, 0),
336 _gtk_css_number_value_get (shadow->voffset, 0));
337 cairo_mask (cr, pattern);
340 cairo_pattern_destroy (pattern);
344 _gtk_css_shadow_value_paint_spinner (const GtkCssValue *shadow,
349 g_return_if_fail (shadow->class == >K_CSS_VALUE_SHADOW);
354 _gtk_css_number_value_get (shadow->hoffset, 0),
355 _gtk_css_number_value_get (shadow->voffset, 0));
356 _gtk_theming_engine_paint_spinner (cr,
358 _gtk_css_rgba_value_get_rgba (shadow->color));
364 _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow,
366 const GtkRoundedBox *padding_box)
371 g_return_if_fail (shadow->class == >K_CSS_VALUE_SHADOW);
374 cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
376 _gtk_rounded_box_path (padding_box, cr);
380 _gtk_rounded_box_move (&box,
381 _gtk_css_number_value_get (shadow->hoffset, 0),
382 _gtk_css_number_value_get (shadow->voffset, 0));
383 spread = _gtk_css_number_value_get (shadow->spread, 0);
384 _gtk_rounded_box_shrink (&box, spread, spread, spread, spread);
386 _gtk_rounded_box_path (&box, cr);
387 _gtk_rounded_box_clip_path (padding_box, cr);
389 gdk_cairo_set_source_rgba (cr, _gtk_css_rgba_value_get_rgba (shadow->color));