Clone in a terminal:
Commit 9597194
Johan Mattsson - 2015-10-22T21:06:48+00:00
9597194e8206e113c25612b89758da2b1a4fc2e2johan.mattsson.m@gmail.com

Zoom with trackpad and other fixes for Mac

Changed files (6)

Diff

diff --git a/install.py b/install.pyindex 0013d0b..c3660fd 100755--- a/install.py+++ b/install.py@@ -123,7 +123,9 @@ if not options.nocli: 	install ('build/bin/birdfont-import', '/bin', 755)  #library-if not options.libdir:+if sys.platform == 'darwin':+	libdir = '/lib'+elif not options.libdir: 	 	if platform.dist()[0] == 'Ubuntu' or platform.dist()[0] == 'Debian': 		process = subprocess.Popen(['dpkg-architecture', '-qDEB_HOST_MULTIARCH'], stdout=subprocess.PIPE)diff --git a/libbirdfont/BirdFont.vala b/libbirdfont/BirdFont.valaindex eb1408e..e93ba6f 100644--- a/libbirdfont/BirdFont.vala+++ b/libbirdfont/BirdFont.vala@@ -1,19 +1,19 @@ /*     Copyright (C) 2012 2014 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 +    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 +    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 BirdFont; -public const string GETTEXT_PACKAGE = "birdfont"; +public const string GETTEXT_PACKAGE = "birdfont";  namespace BirdFont { @@ -39,26 +39,26 @@ public static string wine_to_unix_path (string exec_path) {  	p = exec_path; 	p = p.replace ("\\", "/");-	+ 	drive_c = exec_path.index_of ("C:") == 0; 	drive_z = exec_path.index_of ("Z:") == 0;-	+ 	i = p.index_of (":");-	+ 	if (i != -1) { 		p = p.substring (i + 2); 	}  	if (drive_c) { 		q = @"/home/$(Environment.get_user_name ())/.wine/drive_c/" + p;-		+ 		if (File.new_for_path (q).query_exists ()) { 			return q; 		} else { 			return p; 		} 	}-	+ 	if (drive_z) { 		return ("/" + p).dup (); 	}@@ -90,28 +90,27 @@ public class BirdFont {  	public static Font current_font; 	public static GlyphCollection current_glyph_collection;-	+ 	public static Drawing? drawing = null;-	+ 	public static string? settings_subdirectory = null;-	+ 	public BirdFont () { 		set_defaul_drawing_callbacks (); 	}-	+ 	void set_defaul_drawing_callbacks () { 		if (drawing == null) { 			drawing = new Drawing (); 		}-	}	-	+	}+ 	/** 	 * @param arg command line arguments 	 * @param program path 	 * @param setting subdirectory 	 */ 	public void init (string[] arg, string? program_path, string? settings_subdir) {-		int err_arg; 		int i; 		File font_file; 		string exec_path;@@ -120,7 +119,7 @@ public class BirdFont { 		string theme_version; 		CharDatabaseParser parser; 		CodePageBits codepage_bits;-		+ 		set_settings_subdir (settings_subdir);  		args = new Argument.command_line (arg);@@ -128,17 +127,17 @@ public class BirdFont {  #if ANDROID 		BirdFont.logging = true;-		+ 		__android_log_print (ANDROID_LOG_WARN, "BirdFont", @"libbirdfont version $VERSION"); 		LogLevelFlags log_levels = LogLevelFlags.LEVEL_ERROR | LogLevelFlags.LEVEL_CRITICAL | LogLevelFlags.LEVEL_WARNING; 		Log.set_handler (null, log_levels, android_warning);-		+ 		android = true; #else 		stdout.printf ("birdfont version %s\n", VERSION);-		+ 		android = args.has_argument ("--android");-		+ 		if (!BirdFont.logging) { 			BirdFont.logging = args.has_argument ("--log"); 		}@@ -147,7 +146,7 @@ public class BirdFont { 		if (BirdFont.logging) { 			init_logfile (); 		}-		+ 		if (!args.has_argument ("--no-translation")) { 			init_gettext (); 		}@@ -157,24 +156,25 @@ public class BirdFont { 			Process.exit (0); 		} -		err_arg = args.validate ();+#if !MAC+		int err_arg = args.validate (); 		if (err_arg != 0) { 			stdout.printf (@"Unknown parameter $(arg [err_arg])\n\n"); 			args.print_help (); 			Process.exit (0); 		}-+#endif 		Preferences.load ();-		+ 		// always load default theme when names in theme does change 		default_theme_version = 1; 		theme = Preferences.get ("theme"); 		theme_version = Preferences.get ("theme_version");  		Theme.set_default_colors ();-		+ 		if (theme_version == "" || int.parse (theme_version) < default_theme_version) {-			+ 			Theme.load_theme ("dark.theme"); 			Preferences.set ("theme", "dark.theme"); 		} else {@@ -186,16 +186,16 @@ public class BirdFont { 		}  		Preferences.set ("theme_version", @"$default_theme_version");-		+ 		current_font = new Font (); 		current_font.set_name (""); 		current_font.initialised = false; 		current_glyph_collection = new GlyphCollection.with_glyph ('\0', "");-		+ 		experimental = args.has_argument ("--test"); 		show_coordinates = args.has_argument ("--show-coordinates") || experimental; 		fatal_wanings = args.has_argument ("--fatal-warning");-		win32 = (arg[0].index_of (".exe") > -1) +		win32 = (arg[0].index_of (".exe") > -1) 			|| arg[0] == "wine" 			|| args.has_argument ("--windows"); @@ -204,18 +204,18 @@ public class BirdFont { #else 		mac = args.has_argument ("--mac"); #endif-	+ 		if (program_path == null) { 			exec_path = "";  			if (win32) { 				// wine hack to get "." folder in win32 environment 				i = arg[0].last_index_of ("\\");-				-				if (i != -1) {	++				if (i != -1) { 					exec_path = arg[0]; 					exec_path = exec_path.substring (0, i);-					exec_path = wine_to_unix_path (exec_path);			+					exec_path = wine_to_unix_path (exec_path); 				} 			} else { 				exec_path = "./";@@ -223,10 +223,10 @@ public class BirdFont { 		} else { 			exec_path = (!) program_path; 		}-		+ 		if (args.get_file () != "") { 			font_file = File.new_for_path (args.get_file ());-			+ 			if (!font_file.query_exists ()) { 				stderr.printf (@"The file \"$(args.get_file ())\" was not found.\n"); 				Process.exit (-1);@@ -237,7 +237,7 @@ public class BirdFont { 			LogLevelFlags levels = LogLevelFlags.LEVEL_ERROR | LogLevelFlags.LEVEL_CRITICAL | LogLevelFlags.LEVEL_WARNING; 			Log.set_handler (null, levels, fatal_warning); 		}-		+ 		Preferences.set_last_file (get_current_font ().get_path ());  		DefaultCharacterSet.create_default_character_sets ();@@ -248,7 +248,7 @@ public class BirdFont { 		if (TestBirdFont.get_singleton ().test_cases_to_run != "All") { 			TestBirdFont.run_tests (); 		}-		+ 		if (has_argument ("--parse-ucd")) { 			parser = new CharDatabaseParser (); 			parser.regenerate_database ();@@ -262,20 +262,20 @@ public class BirdFont {  	public static bool has_logging () { 		bool log;-		+ 		lock (BirdFont.logging) { 			log = BirdFont.logging; 		}-		+ 		return log; 	}-	+ 	public static Argument get_arguments () { 		return args; 	}  	public static void set_bundle_path (string path) {-		bundle_path = path;	+		bundle_path = path; 	}  	public static void init_gettext () {@@ -287,25 +287,25 @@ public class BirdFont { 		Intl.bindtextdomain (GETTEXT_PACKAGE, locale_directory); #endif 	}-	+ 	public static void load_font_from_command_line () { 		string file = args.get_file (); 		if (file != "") { 			RecentFiles.load_font (file);-		}	+		} 	}-	+ 	public static Font get_current_font () { 		return current_font; 	} -	internal static void fatal_warning (string? log_domain, LogLevelFlags log_levels, string message) {		+	internal static void fatal_warning (string? log_domain, LogLevelFlags log_levels, string message) { 		bool fatal = true;-		+ 		if (log_domain != null) { 			stderr.printf ("%s: \n", (!) log_domain); 		}-		+ 		stderr.printf ("\n%s\n\n", message); 		assert (!fatal); 	}@@ -315,38 +315,38 @@ public class BirdFont { 		__android_log_print (ANDROID_LOG_WARN, "BirdFont", message); 	} #endif-	+ 	public static Font new_font () { 		current_font = new Font ();-		+ 		if (!is_null (MainWindow.tools)) { 			MainWindow.get_drawing_tools ().remove_all_grid_buttons (); 			DrawingTools.add_new_grid (1, false); 			DrawingTools.add_new_grid (2, false); 			DrawingTools.add_new_grid (4, false); 		}-		+ 		if (!is_null (Toolbox.background_tools)) { 			Toolbox.background_tools.remove_images (); 		}-		+ 		KerningTools.update_kerning_classes ();-		+ 		return current_font; 	}  	public static void set_settings_directory (string directory) { 		settings_subdirectory = directory; 	}-	+ 	public static File get_preview_directory () { 		File settings = get_settings_directory (); 		File backup = get_child(settings, "preview");-		+ 		if (!backup.query_exists ()) { 			DirUtils.create ((!) backup.get_path (), 0755); 		}-			+ 		return backup; 	} @@ -367,15 +367,15 @@ public class BirdFont { 			printd ("Create settings directory."); 			DirUtils.create ((!) home.get_path (),0755); 		}-#else	-		home_path = (settings_directory != null) +#else+		home_path = (settings_directory != null) 			? (!) settings_directory : Environment.get_user_config_dir ();-						+ 		if (is_null (home_path)) { 			warning ("No home directory set."); 			home_path = "."; 		}-		+ 		home = File.new_for_path (home_path); #endif @@ -384,22 +384,22 @@ public class BirdFont { 		} else { 			settings = get_child(home, "birdfont"); 		}-			+ 		if (!settings.query_exists ()) { 			DirUtils.create ((!) settings.get_path (), 0755); 		}-			+ 		return settings; 	}  	internal static File get_backup_directory () { 		File settings = get_settings_directory (); 		File backup = get_child (settings, "backup");-		+ 		if (!backup.query_exists ()) { 			DirUtils.create ((!) backup.get_path (), 0755); 		}-			+ 		return backup; 	} @@ -407,14 +407,14 @@ public class BirdFont { 		if (is_null (args)) { 			return false; 		}-		+ 		return args.has_argument (param); 	}-	+ 	internal static string? get_argument (string param) { 		return args.get_argument (param); 	}-	+ 	public static void debug_message (string s) { 		if (unlikely (has_logging ())) { 			try {@@ -424,7 +424,7 @@ public class BirdFont { 				} else { 					warning ("No logstream."); 				}-				+ 				stderr.printf (s); 			} catch (GLib.Error e) { 				warning (e.message);@@ -438,26 +438,26 @@ void init_logfile () { 	File settings; 	string s; 	File log;-	+ 	try { 		t = new DateTime.now_local (); 		settings = BirdFont.get_settings_directory (); 		s = t.to_string ().replace (":", "_"); 		log = get_child (settings, @"birdfont_$s.log");-		+ 		BirdFont.logstream = new DataOutputStream (log.create (FileCreateFlags.REPLACE_DESTINATION)); 		((!)BirdFont.logstream).put_string ((!) log.get_path ()); 		((!)BirdFont.logstream).put_string ("\n");-		-		warning ("Logging to " + (!) log.get_path ());	++		warning ("Logging to " + (!) log.get_path ()); 	} catch (GLib.Error e) { 		warning (e.message); 		warning ((!) log.get_path ()); 	}  	LogLevelFlags levels = LogLevelFlags.LEVEL_ERROR | LogLevelFlags.LEVEL_CRITICAL | LogLevelFlags.LEVEL_WARNING | LogLevelFlags.LEVEL_DEBUG;-	Log.set_handler (null, levels, log_warning);		-		+	Log.set_handler (null, levels, log_warning);+ 	BirdFont.logging = true;  	printd (@"Program version: $(VERSION)\n");@@ -467,7 +467,7 @@ internal static void log_warning (string? log_domain, LogLevelFlags log_levels,  	if (log_domain != null) { 		printd ((!) log_domain); 	}-	+ 	printd ("\n"); 	printd (message); 	printd ("\n");@@ -487,7 +487,7 @@ public static void printd (string s) { public string t_ (string t) { #if ANDROID 	return t;-#else +#else 	return _(t); #endif }@@ -505,7 +505,7 @@ public static void warn_if_test (string message) { 	} } -/** Obtain a handle to a file in a folder. */ +/** Obtain a handle to a file in a folder. */ public static File get_child (File folder, string file_name) { 	string f; 	string s;@@ -516,11 +516,11 @@ public static File get_child (File folder, string file_name) { 	f = (!) folder.get_path ();  #if LINUX-	s = "/"; +	s = "/"; #else-	s = (BirdFont.win32) ? "\\" : "/"; +	s = (BirdFont.win32) ? "\\" : "/"; #endif-	+ 	n = file_name; 	if (unlikely (BirdFont.win32 && file_name.index_of ("\\") != -1)) { 		warning (@"File name contains path separator: $file_name, Directory: $f");@@ -530,9 +530,9 @@ public static File get_child (File folder, string file_name) { 	if (!f.has_suffix (s)) { 		f += s; 	}-	+ 	printd (@"File in Directory: $f Name: $n\n");-	+ 	return File.new_for_path (f + n); } diff --git a/libbirdfont/FontDisplay.vala b/libbirdfont/FontDisplay.valaindex ebd84e0..378f5a3 100644--- a/libbirdfont/FontDisplay.vala+++ b/libbirdfont/FontDisplay.vala@@ -1,14 +1,14 @@ /*     Copyright (C) 2012 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 +    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 +    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. */ @@ -18,7 +18,7 @@ using Math; namespace BirdFont {  public abstract class FontDisplay : GLib.Object {-	+ 	private static double last_tap_y = -1; 	private static double last_tap_time = 0; @@ -26,7 +26,7 @@ public abstract class FontDisplay : GLib.Object {  	/** Queue redraw area */ 	public signal void redraw_area (double x, double y, double w, double h);-	+ 	public virtual string get_name () { 		warning ("No name."); 		return "";@@ -36,43 +36,46 @@ public abstract class FontDisplay : GLib.Object { 		warning ("No label."); 		return ""; 	}-		+ 	public virtual void close () { 	}-	+ 	public virtual bool has_scrollbar () { 		return false; 	}-	+ 	public virtual void update_scrollbar () { 	}-		+ 	public virtual void scroll_to (double percent) { 	}-	+ 	public virtual void draw (WidgetAllocation allocation, Context cr) { 	}-	+ 	public virtual void selected_canvas () { 	}-	+ 	public virtual void key_press (uint keyval) { 	}-	+ 	public virtual void key_release (uint keyval) { 	}-	+ 	public virtual void motion_notify (double x, double y) { 	}-	+ 	public virtual void button_release (int button, double x, double y) { 	}-	+ 	public virtual void button_press (uint button, double x, double y) { 	}  	public virtual void double_click (uint button, double ex, double ey) {-	}	+	}++  public virtual void magnify (double magnification) {+	}  	public virtual void tap_down (int finger, int x, int y) { 		if (finger == 0) {@@ -81,27 +84,27 @@ public abstract class FontDisplay : GLib.Object { 			} else { 				button_press (1, x, y); 			}-			-			last_tap_time = GLib.get_real_time ();	++			last_tap_time = GLib.get_real_time (); 		}-		+ 		last_tap_y = -1; 	}-	+ 	public virtual void tap_up (int finger, int x, int y) { 		if (finger == 0) { 			button_release (1, x, y); 		}-		+ 		last_tap_y = -1; 	}-	+ 	public virtual void tap_move (int finger, int x, int y) { 		double d; 		if (finger == 0) { 			motion_notify (x, y);-			-			d = y - last_tap_y;		++			d = y - last_tap_y; 			if (last_tap_y > -1 && fabs (d) > 15) { // FIXME: pixels, other units are better 				if (d > 0) { 					scroll_wheel (x, y, 15, 0);@@ -109,50 +112,50 @@ public abstract class FontDisplay : GLib.Object { 					scroll_wheel (x, y, 15, 0); 				} 			}-			+ 			last_tap_y = y; 		} 	}  	public virtual void zoom_in () { 	}-	+ 	public virtual void zoom_out () { 	}-	+ 	public virtual void zoom_max () { 	}-	+ 	public virtual void zoom_min () { 	}-	+ 	public virtual void move_view (double x, double y) { 	}-	+ 	public virtual void reset_zoom () { 	}-	+ 	public virtual void store_current_view () { 	}-	+ 	public virtual void restore_last_view () { 	}  	public virtual void next_view () { 	}-	+ 	public virtual void scroll_wheel (double x, double y, 		double pixeldelta_x,  double pixeldelta_y) { 	}-	+ 	public virtual void undo () { 	}  	public virtual void redo () { 	}-	+ 	public static File find_file (string? dir, string name) {-		return SearchPaths.find_file (dir, name);	+		return SearchPaths.find_file (dir, name); 	}  	/** returns false if bindings to a single key works in the display. */diff --git a/libbirdfont/Glyph.vala b/libbirdfont/Glyph.valaindex f58deaf..10db913 100644--- a/libbirdfont/Glyph.vala+++ b/libbirdfont/Glyph.vala@@ -1,14 +1,14 @@ /*     Copyright (C) 2012 2013 2014 2015 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 +    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 +    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. */ @@ -19,20 +19,20 @@ using Gee; namespace BirdFont {  public class Glyph : FontDisplay {-	+ 	// Background image 	BackgroundImage? background_image = null; 	bool background_image_visible = true;-	+ 	// Glyph zoom level 	public double view_zoom = 0.1;-	+ 	public double view_offset_x = 0; 	public double view_offset_y = 0; 	Gee.ArrayList<ZoomView> zoom_list = new Gee.ArrayList<ZoomView> (); 	int zoom_list_index = 0;-	-	// The point where edit event begun ++	// The point where edit event begun 	double pointer_begin_x = 0; 	double pointer_begin_y = 0; @@ -42,21 +42,21 @@ public class Glyph : FontDisplay { 	int last_tap1_y = 0; 	int last_tap1_x = 0; 	double zoom_distance = 0;-	bool change_view; +	bool change_view;  	bool ignore_input = false;-	+ 	// Current pointer position 	public double motion_x = 0; 	public double motion_y = 0;-		+ 	// Zoom area 	public double zoom_x1 = 0; 	public double zoom_y1 = 0; 	public double zoom_x2 = 0; 	public double zoom_y2 = 0; 	public bool zoom_area_is_visible = false;-	+ 	bool view_is_moving = false; 	public double move_offset_x = 0; 	public double move_offset_y = 0;@@ -64,34 +64,34 @@ public class Glyph : FontDisplay {  	public WidgetAllocation allocation = new WidgetAllocation (); -	public unichar unichar_code = 0; // FIXME: name and unichar should be moved to to glyph collection +	public unichar unichar_code = 0; // FIXME: name and unichar should be moved to to glyph collection 	public string name;  	public double left_limit { 		get { 			return _left_limit; 		}-		+ 		set { 			ttf_data = null; 			_left_limit = value; 		} 	}-	+ 	public double right_limit { 		get { 			return _right_limit; 		}-		+ 		set { 			ttf_data = null; 			_right_limit = value; 		} 	}-	+ 	private double _right_limit = 0; 	private double _left_limit = 0;-	+ 	// x-height, lsb, etc. 	public Gee.ArrayList<Line> vertical_help_lines = new Gee.ArrayList<Line> (); 	public Gee.ArrayList<Line> horizontal_help_lines = new Gee.ArrayList<Line> ();@@ -99,26 +99,26 @@ public class Glyph : FontDisplay { 	bool xheight_lines_visible = false; 	bool margin_boundaries_visible = false; 	string new_guide_name = "";-	+ 	Gee.ArrayList<Glyph> undo_list = new Gee.ArrayList<Glyph> (); 	Gee.ArrayList<Glyph> redo_list = new Gee.ArrayList<Glyph> ();  	string glyph_sequence = ""; 	bool open = true;-	+ 	public static Glyph? background_glyph = null;-	+ 	bool empty = false;-	+ 	/** Id in the version list. */ 	public int version_id = 0;-	+ 	/** Cache quadratic form on export. */ 	GlyfData? ttf_data = null;-	+ 	Line left_line; 	Line right_line;-	+ 	/** Cache for Cairo rendering */ 	HashMap<string, Surface> glyph_cache = new HashMap<string, Surface> (); @@ -127,7 +127,7 @@ public class Glyph : FontDisplay {  	public static bool show_orientation_arrow = false; 	public static double orientation_arrow_opacity = 1;-	+ 	public Layer layers = new Layer (); 	public int current_layer = 0; 	public Gee.ArrayList<Path> active_paths = new Gee.ArrayList<Path> ();@@ -143,7 +143,7 @@ public class Glyph : FontDisplay { 		this.unichar_code = unichar_code;  		add_help_lines ();-		+ 		left_limit = -28; 		right_limit = 28; 	}@@ -156,7 +156,7 @@ public class Glyph : FontDisplay { 	public Gee.ArrayList<Path> get_active_paths () { 		return active_paths; 	}-	+ 	public Layer get_current_layer () { 		return_val_if_fail (0 <= current_layer < layers.subgroups.size, new Layer ()); 		return layers.subgroups.get (current_layer);@@ -171,10 +171,10 @@ public class Glyph : FontDisplay { 			} 			i++; 		}-		+ 		warning ("Layer is not added to glyph."); 	}-		+ 	public Gee.ArrayList<Path> get_visible_paths () { 		return layers.get_visible_paths ().paths; 	}@@ -182,36 +182,36 @@ public class Glyph : FontDisplay { 	public PathList get_visible_path_list () { 		return layers.get_visible_paths (); 	}-	+ 	public Gee.ArrayList<Path> get_paths_in_current_layer () { 		return get_current_layer ().get_all_paths ().paths; 	}-	+ 	public Gee.ArrayList<Path> get_all_paths () { 		return layers.get_all_paths ().paths; 	}-	+ 	public void add_new_layer () { 		layers.add_layer (new Layer ()); 		current_layer = layers.subgroups.size - 1; 	}-	+ 	public GlyfData get_ttf_data () { 		if (ttf_data == null) {-			+ 			ttf_data =  new GlyfData (this); 		}-		+ 		return (!) ttf_data; 	}-	+ 	public PathList get_quadratic_paths () { 		PointConverter pc; 		PathList pl; 		PathList stroke;  		pl = new PathList ();-		+ 		foreach (Path p in get_visible_paths ()) { 			if (p.stroke > 0) { 				stroke = p.get_stroke ();@@ -232,7 +232,7 @@ public class Glyph : FontDisplay { 		undo_list.clear (); 		redo_list.clear (); 	}-	+ 	public void set_empty_ttf (bool e) { 		empty = e; 	}@@ -241,24 +241,24 @@ public class Glyph : FontDisplay { 		return empty; 	} -	public void clear_active_paths () {	+	public void clear_active_paths () { 		selected_groups.clear (); 		active_paths.clear (); 	}-	+ 	public void add_active_path (Layer? group, Path? p) { 		Path path; 		Layer g;-		+ 		if (p != null) { 			path = (!) p;-			+ 			if (Toolbox.get_move_tool ().is_selected ()) { 				if (path.stroke > 0) { 					Toolbox.set_object_stroke (path.stroke); 				} 			}-			+ 			if (!active_paths.contains (path)) { 				active_paths.add (path); 			}@@ -272,21 +272,21 @@ public class Glyph : FontDisplay { 			} 		} 	}-	+ 	public void delete_background () { 		store_undo_state (); 		background_image = null; 		GlyphCanvas.redraw (); 	}-	+ 	public Path? get_active_path () { 		return_val_if_fail (active_paths.size > 0, null); 		return active_paths.get (active_paths.size - 1); 	}-	+ 	public bool boundaries (out double x1, out double y1, out double x2, out double y2) { 		var paths = get_all_paths ();-		+ 		if (paths.size == 0) { 			x1 = 0; 			y1 = 0;@@ -299,7 +299,7 @@ public class Glyph : FontDisplay { 		x2 = CANVAS_MIN; 		y1 = CANVAS_MAX; 		y2 = CANVAS_MIN;-	+ 		foreach (Path p in paths) { 			p.update_region_boundaries (); @@ -307,36 +307,36 @@ public class Glyph : FontDisplay { 				if (p.xmin < x1) { 					x1 = p.xmin; 				}-				+ 				if (p.xmax > x2) { 					x2 = p.xmax; 				}-				+ 				if (p.ymin < y1) { 					y1 = p.ymin; 				}-				+ 				if (p.ymax > y2) { 					y2 = p.ymax; 				} 			} 		}-		+ 		return x1 != double.MAX; 	}-	+ 	public void selection_boundaries (out double x, out double y, out double w, out double h) { 		double px, py, px2, py2;-		+ 		px = 10000; 		py = 10000; 		px2 = -10000; 		py2 = -10000;-				+ 		foreach (Path p in active_paths) { 			if (p.xmin < px) { 				px = p.xmin;-			} +			}  			if (p.ymin < py) { 				py = p.ymin;@@ -345,12 +345,12 @@ public class Glyph : FontDisplay { 			if (p.xmax > px2) { 				px2 = p.xmax; 			}-			+ 			if (p.ymax > py2) { 				py2 = p.ymax; 			} 		}-		+ 		if (px2 == -10000 || px == 10000) { 			warning (@"No box for selected paths. ($(active_paths.size))"); 			px = 0;@@ -360,15 +360,15 @@ public class Glyph : FontDisplay { 		}  		x = px;-		y = py2;		+		y = py2; 		w = px2 - px; 		h = py2 - py; 	}-	+ 	/** @return centrum pixel for x coordinates. */ 	public static double xc () { 		double c = MainWindow.get_current_glyph ().allocation.width / 2.0;-		return c;	+		return c; 	}  	/** @return centrum pixel for y coordinates. */@@ -387,7 +387,7 @@ public class Glyph : FontDisplay {  		a = Glyph.path_coordinate_x (0); 		b = Glyph.path_coordinate_y (0);-		+ 		this.allocation = alloc;  		c = Glyph.path_coordinate_x (0);@@ -399,24 +399,24 @@ public class Glyph : FontDisplay {  	public void set_background_image (BackgroundImage? b) { 		BackgroundImage bg;-		+ 		if (b == null) { 			background_image = null;-		} else {		+		} else { 			bg = (!) b; 			background_image = bg; 		}-		+ 		BirdFont.get_current_font ().touch (); 	}-	+ 	public BackgroundImage? get_background_image () { 		return background_image; 	}-		-	public override void scroll_wheel (double x, double y, ++	public override void scroll_wheel (double x, double y, 		double pixeldelta_x, double pixeldelta_y) {-			+ 		if (KeyBindings.has_alt () || KeyBindings.has_ctrl ()) { 			if (pixeldelta_y > 0) { 				zoom_in_at_point (x, y, pixeldelta_y);@@ -433,23 +433,23 @@ public class Glyph : FontDisplay { 				view_offset_y -= pixeldelta_x / view_zoom; 			} 		}-		+ 		redraw_area (0, 0, allocation.width, allocation.height); 	}-	+ 	public virtual void add_path (Path p) { 		if (layers.subgroups.size == 0) { 			layers.add_layer (new Layer ()); 		}-		+ 		get_current_layer ().add_path (p); 	}-	+ 	public override void selected_canvas () { 		TimeoutSource input_delay;-		+ 		ttf_data = null; // recreate quatradic path on export-		+ 		ignore_input = true; // make sure that tripple clicks in overview are ignored  		input_delay = new TimeoutSource (250);@@ -458,58 +458,58 @@ public class Glyph : FontDisplay { 			return false; 		}); 		input_delay.attach (null);-		+ 		add_help_lines (); 		KeyBindings.set_require_modifier (false); 		glyph_sequence = Preferences.get ("glyph_sequence");-		+ 		GridTool.update_lines ();-		+ 		if (!is_null (MainWindow.native_window)) { 			MainWindow.native_window.set_scrollbar_size (0); 		}-		+ 		update_zoom_bar (); 		DrawingTools.update_layers (); 		MainWindow.get_toolbox ().update_expanders (); 	}-	+ 	void update_zoom_bar () { 		if (!is_null (Toolbox.drawing_tools) 			&& !is_null (Toolbox.drawing_tools.zoom_bar)) { 			Toolbox.drawing_tools.zoom_bar.set_zoom ((view_zoom - 1) / 20); 		} 	}-	+ 	public void remove_lines () { 		vertical_help_lines.clear ();-		horizontal_help_lines.clear ();	+		horizontal_help_lines.clear (); 	}-	+ 	public void add_help_lines () { 		remove_lines ();-		+ 		return_if_fail (!is_null (BirdFont.get_current_font ()));-		+ 		double bgt = BirdFont.get_current_font ().top_limit; 		Line top_margin_line = new Line ("top margin", bgt, false); 		top_margin_line.set_color_theme ("Guide 2"); 		top_margin_line.position_updated.connect ((pos) => { 			BirdFont.get_current_font ().top_limit = pos; 		});-						+ 		double thp = BirdFont.get_current_font ().top_position; 		Line top_line = new Line ("top", thp, false); 		top_line.position_updated.connect ((pos) => { 				Font f = BirdFont.get_current_font (); 				f.top_position = pos; 			});-		+ 		double xhp = BirdFont.get_current_font ().xheight_position; 		Line xheight_line = new Line ("x-height", xhp, false); 		xheight_line.set_color_theme ("Guide 3"); 		xheight_line.dashed = true;-		xheight_line.position_updated.connect ((pos) => {				+		xheight_line.position_updated.connect ((pos) => { 				Font f = BirdFont.get_current_font (); 				f.xheight_position = pos; 			});@@ -520,7 +520,7 @@ public class Glyph : FontDisplay { 				Font f = BirdFont.get_current_font (); 				f.base_line = pos; 			});-		+ 		double bp = BirdFont.get_current_font ().bottom_position; 		Line bottom_line = new Line ("bottom", bp, false); 		bottom_line.position_updated.connect ((pos) => {@@ -533,7 +533,7 @@ public class Glyph : FontDisplay { 		bottom_margin_line.position_updated.connect ((pos) => { 			BirdFont.get_current_font ().bottom_limit = pos; 		});-					+ 		left_line = new Line ("left", left_limit, true); 		left_line.lsb = true; 		left_line.position_updated.connect ((pos) => {@@ -542,7 +542,7 @@ public class Glyph : FontDisplay { 			left_line.set_metrics (get_left_side_bearing ()); 		}); 		left_line.set_metrics (get_left_side_bearing ());-			+ 		right_line = new Line ("right", right_limit, true); 		right_line.rsb = true; 		right_line.position_updated.connect ((pos) => {@@ -551,10 +551,10 @@ public class Glyph : FontDisplay { 			right_line.set_metrics (get_right_side_bearing ()); 		}); 		right_line.set_metrics (get_right_side_bearing ());-		-		// lists of lines are sorted and lines are added only if ++		// lists of lines are sorted and lines are added only if 		// they are relevant for a particular glyph.-		+ 		// left to right 		add_line (left_line); 		add_line (right_line);@@ -564,29 +564,29 @@ public class Glyph : FontDisplay { 		// top to bottom 		add_line (top_margin_line); 		top_margin_line.set_visible (margin_boundaries_visible);-		+ 		add_line (top_line); 		top_line.set_visible (glyph_has_top || xheight_lines_visible);-		+ 		add_line (xheight_line); 		xheight_line.set_visible (!glyph_has_top || xheight_lines_visible);-		+ 		add_line (base_line);-		+ 		add_line (bottom_line); 		bottom_line.set_visible (CharDatabase.has_descender (unichar_code) || xheight_lines_visible);-		+ 		add_line (bottom_margin_line); 		bottom_margin_line.set_visible (margin_boundaries_visible);-		+ 		foreach (Line guide in BirdFont.get_current_font ().custom_guides) { 			add_line (guide); 		} 	}-	+ 	public double get_left_side_bearing () { 		double x1, y1, x2, y2;-		+ 		if (get_boundaries (out x1, out y1, out x2, out y2)) { 			return x1 - left_limit; 		} else {@@ -596,21 +596,21 @@ public class Glyph : FontDisplay {  	public double get_right_side_bearing () { 		double x1, y1, x2, y2;-		+ 		if (get_boundaries (out x1, out y1, out x2, out y2)) { 			return right_limit - x2; 		} else { 			return right_limit - left_limit; 		} 	}-	+ 	public bool get_boundaries (out double x1, out double y1, 		out double x2, out double y2) {-		+ 		double max_x, min_x, max_y, min_y; 		PathList pl; 		var paths = get_all_paths ();-		+ 		if (paths.size == 0) { 			x1 = 0; 			y1 = 0;@@ -618,18 +618,18 @@ public class Glyph : FontDisplay { 			y2 = 0; 			return false; 		}-				+ 		max_x = CANVAS_MIN; 		min_x = CANVAS_MAX; 		max_y = CANVAS_MIN; 		min_y = CANVAS_MAX;-		+ 		// FIXME: optimize 		foreach (Path p in paths) {-			+ 			if (p.stroke > 0) { 				pl = p.get_stroke_fast ();-				+ 				foreach (Path part in pl.paths) { 					boundaries_for_path (part, ref min_x, ref max_x, ref min_y, ref max_y); 				}@@ -642,20 +642,20 @@ public class Glyph : FontDisplay { 		y1 = max_y; 		x2 = max_x; 		y2 = min_y;-		+ 		return max_x != CANVAS_MIN; 	}-	+ 	void boundaries_for_path (Path p, ref double min_x, ref double max_x, 		ref double min_y, ref double max_y) {-		+ 		double max_x2, max_y2, min_x2, min_y2;  		max_x2 = max_x; 		min_x2 = min_x; 		max_y2 = max_y; 		min_y2 = min_y;-				+ 		p.all_of_path ((x, y, t) => { 			if (x > max_x2) { 				max_x2 = x;@@ -668,20 +668,20 @@ public class Glyph : FontDisplay { 			if (x < min_x2) { 				min_x2 = x; 			}-			+ 			if (y < min_y2) { 				min_y2 = y; 			}-			+ 			return true;-		});	-		+		});+ 		max_x = max_x2; 		min_x = min_x2; 		max_y = max_y2; 		min_y = min_y2; 	}-	+ 	bool has_top_line () { 		return !unichar_code.islower () || CharDatabase.has_ascender (unichar_code); 	}@@ -689,7 +689,7 @@ public class Glyph : FontDisplay { 	public bool get_show_help_lines () { 		return show_help_lines; 	}-		+ 	/** Show both x-height and top lines. */ 	public bool get_xheight_lines_visible () { 		return xheight_lines_visible;@@ -700,16 +700,16 @@ public class Glyph : FontDisplay { 		xheight_lines_visible = x; 		add_help_lines (); 	}-		+ 	public void set_margin_lines_visible (bool m) { 		margin_boundaries_visible = m; 		add_help_lines (); 	}-	+ 	public bool get_margin_lines_visible () { 		return margin_boundaries_visible; 	}-	+ 	public void remove_empty_paths () { 		foreach (Path p in get_all_paths ()) { 			if (p.points.size < 2) {@@ -719,20 +719,20 @@ public class Glyph : FontDisplay { 			} 		} 	}-	+ 	public void delete_path (Path p) { 		layers.remove_path(p); 	}-	+ 	public string get_svg_data () { 		return Svg.to_svg_glyph (this); 	}-	+ 	public int get_height () { 		Font f = BirdFont.get_current_font ();-		return (int) Math.fabs (f.top_limit - f.bottom_limit); +		return (int) Math.fabs (f.top_limit - f.bottom_limit); 	}-	+ 	public double get_width () { 		return Math.fabs (right_limit - left_limit); 	}@@ -743,23 +743,23 @@ public class Glyph : FontDisplay {  	public string get_unichar_string () { 		string? s = (!)get_unichar ().to_string ();-		+ 		if (unlikely (s == null)) { 			warning ("Invalid character."); 			return "".dup (); 		}-		+ 		return (!) s; 	}-	+ 	public void redraw_help_lines () { 		redraw_area (0, 0, allocation.width, allocation.height); 	}-	+ 	public void set_show_help_lines (bool hl) { 		show_help_lines = hl; 	}-	+ 	private void add_line (Line line) { 		if (line.is_vertical ()) { 			vertical_help_lines.add (line);@@ -768,12 +768,12 @@ public class Glyph : FontDisplay { 		}  		sort_help_lines ();-		+ 		line.queue_draw_area.connect ((x, y, w, h) => { 			this.redraw_area (x, y, w, h); 		}); 	}-	+ 	public void sort_help_lines () { 		vertical_help_lines.sort ((a, b) => { 			Line first, next;@@ -781,7 +781,7 @@ public class Glyph : FontDisplay { 			next = (Line) b; 			return (int) (first.get_pos () - next.get_pos ()); 		});-		+ 		horizontal_help_lines.sort ((a, b) => { 			Line first, next; 			first = (Line) a;@@ -789,7 +789,7 @@ public class Glyph : FontDisplay { 			return (int) (first.get_pos () - next.get_pos ()); 		}); 	}-	+ 	public override string get_name () { 		return name; 	}@@ -797,10 +797,10 @@ public class Glyph : FontDisplay { 	public override string get_label () { 		return name; 	}-				+ 	private void help_line_event (int x, int y) { 		bool m = false;-		+ 		foreach (Line line in vertical_help_lines) { 			if (!m && line.event_move_to (x, y, allocation)) { 				m = true;@@ -814,7 +814,7 @@ public class Glyph : FontDisplay { 		} 	} -	public override void key_release (uint keyval) {	+	public override void key_release (uint keyval) { 		Tool t; 		t = MainWindow.get_toolbox ().get_current_tool (); 		t.key_release_action (t, keyval);@@ -824,10 +824,10 @@ public class Glyph : FontDisplay { 		} 	} -	public override void key_press (uint keyval) {	+	public override void key_press (uint keyval) { 		Tool t = MainWindow.get_toolbox ().get_current_tool (); 		t.key_press_action (t, keyval);-		+ 		if (keyval == (uint)' ') { 			move_canvas = true; 		}@@ -843,7 +843,7 @@ public class Glyph : FontDisplay { 	}  	/** Delete edit point from path.-	 * @return false if no points was deleted +	 * @return false if no points was deleted 	 */ 	public bool process_deleted () { 		Gee.ArrayList<Path> deleted_paths = new Gee.ArrayList<Path> ();@@ -856,14 +856,14 @@ public class Glyph : FontDisplay { 				deleted_paths.add (p); 			} 		}-		+ 		foreach (Path p in deleted_paths) { 			delete_path (p); 		}-		+ 		return false; 	}-	+ 	private bool process_deleted_points_in_path (Path p) { 		PathList remaining_points; 		remaining_points = p.process_deleted_points ();@@ -871,37 +871,37 @@ public class Glyph : FontDisplay { 			add_path (path); 			path.reopen (); 			path.create_list ();-			+ 			add_active_path (null, path); 		}-		+ 		if (remaining_points.paths.size > 0) { 			delete_path (p); 			return true; 		}-		+ 		return false; 	}-	+ 	public override void motion_notify (double x, double y) { 		Tool t = MainWindow.get_toolbox ().get_current_tool ();-		+ 		if (view_is_moving) { 			move_view_offset  (x, y); 			return; 		}-		+ 		help_line_event ((int) x, (int) y); 		t.move_action (t, (int) x, (int) y);  		motion_x = x * ivz () - xc () + view_offset_x; 		motion_y = yc () - y * ivz () - view_offset_y; 	}-	+ 	public override void button_release (int button, double ex, double ey) { 		bool line_moving = false; 		view_is_moving = false;-		+ 		foreach (Line line in get_all_help_lines ()) { 			if (!line.set_move (false)) { 				line_moving = true;@@ -912,13 +912,13 @@ public class Glyph : FontDisplay { 			Tool t = MainWindow.get_toolbox ().get_current_tool (); 			t.release_action (t, (int) button, (int) ex, (int) ey); 		}-		+ 		update_view (); 	}  	private Gee.ArrayList<Line> get_all_help_lines () { 		Gee.ArrayList<Line> all_lines = new Gee.ArrayList<Line> ();-		+ 		foreach (Line l in vertical_help_lines) { 			all_lines.add (l); 		}@@ -926,35 +926,35 @@ public class Glyph : FontDisplay { 		foreach (Line l in horizontal_help_lines) { 			all_lines.add (l); 		}-				+ 		if (GridTool.is_visible ()) { 			foreach (Line l in GridTool.get_vertical_lines ()) { 				all_lines.add (l); 			}-			+ 			foreach (Line l in GridTool.get_horizontal_lines ()) { 				all_lines.add (l); 			} 		}-		+ 		return all_lines; 	}-		+ 	public void update_view () { 		GlyphCanvas.redraw (); 	}-	-	public override void double_click (uint button, double ex, double ey) {	++	public override void double_click (uint button, double ex, double ey) { 		Tool t = MainWindow.get_toolbox ().get_current_tool (); 		t.double_click_action (t, (int) button, (int) ex, (int) ey); 	}-	-	public override void button_press (uint button, double ex, double ey) {				++	public override void button_press (uint button, double ex, double ey) { 		bool moving_lines = false;-			+ 		pointer_begin_x = ex; 		pointer_begin_y = ey;-		+ 		foreach (Line line in horizontal_help_lines) { 			if (!moving_lines && line.is_visible () && line.button_press (button)) { 				moving_lines = true;@@ -966,11 +966,11 @@ public class Glyph : FontDisplay { 				moving_lines = true; 			} 		}-				+ 		if (moving_lines) { 			return; 		}-			+ 		if (move_canvas || DrawingTools.move_canvas.is_selected ()) { 			view_is_moving = true; 			move_offset_x = view_offset_x;@@ -992,9 +992,9 @@ public class Glyph : FontDisplay { 	public void set_center (double x, double y) { 		x -= allocation.width / 2.0; 		y -= allocation.height / 2.0;-		+ 		view_offset_x += x / view_zoom;-		view_offset_y += y / view_zoom;		+		view_offset_y += y / view_zoom; 	}  	public void set_zoom_from_area () {@@ -1003,7 +1003,7 @@ public class Glyph : FontDisplay {  		double w = Math.fabs (zoom_x1 - zoom_x2); 		double h = Math.fabs (zoom_y1 - zoom_y2);-		+ 		double view_zoom_x, view_zoom_y; 		double ivz, off; @@ -1016,57 +1016,57 @@ public class Glyph : FontDisplay { 		} else { 			view_offset_x += x / view_zoom; 			view_offset_y += y / view_zoom;-			+ 			if (unlikely (allocation.width == 0 || allocation.height == 0)) { 				return; 			}-			+ 			view_zoom_x = allocation.width * view_zoom / w; 			view_zoom_y = allocation.height * view_zoom / h;-					+ 			// TODO: there is a max zoom level-			+ 			if (view_zoom_x * allocation.width < view_zoom_y * allocation.height) { 				view_zoom = view_zoom_x; 				ivz = 1 / view_zoom; -				off = (view_zoom / view_zoom_y) * allocation.height / view_zoom;	+				off = (view_zoom / view_zoom_y) * allocation.height / view_zoom; 				off = allocation.height/view_zoom - off; 				off /= 2;-				+ 				view_offset_y -= off;  			} else { 				view_zoom = view_zoom_y; 				ivz = 1 / view_zoom; -				off = (view_zoom / view_zoom_x) * allocation.width / view_zoom;	+				off = (view_zoom / view_zoom_x) * allocation.width / view_zoom; 				off = allocation.width / view_zoom - off;-				off /= 2;			+				off /= 2;  				view_offset_x -= off; 			}-			+ 			zoom_area_is_visible = false; 			store_current_view (); 		}-		+ 		update_zoom_bar (); 	}-	+ 	public void show_zoom_area (int sx, int sy, int nx, int ny) { 		double x, y, w, h;-				+ 		set_zoom_area (sx, sy, nx, ny);-		+ 		zoom_area_is_visible = true;-		+ 		x = Math.fmin (zoom_x1, zoom_x2) - 50; 		y = Math.fmin (zoom_y1, zoom_y2) - 50;  		w = Math.fabs (zoom_x1 - zoom_x2) + 100; 		h = Math.fabs (zoom_y1 - zoom_y2) + 100;-				+ 		redraw_area ((int)x, (int)y, (int)w, (int)h); 	} @@ -1082,13 +1082,13 @@ public class Glyph : FontDisplay { 		if (unlikely (g.view_zoom == 0)) { 			warning ("Zoom is zero."); 			g.reset_zoom ();-			+ 			if (g.view_zoom == 0) { 				g.view_zoom = 1; 				g.view_offset_x = 0; 				g.view_offset_y = 0; 			}-		}	+		} 	}  	public static double path_coordinate_x (double x) {@@ -1108,7 +1108,7 @@ public class Glyph : FontDisplay { 		validate_zoom (); 		return (x - g.view_offset_x + xc ()) * g.view_zoom; 	}-	+ 	public static double path_coordinate_y (double y) { 		Glyph g = MainWindow.get_current_glyph (); 		validate_zoom ();@@ -1118,14 +1118,14 @@ public class Glyph : FontDisplay { 	public static int reverse_path_coordinate_y (double y) { 		Glyph g = MainWindow.get_current_glyph (); 		validate_zoom ();-		y =  Math.rint ((y + g.view_offset_y - yc ()) * g.view_zoom);	+		y =  Math.rint ((y + g.view_offset_y - yc ()) * g.view_zoom); 		return (int) (-y); 	}  	public static double precise_reverse_path_coordinate_y (double y) { 		Glyph g = MainWindow.get_current_glyph (); 		validate_zoom ();-		y = (y + g.view_offset_y - yc ()) * g.view_zoom;	+		y = (y + g.view_offset_y - yc ()) * g.view_zoom; 		return -y; 	} @@ -1141,7 +1141,7 @@ public class Glyph : FontDisplay { 				} 			} 		}-					+ 		if (!found) { 			foreach (Path pt in get_paths_in_current_layer ()) { 				if (pt.is_over (x, y)) {@@ -1153,43 +1153,43 @@ public class Glyph : FontDisplay { 				} 			} 		}-		+ 		return group; 	}-		+ 	public bool select_path (double x, double y) { 		Path? p = null; 		bool found = false;-		+ 		foreach (Path pt in get_paths_in_current_layer ()) { 			if (pt.is_over (x, y)) { 				p = pt; 				found = true; 			} 		}-		+ 		if (!KeyBindings.has_shift ()) { 			clear_active_paths (); 		}-		+ 		add_active_path (null, p);-		+ 		return found; 	}-	+ 	public bool is_over_selected_path (double x, double y) { 		foreach (Path pt in active_paths) { 			if (pt.is_over (x, y)) { 				return true; 			} 		}-		return false;		+		return false; 	}-		+ 	public void queue_redraw_path (Path path) { 		redraw_path (path.xmin, path.ymin, path.xmax, path.ymax); 	}-	+ 	private void redraw_path (double xmin, double ymin, double xmax, double ymax) { 		int yc = (int)(allocation.height / 2.0); @@ -1205,7 +1205,7 @@ public class Glyph : FontDisplay { 	public Path get_closeset_path (double x, double y) { 		double d; 		EditPoint ep = new EditPoint ();-		+ 		Path min_point = new Path (); 		double min_distance = double.MAX; @@ -1221,17 +1221,17 @@ public class Glyph : FontDisplay {  		foreach (Path p in paths) { 			if (p.points.size == 0) continue;-			+ 			p.get_closest_point_on_path (ep, xt, yt); 			d = Math.pow (ep.x - xt, 2) + Math.pow (ep.y - yt, 2);-			+ 			if (d < min_distance) { 				min_distance = d; 				min_point = p; 			}  		}-		+ 		// a path without any editpoints 		if (paths.size > 0) { 			return paths.get (0);@@ -1240,47 +1240,47 @@ public class Glyph : FontDisplay { 		if (unlikely (min_distance == double.MAX)) { 			warning (@"No path found in path_list."); 		}-		+ 		return min_point; 	}-	-	public void move_selected_edit_point_coordinates (EditPoint selected_point, double xt, double yt) {	++	public void move_selected_edit_point_coordinates (EditPoint selected_point, double xt, double yt) { 		double x, y;-				+ 		BirdFont.get_current_font ().touch ();  		x = reverse_path_coordinate_x (xt); 		y = reverse_path_coordinate_y (yt);-		+ 		// redraw control point 		redraw_area ((int)(x - 4*view_zoom), (int)(y - 4*view_zoom), (int)(x + 3*view_zoom), (int)(y + 3*view_zoom));-		+ 		// update position of selected point 		selected_point.set_position (xt, yt);-		+ 		if (view_zoom >= 2) { 			redraw_area (0, 0, allocation.width, allocation.height); 		} else { 			redraw_last_stroke (x, y);-		}	+		} 	} -	public void move_selected_edit_point (EditPoint selected_point, double x, double y) {		+	public void move_selected_edit_point (EditPoint selected_point, double x, double y) { 		double xt = path_coordinate_x (x); 		double yt = path_coordinate_y (y); 		move_selected_edit_point_coordinates (selected_point, xt, yt); 	}-	+ 	public void redraw_segment (EditPoint a, EditPoint b) { 		double margin = 10; 		double x = Math.fmin (reverse_path_coordinate_x (a.x), reverse_path_coordinate_x (b.x)) - margin; 		double y = Math.fmin (reverse_path_coordinate_y (a.y), reverse_path_coordinate_y(b.y)) - margin; 		double w = Math.fabs (reverse_path_coordinate_x (a.x) - reverse_path_coordinate_x(b.x)) + 2 * margin; 		double h = Math.fabs (reverse_path_coordinate_y (a.y) - reverse_path_coordinate_y (b.y)) + 2 * margin;-				+ 		redraw_area ((int)x, (int)y, (int)w, (int)h); 	}-	+ 	private void redraw_last_stroke (double x, double y) { 		// redraw line, if we have more than one new point on path 		double px = 0;@@ -1293,23 +1293,23 @@ public class Glyph : FontDisplay { 		if (active_paths.size == 0) { 			return; 		}-		+ 		foreach (Path path in active_paths) { 			EditPoint p; 			EditPoint pl = path.get_last_point ();-			+ 			if (pl.prev != null) { 				p = pl.get_prev ();-				+ 				px = p.x + xc; 				py = p.y - xc;-								+ 				tw = (px > x) ? (int) (px - x) : (int) (x - px); 				th = (py > y) ? (int) (py - y) : (int) (y - py);-				+ 				if (px > x) px -= tw + 60; 				if (py > y) py -= th + 60;-				+ 			} else { 				px = x - 60; 				py = y - 60;@@ -1317,18 +1317,18 @@ public class Glyph : FontDisplay { 				th = 0; 			} 		}-		-		redraw_area ((int)px - 20, (int)py - 20, tw + 120, th + 120); 		++		redraw_area ((int)px - 20, (int)py - 20, tw + 120, th + 120); 	}-	+ 	public bool has_active_path () { 		return active_paths.size > 0; 	}-	+ 	public bool is_open () { 		return open; 	}-	+ 	/** Close all editable paths and return false if no path have been closed. */ 	public bool close_path () { 		bool r = false;@@ -1337,15 +1337,15 @@ public class Glyph : FontDisplay { 			if (p.is_editable ()) { 				r = true; 				p.set_editable (false);-			}			+			} 		}-		+ 		open = false; 		clear_active_paths (); 		GlyphCanvas.redraw ();-		+ 		MainWindow.set_cursor (NativeWindow.VISIBLE);-		+ 		return r; 	} @@ -1353,7 +1353,7 @@ public class Glyph : FontDisplay { 		foreach (Path p in get_visible_paths ()) { 			p.set_editable (true); 			p.recalculate_linear_handles ();-			+ 			if (p.is_open () && p.points.size > 0) { 				p.get_first_point ().set_reflective_handles (false); 				p.get_first_point ().set_tie_handle (false);@@ -1361,52 +1361,52 @@ public class Glyph : FontDisplay { 				p.get_last_point ().set_tie_handle (false); 			} 		}-		+ 		open = true; 		redraw_area (0, 0, allocation.width, allocation.height); 	}-	+ 	public void redraw_path_region (Path p) { 		int x, y, w, h;-			+ 		p.update_region_boundaries ();-		+ 		x = reverse_path_coordinate_x (p.xmin); 		y = reverse_path_coordinate_x (p.xmin); 		w = reverse_path_coordinate_x (p.xmax) - x; 		h = reverse_path_coordinate_x (p.ymax) - y; // FIXME: redraw path-					-		redraw_area (x, y, w, h);		++		redraw_area (x, y, w, h); 	} -	public Line get_line (string name) {		+	public Line get_line (string name) { 		foreach (Line line in vertical_help_lines) { 			if (likely (line.get_label () == name)) { 				return line; 			} 		}-		+ 		foreach (Line line in horizontal_help_lines) { 			if (likely (line.get_label () == name)) { 				return line; 			} 		}-		+ 		warning (@"No line with label $name found"); 		return new Line ("Err"); 	}-	+ 	public override void zoom_in () { 		if (move_canvas) { 			return; 		}-		+ 		set_zoom_area (10, 10, allocation.width - 10, allocation.height - 10); 		set_zoom_from_area (); 		update_view (); 		update_zoom_bar (); 	}-	+ 	public override void zoom_out () { 		double w = allocation.width; 		int n = (int) (10 * ((w - 10) / allocation.width));@@ -1415,35 +1415,35 @@ public class Glyph : FontDisplay { 		update_view (); 		update_zoom_bar (); 	}-	+ 	public override void zoom_max () { 		default_zoom (); 		update_zoom_bar (); 	}-	+ 	public override void zoom_min () { 		double ax =  1000; 		double ay =  1000; 		double bx = -1000; 		double by = -1000;-		+ 		int iax, iay, ibx, iby;-		+ 		reset_zoom ();  		foreach (var p in get_visible_paths ()) { 			p.update_region_boundaries ();-			+ 			if (p.points.size > 2) { 				if (p.xmin < ax) ax = p.xmin;-				if (p.ymin < ay) ay = p.ymin;			+				if (p.ymin < ay) ay = p.ymin; 				if (p.xmax > bx) bx = p.xmax; 				if (p.ymax > by) by = p.ymax; 			} 		}-	+ 		if (ax == 1000) return; // empty page-		+ 		iax = (int) ((ax + view_offset_x + allocation.width / 2.0) * view_zoom); 		iay = (int) ((-ay + view_offset_y + allocation.height / 2.0) * view_zoom); 		ibx = (int) ((bx + view_offset_x + allocation.width / 2.0) * view_zoom);@@ -1452,81 +1452,81 @@ public class Glyph : FontDisplay { 		show_zoom_area (iax, iay, ibx, iby); // set this later on button release 		set_zoom_from_area (); 		zoom_out (); // add some margin-		+ 		redraw_area (0, 0, allocation.width, allocation.height); 		update_zoom_bar (); 	}  	public override void store_current_view () { 		ZoomView n;-		+ 		if (zoom_list_index + 1 < zoom_list.size) { 			n = zoom_list.get (zoom_list_index); 			while (n != zoom_list.get (zoom_list.size - 1)) { 				zoom_list.remove_at (zoom_list.size - 1); 			} 		}-		+ 		zoom_list.add (new ZoomView (view_offset_x, view_offset_y, view_zoom, allocation)); 		zoom_list_index = (int) zoom_list.size - 1;-		+ 		if (zoom_list.size > 50) { 			zoom_list.remove_at (0); 		} 	}-	+ 	public override void restore_last_view () { 		if (zoom_list.size == 0 || zoom_list_index - 1 < 0) { 			return; 		}-		+ 		zoom_list_index--;-			+ 		ZoomView z = zoom_list.get (zoom_list_index);-		+ 		view_offset_x = z.x; 		view_offset_y = z.y; 		view_zoom = z.zoom; 		allocation = z.allocation;-		+ 		update_zoom_bar (); 	}  	public override void next_view () { 		ZoomView z;-		+ 		if (zoom_list.size == 0 || zoom_list_index + 1 >= zoom_list.size) { 			return; 		}-		+ 		zoom_list_index++;-		+ 		z = zoom_list.get (zoom_list_index);-			+ 		view_offset_x = z.x; 		view_offset_y = z.y; 		view_zoom = z.zoom; 		allocation = z.allocation;-		-		update_zoom_bar ();		++		update_zoom_bar (); 	}-	+ 	public override void reset_zoom () { 		view_offset_x = 0; 		view_offset_y = 0;-		+ 		set_zoom (1);-		+ 		store_current_view (); 		update_zoom_bar (); 	}-	+ 	/** Get x-height or top line. */ 	public Line get_upper_line () { 		if (has_top_line () || xheight_lines_visible) { 			return get_line ("top"); 		}-		+ 		return get_line ("x-height"); 	} @@ -1534,72 +1534,72 @@ public class Glyph : FontDisplay { 	public Line get_lower_line () { 		return get_line ("baseline"); 	}-		+ 	/** Set default zoom. See default_zoom. */ 	public void set_default_zoom () { 		int bottom = 0; 		int top = 0; 		int left = 0; 		int right = 0;-	+ 		return_if_fail (vertical_help_lines.size != 0); 		return_if_fail (horizontal_help_lines.size != 0);  		reset_zoom ();-		+ 		bottom = get_lower_line ().get_position_pixel (); 		top = get_upper_line ().get_position_pixel ();  		left = vertical_help_lines.get (vertical_help_lines.size - 1).get_position_pixel (); 		right = vertical_help_lines.get (0).get_position_pixel ();-		+ 		set_zoom_area (left + 10, top - 10, right - 10, bottom + 10); 		set_zoom_from_area (); 	}-	+ 	/** Set default zoom and redraw canvas. */ 	public void default_zoom () { 		set_default_zoom (); 		update_view (); 	}-	+ 	public bool is_empty () { 		foreach (Path p in get_visible_paths ()) { 			if (p.points.size > 0) { 				return false; 			} 		}-		+ 		return true; 	}-	+ 	public void set_zoom (double z) 		requires (z > 0)-	{		+	{ 		view_zoom = z; 	}  	public void set_background_visible (bool visibility) { 		background_image_visible = visibility; 	}-	+ 	public bool get_background_visible () { 		return background_image_visible; 	}-	+ 	public void draw_coordinate (Context cr) { 		Theme.color (cr, "Table Border"); 		cr.set_font_size (12); 		cr.move_to (0, 10); 		cr.show_text (@"($motion_x, $motion_y)");-		cr.stroke ();		+		cr.stroke (); 	}-	+ 	/** Draw filled paths. */ 	public void draw_paths (Context cr, Color? c = null) { 		PathList stroke; 		Color color;-		+ 		cr.save (); 		cr.new_path (); 		foreach (Path p in get_visible_paths ()) {@@ -1610,7 +1610,7 @@ public class Glyph : FontDisplay { 			} else { 				color = Color.black (); 			}-			+ 			if (p.stroke > 0) { 				stroke = p.get_stroke_fast (); 				draw_path_list (stroke, cr, color);@@ -1621,24 +1621,24 @@ public class Glyph : FontDisplay { 		cr.fill (); 		cr.restore (); 	}-	+ 	public void draw_path (Context cr) { 		PathList stroke; 		Color color;-		+ 		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 = Theme.get_color ("Filled Stroke"); 					color.a = 0.8; 				} else { 					color = Color.black (); 				}-				+ 				draw_path_list (stroke, cr, color); 			} 		}@@ -1661,7 +1661,7 @@ public class Glyph : FontDisplay { 			cr.fill (); 			cr.restore (); 		}-			+ 		if (is_open () && Path.fill_open_path) { 			cr.save (); 			cr.new_path ();@@ -1674,7 +1674,7 @@ public class Glyph : FontDisplay { 			cr.fill (); 			cr.restore (); 		}-						+ 		if (is_open ()) { 			cr.save (); 			cr.new_path ();@@ -1684,11 +1684,11 @@ public class Glyph : FontDisplay { 			} 			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 (); 			foreach (Path p in get_visible_paths ()) {@@ -1700,7 +1700,7 @@ public class Glyph : FontDisplay { 			cr.close_path (); 			cr.fill (); 			cr.restore ();-			+ 			foreach (Path p in active_paths) { 				cr.save (); 				cr.new_path ();@@ -1712,25 +1712,25 @@ public class Glyph : FontDisplay { 				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); 				} 			} 		} 	}-	+ 	private Color get_path_fill_color () { 		return Theme.get_color ("Fill Color"); 	}-	+ 	public void draw_path_list (PathList pl, Context cr, Color? c = null) { 		foreach (Path p in pl.paths) { 			p.draw_path (cr, this, c);@@ -1746,7 +1746,7 @@ public class Glyph : FontDisplay { 			cr.restore (); 		} 	}-	+ 	public void draw_help_lines (Context cr) { 		foreach (Line line in get_all_help_lines ()) { 			cr.save ();@@ -1754,20 +1754,20 @@ public class Glyph : FontDisplay { 			cr.restore (); 		} 	}-	+ 	public void set_allocation (WidgetAllocation a) { 		allocation = a; 	}-	+ 	public override void draw (WidgetAllocation allocation, Context cmp) { 		Tool tool;-			+ 		this.allocation = allocation;-		+ 		cmp.save (); 		draw_background_color (cmp, 1); 		cmp.restore ();-		+ 		if (background_image != null && background_image_visible) { 			((!)background_image).draw (cmp, allocation, view_offset_x, view_offset_y, view_zoom); 		}@@ -1777,7 +1777,7 @@ public class Glyph : FontDisplay { 				p.draw_boundaries (cmp); 			} 		}-		+ 		draw_background_glyph (allocation, cmp); 		juxtapose (allocation, cmp); @@ -1799,23 +1799,23 @@ public class Glyph : FontDisplay { 			cmp.restore (); 		} -		cmp.save (); +		cmp.save (); 		tool = MainWindow.get_toolbox ().get_current_tool (); 		tool.draw_action (tool, cmp, this); 		cmp.restore ();-	}	+	}  	private void zoom_in_at_point (double x, double y, double amount = 15) { 		int n = (int) (-amount); 		zoom_at_point (x, y, n); 	}-		+ 	private void zoom_out_at_point (double x, double y, double amount = 15) { 		double a = -amount; 		int n = (int) (a * ((allocation.width - a) / allocation.width)); 		zoom_at_point (x, y, n); 	}-	+ 	public void zoom_tap (double distance) { 		int w = (int) (distance); 		if (distance != 0) {@@ -1823,22 +1823,22 @@ public class Glyph : FontDisplay { 			set_zoom_from_area (); 		} 	}-	+ 	/** Zoom in @param n pixels. */ 	private void zoom_at_point (double x, double y, int n) { 		double w = allocation.width; 		double h = allocation.height;-		+ 		double rx = Math.fabs (w / 2 - x) / (w / 2); 		double ry = Math.fabs (h / 2 - y) / (h / 2);-		+ 		int xd = (x < w / 2) ? (int) (n * rx) : (int) (-n * rx); 		int yd = (y < h / 2) ? (int) (n * ry) : (int) (-n * ry);-			+ 		show_zoom_area (-n + xd, -n + yd, allocation.width + n + xd, allocation.height + n + yd); 		set_zoom_from_area (); 	}-	+ 	private void move_view_offset (double x, double y) { 		view_offset_x = move_offset_x + (pointer_begin_x - x) * (1/view_zoom); 		view_offset_y = move_offset_y + (pointer_begin_y - y) * (1/view_zoom);@@ -1848,7 +1848,7 @@ public class Glyph : FontDisplay { 	public void store_undo_state (bool clear_redo = false) { 		Glyph g = copy (); 		undo_list.add (g);-		+ 		if (clear_redo) { 			redo_list.clear (); 		}@@ -1856,29 +1856,29 @@ public class Glyph : FontDisplay {  	public void store_redo_state () { 		Glyph g = copy ();-		redo_list.add (g);	+		redo_list.add (g); 	}  	public Glyph copy () { 		Glyph g = new Glyph.no_lines (name, unichar_code);-		+ 		g.current_layer = current_layer;-		+ 		g.left_limit = left_limit; 		g.right_limit = right_limit;-		+ 		g.remove_lines ();-		+ 		foreach (Line line in get_all_help_lines ()) { 			g.add_line (line.copy ()); 		}-		+ 		g.layers = layers.copy ();-		+ 		foreach (Path p in active_paths) { 			g.active_paths.add (p); 		}-		+ 		if (background_image != null) { 			g.background_image = ((!) background_image).copy (); 		}@@ -1886,13 +1886,13 @@ public class Glyph : FontDisplay { 		g.empty = empty; 		g.open = open; 		g.version_id = version_id;-		+ 		return g; 	}  	public void reload () { 		Font f = BirdFont.get_current_font ();-		+ 		if (f.has_glyph (name)) { 			set_glyph_data ((!) f.get_glyph (name)); 		}@@ -1901,49 +1901,49 @@ public class Glyph : FontDisplay { 	public override void undo () { 		Glyph g; 		Tool tool;-		+ 		if (undo_list.size == 0) { 			return; 		}-		+ 		tool = MainWindow.get_toolbox ().get_current_tool (); 		tool.before_undo ();-		-		g = undo_list.get (undo_list.size - 1);	-		++		g = undo_list.get (undo_list.size - 1);+ 		store_redo_state (); 		set_glyph_data (g);-		+ 		undo_list.remove_at (undo_list.size - 1);-		+ 		DrawingTools.update_layers (); 		PenTool.update_selected_points ();-		+ 		clear_active_paths ();-		+ 		tool.after_undo (); 	}  	public override void redo () { 		Glyph g;-		+ 		if (redo_list.size == 0) { 			return; 		}-		-		g = redo_list.get (redo_list.size - 1);	-		++		g = redo_list.get (redo_list.size - 1);+ 		store_undo_state (false); 		set_glyph_data (g);-		+ 		redo_list.remove_at (redo_list.size - 1);  		DrawingTools.update_layers (); 		PenTool.update_selected_points ();-		+ 		clear_active_paths (); 	}-	+ 	void set_glyph_data (Glyph g) { 		current_layer = g.current_layer; 		layers = g.layers.copy ();@@ -1954,17 +1954,17 @@ public class Glyph : FontDisplay { 		}  		add_help_lines ();-		+ 		if (g.background_image != null) { 			background_image = ((!) g.background_image).copy (); 		}-		+ 		clear_active_paths (); 		foreach (Path p in g.active_paths) { 			add_active_path (null, p); 		} -		redraw_area (0, 0, allocation.width, allocation.height);		+		redraw_area (0, 0, allocation.width, allocation.height); 	}  	/** Split curve in two parts and add a new point in between.@@ -1976,20 +1976,20 @@ public class Glyph : FontDisplay { 		Path path; 		EditPoint? np = null; 		EditPoint lep;-		+ 		double xt; 		double yt;  		xt = x * ivz () - xc () + view_offset_x; 		yt = yc () - y * ivz () - view_offset_y;-		+ 		min = double.MAX;-		+ 		foreach (Path pp in get_visible_paths ()) { 			lep = new EditPoint (); 			pp.get_closest_point_on_path (lep, xt, yt); 			distance = Math.sqrt (Math.pow (Math.fabs (xt - lep.x), 2) + Math.pow (Math.fabs (yt - lep.y), 2));-			+ 			if (distance < min) { 				min = distance; 				p = pp;@@ -2000,18 +2000,18 @@ public class Glyph : FontDisplay { 		if (p == null) { 			return; 		}-		+ 		path = (!) p;  		lep = new EditPoint (); 		path.get_closest_point_on_path (lep, xt, yt); 		path.insert_new_point_on_path (lep); 	}-	+ 	static bool in_range (double offset_x, double coordinate_x1, double coordinate_x2) { 		return coordinate_x1 <= offset_x <= coordinate_x2; 	}-	+ 	public void juxtapose (WidgetAllocation allocation, Context cr) { 		string glyph_sequence = Preferences.get ("glyph_sequence"); 		unichar c;@@ -2024,22 +2024,22 @@ public class Glyph : FontDisplay { 		double x, kern; 		double left, baseline; 		string last_name;-		+ 		double box_x1, box_x2, box_y1, box_y2; 		double marker_x, marker_y;-		+ 		KerningClasses classes = font.get_kerning_classes ();-		+ 		x = 0;-		+ 		box_x1 = path_coordinate_x (0); 		box_y1 = path_coordinate_y (0); 		box_x2 = path_coordinate_x (allocation.width); 		box_y2 = path_coordinate_y (allocation.height);-		+ 		current.append_unichar (glyph.unichar_code); 		pos = glyph_sequence.index_of (current.str);-		+ 		baseline = font.base_line;; 		left = glyph.get_line ("left").pos; @@ -2047,22 +2047,22 @@ public class Glyph : FontDisplay { 		last_name = glyph.name; 		for (int i = pos + 1; i < glyph_sequence.char_count (); i++) { 			c = glyph_sequence.get_char (i);-			name = (!) c.to_string ();			+			name = (!) c.to_string (); 			juxtaposed = (font.has_glyph (name)) ? (!) font.get_glyph (name) : font.get_space ().get_current ();-			+ 			if (font.has_glyph (last_name) && font.has_glyph (name)) { 				kern = classes.get_kerning (last_name, name); 			} else { 				kern = 0; 			}-			+ 			if (!juxtaposed.is_empty () 				&& (in_range (left + x + kern, box_x1, box_x2) // the letter is visible 				|| in_range (left + x + kern + juxtaposed.get_width (), box_x1, box_x2))) {  				marker_x = Glyph.xc () + left + x + kern - glyph.view_offset_x; 				marker_y = Glyph.yc () - baseline - glyph.view_offset_y;-				+ 				cr.save (); 				cr.scale (glyph.view_zoom, glyph.view_zoom); 				Theme.color (cr, "Foreground 1");@@ -2070,7 +2070,7 @@ public class Glyph : FontDisplay { 				Svg.draw_svg_path (cr, juxtaposed.get_svg_data (), marker_x, marker_y); 				cr.restore (); 			}-			+ 			x += juxtaposed.get_width () + kern;  			last_name = name;@@ -2082,19 +2082,19 @@ public class Glyph : FontDisplay { 			c = glyph_sequence.get_char (i); 			name = (!) c.to_string (); 			juxtaposed = (font.has_glyph (name)) ? (!) font.get_glyph (name) : font.get_space ().get_current ();-			+ 			if (font.has_glyph (last_name) && font.has_glyph (name)) { 				kern = classes.get_kerning (name, last_name); 			} else { 				kern = 0; 			}-			+ 			x -= juxtaposed.get_width (); 			x -= kern;-			+ 			marker_x = Glyph.xc () + left + x; 			marker_y = Glyph.yc () - baseline;-			if (!juxtaposed.is_empty () +			if (!juxtaposed.is_empty () 				&&(in_range (left + x, box_x1, box_x2) 				|| in_range (left + x + juxtaposed.get_width (), box_x1, box_x2))) { 				cr.save ();@@ -2104,11 +2104,11 @@ public class Glyph : FontDisplay { 				Svg.draw_svg_path (cr, juxtaposed.get_svg_data (), marker_x, marker_y); 				cr.restore (); 			}-			+ 			last_name = name; 		} 	}-	+ 	/** @return left side bearing */ 	public double get_lsb () { 		return get_line ("left").pos;@@ -2119,14 +2119,14 @@ public class Glyph : FontDisplay { 		Font font = BirdFont.get_current_font (); 		return font.base_line; 	}-	+ 	void draw_background_glyph (WidgetAllocation allocation, Context cr) { 		double left, baseline, current_left; 		Glyph g; 		Font font = BirdFont.get_current_font ();-		+ 		current_left = get_line ("left").pos;-		+ 		if (background_glyph != null) { 			g = (!) background_glyph; 			baseline = font.base_line;@@ -2135,21 +2135,21 @@ public class Glyph : FontDisplay { 			cr.scale (view_zoom, view_zoom); 			cr.translate (-view_offset_x, -view_offset_y); 			Theme.color (cr, "Background Glyph");-			-			Svg.draw_svg_path (cr, g.get_svg_data (), -				Glyph.xc () + left - (left - current_left) , ++			Svg.draw_svg_path (cr, g.get_svg_data (),+				Glyph.xc () + left - (left - current_left) , 				Glyph.yc () - baseline); 			cr.restore (); 		}-		+ 	}-	+ 	public string get_hex () { 		return Font.to_hex_code (unichar_code); 	}-	+ 	public override void move_view (double x, double y) {-		view_offset_x += x / view_zoom; +		view_offset_x += x / view_zoom; 		view_offset_y += y / view_zoom; 		GlyphCanvas.redraw (); 	}@@ -2163,40 +2163,40 @@ public class Glyph : FontDisplay { 		dy = 0;  		new_distance = 0;-		+ 		if (last_tap0_y == -1 || last_tap0_x == -1 || last_tap1_y == -1 || last_tap1_x == -1) { 			return; 		}-		+ 		if (finger == 0) { 			dx = last_tap0_x - x; 			dy = last_tap0_y - y; 			new_distance = Path.distance (last_tap1_x, x, last_tap1_y, y); 		}-		+ 		if (finger == 1) { 			dx = last_tap1_x - x; 			dy = last_tap1_y - y; 			new_distance = Path.distance (last_tap0_x, x, last_tap0_y, y); 		}-		+ 		last_distance = Path.distance (last_tap0_x, last_tap1_x, last_tap0_y, last_tap1_y);  		if (zoom_distance != 0) {-			zoom_tap (zoom_distance - new_distance);	-		}	-				+			zoom_tap (zoom_distance - new_distance);+		}+ 		if (finger == 1) { 			warning (@"dx $dx dy $dy last_tap1_x $last_tap1_x  last_tap1_y $last_tap1_y   x $x  y $y");-			move_view (dx, dy); -		} +			move_view (dx, dy);+		}  		zoom_distance = new_distance; 	}  	public override void tap_down (int finger, int x, int y) { 		TimeoutSource delay;-		+ 		if (finger == 0) { 			delay = new TimeoutSource (400); // wait for second finger 			delay.set_callback(() => {@@ -2206,53 +2206,53 @@ public class Glyph : FontDisplay { 				return false; 			}); 			delay.attach (null);-			+ 			last_tap0_x = x; 			last_tap0_y = y; 		}-		+ 		if (finger == 1) { 			change_view = true; 			last_tap1_x = x; 			last_tap1_y = y; 		} 	}-	+ 	public override void tap_up (int finger, int x, int y) { 		if (finger == 0) { 			button_release (1, x, y);-			+ 			last_tap0_x = -1; 			last_tap0_y = -1; 		}-		+ 		if (finger == 1) { 			last_tap1_x = -1; 			last_tap1_y = -1;-			+ 			change_view = false; 			zoom_distance = 0; 		} 	}-		+ 	public override void tap_move (int finger, int x, int y) { 		if (!change_view) { 			motion_notify (x, y); 		} else { 			change_view_event (finger, x, y); 		}-						+ 		if (finger == 0) { 			last_tap0_x = x; 			last_tap0_y = y; 		}-		+ 		if (finger == 1) { 			last_tap1_x = x; 			last_tap1_y = y; 		} 	}-	+ 	public void update_spacing_class () { 		Font font = BirdFont.get_current_font (); 		GlyphCollection? g;@@ -2260,7 +2260,7 @@ public class Glyph : FontDisplay { 		Glyph glyph; 		Gee.ArrayList<string> s; 		SpacingData sd;-		+ 		sd = font.get_spacing (); 		s = sd.get_all_connections ((!) unichar_code.to_string ()); 		foreach (string l in s) {@@ -2273,7 +2273,7 @@ public class Glyph : FontDisplay { 					if (glyph.left_limit == glyph.right_limit) { 						warning ("Zero width glyph in kerning class."); 					}-					+ 					left_limit = glyph.left_limit; 					right_limit = glyph.right_limit; @@ -2281,7 +2281,7 @@ public class Glyph : FontDisplay { 				} 			} 		}-		+ 		add_help_lines (); 	} @@ -2292,10 +2292,10 @@ public class Glyph : FontDisplay { 		Glyph glyph; 		Gee.ArrayList<string> s; 		SpacingData sd;-		+ 		sd = font.get_spacing (); 		s = sd.get_all_connections ((!) unichar_code.to_string ());-				+ 		foreach (string l in s) { 			if (l != (!) unichar_code.to_string ()) { 				g = font.get_glyph_collection (l);@@ -2306,7 +2306,7 @@ public class Glyph : FontDisplay { 					glyph.right_limit = right_limit; 				} 			}-		}	+		} 	}  	public void set_cache (string key, Surface cache) {@@ -2322,33 +2322,33 @@ public class Glyph : FontDisplay { 			warning ("No cache for glyph."); 			return new ImageSurface (Cairo.Format.ARGB32, 1, 1); 		}-		+ 		return glyph_cache.get (key); 	}-	+ 	public void add_custom_guide () { 		TextListener listener;-		+ 		listener = new TextListener (t_("Guide"), "", t_("Add"));-		+ 		listener.signal_text_input.connect ((text) => { 			new_guide_name = text; 		});-		+ 		listener.signal_submit.connect (() => { 			Line guide; 			double position;-			+ 			position = path_coordinate_y (allocation.height / 2.0); 			guide = new Line (new_guide_name, position); 			horizontal_help_lines.add (guide);-			+ 			BirdFont.get_current_font ().custom_guides.add (guide);-			+ 			TabContent.hide_text_input (); 			GlyphCanvas.redraw (); 		});-		+ 		TabContent.show_text_input (listener); 	} @@ -2360,53 +2360,53 @@ 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);  			return_if_fail (0 <= current_layer + 1 < layers.subgroups.size); 			layers.subgroups.remove_at (current_layer);-			+ 			set_current_layer (layer);-		} +		} 	}-		+ 	public void move_layer_down () { 		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.subgroups.size); 			layers.subgroups.remove_at (current_layer + 1);-			+ 			set_current_layer (layer);-		} +		} 	}-	+ 	public void fix_curve_orientation () { 		int inside_count; 		bool inside; 		Path outline;-		+ 		foreach (Path p1 in get_visible_paths ()) { 			inside_count = 0;-			+ 			foreach (Path p2 in get_visible_paths ()) { 				if (p1 != p2) { 					inside = true; 					outline = p2.flatten ();-					+ 					foreach (EditPoint ep in p1.points) { 						if (!SvgParser.is_inside (ep, outline)) { 							inside = false; 						} 					}-					+ 					if (inside) {-						inside_count++; +						inside_count++; 					} 				} 			}@@ -2418,6 +2418,18 @@ public class Glyph : FontDisplay { 			} 		} 	}++  public override void magnify (double magnification) {+    double x_center = path_coordinate_x (xc ());+    double y_center = path_coordinate_y (yc ());++    view_zoom *= 1 + magnification;++    view_offset_x -= path_coordinate_x (xc ()) - x_center;+    view_offset_y += path_coordinate_y (yc ()) - y_center;++    GlyphCanvas.redraw ();+  } }  }diff --git a/libbirdfont/Preview.vala b/libbirdfont/Preview.valaindex 894d144..02935d0 100644--- a/libbirdfont/Preview.vala+++ b/libbirdfont/Preview.vala@@ -1,24 +1,24 @@ /*     Copyright (C) 2012 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 +    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 +    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. */  namespace BirdFont { -public class Preview : FontDisplay {	-	+public class Preview : FontDisplay {+ 	public Preview () { 	}-	+ 	public override string get_name () { 		return "Preview"; 	}@@ -26,8 +26,9 @@ public class Preview : FontDisplay { 	public override string get_label () { 		return t_("Preview"); 	}-	+ 	public override void selected_canvas () {+    MainWindow.set_scrollbar_size (0); 	}  	public static string get_html_path () {@@ -39,14 +40,14 @@ public class Preview : FontDisplay { 		string fn = get_html_file_name (); 		File dir = font.get_folder (); 		File file = get_child (dir, fn);-		+ 		if (!file.query_exists ()) {-			ExportTool.generate_html_document ((!)file.get_path (), font);				+			ExportTool.generate_html_document ((!)file.get_path (), font); 		}-		+ 		return file; 	}-	+ 	public static bool has_html_document () { 		Font font = BirdFont.get_current_font (); 		string path = get_html_file_name ();@@ -54,7 +55,7 @@ public class Preview : FontDisplay { 		File file = get_child (dir, path); 		return file.query_exists (); 	}-	+ 	public static void generate_html_document () { 		Font font = BirdFont.get_current_font (); 		string path = get_html_file_name ();@@ -74,20 +75,20 @@ public class Preview : FontDisplay { 			warning (e.message); 		} 	}-	+ 	static string get_html_file_name () { 		Font font = BirdFont.get_current_font (); 		return  @"$(ExportSettings.get_file_name (font)).html"; 	}  	public static File get_html_file () {-		return get_file ();	+		return get_file (); 	}  	public static string get_uri () { 		return TabContent.path_to_uri ((!) get_html_file ().get_path ()); 	}-	+ 	public static string get_windows_uri () { 		Font font = BirdFont.get_current_font (); 		string html = get_html_file_name ();@@ -95,16 +96,16 @@ public class Preview : FontDisplay { 		File file = get_child (dir, html); 		return "file:///" + (!)	file.get_path (); 	}-	-	public static string get_html_with_absolute_paths () {				-		// hack: force webkit to ignore cache in preview	++	public static string get_html_with_absolute_paths () {+		// hack: force webkit to ignore cache in preview 		StringBuilder sb = new StringBuilder (); 		DataInputStream dis; 		string? line;-			+ 		uint rid = Random.next_int (); 		Font font = BirdFont.get_current_font ();-		+ 		File preview_directory; 		File f_ttf; 		File f_eot;@@ -112,9 +113,9 @@ public class Preview : FontDisplay {  		try { 			dis = new DataInputStream (get_file ().read ());-			+ 			preview_directory = BirdFont.get_preview_directory ();-			+ 			f_ttf = get_child (font.get_folder (), @"$(ExportSettings.get_file_name (font)).ttf"); 			f_eot = get_child (font.get_folder (), @"$(ExportSettings.get_file_name (font)).eot"); 			f_svg = get_child (font.get_folder (), @"$(ExportSettings.get_file_name (font)).svg");@@ -122,11 +123,11 @@ public class Preview : FontDisplay { 			if (!f_ttf.query_exists ()) { 				warning ("TTF file does not exist."); 			}-			+ 			if (!f_svg.query_exists ()) { 				warning ("SVG file does not exist."); 			}-			+ 			while ((line = dis.read_line (null)) != null) { 				line = ((!) line).replace (@"$(ExportSettings.get_file_name (font)).ttf", @"$(TabContent.path_to_uri ((!) f_ttf.get_path ()))?$rid"); 				line = ((!) line).replace (@"$(ExportSettings.get_file_name (font)).eot", @"$(TabContent.path_to_uri ((!) f_eot.get_path ()))?$rid");@@ -140,7 +141,7 @@ public class Preview : FontDisplay { 		} 		return sb.str; 	}-	+ 	public override bool needs_modifier () { 		return true; 	}diff --git a/libbirdfont/TabContent.vala b/libbirdfont/TabContent.valaindex 12a11e5..83ddc70 100644--- a/libbirdfont/TabContent.vala+++ b/libbirdfont/TabContent.vala@@ -1,14 +1,14 @@ /*     Copyright (C) 2014 2015 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 +    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 +    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. */ @@ -27,123 +27,123 @@ public class TabContent : GLib.Object { 	static ImageSurface? pause_surface = null;  	static const int TEXT_INPUT_HEIGHT = 51;-	+ 	static double last_press_time = 0;-	+ 	public static void zoom_in () { 		if (MenuTab.has_suppress_event ()) { 		}-		+ 		GlyphCanvas.current_display.zoom_in (); 	}-	+ 	public static void zoom_out () { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		GlyphCanvas.current_display.zoom_out (); 	}-	+ 	public static void move_view (double x, double y) { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		GlyphCanvas.current_display.move_view (x, y); 	}-	+ 	public static bool has_scrollbar () { 		if (MenuTab.has_suppress_event ()) { 			return false; 		}-		+ 		return GlyphCanvas.current_display.has_scrollbar (); 	}-	+ 	public static void scroll_to (double percent) { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		GlyphCanvas.current_display.scroll_to (percent); 	}-	+ 	public static void draw (WidgetAllocation allocation, Context cr) { 		AbstractMenu menu; 		Dialog dialog;-		+ 		if (unlikely (MenuTab.has_suppress_event ())) { 			cr.save (); 			Theme.color (cr, "Background 1"); 			cr.rectangle (0, 0, allocation.width, allocation.height); 			cr.fill ();-			+ 			if (pause_surface != null) { 				cr.scale (1.0 / Screen.get_scale (), 1.0 / Screen.get_scale ()); 				cr.set_source_surface ((!) pause_surface, 0, 0); 				cr.paint (); 			}-			+ 			cr.restore (); 		} else { 			menu = MainWindow.get_menu (); 			dialog = MainWindow.get_dialog ();-		+ 			GlyphCanvas.set_allocation (allocation); 			MainWindow.get_current_glyph ().resized (allocation); 			GlyphCanvas.current_display.draw (allocation, cr);-			+ 			if (dialog.visible) { 				dialog.allocation = allocation; 				dialog.draw (cr); 			}-			+ 			if (menu.show_menu) { 				menu.draw (allocation, cr); 			}-			+ 			if (FontDisplay.dirty_scrollbar) { 				GlyphCanvas.current_display.update_scrollbar (); 				FontDisplay.dirty_scrollbar = false; 			}-			+ 			if (text_input_visible) { 				draw_text_input (allocation, cr); 			} 		} 	}-	+ 	public static void create_pause_surface () { 		Context cr; 		WidgetAllocation alloc;-		+ 		if (MenuTab.has_suppress_event ()) { 			warning ("Background surface already created."); 			return; 		}-		+ 		alloc = GlyphCanvas.get_allocation (); 		pause_surface = Screen.create_background_surface (alloc.width, alloc.height); 		cr = new Context ((!) pause_surface); 		cr.scale (Screen.get_scale (), Screen.get_scale ()); 		draw (alloc, cr); 	}-	+ 	public static void key_press (uint keyval) { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		unichar c = (unichar) keyval;-		+ 		if (unlikely (!c.validate ())) { 			warning ("Invalid unichar: $(keyval)"); 			return; 		}-		+ 		KeyBindings.add_modifier_from_keyval (keyval);-		+ 		if (!text_input_visible) { 			MainWindow.get_menu ().process_key_binding_events (keyval); 			GlyphCanvas.current_display.key_press (keyval);@@ -151,14 +151,14 @@ public class TabContent : GLib.Object { 			text_input.key_press (keyval); 		} 	}-	+ 	public static void key_release (uint keyval) { 		if (MenuTab.has_suppress_event ()) { 			return; 		}  		unichar c = (unichar) keyval;-		+ 		if (unlikely (!c.validate ())) { 			warning ("Invalid unichar: $(keyval)"); 			return;@@ -170,57 +170,57 @@ public class TabContent : GLib.Object { 			GlyphCanvas.current_display.key_release (keyval); 		} 	}-	+ 	public static void motion_notify (double x, double y) { 		Toolbox toolbox;-		+ 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		if (!text_input_visible) { 			GlyphCanvas.current_display.motion_notify (x, y); 		} else { 			text_input.motion (x, y); 			GlyphCanvas.redraw (); 		}-		+ 		toolbox = MainWindow.get_toolbox (); 		toolbox.hide_tooltip (); 	}-	+ 	public static void button_release (int button, double x, double y) { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		if (MainWindow.get_dialog ().visible) { 			MainWindow.get_dialog ().button_release (button, x, y); 		} else if (MainWindow.get_menu ().show_menu) { 			MainWindow.get_menu ().button_release (button, x, y); 		} else if (text_input_visible) { 			text_input_button.button_release (button, x, y);-			text_input.button_release (button, x, y);				+			text_input.button_release (button, x, y); 			GlyphCanvas.redraw (); 		} else { 			GlyphCanvas.current_display.button_release (button, x, y); 		} 	}-	+ 	public static void button_press (uint button, double x, double y) { 		if (MenuTab.has_suppress_event ()) { 			return; 		}  		last_press_time = GLib.get_real_time ();-		+ 		if (MainWindow.get_dialog ().visible) { 			MainWindow.get_dialog ().button_press (button, x, y); 		} else if (!MainWindow.get_menu ().show_menu) { 			if (text_input_visible) { 				text_input.button_press (button, x, y); 				text_input_button.button_press (button, x, y);-				+ 				if (y > TEXT_INPUT_HEIGHT) { 					hide_text_input (); 				}@@ -234,79 +234,89 @@ public class TabContent : GLib.Object { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		if (!MainWindow.get_menu ().show_menu) { 			GlyphCanvas.current_display.double_click (button, ex, ey); 		} 	}-	-	public static void scroll_wheel_pixel_delta (double x, double y, ++	public static void scroll_wheel_pixel_delta (double x, double y, 		double pixeldelta_x, double pixeldelta_y) {-			+ 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		if (!MainWindow.get_menu ().show_menu) { 			GlyphCanvas.current_display.scroll_wheel (x, y, pixeldelta_x, pixeldelta_y);-		}		+		} 	}-		+ 	public static void scroll_wheel_up (double x, double y) { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		if (!MainWindow.get_menu ().show_menu) { 			GlyphCanvas.current_display.scroll_wheel (x, y, 0, 15); 		} 	}-	+ 	public static void scroll_wheel_down (double x, double y) { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		if (!MainWindow.get_menu ().show_menu) { 			GlyphCanvas.current_display.scroll_wheel (x, y, 0, -15); 		} 	} +  public static void magnify (double magnification) {+		if (MenuTab.has_suppress_event ()) {+			return;+		}++		if (!MainWindow.get_menu ().show_menu) {+			GlyphCanvas.current_display.magnify (magnification);+		}+	}+ 	public static void tap_down (int finger, int x, int y) { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		if (!MainWindow.get_menu ().show_menu) { 			GlyphCanvas.current_display.tap_down (finger, x, y); 		} 	}-	+ 	public static void tap_up (int finger, int x, int y) { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		if (!MainWindow.get_menu ().show_menu) { 			GlyphCanvas.current_display.tap_up (finger, x, y); 		} 	}-	+ 	public static void tap_move (int finger, int x, int y) { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		if (!MainWindow.get_menu ().show_menu) { 			GlyphCanvas.current_display.tap_move (finger, x, y); 		} 	}-		+ 	public static void undo () { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		GlyphCanvas.current_display.undo (); 	} @@ -314,18 +324,18 @@ public class TabContent : GLib.Object { 		if (MenuTab.has_suppress_event ()) { 			return; 		}-		+ 		GlyphCanvas.current_display.redo (); 	}-		+ 	public static string path_to_uri (string path) { 		string uri = path; 		string wp;-		+ 		// wine uri hack 		if (BirdFont.win32) { 			wp = wine_to_unix_path (uri);-			+ 			if (SearchPaths.find_file (wp, "").query_exists ()) { 				uri = wp; 			}@@ -340,20 +350,20 @@ public class TabContent : GLib.Object { 		} else { 			uri = @"file:///$uri"; 		}-		+ 		return uri; 	}-	+ 	public static void draw_text_input (WidgetAllocation allocation, Context cr) { 		cr.save ();-		+ 		Theme.color (cr, "Default Background"); 		cr.rectangle (0, 0, allocation.width, TEXT_INPUT_HEIGHT); 		cr.fill (); 		cr.restore ();-		+ 		Theme.text_color (text_input_label, "Button Foreground");-		+ 		text_input_label.widget_x = 10; 		text_input_label.widget_y = 17; @@ -361,11 +371,11 @@ public class TabContent : GLib.Object { 		text_input.layout (); 		text_input.widget_x = text_input_label.get_extent () + 20; 		text_input.widget_y = 10;-		text_input.width = allocation.width -			- text_input_button.get_width () +		text_input.width = allocation.width+			- text_input_button.get_width () 			- text_input_label.get_extent () 			- 40;-		+ 		text_input_button.allocation = allocation; 		text_input_button.widget_x = text_input.widget_x + text_input.width + 10; 		text_input_button.widget_y = 10;@@ -374,40 +384,40 @@ public class TabContent : GLib.Object { 		text_input.draw (cr); 		text_input_button.draw (cr); 	}-	+ 	public static void show_text_input (TextListener tl) { 		text_callback = tl;-		+ 		text_input_label = new Text (tl.label); 		text_input = new LineTextArea (20 * MainWindow.units); 		text_input_button = new Button (tl.button_label);-		+ 		text_input.carret_is_visible = true;-		+ 		text_input.set_text (tl.default_text); 		text_input.text_changed.connect ((text) => { 			tl.signal_text_input (text); 		});-		+ 		text_input.enter.connect ((text) => { 			tl.signal_submit (text); 			text_input_visible = false; 			GlyphCanvas.redraw (); 		});-		+ 		text_input_button.action.connect (() => { 			tl.signal_submit (text_input.get_text ()); 		});-		+ 		text_input_visible = true; 		GlyphCanvas.redraw (); 	}-	+ 	public static void hide_text_input () { 		text_input_visible = false; 		text_callback = new TextListener ("", "", ""); 	}-	+ 	public static void reset_modifier () { 		TabContent.key_release (Key.CTRL_RIGHT); 		TabContent.key_release (Key.CTRL_LEFT);@@ -417,7 +427,7 @@ public class TabContent : GLib.Object { 		TabContent.key_release (Key.ALT_RIGHT); 		TabContent.key_release (Key.LOGO_LEFT); 		TabContent.key_release (Key.LOGO_RIGHT);-		+ 		if (MainWindow.get_current_display () is Glyph) { 			TabContent.key_release ((uint) ' '); 		}

Contact

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