]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssrepeatvalue.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkcssrepeatvalue.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 "gtkcssrepeatvalueprivate.h"
21
22 #include "gtkcssnumbervalueprivate.h"
23
24 struct _GtkCssValue {
25   GTK_CSS_VALUE_BASE
26   GtkCssRepeatStyle x;
27   GtkCssRepeatStyle y;
28 };
29
30 static void
31 gtk_css_value_repeat_free (GtkCssValue *value)
32 {
33   g_slice_free (GtkCssValue, value);
34 }
35
36 static GtkCssValue *
37 gtk_css_value_repeat_compute (GtkCssValue             *value,
38                               guint                    property_id,
39                               GtkStyleProviderPrivate *provider,
40                               GtkCssComputedValues    *values,
41                               GtkCssComputedValues    *parent_values,
42                               GtkCssDependencies      *dependencies)
43 {
44   return _gtk_css_value_ref (value);
45 }
46
47 static gboolean
48 gtk_css_value_repeat_equal (const GtkCssValue *repeat1,
49                             const GtkCssValue *repeat2)
50 {
51   return repeat1->x == repeat2->x
52       && repeat1->y == repeat2->y;
53 }
54
55 static GtkCssValue *
56 gtk_css_value_repeat_transition (GtkCssValue *start,
57                                  GtkCssValue *end,
58                                  guint        property_id,
59                                  double       progress)
60 {
61   return NULL;
62 }
63
64 static void
65 gtk_css_value_background_repeat_print (const GtkCssValue *repeat,
66                                        GString           *string)
67 {
68   static const char *names[] = {
69     "no-repeat",
70     "repeat",
71     "round",
72     "space"
73   };
74
75   if (repeat->x == repeat->y)
76     {
77       g_string_append (string, names[repeat->x]);
78     }
79   else if (repeat->x == GTK_CSS_REPEAT_STYLE_REPEAT &&
80            repeat->y == GTK_CSS_REPEAT_STYLE_NO_REPEAT)
81     {
82       g_string_append (string, "repeat-x");
83     }
84   else if (repeat->x == GTK_CSS_REPEAT_STYLE_NO_REPEAT &&
85            repeat->y == GTK_CSS_REPEAT_STYLE_REPEAT)
86     {
87       g_string_append (string, "repeat-y");
88     }
89   else
90     {
91       g_string_append (string, names[repeat->x]);
92       g_string_append_c (string, ' ');
93       g_string_append (string, names[repeat->y]);
94     }
95 }
96
97 static void
98 gtk_css_value_border_repeat_print (const GtkCssValue *repeat,
99                                    GString           *string)
100 {
101   static const char *names[] = {
102     "stretch",
103     "repeat",
104     "round",
105     "space"
106   };
107
108   g_string_append (string, names[repeat->x]);
109   if (repeat->x != repeat->y)
110     {
111       g_string_append_c (string, ' ');
112       g_string_append (string, names[repeat->y]);
113     }
114 }
115
116 static const GtkCssValueClass GTK_CSS_VALUE_BACKGROUND_REPEAT = {
117   gtk_css_value_repeat_free,
118   gtk_css_value_repeat_compute,
119   gtk_css_value_repeat_equal,
120   gtk_css_value_repeat_transition,
121   gtk_css_value_background_repeat_print
122 };
123
124 static const GtkCssValueClass GTK_CSS_VALUE_BORDER_REPEAT = {
125   gtk_css_value_repeat_free,
126   gtk_css_value_repeat_compute,
127   gtk_css_value_repeat_equal,
128   gtk_css_value_repeat_transition,
129   gtk_css_value_border_repeat_print
130 };
131 /* BACKGROUND REPEAT */
132
133 static struct {
134   const char *name;
135   GtkCssValue values[4];
136 } background_repeat_values[4] = {
137   { "no-repeat",
138   { { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_NO_REPEAT },
139     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_REPEAT    },
140     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_ROUND     },
141     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_SPACE     }
142   } },
143   { "repeat",
144   { { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,    GTK_CSS_REPEAT_STYLE_NO_REPEAT },
145     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,    GTK_CSS_REPEAT_STYLE_REPEAT    },
146     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,    GTK_CSS_REPEAT_STYLE_ROUND     },
147     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,    GTK_CSS_REPEAT_STYLE_SPACE     }
148   } }, 
149   { "round",
150   { { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,     GTK_CSS_REPEAT_STYLE_NO_REPEAT },
151     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,     GTK_CSS_REPEAT_STYLE_REPEAT    },
152     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,     GTK_CSS_REPEAT_STYLE_ROUND     },
153     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,     GTK_CSS_REPEAT_STYLE_SPACE     }
154   } }, 
155   { "space",
156   { { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,     GTK_CSS_REPEAT_STYLE_NO_REPEAT },
157     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,     GTK_CSS_REPEAT_STYLE_REPEAT    },
158     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,     GTK_CSS_REPEAT_STYLE_ROUND     },
159     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,     GTK_CSS_REPEAT_STYLE_SPACE     }
160   } }
161 };
162
163 GtkCssValue *
164 _gtk_css_background_repeat_value_new (GtkCssRepeatStyle x,
165                                       GtkCssRepeatStyle y)
166 {
167   return _gtk_css_value_ref (&background_repeat_values[x].values[y]);
168 }
169
170 static gboolean
171 _gtk_css_background_repeat_style_try (GtkCssParser      *parser,
172                                       GtkCssRepeatStyle *result)
173 {
174   guint i;
175
176   for (i = 0; i < G_N_ELEMENTS (background_repeat_values); i++)
177     {
178       if (_gtk_css_parser_try (parser, background_repeat_values[i].name, TRUE))
179         {
180           *result = i;
181           return TRUE;
182         }
183     }
184
185   return FALSE;
186 }
187
188 GtkCssValue *
189 _gtk_css_background_repeat_value_try_parse (GtkCssParser *parser)
190 {
191   GtkCssRepeatStyle x, y;
192
193   g_return_val_if_fail (parser != NULL, NULL);
194
195   if (_gtk_css_parser_try (parser, "repeat-x", TRUE))
196     return _gtk_css_background_repeat_value_new (GTK_CSS_REPEAT_STYLE_REPEAT, GTK_CSS_REPEAT_STYLE_NO_REPEAT);
197   if (_gtk_css_parser_try (parser, "repeat-y", TRUE))
198     return _gtk_css_background_repeat_value_new (GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_REPEAT);
199
200   if (!_gtk_css_background_repeat_style_try (parser, &x))
201     return NULL;
202
203   if (!_gtk_css_background_repeat_style_try (parser, &y))
204     y = x;
205
206   return _gtk_css_background_repeat_value_new (x, y);
207 }
208
209 GtkCssRepeatStyle
210 _gtk_css_background_repeat_value_get_x (const GtkCssValue *repeat)
211 {
212   g_return_val_if_fail (repeat->class == &GTK_CSS_VALUE_BACKGROUND_REPEAT, GTK_CSS_REPEAT_STYLE_NO_REPEAT);
213
214   return repeat->x;
215 }
216
217 GtkCssRepeatStyle
218 _gtk_css_background_repeat_value_get_y (const GtkCssValue *repeat)
219 {
220   g_return_val_if_fail (repeat->class == &GTK_CSS_VALUE_BACKGROUND_REPEAT, GTK_CSS_REPEAT_STYLE_NO_REPEAT);
221
222   return repeat->y;
223 }
224
225 /* BORDER IMAGE REPEAT */
226
227 static struct {
228   const char *name;
229   GtkCssValue values[4];
230 } border_repeat_values[4] = {
231   { "stretch",
232   { { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_STRETCH },
233     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_REPEAT  },
234     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_ROUND   },
235     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_SPACE   }
236   } },
237   { "repeat",
238   { { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,  GTK_CSS_REPEAT_STYLE_STRETCH },
239     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,  GTK_CSS_REPEAT_STYLE_REPEAT  },
240     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,  GTK_CSS_REPEAT_STYLE_ROUND   },
241     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,  GTK_CSS_REPEAT_STYLE_SPACE   }
242   } }, 
243   { "round",
244   { { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,   GTK_CSS_REPEAT_STYLE_STRETCH },
245     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,   GTK_CSS_REPEAT_STYLE_REPEAT  },
246     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,   GTK_CSS_REPEAT_STYLE_ROUND   },
247     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,   GTK_CSS_REPEAT_STYLE_SPACE   }
248   } }, 
249   { "space",
250   { { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,   GTK_CSS_REPEAT_STYLE_STRETCH },
251     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,   GTK_CSS_REPEAT_STYLE_REPEAT  },
252     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,   GTK_CSS_REPEAT_STYLE_ROUND   },
253     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,   GTK_CSS_REPEAT_STYLE_SPACE   }
254   } }
255 };
256
257 GtkCssValue *
258 _gtk_css_border_repeat_value_new (GtkCssRepeatStyle x,
259                                   GtkCssRepeatStyle y)
260 {
261   return _gtk_css_value_ref (&border_repeat_values[x].values[y]);
262 }
263
264 static gboolean
265 _gtk_css_border_repeat_style_try (GtkCssParser      *parser,
266                                   GtkCssRepeatStyle *result)
267 {
268   guint i;
269
270   for (i = 0; i < G_N_ELEMENTS (border_repeat_values); i++)
271     {
272       if (_gtk_css_parser_try (parser, border_repeat_values[i].name, TRUE))
273         {
274           *result = i;
275           return TRUE;
276         }
277     }
278
279   return FALSE;
280 }
281
282 GtkCssValue *
283 _gtk_css_border_repeat_value_try_parse (GtkCssParser *parser)
284 {
285   GtkCssRepeatStyle x, y;
286
287   g_return_val_if_fail (parser != NULL, NULL);
288
289   if (!_gtk_css_border_repeat_style_try (parser, &x))
290     return NULL;
291
292   if (!_gtk_css_border_repeat_style_try (parser, &y))
293     y = x;
294
295   return _gtk_css_border_repeat_value_new (x, y);
296 }
297
298 GtkCssRepeatStyle
299 _gtk_css_border_repeat_value_get_x (const GtkCssValue *repeat)
300 {
301   g_return_val_if_fail (repeat->class == &GTK_CSS_VALUE_BORDER_REPEAT, GTK_CSS_REPEAT_STYLE_STRETCH);
302
303   return repeat->x;
304 }
305
306 GtkCssRepeatStyle
307 _gtk_css_border_repeat_value_get_y (const GtkCssValue *repeat)
308 {
309   g_return_val_if_fail (repeat->class == &GTK_CSS_VALUE_BORDER_REPEAT, GTK_CSS_REPEAT_STYLE_STRETCH);
310
311   return repeat->y;
312 }
313