The Birdfont Source Code


All Repositories / birdfont.git / commit – RSS feed

Bird UI - a new GUI toolkit based on SVG components

These changes was commited to the Birdfont repository Thu, 14 Jan 2016 18:38:02 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
author Johan Mattsson <johan.mattsson.m@gmail.com>
Thu, 14 Jan 2016 18:38:02 +0000 (19:38 +0100)
committer Johan Mattsson <johan.mattsson.m@gmail.com>
Thu, 14 Jan 2016 18:38:02 +0000 (19:38 +0100)
commit 46f109983f33587c994679ab3776cb0cfdd65d8f
tree dfc7ddd02c712d2d3390235b4a72352a84da7b25
parent 28688639b00f763e8ef518eeeafc1a56c1089619
Bird UI - a new GUI toolkit based on SVG components

26 files changed:
birdfont/GtkWindow.vala
birdfont/Main.vala
birdui/AbsoluteLayout.vala [new ]
birdui/BoxLayout.vala [new ]
birdui/Component.vala [new ]
birdui/GtkWidget.vala [new ]
birdui/GtkWindow.vala [new ]
birdui/HBox.vala [new ]
birdui/Style.vala [new ]
birdui/SvgComponent.vala [new ]
birdui/VBox.vala [new ]
dodo.py
libsvgbird/AttributePattern.vala
libsvgbird/Color.vala
libsvgbird/Defs.vala
libsvgbird/Object.vala
libsvgbird/Points.vala
libsvgbird/Selector.vala
libsvgbird/SelectorPattern.vala
libsvgbird/SelectorTag.vala
libsvgbird/StyleSheet.vala
libsvgbird/SvgArc.vala
libsvgbird/SvgFile.vala
libsvgbird/SvgPath.vala
libsvgbird/SvgStyle.vala
--- a/birdfont/GtkWindow.vala +++ b/birdfont/GtkWindow.vala @@ -51,8 +51,6 @@ Entry text_entry; Box text_box; Gtk.Button submit_text_button; - - Gtk.Window tooltip_window = new Gtk.Window (); ToolboxCanvas toolbox; @@ -112,12 +110,7 @@ uri = Preview.get_uri (); html = Preview.get_html_with_absolute_paths (); - try { - html_canvas.load_html_string (html, uri); - } catch (Error e) { - warning (e.message); - warning ("Failed to load html into canvas."); - } + html_canvas.load_html_string (html, uri); // show the webview when loading has finished html_box.set_visible (true);
--- a/birdfont/Main.vala +++ b/birdfont/Main.vala @@ -32,7 +32,7 @@ window.set_native (native_window); native_window.init (); - birdfont.load_font_from_command_line (); + BirdFont.BirdFont.load_font_from_command_line (); Gtk.main (); return 0;
diff --git birdui/AbsoluteLayout.vala(new)
--- /dev/null +++ b/birdui/AbsoluteLayout.vala @@ -1,1 +1,36 @@ + /* + Copyright (C) 2016 Johan Mattsson + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + */ + + using Gee; + using SvgBird; + using B; + + namespace Bird { + + class AbsoluteLayout : Component { + + public AbsoluteLayout () { + } + + public AbsoluteLayout.for_tag (XmlElement layout_tag) { + parse (layout_tag); + } + + public override string to_string () { + return "AbsoluteLayout"; + } + } + + }
diff --git birdui/BoxLayout.vala(new)
--- /dev/null +++ b/birdui/BoxLayout.vala @@ -1,1 +1,95 @@ + /* + Copyright (C) 2016 Johan Mattsson + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + */ + + using Gee; + using SvgBird; + using B; + + namespace Bird { + + public enum BoxOrientation { + HORIZONTAL, + VERTICAL + } + + class BoxLayout : Component { + + public BoxOrientation orientation { get; private set; } + + public BoxLayout (BoxOrientation orientation) { + base (); + this.orientation = orientation; + } + + public BoxLayout.for_tag (XmlElement layout_tag, BoxOrientation orientation) { + base.for_tag (layout_tag); + this.orientation = orientation; + } + + public override void layout () { + switch (orientation) { + case BoxOrientation.HORIZONTAL: + layout_horizontal (); + break; + case BoxOrientation.VERTICAL: + layout_vertical (); + break; + } + } + + void layout_horizontal () { + double child_x = 0; + double child_y = 0; + + foreach (Component component in components) { + component.x = child_x; + component.y = child_y; + component.layout (); + child_x += component.padded_width; + + if (component.height > height) { + height = component.height; + } + } + + width = child_x; + } + + void layout_vertical () { + double child_x = 0; + double child_y = 0; + + foreach (Component component in components) { + component.x = child_x; + component.y = child_y; + component.layout (); + component.apply_padding (); + + child_y += component.padded_height; + + if (component.width > width) { + width = component.width; + } + } + + height = child_y; + } + + public override string to_string () { + return "BoxLayout"; + } + } + + }
diff --git birdui/Component.vala(new)
--- /dev/null +++ b/birdui/Component.vala @@ -1,1 +1,292 @@ + /* + Copyright (C) 2016 Johan Mattsson + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + */ + + using B; + using SvgBird; + using Gee; + using Cairo; + + namespace Bird { + + class Component : GLib.Object { + public double width { get; protected set; } + public double height { get; protected set; } + + public double padded_width { + get { + return width + get_padding_top () + get_padding_bottom (); + } + } + + public double padded_height { + get { + return height + get_padding_left () + get_padding_right (); + } + } + + /** Vertical placement for this component relative to the parent container. */ + public double x { get; protected set; } + + /** Horizontal placement for this component relative to the parent container. */ + public double y { get; protected set; } + + /** The parts this component is made of. */ + protected ArrayList<Component> components = new ArrayList<Component> (); + + XmlElement? component_tag = null; + + /** Style sheet and other SVG definitions. */ + Defs? defs = null; + SvgStyle style = new SvgStyle (); + + string? css_class = null; + string? id = null; + + public Component () { + } + + public Component.for_tag (XmlElement component_tag) { + this.component_tag = component_tag; + parse (component_tag); + } + + private void inherit_style (Defs? defs) { + this.defs = defs; + } + + protected void apply_padding () { + } + + protected void load_svg_file (string file_name) { + SvgComponent svg = new SvgComponent.for_file (file_name); + add_component (svg); + } + + protected void parse_style (XmlElement style_tag) { + Defs definitions = new Defs (); + StyleSheet style_sheet = StyleSheet.parse (definitions, style_tag); + + if (defs != null) { + Defs subscope_definitions = ((!) defs).shallow_copy (); + subscope_definitions.style_sheet.merge (style_sheet); + } else { + defs = definitions; + } + } + + protected void parse_svg (XmlElement svg_tag) { + foreach (Attribute attribute in svg_tag.get_attributes ()) { + string attribute_name = attribute.get_name (); + + if (attribute_name == "file") { + load_svg_file (attribute.get_content ()); + } + } + } + + protected void add_component (Component component) { + components.add (component); + component.inherit_style (defs); + + if (component.component_tag != null) { + style = SvgStyle.parse (defs, style, (!) component.component_tag); + } + } + + protected void parse_layout (XmlElement layout_tag) { + foreach (Attribute attribute in layout_tag.get_attributes ()) { + string attribute_name = attribute.get_name (); + + if (attribute_name == "type") { + if (attribute.get_content () == "hbox") { + HBox hbox = new HBox.for_tag (layout_tag); + add_component (hbox); + } else if (attribute.get_content () == "vbox") { + VBox hbox = new VBox.for_tag (layout_tag); + add_component (hbox); + } else { + warning ("Layout of type " + attribute.get_content () + + " is not implemented in this verison."); + } + } else if (attribute_name == "id") { + id = attribute.get_content (); + } else if (attribute_name == "class") { + css_class = attribute.get_content (); + } else if (attribute_name == "style") { + // style will be parsed later + } else { + unused_attribute (attribute_name); + } + } + } + + protected void parse_component (XmlElement component_tag) { + foreach (Attribute attribute in component_tag.get_attributes ()) { + string attribute_name = attribute.get_name (); + + if (attribute_name == "file") { + Component component = new Component (); + component.load (attribute.get_content ()); + add_component (component); + } else { + unused_attribute (attribute_name); + } + } + } + + protected void parse (XmlElement component_tag) { + foreach (XmlElement tag in component_tag) { + string tag_name = tag.get_name (); + + if (tag_name == "ui") { + parse (tag); + } else if (tag_name == "layout") { + parse_layout (tag); + } else if (tag_name == "component") { + parse_component (tag); + } else if (tag_name == "svg") { + parse_svg (tag); + } else if (tag_name == "style") { + parse_style (tag); + } else { + unused_tag (tag_name); + } + } + } + + internal void unused_attribute (string attribute) { + warning ("The attribute " + attribute + " is not known in this version."); + } + + internal void unused_tag (string tag_name) { + warning ("The tag " + tag_name + " is not known in this version."); + } + + public void load (string file_name) { + if (file_name.has_suffix (".ui")) { + load_layout (file_name); + } else if (file_name.has_suffix (".svg")) { + load_svg_file (file_name); + } else { + warning (file_name + " is not a ui file or svg file."); + } + } + + public void load_layout (string file_name) { + string? path = find_file (file_name); + + if (path == null) { + warning (file_name + " not found."); + return; + } + + string xml_data; + File layout_file = File.new_for_path ((!) path); + + try { + FileUtils.get_contents((!) layout_file.get_path (), out xml_data); + } catch (GLib.Error error) { + warning (error.message); + return; + } + + XmlTree xml_parser = new XmlTree (xml_data); + Component component = new Component.for_tag (xml_parser.get_root ()); + add_component (component); + layout (); + } + + public static string find_file (string file_name) { + File file = File.new_for_path ("birdui/" + file_name); + + if (file.query_exists ()) { + return (!) file.get_path (); + } + + return file_name; + } + + public virtual void layout () { + if (unlikely (components.size > 1)) { + warning ("A component has several parts but no layout has been set."); + } + + foreach (Component component in components) { + component.layout (); + width = component.width; + height = component.height; + } + } + + public virtual void draw (Context cairo) { + foreach (Component component in components) { + cairo.save (); + cairo.translate (component.x, component.y); + component.draw (cairo); + cairo.restore (); + } + } + + public virtual void motion_notify_event (double x, double y) { + } + + public virtual void button_press_event (uint button, double x, double y) { + } + + public virtual string to_string () { + if (component_tag != null) { + XmlElement tag = (!) component_tag; + return @"Component $(tag.get_name ())"; + } else { + + return "Component"; + } + } + + public void print_tree () { + print_tree_level (0); + } + + protected void print_tree_level (int indent) { + for (int i = 0; i < indent; i++) { + print ("\t"); + } + + print (@"$(to_string ()), x: $x, y: $y, w: $width, h: $height\n"); + + foreach (Component component in components) { + component.print_tree_level (indent + 1); + } + } + + double get_padding_bottom () { + return SvgFile.parse_number (style.get_css_property ("padding-bottom")); + } + + double get_padding_top () { + return SvgFile.parse_number (style.get_css_property ("padding-top")); + } + + double get_padding_left () { + return SvgFile.parse_number (style.get_css_property ("padding-left")); + } + + double get_padding_right () { + return SvgFile.parse_number (style.get_css_property ("padding-right")); + } + } + + } +
diff --git birdui/GtkWidget.vala(new)
--- /dev/null +++ b/birdui/GtkWidget.vala @@ -1,1 +1,52 @@ + /* + Copyright (C) 2016 Johan Mattsson + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + */ + + using Gtk; + using Gdk; + using Cairo; + + namespace Bird { + + class Widget : DrawingArea { + + Component component; + + public Widget (Component main_component) { + component = main_component; + + add_events (EventMask.BUTTON_PRESS_MASK + | EventMask.POINTER_MOTION_MASK + | EventMask.LEAVE_NOTIFY_MASK); + + motion_notify_event.connect ((event)=> { + component.motion_notify_event (event.x, event.y); + return true; + }); + + button_press_event.connect ((event)=> { + component.button_press_event (event.button, event.x, event.y); + return true; + }); + + draw.connect ((event) => { + Context cairo_context = cairo_create (get_window ()); + component.draw (cairo_context); + return true; + }); + } + + } + + }
diff --git birdui/GtkWindow.vala(new)
--- /dev/null +++ b/birdui/GtkWindow.vala @@ -1,1 +1,39 @@ + /* + Copyright (C) 2016 Johan Mattsson + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + */ + + using Bird; + using Gtk; + + int main (string[] args) { + Gtk.init (ref args); + + Window window = new Window (); + window.set_title ("UI Bird"); + window.destroy.connect (Gtk.main_quit); + + Component layout = new Component (); + layout.load ("test.ui"); + + Bird.Widget primary_layout = new Bird.Widget (layout); + + Box vbox = new Box (Orientation.VERTICAL, 0); + vbox.pack_start(primary_layout, true, true, 0); + window.add (vbox); + + window.show_all (); + + Gtk.main (); + return 0; + }
diff --git birdui/HBox.vala(new)
--- /dev/null +++ b/birdui/HBox.vala @@ -1,1 +1,35 @@ + /* + Copyright (C) 2016 Johan Mattsson + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + */ + + using Gee; + using B; + + namespace Bird { + + class HBox : BoxLayout { + public HBox () { + base (BoxOrientation.HORIZONTAL); + } + + public HBox.for_tag (XmlElement layout) { + base.for_tag (layout, BoxOrientation.HORIZONTAL); + } + + public override string to_string () { + return "HBox"; + } + } + + }
diff --git birdui/Style.vala(new)
--- /dev/null +++ b/birdui/Style.vala @@ -1,1 +1,35 @@ + /* + Copyright (C) 2016 Johan Mattsson + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + */ + + using B; + using SvgBird; + using Gee; + using Cairo; + + namespace Bird { + + public class Style : GLib.Object { + public SvgStyle svg_style; + + public Style () { + svg_style = new SvgStyle (); + } + + public Style.for_svg (SvgStyle svg_style) { + this.svg_style = svg_style; + } + } + + }
diff --git birdui/SvgComponent.vala(new)
--- /dev/null +++ b/birdui/SvgComponent.vala @@ -1,1 +1,89 @@ + /* + Copyright (C) 2016 Johan Mattsson + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + */ + + using B; + using SvgBird; + using Gee; + using Cairo; + + namespace Bird { + + class SvgComponent : Component { + string? path = null; + string file_name = ""; + SvgDrawing? drawing = null; + + public SvgComponent () { + base (); + } + + public SvgComponent.for_tag (XmlElement svg_component_tag) { + base (); + } + + public SvgComponent.for_file (string svg_file) { + base (); + load_svg (svg_file); + } + + public override void layout () { + if (unlikely (components.size > 0)) { + warning ("SVG files can not have subviews."); + } + + if (drawing != null) { + SvgDrawing svg = (!) drawing; + width = svg.width; + height = svg.height; + } + } + + public override string to_string () { + return "Svg: " + file_name; + } + + private void load_svg (string file_name) { + this.file_name = file_name; + path = find_file (file_name); + + if (path == null) { + warning (file_name + " not found."); + return; + } + + string xml_data; + File svg_file = File.new_for_path ((!) path); + try { + FileUtils.get_contents((!) svg_file.get_path (), out xml_data); + } catch (GLib.Error error) { + warning (error.message); + return; + } + + SvgFile svg_parser = new SvgFile (); + drawing = svg_parser.parse_svg_data (xml_data); + } + + public override void draw (Context cairo) { + if (drawing != null) { + SvgDrawing svg = (!) drawing; + svg.draw (cairo); + } + } + + } + + } +
diff --git birdui/VBox.vala(new)
--- /dev/null +++ b/birdui/VBox.vala @@ -1,1 +1,36 @@ + /* + Copyright (C) 2016 Johan Mattsson + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + */ + + using Gee; + using B; + + namespace Bird { + + class VBox : BoxLayout { + public VBox () { + base (BoxOrientation.VERTICAL); + } + + public VBox.for_tag (XmlElement layout) { + base.for_tag (layout, BoxOrientation.VERTICAL); + } + + public override string to_string () { + return "VBox"; + } + + } + + }
diff --git a/dodo.py b/dodo.py
--- a/dodo.py +++ b/dodo.py @@ -559,5 +559,56 @@ def task_birdfont_test(): yield make_birdfont_test('birdfont-test', ['libbirdgems.so', 'libbirdfont.so']) + def make_birdui(target_binary, deps): + valac_command = config.VALAC + """\ + -C \ + --pkg posix \ + --pkg """ + config.GEE + """ \ + --pkg gtk+-3.0 \ + --pkg libsvgbird \ + --pkg xmlbird \ + --vapidir=./ \ + --basedir=build/birdui/ \ + """ + config.NON_NULL + """ \ + --enable-experimental \ + birdui/*.vala \ + """ + cc_command = config.CC + """ \ + -fPIC \ + $(pkg-config --cflags gtk+-3.0) \ + $(pkg-config --cflags glib-2.0) \ + $(pkg-config --cflags xmlbird) \ + $(pkg-config --cflags """ + config.GEE + """) \ + -g \ + -I ./build/libsvgbird \ + -c C_SOURCE \ + -o OBJECT_FILE \ + """ + + linker_command = config.CC + """ \ + """ + soname(target_binary) + """ \ + -fPIC \ + -g \ + build/birdui/*.o \ + $(pkg-config --libs gtk+-3.0) \ + $(pkg-config --libs glib-2.0) \ + $(pkg-config --libs gobject-2.0) \ + $(pkg-config --libs xmlbird) \ + $(pkg-config --libs """ + config.GEE + """) \ + -L ./build/bin -l svgbird \ + -o build/bin/""" + target_binary + + libbirdgems = Builder('birdui', + valac_command, + cc_command, + linker_command, + target_binary, + None, + deps) + + yield libbirdgems.build() + + def task_birdui(): + yield make_birdui('birdui', [])
--- a/libsvgbird/AttributePattern.vala +++ b/libsvgbird/AttributePattern.vala @@ -29,6 +29,14 @@ public string name = ""; public string? content = null; public AttributePatternType type = AttributePatternType.NONE; + + public AttributePattern copy () { + AttributePattern a = new AttributePattern (); + a.name = name; + a.content = content; + a.type = type; + return a; + } public bool match (Attributes attributes) { switch (type) {
--- a/libsvgbird/Color.vala +++ b/libsvgbird/Color.vala @@ -95,9 +95,9 @@ public string to_rgb_hex () { StringBuilder rgb = new StringBuilder (); rgb.append ("#"); - rgb.append_printf ("%x", (int) Math.rint (r * 254)); - rgb.append_printf ("%x", (int) Math.rint (g * 254)); - rgb.append_printf ("%x", (int) Math.rint (b * 254)); + rgb.append_printf ("%02x", (int) Math.rint (r * 254)); + rgb.append_printf ("%02x", (int) Math.rint (g * 254)); + rgb.append_printf ("%02x", (int) Math.rint (b * 254)); return rgb.str; } @@ -107,7 +107,6 @@ rgba.append_printf ("%x", (int) Math.rint (a * 254)); return rgba.str; } - public Color copy () { return new Color (r, g, b, a);
--- a/libsvgbird/Defs.vala +++ b/libsvgbird/Defs.vala @@ -81,17 +81,30 @@ return ((!) attribute).has_prefix ("url"); } - public Defs copy () { + public Defs shallow_copy () { Defs d = new Defs (); foreach (Gradient g in gradients) { d.add (g); } + + d.style_sheet = style_sheet.shallow_copy (); return d; } + public Defs copy () { + Defs d = new Defs (); + + foreach (Gradient g in gradients) { + d.add (g.copy ()); + } + + d.style_sheet = style_sheet.copy (); + + return d; + } } }
--- a/libsvgbird/Object.vala +++ b/libsvgbird/Object.vala @@ -91,7 +91,7 @@ bool need_stroke = style.stroke_gradient != null || style.stroke != null; cr.set_line_width (style.stroke_width); - + if (style.fill_gradient != null) { apply_gradient (cr, (!) style.fill_gradient); } else if (style.fill != null) {
--- a/libsvgbird/Points.vala +++ b/libsvgbird/Points.vala @@ -21,7 +21,12 @@ public double x = 0; public double y = 0; public bool closed = false; - + public int size { + get { + return point_data.size; + } + } + public void add (double p) { point_data.add (p); }
--- a/libsvgbird/Selector.vala +++ b/libsvgbird/Selector.vala @@ -19,11 +19,10 @@ public class Selector : GLib.Object { - Gee.ArrayList<SelectorPattern> patterns; + Gee.ArrayList<SelectorPattern> patterns = new Gee.ArrayList<SelectorPattern> (); public SvgStyle style { get; set; } public Selector (string pattern, SvgStyle style) { - this.patterns = new Gee.ArrayList<SelectorPattern> (); string[] selector_patterns = pattern.split (","); for (int i = 0; i < selector_patterns.length; i++) { @@ -31,6 +30,18 @@ } this.style = style; + } + + public Selector.copy_constructor (Selector selector) { + style = selector.style.copy (); + + foreach (SelectorPattern pattern in selector.patterns) { + selector.patterns.add (pattern.copy ()); + } + } + + public Selector copy () { + return new Selector.copy_constructor (this); } public bool match (XmlElement tag, string? id, string? css_class) {
--- a/libsvgbird/SelectorPattern.vala +++ b/libsvgbird/SelectorPattern.vala @@ -19,18 +19,30 @@ /** A CSS selector pattern. */ public class SelectorPattern : GLib.Object { - Gee.ArrayList<SelectorTag> tags; + Gee.ArrayList<SelectorTag> tags = new Gee.ArrayList<SelectorTag> (); + public SelectorPattern.empty () { + } + public SelectorPattern (string pattern) { string p = pattern.strip (); string[] elements = p.split (" "); - tags = new Gee.ArrayList<SelectorTag> (); - + foreach (string element in elements) { if (element != "") { tags.add (new SelectorTag (element)); } } + } + + public SelectorPattern copy () { + SelectorPattern pattern = new SelectorPattern.empty (); + + foreach (SelectorTag tag in tags) { + pattern.tags.add (tag.copy ()); + } + + return pattern; } public bool match (XmlElement tag, string? id, string? css_class) { @@ -39,6 +51,7 @@ if (pattern.name == ">") { if (i - 1 < 0) { + return false; }
--- a/libsvgbird/SelectorTag.vala +++ b/libsvgbird/SelectorTag.vala @@ -24,6 +24,9 @@ string? css_class = null; Gee.ArrayList<AttributePattern>? attribute_patterns = null; + public SelectorTag.empty () { + } + public SelectorTag (string pattern) { string tag_pattern = pattern.strip (); int id_separator = tag_pattern.index_of ("#"); @@ -61,6 +64,22 @@ } } + public SelectorTag copy () { + SelectorTag tag = new SelectorTag.empty(); + + tag.name = name; + tag.id = id; + tag.css_class = css_class; + + if (attribute_patterns != null) { + foreach (AttributePattern p in (!) attribute_patterns) { + ((!) attribute_patterns).add (p.copy ()); + } + } + + return tag; + } + void parse_attributes (string attributes) { int index = 0; Gee.ArrayList<AttributePattern> patterns = new Gee.ArrayList<AttributePattern> (); @@ -139,7 +158,6 @@ } if (((!) this.css_class) != ((!) css_class)) { - print(@"class \"$((!)this.css_class)\"=\"$((!)css_class)\"\n"); return false; } }
--- a/libsvgbird/StyleSheet.vala +++ b/libsvgbird/StyleSheet.vala @@ -16,6 +16,7 @@ using Math; namespace SvgBird { + public class StyleSheet : GLib.Object { @@ -23,6 +24,27 @@ public StyleSheet () { styles = new Gee.ArrayList<Selector> (); + } + + /** Copy references to all selectors in this style sheet. */ + public StyleSheet shallow_copy () { + StyleSheet style_sheet = new StyleSheet (); + + foreach (Selector selector in styles) { + style_sheet.styles.add (selector); + } + + return style_sheet; + } + + public StyleSheet copy () { + StyleSheet style_sheet = new StyleSheet (); + + foreach (Selector selector in styles) { + style_sheet.styles.add (selector.copy ()); + } + + return style_sheet; } public void inherit_style (XmlElement tag, SvgStyle style) { @@ -43,6 +65,12 @@ if (selector.match (tag, id, css_class)) { style.inherit (selector.style); } + } + } + + public void merge (StyleSheet style_sheet) { + foreach (Selector selector in style_sheet.styles) { + styles.add (selector); } }
--- a/libsvgbird/SvgArc.vala +++ b/libsvgbird/SvgArc.vala @@ -138,9 +138,6 @@ } else if (sweepFlag && angleExtent < 0) { angleExtent += 2 * PI; } - - //center_x = cx - rx; - //center_y = cy - ry; center_x = cx; center_y = cy; @@ -150,11 +147,9 @@ angle_start = angleStart; angle_extent = angleExtent; - - print (@"angleStart: $angle_start angleExtent $angle_extent\n"); } }
--- a/libsvgbird/SvgFile.vala +++ b/libsvgbird/SvgFile.vala @@ -23,6 +23,11 @@ SvgDrawing drawing; public SvgFile () { + } + + public SvgDrawing parse_svg_data (string xml_data) { + XmlTree tree = new XmlTree (xml_data); + return parse_svg_file (tree.get_root ()); } public SvgDrawing parse_svg_file (XmlElement svg_tag) { @@ -43,7 +48,7 @@ foreach (XmlElement t in svg_tag) { string name = t.get_name (); - + if (name == "g") { parse_layer (drawing.root_layer, style, t); } @@ -642,8 +647,19 @@ for (int i = 0; i < points_size; i++) { // FIXME: add more types if (bezier_points[i].type == 'M') { - points.x = bezier_points[i].x0; - points.y = bezier_points[i].y0; + if (i == 0) { + points.x = bezier_points[i].x0; + points.y = bezier_points[i].y0; + } else { + points.add_type (LINE); + points.add (bezier_points[i].x0); + points.add (bezier_points[i].y0); + points.add (0); + points.add (0); + points.add (0); + points.add (0); + points.add (0); + } } else if (bezier_points[i].type == 'C') { points.add_type (CUBIC); points.add (bezier_points[i].x0); @@ -694,10 +710,10 @@ } } - if (points.point_data.size > 0) { + if (points.size > 0) { path_data.add (points); } - + return path_data; }
--- a/libsvgbird/SvgPath.vala +++ b/libsvgbird/SvgPath.vala @@ -70,7 +70,6 @@ case LINE: cr.line_to (points[i + 1].value, points[i + 2].value); break; - } } }
--- a/libsvgbird/SvgStyle.vala +++ b/libsvgbird/SvgStyle.vala @@ -34,6 +34,16 @@ public SvgStyle.for_properties (Defs? defs, string style) { parse_key_value_pairs (style); set_style_properties (defs, this); + } + + public string? get_css_property (string key) { + return style.get (key); + } + + public SvgStyle copy () { + SvgStyle style = new SvgStyle (); + style.inherit (this); + return style; } public LineCap get_line_cap () { @@ -169,11 +179,35 @@ k = pair[0].strip (); v = pair[1].strip (); - style.set (k, v); + if (k == "padding") { + parse_padding_shorthand (v); + } else { + style.set (k, v); + } } + } + } + + void parse_padding_shorthand (string arguments) { + string[] args = StyleSheet.replace_whitespace (arguments).split (" "); + + if (args.length > 0) { + style.set ("padding-top", args[0]); + } + + if (args.length > 1) { + style.set ("padding-right", args[1]); + } + + if (args.length > 2) { + style.set ("padding-bottom", args[2]); + } + + if (args.length > 3) { + style.set ("padding-left", args[3]); } } } }