Clone in a terminal:
Commit f17b819
Johan Mattsson - 2016-01-16T20:35:38+00:00
f17b819e135e82e966550170f00a7e4bbedbf9b2johan.mattsson.m@gmail.com

Fix layout containers

Changed files (20)

Diff

diff --git a/birdui/AbsoluteLayout.vala b/birdui/AbsoluteLayout.valadeleted file mode 100644index 0b022d2..0000000--- a/birdui/AbsoluteLayout.vala+++ /dev/null@@ -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";-	}-}--}diff --git a/birdui/BoxLayout.vala b/birdui/BoxLayout.valaindex cb7f7eb..df7ee8d 100644--- a/birdui/BoxLayout.vala+++ b/birdui/BoxLayout.vala@@ -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 () {diff --git a/birdui/Component.vala b/birdui/Component.valaindex 4561164..f410e59 100644--- a/birdui/Component.vala+++ b/birdui/Component.vala@@ -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;+		}+	} }  }diff --git a/birdui/GtkWidget.vala b/birdui/GtkWidget.valaindex 3db70a1..c31e14d 100644--- a/birdui/GtkWidget.vala+++ b/birdui/GtkWidget.vala@@ -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);+		}); 	}-	 }  }diff --git a/birdui/GtkWindow.vala b/birdui/GtkWindow.valaindex 8f4375d..b27b127 100644--- a/birdui/GtkWindow.vala+++ b/birdui/GtkWindow.vala@@ -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); diff --git a/birdui/SvgComponent.vala b/birdui/SvgComponent.valaindex b0ebd3a..416cc28 100644--- a/birdui/SvgComponent.vala+++ b/birdui/SvgComponent.vala@@ -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 (); 	}  }diff --git a/libbirdfont/BirdFontFile.vala b/libbirdfont/BirdFontFile.valaindex 948a66a..4c9d38c 100644--- a/libbirdfont/BirdFontFile.vala+++ b/libbirdfont/BirdFontFile.vala@@ -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); 		} diff --git a/libbirdfont/DrawingTools.vala b/libbirdfont/DrawingTools.valaindex c79c488..0ea8a04 100644--- a/libbirdfont/DrawingTools.vala+++ b/libbirdfont/DrawingTools.vala@@ -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); 			diff --git a/libbirdfont/Glyph.vala b/libbirdfont/Glyph.valaindex f823ef0..511ecb7 100644--- a/libbirdfont/Glyph.vala+++ b/libbirdfont/Glyph.vala@@ -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); 		}diff --git a/libbirdfont/LayerUtils.vala b/libbirdfont/LayerUtils.valaindex 5035655..3cd28d5 100644--- a/libbirdfont/LayerUtils.vala+++ b/libbirdfont/LayerUtils.vala@@ -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); 		} 	}diff --git a/libbirdfont/SvgParser.vala b/libbirdfont/SvgParser.valaindex 487198c..c443791 100644--- a/libbirdfont/SvgParser.vala+++ b/libbirdfont/SvgParser.vala@@ -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); 		} 	}diff --git a/libsvgbird/Layer.vala b/libsvgbird/Layer.valaindex 8580bdd..60e7251 100644--- a/libsvgbird/Layer.vala+++ b/libsvgbird/Layer.vala@@ -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) { 	} 	diff --git a/libsvgbird/Object.vala b/libsvgbird/Object.valaindex e7fc751..93a3293 100644--- a/libsvgbird/Object.vala+++ b/libsvgbird/Object.vala@@ -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);diff --git a/libsvgbird/ObjectGroup.vala b/libsvgbird/ObjectGroup.valaindex 3beb2b1..b44c336 100644--- a/libsvgbird/ObjectGroup.vala+++ b/libsvgbird/ObjectGroup.vala@@ -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 (); 	}diff --git a/libsvgbird/PointValue.vala b/libsvgbird/PointValue.valaindex f91bc01..6c93beb 100644--- a/libsvgbird/PointValue.vala+++ b/libsvgbird/PointValue.vala@@ -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;  }diff --git a/libsvgbird/SvgDrawing.vala b/libsvgbird/SvgDrawing.valaindex f97d986..3301e70 100644--- a/libsvgbird/SvgDrawing.vala+++ b/libsvgbird/SvgDrawing.vala@@ -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 () {diff --git a/libsvgbird/SvgFile.vala b/libsvgbird/SvgFile.valaindex bc35dc0..9cb8c36 100644--- a/libsvgbird/SvgFile.vala+++ b/libsvgbird/SvgFile.vala@@ -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);diff --git a/libsvgbird/SvgPath.vala b/libsvgbird/SvgPath.valaindex c9215c3..af2a41d 100644--- a/libsvgbird/SvgPath.vala+++ b/libsvgbird/SvgPath.vala@@ -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; 			}diff --git a/libsvgbird/SvgTransform.vala b/libsvgbird/SvgTransform.valaindex e1fc43a..e2e8527 100644--- a/libsvgbird/SvgTransform.vala+++ b/libsvgbird/SvgTransform.vala@@ -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; 		diff --git a/libsvgbird/SvgTransforms.vala b/libsvgbird/SvgTransforms.valaindex a799aff..73f7018 100644--- a/libsvgbird/SvgTransforms.vala+++ b/libsvgbird/SvgTransforms.vala@@ -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;+	} }  }

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112