Ctk

Merge lp:~tkk2112/ctk/partial-new-css into lp:ctk

Proposed by Thomas Kristensen
Status: Needs review
Proposed branch: lp:~tkk2112/ctk/partial-new-css
Merge into: lp:ctk
Diff against target: 1276 lines (+796/-172)
12 files modified
configure.ac (+4/-6)
ctk/Makefile.am (+1/-0)
ctk/adjustment.vala (+7/-0)
ctk/box.vala (+1/-1)
ctk/button.vala (+6/-2)
ctk/layout-manager.vala (+4/-4)
ctk/scrollbar.vala (+1/-1)
ctk/stylable.vala (+5/-7)
ctk/style.vala (+120/-138)
ctk/stylesheet.vala (+584/-0)
ctk/text-entry.vala (+6/-2)
ctk/widget.vala (+57/-11)
To merge this branch: bzr merge lp:~tkk2112/ctk/partial-new-css
Reviewer Review Type Date Requested Status
Ali Sabil Pending
Review via email: mp+24604@code.launchpad.net

Description of the change

partially implemented new css system

To post a comment you must log in.

Unmerged revisions

115. By Thomas Kristensen

Partially implemented the new stylesheet code.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2009-11-13 11:52:55 +0000
3+++ configure.ac 2010-05-03 20:12:42 +0000
4@@ -27,23 +27,21 @@
5 GLIB_REQUIRED=2.16.0
6 CLUTTER_REQUIRED=1.0.0
7 GEE_REQUIRED=0.5.0
8-CCSS_REQUIRED=0.5.0
9
10 PKG_CHECK_MODULES(GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED)
11 PKG_CHECK_MODULES(CLUTTER, clutter-1.0 >= $CLUTTER_REQUIRED)
12 PKG_CHECK_MODULES(GEE, gee-1.0 >= $GEE_REQUIRED)
13-PKG_CHECK_MODULES(CCSS, ccss-1 >= $CCSS_REQUIRED)
14
15-CTK_PKG_DEPS="glib-2.0, gobject-2.0, clutter-1.0, gee-1.0, ccss-1"
16+CTK_PKG_DEPS="glib-2.0, gobject-2.0, gio-2.0, clutter-1.0, gee-1.0"
17 AC_SUBST(CTK_PKG_DEPS)
18
19-CTK_VALAFLAGS="--pkg clutter-1.0 --pkg cogl-1.0 --pkg ccss-1 --pkg gee-1.0"
20+CTK_VALAFLAGS="--pkg gio-2.0 --pkg clutter-1.0 --pkg cogl-1.0 --pkg gee-1.0"
21 AC_SUBST(CTK_VALAFLAGS)
22
23-CTK_CFLAGS="$GLIB_CFLAGS $CLUTTER_CFLAGS $GEE_CFLAGS $CCSS_CFLAGS"
24+CTK_CFLAGS="$GLIB_CFLAGS $CLUTTER_CFLAGS $GEE_CFLAGS"
25 AC_SUBST(CTK_CFLAGS)
26
27-CTK_LIBS="$GLIB_LIBS $CLUTTER_LIBS $GEE_LIBS $CCSS_LIBS"
28+CTK_LIBS="$GLIB_LIBS $CLUTTER_LIBS $GEE_LIBS"
29 AC_SUBST(CTK_LIBS)
30
31 AC_CONFIG_FILES([Makefile
32
33=== modified file 'ctk/Makefile.am'
34--- ctk/Makefile.am 2010-01-24 14:59:58 +0000
35+++ ctk/Makefile.am 2010-05-03 20:12:42 +0000
36@@ -26,6 +26,7 @@
37 scrollview.vala \
38 stylable.vala \
39 style.vala \
40+ stylesheet.vala \
41 text-entry.vala \
42 texture-factory.vala \
43 types.vala \
44
45=== modified file 'ctk/adjustment.vala'
46--- ctk/adjustment.vala 2010-01-19 08:41:34 +0000
47+++ ctk/adjustment.vala 2010-05-03 20:12:42 +0000
48@@ -39,6 +39,7 @@
49 this.value_changed_source = Idle.add_full (Clutter.PRIORITY_REDRAW, () => {
50 this.value_changed_source = 0;
51 this.notify_property ("value");
52+ return false;
53 });
54 }
55 }
56@@ -60,6 +61,7 @@
57 this.lower_changed_source = Idle.add_full (Clutter.PRIORITY_REDRAW, () => {
58 this.lower_changed_source = 0;
59 this.notify_property ("lower");
60+ return false;
61 });
62 }
63 this.clamp_page (this.lower, this.upper);
64@@ -82,6 +84,7 @@
65 this.upper_changed_source = Idle.add_full (Clutter.PRIORITY_REDRAW, () => {
66 this.upper_changed_source = 0;
67 this.notify_property ("upper");
68+ return false;
69 });
70 }
71 this.clamp_page (this.lower, this.upper);
72@@ -104,6 +107,7 @@
73 this.step_increment_changed_source = Idle.add_full (Clutter.PRIORITY_REDRAW, () => {
74 this.step_increment_changed_source = 0;
75 this.notify_property ("step-increment");
76+ return false;
77 });
78 }
79 }
80@@ -125,6 +129,7 @@
81 this.page_increment_changed_source = Idle.add_full (Clutter.PRIORITY_REDRAW, () => {
82 this.page_increment_changed_source = 0;
83 this.notify_property ("page-increment");
84+ return false;
85 });
86 }
87 }
88@@ -146,6 +151,7 @@
89 this.page_size_changed_source = Idle.add_full (Clutter.PRIORITY_REDRAW, () => {
90 this.page_size_changed_source = 0;
91 this.notify_property ("page-size");
92+ return false;
93 });
94 }
95 this.clamp_page (this.lower, this.upper);
96@@ -238,6 +244,7 @@
97 this.changed_source = Idle.add_full (Clutter.PRIORITY_REDRAW, () => {
98 this.changed_source = 0;
99 this.changed ();
100+ return false;
101 });
102 }
103 }
104
105=== modified file 'ctk/box.vala'
106--- ctk/box.vala 2010-01-25 09:02:47 +0000
107+++ ctk/box.vala 2010-05-03 20:12:42 +0000
108@@ -70,7 +70,7 @@
109 if (value != null) {
110 this._layout_manager = value;
111 this._layout_manager.set_container (this);
112- this._layout_manager.layout_changed.connect (this.queue_relayout);
113+ this._layout_manager.layout_changed.connect (() => this.queue_relayout);
114 }
115 this.queue_relayout ();
116 }
117
118=== modified file 'ctk/button.vala'
119--- ctk/button.vala 2009-11-15 21:38:53 +0000
120+++ ctk/button.vala 2010-05-03 20:12:42 +0000
121@@ -71,11 +71,15 @@
122 this._label = new Clutter.Text();
123
124 this.notify["font-family"].connect(() => {
125- this._label.font_name = this.font_family + " " + this.font_size.to_string() + "px";
126+ this._label.font_name = this.get_font_description ();
127 });
128
129 this.notify["font-size"].connect(() => {
130- this._label.font_name = this.font_family + " " + this.font_size.to_string() + "px";
131+ this._label.font_name = this.get_font_description ();
132+ });
133+
134+ this.notify["font-weight"].connect(() => {
135+ this._label.font_name = this.get_font_description ();
136 });
137
138 this.notify["color"].connect(() => {
139
140=== modified file 'ctk/layout-manager.vala'
141--- ctk/layout-manager.vala 2010-01-14 18:04:20 +0000
142+++ ctk/layout-manager.vala 2010-05-03 20:12:42 +0000
143@@ -96,7 +96,7 @@
144 }
145
146 public virtual Clutter.Alpha begin_animation (ulong mode, uint duration) requires (duration < 1000) {
147- Clutter.Alpha alpha = (Clutter.Alpha) this.get_qdata (quark_layout_alpha);
148+ Clutter.Alpha alpha = this.get_qdata<Clutter.Alpha> (quark_layout_alpha);
149 if (alpha != null) {
150 alpha.mode = mode;
151
152@@ -121,7 +121,7 @@
153 }
154
155 public virtual double get_animation_progress () {
156- Clutter.Alpha alpha = (Clutter.Alpha) this.get_qdata (quark_layout_alpha);
157+ Clutter.Alpha alpha = this.get_qdata<Clutter.Alpha> (quark_layout_alpha);
158 if (alpha == null)
159 return 1.0;
160
161@@ -129,7 +129,7 @@
162 }
163
164 public virtual void end_animation () {
165- Clutter.Alpha alpha = (Clutter.Alpha) this.get_qdata (quark_layout_alpha);
166+ Clutter.Alpha alpha = this.get_qdata<Clutter.Alpha> (quark_layout_alpha);
167 if (alpha == null)
168 return;
169
170@@ -143,7 +143,7 @@
171 }
172
173 public LayoutMeta? get_child_meta (Clutter.Container container, Clutter.Actor actor) {
174- LayoutMeta meta = (LayoutMeta) actor.get_qdata(quark_layout_meta);
175+ LayoutMeta meta = actor.get_qdata<LayoutMeta> (quark_layout_meta);
176 if (meta != null) {
177 var child = meta as Clutter.ChildMeta;
178 if (meta.manager == this && child.container == container && child.actor == actor)
179
180=== modified file 'ctk/scrollbar.vala'
181--- ctk/scrollbar.vala 2010-01-21 09:27:32 +0000
182+++ ctk/scrollbar.vala 2010-05-03 20:12:42 +0000
183@@ -35,7 +35,7 @@
184 }
185
186 this._adjustment = value;
187- this._adjustment.changed.connect (this.queue_relayout);
188+ this._adjustment.changed.connect (() => this.queue_relayout);
189 this._adjustment.notify["value"].connect (this.update_handle_from_size);
190 this.queue_relayout ();
191 }
192
193=== modified file 'ctk/stylable.vala'
194--- ctk/stylable.vala 2009-11-03 12:28:33 +0000
195+++ ctk/stylable.vala 2010-05-03 20:12:42 +0000
196@@ -4,6 +4,7 @@
197 * A Clutter UI toolkit
198 *
199 * Copyright (C) 2009 Ali Sabil
200+* Copyright (C) 2010 Thomas Kristensen
201 *
202 * This library is free software; you can redistribute it and/or
203 * modify it under the terms of the GNU Lesser General Public
204@@ -18,8 +19,8 @@
205 * You should have received a copy of the GNU Lesser General Public
206 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
207 *
208-* Author:
209-* Ali Sabil <ali.sabil@gmail.com>
210+* Author: Ali Sabil <ali.sabil@gmail.com>
211+* Thomas Kristensen <thomas.k.kristensen@tandberg.com>
212 *
213 */
214
215@@ -30,15 +31,12 @@
216 set;
217 }
218
219-
220 public abstract void refresh ();
221 public abstract Stylable? get_style_container ();
222 public abstract Stylable? get_style_base ();
223 public abstract string? get_style_id ();
224 public abstract string? get_style_type ();
225- [CCode (array_length = false, array_null_terminated = true)]
226- public abstract string[]? get_style_classes ();
227- [CCode (array_length = false, array_null_terminated = true)]
228- public abstract string[]? get_style_pseudo_classes ();
229+ public abstract Gee.Set<string> get_style_classes ();
230+ public abstract Gee.Set<string> get_style_pseudo_classes ();
231 }
232 }
233
234=== modified file 'ctk/style.vala'
235--- ctk/style.vala 2010-01-24 17:06:13 +0000
236+++ ctk/style.vala 2010-05-03 20:12:42 +0000
237@@ -4,6 +4,7 @@
238 * A Clutter UI toolkit
239 *
240 * Copyright (C) 2009 Ali Sabil
241+* Copyright (C) 2010 Thomas Kristensen
242 *
243 * This library is free software; you can redistribute it and/or
244 * modify it under the terms of the GNU Lesser General Public
245@@ -18,16 +19,23 @@
246 * You should have received a copy of the GNU Lesser General Public
247 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
248 *
249-* Author:
250-* Ali Sabil <ali.sabil@gmail.com>
251+* Author: Ali Sabil <ali.sabil@gmail.com>
252+* Thomas Kristensen <thomas.k.kristensen@tandberg.com>
253 *
254 */
255
256 namespace Ctk {
257- public class Style: Object {
258+
259+ public enum FontWeight {
260+ NORMAL,
261+ BOLD,
262+ LIGHTER,
263+ BOLDER
264+ }
265+
266+ public class Style: Object {
267 private static Style default_style;
268- private CCss.Grammar grammar;
269- private CCss.Stylesheet stylesheet;
270+ private Css.Stylesheet stylesheet;
271
272 public signal void changed ();
273
274@@ -36,7 +44,7 @@
275 if (rc_file == null) {
276 rc_file = Path.build_filename (Config.PACKAGE_DATADIR, "ctk", "style", "default.css");
277 }
278- this.load_stylesheet (rc_file, CCss.Stylesheet.Precedence.USER_AGENT);
279+ this.load_stylesheet (rc_file, Css.Stylesheet.Precedence.USER_AGENT);
280 }
281
282 public static unowned Style get_default () {
283@@ -46,11 +54,99 @@
284 }
285
286 public bool load_from_file (string filename) {
287- return this.load_stylesheet (filename, CCss.Stylesheet.Precedence.AUTHOR);
288+ return this.load_stylesheet (filename, Css.Stylesheet.Precedence.AUTHOR);
289 }
290
291 public new bool get_property (Stylable target, ParamSpec pspec, out Value value) {
292- value.init (pspec.value_type);
293+ value.init (pspec.value_type);
294+
295+ var properties = this.stylesheet.get_properties (target);
296+
297+ stdout.printf("target=%s typeof(%s)\n", target.get_style_id (), target.get_style_type ());
298+ stdout.printf("prop size=%d\n", properties.size);
299+
300+
301+ foreach (var p in properties) {
302+ stdout.printf("%s\n", p.key);
303+ }
304+ var css_value = properties[pspec.name];
305+
306+
307+
308+ if (css_value.source != null)
309+ stdout.printf("name=%s\n", css_value.source);
310+ if (css_value.value != null)
311+ stdout.printf("string=%s\n", css_value.value);
312+ if (pspec.name != null)
313+ stdout.printf("pname=%s\n", pspec.name);
314+
315+ if (pspec.value_type == typeof (int)) {
316+ if (css_value.value != null)
317+ value.set_int (css_value.value.to_int ());
318+ else
319+ value.set_int (0);
320+ return true;
321+ } else if (pspec.value_type == typeof (uint)) {
322+ if (css_value.value != null)
323+ value.set_uint (css_value.value.to_int ());
324+ else
325+ value.set_uint (0);
326+ return true;
327+ }
328+ return false;
329+ /* else if (pspec.value_type == typeof (BorderImage)) {
330+
331+ unowned Css.Property property;
332+
333+ if (style.get_property ("border-image", out property)) {
334+ unowned Css.BorderImage border_image = (Css.BorderImage) property;
335+
336+ BorderImage result = BorderImage (border_image.uri);
337+
338+ if (result.uri != null) {
339+ int width, height;
340+ result.texture.get_base_size (out width, out height);
341+
342+ result.top = (float) border_image.top.get_size (height);
343+ result.right = (float) border_image.right.get_size (width);
344+ result.bottom = (float) border_image.bottom.get_size (height);
345+ result.left = (float) border_image.left.get_size (width);
346+ }
347+
348+ value.set_boxed (&result);
349+ return true;
350+ }
351+ } else if (pspec->value_type == MX_TYPE_FONT_WEIGHT)
352+ {
353+ g_value_init (value, pspec->value_type);
354+
355+ mx_font_weight_set_from_string (value, css_value->string);
356+ }
357+ else
358+ {
359+ GValue strval = { 0, };
360+
361+ g_value_init (value, pspec->value_type);
362+
363+ g_value_init (&strval, G_TYPE_STRING);
364+ g_value_set_string (&strval, css_value->string);
365+
366+ if (!g_value_transform (&strval, value))
367+ {
368+ g_warning ("Error setting property \"%s\" on \"%s\", could"
369+ " not transform \"%s\" from string to type %s",
370+ pspec->name,
371+ G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS (stylable)),
372+ css_value->string,
373+ g_type_name (pspec->value_type));
374+ }
375+ g_value_unset (&strval);
376+ }*/
377+ }
378+
379+
380+
381+/* value.init (pspec.value_type);
382
383 if (this.stylesheet != null) {
384 double number = 0.0;
385@@ -96,10 +192,10 @@
386 value.set_boxed (&padding);
387 return result;
388 } else if (pspec.value_type == typeof (BorderImage)) {
389- unowned CCss.Property property;
390+ unowned Css.Property property;
391
392 if (style.get_property ("border-image", out property)) {
393- unowned CCss.BorderImage border_image = (CCss.BorderImage) property;
394+ unowned Css.BorderImage border_image = (Css.BorderImage) property;
395
396 BorderImage result = BorderImage (border_image.uri);
397
398@@ -117,10 +213,10 @@
399 return true;
400 }
401 } else if (pspec.value_type == typeof (Clutter.Texture)) {
402- unowned CCss.Property property;
403+ unowned Css.Property property;
404
405 if (style.get_property ("background-image", out property)) {
406- unowned CCss.BackgroundImage background_image = (CCss.BackgroundImage) property;
407+ unowned Css.BackgroundImage background_image = (Css.BackgroundImage) property;
408
409 if (background_image.uri != null) {
410 var result = TextureFactory.get_default ().get_texture (background_image.uri, true);
411@@ -141,136 +237,22 @@
412 }
413 }
414 }
415- }
416- return false;
417- }
418-
419- private CCss.Style get_style (Stylable stylable) {
420- var node = new Node (stylable);
421- var style = this.stylesheet.query (node.get_internal_node ());
422- return style;
423- }
424-
425- private bool load_stylesheet (string filename, CCss.Stylesheet.Precedence precedence) {
426- if (!FileUtils.test (filename, FileTest.IS_REGULAR)) {
427+ }*/
428+
429+ private bool load_stylesheet (string filename, Css.Stylesheet.Precedence precedence) {
430+ if (!FileUtils.test (filename, FileTest.IS_REGULAR))
431 return false;
432- }
433
434- string path = Path.get_dirname (filename);
435+ var success = false;
436 if (this.stylesheet == null) {
437- this.grammar = new CCss.Grammar.css ();
438-
439- var url_function = new CCss.Function ("url", url_handler);
440- grammar.add_function (url_function);
441-
442- // FIXME: memory leak in path
443- this.stylesheet = grammar.create_stylesheet_from_file (filename, (owned) path);
444+ this.stylesheet = new Css.Stylesheet ();
445+ success = this.stylesheet.add_from_file (filename, precedence);
446 } else {
447- var url_function = new CCss.Function ("url", url_handler);
448- this.grammar.add_function (url_function);
449- this.stylesheet.add_from_file (filename, precedence, (owned) path);
450- }
451- this.changed ();
452- return true;
453- }
454-
455- private static string? url_handler (SList<string> args, void* user_data) {
456- string? url = args.data;
457-
458- if (url == null || !url.has_prefix ("file://"))
459- return null;
460-
461- url = url.substring (7);
462- if (url[0] != '/' && user_data != null) {
463- url = Path.build_filename ((string) user_data, url);
464- }
465-
466- if (!FileUtils.test (url, FileTest.IS_REGULAR)) {
467- url = null;
468- }
469- return url;
470- }
471-
472- private class Node {
473- private Stylable stylable;
474- private static CCss.NodeClass node_class;
475- private CCss.Node node;
476-
477- public Node (Stylable stylable) {
478- this.stylable = stylable;
479-
480- this.node_class.get_container = Node.get_style_container;
481- this.node_class.get_id = Node.get_style_id;
482- this.node_class.get_type = Node.get_style_type;
483- this.node_class.get_classes = Node.get_style_classes;
484- this.node_class.get_pseudo_classes = Node.get_style_pseudo_classes;
485- this.node_class.release = Node.style_release;
486-
487- this.node = new CCss.Node (this.node_class, 12, this);
488- }
489-
490- public unowned CCss.Node get_internal_node () {
491- return this.node;
492- }
493-
494- private static CCss.Node? get_style_container (CCss.Node ccss_node) {
495- Node node = ccss_node.get_user_data () as Node;
496-
497- if (node != null) {
498- Stylable stylable = node.stylable;
499-
500- Clutter.Actor parent = (stylable as Clutter.Actor).get_parent ();
501- if (parent != null) {
502- return new CCss.Node (Node.node_class, 12, parent);
503- }
504- }
505-
506- return null;
507- }
508-
509- private static string? get_style_id (CCss.Node ccss_node) {
510- Node node = ccss_node.get_user_data () as Node;
511- Stylable stylable = node.stylable;
512- return stylable.get_style_id ();
513- }
514-
515- private static string? get_style_type (CCss.Node ccss_node) {
516- Node node = ccss_node.get_user_data () as Node;
517-
518- if (node != null) {
519- Stylable stylable = node.stylable;
520- return stylable.get_style_type ();
521- }
522-
523- return null;
524- }
525-
526- [CCode (array_length = false, array_null_terminated = true)]
527- private static string[]? get_style_classes (CCss.Node ccss_node) {
528- Node node = ccss_node.get_user_data () as Node;
529-
530- if (node != null) {
531- Stylable stylable = node.stylable;
532- return stylable.get_style_classes ();
533- }
534-
535- return null;
536- }
537-
538- [CCode (array_length = false, array_null_terminated = true)]
539- private static string[]? get_style_pseudo_classes (CCss.Node ccss_node) {
540- Node node = ccss_node.get_user_data () as Node;
541-
542- if (node != null) {
543- Stylable stylable = node.stylable;
544- return stylable.get_style_pseudo_classes ();
545- }
546-
547- return null;
548- }
549-
550- private static void style_release (CCss.Node ccss_node) {
551- }
552+ success = this.stylesheet.add_from_file (filename, precedence);
553+ }
554+ if (success)
555+ this.changed ();
556+ return success;
557 }
558 }
559 }
560
561=== added file 'ctk/stylesheet.vala'
562--- ctk/stylesheet.vala 1970-01-01 00:00:00 +0000
563+++ ctk/stylesheet.vala 2010-05-03 20:12:42 +0000
564@@ -0,0 +1,584 @@
565+/*
566+ * Ctk
567+ *
568+ * A Clutter UI toolkit
569+ *
570+ * Copyright (C) 2009 Ali Sabil
571+ * Copyright (C) 2010 Thomas Kristensen
572+ *
573+ * This program is free software; you can redistribute it and/or modify it
574+ * under the terms and conditions of the GNU Lesser General Public License,
575+ * version 2.1, as published by the Free Software Foundation.
576+ *
577+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
578+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
579+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
580+ * more details.
581+ *
582+ * You should have received a copy of the GNU Lesser General Public License
583+ * along with this program; if not, write to the Free Software Foundation,
584+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
585+ *
586+ * Author: Thomas Kristensen <thomas.k.kristensen@tandberg.com>
587+ *
588+ * The most of the code was translated from C to Vala, the original code
589+ * had the following Copyright notice:
590+ */
591+
592+/*
593+ * Copyright 2009 Intel Corporation.
594+ *
595+ * This program is free software; you can redistribute it and/or modify it
596+ * under the terms and conditions of the GNU Lesser General Public License,
597+ * version 2.1, as published by the Free Software Foundation.
598+ *
599+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
600+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
601+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
602+ * more details.
603+ *
604+ * You should have received a copy of the GNU Lesser General Public License
605+ * along with this program; if not, write to the Free Software Foundation,
606+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
607+ *
608+ * Author: Thomas Wood <thos@gnome.org>
609+ *
610+ */
611+
612+namespace Ctk {
613+ namespace Css {
614+
615+ public struct StyleSheetValue {
616+ string value;
617+ string source;
618+ }
619+
620+ public class Stylesheet: Object {
621+ public enum Precedence {
622+ USER_AGENT,
623+ USER,
624+ AUTHOR
625+ }
626+
627+ private Gee.ArrayList<Gee.HashMap?> styles;
628+ private Gee.ArrayList<Selector?> selectors;
629+ private Gee.ArrayList<string>? filenames;
630+ private Scanner scanner;
631+ private weak string filename;
632+ private int precedence;
633+
634+ private struct Selector {
635+ string type;
636+ string id;
637+ string class;
638+ string pseudo_class;
639+ Selector? parent;
640+ Selector? ancestor;
641+ Gee.HashMap<string, string> style;
642+ string filename;
643+ int precedence;
644+ }
645+
646+ private struct SelectorMatch {
647+ int id;
648+ int precedence;
649+ int score;
650+ }
651+
652+ public Stylesheet () {
653+ this.styles = new Gee.ArrayList<Gee.HashMap?> ();
654+ this.selectors = new Gee.ArrayList<Selector?> ();
655+ this.filenames = new Gee.ArrayList<string> ();
656+ }
657+
658+ public bool add_from_file (string filename, Precedence precedence) {
659+ if (!FileUtils.test (filename, FileTest.IS_REGULAR))
660+ return false;
661+
662+ if (this.filenames.contains (filename))
663+ return false;
664+
665+ this.filename = filename;
666+ this.precedence = (int) precedence;
667+
668+ var result = parse_file (filename);
669+
670+ if (result)
671+ this.filenames.add (filename);
672+
673+ return result;
674+ }
675+
676+ private int sort_selector_matches (SelectorMatch a, SelectorMatch b) {
677+ int precedence = a.precedence - b.precedence;
678+ if (precedence > 0)
679+ return precedence;
680+ return a.score - b.score;
681+ }
682+
683+
684+ public Gee.HashMap<string, StyleSheetValue?> get_properties (Stylable stylable) {
685+ stdout.printf("this.selectors size=%d\n", this.selectors.size);
686+
687+ var matching_selectors = new Gee.ArrayList<SelectorMatch?> ();
688+
689+
690+ /* find matching selectors */
691+ for (var i = 0; i < this.selectors.size; ++i) {
692+ Selector selector = this.selectors[i];
693+
694+ var score = node_matches_selector (selector, stylable);
695+
696+ stdout.printf("Selector=%s, %s, %s, %s - score=%d", selector.id, selector.type, selector.class, selector.pseudo_class, score);
697+
698+ if (score >= 0) {
699+ var selector_match = SelectorMatch ();
700+ selector_match.id = i;
701+ selector_match.precedence = selector.precedence;
702+ selector_match.score = score;
703+ matching_selectors.add (selector_match);
704+ }
705+ }
706+
707+ /* score the selectors by their score */
708+ matching_selectors.sort ((CompareFunc) sort_selector_matches);
709+
710+ /* get properties from selector's styles */
711+ var result = new Gee.HashMap<string, StyleSheetValue?> (str_hash, str_equal);
712+
713+ foreach (var l in matching_selectors) {
714+ Selector selector = this.selectors[l.id];
715+
716+ foreach (var element in selector.style) {
717+ var style_sheet_value = StyleSheetValue ();
718+ style_sheet_value.source = selector.filename;
719+ style_sheet_value.value = element.value;
720+
721+ result[element.key] = style_sheet_value;
722+ }
723+
724+ }
725+ return result;
726+ }
727+
728+ private int node_matches_selector (Selector selector, Stylable stylable) {
729+ var a = 0;
730+ var b = 0;
731+ var c = 0;
732+
733+ /* get properties for this stylable */
734+ var id = stylable.get_style_id ();
735+ var classes = stylable.get_style_classes ();
736+ var pseudo_classes = stylable.get_style_pseudo_classes ();
737+ var parent = stylable.get_style_container ();
738+
739+ stdout.printf("target=%s (%s), selector=%s (%s)", id, stylable.get_style_type(), selector.id, selector.type);
740+
741+ /* check type */
742+ if (selector.type == null || selector.type[0] == '*') {
743+ /* null or universal selector match, but are ignored for score */
744+ } else {
745+ var type = stylable.get_type ();
746+ var type_name = type.name ();
747+ var matched = 0;
748+ var depth = 10;
749+
750+ while (type_name.len () > 0) {
751+ if (selector.type != type_name) {
752+ matched = depth;
753+ break;
754+ } else {
755+ type = type.parent ();
756+ type_name = type.name ();
757+ if (depth > 1)
758+ depth--;
759+ }
760+ }
761+
762+ if (matched > 0)
763+ return -1;
764+ else
765+ c += depth;
766+ }
767+
768+ /* check id */
769+ if (id == null || selector.id != id)
770+ return -1;
771+ else
772+ a += 10;
773+
774+ /* check psuedo_class */
775+ if (pseudo_classes == null|| !(selector.pseudo_class in pseudo_classes))
776+ return -1;
777+ else
778+ b += 10;
779+
780+ /* check class */
781+ if (classes == null || !(selector.class in classes))
782+ return -1;
783+ else
784+ b += 10;
785+
786+ /* check parent */
787+ if (selector.parent != null) {
788+ if (parent == null)
789+ return -1;
790+
791+ var parent_matches = node_matches_selector (selector.parent, parent);
792+ if (parent_matches < 0)
793+ return -1;
794+
795+ /* increase the 'c' score, since the parent matched */
796+ c += parent_matches;
797+ }
798+
799+ /* check ancestor */
800+ if (selector.ancestor != null) {
801+ if (parent == null)
802+ return -1;
803+
804+ var ancestor = parent;
805+ while (ancestor != null) {
806+ var pparent = ancestor.get_style_container ();
807+
808+ var ancestor_matches = node_matches_selector (selector.ancestor, ancestor);
809+
810+ /* if one of the ancestors match, stop search and increase 'c' score */
811+ if (ancestor_matches >= 0) {
812+ c += ancestor_matches;
813+ break;
814+ }
815+
816+ ancestor = pparent;
817+ if (ancestor == null)
818+ return -1;
819+ }
820+ }
821+ return a * 10000 + b * 100 + c;
822+ }
823+
824+ private bool parse_file (string filename) {
825+ var file = File.new_for_path (filename);
826+
827+ if (!file.query_exists (null)) {
828+ stderr.printf ("File '%s' doesn't exist.\n", file.get_path ());
829+ return false;
830+ }
831+
832+ try {
833+ var in_stream = new DataInputStream (file.read (null));
834+ var data = new StringBuilder ();
835+
836+ string line;
837+
838+ // Read lines until end of file (null) is reached
839+ while ((line = in_stream.read_line (null, null)) != null) {
840+ data.append (line);
841+ }
842+
843+ return parse (data.str);
844+
845+ } catch (Error e) {
846+ error ("%s", e.message);
847+ }
848+ return false;
849+ }
850+
851+
852+ private bool parse (string data) {
853+
854+ this.scanner = new Scanner (null);
855+ this.scanner.config.cpair_comment_single = "\x01\n";
856+ this.scanner.config.cset_identifier_nth = CharacterSet.a_2_z + "-_0123456789" + CharacterSet.A_2_Z + CharacterSet.LATINS + CharacterSet.LATINC;
857+ this.scanner.config.scan_float = false; /* allows scanning '.' */
858+ this.scanner.config.scan_hex = false;
859+ this.scanner.config.scan_string_sq = false;
860+ this.scanner.config.scan_string_dq = false;
861+
862+ this.scanner.input_text (data, (uint) data.len ());
863+
864+ var token = this.scanner.peek_next_token ();
865+ while (token != TokenType.EOF) {
866+ token = parse_block ();
867+
868+ if (token != TokenType.NONE)
869+ break;
870+
871+ token = this.scanner.peek_next_token ();
872+ }
873+
874+ if (token == TokenType.EOF)
875+ return true;
876+ else
877+ this.scanner.unexp_token (token, null, null, null, "Error", true);
878+
879+ return false;
880+ }
881+
882+ private TokenType parse_block () {
883+ Gee.ArrayList<Selector?> list;
884+ var token = parse_ruleset (out list);
885+
886+ if (token != TokenType.NONE)
887+ return token;
888+
889+ /* create a hash table for the properties */
890+ var table = new Gee.HashMap<string, string> (str_hash, direct_equal);
891+ token = parse_style (ref table);
892+
893+ /* assign all the selectors to this style */
894+ foreach (var l in list)
895+ l.style = table;
896+
897+
898+ this.styles.add (table);
899+ this.selectors.add_all (list);
900+
901+ return token;
902+ }
903+
904+ private TokenType parse_ruleset (out Gee.ArrayList<Selector?> selector_list) {
905+ selector_list = new Gee.ArrayList<Selector?> ();
906+
907+ /* parse the first selector, then keep going until we find left curly */
908+ var token = this.scanner.peek_next_token ();
909+
910+ Selector? parent = null;
911+ Selector? selector = null;
912+
913+ while (token != TokenType.LEFT_CURLY) {
914+ stdout.printf("token=%d\n", (int)token);
915+ switch ((int)token) {
916+ case TokenType.IDENTIFIER:
917+ case 42: // '*'
918+ case 35: // '#'
919+ case 46: // '.'
920+ case 58: // ':'
921+ if (selector != null)
922+ parent = selector;
923+ else
924+ parent = null;
925+
926+ /* check if there was a previous selector and if so, the new one
927+ * should use the previous selector to match an ancestor */
928+
929+ selector = Selector ();
930+ selector.filename = this.filename.dup ();
931+ selector.precedence = this.precedence;
932+ selector_list.add (selector);
933+
934+ if (parent != null) {
935+ selector_list.remove (parent);
936+ selector.ancestor = parent;
937+ }
938+
939+ token = parse_simple_selector (ref selector);
940+ if (token != TokenType.NONE)
941+ return token;
942+
943+ break;
944+
945+ case 62: // '>'
946+ this.scanner.get_next_token ();
947+ if (selector == null)
948+ warning ("null parent when parsing '>'");
949+
950+ parent = selector;
951+
952+ selector = Selector ();
953+ selector.filename = this.filename;
954+ selector_list.add (selector);
955+
956+ /* remove parent from list of selectors and link it to the new selector */
957+ selector.parent = parent;
958+ selector_list.remove (parent);
959+
960+ token = parse_simple_selector (ref selector);
961+ if (token != TokenType.NONE)
962+ return token;
963+
964+ break;
965+
966+ case 44: // ','
967+ this.scanner.get_next_token ();
968+
969+ selector = Selector ();
970+ selector.filename = this.filename;
971+ selector_list.add (selector);
972+
973+ token = parse_simple_selector (ref selector);
974+ if (token != TokenType.NONE)
975+ return token;
976+
977+ break;
978+
979+ default:
980+ this.scanner.get_next_token ();
981+ this.scanner.unexp_token (TokenType.ERROR, null, null, null, "Unhandled selector", true);
982+ return TokenType.LEFT_CURLY;
983+ }
984+ token = this.scanner.peek_next_token ();
985+ }
986+
987+ return TokenType.NONE;
988+ }
989+
990+ private TokenType parse_simple_selector (ref Selector selector) {
991+ /* parse optional type (either '*' or an identifier) */
992+ var token = this.scanner.peek_next_token ();
993+ switch ((int) token) {
994+ case 42: // '*'
995+ token = this.scanner.get_next_token ();
996+ selector.type = "*";
997+ break;
998+ case TokenType.IDENTIFIER:
999+ token = this.scanner.get_next_token ();
1000+ selector.type = this.scanner.value.identifier;
1001+ break;
1002+ default:
1003+ break;
1004+ }
1005+
1006+ /* Here we look for '#', '.' or ':' and return if we find anything else */
1007+ token = this.scanner.peek_next_token ();
1008+ while (token != TokenType.NONE) {
1009+ switch ((int) token) {
1010+ /* id */
1011+ case 35: // '#'
1012+ token = this.scanner.get_next_token ();
1013+ token = this.scanner.get_next_token ();
1014+ if (token != TokenType.IDENTIFIER)
1015+ return TokenType.IDENTIFIER;
1016+ selector.id = this.scanner.value.identifier;
1017+ break;
1018+ /* class */
1019+ case 46: // '.'
1020+ token = this.scanner.get_next_token ();
1021+ token = this.scanner.get_next_token ();
1022+ if (token != TokenType.IDENTIFIER)
1023+ return TokenType.IDENTIFIER;
1024+ selector.id = this.scanner.value.identifier;
1025+ break;
1026+ /* pseudo-class */
1027+ case 58: // ':'
1028+ token = this.scanner.get_next_token ();
1029+ token = this.scanner.get_next_token ();
1030+ if (token != TokenType.IDENTIFIER)
1031+ return TokenType.IDENTIFIER;
1032+ selector.id = this.scanner.value.identifier;
1033+ break;
1034+
1035+ /* unhandled */
1036+ default:
1037+ return TokenType.NONE;
1038+ }
1039+ token = this.scanner.peek_next_token ();
1040+ }
1041+ return TokenType.NONE;
1042+ }
1043+
1044+ private TokenType parse_style (ref Gee.HashMap<string, string> table) {
1045+ /* { */
1046+ var token = this.scanner.get_next_token ();
1047+ if (token != TokenType.LEFT_CURLY)
1048+ return TokenType.LEFT_CURLY;
1049+
1050+ /* keep going until we find '}' */
1051+ token = this.scanner.peek_next_token ();
1052+ while (token != TokenType.RIGHT_CURLY) {
1053+ string? key = null;
1054+ string? value = null;
1055+
1056+ token = parse_key_value (out key, out value);
1057+ if (token != TokenType.NONE)
1058+ return token;
1059+
1060+ table[key] = value;
1061+
1062+ token = this.scanner.peek_next_token ();
1063+ }
1064+
1065+ /* } */
1066+ token = this.scanner.get_next_token ();
1067+ if (token != TokenType.RIGHT_CURLY)
1068+ return TokenType.RIGHT_CURLY;
1069+
1070+ return TokenType.NONE;
1071+ }
1072+
1073+ private TokenType parse_key_value (out string? key, out string? value) {
1074+ bool start_with_dash = false;
1075+ string id_first = this.scanner.config.cset_identifier_first;
1076+ string id_nth = this.scanner.config.cset_identifier_nth;
1077+ bool scan_identifier_1char = this.scanner.config.scan_identifier_1char;
1078+
1079+ /* parse property name */
1080+ var token = this.scanner.get_next_token ();
1081+
1082+ /* allow property names to start with '-' */
1083+ if ((char) token == '-') {
1084+ /* FIXME: this will now ignore whitepsace and comments, but this should
1085+ * not be allowed in the middle of a property name! */
1086+ token = this.scanner.get_next_token ();
1087+ start_with_dash = true;
1088+ }
1089+
1090+ if (token != TokenType.IDENTIFIER)
1091+ return TokenType.IDENTIFIER;
1092+
1093+ if (start_with_dash)
1094+ key = "-".concat (this.scanner.value.identifier);
1095+ else
1096+ key = this.scanner.value.identifier;
1097+
1098+ token = this.scanner.get_next_token ();
1099+ if (token != ':')
1100+ return (TokenType) ':';
1101+
1102+ /* value parsing options */
1103+ this.scanner.config.cset_identifier_first = CharacterSet.a_2_z + "#_-0123456789" + CharacterSet.A_2_Z + CharacterSet.LATINS + CharacterSet.LATINC;
1104+ this.scanner.config.cset_identifier_nth = this.scanner.config.cset_identifier_first;
1105+ this.scanner.config.scan_identifier_1char = true;
1106+ this.scanner.config.char_2_token = false;
1107+ this.scanner.config.cset_skip_characters = "\n";
1108+
1109+ /* parse value */
1110+ while (this.scanner.next_value.char != ';') {
1111+ token = this.scanner.get_next_token ();
1112+ switch (token) {
1113+ case TokenType.IDENTIFIER:
1114+ value = value + this.scanner.value.identifier;
1115+ break;
1116+ case TokenType.CHAR:
1117+ var string_builder = new StringBuilder(value);
1118+ string_builder.append_c ((char) this.scanner.value.char);
1119+ value = string_builder.str;
1120+ break;
1121+
1122+ default:
1123+ return (TokenType) ';';
1124+ }
1125+
1126+ token = this.scanner.peek_next_token ();
1127+ }
1128+
1129+ /* semi colon */
1130+ token = this.scanner.get_next_token ();
1131+ if (this.scanner.value.char != ';')
1132+ return (TokenType) ';';
1133+
1134+ /* we've come to the end of the value, so reset the options */
1135+ this.scanner.config.cset_identifier_nth = id_nth;
1136+ this.scanner.config.cset_identifier_first = id_first;
1137+ this.scanner.config.scan_identifier_1char = scan_identifier_1char;
1138+ this.scanner.config.char_2_token = true;
1139+ this.scanner.config.cset_skip_characters = " \t\n";
1140+
1141+ /* strip the leading and trailing whitespace */
1142+ value.strip ();
1143+
1144+ return TokenType.NONE;
1145+ }
1146+ }
1147+ }
1148+}
1149
1150=== modified file 'ctk/text-entry.vala'
1151--- ctk/text-entry.vala 2010-01-14 13:48:18 +0000
1152+++ ctk/text-entry.vala 2010-05-03 20:12:42 +0000
1153@@ -126,11 +126,15 @@
1154 });
1155
1156 this.notify["font-family"].connect(() => {
1157- this._text_actor.font_name = this.font_family + " " + this.font_size.to_string() + "px";
1158+ this._text_actor.font_name = this.get_font_description ();
1159 });
1160
1161 this.notify["font-size"].connect(() => {
1162- this._text_actor.font_name = this.font_family + " " + this.font_size.to_string() + "px";
1163+ this._text_actor.font_name = this.get_font_description ();
1164+ });
1165+
1166+ this.notify["font-weight"].connect(() => {
1167+ this._text_actor.font_name = this.get_font_description ();
1168 });
1169
1170 this.notify["color"].connect(() => {
1171
1172=== modified file 'ctk/widget.vala'
1173--- ctk/widget.vala 2010-01-23 19:34:51 +0000
1174+++ ctk/widget.vala 2010-05-03 20:12:42 +0000
1175@@ -4,6 +4,7 @@
1176 * A Clutter UI toolkit
1177 *
1178 * Copyright (C) 2009 Ali Sabil
1179+* Copyright (C) 2010 Thomas Kristensen
1180 *
1181 * This library is free software; you can redistribute it and/or
1182 * modify it under the terms of the GNU Lesser General Public
1183@@ -18,8 +19,8 @@
1184 * You should have received a copy of the GNU Lesser General Public
1185 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
1186 *
1187-* Author:
1188-* Ali Sabil <ali.sabil@gmail.com>
1189+* Author: Ali Sabil <ali.sabil@gmail.com>
1190+* Thomas Kristensen <thomas.k.kristensen@tandberg.com>
1191 *
1192 */
1193
1194@@ -108,6 +109,21 @@
1195 private uint _font_size = 12;
1196
1197 [CCode(notify = false)]
1198+ public FontWeight font_weight {
1199+ get {
1200+ return this._font_weight;
1201+ }
1202+ set {
1203+ if (this._font_weight != value) {
1204+ this._font_weight = value;
1205+ this.pending_relayout = true;
1206+ this.notify_property ("font-weight");
1207+ }
1208+ }
1209+ }
1210+ private FontWeight _font_weight = FontWeight.NORMAL;
1211+
1212+ [CCode(notify = false)]
1213 public Padding padding {
1214 get {
1215 return this.children_container.padding;
1216@@ -338,6 +354,7 @@
1217 this.get_property_from_style ("color");
1218 this.get_property_from_style ("font-family");
1219 this.get_property_from_style ("font-size");
1220+ this.get_property_from_style ("font-weight");
1221 this.get_property_from_style ("opacity");
1222 this.get_property_from_style ("padding");
1223 this.get_property_from_style ("border-image");
1224@@ -388,14 +405,43 @@
1225 return ((Object) this).get_type().name();
1226 }
1227
1228- [CCode (array_length = false, array_null_terminated = true)]
1229- public string[]? get_style_classes () {
1230- return (string[]) this.style_classes.to_array ();
1231- }
1232-
1233- [CCode (array_length = false, array_null_terminated = true)]
1234- public string[]? get_style_pseudo_classes () {
1235- return (string[]) this.style_pseudo_classes.to_array ();
1236- }
1237+ public Gee.Set<string> get_style_classes () {
1238+ return this.style_classes.read_only_view;
1239+ }
1240+
1241+ public Gee.Set<string> get_style_pseudo_classes () {
1242+ return this.style_pseudo_classes.read_only_view;
1243+ }
1244+
1245+ /* Utilities */
1246+
1247+ public string get_font_description () {
1248+ var font_description = new Pango.FontDescription ();
1249+
1250+ font_description.set_family (this.font_family);
1251+ font_description.set_absolute_size (this.font_size * 1024 /* PANGO_SCALE */);
1252+
1253+ var weight = Pango.Weight.NORMAL;
1254+ switch (this.font_weight) {
1255+ case FontWeight.BOLD:
1256+ weight = Pango.Weight.BOLD;
1257+ break;
1258+ case FontWeight.LIGHTER:
1259+ weight = Pango.Weight.LIGHT;
1260+ break;
1261+ case FontWeight.BOLDER:
1262+ weight = Pango.Weight.HEAVY;
1263+ break;
1264+ default:
1265+ weight = Pango.Weight.NORMAL;
1266+ break;
1267+ }
1268+
1269+ font_description.set_weight (weight);
1270+
1271+ var description_string = font_description.to_string ();
1272+ return description_string;
1273+ }
1274+
1275 }
1276 }

Subscribers

People subscribed via source and target branches

to all changes: