]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssshadowsvalue.c
css: Handle some more simple cases of dependencies
[~andy/gtk] / gtk / gtkcssshadowsvalue.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 "gtkcssshadowsvalueprivate.h"
23
24 #include "gtkcssshadowvalueprivate.h"
25
26 #include <string.h>
27
28 struct _GtkCssValue {
29   GTK_CSS_VALUE_BASE
30   guint         len;
31   GtkCssValue  *values[1];
32 };
33
34 static GtkCssValue *    gtk_css_shadows_value_new       (GtkCssValue **values,
35                                                          guint         len);
36
37 static void
38 gtk_css_value_shadows_free (GtkCssValue *value)
39 {
40   guint i;
41
42   for (i = 0; i < value->len; i++)
43     {
44       _gtk_css_value_unref (value->values[i]);
45     }
46
47   g_slice_free1 (sizeof (GtkCssValue) + sizeof (GtkCssValue *) * (value->len - 1), value);
48 }
49
50 static GtkCssValue *
51 gtk_css_value_shadows_compute (GtkCssValue        *value,
52                                guint               property_id,
53                                GtkStyleContext    *context,
54                                GtkCssDependencies *dependencies)
55 {
56   GtkCssValue *result;
57   GtkCssDependencies child_deps;
58   guint i;
59
60   if (value->len == 0)
61     return _gtk_css_value_ref (value);
62
63   result = gtk_css_shadows_value_new (value->values, value->len);
64   for (i = 0; i < value->len; i++)
65     {
66       result->values[i] = _gtk_css_value_compute (value->values[i], property_id, context, &child_deps);
67       *dependencies = _gtk_css_dependencies_union (*dependencies, child_deps);
68     }
69
70   return result;
71 }
72
73 static gboolean
74 gtk_css_value_shadows_equal (const GtkCssValue *value1,
75                              const GtkCssValue *value2)
76 {
77   guint i;
78
79   /* XXX: Should we fill up here? */
80   if (value1->len != value2->len)
81     return FALSE;
82
83   for (i = 0; i < value1->len; i++)
84     {
85       if (!_gtk_css_value_equal (value1->values[i],
86                                  value2->values[i]))
87         return FALSE;
88     }
89
90   return TRUE;
91 }
92
93 static GtkCssValue *
94 gtk_css_value_shadows_transition (GtkCssValue *start,
95                                   GtkCssValue *end,
96                                   double       progress)
97 {
98   GtkCssValue *result;
99   guint i;
100
101   /* catches the important case of 2 none values */
102   if (start == end)
103     return _gtk_css_value_ref (start);
104
105   if (start->len > end->len)
106     result = gtk_css_shadows_value_new (start->values, start->len);
107   else
108     result = gtk_css_shadows_value_new (end->values, end->len);
109
110   for (i = 0; i < MIN (start->len, end->len); i++)
111     {
112       result->values[i] = _gtk_css_value_transition (start->values[i], end->values[i], progress);
113     }
114   if (start->len > end->len)
115     {
116       for (; i < result->len; i++)
117         {
118           GtkCssValue *fill = _gtk_css_shadow_value_new_for_transition (start->values[i]);
119           result->values[i] = _gtk_css_value_transition (start->values[i], fill, progress);
120           _gtk_css_value_unref (fill);
121         }
122     }
123   else
124     {
125       for (; i < result->len; i++)
126         {
127           GtkCssValue *fill = _gtk_css_shadow_value_new_for_transition (end->values[i]);
128           result->values[i] = _gtk_css_value_transition (fill, end->values[i], progress);
129           _gtk_css_value_unref (fill);
130         }
131     }
132
133   return result;
134 }
135
136 static void
137 gtk_css_value_shadows_print (const GtkCssValue *value,
138                              GString           *string)
139 {
140   guint i;
141
142   if (value->len == 0)
143     {
144       g_string_append (string, "none");
145       return;
146     }
147
148   for (i = 0; i < value->len; i++)
149     {
150       if (i > 0)
151         g_string_append (string, ", ");
152       _gtk_css_value_print (value->values[i], string);
153     }
154 }
155
156 static const GtkCssValueClass GTK_CSS_VALUE_SHADOWS = {
157   gtk_css_value_shadows_free,
158   gtk_css_value_shadows_compute,
159   gtk_css_value_shadows_equal,
160   gtk_css_value_shadows_transition,
161   gtk_css_value_shadows_print
162 };
163
164 static GtkCssValue none_singleton = { &GTK_CSS_VALUE_SHADOWS, 1, 0, { NULL } };
165
166 GtkCssValue *
167 _gtk_css_shadows_value_new_none (void)
168 {
169   return _gtk_css_value_ref (&none_singleton);
170 }
171
172 static GtkCssValue *
173 gtk_css_shadows_value_new (GtkCssValue **values,
174                            guint         len)
175 {
176   GtkCssValue *result;
177            
178   g_return_val_if_fail (values != NULL, NULL);
179   g_return_val_if_fail (len > 0, NULL);
180          
181   result = _gtk_css_value_alloc (&GTK_CSS_VALUE_SHADOWS, sizeof (GtkCssValue) + sizeof (GtkCssValue *) * (len - 1));
182   result->len = len;
183   memcpy (&result->values[0], values, sizeof (GtkCssValue *) * len);
184             
185   return result;
186 }
187
188 GtkCssValue *
189 _gtk_css_shadows_value_parse (GtkCssParser *parser)
190 {
191   GtkCssValue *value, *result;
192   GPtrArray *values;
193
194   if (_gtk_css_parser_try (parser, "none", TRUE))
195     return _gtk_css_shadows_value_new_none ();
196
197   values = g_ptr_array_new ();
198
199   do {
200     value = _gtk_css_shadow_value_parse (parser);
201
202     if (value == NULL)
203       {
204         g_ptr_array_set_free_func (values, (GDestroyNotify) _gtk_css_value_unref);
205         g_ptr_array_free (values, TRUE);
206         return NULL;
207       }
208
209     g_ptr_array_add (values, value);
210   } while (_gtk_css_parser_try (parser, ",", TRUE));
211
212   result = gtk_css_shadows_value_new ((GtkCssValue **) values->pdata, values->len);
213   g_ptr_array_free (values, TRUE);
214   return result;
215 }
216
217 void
218 _gtk_css_shadows_value_paint_layout (const GtkCssValue *shadows,
219                                      cairo_t           *cr,
220                                      PangoLayout       *layout)
221 {
222   guint i;
223
224   g_return_if_fail (shadows->class == &GTK_CSS_VALUE_SHADOWS);
225
226   for (i = 0; i < shadows->len; i++)
227     {
228       _gtk_css_shadow_value_paint_layout (shadows->values[i], cr, layout);
229     }
230 }
231
232 void
233 _gtk_css_shadows_value_paint_icon (const GtkCssValue *shadows,
234                                    cairo_t           *cr)
235 {
236   guint i;
237
238   g_return_if_fail (shadows->class == &GTK_CSS_VALUE_SHADOWS);
239
240   for (i = 0; i < shadows->len; i++)
241     {
242       _gtk_css_shadow_value_paint_icon (shadows->values[i], cr);
243     }
244 }
245
246 void
247 _gtk_css_shadows_value_paint_spinner (const GtkCssValue *shadows,
248                                       cairo_t           *cr,
249                                       gdouble            radius,
250                                       gdouble            progress)
251 {
252   guint i;
253
254   g_return_if_fail (shadows->class == &GTK_CSS_VALUE_SHADOWS);
255
256   for (i = 0; i < shadows->len; i++)
257     {
258       _gtk_css_shadow_value_paint_spinner (shadows->values[i], cr, radius, progress);
259     }
260 }
261
262 void
263 _gtk_css_shadows_value_paint_box (const GtkCssValue   *shadows,
264                                   cairo_t             *cr,
265                                   const GtkRoundedBox *padding_box)
266 {
267   guint i;
268
269   g_return_if_fail (shadows->class == &GTK_CSS_VALUE_SHADOWS);
270
271   for (i = 0; i < shadows->len; i++)
272     {
273       _gtk_css_shadow_value_paint_box (shadows->values[i], cr, padding_box);
274     }
275 }