Commit f17b819
Fix layout containers
Changed files (20)
deletedbirdui/AbsoluteLayout.valamodifiedbirdui/BoxLayout.valamodifiedbirdui/Component.valamodifiedbirdui/GtkWidget.valamodifiedbirdui/GtkWindow.valamodifiedbirdui/SvgComponent.valamodifiedlibbirdfont/BirdFontFile.valamodifiedlibbirdfont/DrawingTools.valamodifiedlibbirdfont/Glyph.valamodifiedlibbirdfont/LayerUtils.valamodifiedlibbirdfont/SvgParser.valamodifiedlibsvgbird/Layer.valamodifiedlibsvgbird/Object.valamodifiedlibsvgbird/ObjectGroup.valamodifiedlibsvgbird/PointValue.valamodifiedlibsvgbird/SvgDrawing.valamodifiedlibsvgbird/SvgFile.valamodifiedlibsvgbird/SvgPath.valamodifiedlibsvgbird/SvgTransform.valamodifiedlibsvgbird/SvgTransforms.vala
Diff
deleted file mode 100644@@ -1,32 +0,0 @@-/*- 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 (XmlElement layout_tag, Defs defs) {- base (layout_tag, defs);- }-- public override string to_string () {- return "AbsoluteLayout";- }-}--}@@ -15,6 +15,7 @@ using Gee; using SvgBird; using B;+using Cairo; namespace Bird { @@ -31,75 +32,179 @@ class BoxLayout : Component { base (layout_tag, defs); this.orientation = orientation; }- - void set_size_limits (Component component) {- string? min_width = component.style.get_css_property ("min-width");- if (min_width != null) {- double w = SvgFile.parse_number (min_width);- if (component.width < w) {- component.width = w;- }++ public override void draw (Context cairo) {+ cairo.save ();+ cairo.translate (padded_x, padded_y);+ clip (cairo);+ + foreach (Component component in components) {+ component.draw (cairo); } - string? min_height = component.style.get_css_property ("min-height");- if (min_height != null) {- double h = SvgFile.parse_number (min_height);+ cairo.restore ();+ } - if (component.height < h) {- component.height = h;+ bool is_width_remainder (Component component) {+ return component.style.property_equals ("width", "remainder");+ }++ bool is_height_remainder (Component component) {+ return component.style.property_equals ("height", "remainder");+ }++ /** The smallest size this layout can be. */+ public override void get_min_size (out double min_width, out double min_height) {+ min_width = 0;+ min_height = 0;+ + if (orientation == BoxOrientation.HORIZONTAL) {+ foreach (Component component in components) {+ double w, h;+ + component.get_min_size (out w, out h);+ min_width += w;+ + if (h > min_height) {+ min_height = h;+ }+ } + } else {+ foreach (Component component in components) {+ double w, h;+ + component.get_min_size (out w, out h); + min_height += h;+ + if (w > min_width) {+ min_width = w;+ } } } - string? max_width = component.style.get_css_property ("max-width");- if (max_width != null) {- double w = SvgFile.parse_number (max_width);+ min_width += get_padding_left ();+ min_width += get_padding_right ();+ min_height += get_padding_top ();+ min_height += get_padding_bottom ();+ + limit_size (ref min_width, ref min_height);+ }++ public override void layout (double parent_width, double parent_height) {+ double w, h;+ + get_min_size (out w, out h);+ int remainders = count_remainders ();+ + if (!is_width_remainder (this)) {+ width = w;+ }+ + if (!is_height_remainder (this)) {+ height = h;+ }+ + if (remainders > 0) {+ double remainder_size; - if (component.width > w) {- component.width = w;+ if (orientation == BoxOrientation.HORIZONTAL) {+ remainder_size = (parent_width - w) / remainders;+ layout_variable_size (remainder_size, parent_height);+ } else {+ remainder_size = (parent_height - h) / remainders;+ layout_variable_size (remainder_size, parent_width); } }-- string? max_height = component.style.get_css_property ("max-height");- if (max_height != null) {- double h = SvgFile.parse_number (max_height);+ + if (orientation == BoxOrientation.HORIZONTAL) {+ foreach (Component component in components) {+ component.layout (parent_width, h);+ }+ } else {+ foreach (Component component in components) {+ component.layout (w, parent_height);+ }+ }+ + layout_positions ();+ }+ + int count_remainders () {+ int remainders = 0;+ + if (orientation == BoxOrientation.HORIZONTAL) {+ foreach (Component component in components) {+ if (is_width_remainder (component)) {+ remainders++;+ }+ }+ } else {+ foreach (Component component in components) {+ if (is_height_remainder (component)) {+ remainders++;+ }+ }+ }+ + return remainders;+ }+ + void layout_variable_size (double remainder_size, double fixed_size) {+ double w, h;+ + w = 0;+ h = 0;+ foreach (Component component in components) {+ bool width_remainder = is_width_remainder (component);+ bool height_remainder = is_height_remainder (component);+ + if (width_remainder && orientation == BoxOrientation.HORIZONTAL) {+ w = remainder_size;+ w -= component.get_padding_left ();+ w -= component.get_padding_right ();+ h = fixed_size;+ }+ + if (height_remainder && orientation == BoxOrientation.VERTICAL) {+ w = fixed_size;+ h = remainder_size;+ h -= component.get_padding_top ();+ h -= component.get_padding_bottom ();+ } - if (component.height > h) {+ if (width_remainder || height_remainder) {+ double min_width, min_height;+ component.get_min_size (out min_width, out min_height);+ + if (w < min_width) {+ w = min_width;+ }+ + if (h < min_height) {+ h = min_height;+ }+ + component.limit_size (ref w, ref h);+ component.width = w; component.height = h; } } }- - public override void layout () {++ void layout_positions () { 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 ();- set_size_limits (component);+ component.x = child_x + component.get_padding_left ();+ component.y = child_y + component.get_padding_top (); if (orientation == BoxOrientation.HORIZONTAL) {- child_x += component.padded_width;- - if (component.height > height) {- height = component.height;- }+ child_x = component.x + component.padded_width + get_padding_right (); } else {- child_y += component.padded_height;- - if (component.width > width) {- width = component.width;- } + child_y = component.y + component.padded_height + get_padding_bottom (); } }- - if (orientation == BoxOrientation.HORIZONTAL) {- width = child_x;- } else {- height = child_y;- } } public override string to_string () {@@ -19,7 +19,7 @@ using Cairo; namespace Bird { -class Component : GLib.Object {+public abstract class Component : GLib.Object { public double width { get; protected set; } public double height { get; protected set; } @@ -34,6 +34,18 @@ class Component : GLib.Object { return height + get_padding_left () + get_padding_right (); } }++ public double padded_x {+ get {+ return x + get_padding_top ();+ }+ }+ + public double padded_y { + get {+ return y + get_padding_left ();+ }+ } /** Vertical placement for this component relative to the parent container. */ public double x { get; protected set; }@@ -55,6 +67,18 @@ class Component : GLib.Object { Overflow overflow = Overflow.VISIBLE; + public Component.load (string file_name, double width, double height) {+ this.width = width;+ this.height = height;+ load_file (file_name, null);+ layout (width, height);+ }++ /** Parse component ui file but don't do layout. */+ internal Component.load_component (string file_name, Component parent) {+ load_file (file_name, parent);+ }+ public Component (XmlElement component_tag, Defs defs) { this.defs = defs; this.component_tag = component_tag;@@ -79,18 +103,11 @@ class Component : GLib.Object { } } }- - public Component.load (string file_name) {- load_file (file_name);- } private void inherit_styles_sheet (Defs defs) { this.defs = defs; } - protected void apply_padding () { - }- protected void parse_style (XmlElement style_tag) { defs = defs.shallow_copy (); StyleSheet style_sheet = StyleSheet.parse (defs, style_tag);@@ -111,12 +128,16 @@ class Component : GLib.Object { protected void add_component (Component component) { components.add (component);- component.inherit_styles_sheet (defs);- component.style = SvgStyle.parse (defs, style, component.component_tag); - component.set_overflow_property_from_css ();- component.set_identification ();+ component.set_style_properties (this); } + protected void set_style_properties (Component parent) {+ inherit_styles_sheet (parent.defs);+ style = SvgStyle.parse (parent.defs, parent.style, component_tag); + set_overflow_property_from_css ();+ set_identification ();+ }+ protected void set_overflow_property_from_css () { string? css_overflow = style.get_css_property ("overflow"); @@ -149,21 +170,26 @@ class Component : GLib.Object { VBox vbox = new VBox (layout_tag, defs); add_component (vbox); } else {- warning ("Layout of type " + type- + " is supported in this verison.");+ warning (type + " layout of type is supported in this verison."); } }-+ 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_tag, defs);- add_component (component);- component.load_layout (attribute.get_content ());- } else {- unused_attribute (attribute_name);+ string file_name = attribute.get_content ();+ UI ui = new UI.load_component (file_name, this);+ + foreach (Component component in ui.components) {+ add_component (component);+ + SvgStyle copied_style;+ copied_style = SvgStyle.parse (defs, style, component_tag); + copied_style.apply (component.style);+ component.style = copied_style;+ } } } }@@ -196,9 +222,9 @@ class Component : GLib.Object { warning ("The tag " + tag_name + " is not known in this version."); } - public void load_file (string file_name) {+ public void load_file (string file_name, Component? parent) { if (file_name.has_suffix (".ui")) {- load_layout (file_name);+ load_layout (file_name, parent); } else if (file_name.has_suffix (".svg")) { SvgComponent svg = new SvgComponent.for_file (file_name); add_component (svg); @@ -207,7 +233,7 @@ class Component : GLib.Object { } } - public void load_layout (string file_name) {+ public void load_layout (string file_name, Component? parent) { string? path = find_file (file_name); if (path == null) {@@ -225,14 +251,19 @@ class Component : GLib.Object { return; } - XmlTree xml_parser = new XmlTree (xml_data);+ XmlTree xml_parser = new XmlTree (xml_data); + XmlElement tag = xml_parser.get_root (); - component_tag = xml_parser.get_root ();- - defs = new Defs ();- parse (component_tag);+ if (parent == null) {+ component_tag = tag;+ defs = new Defs ();+ } else {+ Component p = (!) parent;+ component_tag = p.component_tag;+ defs = p.defs;+ } - layout ();+ parse (tag); } public static string find_file (string file_name) {@@ -245,34 +276,47 @@ class Component : GLib.Object { return file_name; } - public virtual void layout () {+ public virtual void get_min_size (out double min_width, out double min_height) {+ min_width = width;+ min_height = height;+ if (unlikely (components.size > 1)) { warning ("A component has several parts but no layout has been set."); } foreach (Component component in components) {- component.layout ();- component.apply_padding ();- width = component.padded_width;- height = component.padded_height;+ component.get_min_size (out min_width, out min_height); }++ min_width += get_padding_left ();+ min_width += get_padding_right ();+ min_height += get_padding_top ();+ min_height += get_padding_bottom (); } - public virtual void draw (Context cairo) {+ public virtual void layout (double parent_width, double parent_height) {+ warning ("A component without a layout was added to the view.");++ double w, h;+ get_min_size (out w, out h);++ width = w;+ height = h;+ foreach (Component component in components) {- cairo.save ();- cairo.translate (component.x, component.y);- - if (component.overflow == Overflow.HIDDEN) {- cairo.rectangle (0, 0, component.width, component.height);- cairo.clip ();- }- - component.draw (cairo);- cairo.restore ();+ component.layout (parent_width, parent_height);+ }+ }+ + public void clip (Context cairo) {+ if (overflow == Overflow.HIDDEN) {+ cairo.rectangle (0, 0, width, height);+ cairo.clip (); } } + public abstract void draw (Context cairo);+ public virtual void motion_notify_event (double x, double y) { } @@ -292,28 +336,73 @@ class Component : GLib.Object { print ("\t"); } - print (@"$(to_string ()), x: $x, y: $y, w: $width, h: $height\n");+ print (@"$(to_string ()) width: $padded_width, height: $padded_height x $x y $y $(style)\n"); foreach (Component component in components) { component.print_tree_level (indent + 1); } } - double get_padding_bottom () {+ protected double get_padding_bottom () { return SvgFile.parse_number (style.get_css_property ("padding-bottom")); } - double get_padding_top () {+ protected double get_padding_top () { return SvgFile.parse_number (style.get_css_property ("padding-top")); } - double get_padding_left () {+ protected double get_padding_left () { return SvgFile.parse_number (style.get_css_property ("padding-left")); } - double get_padding_right () {+ protected double get_padding_right () { return SvgFile.parse_number (style.get_css_property ("padding-right")); }++ protected void limit_size (ref double width, ref double height) {+ string? min_width = style.get_css_property ("min-width");+ if (min_width != null) {+ double w = SvgFile.parse_number (min_width);+ if (width < w) {+ width = w;+ }+ }++ string? min_height = style.get_css_property ("min-height");+ if (min_height != null) {+ double h = SvgFile.parse_number (min_height);+ + if (height < h) {+ height = h;+ }+ }+ + string? max_width = style.get_css_property ("max-width");+ if (max_width != null) {+ double w = SvgFile.parse_number (max_width);+ + if (width > w) {+ width = w;+ }+ }++ string? max_height = style.get_css_property ("max-height");+ if (max_height != null) {+ double h = SvgFile.parse_number (max_height);+ + if (height > h) {+ height = h;+ }+ }+ + if (width < 0) {+ width = 0;+ }++ if (height < 0) {+ height = 0;+ }+ } } }@@ -19,11 +19,11 @@ using Math; namespace Bird { -class Widget : DrawingArea {+public class Widget : DrawingArea { - Component component;+ UI component; - public Widget (Component main_component) { + public Widget (UI main_component) { component = main_component; add_events (EventMask.BUTTON_PRESS_MASK @@ -49,8 +49,11 @@ class Widget : DrawingArea { int width = (int) rint (component.padded_width); int height = (int) rint (component.padded_height); set_size_request (width, height);++ size_allocate.connect((allocation) => {+ component.resize (allocation.width, allocation.height);+ }); }- } }@@ -22,7 +22,9 @@ int main (string[] args) { window.set_title ("UI Bird"); window.destroy.connect (Gtk.main_quit); - Component layout = new Component.load ("test.ui");+ UI layout = new UI ("test.ui", 700, 200);+ + layout.print_tree (); Bird.Widget primary_layout = new Bird.Widget (layout); @@ -34,7 +34,18 @@ class SvgComponent : Component { load_svg (svg_file); } - public override void layout () {+ public override void get_min_size (out double min_width, out double min_height) {+ min_width = 0;+ min_height = 0;+ + if (drawing != null) {+ SvgDrawing svg = (!) drawing;+ min_width = svg.width + get_padding_left () + get_padding_right ();+ min_height = svg.height + get_padding_bottom () + get_padding_top ();+ }+ }+ + public override void layout (double parent_width, double parent_height) { if (unlikely (components.size > 0)) { warning ("SVG files can not have subviews."); }@@ -73,10 +84,16 @@ class SvgComponent : Component { } public override void draw (Context cairo) {+ cairo.save ();+ cairo.translate (padded_x, padded_y);+ clip (cairo);+ if (drawing != null) { SvgDrawing svg = (!) drawing; svg.draw (cairo); }+ + cairo.restore (); } }@@ -434,7 +434,7 @@ class BirdFontFile : GLib.Object { public void write_glyph (Glyph g, DataOutputStream os) throws GLib.Error { os.put_string (@"\t<glyph id=\"$(g.version_id)\" left=\"$(double_to_string (g.left_limit))\" right=\"$(double_to_string (g.right_limit))\">\n"); - foreach (Layer layer in g.layers.subgroups) {+ foreach (Layer layer in g.layers.get_sublayers ()) { write_layer (layer, os); } @@ -1626,7 +1626,7 @@ public class DrawingTools : ToolCollection { int i = 0; layer_tools.tool.clear ();- foreach (Layer layer in g.layers.subgroups) { + foreach (Layer layer in g.layers.get_sublayers ()) { LayerLabel label = new LayerLabel (layer); layer_tools.add_tool (label, 0); @@ -158,17 +158,17 @@ public class Glyph : FontDisplay { } public Layer get_current_layer () {- if (unlikely (!(0 <= current_layer < layers.subgroups.size))) {+ if (unlikely (!(0 <= current_layer < layers.objects.size))) { warning ("Layer index out of bounds."); return new Layer (); } - return layers.subgroups.get (current_layer);+ return layers.get_sublayers ().get (current_layer); } public void set_current_layer (Layer layer) { int i = 0;- foreach (Layer l in layers.subgroups) {+ foreach (Layer l in layers.get_sublayers ()) { if (likely (l == layer)) { current_layer = i; return;@@ -205,12 +205,12 @@ public class Glyph : FontDisplay { public void add_new_layer () { layers.add_layer (new Layer ());- current_layer = layers.subgroups.size - 1;+ current_layer = layers.objects.size - 1; } public void add_layer (Layer layer) { layers.add_layer (layer);- current_layer = layers.subgroups.size - 1;+ current_layer = layers.objects.size - 1; } public int get_layer_index (Layer layer) {@@ -482,7 +482,7 @@ public class Glyph : FontDisplay { } public virtual void add_path (Path p) {- if (layers.subgroups.size == 0) {+ if (layers.objects.size == 0) { layers.add_layer (new Layer ()); } @@ -490,7 +490,7 @@ public class Glyph : FontDisplay { } public void add_object (SvgBird.Object object) {- if (layers.subgroups.size == 0) {+ if (layers.objects.size == 0) { layers.add_layer (new Layer ()); } @@ -530,7 +530,7 @@ public class Glyph : FontDisplay { if (index != "") { int i = int.parse (index); - if (0 <= i < layers.subgroups.size) {+ if (0 <= i < layers.objects.size) { current_layer = i; } }@@ -1578,144 +1578,11 @@ public class Glyph : FontDisplay { /** Draw filled paths. */ public void draw_paths (Context cr, Color? c = null) {- cr.save ();- cr.new_path ();- - foreach (SvgBird.Object o in get_visible_objects ()) {- if (o is PathObject) {- ((PathObject) o).draw_path (cr, c);- } else {- o.draw (cr);- }- }- - cr.fill ();- cr.restore ();+ layers.draw (cr); } public void draw_path (Context cr) {- PathList stroke;- Color color;-- // FIXME: layer transforms- foreach (SvgBird.Object o in get_visible_objects ()) {- if (!(o is PathObject)) {- o.draw (cr);- }- }-- cr.save ();- cr.new_path ();- foreach (Path p in get_visible_paths ()) {- if (p.stroke > 0) {- stroke = p.get_stroke_fast ();-- if (p.is_editable ()) {- color = Theme.get_color ("Filled Stroke");- color.a = 0.8;- } else {- color = Color.black ();- }-- PathObject.draw_path_list (stroke, cr, color);- }- }- cr.fill ();- cr.restore ();-- if (!(MainWindow.get_toolbox ().get_current_tool () is PenTool)- && !(MainWindow.get_toolbox ().get_current_tool () is PointTool)- && !(MainWindow.get_toolbox ().get_current_tool () is TrackTool)- && !(MainWindow.get_toolbox ().get_current_tool () is BezierTool)) {- cr.save ();- cr.new_path ();- foreach (SvgBird.Object o in active_paths) {- if (o is PathObject) {- Path p = ((PathObject) o).get_path ();- if (p.stroke > 0) {- stroke = p.get_stroke_fast ();- color = Theme.get_color ("Selected SvgBird.Objects");- PathObject.draw_path_list (stroke, cr, color);- }- }- }- cr.fill ();- cr.restore ();- }-- if (is_open () && Path.fill_open_path) {- cr.save ();- cr.new_path ();- foreach (Path p in get_visible_paths ()) {- if (p.stroke == 0) {- color = p.color == null ? get_path_fill_color () : (!) p.color;- p.draw_path (cr, color);- }- }- cr.fill ();- cr.restore ();- }-- if (is_open ()) {- cr.save ();- cr.new_path ();- foreach (Path p in get_visible_paths ()) {- p.draw_outline (cr);- p.draw_edit_points (cr);- }- cr.restore ();- }-- if (!is_open ()) {- // This was good for testing but it is way too slow:- // Svg.draw_svg_path (cr, get_svg_data (), Glyph.xc () + left, Glyph.yc () - baseline);-- cr.save ();- cr.new_path ();- - // FIXME: layer transforms- foreach (SvgBird.Object o in get_visible_objects ()) {- if (o is PathObject) {- Path p = ((PathObject) o).get_path ();-- if (p.stroke == 0) {- color = p.color == null ? Color.black () : (!) p.color;- p.draw_path (cr, color);- }- }- }- - cr.close_path ();- cr.fill ();- cr.restore ();-- foreach (SvgBird.Object o in active_paths) {- if (o is PathObject) {- Path p = ((PathObject) o).get_path ();- cr.save ();- cr.new_path ();- if (p.stroke == 0) {- p.draw_path (cr);- }- cr.close_path ();- cr.fill ();- cr.restore ();- }- }- }-- if (show_orientation_arrow) {- foreach (Path p in get_visible_paths ()) {- if (p.stroke > 0) {- stroke = p.get_stroke_fast ();- foreach (Path ps in stroke.paths) {- ps.draw_orientation_arrow (cr, orientation_arrow_opacity);- }- } else {- p.draw_orientation_arrow (cr, orientation_arrow_opacity);- }- }- }+ layers.draw (cr); } private Color get_path_fill_color () {@@ -2348,12 +2215,12 @@ public class Glyph : FontDisplay { public void move_layer_up () { Layer layer = get_current_layer (); - if (current_layer + 2 <= layers.subgroups.size) {- return_if_fail (0 <= current_layer + 2 <= layers.subgroups.size);- layers.subgroups.insert (current_layer + 2, layer);+ if (current_layer + 2 <= layers.objects.size) {+ return_if_fail (0 <= current_layer + 2 <= layers.objects.size);+ layers.objects.objects.insert (current_layer + 2, layer); - return_if_fail (0 <= current_layer + 1 < layers.subgroups.size);- layers.subgroups.remove_at (current_layer);+ return_if_fail (0 <= current_layer + 1 < layers.objects.size);+ layers.objects.objects.remove_at (current_layer); set_current_layer (layer); }@@ -2363,11 +2230,11 @@ public class Glyph : FontDisplay { Layer layer = get_current_layer (); if (current_layer >= 1) {- return_if_fail (0 <= current_layer - 1 < layers.subgroups.size);- layers.subgroups.insert (current_layer - 1, layer);+ return_if_fail (0 <= current_layer - 1 < layers.objects.size);+ layers.objects.objects.insert (current_layer - 1, layer); - return_if_fail (0 <= current_layer + 1 < layers.subgroups.size);- layers.subgroups.remove_at (current_layer + 1);+ return_if_fail (0 <= current_layer + 1 < layers.objects.size);+ layers.objects.objects.remove_at (current_layer + 1); set_current_layer (layer); }@@ -77,7 +77,7 @@ public class LayerUtils { layer.objects.remove ((!) p); } - foreach (SvgBird.Layer sublayer in layer.subgroups) {+ foreach (SvgBird.Layer sublayer in layer.get_sublayers ()) { remove_path (sublayer, path); } }@@ -256,7 +256,7 @@ public class SvgParser { if (t.get_name () == "g") { layer = new Layer (); parse_layer (t, layer);- pl.subgroups.add (layer);+ pl.objects.add (layer); } if (t.get_name () == "polygon") {@@ -305,7 +305,7 @@ public class SvgParser { } private void transform_subgroups (string transform_functions, Layer layer) {- foreach (Layer subgroup in layer.subgroups) {+ foreach (Layer subgroup in layer.get_sublayers ()) { transform (transform_functions, subgroup); } }@@ -18,52 +18,67 @@ namespace SvgBird { public class Layer : Object { public ObjectGroup objects;- - public Gee.ArrayList<Layer> subgroups; // FIXME: delete public string name = "Layer"; public Layer () { objects = new ObjectGroup ();- subgroups = new Gee.ArrayList<Layer> (); transforms = new SvgTransforms (); } - public int index_of (Layer sublayer) {- return subgroups.index_of (sublayer);- }-- public ObjectGroup get_all_objects () {- ObjectGroup o = new ObjectGroup ();- - o.append (objects);+ public void draw (Context cr) {+ cr.save ();+ apply_transform (cr); - foreach (Layer sublayer in subgroups) {- o.append (sublayer.get_all_objects ());+ if (clip_path != null) {+ ClipPath clipping = (!) clip_path;+ clipping.apply (cr);+ }++ foreach (Object object in objects) {+ cr.save ();+ object.apply_transform (cr);+ + if (object.clip_path != null) {+ ClipPath clipping = (!) object.clip_path;+ clipping.apply (cr);+ }++ object.draw_outline (cr);+ object.paint (cr);+ cr.restore (); } - return o;+ cr.restore (); }++ public override void draw_outline (Context cr) {+ cr.save ();+ apply_transform (cr); - public ObjectGroup get_visible_objects () {- ObjectGroup object_group = new ObjectGroup ();- - if (visible) {- foreach (Object o in objects) {- object_group.add (o);- }+ foreach (Object object in objects) {+ cr.save ();+ object.apply_transform (cr);+ object.draw_outline (cr);+ cr.restore (); } - foreach (Layer sublayer in subgroups) {- if (sublayer.visible) {- object_group.append (sublayer.get_visible_objects ());- }- }+ cr.restore ();+ }++ public int index_of (Layer sublayer) {+ return objects.index_of (sublayer);+ }++ public ObjectGroup get_all_objects () {+ return objects;+ } - return object_group; + public ObjectGroup get_visible_objects () {+ return objects; // FIXME: remove this } public void add_layer (Layer layer) {- subgroups.add (layer);+ objects.add (layer); } public void add_object (Object object) {@@ -75,21 +90,19 @@ public class Layer : Object { } public void remove_layer (Layer layer) {- subgroups.remove (layer);+ objects.remove (layer); - foreach (Layer sublayer in subgroups) {- sublayer.remove_layer (layer);+ foreach (Object object in objects) {+ if (object is Layer) {+ Layer sublayer = (Layer) object;+ sublayer.remove_layer (layer);+ } } } public static void copy_layer (Layer from, Layer to) { to.name = from.name; to.objects = from.objects.copy ();- - foreach (Layer l in from.subgroups) {- Layer layer = (Layer) l.copy ();- to.subgroups.add (layer);- } } public override Object copy () {@@ -130,6 +143,21 @@ public class Layer : Object { x = px; y = py2; }++ public Gee.ArrayList<Layer> get_sublayers () {+ Gee.ArrayList<Layer> sublayers = new Gee.ArrayList<Layer> ();+ + foreach (Object object in objects) {+ if (likely (object is Layer)) {+ Layer sublayer = (Layer) object;+ sublayers.add (sublayer);+ } else {+ warning ("An object in the group " + name + " is not a layer.");+ }+ }+ + return sublayers;+ } public void print (int indent = 0) { stdout.printf (@"Layer: $(name)");@@ -138,31 +166,27 @@ public class Layer : Object { stdout.printf (" hidden"); } - stdout.printf (@"\n");+ stdout.printf (@" $(transforms) $(style)"); - foreach (Object o in objects) {- for (int i = 0; i < indent; i++) {- stdout.printf ("\t");- }- stdout.printf (@"Object $(o.to_string ())");- - if (o.color != null) {- stdout.printf (" %s", ((!) o.color).to_rgb_hex ());- }+ stdout.printf (@"\n"); - if (!o.visible) {+ foreach (Object object in objects) {+ stdout.printf (@"$(object.to_string ()) $(object.transforms) $(object.style)");+ + if (!object.visible) { stdout.printf (" hidden"); } stdout.printf ("\n");- }- - foreach (Layer l in subgroups) {+ for (int i = 0; i < indent; i++) { stdout.printf ("\t"); }- stdout.printf ("%s\n", l.name);- l.print (indent + 1);++ if (object is Layer) {+ Layer sublayer = (Layer) object;+ sublayer.print (indent + 1);+ } } } @@ -170,13 +194,7 @@ public class Layer : Object { public override bool is_over (double x, double y) { return false; }- - public override void draw_outline (Context cr) {- foreach (Object object in objects) {- object.draw_outline (cr);- }- }- + public override void move (double dx, double dy) { } @@ -61,20 +61,6 @@ public abstract class Object : GLib.Object { public abstract bool is_over (double x, double y); public abstract void draw_outline (Context cr); - public void draw (Context cr) {- cr.save ();- apply_transform (cr);- - if (clip_path != null) {- ClipPath clipping = (!) clip_path;- clipping.apply (cr);- }- - draw_outline (cr);- paint (cr);- cr.restore ();- }- public abstract Object copy (); public abstract void move (double dx, double dy); public abstract void rotate (double theta, double xc, double yc);@@ -27,6 +27,10 @@ public class ObjectGroup : GLib.Object { objects = new Gee.ArrayList<Object> (); } + public int index_of (Object o) {+ return objects.index_of (o);+ }+ public Gee.Iterator<Object> iterator () { return objects.iterator (); }@@ -20,9 +20,9 @@ public extern struct PointValue { double value; } -public static const uchar NONE = 0;-public static const uchar ARC = 1;-public static const uchar CUBIC = 2;-public static const uchar LINE = 3;+public static const uchar POINT_NONE = 0;+public static const uchar POINT_ARC = 1;+public static const uchar POINT_CUBIC = 2;+public static const uchar POINT_LINE = 3; }@@ -47,18 +47,13 @@ public class SvgDrawing : Object { return (this.x <= x <= this.x + width) && (this.y <= y <= this.y + height); }- ++ public void draw (Context cr) {+ root_layer.draw (cr);+ }+ public override void draw_outline (Context cr) {- cr.save ();- cr.translate (x, y); root_layer.draw_outline (cr);- - // FIXME: update layer structure- foreach (Object o in root_layer.get_visible_objects ().objects) {- o.draw (cr);- }- - cr.restore (); } public override Object copy () {@@ -76,7 +76,7 @@ public class SvgFile : GLib.Object { if (name == "g") { Layer sublayer = new Layer (); parse_layer (layer, parent_style, t);- layer.subgroups.add (sublayer);+ layer.objects.add (sublayer); } if (name == "a") {@@ -648,7 +648,7 @@ public class SvgFile : GLib.Object { points.x = bezier_points[i].x0; points.y = bezier_points[i].y0; } else {- points.add_type (LINE);+ points.add_type (POINT_LINE); points.add (bezier_points[i].x0); points.add (bezier_points[i].y0); points.add (0);@@ -658,7 +658,7 @@ public class SvgFile : GLib.Object { points.add (0); } } else if (bezier_points[i].type == 'C') {- points.add_type (CUBIC);+ points.add_type (POINT_CUBIC); points.add (bezier_points[i].x0); points.add (bezier_points[i].y0); points.add (bezier_points[i].x1);@@ -667,7 +667,7 @@ public class SvgFile : GLib.Object { points.add (bezier_points[i].y2); points.add (0); } else if (bezier_points[i].type == 'L') {- points.add_type (LINE);+ points.add_type (POINT_LINE); points.add (bezier_points[i].x0); points.add (bezier_points[i].y0); points.add (0);@@ -688,7 +688,7 @@ public class SvgFile : GLib.Object { out angle_start, out angle_extent, out center_x, out center_y); - points.add_type (ARC);+ points.add_type (POINT_ARC); points.add (center_x); points.add (center_y); points.add (b.rx);@@ -49,18 +49,18 @@ public class SvgPath : Object { for (int i = 0; i < size; i += 8) { switch (points[i].type) {- case ARC: + case POINT_ARC: draw_arc (cr, points[i + 1].value, points[i + 2].value, points[i + 3].value, points[i + 4].value, points[i + 5].value, points[i + 6].value, points[i + 7].value); break;- case CUBIC:+ case POINT_CUBIC: cr.curve_to (points[i + 1].value, points[i + 2].value, points[i + 3].value, points[i + 4].value, points[i + 5].value, points[i + 6].value); break;- case LINE:+ case POINT_LINE: cr.line_to (points[i + 1].value, points[i + 2].value); break; }@@ -30,7 +30,20 @@ public class SvgTransform : GLib.Object { public SvgTransform () { }- ++ public string to_string () {+ StringBuilder sb = new StringBuilder ();+ + sb.append (@"$type");+ sb.append (" ");+ + for (int i = 0; i < arguments.size; i++) {+ sb.append (@"$(arguments.get_double (i)) ");+ }++ return sb.str;+ }+ public Matrix get_matrix () { Matrix matrix; @@ -42,6 +42,17 @@ public class SvgTransforms : GLib.Object { return matrix; }+ + public string to_string () {+ StringBuilder sb = new StringBuilder ();+ + foreach (SvgTransform t in transforms) {+ sb.append (t.to_string ());+ sb.append (" ");+ }+ + return sb.str;+ } } }