]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssenumvalue.c
css: Huge refactoring to avoid computing wrong values
[~andy/gtk] / gtk / gtkcssenumvalue.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2011 Red Hat, Inc.
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, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "config.h"
19
20 #include "gtkcssenumvalueprivate.h"
21
22 #include "gtkstylepropertyprivate.h"
23
24 /* repeated API */
25
26 struct _GtkCssValue {
27   GTK_CSS_VALUE_BASE
28   int value;
29   const char *name;
30 };
31
32 static void
33 gtk_css_value_enum_free (GtkCssValue *value)
34 {
35   g_slice_free (GtkCssValue, value);
36 }
37
38 static GtkCssValue *
39 gtk_css_value_enum_compute (GtkCssValue             *value,
40                             guint                    property_id,
41                             GtkStyleProviderPrivate *provider,
42                             GtkCssComputedValues    *values,
43                             GtkCssComputedValues    *parent_values,
44                             GtkCssDependencies      *dependencies)
45 {
46   return _gtk_css_value_ref (value);
47 }
48
49 static gboolean
50 gtk_css_value_enum_equal (const GtkCssValue *enum1,
51                           const GtkCssValue *enum2)
52 {
53   return enum1 == enum2;
54 }
55
56 static GtkCssValue *
57 gtk_css_value_enum_transition (GtkCssValue *start,
58                                GtkCssValue *end,
59                                guint        property_id,
60                                double       progress)
61 {
62   return NULL;
63 }
64
65 static void
66 gtk_css_value_enum_print (const GtkCssValue *value,
67                           GString           *string)
68 {
69   g_string_append (string, value->name);
70 }
71
72 /* GtkBorderStyle */
73
74 static const GtkCssValueClass GTK_CSS_VALUE_BORDER_STYLE = {
75   gtk_css_value_enum_free,
76   gtk_css_value_enum_compute,
77   gtk_css_value_enum_equal,
78   gtk_css_value_enum_transition,
79   gtk_css_value_enum_print
80 };
81
82 static GtkCssValue border_style_values[] = {
83   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_NONE, "none" },
84   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_SOLID, "solid" },
85   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_INSET, "inset" },
86   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_OUTSET, "outset" },
87   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_HIDDEN, "hidden" },
88   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_DOTTED, "dotted" },
89   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_DASHED, "dashed" },
90   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_DOUBLE, "double" },
91   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_GROOVE, "groove" },
92   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_RIDGE, "ridge" }
93 };
94
95 GtkCssValue *
96 _gtk_css_border_style_value_new (GtkBorderStyle border_style)
97 {
98   g_return_val_if_fail (border_style < G_N_ELEMENTS (border_style_values), NULL);
99
100   return _gtk_css_value_ref (&border_style_values[border_style]);
101 }
102
103 GtkCssValue *
104 _gtk_css_border_style_value_try_parse (GtkCssParser *parser)
105 {
106   guint i;
107
108   g_return_val_if_fail (parser != NULL, NULL);
109
110   for (i = 0; i < G_N_ELEMENTS (border_style_values); i++)
111     {
112       if (_gtk_css_parser_try (parser, border_style_values[i].name, TRUE))
113         return _gtk_css_value_ref (&border_style_values[i]);
114     }
115
116   return NULL;
117 }
118
119 GtkBorderStyle
120 _gtk_css_border_style_value_get (const GtkCssValue *value)
121 {
122   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER_STYLE, GTK_BORDER_STYLE_NONE);
123
124   return value->value;
125 }
126
127 /* PangoStyle */
128
129 static const GtkCssValueClass GTK_CSS_VALUE_FONT_STYLE = {
130   gtk_css_value_enum_free,
131   gtk_css_value_enum_compute,
132   gtk_css_value_enum_equal,
133   gtk_css_value_enum_transition,
134   gtk_css_value_enum_print
135 };
136
137 static GtkCssValue font_style_values[] = {
138   { &GTK_CSS_VALUE_FONT_STYLE, 1, PANGO_STYLE_NORMAL, "normal" },
139   { &GTK_CSS_VALUE_FONT_STYLE, 1, PANGO_STYLE_OBLIQUE, "oblique" },
140   { &GTK_CSS_VALUE_FONT_STYLE, 1, PANGO_STYLE_ITALIC, "italic" }
141 };
142
143 GtkCssValue *
144 _gtk_css_font_style_value_new (PangoStyle font_style)
145 {
146   g_return_val_if_fail (font_style < G_N_ELEMENTS (font_style_values), NULL);
147
148   return _gtk_css_value_ref (&font_style_values[font_style]);
149 }
150
151 GtkCssValue *
152 _gtk_css_font_style_value_try_parse (GtkCssParser *parser)
153 {
154   guint i;
155
156   g_return_val_if_fail (parser != NULL, NULL);
157
158   for (i = 0; i < G_N_ELEMENTS (font_style_values); i++)
159     {
160       if (_gtk_css_parser_try (parser, font_style_values[i].name, TRUE))
161         return _gtk_css_value_ref (&font_style_values[i]);
162     }
163
164   return NULL;
165 }
166
167 PangoStyle
168 _gtk_css_font_style_value_get (const GtkCssValue *value)
169 {
170   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_STYLE, PANGO_STYLE_NORMAL);
171
172   return value->value;
173 }
174
175 /* PangoVariant */
176
177 static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT = {
178   gtk_css_value_enum_free,
179   gtk_css_value_enum_compute,
180   gtk_css_value_enum_equal,
181   gtk_css_value_enum_transition,
182   gtk_css_value_enum_print
183 };
184
185 static GtkCssValue font_variant_values[] = {
186   { &GTK_CSS_VALUE_FONT_VARIANT, 1, PANGO_VARIANT_NORMAL, "normal" },
187   { &GTK_CSS_VALUE_FONT_VARIANT, 1, PANGO_VARIANT_SMALL_CAPS, "small-caps" }
188 };
189
190 GtkCssValue *
191 _gtk_css_font_variant_value_new (PangoVariant font_variant)
192 {
193   g_return_val_if_fail (font_variant < G_N_ELEMENTS (font_variant_values), NULL);
194
195   return _gtk_css_value_ref (&font_variant_values[font_variant]);
196 }
197
198 GtkCssValue *
199 _gtk_css_font_variant_value_try_parse (GtkCssParser *parser)
200 {
201   guint i;
202
203   g_return_val_if_fail (parser != NULL, NULL);
204
205   for (i = 0; i < G_N_ELEMENTS (font_variant_values); i++)
206     {
207       if (_gtk_css_parser_try (parser, font_variant_values[i].name, TRUE))
208         return _gtk_css_value_ref (&font_variant_values[i]);
209     }
210
211   return NULL;
212 }
213
214 PangoVariant
215 _gtk_css_font_variant_value_get (const GtkCssValue *value)
216 {
217   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT, PANGO_VARIANT_NORMAL);
218
219   return value->value;
220 }
221
222 /* PangoWeight */
223
224 static const GtkCssValueClass GTK_CSS_VALUE_FONT_WEIGHT = {
225   gtk_css_value_enum_free,
226   gtk_css_value_enum_compute,
227   gtk_css_value_enum_equal,
228   gtk_css_value_enum_transition,
229   gtk_css_value_enum_print
230 };
231
232 static GtkCssValue font_weight_values[] = {
233   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_THIN, "100" },
234   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_ULTRALIGHT, "200" },
235   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_LIGHT, "300" },
236   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_NORMAL, "normal" },
237   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_MEDIUM, "500" },
238   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_SEMIBOLD, "600" },
239   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_BOLD, "bold" },
240   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_ULTRABOLD, "800" },
241   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_HEAVY, "900" }
242 };
243
244 GtkCssValue *
245 _gtk_css_font_weight_value_new (PangoWeight font_weight)
246 {
247   guint i;
248   gint w;
249
250   w = ((font_weight + 50) / 100) * 100;
251
252   for (i = 0; i < G_N_ELEMENTS (font_weight_values); i++)
253     {
254       if (font_weight_values[i].value == w)
255         return _gtk_css_value_ref (&font_weight_values[i]);
256     }
257
258   g_return_val_if_reached (NULL);
259 }
260
261 GtkCssValue *
262 _gtk_css_font_weight_value_try_parse (GtkCssParser *parser)
263 {
264   guint i;
265
266   g_return_val_if_fail (parser != NULL, NULL);
267
268   for (i = 0; i < G_N_ELEMENTS (font_weight_values); i++)
269     {
270       if (_gtk_css_parser_try (parser, font_weight_values[i].name, TRUE))
271         return _gtk_css_value_ref (&font_weight_values[i]);
272     }
273   /* special cases go here */
274   if (_gtk_css_parser_try (parser, "400", TRUE))
275     return _gtk_css_value_ref (&font_weight_values[3]);
276   if (_gtk_css_parser_try (parser, "700", TRUE))
277     return _gtk_css_value_ref (&font_weight_values[6]);
278
279   return NULL;
280 }
281
282 PangoWeight
283 _gtk_css_font_weight_value_get (const GtkCssValue *value)
284 {
285   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_WEIGHT, PANGO_WEIGHT_NORMAL);
286
287   return value->value;
288 }
289
290 /* GtkCssArea */
291
292 static const GtkCssValueClass GTK_CSS_VALUE_AREA = {
293   gtk_css_value_enum_free,
294   gtk_css_value_enum_compute,
295   gtk_css_value_enum_equal,
296   gtk_css_value_enum_transition,
297   gtk_css_value_enum_print
298 };
299
300 static GtkCssValue area_values[] = {
301   { &GTK_CSS_VALUE_AREA, 1, GTK_CSS_AREA_BORDER_BOX, "border-box" },
302   { &GTK_CSS_VALUE_AREA, 1, GTK_CSS_AREA_PADDING_BOX, "padding-box" },
303   { &GTK_CSS_VALUE_AREA, 1, GTK_CSS_AREA_CONTENT_BOX, "content-box" }
304 };
305
306 GtkCssValue *
307 _gtk_css_area_value_new (GtkCssArea area)
308 {
309   guint i;
310
311   for (i = 0; i < G_N_ELEMENTS (area_values); i++)
312     {
313       if (area_values[i].value == area)
314         return _gtk_css_value_ref (&area_values[i]);
315     }
316
317   g_return_val_if_reached (NULL);
318 }
319
320 GtkCssValue *
321 _gtk_css_area_value_try_parse (GtkCssParser *parser)
322 {
323   guint i;
324
325   g_return_val_if_fail (parser != NULL, NULL);
326
327   for (i = 0; i < G_N_ELEMENTS (area_values); i++)
328     {
329       if (_gtk_css_parser_try (parser, area_values[i].name, TRUE))
330         return _gtk_css_value_ref (&area_values[i]);
331     }
332
333   return NULL;
334 }
335
336 GtkCssArea
337 _gtk_css_area_value_get (const GtkCssValue *value)
338 {
339   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_AREA, GTK_CSS_AREA_BORDER_BOX);
340
341   return value->value;
342 }
343
344 /* GtkCssDirection */
345
346 static const GtkCssValueClass GTK_CSS_VALUE_DIRECTION = {
347   gtk_css_value_enum_free,
348   gtk_css_value_enum_compute,
349   gtk_css_value_enum_equal,
350   gtk_css_value_enum_transition,
351   gtk_css_value_enum_print
352 };
353
354 static GtkCssValue direction_values[] = {
355   { &GTK_CSS_VALUE_DIRECTION, 1, GTK_CSS_DIRECTION_NORMAL, "normal" },
356   { &GTK_CSS_VALUE_DIRECTION, 1, GTK_CSS_DIRECTION_REVERSE, "reverse" },
357   { &GTK_CSS_VALUE_DIRECTION, 1, GTK_CSS_DIRECTION_ALTERNATE, "alternate" },
358   { &GTK_CSS_VALUE_DIRECTION, 1, GTK_CSS_DIRECTION_ALTERNATE_REVERSE, "alternate-reverse" }
359 };
360
361 GtkCssValue *
362 _gtk_css_direction_value_new (GtkCssDirection direction)
363 {
364   guint i;
365
366   for (i = 0; i < G_N_ELEMENTS (direction_values); i++)
367     {
368       if (direction_values[i].value == direction)
369         return _gtk_css_value_ref (&direction_values[i]);
370     }
371
372   g_return_val_if_reached (NULL);
373 }
374
375 GtkCssValue *
376 _gtk_css_direction_value_try_parse (GtkCssParser *parser)
377 {
378   guint i;
379
380   g_return_val_if_fail (parser != NULL, NULL);
381
382   for (i = 0; i < G_N_ELEMENTS (direction_values); i++)
383     {
384       if (_gtk_css_parser_try (parser, direction_values[i].name, TRUE))
385         return _gtk_css_value_ref (&direction_values[i]);
386     }
387
388   return NULL;
389 }
390
391 GtkCssDirection
392 _gtk_css_direction_value_get (const GtkCssValue *value)
393 {
394   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_DIRECTION, GTK_CSS_DIRECTION_NORMAL);
395
396   return value->value;
397 }
398
399 /* GtkCssPlayState */
400
401 static const GtkCssValueClass GTK_CSS_VALUE_PLAY_STATE = {
402   gtk_css_value_enum_free,
403   gtk_css_value_enum_compute,
404   gtk_css_value_enum_equal,
405   gtk_css_value_enum_transition,
406   gtk_css_value_enum_print
407 };
408
409 static GtkCssValue play_state_values[] = {
410   { &GTK_CSS_VALUE_PLAY_STATE, 1, GTK_CSS_PLAY_STATE_RUNNING, "running" },
411   { &GTK_CSS_VALUE_PLAY_STATE, 1, GTK_CSS_PLAY_STATE_PAUSED, "paused" }
412 };
413
414 GtkCssValue *
415 _gtk_css_play_state_value_new (GtkCssPlayState play_state)
416 {
417   guint i;
418
419   for (i = 0; i < G_N_ELEMENTS (play_state_values); i++)
420     {
421       if (play_state_values[i].value == play_state)
422         return _gtk_css_value_ref (&play_state_values[i]);
423     }
424
425   g_return_val_if_reached (NULL);
426 }
427
428 GtkCssValue *
429 _gtk_css_play_state_value_try_parse (GtkCssParser *parser)
430 {
431   guint i;
432
433   g_return_val_if_fail (parser != NULL, NULL);
434
435   for (i = 0; i < G_N_ELEMENTS (play_state_values); i++)
436     {
437       if (_gtk_css_parser_try (parser, play_state_values[i].name, TRUE))
438         return _gtk_css_value_ref (&play_state_values[i]);
439     }
440
441   return NULL;
442 }
443
444 GtkCssPlayState
445 _gtk_css_play_state_value_get (const GtkCssValue *value)
446 {
447   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_PLAY_STATE, GTK_CSS_PLAY_STATE_RUNNING);
448
449   return value->value;
450 }
451
452 /* GtkCssFillMode */
453
454 static const GtkCssValueClass GTK_CSS_VALUE_FILL_MODE = {
455   gtk_css_value_enum_free,
456   gtk_css_value_enum_compute,
457   gtk_css_value_enum_equal,
458   gtk_css_value_enum_transition,
459   gtk_css_value_enum_print
460 };
461
462 static GtkCssValue fill_mode_values[] = {
463   { &GTK_CSS_VALUE_FILL_MODE, 1, GTK_CSS_FILL_NONE, "none" },
464   { &GTK_CSS_VALUE_FILL_MODE, 1, GTK_CSS_FILL_FORWARDS, "forwards" },
465   { &GTK_CSS_VALUE_FILL_MODE, 1, GTK_CSS_FILL_BACKWARDS, "backwards" },
466   { &GTK_CSS_VALUE_FILL_MODE, 1, GTK_CSS_FILL_BOTH, "both" }
467 };
468
469 GtkCssValue *
470 _gtk_css_fill_mode_value_new (GtkCssFillMode fill_mode)
471 {
472   guint i;
473
474   for (i = 0; i < G_N_ELEMENTS (fill_mode_values); i++)
475     {
476       if (fill_mode_values[i].value == fill_mode)
477         return _gtk_css_value_ref (&fill_mode_values[i]);
478     }
479
480   g_return_val_if_reached (NULL);
481 }
482
483 GtkCssValue *
484 _gtk_css_fill_mode_value_try_parse (GtkCssParser *parser)
485 {
486   guint i;
487
488   g_return_val_if_fail (parser != NULL, NULL);
489
490   for (i = 0; i < G_N_ELEMENTS (fill_mode_values); i++)
491     {
492       if (_gtk_css_parser_try (parser, fill_mode_values[i].name, TRUE))
493         return _gtk_css_value_ref (&fill_mode_values[i]);
494     }
495
496   return NULL;
497 }
498
499 GtkCssFillMode
500 _gtk_css_fill_mode_value_get (const GtkCssValue *value)
501 {
502   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FILL_MODE, GTK_CSS_FILL_NONE);
503
504   return value->value;
505 }
506