]> Pileus Git - ~andy/gtk/blob - gtk/gtkcsspositionvalue.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkcsspositionvalue.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 "gtkcsspositionvalueprivate.h"
21
22 #include "gtkcssnumbervalueprivate.h"
23
24 struct _GtkCssValue {
25   GTK_CSS_VALUE_BASE
26   GtkCssValue *x;
27   GtkCssValue *y;
28 };
29
30 static void
31 gtk_css_value_position_free (GtkCssValue *value)
32 {
33   _gtk_css_value_unref (value->x);
34   _gtk_css_value_unref (value->y);
35
36   g_slice_free (GtkCssValue, value);
37 }
38
39 static GtkCssValue *
40 gtk_css_value_position_compute (GtkCssValue             *position,
41                                 guint                    property_id,
42                                 GtkStyleProviderPrivate *provider,
43                                 GtkCssComputedValues    *values,
44                                 GtkCssComputedValues    *parent_values,
45                                 GtkCssDependencies      *dependencies)
46 {
47   GtkCssValue *x, *y;
48   GtkCssDependencies x_deps, y_deps;
49
50   x = _gtk_css_value_compute (position->x, property_id, provider, values, parent_values, &x_deps);
51   y = _gtk_css_value_compute (position->y, property_id, provider, values, parent_values, &y_deps);
52   *dependencies = _gtk_css_dependencies_union (x_deps, y_deps);
53   if (x == position->x && y == position->y)
54     {
55       _gtk_css_value_unref (x);
56       _gtk_css_value_unref (y);
57       return _gtk_css_value_ref (position);
58     }
59
60   return _gtk_css_position_value_new (x, y);
61 }
62
63 static gboolean
64 gtk_css_value_position_equal (const GtkCssValue *position1,
65                               const GtkCssValue *position2)
66 {
67   return _gtk_css_value_equal (position1->x, position2->x)
68       && _gtk_css_value_equal (position1->y, position2->y);
69 }
70
71 static GtkCssValue *
72 gtk_css_value_position_transition (GtkCssValue *start,
73                                    GtkCssValue *end,
74                                    guint        property_id,
75                                    double       progress)
76 {
77   GtkCssValue *x, *y;
78
79   x = _gtk_css_value_transition (start->x, end->x, property_id, progress);
80   if (x == NULL)
81     return NULL;
82   y = _gtk_css_value_transition (start->y, end->y, property_id, progress);
83   if (y == NULL)
84     {
85       _gtk_css_value_unref (x);
86       return NULL;
87     }
88
89   return _gtk_css_position_value_new (x, y);
90 }
91
92 static void
93 gtk_css_value_position_print (const GtkCssValue *position,
94                               GString           *string)
95 {
96   struct {
97     const char *x_name;
98     const char *y_name;
99     GtkCssValue *number;
100   } values[] = { 
101     { "left",   "top",    _gtk_css_number_value_new (0, GTK_CSS_PERCENT) },
102     { "right",  "bottom", _gtk_css_number_value_new (100, GTK_CSS_PERCENT) }
103   };
104   GtkCssValue *center = _gtk_css_number_value_new (50, GTK_CSS_PERCENT);
105   guint i;
106
107   if (_gtk_css_value_equal (position->x, center))
108     {
109       if (_gtk_css_value_equal (position->y, center))
110         {
111           g_string_append (string, "center");
112           goto done;
113         }
114     }
115   else
116     {
117       for (i = 0; i < G_N_ELEMENTS (values); i++)
118         {
119           if (_gtk_css_value_equal (position->x, values[i].number))
120             {
121               g_string_append (string, values[i].x_name);
122               break;
123             }
124         }
125       if (i == G_N_ELEMENTS (values))
126         _gtk_css_value_print (position->x, string);
127
128       if (_gtk_css_value_equal (position->y, center))
129         goto done;
130
131       g_string_append_c (string, ' ');
132     }
133
134   for (i = 0; i < G_N_ELEMENTS (values); i++)
135     {
136       if (_gtk_css_value_equal (position->y, values[i].number))
137         {
138           g_string_append (string, values[i].y_name);
139           goto done;
140         }
141     }
142   if (i == G_N_ELEMENTS (values))
143     {
144       if (_gtk_css_value_equal (position->x, center))
145         g_string_append (string, "center ");
146       _gtk_css_value_print (position->y, string);
147     }
148
149 done:
150   for (i = 0; i < G_N_ELEMENTS (values); i++)
151     _gtk_css_value_unref (values[i].number);
152   _gtk_css_value_unref (center);
153 }
154
155 static const GtkCssValueClass GTK_CSS_VALUE_POSITION = {
156   gtk_css_value_position_free,
157   gtk_css_value_position_compute,
158   gtk_css_value_position_equal,
159   gtk_css_value_position_transition,
160   gtk_css_value_position_print
161 };
162
163 GtkCssValue *
164 _gtk_css_position_value_new (GtkCssValue *x,
165                              GtkCssValue *y)
166 {
167   GtkCssValue *result;
168
169   result = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_POSITION);
170   result->x = x;
171   result->y = y;
172
173   return result;
174 }
175
176 static GtkCssValue *
177 position_value_parse (GtkCssParser *parser, gboolean try)
178 {
179   static const struct {
180     const char *name;
181     guint       percentage;
182     gboolean    horizontal;
183     gboolean    vertical;
184   } names[] = {
185     { "left",     0, TRUE,  FALSE },
186     { "right",  100, TRUE,  FALSE },
187     { "center",  50, TRUE,  TRUE  },
188     { "top",      0, FALSE, TRUE  },
189     { "bottom", 100, FALSE, TRUE  },
190     { NULL    ,   0, TRUE,  FALSE }, /* used for numbers */
191     { NULL    ,  50, TRUE,  TRUE  }  /* used for no value */
192   };
193   GtkCssValue *x, *y;
194   GtkCssValue **missing;
195   guint first, second;
196
197   for (first = 0; names[first].name != NULL; first++)
198     {
199       if (_gtk_css_parser_try (parser, names[first].name, TRUE))
200         {
201           if (names[first].horizontal)
202             {
203               x = _gtk_css_number_value_new (names[first].percentage, GTK_CSS_PERCENT);
204               missing = &y;
205             }
206           else
207             {
208               y = _gtk_css_number_value_new (names[first].percentage, GTK_CSS_PERCENT);
209               missing = &x;
210             }
211           break;
212         }
213     }
214   if (names[first].name == NULL)
215     {
216       if (_gtk_css_parser_has_number (parser))
217         {
218           missing = &y;
219           x = _gtk_css_number_value_parse (parser,
220                                            GTK_CSS_PARSE_PERCENT
221                                            | GTK_CSS_PARSE_LENGTH);
222
223           if (x == NULL)
224             return NULL;
225         }
226       else
227         {
228           if (!try)
229             _gtk_css_parser_error (parser, "Unrecognized position value");
230           return NULL;
231         }
232     }
233
234   for (second = 0; names[second].name != NULL; second++)
235     {
236       if (_gtk_css_parser_try (parser, names[second].name, TRUE))
237         {
238           *missing = _gtk_css_number_value_new (names[second].percentage, GTK_CSS_PERCENT);
239           break;
240         }
241     }
242
243   if (names[second].name == NULL)
244     {
245       if (_gtk_css_parser_has_number (parser))
246         {
247           if (missing != &y)
248             {
249               if (!try)
250                 _gtk_css_parser_error (parser, "Invalid combination of values");
251               _gtk_css_value_unref (y);
252               return NULL;
253             }
254           y = _gtk_css_number_value_parse (parser,
255                                            GTK_CSS_PARSE_PERCENT
256                                            | GTK_CSS_PARSE_LENGTH);
257           if (y == NULL)
258             {
259               _gtk_css_value_unref (x);
260               return NULL;
261             }
262         }
263       else
264         {
265           second++;
266           *missing = _gtk_css_number_value_new (50, GTK_CSS_PERCENT);
267         }
268     }
269   else
270     {
271       if ((names[first].horizontal && !names[second].vertical) ||
272           (!names[first].horizontal && !names[second].horizontal))
273         {
274           if (!try)
275             _gtk_css_parser_error (parser, "Invalid combination of values");
276           _gtk_css_value_unref (x);
277           _gtk_css_value_unref (y);
278           return NULL;
279         }
280     }
281
282   return _gtk_css_position_value_new (x, y);
283 }
284
285 GtkCssValue *
286 _gtk_css_position_value_parse (GtkCssParser *parser)
287 {
288   return position_value_parse (parser, FALSE);
289 }
290
291 GtkCssValue *
292 _gtk_css_position_value_try_parse (GtkCssParser *parser)
293 {
294   return position_value_parse (parser, TRUE);
295 }
296
297 double
298 _gtk_css_position_value_get_x (const GtkCssValue *position,
299                                double             one_hundred_percent)
300 {
301   g_return_val_if_fail (position != NULL, 0.0);
302   g_return_val_if_fail (position->class == &GTK_CSS_VALUE_POSITION, 0.0);
303
304   return _gtk_css_number_value_get (position->x, one_hundred_percent);
305 }
306
307 double
308 _gtk_css_position_value_get_y (const GtkCssValue *position,
309                                double             one_hundred_percent)
310 {
311   g_return_val_if_fail (position != NULL, 0.0);
312   g_return_val_if_fail (position->class == &GTK_CSS_VALUE_POSITION, 0.0);
313
314   return _gtk_css_number_value_get (position->y, one_hundred_percent);
315 }
316