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