]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssmatcher.c
Updated Russian translation
[~andy/gtk] / gtk / gtkcssmatcher.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2012 Benjamin Otte <otte@gnome.org>
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 "gtkcssmatcherprivate.h"
21
22 #include "gtkwidgetpath.h"
23
24 /* GTK_CSS_MATCHER_WIDGET_PATH */
25
26 static gboolean
27 gtk_css_matcher_widget_path_get_parent (GtkCssMatcher       *matcher,
28                                         const GtkCssMatcher *child)
29 {
30   if (child->path.index == 0)
31     return FALSE;
32
33   matcher->path.klass = child->path.klass;
34   matcher->path.path = child->path.path;
35   matcher->path.state_flags = 0;
36   matcher->path.index = child->path.index - 1;
37   matcher->path.sibling_index = gtk_widget_path_iter_get_sibling_index (matcher->path.path, matcher->path.index);
38
39   return TRUE;
40 }
41
42 static gboolean
43 gtk_css_matcher_widget_path_get_previous (GtkCssMatcher       *matcher,
44                                           const GtkCssMatcher *next)
45 {
46   if (next->path.sibling_index == 0)
47     return FALSE;
48
49   matcher->path.klass = next->path.klass;
50   matcher->path.path = next->path.path;
51   matcher->path.state_flags = 0;
52   matcher->path.index = next->path.index;
53   matcher->path.sibling_index = next->path.sibling_index - 1;
54
55   return TRUE;
56 }
57
58 static GtkStateFlags
59 gtk_css_matcher_widget_path_get_state (const GtkCssMatcher *matcher)
60 {
61   return matcher->path.state_flags;
62 }
63
64 static gboolean
65 gtk_css_matcher_widget_path_has_name (const GtkCssMatcher *matcher,
66                                       const char          *name)
67 {
68   const GtkWidgetPath *siblings;
69   GType type;
70   
71   type = g_type_from_name (name);
72   siblings = gtk_widget_path_iter_get_siblings (matcher->path.path, matcher->path.index);
73   if (siblings && matcher->path.sibling_index != gtk_widget_path_iter_get_sibling_index (matcher->path.path, matcher->path.index))
74     return g_type_is_a (gtk_widget_path_iter_get_object_type (siblings, matcher->path.sibling_index), type);
75   else
76     return g_type_is_a (gtk_widget_path_iter_get_object_type (matcher->path.path, matcher->path.index), type);
77 }
78
79 static gboolean
80 gtk_css_matcher_widget_path_has_class (const GtkCssMatcher *matcher,
81                                        GQuark               class_name)
82 {
83   const GtkWidgetPath *siblings;
84   
85   siblings = gtk_widget_path_iter_get_siblings (matcher->path.path, matcher->path.index);
86   if (siblings && matcher->path.sibling_index != gtk_widget_path_iter_get_sibling_index (matcher->path.path, matcher->path.index))
87     return gtk_widget_path_iter_has_qclass (siblings, matcher->path.sibling_index, class_name);
88   else
89     return gtk_widget_path_iter_has_qclass (matcher->path.path, matcher->path.index, class_name);
90 }
91
92 static gboolean
93 gtk_css_matcher_widget_path_has_id (const GtkCssMatcher *matcher,
94                                     const char          *id)
95 {
96   const GtkWidgetPath *siblings;
97   
98   siblings = gtk_widget_path_iter_get_siblings (matcher->path.path, matcher->path.index);
99   if (siblings && matcher->path.sibling_index != gtk_widget_path_iter_get_sibling_index (matcher->path.path, matcher->path.index))
100     return gtk_widget_path_iter_has_name (siblings, matcher->path.sibling_index, id);
101   else
102     return gtk_widget_path_iter_has_name (matcher->path.path, matcher->path.index, id);
103 }
104
105 static gboolean
106 gtk_css_matcher_widget_path_has_regions (const GtkCssMatcher *matcher)
107 {
108   const GtkWidgetPath *siblings;
109   GSList *regions;
110   gboolean result;
111   
112   siblings = gtk_widget_path_iter_get_siblings (matcher->path.path, matcher->path.index);
113   if (siblings && matcher->path.sibling_index != gtk_widget_path_iter_get_sibling_index (matcher->path.path, matcher->path.index))
114     regions = gtk_widget_path_iter_list_regions (siblings, matcher->path.sibling_index);
115   else
116     regions = gtk_widget_path_iter_list_regions (matcher->path.path, matcher->path.index);
117   result = regions != NULL;
118   g_slist_free (regions);
119
120   return result;
121 }
122
123 static gboolean
124 gtk_css_matcher_widget_path_has_region (const GtkCssMatcher *matcher,
125                                         const char          *region,
126                                         GtkRegionFlags       flags)
127 {
128   const GtkWidgetPath *siblings;
129   GtkRegionFlags region_flags;
130   
131   siblings = gtk_widget_path_iter_get_siblings (matcher->path.path, matcher->path.index);
132   if (siblings && matcher->path.sibling_index != gtk_widget_path_iter_get_sibling_index (matcher->path.path, matcher->path.index))
133     {
134       if (!gtk_widget_path_iter_has_region (siblings, matcher->path.sibling_index, region, &region_flags))
135         return FALSE;
136     }
137   else
138     {
139       if (!gtk_widget_path_iter_has_region (matcher->path.path, matcher->path.index, region, &region_flags))
140         return FALSE;
141     }
142
143   if ((flags & region_flags) != flags)
144     return FALSE;
145
146   return TRUE;
147 }
148
149 static gboolean
150 gtk_css_matcher_widget_path_has_position (const GtkCssMatcher *matcher,
151                                           gboolean             forward,
152                                           int                  a,
153                                           int                  b)
154 {
155   const GtkWidgetPath *siblings;
156   int x;
157
158   siblings = gtk_widget_path_iter_get_siblings (matcher->path.path, matcher->path.index);
159   if (!siblings)
160     return FALSE;
161
162   if (forward)
163     x = matcher->path.sibling_index + 1;
164   else
165     x = gtk_widget_path_length (siblings) - matcher->path.sibling_index;
166
167   x -= b;
168
169   if (a == 0)
170     return x == 0;
171
172   if (x % a)
173     return FALSE;
174
175   return x / a > 0;
176 }
177
178 static const GtkCssMatcherClass GTK_CSS_MATCHER_WIDGET_PATH = {
179   gtk_css_matcher_widget_path_get_parent,
180   gtk_css_matcher_widget_path_get_previous,
181   gtk_css_matcher_widget_path_get_state,
182   gtk_css_matcher_widget_path_has_name,
183   gtk_css_matcher_widget_path_has_class,
184   gtk_css_matcher_widget_path_has_id,
185   gtk_css_matcher_widget_path_has_regions,
186   gtk_css_matcher_widget_path_has_region,
187   gtk_css_matcher_widget_path_has_position,
188 };
189
190 gboolean
191 _gtk_css_matcher_init (GtkCssMatcher       *matcher,
192                        const GtkWidgetPath *path,
193                        GtkStateFlags        state)
194 {
195   if (gtk_widget_path_length (path) == 0)
196     return FALSE;
197
198   matcher->path.klass = &GTK_CSS_MATCHER_WIDGET_PATH;
199   matcher->path.path = path;
200   matcher->path.state_flags = state;
201   matcher->path.index = gtk_widget_path_length (path) - 1;
202   matcher->path.sibling_index = gtk_widget_path_iter_get_sibling_index (path, matcher->path.index);
203
204   return TRUE;
205 }
206
207 /* GTK_CSS_MATCHER_WIDGET_ANY */
208
209 static gboolean
210 gtk_css_matcher_any_get_parent (GtkCssMatcher       *matcher,
211                                 const GtkCssMatcher *child)
212 {
213   _gtk_css_matcher_any_init (matcher);
214
215   return TRUE;
216 }
217
218 static gboolean
219 gtk_css_matcher_any_get_previous (GtkCssMatcher       *matcher,
220                                   const GtkCssMatcher *next)
221 {
222   _gtk_css_matcher_any_init (matcher);
223
224   return TRUE;
225 }
226
227 static GtkStateFlags
228 gtk_css_matcher_any_get_state (const GtkCssMatcher *matcher)
229 {
230   /* XXX: This gets tricky when we implement :not() */
231
232   return GTK_STATE_FLAG_ACTIVE | GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED
233     | GTK_STATE_FLAG_INSENSITIVE | GTK_STATE_FLAG_INCONSISTENT
234     | GTK_STATE_FLAG_FOCUSED | GTK_STATE_FLAG_BACKDROP;
235 }
236
237 static gboolean
238 gtk_css_matcher_any_has_name (const GtkCssMatcher *matcher,
239                               const char          *name)
240 {
241   return TRUE;
242 }
243
244 static gboolean
245 gtk_css_matcher_any_has_class (const GtkCssMatcher *matcher,
246                                GQuark               class_name)
247 {
248   return TRUE;
249 }
250
251 static gboolean
252 gtk_css_matcher_any_has_id (const GtkCssMatcher *matcher,
253                                     const char          *id)
254 {
255   return TRUE;
256 }
257
258 static gboolean
259 gtk_css_matcher_any_has_regions (const GtkCssMatcher *matcher)
260 {
261   return TRUE;
262 }
263
264 static gboolean
265 gtk_css_matcher_any_has_region (const GtkCssMatcher *matcher,
266                                 const char          *region,
267                                 GtkRegionFlags       flags)
268 {
269   return TRUE;
270 }
271
272 static gboolean
273 gtk_css_matcher_any_has_position (const GtkCssMatcher *matcher,
274                                   gboolean             forward,
275                                   int                  a,
276                                   int                  b)
277 {
278   return TRUE;
279 }
280
281 static const GtkCssMatcherClass GTK_CSS_MATCHER_ANY = {
282   gtk_css_matcher_any_get_parent,
283   gtk_css_matcher_any_get_previous,
284   gtk_css_matcher_any_get_state,
285   gtk_css_matcher_any_has_name,
286   gtk_css_matcher_any_has_class,
287   gtk_css_matcher_any_has_id,
288   gtk_css_matcher_any_has_regions,
289   gtk_css_matcher_any_has_region,
290   gtk_css_matcher_any_has_position,
291 };
292
293 void
294 _gtk_css_matcher_any_init (GtkCssMatcher *matcher)
295 {
296   matcher->klass = &GTK_CSS_MATCHER_ANY;
297 }
298
299 /* GTK_CSS_MATCHER_WIDGET_SUPERSET */
300
301 static gboolean
302 gtk_css_matcher_superset_get_parent (GtkCssMatcher       *matcher,
303                                      const GtkCssMatcher *child)
304 {
305   _gtk_css_matcher_any_init (matcher);
306
307   return TRUE;
308 }
309
310 static gboolean
311 gtk_css_matcher_superset_get_previous (GtkCssMatcher       *matcher,
312                                        const GtkCssMatcher *next)
313 {
314   _gtk_css_matcher_any_init (matcher);
315
316   return TRUE;
317 }
318
319 static GtkStateFlags
320 gtk_css_matcher_superset_get_state (const GtkCssMatcher *matcher)
321 {
322   /* XXX: This gets tricky when we implement :not() */
323
324   if (matcher->superset.relevant & GTK_CSS_CHANGE_STATE)
325     return _gtk_css_matcher_get_state (matcher->superset.subset);
326   else
327     return GTK_STATE_FLAG_ACTIVE | GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED
328       | GTK_STATE_FLAG_INSENSITIVE | GTK_STATE_FLAG_INCONSISTENT
329       | GTK_STATE_FLAG_FOCUSED | GTK_STATE_FLAG_BACKDROP;
330 }
331
332 static gboolean
333 gtk_css_matcher_superset_has_name (const GtkCssMatcher *matcher,
334                                    const char          *name)
335 {
336   if (matcher->superset.relevant & GTK_CSS_CHANGE_NAME)
337     return _gtk_css_matcher_has_name (matcher->superset.subset, name);
338   else
339     return TRUE;
340 }
341
342 static gboolean
343 gtk_css_matcher_superset_has_class (const GtkCssMatcher *matcher,
344                                     GQuark               class_name)
345 {
346   if (matcher->superset.relevant & GTK_CSS_CHANGE_CLASS)
347     return _gtk_css_matcher_has_class (matcher->superset.subset, class_name);
348   else
349     return TRUE;
350 }
351
352 static gboolean
353 gtk_css_matcher_superset_has_id (const GtkCssMatcher *matcher,
354                                  const char          *id)
355 {
356   if (matcher->superset.relevant & GTK_CSS_CHANGE_NAME)
357     return _gtk_css_matcher_has_id (matcher->superset.subset, id);
358   else
359     return TRUE;
360 }
361
362 static gboolean
363 gtk_css_matcher_superset_has_regions (const GtkCssMatcher *matcher)
364 {
365   if (matcher->superset.relevant & GTK_CSS_CHANGE_NAME)
366     return _gtk_css_matcher_has_regions (matcher->superset.subset);
367   else
368     return TRUE;
369 }
370
371 static gboolean
372 gtk_css_matcher_superset_has_region (const GtkCssMatcher *matcher,
373                                      const char          *region,
374                                      GtkRegionFlags       flags)
375 {
376   if (matcher->superset.relevant & GTK_CSS_CHANGE_NAME)
377     {
378       if (matcher->superset.relevant & GTK_CSS_CHANGE_POSITION)
379         return _gtk_css_matcher_has_region (matcher->superset.subset, region, flags);
380       else
381         return _gtk_css_matcher_has_region (matcher->superset.subset, region, 0);
382     }
383   else
384     return TRUE;
385 }
386
387 static gboolean
388 gtk_css_matcher_superset_has_position (const GtkCssMatcher *matcher,
389                                        gboolean             forward,
390                                        int                  a,
391                                        int                  b)
392 {
393   if (matcher->superset.relevant & GTK_CSS_CHANGE_POSITION)
394     return _gtk_css_matcher_has_position (matcher->superset.subset, forward, a, b);
395   else
396     return TRUE;
397 }
398
399 static const GtkCssMatcherClass GTK_CSS_MATCHER_SUPERSET = {
400   gtk_css_matcher_superset_get_parent,
401   gtk_css_matcher_superset_get_previous,
402   gtk_css_matcher_superset_get_state,
403   gtk_css_matcher_superset_has_name,
404   gtk_css_matcher_superset_has_class,
405   gtk_css_matcher_superset_has_id,
406   gtk_css_matcher_superset_has_regions,
407   gtk_css_matcher_superset_has_region,
408   gtk_css_matcher_superset_has_position,
409 };
410
411 void
412 _gtk_css_matcher_superset_init (GtkCssMatcher       *matcher,
413                                 const GtkCssMatcher *subset,
414                                 GtkCssChange         relevant)
415 {
416   g_return_if_fail (subset != NULL);
417   g_return_if_fail ((relevant & ~(GTK_CSS_CHANGE_CLASS | GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_STATE)) == 0);
418
419   matcher->superset.klass = &GTK_CSS_MATCHER_SUPERSET;
420   matcher->superset.subset = subset;
421   matcher->superset.relevant = relevant;
422 }
423