]> Pileus Git - ~andy/gtk/blob - gtk/gtkshadow.c
Strip "Custom." prefix when getting default options from cups.
[~andy/gtk] / gtk / gtkshadow.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, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23
24 #include "gtkshadowprivate.h"
25
26 #include "gtkstylecontextprivate.h"
27 #include "gtkthemingengineprivate.h"
28 #include "gtkpango.h"
29
30 typedef struct _GtkShadowElement GtkShadowElement;
31
32 struct _GtkShadowElement {
33   gint16 hoffset;
34   gint16 voffset;
35   gint16 radius;
36   gint16 spread;
37
38   gboolean inset;
39
40   GdkRGBA color;
41   GtkSymbolicColor *symbolic_color;
42 };
43
44 static void
45 shadow_element_print (GtkShadowElement *element,
46                       GString          *str)
47 {
48   gchar *color_str;
49
50   if (element->inset)
51     g_string_append (str, "inset ");
52
53   g_string_append_printf (str, "%d %d ",
54                           (gint) element->hoffset,
55                           (gint) element->voffset);
56
57   if (element->radius != 0)
58     g_string_append_printf (str, "%d ", (gint) element->radius);
59
60   if (element->spread != 0)
61     g_string_append_printf (str, "%d ", (gint) element->spread);
62
63   if (element->symbolic_color != NULL)
64     color_str = gtk_symbolic_color_to_string (element->symbolic_color);
65   else
66     color_str = gdk_rgba_to_string (&element->color);
67
68   g_string_append (str, color_str);
69   g_free (color_str);
70 }
71
72 static void
73 shadow_element_free (GtkShadowElement *element)
74 {
75   if (element->symbolic_color != NULL)
76     gtk_symbolic_color_unref (element->symbolic_color);
77
78   g_slice_free (GtkShadowElement, element);
79 }
80
81 static GtkShadowElement *
82 shadow_element_new (gdouble hoffset,
83                     gdouble voffset,
84                     gdouble radius,
85                     gdouble spread,
86                     gboolean inset,
87                     GdkRGBA *color,
88                     GtkSymbolicColor *symbolic_color)
89 {
90   GtkShadowElement *retval;
91
92   retval = g_slice_new0 (GtkShadowElement);
93
94   retval->hoffset = hoffset;
95   retval->voffset = voffset;
96   retval->radius = radius;
97   retval->spread = spread;
98   retval->inset = inset;
99
100   if (symbolic_color != NULL)
101     retval->symbolic_color = gtk_symbolic_color_ref (symbolic_color);
102
103   if (color != NULL)
104     retval->color = *color;
105
106   return retval;
107 }                  
108
109 /****************
110  * GtkShadow *
111  ****************/
112
113 G_DEFINE_BOXED_TYPE (GtkShadow, _gtk_shadow,
114                      _gtk_shadow_ref, _gtk_shadow_unref)
115
116 struct _GtkShadow {
117   GList *elements;
118
119   guint ref_count;
120   gboolean resolved;
121 };
122
123 GtkShadow *
124 _gtk_shadow_new (void)
125 {
126   GtkShadow *retval;
127
128   retval = g_slice_new0 (GtkShadow);
129   retval->ref_count = 1;
130   retval->resolved = FALSE;
131
132   return retval;
133 }
134
135 GtkShadow *
136 _gtk_shadow_ref (GtkShadow *shadow)
137 {
138   g_return_val_if_fail (shadow != NULL, NULL);
139
140   shadow->ref_count++;
141
142   return shadow;
143 }
144
145 gboolean
146 _gtk_shadow_get_resolved (GtkShadow *shadow)
147 {
148   return shadow->resolved;
149 }
150
151 void
152 _gtk_shadow_unref (GtkShadow *shadow)
153 {
154   g_return_if_fail (shadow != NULL);
155
156   shadow->ref_count--;
157
158   if (shadow->ref_count == 0)
159     {
160       g_list_free_full (shadow->elements,
161                         (GDestroyNotify) shadow_element_free);
162       g_slice_free (GtkShadow, shadow);
163     }
164 }
165
166 void
167 _gtk_shadow_append (GtkShadow        *shadow,
168                     gdouble           hoffset,
169                     gdouble           voffset,
170                     gdouble           radius,
171                     gdouble           spread,
172                     gboolean          inset,
173                     GtkSymbolicColor *color)
174 {
175   GtkShadowElement *element;
176
177   g_return_if_fail (shadow != NULL);
178   g_return_if_fail (color != NULL);
179
180   element = shadow_element_new (hoffset, voffset,
181                                 radius, spread, inset,
182                                 NULL, color);
183
184   shadow->elements = g_list_append (shadow->elements, element);
185 }
186
187 GtkShadow *
188 _gtk_shadow_resolve (GtkShadow       *shadow,
189                      GtkStyleContext *context)
190 {
191   GtkShadow *resolved_shadow;
192   GtkShadowElement *element, *resolved_element;
193   GdkRGBA color;
194   GList *l;
195
196   if (shadow->resolved)
197     return _gtk_shadow_ref (shadow);
198
199   resolved_shadow = _gtk_shadow_new ();
200
201   for (l = shadow->elements; l != NULL; l = l->next)
202     {
203       element = l->data;
204
205       if (!_gtk_style_context_resolve_color (context,
206                                              element->symbolic_color,
207                                              &color))
208         {
209           _gtk_shadow_unref (resolved_shadow);
210           return NULL;
211         }
212
213       resolved_element =
214         shadow_element_new (element->hoffset, element->voffset,
215                             element->radius, element->spread, element->inset,
216                             &color, NULL);
217
218       resolved_shadow->elements =
219         g_list_append (resolved_shadow->elements, resolved_element);
220     }
221
222   resolved_shadow->resolved = TRUE;
223
224   return resolved_shadow;
225 }
226
227 void
228 _gtk_shadow_print (GtkShadow *shadow,
229                    GString   *str)
230 {
231   gint length;
232   GList *l;
233
234   length = g_list_length (shadow->elements);
235
236   if (length == 0)
237     return;
238
239   shadow_element_print (shadow->elements->data, str);
240
241   if (length == 1)
242     return;
243
244   for (l = g_list_next (shadow->elements); l != NULL; l = l->next)
245     {
246       g_string_append (str, ", ");
247       shadow_element_print (l->data, str);
248     }
249 }
250
251 void
252 _gtk_text_shadow_paint_layout (GtkShadow       *shadow,
253                                cairo_t         *cr,
254                                PangoLayout     *layout)
255 {
256   GList *l;
257   GtkShadowElement *element;
258
259   if (!cairo_has_current_point (cr))
260     cairo_move_to (cr, 0, 0);
261
262   /* render shadows starting from the last one,
263    * and the others on top.
264    */
265   for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
266     {
267       element = l->data;
268
269       cairo_save (cr);
270
271       cairo_rel_move_to (cr, element->hoffset, element->voffset);
272       gdk_cairo_set_source_rgba (cr, &element->color);
273       _gtk_pango_fill_layout (cr, layout);
274
275       cairo_rel_move_to (cr, -element->hoffset, -element->voffset);
276       cairo_restore (cr);
277   }
278 }
279
280 void
281 _gtk_icon_shadow_paint (GtkShadow *shadow,
282                         cairo_t *cr)
283 {
284   GList *l;
285   GtkShadowElement *element;
286   cairo_pattern_t *pattern;
287
288   for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
289     {
290       element = l->data;
291
292       cairo_save (cr);
293       pattern = cairo_pattern_reference (cairo_get_source (cr));
294       gdk_cairo_set_source_rgba (cr, &element->color);
295
296       cairo_translate (cr, element->hoffset, element->voffset);
297       cairo_mask (cr, pattern);
298
299       cairo_restore (cr);
300       cairo_pattern_destroy (pattern);
301     }
302 }
303
304 void
305 _gtk_icon_shadow_paint_spinner (GtkShadow *shadow,
306                                 cairo_t   *cr,
307                                 gdouble    radius,
308                                 gdouble    progress)
309 {
310   GtkShadowElement *element;
311   GList *l;
312
313   for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
314     {
315       element = l->data;
316
317       cairo_save (cr);
318
319       cairo_translate (cr, element->hoffset, element->voffset);
320       _gtk_theming_engine_paint_spinner (cr,
321                                          radius, progress,
322                                          &element->color);
323
324       cairo_restore (cr);
325     }
326 }
327
328 void
329 _gtk_box_shadow_render (GtkShadow           *shadow,
330                         cairo_t             *cr,
331                         const GtkRoundedBox *padding_box)
332 {
333   GtkShadowElement *element;
334   GtkRoundedBox box;
335   GList *l;
336
337   cairo_save (cr);
338   cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
339
340   _gtk_rounded_box_path (padding_box, cr);
341   cairo_clip (cr);
342
343   /* render shadows starting from the last one,
344    * and the others on top.
345    */
346   for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
347     {
348       element = l->data;
349
350       if (!element->inset)
351         continue;
352
353       box = *padding_box;
354       _gtk_rounded_box_move (&box, element->hoffset, element->voffset);
355       _gtk_rounded_box_shrink (&box,
356                                element->spread, element->spread,
357                                element->spread, element->spread);
358
359       _gtk_rounded_box_path (&box, cr);
360       _gtk_rounded_box_clip_path (padding_box, cr);
361
362       gdk_cairo_set_source_rgba (cr, &element->color);
363       cairo_fill (cr);
364   }
365
366   cairo_restore (cr);
367 }