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

source code of gtk/gtk/gtkcssbordervalue.c