]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssbordervalue.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkcssbordervalue.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 "gtkcssbordervalueprivate.h"
21
22 #include "gtkcssnumbervalueprivate.h"
23
24 struct _GtkCssValue {
25   GTK_CSS_VALUE_BASE
26   guint fill :1;
27   GtkCssValue *values[4];
28 };
29
30 static void
31 gtk_css_value_border_free (GtkCssValue *value)
32 {
33   guint i;
34
35   for (i = 0; i < 4; i++)
36     {
37       if (value->values[i])
38         _gtk_css_value_unref (value->values[i]);
39     }
40
41   g_slice_free (GtkCssValue, value);
42 }
43
44 static GtkCssValue *
45 gtk_css_value_border_compute (GtkCssValue             *value,
46                               guint                    property_id,
47                               GtkStyleProviderPrivate *provider,
48                               GtkCssComputedValues    *values,
49                               GtkCssComputedValues    *parent_values,
50                               GtkCssDependencies       *dependencies)
51 {
52   GtkCssValue *computed;
53   GtkCssDependencies child_deps;
54   gboolean changed = FALSE;
55   guint i;
56
57   computed = _gtk_css_border_value_new (NULL, NULL, NULL, NULL);
58   computed->fill = value->fill;
59
60   for (i = 0; i < 4; i++)
61     {
62       if (value->values[i])
63         {
64           computed->values[i] = _gtk_css_value_compute (value->values[i], property_id, provider, values, parent_values, &child_deps);
65           *dependencies = _gtk_css_dependencies_union (*dependencies, child_deps);
66           changed |= (computed->values[i] != value->values[i]);
67         }
68     }
69
70   if (!changed)
71     {
72       _gtk_css_value_unref (computed);
73       return _gtk_css_value_ref (value);
74     }
75
76   return computed;
77 }
78
79 static gboolean
80 gtk_css_value_border_equal (const GtkCssValue *value1,
81                             const GtkCssValue *value2)
82 {
83   guint i;
84
85   if (value1->fill != value2->fill)
86     return FALSE;
87
88   for (i = 0; i < 4; i++)
89     {
90       if (!_gtk_css_value_equal0 (value1->values[i], value2->values[i]))
91         return FALSE;
92     }
93
94   return TRUE;
95 }
96
97 static GtkCssValue *
98 gtk_css_value_border_transition (GtkCssValue *start,
99                                  GtkCssValue *end,
100                                  guint        property_id,
101                                  double       progress)
102 {
103   return NULL;
104 }
105
106 static void
107 gtk_css_value_border_print (const GtkCssValue *value,
108                             GString           *string)
109 {
110   guint i, n;
111
112   if (!_gtk_css_value_equal0 (value->values[GTK_CSS_RIGHT], value->values[GTK_CSS_LEFT]))
113     n = 4;
114   else if (!_gtk_css_value_equal0 (value->values[GTK_CSS_TOP], value->values[GTK_CSS_BOTTOM]))
115     n = 3;
116   else if (!_gtk_css_value_equal0 (value->values[GTK_CSS_TOP], value->values[GTK_CSS_RIGHT]))
117     n = 2;
118   else
119     n = 1;
120
121   for (i = 0; i < n; i++)
122     {
123       if (i > 0)
124         g_string_append_c (string, ' ');
125
126       if (value->values[i] == NULL)
127         g_string_append (string, "auto");
128       else
129         _gtk_css_value_print (value->values[i], string);
130     }
131
132   if (value->fill)
133     g_string_append (string, " fill");
134 }
135
136 static const GtkCssValueClass GTK_CSS_VALUE_BORDER = {
137   gtk_css_value_border_free,
138   gtk_css_value_border_compute,
139   gtk_css_value_border_equal,
140   gtk_css_value_border_transition,
141   gtk_css_value_border_print
142 };
143
144 GtkCssValue *
145 _gtk_css_border_value_new (GtkCssValue *top,
146                            GtkCssValue *right,
147                            GtkCssValue *bottom,
148                            GtkCssValue *left)
149 {
150   GtkCssValue *result;
151
152   result = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_BORDER);
153   result->values[GTK_CSS_TOP] = top;
154   result->values[GTK_CSS_RIGHT] = right;
155   result->values[GTK_CSS_BOTTOM] = bottom;
156   result->values[GTK_CSS_LEFT] = left;
157
158   return result;
159 }
160
161 GtkCssValue *
162 _gtk_css_border_value_parse (GtkCssParser           *parser,
163                              GtkCssNumberParseFlags  flags,
164                              gboolean                allow_auto,
165                              gboolean                allow_fill)
166 {
167   GtkCssValue *result;
168   guint i;
169
170   result = _gtk_css_border_value_new (NULL, NULL, NULL, NULL);
171
172   if (allow_fill)
173     result->fill = _gtk_css_parser_try (parser, "fill", TRUE);
174
175   for (i = 0; i < 4; i++)
176     {
177       if (allow_auto && _gtk_css_parser_try (parser, "auto", TRUE))
178         continue;
179
180       if (!_gtk_css_parser_has_number (parser))
181         break;
182
183       result->values[i] = _gtk_css_number_value_parse (parser, flags);
184       if (result->values[i] == NULL)
185         {
186           _gtk_css_value_unref (result);
187           return NULL;
188         }
189     }
190
191   if (i == 0)
192     {
193       _gtk_css_parser_error (parser, "Expected a number");
194       _gtk_css_value_unref (result);
195       return NULL;
196     }
197
198   if (allow_fill && !result->fill)
199     result->fill = _gtk_css_parser_try (parser, "fill", TRUE);
200
201   for (; i < 4; i++)
202     {
203       if (result->values[(i - 1) >> 1])
204         result->values[i] = _gtk_css_value_ref (result->values[(i - 1) >> 1]);
205     }
206
207   return result;
208 }
209
210 GtkCssValue *
211 _gtk_css_border_value_get_top (const GtkCssValue *value)
212 {
213   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER, NULL);
214
215   return value->values[GTK_CSS_TOP];
216 }
217
218 GtkCssValue *
219 _gtk_css_border_value_get_right (const GtkCssValue *value)
220 {
221   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER, NULL);
222
223   return value->values[GTK_CSS_RIGHT];
224 }
225
226 GtkCssValue *
227 _gtk_css_border_value_get_bottom (const GtkCssValue *value)
228 {
229   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER, NULL);
230
231   return value->values[GTK_CSS_BOTTOM];
232 }
233
234 GtkCssValue *
235 _gtk_css_border_value_get_left (const GtkCssValue *value)
236 {
237   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER, NULL);
238
239   return value->values[GTK_CSS_LEFT];
240 }
241