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: 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 | 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 | |
85 | static gboolean |
86 | gtk_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 | |
103 | static GtkCssValue * |
104 | gtk_css_value_border_transition (GtkCssValue *start, |
105 | GtkCssValue *end, |
106 | guint property_id, |
107 | double progress) |
108 | { |
109 | return NULL; |
110 | } |
111 | |
112 | static void |
113 | gtk_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 | |
142 | static 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 | |
153 | GtkCssValue * |
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, >K_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 | |
174 | GtkCssValue * |
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 | |
231 | GtkCssValue * |
232 | _gtk_css_border_value_get_top (const GtkCssValue *value) |
233 | { |
234 | g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL); |
235 | |
236 | return value->values[GTK_CSS_TOP]; |
237 | } |
238 | |
239 | GtkCssValue * |
240 | _gtk_css_border_value_get_right (const GtkCssValue *value) |
241 | { |
242 | g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL); |
243 | |
244 | return value->values[GTK_CSS_RIGHT]; |
245 | } |
246 | |
247 | GtkCssValue * |
248 | _gtk_css_border_value_get_bottom (const GtkCssValue *value) |
249 | { |
250 | g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL); |
251 | |
252 | return value->values[GTK_CSS_BOTTOM]; |
253 | } |
254 | |
255 | GtkCssValue * |
256 | _gtk_css_border_value_get_left (const GtkCssValue *value) |
257 | { |
258 | g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL); |
259 | |
260 | return value->values[GTK_CSS_LEFT]; |
261 | } |
262 | |
263 | |