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