Clone in a terminal:
Commit f319bf5
Johan Mattsson - 2015-05-23T13:13:29+00:00
f319bf52ad7769ed3abb8001ca74a7b00673283bjohan.mattsson.m@gmail.com

Fix memory leak

Changed files (16)

Diff

diff --git a/libbirdfont/BirdFont.vala b/libbirdfont/BirdFont.valaindex b85ba97..15c932f 100644--- a/libbirdfont/BirdFont.vala+++ b/libbirdfont/BirdFont.vala@@ -402,6 +402,7 @@ public class BirdFont { 		CodePageBits codepage_bits;  		args = new Argument.command_line (arg);+		Font.empty = new Font ();  #if ANDROID 		BirdFont.logging = true;diff --git a/libbirdfont/BirdFontFile.vala b/libbirdfont/BirdFontFile.valaindex dd32490..3b8b493 100644--- a/libbirdfont/BirdFontFile.vala+++ b/libbirdfont/BirdFontFile.vala@@ -146,7 +146,7 @@ class BirdFontFile : GLib.Object { 				 				try { 					string data;-					foreach (Glyph g in gc.get_version_list ().glyphs) {+					foreach (Glyph g in gc.glyphs) { 						if (g.get_background_image () != null) { 							bg = (!) g.get_background_image (); 							data = bg.get_png_base64 ();@@ -370,13 +370,13 @@ class BirdFontFile : GLib.Object { 	}  	public void write_selected (GlyphCollection gc, DataOutputStream os)  throws GLib.Error {-		os.put_string (@"\t<selected id=\"$(gc.get_selected_id ())\"/>\n");+		os.put_string (@"\t<selected id=\"$(gc.selected)\"/>\n"); 	}  	public void write_glyph_collection (GlyphCollection gc, DataOutputStream os)  throws GLib.Error { 		write_glyph_collection_start (gc, os); 		write_selected (gc, os);-		foreach (Glyph g in gc.get_version_list ().glyphs) {+		foreach (Glyph g in gc.glyphs) { 			write_glyph (g, os); 		} 		write_glyph_collection_end (os);@@ -1124,8 +1124,13 @@ class BirdFontFile : GLib.Object {  		current_gc = font.get_glyph_collection_by_name (name); 		new_glyph_collection = (current_gc == null);-		gc = (!new_glyph_collection) ? (!) current_gc : new GlyphCollection (unicode, name);-+		+		if (!new_glyph_collection) {+			gc =  (!) current_gc;+		} else {+			gc = new GlyphCollection (unicode, name);+		}+				 		foreach (Tag t in tag) {			 			if (t.get_name () == "selected") { 				selected_id = parse_selected (t);diff --git a/libbirdfont/BirdFontPart.vala b/libbirdfont/BirdFontPart.valaindex 533516f..8d123f0 100644--- a/libbirdfont/BirdFontPart.vala+++ b/libbirdfont/BirdFontPart.vala@@ -30,6 +30,11 @@ public class BirdFontPart : GLib.Object{  	public BirdFontPart (Font font) {	 		this.font = font;++		font.font_deleted.connect (() => {+			this.font = Font.empty;+		});+		 		parts = new Gee.ArrayList<string> (); 		root_directory = ""; 	}@@ -154,7 +159,7 @@ public class BirdFontPart : GLib.Object{ 					bf.write_closing_root_tag (os); 					os.close (); 			-					foreach (Glyph g in gc.get_version_list ().glyphs) {+					foreach (Glyph g in gc.glyphs) { 						try { 							write_glyph (bf, gc, g); 							write_glyph_background_image (bf, gc, g);diff --git a/libbirdfont/DropMenu.vala b/libbirdfont/DropMenu.valadeleted file mode 100644index 2ce5f9d..0000000--- a/libbirdfont/DropMenu.vala+++ /dev/null@@ -1,228 +0,0 @@-/*-    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 -    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 Cairo;--namespace BirdFont {--public enum MenuDirection {-	DROP_DOWN,-	POP_UP;-}--public class DropMenu : GLib.Object {--	public delegate void Selected (MenuAction self);-	public signal void selected (DropMenu self);-	-	double x = -1;-	double y = -1;-	double width = 0;-	-	double menu_x = -1;-	-	public bool menu_visible = false;--	Gee.ArrayList <MenuAction> actions = new Gee.ArrayList <MenuAction> ();--	const int item_height = 25;-	-	MenuDirection direction = MenuDirection.DROP_DOWN;-	-	public signal void signal_delete_item  (int item_index);-	-	public DropMenu () {-	}-	-	public MenuAction get_action_index (int index) {-		if (!(0 <= index < actions.size)) {-			warning (@"No action for index $index.");-			return new MenuAction ("None");-		}-		return actions.get (index);-	}-	-	public void recreate_index () {-		int i = -1;-		foreach (MenuAction a in actions) {-			a.index = i;-			i++;-		}-	}-	-	public MenuAction get_action_no2 () {-		if (actions.size < 2) {-			warning ("No such action");-			return new MenuAction ("None");-		}-		-		return actions.get (1);-	}-	-	public void deselect_all () {-		foreach (MenuAction m in actions) {-			m.set_selected (false);-		}-	}-	-	public void set_direction (MenuDirection d) {-		direction = d;-	}-	-	public void close () {-		menu_visible = false;-	}-	-	public MenuAction add_item (string label) {-		MenuAction m = new MenuAction (label);-		add_menu_item (m);-		return m;-	}-	-	public void add_menu_item (MenuAction m) {-		m.parent = this;-		actions.add (m);-	}-		-	public bool is_over_icon (double px, double py) {-		if (x == -1 || y == -1) {-			return false;-		}-		-		return x - 12 < px <= x && y - 5 < py < y + 12 + 5;-	}--	public bool menu_item_action (double px, double py) {-		MenuAction? action;-		MenuAction a;-		MenuAction ma;-		int index;-		-		if (menu_visible) {-			action = get_menu_action_at (px, py);-			-			if (action != null) {-				a = (!) action;-				-				// action for the delete button-				if (a.has_delete_button && menu_x + width - 13 < px <= menu_x + width) { -					index = 0;-					ma = actions.get (0);-					while (true) {-						if (a == ma) {-							actions.remove_at (index);-							signal_delete_item (index);-							break;-						}-						-						if (ma == actions.get (actions.size - 1)) {-							break;-						} else {-							ma = actions.get (index + 1);-							index++;-						}-					}-					return false;-				} else {-					a.action (a);-					selected (this);-					menu_visible = false;-				}-				-				return true;-			}-		}-		-		return false;-	}-	-	public bool menu_icon_action (double px, double py) {		-		menu_visible = is_over_icon (px, py);-		return menu_visible;-	}-	-	MenuAction? get_menu_action_at (double px, double py) {-		double n = 0;-		double ix, iy;-		-		foreach (MenuAction item in actions) {-			ix = menu_x - 6;-			-			if (direction == MenuDirection.DROP_DOWN) {-				iy = y + 12 + n * item_height;-			} else {-				iy = y - 24 - n * item_height;-			}-	-			if (ix <= px <= ix + width && iy <= py <= iy + item_height) {-				return item;-			}-			-			n++;			-		}--		return null;-	}-	-	public void set_position (double px, double py) {-		x = px;-		y = py;--		foreach (MenuAction item in actions) {-			if (item.text.get_sidebearing_extent () + 25 > width) {-				width = item.text.get_sidebearing_extent () + 25;-			}-		}-				-		if (x - width + 19 < 0) {-			menu_x = 30;-		} else {-			menu_x = x - width;-		}-	}-	-	public void draw_menu (Context cr) {-		double ix, iy;-		int n;-		-		if (likely (!menu_visible)) {-			return;-		}-		-		cr.save ();-		Theme.color (cr, "Default Background");-		cr.rectangle (menu_x, y - actions.size * item_height, width, actions.size * item_height);-		-		cr.fill_preserve ();-		cr.stroke ();-		cr.restore ();-		-		cr.save ();-		-		n = 0;-		foreach (MenuAction item in actions) {-			item.width = width;-			-			iy = y - 8 - n * item_height;-			ix = menu_x + 2;-			-			item.draw (ix, iy, cr);-			n++;-		}-		-		cr.restore ();-	}-}--}diff --git a/libbirdfont/Font.vala b/libbirdfont/Font.valaindex 9d36cc9..1439de4 100644--- a/libbirdfont/Font.vala+++ b/libbirdfont/Font.vala@@ -104,6 +104,10 @@ public class Font : GLib.Object { 	public FontSettings settings; 	public KerningStrings kerning_strings; 	+	public signal void font_deleted ();+	+	public static Font empty;+	 	public Font () { 		KerningClasses kerning_classes; 		@@ -143,6 +147,10 @@ public class Font : GLib.Object { 		kerning_strings = new KerningStrings (); 	} +	~Font () {+		font_deleted ();+	}+ 	public static void set_default_license (string license) { 		default_license = license; 	}@@ -473,7 +481,7 @@ public class Font : GLib.Object { 		glyph_name.remove (glyph.get_name ()); 		ligature.remove (glyph.get_current ().get_name ()); 		-		foreach (Glyph g in glyph.get_version_list ().glyphs) {+		foreach (Glyph g in glyph.glyphs) { 			deleted_glyphs.add (g); 		} 	}@@ -492,7 +500,6 @@ public class Font : GLib.Object {  	/** Get glyph collection by name. */ 	public GlyphCollection? get_glyph_collection_by_name (string? glyph) {-		// TODO: load from disk here if needed. 		GlyphCollection? gc = null; 		 		if (glyph != null) {diff --git a/libbirdfont/Glyph.vala b/libbirdfont/Glyph.valaindex fe38e4b..be1e850 100644--- a/libbirdfont/Glyph.vala+++ b/libbirdfont/Glyph.vala@@ -2232,6 +2232,7 @@ public class Glyph : FontDisplay { 	}  	public bool has_cache (string key) {+		// FIXME: DELETE print (@"glyph_cache.keys.size $(glyph_cache.keys.size)\n"); 		return glyph_cache.has_key (key); 	} diff --git a/libbirdfont/GlyphCollection.vala b/libbirdfont/GlyphCollection.valaindex 3ba152e..d2c76b4 100644--- a/libbirdfont/GlyphCollection.vala+++ b/libbirdfont/GlyphCollection.vala@@ -1,5 +1,5 @@ /*-    Copyright (C) 2012, 2014 Johan Mattsson+    Copyright (C) 2012, 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 @@ -18,15 +18,15 @@ using Math; namespace BirdFont {  public class GlyphCollection : GLib.Object {-	public VersionList versions; 	unichar unicode_character; 	string name; 	bool unassigned = false;+	public Gee.ArrayList<Glyph> glyphs = new Gee.ArrayList<Glyph> ();+	public int selected = 0;  	public GlyphCollection (unichar unicode_character, string name) { 		this.unicode_character = unicode_character; 		this.name = name;-		versions = new VersionList (null, this); 	}  	public GlyphCollection.with_glyph (unichar unicode_character, string name) {@@ -36,11 +36,32 @@ public class GlyphCollection : GLib.Object { 		this.name = name; 		 		g = new Glyph (name, unicode_character);-		versions = new VersionList (g, this);+		glyphs.add (g); 	}--	~GlyphCollection () {-		versions.glyphs.clear ();+	+	public void remove (int index) {+		return_if_fail (0 <= index < glyphs.size);+		+		if (selected >= index) {+			selected--;+		}+		+		glyphs.remove_at (index);+	}+	+	public void set_selected (Glyph g) {+		int i = 0;+		+		foreach (Glyph gl in glyphs) {+			if (gl == g) {+				selected = i;+				return;+			}+			i++;+		}+		+		selected = 0;+		warning ("Glyph is not a part of the collection."); 	} 	 	public void set_unassigned (bool a) {@@ -52,24 +73,27 @@ public class GlyphCollection : GLib.Object { 	} 	 	public void add_glyph (Glyph g) {-		get_version_list ().add_glyph (g);-	}--	public VersionList get_version_list () {-		return versions;+		glyphs.add (g); 	} 	 	public Glyph get_current () {-		return versions.get_current ();+		if (0 <= selected < glyphs.size) {+			return glyphs.get (selected);+		}+		+		return new Glyph ("", '\0'); 	} 	-	public void insert_glyph (Glyph g, bool selected) {-		versions.add_glyph (g, selected);-		assert (versions.glyphs.size > 0);+	public void insert_glyph (Glyph g, bool selected_glyph) {+		glyphs.add (g);+		+		if (selected_glyph) {+			selected = glyphs.size - 1;+		} 	} 	 	public uint length () {-		return versions.glyphs.size;+		return glyphs.size; 	} 	 	public string get_unicode () {@@ -94,16 +118,15 @@ public class GlyphCollection : GLib.Object { 		name = n; 	} 	-	public int get_selected_id () {-		return versions.get_current ().version_id;	-	}-	-	public int get_last_id () {-		return versions.get_last_id ();-	}-	 	public void set_selected_version (int version_id) {-		versions.set_selected_version (version_id);+		int i = 0;+		foreach (Glyph g in glyphs) {+			if (g.version_id == version_id) {+				selected = i;+				break;+			}+			i++;+		} 	} 	 	/** Create a copy of this list. This method will copy the list data but @@ -113,15 +136,20 @@ public class GlyphCollection : GLib.Object { 	public GlyphCollection copy () { 		GlyphCollection n = new GlyphCollection (unicode_character, name); 		-		foreach (Glyph g in versions.glyphs) {+		foreach (Glyph g in glyphs) { 			n.insert_glyph (g, false); 		} 		-		n.versions.set_selected_version (versions.current_version_id);+		n.selected = selected; 		n.unassigned = unassigned; 		 		return n; 	}+	+	public int get_last_id () {+		return_val_if_fail (glyphs.size > 0, 0);+		return glyphs.get (glyphs.size - 1).version_id;+	} } 	 }diff --git a/libbirdfont/KerningClasses.vala b/libbirdfont/KerningClasses.valaindex 2e75483..e2d3884 100644--- a/libbirdfont/KerningClasses.vala+++ b/libbirdfont/KerningClasses.vala@@ -42,6 +42,10 @@ public class KerningClasses : GLib.Object { 	public KerningClasses (Font font) { 		this.font = font; 		+		font.font_deleted.connect (() => {+			this.font = Font.empty;+		});+		 		classes_first = new Gee.ArrayList<GlyphRange> (); 		classes_last = new Gee.ArrayList<GlyphRange> (); 		classes_kerning = new Gee.ArrayList<Kerning> ();diff --git a/libbirdfont/Ligatures.vala b/libbirdfont/Ligatures.valaindex b4be56c..aecfe78 100644--- a/libbirdfont/Ligatures.vala+++ b/libbirdfont/Ligatures.vala@@ -31,6 +31,10 @@ public class Ligatures : GLib.Object {  	public Ligatures (Font font) { 		this.font = font;++		font.font_deleted.connect (() => {+			this.font = Font.empty;+		}); 	} 	 	public void get_ligatures (LigatureIterator iter) {diff --git a/libbirdfont/MenuAction.vala b/libbirdfont/MenuAction.valaindex 6532d41..64418f1 100644--- a/libbirdfont/MenuAction.vala+++ b/libbirdfont/MenuAction.vala@@ -18,8 +18,7 @@ namespace BirdFont {  public class MenuAction : GLib.Object { 	public string label;-	public DropMenu.Selected action;-	public DropMenu? parent = null;+	public signal void action (MenuAction a); 	public int index = -1; 	public bool has_delete_button = true; 	public double width = 100;diff --git a/libbirdfont/OverView.vala b/libbirdfont/OverView.valaindex 86c8050..5a476aa 100644--- a/libbirdfont/OverView.vala+++ b/libbirdfont/OverView.vala@@ -85,7 +85,7 @@ public class OverView : FontDisplay { 		IdleSource idle = new IdleSource ();  		idle.set_callback (() => {			-			// FIXME: selected_canvas ();+			selected_canvas (); 			return false; 		}); 		@@ -262,6 +262,7 @@ public class OverView : FontDisplay { 		update_scrollbar (); 		update_zoom_bar (); 		OverViewItem.glyph_scale = 1;+		update_item_list (); 		selected_item = get_selected_item (); 		GlyphCanvas.redraw (); 	}@@ -371,7 +372,7 @@ public class OverView : FontDisplay { 		return i - 1; 	} 		-	void update_item_list (int item_list_length = -1) {+	public void update_item_list (int item_list_length = -1) { 		string character_string; 		Font f = BirdFont.get_current_font (); 		GlyphCollection? glyphs = null;@@ -456,8 +457,6 @@ public class OverView : FontDisplay { 	public override void draw (WidgetAllocation allocation, Context cr) { 		this.allocation = allocation; 		-		update_item_list ();-		 		// clear canvas 		cr.save (); 		Theme.color (cr, "Background 1");@@ -1074,7 +1073,7 @@ public class OverView : FontDisplay { 			index++; 		} 	-		update_item_list ();+		// FIXME: update_item_list (); 		GlyphCanvas.redraw (); 	} diff --git a/libbirdfont/OverViewItem.vala b/libbirdfont/OverViewItem.valaindex 3d6ba27..bba5f6a 100644--- a/libbirdfont/OverViewItem.vala+++ b/libbirdfont/OverViewItem.vala@@ -24,7 +24,7 @@ public class OverViewItem : GLib.Object { 	public double y; 	public bool selected = false; 	public CharacterInfo info;-	+		 	public static double DEFAULT_WIDTH = 100; 	public static double DEFAULT_HEIGHT = 130; 	public static double DEFAULT_MARGIN = 20;@@ -35,6 +35,7 @@ public class OverViewItem : GLib.Object {  	public static double glyph_scale = 1.0; 	+	VersionList version_menu; 	Text icon; 	 	public OverViewItem (GlyphCollection? glyphs, unichar character, double x, double y) {	@@ -47,8 +48,23 @@ public class OverViewItem : GLib.Object { 		icon = new Text ("dropdown_menu", 17); 		icon.load_font ("icons.bf"); 		icon.use_cache (true);+		+		if (glyphs != null) {+			version_menu = new VersionList ((!) glyphs);+			version_menu.add_glyph_item.connect ((glyph) => {+				((!) glyphs).insert_glyph (glyph, true);+			});+			version_menu.signal_delete_item.connect ((glyph_index) => {+				OverView v = MainWindow.get_overview ();+				version_menu = new VersionList ((!) glyphs);+				v.update_item_list ();+				GlyphCanvas.redraw ();+			});+		} else {+			version_menu = new VersionList (new GlyphCollection (character, (!) character.to_string ()));+		} 	}-	+ 	public string get_name () { 		StringBuilder s; 		@@ -81,12 +97,13 @@ public class OverViewItem : GLib.Object { 		 		if (has_icons () && glyphs != null) { 			g = (!) glyphs;-			a = g.get_version_list ().menu_item_action (px, py); // select one item on the menu++			a = version_menu.menu_item_action (px, py); // select one item on the menu 			if (a) { 				return s; 			} 			-			g.get_version_list ().menu_icon_action (px, py); // click in the open menu+			version_menu.menu_icon_action (px, py); // click in the open menu 		} 		 		if (has_icons () && info.is_over_icon (px, py)) {@@ -276,18 +293,12 @@ public class OverViewItem : GLib.Object { 	} 	 	public void hide_menu () {-		GlyphCollection g;-		-		if (glyphs != null) {-			g = (!) glyphs;-			g.get_version_list ().menu_visible = false;-		}+		version_menu.menu_visible = false; 	} 	 	private void draw_menu (Context cr) { 		GlyphCollection g;-		DropMenu menu;-				+		 		if (glyphs == null) { 			return; 		}@@ -300,10 +311,8 @@ public class OverViewItem : GLib.Object { 		 		icon.draw_at_top (cr, x + width - 32, y + height - 19); 		-		g = (!) glyphs;-		menu = g.get_version_list ();		-		menu.draw_menu (cr);-		menu.set_position (x + width - 21, y + height - 18);+		version_menu.set_position (x + width - 21, y + height - 18);+		version_menu.draw_menu (cr); 	} } diff --git a/libbirdfont/Renderer/FallbackFont.vala b/libbirdfont/Renderer/FallbackFont.valaindex 8144ead..858a1c6 100644--- a/libbirdfont/Renderer/FallbackFont.vala+++ b/libbirdfont/Renderer/FallbackFont.vala@@ -121,7 +121,7 @@ public class FallbackFont : GLib.Object { 		FontFace* font; 		 		bf_font = new Font ();-		+ 		for (int i = fallback_fonts.size - 1; i >= 0; i--) { 			f = fallback_fonts.get (i); 			@@ -153,8 +153,7 @@ public class FallbackFont : GLib.Object {  		bf_parser = new BirdFontFile (bf_font); 		bf_parser.load_data (((!) glyph_data).str);-		bf_parser = new BirdFontFile (new Font ());-					+				 		return bf_font; 	} diff --git a/libbirdfont/Renderer/FontCache.vala b/libbirdfont/Renderer/FontCache.valaindex e234265..0ef2bb4 100644--- a/libbirdfont/Renderer/FontCache.vala+++ b/libbirdfont/Renderer/FontCache.vala@@ -47,13 +47,13 @@ public class FontCache { 		Font f; 		bool ok; -		if (fonts.has_key (file_name)) {-			return fonts.get (file_name);-		}-		 		if (file_name == "") { 			return fallback; 		}+				+		if (fonts.has_key (file_name)) {+			return fonts.get (file_name);+		} 		 		f = new Font (); 		f.set_file (file_name);@@ -94,13 +94,10 @@ public class FontCache { 		public CachedFont (Font? font) { 			this.font = font; 			cached++;-			-			warning (@"$cached cached fonts\n"); 		} 		 		~CachedFont () { 			cached--;-			warning (@"$cached cached fonts\n"); 		} 		 		public Glyph? get_glyph_by_name (string name) {diff --git a/libbirdfont/Renderer/Text.vala b/libbirdfont/Renderer/Text.valaindex 37dec2a..cb68af6 100644--- a/libbirdfont/Renderer/Text.vala+++ b/libbirdfont/Renderer/Text.vala@@ -113,7 +113,8 @@ public class Text : Widget { 		index = 0; 		while (text.get_next_char (ref index, out c)) { 			name = (!) c.to_string ();-			g = cached_font.get_glyph_by_name (name);				+			g = cached_font.get_glyph_by_name (name);+			 			gs.glyph.add (g); 			glyph_names.add (name); 		}@@ -131,6 +132,7 @@ public class Text : Widget { 		GlyphRange? gr_left, gr_right; 		GlyphSequence word; 		KerningClasses kc;+		Font empty = new Font (); 		 		glyph = new Glyph.no_lines ("", '\0'); @@ -140,7 +142,7 @@ public class Text : Widget { 	 		word = glyph_sequence; 		wi = 0;-+	 		if (cached_font.font != null) { 			word_with_ligatures = word.process_ligatures ((!) cached_font.font); 		} else {@@ -153,9 +155,9 @@ public class Text : Widget { 		if (cached_font.font != null) { 			kc = ((!) cached_font.font).get_kerning_classes (); 		} else {-			kc = new KerningClasses (new Font ());+			kc = new KerningClasses (empty); 		}	-		+ 		for (int i = 0; i < word_with_ligatures.glyph.size; i++) { 			g = word_with_ligatures.glyph.get (i); 			@@ -172,7 +174,7 @@ public class Text : Widget { 			} 				 			// process glyph-			if (g == null) {+			if (g == null && (0 <= i < glyph_names.size)) { 				g = cached_font.get_glyph_by_name (glyph_names.get (i)); 			} 			@@ -180,6 +182,7 @@ public class Text : Widget { 			iter (glyph, kern, i + 1 == word_with_ligatures.glyph.size);			 			prev = g; 			wi++;+ 		} 	} @@ -351,10 +354,10 @@ public class Text : Widget { 				if (truncated_width > 0 && end - px > truncated_width) { 					return; 				}-				+ 				draw_chached (cr, glyph, kerning, last, x, y, cc_y,  					ratio, cacheid);-					+				 				x = end; 			}); 		} else {diff --git a/libbirdfont/VersionList.vala b/libbirdfont/VersionList.valaindex 679fbf5..31b9b91 100644--- a/libbirdfont/VersionList.vala+++ b/libbirdfont/VersionList.vala@@ -15,44 +15,76 @@ using Cairo; using Math; +public enum MenuDirection {+	DROP_DOWN,+	POP_UP;+}+ namespace BirdFont { -public class VersionList : DropMenu {+public class VersionList : GLib.Object { 	public int current_version_id = -1;-	unowned GlyphCollection glyph_collection;+	GlyphCollection glyph_collection; 	 	public Gee.ArrayList<Glyph> glyphs; 	-	public VersionList (Glyph? g = null, GlyphCollection glyph_collection) {-		base ();-		-		this.glyph_collection = glyph_collection;-		glyphs = new  Gee.ArrayList<Glyph> ();-		set_direction (MenuDirection.POP_UP);-		+	static int n_lists = 0;++	public delegate void Selected (MenuAction self);+	public signal void selected (VersionList self);+	+	double x = -1;+	double y = -1;+	double width = 0;+	+	double menu_x = -1;	+	public bool menu_visible = false;+	Gee.ArrayList <MenuAction> actions = new Gee.ArrayList <MenuAction> ();+	const int item_height = 25;+	MenuDirection direction = MenuDirection.DROP_DOWN;+	+	public signal void signal_delete_item  (int item_index);+	public signal void add_glyph_item  (Glyph item);++	public VersionList (GlyphCollection gc) { 		MenuAction ma = add_item (t_("New version")); 		ma.has_delete_button = false;-		ma.action = (self) => {-			return_if_fail (self.parent != null);+		ma.action.connect ((self) => { 			return_if_fail (glyphs.size > 0); 			 			BirdFont.get_current_font ().touch (); 			 			add_new_version (); 			current_version_id = glyphs.get (glyphs.size - 1).version_id;-		};+		}); 	 		// delete one version 		signal_delete_item.connect ((index) => { 			delete_item (index); 		});++		this.glyph_collection = gc;+		glyphs = new Gee.ArrayList<Glyph> ();+		set_direction (MenuDirection.POP_UP); 		-		if (g != null) {-			add_glyph ((!) g);+		glyphs = new Gee.ArrayList<Glyph> ();+		+		foreach (Glyph g in gc.glyphs) {+			add_glyph (g, false); 		}-+		+		set_selected_version (gc.get_current ().version_id);+		n_lists++; 	}+	+	~VersionList () {+		n_lists--; +		if (menu_visible) {+			warning ("menu is visible");+		}+	}+	 	private void delete_item (int index) { 		int current_version; 		Font font = BirdFont.get_current_font ();@@ -72,10 +104,10 @@ public class VersionList : DropMenu { 		return_if_fail (0 <= index < glyphs.size); 		 		font.deleted_glyphs.add (glyph_collection.get_current ());-		 		over_view.store_undo_state (glyph_collection.copy ()); 		 		glyphs.remove_at (index);+		glyph_collection.remove (index); 		 		recreate_index (); 		@@ -85,7 +117,11 @@ public class VersionList : DropMenu { 		} else if (index < current_version) { 			return_if_fail (0 <= current_version - 1 < glyphs.size); 			current_version_id = glyphs.get (current_version - 1).version_id;-		}	+			int i = get_current_version_index ();+			set_selected_item (get_action_index (i));+		}+		+		get_current ().selected_canvas (); 	}  	private int get_current_version_index () {@@ -96,7 +132,9 @@ public class VersionList : DropMenu { 			} 			i++; 		}-		return i;+		+		warning ("No index for menu item.");+		return 0; 	}  	public void set_selected_version (int version_id) {@@ -133,6 +171,7 @@ public class VersionList : DropMenu { 		Glyph new_version = g.copy (); 		new_version.version_id = get_last_id () + 1; 		add_glyph (new_version);+		add_glyph_item (new_version); 	} 	 	public int get_last_id () {@@ -149,19 +188,21 @@ public class VersionList : DropMenu { 		g = glyphs.get (i); 		 		current_version_id = g.version_id;-		-		return_if_fail (ma.parent != null);-		-		((!)ma.parent).deselect_all ();+		deselect_all (); 		ma.set_selected (true); 		 		reload_all_open_glyphs (); 		+		glyph_collection.set_selected (g);+		+		/* 		if (!is_null (BirdFont.current_glyph_collection)) { 			current_glyph = MainWindow.get_current_glyph (); 			g.set_allocation (current_glyph.allocation); 			g.set_default_zoom (); 		}+		*/+		 	} 	 	/** Reload a glyph when a new version is selected. Updates the path@@ -224,17 +265,19 @@ public class VersionList : DropMenu { 		ma = add_item (t_("Version") + @" $v"); 		ma.index = (int) glyphs.size - 1; 		-		ma.action = (self) => {+		ma.action.connect ((self) => { 			Font font = BirdFont.get_current_font (); 			set_selected_item (self); 			font.touch ();-		};+		});  		if (selected) { 			set_selected_item (ma); 		} 		-		update_selection ();+		if (selected) {+			update_selection ();+		} 	} 	 	bool has_version (int id) {@@ -247,11 +290,192 @@ public class VersionList : DropMenu { 	} 	 	void update_selection () {+		int index;+		 		if (has_version (current_version_id)) {-			set_selected_item (get_action_index (get_current_version_index () + 1)); // the first item is the "new version"+			index = get_current_version_index ();+			set_selected_item (get_action_index (index + 1)); // the first item is the "new version"+		}+	}++	public MenuAction get_action_index (int index) {+		if (!(0 <= index < actions.size)) {+			warning (@"No action for index $index. (actions.size: $(actions.size))");+			return new MenuAction ("None");+		}+		return actions.get (index);+	}+	+	public void recreate_index () {+		int i = -1;+		foreach (MenuAction a in actions) {+			a.index = i;+			i++;+		}+	}+	+	public MenuAction get_action_no2 () {+		if (actions.size < 2) {+			warning ("No such action");+			return new MenuAction ("None");+		}+		+		return actions.get (1);+	}+	+	public void deselect_all () {+		foreach (MenuAction m in actions) {+			m.set_selected (false);+		}+	}+	+	public void set_direction (MenuDirection d) {+		direction = d;+	}+	+	public void close () {+		menu_visible = false;+	}+	+	public MenuAction add_item (string label) {+		MenuAction m = new MenuAction (label);+		add_menu_item (m);+		return m;+	}+	+	public void add_menu_item (MenuAction m) {+		actions.add (m);+	}+		+	public bool is_over_icon (double px, double py) {+		if (x == -1 || y == -1) {+			return false; 		}+		+		return x - 12 < px <= x && y - 5 < py < y + 12 + 5; 	} +	public bool menu_item_action (double px, double py) {+		MenuAction? action;+		MenuAction a;+		MenuAction ma;+		int index;+		+		if (menu_visible) {+			action = get_menu_action_at (px, py);+			+			if (action != null) {+				a = (!) action;+				+				// action for the delete button+				if (a.has_delete_button && menu_x + width - 13 < px <= menu_x + width) { +					index = 0;+					ma = actions.get (0);+					while (true) {+						if (a == ma) {+							actions.remove_at (index);+							signal_delete_item (index);+							break;+						}+						+						if (ma == actions.get (actions.size - 1)) {+							break;+						} else {+							ma = actions.get (index + 1);+							index++;+						}+					}+					return false;+				} else {+					a.action (a);+					selected (this);+					menu_visible = false;+				}+				+				return true;+			}+		}+		+		return false;+	}+	+	public bool menu_icon_action (double px, double py) {		+		menu_visible = is_over_icon (px, py);+		return menu_visible;+	}+	+	MenuAction? get_menu_action_at (double px, double py) {+		double n = 0;+		double ix, iy;+		+		foreach (MenuAction item in actions) {+			ix = menu_x - 6;+			+			if (direction == MenuDirection.DROP_DOWN) {+				iy = y + 12 + n * item_height;+			} else {+				iy = y - 24 - n * item_height;+			}+	+			if (ix <= px <= ix + width && iy <= py <= iy + item_height) {+				return item;+			}+			+			n++;			+		}++		return null;+	}+	+	public void set_position (double px, double py) {+		x = px;+		y = py;++		foreach (MenuAction item in actions) {+			item.text = new Text (item.label);+			if (item.text.get_sidebearing_extent () + 25 > width) {+				width = item.text.get_sidebearing_extent () + 25;+			}+		}+				+		if (x - width + 19 < 0) {+			menu_x = 30;+		} else {+			menu_x = x - width;+		}+	}+	+	public void draw_menu (Context cr) {+		double ix, iy;+		int n;+	+		if (likely (!menu_visible)) {+			return;+		}+		+		cr.save ();+		Theme.color (cr, "Default Background");+		cr.rectangle (menu_x, y - actions.size * item_height, width, actions.size * item_height);+		+		cr.fill_preserve ();+		cr.stroke ();+		cr.restore ();+		+		cr.save ();+		+		n = 0;+		foreach (MenuAction item in actions) {+			item.width = width;+			+			iy = y - 8 - n * item_height;+			ix = menu_x + 2;+			+			item.draw (ix, iy, cr);+			n++;+		}+		+		cr.restore ();+	} }  }

Contact

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