Clone in a terminal:
Commit b832c52
Johan Mattsson - 2022-09-23T16:35:25+00:00
b832c5262f47fc168e657fada574f292d306d11fjohan.mattsson.m@gmail.com

Refactoring

Changed files (18)

Diff

diff --git a/libbirdfont/ClipTool.vala b/libbirdfont/ClipTool.valaindex ff567d5..0039732 100644--- a/libbirdfont/ClipTool.vala+++ b/libbirdfont/ClipTool.vala@@ -39,7 +39,7 @@ public class ClipTool : Tool { 			data = svg_data + bf_data; 			MainWindow.native_window.set_clipboard (data); 			MainWindow.native_window.set_inkscape_clipboard (data);-		} else if (fd is OverView) {+		} else if (fd is Overview) { 			copy_overview_glyphs (); 		} else if (fd is DescriptionDisplay) { 			DescriptionDisplay description_tab = (DescriptionDisplay) fd;@@ -74,7 +74,7 @@ public class ClipTool : Tool { 		string svg_data = ""; 		string bf_data = ""; 		string data;-		OverView o = MainWindow.get_overview ();+		Overview o = MainWindow.get_overview (); 		 		if (o.selected_items.size > 0) { 			svg_data = ExportTool.export_to_inkscape_clipboard (@@ -114,7 +114,7 @@ public class ClipTool : Tool { 			paste_letters_to_spacing_tab (); 		} else if (fd is KerningDisplay) { 			paste_letters_to_kerning_tab ();-		} else if (fd is OverView) {+		} else if (fd is Overview) { 			paste_to_overview (); 		} else if (fd is DescriptionDisplay) { 			DescriptionDisplay description_tab = (DescriptionDisplay) fd;@@ -190,7 +190,7 @@ public class ClipTool : Tool { 		Path new_path; 		Glyph glyph; 		GlyphCollection glyph_collection;-		OverView o;+		Overview o; 		 		if (overview) { 			o = MainWindow.get_overview ();@@ -380,7 +380,7 @@ public class ClipTool : Tool { 		unichar c; 		Glyph destination; 		GlyphCollection glyph_collection = new GlyphCollection ('\0', "");-		OverView o;+		Overview o; 		Path path = new Path (); 		 		foreach (string p in items) {diff --git a/libbirdfont/ExportTool.vala b/libbirdfont/ExportTool.valaindex 5b12df2..498ffce 100644--- a/libbirdfont/ExportTool.vala+++ b/libbirdfont/ExportTool.vala@@ -185,8 +185,8 @@ public class ExportTool : GLib.Object { 			 			if (fd is GlyphTab || fd is Glyph) { 				glyph = MainWindow.get_current_glyph ();-			} else if (fd is OverView) {-				OverView overview = MainWindow.get_overview ();+			} else if (fd is Overview) {+				Overview overview = MainWindow.get_overview (); 				Glyph? g = overview.get_selected_glyph (); 				 				if (g == null) {diff --git a/libbirdfont/FileTools.vala b/libbirdfont/FileTools.valaindex 63a54ed..7972458 100644--- a/libbirdfont/FileTools.vala+++ b/libbirdfont/FileTools.vala@@ -85,10 +85,10 @@ public class FileTools : ToolCollection  { 					tc.clear_cache (); 				} -				OverViewItem.label_background = null;-				OverViewItem.selected_label_background = null;-				OverViewItem.label_background_no_menu = null;-				OverViewItem.selected_label_background_no_menu = null;+				OverviewItem.label_background = null;+				OverviewItem.selected_label_background = null;+				OverviewItem.label_background_no_menu = null;+				OverviewItem.selected_label_background_no_menu = null; 				 				foreach (Tool t in themes.tool) {					 					t.set_selected (false);diff --git a/libbirdfont/Glyph.vala b/libbirdfont/Glyph.valaindex 440ffe9..dc02763 100644--- a/libbirdfont/Glyph.vala+++ b/libbirdfont/Glyph.vala@@ -531,7 +531,7 @@ public class Glyph : FontDisplay { 		base_line.position_updated.connect ((pos) => { 				Font f = BirdFont.get_current_font (); 				f.base_line = pos;-				OverView o = MainWindow.get_overview ();+				Overview o = MainWindow.get_overview (); 				o.reset_cache (); 			}); diff --git a/libbirdfont/GlyphSelection.vala b/libbirdfont/GlyphSelection.valaindex a0f584d..849b72a 100644--- a/libbirdfont/GlyphSelection.vala+++ b/libbirdfont/GlyphSelection.vala@@ -15,7 +15,7 @@ namespace BirdFont {  /** A tab for picking characters in the font. */-public class GlyphSelection : OverView {+public class GlyphSelection : Overview {  	public signal void selected_glyph (GlyphCollection gc); diff --git a/libbirdfont/LanguageSelectionTab.vala b/libbirdfont/LanguageSelectionTab.valaindex caaa37a..587aa5a 100644--- a/libbirdfont/LanguageSelectionTab.vala+++ b/libbirdfont/LanguageSelectionTab.vala@@ -46,7 +46,7 @@ public class LanguageSelectionTab : Table {  	void select_language (int row) { 		string iso_code;-		OverView overview;+		Overview overview; 		GlyphRange gr; 		TabBar tb = MainWindow.get_tab_bar (); 		diff --git a/libbirdfont/MainWindow.vala b/libbirdfont/MainWindow.valaindex 08b5e6d..5b9096a 100644--- a/libbirdfont/MainWindow.vala+++ b/libbirdfont/MainWindow.vala@@ -21,7 +21,7 @@ public class MainWindow : GLib.Object { 	public static MainWindow singleton;
 	public static MenuTab menu_tab;
 	public static RecentFiles file_tab;
-	public static OverView overview;	
+	public static Overview overview;	
 	public static TabBar tabs;
 	public static NativeWindow native_window;
 	public static KerningDisplay kerning_display;
@@ -47,7 +47,7 @@ public class MainWindow : GLib.Object { 		tools = new Toolbox (glyph_canvas, tabs);
 		menu_tab = new MenuTab ();
 		file_tab = new RecentFiles ();
-		overview = new OverView();
+		overview = new Overview();
 		kerning_display = new KerningDisplay ();
 		character_database = new CharDatabase ();
 		ligature_display = new LigatureList ();
@@ -334,10 +334,10 @@ public class MainWindow : GLib.Object { 		tools = tb;
 	}
 -	public static OverView get_overview () {+	public static Overview get_overview () { 		foreach (Tab t in tabs.tabs) {-			if (t.get_display () is OverView) {-				return (OverView) t.get_display ();+			if (t.get_display () is Overview) {+				return (Overview) t.get_display (); 			} 		} 		diff --git a/libbirdfont/Menu.vala b/libbirdfont/Menu.valaindex a3004be..b27ae45 100644--- a/libbirdfont/Menu.vala+++ b/libbirdfont/Menu.vala@@ -154,7 +154,7 @@ public class Menu : AbstractMenu {  		MenuItem search = add_menu_item (t_("Search"), "search"); 		search.action.connect (() => {-			OverView.search ();+			Overview.search (); 			show_menu = false; 		}); 		edit_menu.items.add (search);diff --git a/libbirdfont/MenuTab.vala b/libbirdfont/MenuTab.valaindex 1b1a152..1033444 100644--- a/libbirdfont/MenuTab.vala+++ b/libbirdfont/MenuTab.vala@@ -212,7 +212,7 @@ public class MenuTab : FontDisplay { 		if (BirdFont.get_current_font ().is_empty ()) { 			show_default_characters (); 		} else {-			MainWindow.get_tab_bar ().add_unique_tab (new OverView ());+			MainWindow.get_tab_bar ().add_unique_tab (new Overview ()); 			MainWindow.get_tab_bar ().select_tab_name ("Overview"); 		} 	}@@ -554,7 +554,7 @@ public class MenuTab : FontDisplay { 		 		Glyph.background_glyph = MainWindow.get_current_glyph (); 		-		if (MainWindow.get_current_display () is OverView) {+		if (MainWindow.get_current_display () is Overview) { 			Glyph.background_glyph = MainWindow.get_overview ().get_current_glyph (); 		} 	}@@ -724,7 +724,7 @@ public class MenuTab : FontDisplay { 			GlyphCollection? fg; 			Glyph glyph; 			GlyphCollection glyph_collection;-			OverView o = MainWindow.get_overview ();+			Overview o = MainWindow.get_overview ();  			fg = font.get_glyph_collection_by_name (ligature_name); @@ -749,8 +749,8 @@ public class MenuTab : FontDisplay { 	} 	 	public static void show_default_characters () {-		MainWindow.get_tab_bar ().add_unique_tab (new OverView ());-		OverView o = MainWindow.get_overview ();+		MainWindow.get_tab_bar ().add_unique_tab (new Overview ());+		Overview o = MainWindow.get_overview (); 		GlyphRange gr = new GlyphRange ();  		if (!BirdFont.get_current_font ().initialised) {@@ -764,7 +764,7 @@ public class MenuTab : FontDisplay { 	} 	 	public static void show_all_available_characters () {-		MainWindow.get_tab_bar ().add_unique_tab (new OverView ());+		MainWindow.get_tab_bar ().add_unique_tab (new Overview ()); 		 		if (!BirdFont.get_current_font ().initialised) { 			MenuTab.new_file ();diff --git a/libbirdfont/OtfFeatureTable.vala b/libbirdfont/OtfFeatureTable.valaindex 6135e75..2d88912 100644--- a/libbirdfont/OtfFeatureTable.vala+++ b/libbirdfont/OtfFeatureTable.vala@@ -224,7 +224,7 @@ public class OtfFeatureTable : Table { 		listener.signal_submit.connect (() => { 			GlyphCollection alt; 			Font font;-			OverView overview = MainWindow.get_overview ();+			Overview overview = MainWindow.get_overview (); 			 			font = BirdFont.get_current_font (); diff --git a/libbirdfont/OverView.vala b/libbirdfont/OverView.valadeleted file mode 100644index 1f3a418..0000000--- a/libbirdfont/OverView.vala+++ /dev/null@@ -1,1770 +0,0 @@-/*-	Copyright (C) 2012 - 2016 Johan Mattsson--	This library is free software; you can redistribute it and/or modify -	it under the terms of the GNU Lesser General Public License as -	published by the Free Software Foundation; either version 3 of the -	License, or (at your option) any later version.--	This library is distributed in the hope that it will be useful, but -	WITHOUT ANY WARRANTY; without even the implied warranty of -	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -	Lesser General Public License for more details.-*/--using Cairo;--namespace BirdFont {--/** A display with all glyphs present in this font. */-public class OverView : FontDisplay {-	public WidgetAllocation allocation = new WidgetAllocation ();-	-	public OverViewItem selected_item = new OverViewItem ();--	public Gee.ArrayList<GlyphCollection> copied_glyphs = new Gee.ArrayList<GlyphCollection> ();-	public Gee.ArrayList<GlyphCollection> selected_items = new Gee.ArrayList<GlyphCollection> ();	-	-	int selected = 0;-	int first_visible = 0;-	int rows = 0;-	int items_per_row = 0;-	-	double view_offset_y = 0;-	double view_offset_x = 0;-	-	public signal void open_new_glyph_signal (unichar c);-	public signal void open_glyph_signal (GlyphCollection c);-	-	public GlyphRange glyph_range {-		get {-			return _glyph_range;-		}-		-		set {-			_glyph_range = value;-		}-	}-	-	GlyphRange _glyph_range;-	-	string search_query = "";-	-	public Gee.ArrayList<OverViewItem> visible_items = new Gee.ArrayList<OverViewItem> ();-	-	/** List of undo commands. */-	public Gee.ArrayList<OverViewUndoItem> undo_items = new Gee.ArrayList<OverViewUndoItem> ();-	public Gee.ArrayList<OverViewUndoItem> redo_items = new Gee.ArrayList<OverViewUndoItem> ();-	-	/** Show all characters that has been drawn. */-	public bool all_available {-		set {-			_all_available = value;-			update_item_list ();-		}-		-		get {-			return _all_available;-		}-	}-	-	bool _all_available = false;-	-	/** Show unicode database info. */-	CharacterInfo? character_info = null;-	-	double scroll_size = 1;-	const double UCD_LINE_HEIGHT = 17 * 1.3;--	private bool update_scheduled = true;--	public OverView (GlyphRange? range = null,-		bool open_selected = true, bool default_character_set = true) {-			-		GlyphRange gr;-		-		if (range == null) {-			gr = new GlyphRange ();-			set_current_glyph_range (gr);-		}--		if (open_selected) {-			this.open_glyph_signal.connect ((glyph_collection) => {-				TabBar tabs = MainWindow.get_tab_bar ();-				string n = glyph_collection.get_current ().name;-				bool selected = tabs.select_char (n);-				GlyphTab glyph_tab;-				-				if (!selected) {-					glyph_tab = new GlyphTab (glyph_collection);-					tabs.add_tab (glyph_tab, true, glyph_collection);-					set_glyph_zoom (glyph_collection);-					PenTool.update_orientation ();-				}-			});--			this.open_new_glyph_signal.connect ((character) => {-				// ignore control characters-				if (character <= 0x1F || character == 0xFFFF) { -					return;-				}-				-				create_new_glyph (character);-			});-		}--		if (default_character_set) {-			IdleSource idle = new IdleSource ();--			idle.set_callback (() => {-				use_default_character_set ();-				selected_canvas ();-				return false;-			});-			-			idle.attach (null);-		}-						-		update_item_list ();-		update_scrollbar ();-		reset_zoom ();-		-		string? zoom = Preferences.get ("overview_zoom");-		-		if (zoom != null) {-			string z = (!) zoom;-			-			if (z != "") {-				set_zoom (double.parse (z));-			}			-		}-	}--	public void reset_cache () {-		foreach (OverViewItem i in visible_items) {-			i.clear_cache ();-		}-	}--	public Glyph? get_selected_glyph () {-		if (selected_items.size == 0) {-			return null;-		}-		-		return selected_items.get (0).get_current ();-	}-	-	public void select_all_glyphs () {-		Font f;-		GlyphCollection? glyphs;-		-		f = BirdFont.get_current_font ();-		-		for (int index = 0; index < f.length (); index++) {-			glyphs = f.get_glyph_collection_index ((uint32) index);-			return_if_fail (glyphs != null);-			-			selected_items.add ((!) glyphs);-		}-		-		foreach (OverViewItem item in visible_items) {-			item.selected = item.glyphs != null;-		}-		-		GlyphCanvas.redraw ();-	}-	-	public void use_default_character_set () {-		GlyphRange gr = new GlyphRange ();-		all_available = false;-		DefaultCharacterSet.use_default_range (gr);-		set_current_glyph_range (gr);-		OverviewTools.update_overview_characterset ();-		FontDisplay.dirty_scrollbar = true;-	}-	-	public GlyphCollection create_new_glyph (unichar character) {-		StringBuilder name = new StringBuilder ();-		TabBar tabs = MainWindow.get_tab_bar ();-		bool selected;-		Glyph glyph;-		GlyphCollection glyph_collection;-		GlyphCanvas canvas;-		GlyphTab glyph_tab; -		-		glyph_collection = MainWindow.get_current_glyph_collection ();-		name.append_unichar (character);-		selected = tabs.select_char (name.str);-				-		if (!selected) {-			glyph_collection = add_character_to_font (character);-			glyph_tab = new GlyphTab (glyph_collection);-			glyph = glyph_collection.get_current ();-			glyph.layers.add_layer (new Layer ());-			tabs.add_tab (glyph_tab, true, glyph_collection);-			-			selected_items.add (glyph_collection);-			-			canvas = MainWindow.get_glyph_canvas ();-			canvas.set_current_glyph_collection (glyph_collection);-			-			set_glyph_zoom (glyph_collection);-		} else {-			warning ("Glyph is already open");-		}-		-		OverviewTools.update_overview_characterset ();-		return glyph_collection;-	}-		-	public GlyphCollection add_empty_character_to_font (unichar character, bool unassigned, string name) {-		return add_character_to_font (character, true, unassigned);-	}-	-	public GlyphCollection add_character_to_font (unichar character, bool empty = false,-			bool unassigned = false, string glyph_name = "") {-		StringBuilder name = new StringBuilder ();-		Font font = BirdFont.get_current_font ();-		GlyphCollection? fg;-		Glyph glyph;-		GlyphCollection glyph_collection;--		if (glyph_name == "") {-			name.append_unichar (character);-		} else {-			name.append (glyph_name);-		}-		-		if (all_available) {-			fg = font.get_glyph_collection_by_name (name.str);-		} else {-			fg = font.get_glyph_collection (name.str);-		}--		if (fg != null) {-			glyph_collection = (!) fg;-		} else {-			glyph_collection = new GlyphCollection (character, name.str);-			-			if (!empty) {-				glyph = new Glyph (name.str, !unassigned ? character : '\0');-				glyph_collection.add_master (new GlyphMaster ());-				glyph_collection.insert_glyph (glyph, true);-			}-			-			font.add_glyph_collection (glyph_collection);-		}-		-		glyph_collection.set_unassigned (unassigned);-		-		return glyph_collection;-	}-	-	public static void search () {-		OverView ow = MainWindow.get_overview ();-		TextListener listener = new TextListener (t_("Search"), ow.search_query, t_("Filter"));-		-		listener.signal_text_input.connect ((text) => {-			OverView o = MainWindow.get_overview ();-			o.search_query = text;-		});-		-		listener.signal_submit.connect (() => {-			OverView o = MainWindow.get_overview ();-			string q = o.search_query;-			-			if (q == "*") {- 				q = "star";- 			}-						-			if (q == "?") {-				q = "question";-			}--			if (q.char_count () > 1) {-				q = q.down ();-			}-			-			GlyphRange r = CharDatabase.search (q);-			o.set_current_glyph_range (r);-			MainWindow.get_tab_bar ().select_tab_name ("Overview");-	-			TextListener tl = new TextListener (t_("Search"), o.search_query, t_("Filter"));-			TabContent.show_text_input (tl);-		});-		-		TabContent.show_text_input (listener);-	}-	-	public Glyph? get_current_glyph () {-		OverViewItem oi = selected_item;-		if (oi.glyphs != null) {-			return ((!) oi.glyphs).get_current ();-		}-		return null;-	}-	-	public void set_glyph_zoom (GlyphCollection glyphs) {-		GlyphCanvas canvas;-		canvas = MainWindow.get_glyph_canvas ();-		canvas.set_current_glyph_collection (glyphs);-		Toolbox tools = MainWindow.get_toolbox ();-		ZoomTool z = (ZoomTool) tools.get_tool ("zoom_tool");-		z.store_current_view ();-		glyphs.get_current ().default_zoom ();-		z.store_current_view ();-		OverViewItem.reset_label ();-	}-	-	public double get_height () {-		double l;-		Font f;-		-		if (rows == 0) {-			return 0;-		}-				-		if (all_available) {-			f = BirdFont.get_current_font ();-			l = f.length ();-		} else {-			l = glyph_range.length ();-		}-				-		return 2.0 * OverViewItem.height * (l / rows);-	}--	public bool selected_char_is_visible () {-		return first_visible <= selected <= first_visible + items_per_row * rows;-	}--	public override bool has_scrollbar () {-		return true;-	}--	public bool all_characters_in_view () {-		double length;-		Font f;-		-		if (all_available) {-			f = BirdFont.get_current_font ();-			length = f.length ();-		} else {-			length = glyph_range.length ();-		}-		-		return length < items_per_row * rows;-	}-	-	public void move_up () {-		first_visible -= items_per_row;-		selected += items_per_row;-		-		if (first_visible < 0) {-			selected -= items_per_row;-			first_visible = 0;-			view_offset_y = 0;-		}-	}--	public void move_down () {-		if (!at_bottom ()) {-			first_visible += items_per_row;-			selected -= items_per_row;-		}-	}-	-	public override void scroll_wheel (double x, double y, double dx, double dy) {-		double pixel_delta = 3 * dy;-		-		if (dy > 0) {-			view_offset_y += pixel_delta;-			-			while (view_offset_y > 0) {-				view_offset_y -= OverViewItem.height;-				move_up ();-			}						-		} else {-			if (at_bottom ()) {-				if (view_offset_y > -2 * OverViewItem.height && !all_characters_in_view ()) {-					view_offset_y += pixel_delta;-				}-			} else {-				view_offset_y += pixel_delta;-				while (view_offset_y < -OverViewItem.height) {-					view_offset_y += OverViewItem.height;-					move_down ();-				}-			}-		}-				-		if (view_offset_y < -2 * OverViewItem.height) {-			view_offset_y = -2 * OverViewItem.height;-		}-		-		update_item_list ();-		update_scrollbar ();-		hide_menu ();	-		GlyphCanvas.redraw ();-	}-	-	public override void selected_canvas () {-		OverviewTools.update_overview_characterset ();-		KeyBindings.set_require_modifier (true);-		update_scrollbar ();-		update_zoom_bar ();-		OverViewItem.glyph_scale = 1;-		update_item_list ();-		selected_item = get_selected_item ();-		GlyphCanvas.redraw ();-	}-	-	public void update_zoom_bar () {-		double z = OverViewItem.width / OverViewItem.DEFAULT_WIDTH - 0.5;-		Toolbox.overview_tools.zoom_bar.set_zoom (z);-		Toolbox.redraw_tool_box ();-		update_item_list ();-	}-	-	public void set_zoom (double zoom) {-		double z = zoom + 0.5;-		OverViewItem.glyph_scale = 1;-		OverViewItem.width = OverViewItem.DEFAULT_WIDTH * z;-		OverViewItem.height = OverViewItem.DEFAULT_HEIGHT * z;-		OverViewItem.margin = OverViewItem.DEFAULT_MARGIN * z;-		update_item_list ();-		OverViewItem.reset_label ();-		Preferences.set ("overview_zoom", @"$zoom");--		Font font = BirdFont.get_current_font ();-		for (int index = 0; index < font.length (); index++) {-			GlyphCollection? glyphs = font.get_glyph_collection_index ((uint32) index);-			return_if_fail (glyphs != null);-			GlyphCollection g = (!) glyphs;-			g.get_current ().overview_thumbnail = null;-		}-		-		GlyphCanvas.redraw ();-	}-	-	public override void zoom_min () {-		OverViewItem.width = OverViewItem.DEFAULT_WIDTH * 0.5;-		OverViewItem.height = OverViewItem.DEFAULT_HEIGHT * 0.5;-		OverViewItem.margin = OverViewItem.DEFAULT_MARGIN * 0.5;-		update_item_list ();-		OverViewItem.reset_label ();-		GlyphCanvas.redraw ();-		update_zoom_bar ();-	}-	-	public override void reset_zoom () {-		OverViewItem.width = OverViewItem.DEFAULT_WIDTH;-		OverViewItem.height = OverViewItem.DEFAULT_HEIGHT;-		OverViewItem.margin = OverViewItem.DEFAULT_MARGIN;-		update_item_list ();-		OverViewItem.reset_label ();-		GlyphCanvas.redraw ();-		update_zoom_bar ();-	}--	public override void zoom_max () {-		OverViewItem.width = allocation.width;-		OverViewItem.height = allocation.height;-		update_item_list ();-		OverViewItem.reset_label ();-		GlyphCanvas.redraw ();-	}-	-	public override void zoom_in () {-		OverViewItem.width *= 1.1;-		OverViewItem.height *= 1.1;-		OverViewItem.margin *= 1.1;-		update_item_list ();-		OverViewItem.reset_label ();-		GlyphCanvas.redraw ();-		update_zoom_bar ();-	}-	-	public override void zoom_out () {-		OverViewItem.width *= 0.9;-		OverViewItem.height *= 0.9;-		OverViewItem.margin *= 0.9;-		update_item_list ();-		OverViewItem.reset_label ();-		GlyphCanvas.redraw ();-		update_zoom_bar ();-	}--	public override void store_current_view () {-	}-	-	public override void restore_last_view () {-	}--	public override void next_view () {-	}--	public override string get_label () {-		return t_("Overview");-	}-	-	public override string get_name () {-		return "Overview";-	}-	-	public void display_all_available_glyphs () {-		all_available = true;--		view_offset_y = 0;-		first_visible = 0;-		selected = 0;-		-		update_item_list ();-		selected_item = get_selected_item ();-		GlyphCanvas.redraw ();-	}-	-	OverViewItem get_selected_item () {-		if (visible_items.size == 0) {-			return new OverViewItem ();-		}-		-		if (!(0 <= selected < visible_items.size)) { -			return selected_item;-		}--		OverViewItem item = visible_items.get (selected);-		item.selected = true;-		return item;-	}-	-	int get_items_per_row () {-		int i = 1;-		double tab_with = allocation.width - 30; // 30 px for the scroll bar-		OverViewItem.margin = OverViewItem.width * 0.1;-		double l = OverViewItem.margin + OverViewItem.full_width ();-		-		while (l <= tab_with) {-			l += OverViewItem.full_width ();-			i++;-		}-		-		return i - 1;-	}-	-	public void update_item_list () {-		update_scheduled = true;-	}-	-	public void process_item_list_update () {-		string character_string;-		Font f = BirdFont.get_current_font ();-		GlyphCollection? glyphs = null;-		uint32 index;-		OverViewItem item;-		double x, y;-		unichar character;-		Glyph glyph;-		double tab_with;-		int item_list_length;-		int visible_size;-		-		tab_with = allocation.width - 30; // scrollbar-		-		items_per_row = get_items_per_row ();-		rows = (int) (allocation.height /  OverViewItem.full_height ()) + 2;-		-		item_list_length = items_per_row * rows;-		visible_items.clear ();-		-		index = (uint32) first_visible;-		x = OverViewItem.margin;-		y = OverViewItem.margin;-		-		if (all_available) {-			uint font_length = f.length ();-			-			for (int i = 0; i < item_list_length && index < font_length; i++) {-				glyphs = f.get_glyph_collection_index ((uint32) index);-				return_if_fail (glyphs != null);-				-				glyph = ((!) glyphs).get_current ();-				character_string = glyph.name;-				character = glyph.unichar_code;-				-				item = new OverViewItem ();-				item.set_character (character);-				item.set_glyphs (glyphs);-				item.x = x;-				item.y = y;-				visible_items.add (item);-				index++;-			}-		} else {-			uint32 glyph_range_size = glyph_range.get_length ();-			-			uint max_length = glyph_range.length () - first_visible;-			-			if (item_list_length > max_length) {-				item_list_length = (int) max_length;-			}-			-			for (int i = 0; i < item_list_length && index < glyph_range_size; i++) {			-				item = new OverViewItem ();-				visible_items.add (item);-			}-			-			index = (uint32) first_visible;-			visible_size = visible_items.size;-			for (int i = 0; i < visible_size; i++) {-				item = visible_items.get (i);-				character = glyph_range.get_character ((uint32) index);-				item.set_character (character);-				index++;-			}--			visible_size = visible_items.size;-			for (int i = 0; i < visible_size; i++) {-				item = visible_items.get (i);-				glyphs = f.get_glyph_collection_by_name ((!) item.character.to_string ());-				item.set_glyphs (glyphs);-			}-		}-		-		x = OverViewItem.margin;-		y = OverViewItem.margin;-		-		visible_size = visible_items.size;-		int selected_index;-		bool selected_item;-		double full_width = OverViewItem.full_width ();-		-		for (int i = 0; i < visible_size; i++) {-			item = visible_items.get (i);--			selected_item = false;-	-			if (all_available) {-				glyphs = f.get_glyph_collection_index ((uint32) i);-			} else {			-				glyphs = f.get_glyph_collection_by_name ((!) item.character.to_string ());-			}-			-			if (glyphs != null) {-				selected_index = selected_items.index_of ((!) glyphs);-				selected_item = (selected_index != -1);-			}-						-			selected_item |= (i == selected);-			item.selected = selected_item;-			-			item.x = x + view_offset_x;-			item.y = y + view_offset_y;-			-			x += full_width;-			-			if (x + full_width >= tab_with) {-				x = OverViewItem.margin;-				y += OverViewItem.full_height ();-			}-		}-		-		update_scheduled = false;-	}-	-	public override void draw (WidgetAllocation allocation, Context cr) {-		if (update_scheduled-			|| this.allocation.width != allocation.width-			|| this.allocation.height != allocation.height-			|| this.allocation.width == 0) {-			this.allocation = allocation;-			process_item_list_update ();-		}-		-		this.allocation = allocation;-		-		// clear canvas-		cr.save ();-		Theme.color (cr, "Background 1");-		cr.rectangle (0, 0, allocation.width, allocation.height);-		cr.fill ();-		cr.restore ();-		-		foreach (OverViewItem i in visible_items) {-			i.draw (allocation, cr);-		}-		-		if (unlikely (visible_items.size == 0)) {-			draw_empty_canvas (allocation, cr);-		}-		-		if (unlikely (character_info != null)) {-			draw_character_info (cr);-		}-	}-		-	void draw_empty_canvas (WidgetAllocation allocation, Context cr) {-		Text t;-		-		cr.save ();-		t = new Text (t_("No glyphs in this view."), 24);-		Theme.text_color (t, "Text Foreground");-		t.widget_x = 40;-		t.widget_y = 30;-		t.draw (cr);-		cr.restore ();-	}-	-	public void scroll_rows (int row_adjustment) {-		for (int i = 0; i < row_adjustment; i++) {-			scroll (-OverViewItem.height);-		}-		-		for (int i = 0; i > row_adjustment; i--) {-			scroll (OverViewItem.height);-		}-	}-	-	public void scroll_adjustment (double pixel_adjustment) {-		double l;-		Font f;-				-		if (all_available) {-			f = BirdFont.get_current_font ();-			l = f.length ();-		} else {-			l = glyph_range.length ();-		}-		-		if (first_visible <= 0) {-			return;-		}--		if (first_visible + rows * items_per_row >= l) {-			return;-		}-		-		scroll ((int64) pixel_adjustment);-	}-	-	void scroll_to_position (int64 r) {-		if (r < 0) {-			scroll_top ();-			return;-		}-		-		selected -= (int) (r - first_visible);-		first_visible = (int) r;-		update_item_list ();-	}-	-	public override void scroll_to (double position) requires (items_per_row > 0) {-		double r;-		int nrows;-		Font f;-		-		if (all_available) {-			f = BirdFont.get_current_font ();-			nrows = (int) (f.length () / items_per_row);-		} else {-			nrows = (int) (glyph_range.length () / items_per_row);-		}-		-		view_offset_y = 0;-		r = (int64) (position * (nrows - rows + 3)); // 3 invisible rows-		r *= items_per_row;-		-		scroll_to_position ((int64) r);-		update_item_list ();-		GlyphCanvas.redraw ();-	}-		-	private void scroll (double pixel_adjustment) {-		if (first_visible < 0 && pixel_adjustment < 0) {-			scroll_top ();-			return;-		}-				-		view_offset_y += pixel_adjustment;-		-		if (view_offset_y >= 0) {-			while (view_offset_y > OverViewItem.height) {			-				view_offset_y -= OverViewItem.height;-				first_visible -= items_per_row;-			}--			first_visible -= items_per_row;-			view_offset_y -= OverViewItem.height;-		} else if (view_offset_y < -OverViewItem.height) {-			view_offset_y = 0;-			first_visible += items_per_row;-		}-		-		update_item_list ();-	}-	-	public void scroll_top () {-		first_visible = 0;-		view_offset_y = 0;-		-		update_item_list ();-		-		if (visible_items.size != 0) {-			selected_item = get_selected_item ();-		}-	}--	/** Returns true if the selected glyph is at the last row. */-	private bool last_row () {-		return visible_items.size - selected <= items_per_row;-	}--	public void key_down () {-		Font f = BirdFont.get_current_font ();-		int64 len = (all_available) ? f.length () : glyph_range.length ();-		-		if (at_bottom () && last_row ()) {-			return;-		}-		-		selected += items_per_row;-		-		if (selected >= items_per_row * rows) {-			first_visible += items_per_row;-			selected -= items_per_row;-		}-		-		if (first_visible + selected >= len) {-			selected = (int) (len - first_visible - 1);-			-			if (selected < items_per_row * (rows - 1)) {-				first_visible -= items_per_row;-				selected += items_per_row;-			}-		}-		-		if (selected >= visible_items.size) { -			selected = (int) (visible_items.size - 1); -		}--		selected_item = get_selected_item ();-		update_item_list ();-	}--	public void key_right () {-		Font f = BirdFont.get_current_font ();-		int64 len = (all_available) ? f.length () : glyph_range.length ();--		if (at_bottom () && first_visible + selected + 1 >= len) {-			selected = (int) (visible_items.size - 1);-			selected_item = get_selected_item ();-			return;-		}-		-		selected += 1;-		-		if (selected >= items_per_row * rows) {-			first_visible += items_per_row;-			selected -= items_per_row;-			selected -= 1;-		}		--		if (first_visible + selected > len) {-			first_visible -= items_per_row;-			selected = (int) (len - first_visible - 1);-			selected_item = get_selected_item ();-		}-		update_item_list ();-	}-	-	public void key_up () {-		selected -= items_per_row;-		-		if (selected < 0) {-			first_visible -= items_per_row;-			selected += items_per_row;			-		}-		-		if (first_visible < 0) {-			first_visible = 0;		-		}-		update_item_list ();-	}-	-	public void key_left () {-		selected -= 1;--		if (selected < 0) {-			first_visible -= items_per_row;-			selected += items_per_row;-			selected += 1;			-		}--		if (first_visible < 0) {-			scroll_top ();-		}-		update_item_list ();-	}-	-	public string get_selected_char () {-		Font f;-		Glyph? g;-		-		if (all_available) {-			f = BirdFont.get_current_font ();-			g = f.get_glyph_index (selected);-			return_val_if_fail (g != null, "".dup ());-			return ((!) g).get_name ();-		}-		-		return glyph_range.get_char (selected);-	}-	-	public override void key_press (uint keyval) {-		hide_menu ();-		update_item_list ();-		GlyphCanvas.redraw ();--		if (KeyBindings.has_ctrl () || KeyBindings.has_logo ()) {-			return;-		}--		switch (keyval) {-			case Key.ENTER:-				open_current_glyph ();-				return;-			-			case Key.UP:-				get_selected_item ().selected = false;-			-				key_up ();-				selected_item = get_selected_item ();-				-				selected_items.clear ();-				if (selected_item.glyphs != null) {-					selected_items.add ((!) selected_item.glyphs);-				}-				-				update_scrollbar ();-				return;-				-			case Key.RIGHT:-				get_selected_item ().selected = false;-			-				key_right ();-				selected_item = get_selected_item ();-				-				selected_items.clear ();-				if (selected_item.glyphs != null) {-					selected_items.add ((!) selected_item.glyphs);-				}-				-				update_scrollbar ();-				return;-				-			case Key.LEFT:-				get_selected_item ().selected = false;-				-				key_left ();-				selected_item = get_selected_item ();-				-				selected_items.clear ();-				if (selected_item.glyphs != null) {-					selected_items.add ((!) selected_item.glyphs);-				}-				-				update_scrollbar();-				return;-				-			case Key.DOWN:-				get_selected_item ().selected = false;-				-				key_down ();-				selected_item = get_selected_item ();-				-				selected_items.clear ();-				if (selected_item.glyphs != null) {-					selected_items.add ((!) selected_item.glyphs);-				}-				-				update_scrollbar ();-				return;-				-			case Key.PG_UP:-				get_selected_item ().selected = false;-				-				for (int i = 0; i < rows; i++) {-					key_up ();-				}-				selected_item = get_selected_item ();-				-				selected_items.clear ();-				if (selected_item.glyphs != null) {-					selected_items.add ((!) selected_item.glyphs);-				}-				-				update_scrollbar ();-				return;-				-			case Key.PG_DOWN:-				get_selected_item ().selected = false;-				-				for (int i = 0; i < rows; i++) {-					key_down ();-				}-				selected_item = get_selected_item ();--				selected_items.clear ();-				if (selected_item.glyphs != null) {-					selected_items.add ((!) selected_item.glyphs);-				}-				-				update_scrollbar ();-				return;-				-			case Key.DEL:-				delete_selected_glyph ();-				selected_item = get_selected_item ();-				return;-				-			case Key.BACK_SPACE:-				delete_selected_glyph ();-				selected_item = get_selected_item ();-				return;-		}--		if (!KeyBindings.has_ctrl () && !KeyBindings.has_logo ()) {-			scroll_to_char (keyval);-		}-		-		selected_item = get_selected_item ();--		selected_items.clear ();-		if (selected_item.glyphs != null) {-			selected_items.add ((!) selected_item.glyphs);-		}-		-		update_item_list ();-		GlyphCanvas.redraw ();-	}-	-	public void delete_selected_glyph () {-		Font font = BirdFont.get_current_font ();-		OverViewUndoItem undo_item = new OverViewUndoItem ();-		-		undo_item.alternate_sets = font.alternates.copy ();-		-		foreach (GlyphCollection g in selected_items) {-			undo_item.glyphs.add (g.copy ());-		}-		store_undo_items (undo_item);--		foreach (GlyphCollection glyph_collection in selected_items) {-			font.delete_glyph (glyph_collection);-			string name = glyph_collection.get_name ();-			MainWindow.get_tab_bar ().close_background_tab_by_name (name);-		}--		update_item_list ();-		GlyphCanvas.redraw ();-	}-	-	public override void undo () {-		Font font = BirdFont.get_current_font ();-		OverViewUndoItem previous_collection;-		-		if (undo_items.size == 0) {-			return;-		}-		-		previous_collection = undo_items.get (undo_items.size - 1);-		redo_items.add (get_current_state (previous_collection));-		-		// remove the old glyph and add the new one-		foreach (GlyphCollection g in previous_collection.glyphs) {-			font.delete_glyph (g);-			-			if (g.length () > 0) {-				font.add_glyph_collection (g);-			}--			TabBar tabs = MainWindow.get_tab_bar ();-			Tab? tab = tabs.get_tab (g.get_name ());-			-			if (tab != null) {-				Tab t = (!) tab;-				set_glyph_zoom (g);-				t.set_glyph_collection (g);-				t.set_display (new GlyphTab (g));-			}-		}-		-		Font f = BirdFont.get_current_font ();-		f.alternates = previous_collection.alternate_sets.copy ();--		undo_items.remove_at (undo_items.size - 1);-		update_item_list ();-		GlyphCanvas.redraw ();-	}-	-	public override void redo () {-		Font font = BirdFont.get_current_font ();-		OverViewUndoItem previous_collection;--		if (redo_items.size == 0) {-			return;-		}-		-		previous_collection = redo_items.get (redo_items.size - 1);-		undo_items.add (get_current_state (previous_collection));--		// remove the old glyph and add the new one-		foreach (GlyphCollection g in previous_collection.glyphs) {-			font.delete_glyph (g);-			font.add_glyph_collection (g);--			TabBar tabs = MainWindow.get_tab_bar ();-			Tab? tab = tabs.get_tab (g.get_name ());-			-			if (tab != null) {-				Tab t = (!) tab;-				set_glyph_zoom (g);-				t.set_glyph_collection (g);-				t.set_display (new GlyphTab (g));-			}-		}-		font.alternates = previous_collection.alternate_sets.copy ();--		redo_items.remove_at (redo_items.size - 1);-		GlyphCanvas.redraw ();-	}	-	-	public OverViewUndoItem get_current_state (OverViewUndoItem previous_collection) {-		GlyphCollection? gc;-		OverViewUndoItem ui = new OverViewUndoItem ();-		Font font = BirdFont.get_current_font ();-		-		ui.alternate_sets = font.alternates.copy ();-		-		foreach (GlyphCollection g in previous_collection.glyphs) {-			gc = font.get_glyph_collection (g.get_name ());-			-			if (gc != null) {-				ui.glyphs.add (((!) gc).copy ());-			} else {-				ui.glyphs.add (new GlyphCollection (g.get_unicode_character (), g.get_name ()));-			}-		}-		-		return ui;		-	}-	-	public void store_undo_state (GlyphCollection gc) {-		OverViewUndoItem i = new OverViewUndoItem ();-		Font f = BirdFont.get_current_font ();-		i.alternate_sets = f.alternates.copy ();-		i.glyphs.add (gc);-		store_undo_items (i);-	}--	public void store_undo_items (OverViewUndoItem i) {-		undo_items.add (i);-		redo_items.clear ();-	}-	-	bool select_visible_glyph (string name) {-		int i = 0;-		-		foreach (OverViewItem o in visible_items) {-			if (o.get_name () == name) {-				selected = i;-				selected_item = get_selected_item ();--				if (selected_item.y > allocation.height - OverViewItem.height) {-					view_offset_y -= (selected_item.y + OverViewItem.height) - allocation.height;-				}--				if (selected_item.y < 0) {-					view_offset_y = 0;-				}		--				return true;-			}-			-			if (i > 1000) {-				warning ("selected character not found");-				return true;-			}-			-			i++;-		}-		-		return false;-	}-	-	public void scroll_to_char (unichar c) {-		StringBuilder s = new StringBuilder ();--		if (is_modifier_key (c)) {-			return;-		}-		-		s.append_unichar (c);-		scroll_to_glyph (s.str);-	}-		-	public void scroll_to_glyph (string name) {-		GlyphRange gr = glyph_range;-		int i, r, index;-		string ch;-		Font font = BirdFont.get_current_font ();-		GlyphCollection? glyphs = null;-		Glyph glyph;-		-		index = -1;-		-		if (items_per_row <= 0) {-			return;-		}--		ch = name;--		// selected char is visible-		if (select_visible_glyph (ch)) {-			return;-		}-		-		// scroll to char-		if (all_available) {-			-			// don't search for glyphs in huge CJK fonts -			if (font.length () > 500) {-				r = 0;-			} else {-				// FIXME: too slow-				for (r = 0; r < font.length (); r += items_per_row) {-					for (i = 0; i < items_per_row && i < font.length (); i++) {-						glyphs = font.get_glyph_collection_index ((uint32) r + i);-						return_if_fail (glyphs != null);-						glyph = ((!) glyphs).get_current ();-						-						if (glyph.name == ch) {-							index = i;-						}-					}-					-					if (index > -1) {-						break;-					}-				}-			}-		} else {-			-			if (ch.char_count () > 1) {-				warning ("Can't scroll to ligature in this view");-				return;-			}-			-			for (r = 0; r < gr.length (); r += items_per_row) {-				for (i = 0; i < items_per_row; i++) {-					if (gr.get_char (r + i) == ch) {-						index = i;-					}-				}-				-				if (index > -1) {-					break;-				}-			}-		}-		-		if (index > -1) {-			first_visible = r;-			process_item_list_update ();-			update_item_list ();-			select_visible_glyph (ch);-		}-	}-	-	public override void double_click (uint button, double ex, double ey) -		requires (!is_null (visible_items) && !is_null (allocation)) {-		-		return_if_fail (!is_null (this));-		-		foreach (OverViewItem i in visible_items) {-			if (i.double_click (button, ex, ey)) {-				open_overview_item (i);-			}-		}-	-		GlyphCanvas.redraw ();-	}--	public void open_overview_item (OverViewItem i) {-		return_if_fail (!is_null (i));-		-		if (i.glyphs != null) {-			open_glyph_signal ((!) i.glyphs);-			GlyphCollection gc = (!) i.glyphs;-			gc.get_current ().close_path ();-		} else {-			open_new_glyph_signal (i.character);-		}-	}-	-	public void set_character_info (CharacterInfo i) {-		character_info = i;-	}--	public int get_selected_index () {-		GlyphCollection gc;-		int index = 0;-		-		if (selected_items.size == 0) {-			return 0;-		}-		-		gc = selected_items.get (0);-		-		foreach (OverViewItem i in visible_items) {-			if (i.glyphs != null && gc == ((!) i.glyphs)) {-				break;-			}-			-			index++;-		}-		-		return index;-	}--	public void hide_menu () {-		foreach (OverViewItem i in visible_items) {-			i.hide_menu ();-		}	-	}--	public override void button_press (uint button, double x, double y) {-		OverViewItem i;-		int index = 0;-		int selected_index = -1;-		bool update = false;-		-		if (character_info != null) {-			character_info = null;-			GlyphCanvas.redraw ();-			return;-		}-		-		if (!KeyBindings.has_shift ()) {-			selected_items.clear ();-		}-		-		for (int j = 0; j < visible_items.size; j++) {-			i = visible_items.get (j);-			if (i.click_menu (button, x, y)) {-				GlyphCanvas.redraw ();-				return;-			}-		}--		for (int j = 0; j < visible_items.size; j++) {-			i = visible_items.get (j);-			if (i.click_info (button, x, y)) {-				GlyphCanvas.redraw ();-				return;-			}-		}-				-		for (int j = 0; j < visible_items.size; j++) {-			i = visible_items.get (j);-			-			if (i.click (button, x, y)) {-				selected = index;-				selected_item = get_selected_item ();-				-				if (KeyBindings.has_shift ()) {-					if (selected_item.glyphs != null) {-						-						selected_index = selected_items.index_of ((!) selected_item.glyphs);-						if (selected_index == -1) {-							selected_items.add ((!) selected_item.glyphs);-						} else {-							return_if_fail (0 <= selected_index < selected_items.size);-							selected_items.remove_at (selected_index);-							selected = get_selected_index ();-							selected_item = get_selected_item ();-						}-					}-				} else {-					selected_items.clear ();-					if (selected_item.glyphs != null) {-						selected_items.add ((!) selected_item.glyphs);-					}-				}-				-				if (!is_null (i.version_menu)) {-					update = !((!)i).version_menu.menu_visible;-				} else {-					update = true;-				}-			}-			index++;-		}-	-		if (update) {-			update_item_list ();-		}-		-		GlyphCanvas.redraw ();-	}--	/** Returns true if overview shows the last character. */-	private bool at_bottom () {-		Font f;-		double t = rows * items_per_row + first_visible;--		if (all_available) {-			f = BirdFont.get_current_font ();-			return t >= f.length () + 2 * items_per_row;-		}-		-		return t >= glyph_range.length () + 2 * items_per_row;-	}-	-	public void set_current_glyph_range (GlyphRange range) {-		GlyphRange? current = glyph_range;-		string c;-		-		if (current != null) {-			c = glyph_range.get_char (selected);-		}-		-		all_available = false;-		-		glyph_range = range;-		scroll_top ();--		// TODO: scroll down to c-		update_item_list ();-		selected_item = get_selected_item ();--		GlyphCanvas.redraw ();-	}--	public void select_next_glyph () {-		key_right ();-	}-	-	public void open_current_glyph () {-		// keep this object even if open_glyph_signal closes the display-		this.ref ();-		 -		selected_item = get_selected_item ();-		if (selected_item.glyphs != null) {-			open_glyph_signal ((!) selected_item.glyphs);-			GlyphCollection gc = (!) selected_item.glyphs;-			gc.get_current ().close_path ();-		} else {-			open_new_glyph_signal (selected_item.character);-		}-		-		this.unref ();-	}--	public double update_scrollbar () {-		Font f;-		double nrows = 0;-		double pos = 0;-		double size;-		double visible_rows;-		-		if (rows == 0) {-			MainWindow.set_scrollbar_size (0);-			MainWindow.set_scrollbar_position (0);-		} else {-			if (all_available) {-				f = BirdFont.get_current_font ();-				nrows = Math.ceil ((f.length ()) / (double) rows);-				size = f.length ();-			} else {-				nrows = Math.ceil ((glyph_range.length ()) / (double) rows);-				size = glyph_range.length ();-			}-			-			if (nrows <= 0) {-				nrows = 1;-			}--			visible_rows = allocation.height / (OverViewItem.height + OverViewItem.margin);-			scroll_size = visible_rows / nrows;-			MainWindow.set_scrollbar_size (scroll_size);-			pos = first_visible / (size - visible_rows * items_per_row);-			-			if (pos > 1) {-				pos = 1;-			}-								-			MainWindow.set_scrollbar_position (pos);-			-			if (at_bottom () && first_visible == 0) {-				MainWindow.hide_scrollbar ();-			} else {-				MainWindow.show_scrollbar ();-			}-		}-		-		return pos;-	}--	/** Display one entry from the Unicode Character Database. */-	void draw_character_info (Context cr) -	requires (character_info != null) {-		double x, y, w, h;-		int i;-		string unicode_value, unicode_description;-		string[] column;-		string entry;-		int len = 0;-		int length = 0;-		bool see_also = false;-		WidgetAllocation allocation = MainWindow.get_overview ().allocation;-		string name;-		string[] lines;-		double character_start;-		double character_height;-		-		entry = ((!)character_info).get_entry ();--		lines = entry.split ("\n");-		-		foreach (string line in entry.split ("\n")) {-			len = line.char_count ();-			if (len > length) {-				length = len;-			}-		}-		-		x = allocation.width * 0.1;-		y = allocation.height * 0.1;-		w = allocation.width * 0.9 - x; -		h = allocation.height * 0.9 - y;-		-		if (w < 8 * length) {-			w = 8 * length;-			x = (allocation.width - w) / 2.0;-		}-		-		if (x < 0) {-			x = 2;-		}-		-		// background	-		cr.save ();-		Theme.color_opacity (cr, "Background 1", 0.98);-		cr.rectangle (x, y, w, h);-		cr.fill ();-		cr.restore ();--		cr.save ();-		Theme.color_opacity (cr, "Foreground 1", 0.98);-		cr.set_line_width (2);-		cr.rectangle (x, y, w, h);-		cr.stroke ();-		cr.restore ();--		// database entry-		-		if (((!)character_info).is_ligature ()) {-			name = ((!)character_info).get_name ();-			draw_info_line (name, cr, x, y, 0);-		} else {-			i = 0;-			foreach (string line in lines) {-				if (i == 0) {-					column = line.split ("\t");-					return_if_fail (column.length == 2);-					unicode_value = "U+" + column[0];-					unicode_description = column[1];--					draw_info_line (unicode_description, cr, x, y, i);-					i++;--					draw_info_line (unicode_value, cr, x, y, i);-					i++;			-				} else {-					-					if (line.has_prefix ("\t*")) {-						draw_info_line (line.replace ("\t*", "•"), cr, x, y, i);-						i++;					-					} else if (line.has_prefix ("\tx (")) {-						if (!see_also) {-							i++;-							draw_info_line (t_("See also:"), cr, x, y, i);-							i++;-							see_also = true;-						}-						-						draw_info_line (line.replace ("\tx (", "•").replace (")", ""), cr, x, y, i);-						i++;-					} else {-						i++;-					}-				}-			}-			-			character_start = y + 10 + i * UCD_LINE_HEIGHT;-			character_height = h - character_start;--			draw_fallback_character (cr, x, character_start, character_height);-		}-	}-	-	/** Fallback character in UCD info. */-	void draw_fallback_character (Context cr, double x, double y, double height)-	requires (character_info != null) {-		unichar c = ((!)character_info).unicode;--		if (height < 0) {-			return;-		}--		cr.save ();-		Text character = new Text ();-		character.set_use_cache (false);-		Theme.text_color (character, "Foreground 1");-		character.set_text ((!) c.to_string ());-		character.set_font_size (height);-		character.draw_at_top (cr, x + 10, y);-		cr.restore ();-	}--	void draw_info_line (string line, Context cr, double x, double y, int row) {-		Text ucd_entry = new Text (line);-		cr.save ();-		Theme.text_color (ucd_entry, "Foreground 1");-		ucd_entry.widget_x = 10 + x;-		ucd_entry.widget_y = 10 + y + row * UCD_LINE_HEIGHT;-		ucd_entry.draw (cr);-		cr.restore ();		-	}-	-	public void paste () {-		GlyphCollection gc;-		GlyphCollection? c;-		Glyph glyph;-		uint32 index;-		int i;-		int skip = 0;-		int s;-		string character_string;-		Gee.ArrayList<GlyphCollection> glyps;-		Font f;-		OverViewUndoItem undo_item;-		-		f = BirdFont.get_current_font ();-		gc = new GlyphCollection ('\0', "");-		glyps = new Gee.ArrayList<GlyphCollection> ();-		-		copied_glyphs.sort ((a, b) => {-			return (int) ((GlyphCollection) a).get_unicode_character () -				- (int) ((GlyphCollection) b).get_unicode_character ();-		});--		index = (uint32) first_visible + selected;-		for (i = 0; i < copied_glyphs.size; i++) {-			if (all_available) {-				if (f.length () == 0) {-					c = add_empty_character_to_font (copied_glyphs.get (i).get_unicode_character (),-						copied_glyphs.get (i).is_unassigned (), -						copied_glyphs.get (i).get_name ());-				} else if (index >= f.length ()) {-					// FIXME: duplicated unicodes?-					c = add_empty_character_to_font (copied_glyphs.get (i).get_unicode_character (),-						copied_glyphs.get (i).is_unassigned (), -						copied_glyphs.get (i).get_name ());-				} else {-					c = f.get_glyph_collection_index ((uint32) index);-				}-				-				if (c == null) {-					c = add_empty_character_to_font (copied_glyphs.get (i).get_unicode_character (),-						copied_glyphs.get (i).is_unassigned (),-						copied_glyphs.get (i).get_name ());-				}-				-				return_if_fail (c != null);-				gc = (!) c; -			} else {			-				if (i != 0) {-					s = (int) copied_glyphs.get (i).get_unicode_character ();-					s -= (int) copied_glyphs.get (i - 1).get_unicode_character ();-					s -= 1;-					skip += s;-				}--				character_string = glyph_range.get_char ((uint32) (index + skip));-				c = f.get_glyph_collection_by_name (character_string);-				-				if (c == null) {-					gc = add_empty_character_to_font (character_string.get_char (), -						copied_glyphs.get (i).is_unassigned (),-						copied_glyphs.get (i).get_name ());-				} else {-					gc = (!) c;-				}-			}-			-			glyps.add (gc);-			index++;-		}--		undo_item = new OverViewUndoItem ();-		undo_item.alternate_sets = f.alternates.copy ();-		foreach (GlyphCollection g in glyps) {-			undo_item.glyphs.add (g.copy ());-		}-		store_undo_items (undo_item);--		if (glyps.size != copied_glyphs.size) {-			warning ("glyps.size != copied_glyphs.size");-			return;-		}--		if (copied_glyphs.size < i) {-			warning ("Array index out of bounds.");-			return;-		}-		-		i = 0;-		foreach (GlyphCollection g in glyps) {-			glyph = copied_glyphs.get (i).get_current ().copy ();-			glyph.version_id = (glyph.version_id == -1 || g.length () == 0) ? 1 : g.get_last_id () + 1;-			glyph.unichar_code = g.get_unicode_character ();--			if (!g.is_unassigned ()) {-				glyph.name = (!) glyph.unichar_code.to_string ();-			} else {-				glyph.name = g.get_name ();-			}-			-			g.insert_glyph (glyph, true);-			i++;-		}-		-		f.touch ();-		-		update_item_list ();-		GlyphCanvas.redraw ();-	}--	public override bool needs_modifier () {-		return true;-	}-	-	public class OverViewUndoItem {-		public AlternateSets alternate_sets = new AlternateSets ();-		public Gee.ArrayList<GlyphCollection> glyphs = new Gee.ArrayList<GlyphCollection> ();-	}-}--}diff --git a/libbirdfont/OverViewItem.vala b/libbirdfont/OverViewItem.valadeleted file mode 100644index 1491518..0000000--- a/libbirdfont/OverViewItem.vala+++ /dev/null@@ -1,482 +0,0 @@-/*-	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 -	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;-using Math;--[CCode (cname = "draw_overview_glyph")]-public extern bool draw_overview_glyph (Context context, string font_file, double width, double height, unichar character);--namespace BirdFont {-	-public class OverViewItem : GLib.Object {-	public unichar character = '\0';-	public GlyphCollection? glyphs;-	public double x;-	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;-	-	public static double width = 100;-	public static double height = 130;-	public static double margin = 20;--	public static double glyph_scale = 1.0;-	-	public VersionList version_menu;-	Text label;-	-	private Surface? cache = null;-	-	public static Surface? label_background = null;-	public static Surface? selected_label_background = null;-	public static Surface? label_background_no_menu = null;-	public static Surface? selected_label_background_no_menu = null;-		-	public OverViewItem () {	-	}--	public void set_character (unichar character) {-		this.character = character;-	}-	-	public void set_glyphs (GlyphCollection? gc) {-		glyphs = gc;-		-		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 ();-			});-		}	--		info = new CharacterInfo (character, glyphs);-		-		if (glyphs == null) {-			label = new Text ();-		} else {-			if (character != '\0') {-				label = new Text ((!) character.to_string (), 17);-			} else {-				label = new Text ((!) info.get_name (), 17);-			}-			-			truncate_label ();-		}-		-		draw_background ();		-	}--	public void clear_cache () {-		cache = null;-		-		if (glyphs != null) {-			Glyph g = ((!) glyphs).get_current ();-			g.overview_thumbnail = null;-		}-	}--	public void draw_glyph_from_font () {-		if (glyphs == null) {-			return;-		}-		-		Glyph g;-		double gx, gy;-		double x1, x2, y1, y2;-		double scale_box;-		double w, h;-		double glyph_width, glyph_height;-		Surface s;-		Context c;-		Color color = Color.black ();-		-		g = ((!) glyphs).get_current ();-		-		if (likely (g.overview_thumbnail != null)) {-			cache = g.overview_thumbnail;-			return;-		}-		-		w = width;-		h = height;--		scale_box = (height / DEFAULT_HEIGHT) * 0.65;--		s = Screen.create_background_surface ((int) width, (int) height - 20);-		c = new Context (s);-		-		c.save ();-		g.boundaries (out x1, out y1, out x2, out y2);-	-		glyph_width = x2 - x1;-		glyph_height = y2 - y1;-		-		c.save ();-		c.scale (scale_box * Screen.get_scale (), scale_box * Screen.get_scale ());--		g.add_help_lines ();-		-		gx = ((w / scale_box) - glyph_width) / 2 - g.get_left_side_bearing ();-		gy = h / scale_box + g.get_baseline () - 20 / scale_box - 20;--		c.translate (gx - Glyph.xc () - g.get_lsb (), gy - Glyph.yc ());--		g.draw_paths (c, color);-		c.restore ();-		-		cache = s;-		g.overview_thumbnail = s;-		-		GlyphCanvas.redraw ();-	}--	public void draw_background () {-		double scale_box;-		double w, h;-		Surface s;-		Context c;-		-		w = width;-		h = height;-		-		scale_box = width / DEFAULT_WIDTH;-		s = Screen.create_background_surface ((int) width, (int) height - 20);-		c = new Context (s);-		-		if (glyphs != null) { // FIXME: lock-			draw_glyph_from_font ();-		} else {-			c.scale (Screen.get_scale (), Screen.get_scale ());-			-			c.save ();-			-			bool glyph_found;-			string? font_file;-			-			Theme.color (c, "Overview Glyph");-			-			font_file = FontCache.fallback_font.get_default_font_file ();	-			glyph_found = draw_overview_glyph (c, (!) font_file, width, height, character);-			-			if (!glyph_found) {-				font_file = find_font (FallbackFont.font_config, (!) character.to_string ());-				-				if (font_file != null) {-					string path = (!) font_file;-					-					if (!path.has_suffix("LastResort.ttf")) {-						draw_overview_glyph (c, path, width, height, character);-					}-				}-			}-			-			c.restore ();-			-			cache = s;-			GlyphCanvas.redraw ();-		}-	}--	public static void reset_label () {-		label_background = null;-		selected_label_background = null;-	}-	-	void truncate_label () {-		double w = has_icons () ? width - 43 : width;-		label.truncate (w);-	}--	public string get_name () {-		StringBuilder s;-		-		if (glyphs != null) {-			return ((!) glyphs).get_name ();-		}-		-		s = new StringBuilder ();-		s.append_unichar (character);-		-		return s.str;-	}-	-	public void set_selected (bool s) {-		selected = s;-	}-	-	public static double full_width () {-		return width + margin;-	}--	public static double full_height () {-		return height + margin;-	}-	-	public bool click_menu (uint button, double px, double py) {-		bool a;-		GlyphCollection g;--		if (has_icons () && glyphs != null) {-			g = (!) glyphs;-			version_menu.set_position (x + width - 21, y + height - 18);-			a = version_menu.menu_item_action (px, py); // select one item on the menu-			-			if (a) {-				MainWindow.get_overview ().reset_cache ();-				MainWindow.get_overview ().update_item_list ();--				GlyphCanvas.redraw ();-				return true;-			}-			-			version_menu.menu_icon_action (px, py); // click in the open menu-		}-		-		return false;-	}-	-	public bool click_info (uint button, double px, double py) {-		info.set_position (x + width - 17, y + height - 22.5);-		-		if (has_icons () && info.is_over_icon (px, py)) {-			MainWindow.get_overview ().set_character_info (info);-			return true;-		}-		-		return false;-	}-	-	public bool click (uint button, double px, double py) {-		bool s = (x <= px <= x + width) && (y <= py <= y + height);		-		return s;-	}--	public bool double_click (uint button, double px, double py) {-		selected = (x <= px <= x + width) && (y <= py <= y + height);-		return selected;-	}--	public bool is_on_screen (WidgetAllocation allocation) {-		return y + height > 0 && y < allocation.height;-	}--	public void draw (WidgetAllocation allocation, Context cr) {-		if (!is_on_screen (allocation)) {-			return;-		}--		cr.save ();-		Theme.color (cr, "Background 1");-		cr.rectangle (x, y, width, height);-		cr.fill ();-		cr.restore ();--		cr.save ();-		Theme.color (cr, "Overview Item Border");-		cr.rectangle (x, y, width, height);-		cr.set_line_width (1);-		cr.stroke ();-		cr.restore ();-		-		draw_thumbnail (cr, x, y + height);-		-		draw_caption (cr);-		draw_menu (cr);-	}--	private void draw_thumbnail (Context cr, double x, double y) {		-		if (cache != null) {-			cr.save ();-			cr.set_antialias (Cairo.Antialias.NONE);-			cr.scale (1 / Screen.get_scale (), 1 / Screen.get_scale ());	-			cr.set_source_surface ((!) cache, (int) (x * Screen.get_scale ()), (int) ((y - height)) * Screen.get_scale ());-			cr.paint ();-			cr.restore ();-		}-	}--	public bool has_icons () {-		return width > 50;-	}--	public void draw_caption (Context cr) {-		draw_label_background (cr);-		-		cr.save ();-		-		if (glyphs != null) {-			if (selected) {-				Theme.text_color (label, "Overview Selected Foreground");-			} else {-				Theme.text_color (label, "Overview Foreground");-			}-		-			label.draw_at_baseline (cr, x + 0.08 * width, y + height - 6);-		}-		-		cr.restore ();-	}-	-	public void create_label_background_cache (Context cr) {-		Context cc;-		Cairo.Pattern p;-		Surface cache;-			-		// unselected item-		cache = Screen.create_background_surface ((int) width + 1, 20);-		cc = new Context (cache);-		cc.scale(Screen.get_scale(), Screen.get_scale());--		cc.rectangle (0, 0, width, 20 - 1);-		p = new Cairo.Pattern.linear (0.0, 0, 0.0, 20);-		Theme.gradient (p, "Overview Item 1", "Overview Item 2");-		cc.set_source (p);-			-		cc.fill ();-		-		if (has_icons ()) {-			draw_menu_icon (cc, false);-			draw_character_info_icon (cc);-		}--		label_background = (!) cache;	--		// selected item-		cache = Screen.create_background_surface ((int) width + 1, 20);-		cc = new Context (cache);-		cc.scale(Screen.get_scale(), Screen.get_scale());--		cc.rectangle (0, 0, width, 20 - 1);--		Theme.color (cc, "Selected Overview Item");-			-		cc.fill ();-		-		if (has_icons ()) {-			draw_menu_icon (cc, true);-			draw_character_info_icon (cc);-		}--		selected_label_background = (!) cache;	-	-		// deselected item without menu icon-		cache = Screen.create_background_surface ((int) width, 20);-		cc = new Context (cache);-		cc.scale(Screen.get_scale(), Screen.get_scale());-		cc.rectangle (0, 0, width - 1, 20 - 1);-		p = new Cairo.Pattern.linear (0.0, 0, 0.0, 20);-		Theme.gradient (p, "Overview Item 1", "Overview Item 2");-		cc.set_source (p);-		cc.fill ();--		if (has_icons ()) {-			draw_character_info_icon (cc);-		}-		-		label_background_no_menu = (!) cache;--		// selected item-		cache = Screen.create_background_surface ((int) width + 1, 20);-		cc = new Context (cache);-		cc.scale(Screen.get_scale(), Screen.get_scale());-		cc.rectangle (0, 0, width, 20 - 1);-		Theme.color (cc, "Selected Overview Item");-		cc.fill ();--		if (has_icons ()) {-			draw_character_info_icon (cc);-		}-				-		selected_label_background_no_menu = (!) cache;		-	}-	-	bool has_menu () {-		return glyphs != null;-	}-	-	public void draw_label_background (Context cr) {-		Surface cache;-		bool icon;-		-		if (unlikely (label_background == null)) {-			create_label_background_cache (cr);-		}-		-		if (label_background != null -			&& selected_label_background != null-			&& label_background_no_menu != null-			&& selected_label_background_no_menu != null) {-			-			icon = has_menu ();-			if (selected && icon) {-				cache = (!) selected_label_background;-			} else if (!selected && icon) {-				cache = (!) label_background;-			} else if (selected && !icon) {-				cache = (!) selected_label_background_no_menu;-			} else {-				cache = (!) label_background_no_menu;-			}-			-			Screen.paint_background_surface (cr, cache, (int) x, (int) (y + height - 19));-		}-	}-	-	private void draw_character_info_icon (Context cr) {-		info.draw_icon (cr, selected, width - 17, -1.5);-	}-	-	public void hide_menu () {-		if (!is_null (version_menu)) {-			version_menu.menu_visible = false;-		}-	}-	-	private void draw_menu_icon (Context cc, bool selected) {-		Text icon;--		icon = new Text ("dropdown_menu", 17);-		icon.load_font ("icons.birdfont");--		if (selected) {-			Theme.text_color (icon, "Overview Selected Foreground");-		} else {-			Theme.text_color (icon, "Overview Foreground");-		}-		-		icon.draw_at_top (cc, width - 32, 0);-	}-	-	private void draw_menu (Context cr) {-		if (likely (glyphs == null || !version_menu.menu_visible)) {-			return;-		}-		-		version_menu.draw_menu (cr);-	}-}--}diff --git a/libbirdfont/Overview.vala b/libbirdfont/Overview.valanew file mode 100644index 0000000..f3ed0f7--- /dev/null+++ b/libbirdfont/Overview.vala@@ -0,0 +1,1770 @@+/*+	Copyright (C) 2012 - 2016 Johan Mattsson++	This library is free software; you can redistribute it and/or modify +	it under the terms of the GNU Lesser General Public License as +	published by the Free Software Foundation; either version 3 of the +	License, or (at your option) any later version.++	This library is distributed in the hope that it will be useful, but +	WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +	Lesser General Public License for more details.+*/++using Cairo;++namespace BirdFont {++/** A display with all glyphs present in this font. */+public class Overview : FontDisplay {+	public WidgetAllocation allocation = new WidgetAllocation ();+	+	public OverviewItem selected_item = new OverviewItem ();++	public Gee.ArrayList<GlyphCollection> copied_glyphs = new Gee.ArrayList<GlyphCollection> ();+	public Gee.ArrayList<GlyphCollection> selected_items = new Gee.ArrayList<GlyphCollection> ();	+	+	int selected = 0;+	int first_visible = 0;+	int rows = 0;+	int items_per_row = 0;+	+	double view_offset_y = 0;+	double view_offset_x = 0;+	+	public signal void open_new_glyph_signal (unichar c);+	public signal void open_glyph_signal (GlyphCollection c);+	+	public GlyphRange glyph_range {+		get {+			return _glyph_range;+		}+		+		set {+			_glyph_range = value;+		}+	}+	+	GlyphRange _glyph_range;+	+	string search_query = "";+	+	public Gee.ArrayList<OverviewItem> visible_items = new Gee.ArrayList<OverviewItem> ();+	+	/** List of undo commands. */+	public Gee.ArrayList<OverviewUndoItem> undo_items = new Gee.ArrayList<OverviewUndoItem> ();+	public Gee.ArrayList<OverviewUndoItem> redo_items = new Gee.ArrayList<OverviewUndoItem> ();+	+	/** Show all characters that has been drawn. */+	public bool all_available {+		set {+			_all_available = value;+			update_item_list ();+		}+		+		get {+			return _all_available;+		}+	}+	+	bool _all_available = false;+	+	/** Show unicode database info. */+	CharacterInfo? character_info = null;+	+	double scroll_size = 1;+	const double UCD_LINE_HEIGHT = 17 * 1.3;++	private bool update_scheduled = true;++	public Overview (GlyphRange? range = null,+		bool open_selected = true, bool default_character_set = true) {+			+		GlyphRange gr;+		+		if (range == null) {+			gr = new GlyphRange ();+			set_current_glyph_range (gr);+		}++		if (open_selected) {+			this.open_glyph_signal.connect ((glyph_collection) => {+				TabBar tabs = MainWindow.get_tab_bar ();+				string n = glyph_collection.get_current ().name;+				bool selected = tabs.select_char (n);+				GlyphTab glyph_tab;+				+				if (!selected) {+					glyph_tab = new GlyphTab (glyph_collection);+					tabs.add_tab (glyph_tab, true, glyph_collection);+					set_glyph_zoom (glyph_collection);+					PenTool.update_orientation ();+				}+			});++			this.open_new_glyph_signal.connect ((character) => {+				// ignore control characters+				if (character <= 0x1F || character == 0xFFFF) { +					return;+				}+				+				create_new_glyph (character);+			});+		}++		if (default_character_set) {+			IdleSource idle = new IdleSource ();++			idle.set_callback (() => {+				use_default_character_set ();+				selected_canvas ();+				return false;+			});+			+			idle.attach (null);+		}+						+		update_item_list ();+		update_scrollbar ();+		reset_zoom ();+		+		string? zoom = Preferences.get ("overview_zoom");+		+		if (zoom != null) {+			string z = (!) zoom;+			+			if (z != "") {+				set_zoom (double.parse (z));+			}			+		}+	}++	public void reset_cache () {+		foreach (OverviewItem i in visible_items) {+			i.clear_cache ();+		}+	}++	public Glyph? get_selected_glyph () {+		if (selected_items.size == 0) {+			return null;+		}+		+		return selected_items.get (0).get_current ();+	}+	+	public void select_all_glyphs () {+		Font f;+		GlyphCollection? glyphs;+		+		f = BirdFont.get_current_font ();+		+		for (int index = 0; index < f.length (); index++) {+			glyphs = f.get_glyph_collection_index ((uint32) index);+			return_if_fail (glyphs != null);+			+			selected_items.add ((!) glyphs);+		}+		+		foreach (OverviewItem item in visible_items) {+			item.selected = item.glyphs != null;+		}+		+		GlyphCanvas.redraw ();+	}+	+	public void use_default_character_set () {+		GlyphRange gr = new GlyphRange ();+		all_available = false;+		DefaultCharacterSet.use_default_range (gr);+		set_current_glyph_range (gr);+		OverviewTools.update_overview_characterset ();+		FontDisplay.dirty_scrollbar = true;+	}+	+	public GlyphCollection create_new_glyph (unichar character) {+		StringBuilder name = new StringBuilder ();+		TabBar tabs = MainWindow.get_tab_bar ();+		bool selected;+		Glyph glyph;+		GlyphCollection glyph_collection;+		GlyphCanvas canvas;+		GlyphTab glyph_tab; +		+		glyph_collection = MainWindow.get_current_glyph_collection ();+		name.append_unichar (character);+		selected = tabs.select_char (name.str);+				+		if (!selected) {+			glyph_collection = add_character_to_font (character);+			glyph_tab = new GlyphTab (glyph_collection);+			glyph = glyph_collection.get_current ();+			glyph.layers.add_layer (new Layer ());+			tabs.add_tab (glyph_tab, true, glyph_collection);+			+			selected_items.add (glyph_collection);+			+			canvas = MainWindow.get_glyph_canvas ();+			canvas.set_current_glyph_collection (glyph_collection);+			+			set_glyph_zoom (glyph_collection);+		} else {+			warning ("Glyph is already open");+		}+		+		OverviewTools.update_overview_characterset ();+		return glyph_collection;+	}+		+	public GlyphCollection add_empty_character_to_font (unichar character, bool unassigned, string name) {+		return add_character_to_font (character, true, unassigned);+	}+	+	public GlyphCollection add_character_to_font (unichar character, bool empty = false,+			bool unassigned = false, string glyph_name = "") {+		StringBuilder name = new StringBuilder ();+		Font font = BirdFont.get_current_font ();+		GlyphCollection? fg;+		Glyph glyph;+		GlyphCollection glyph_collection;++		if (glyph_name == "") {+			name.append_unichar (character);+		} else {+			name.append (glyph_name);+		}+		+		if (all_available) {+			fg = font.get_glyph_collection_by_name (name.str);+		} else {+			fg = font.get_glyph_collection (name.str);+		}++		if (fg != null) {+			glyph_collection = (!) fg;+		} else {+			glyph_collection = new GlyphCollection (character, name.str);+			+			if (!empty) {+				glyph = new Glyph (name.str, !unassigned ? character : '\0');+				glyph_collection.add_master (new GlyphMaster ());+				glyph_collection.insert_glyph (glyph, true);+			}+			+			font.add_glyph_collection (glyph_collection);+		}+		+		glyph_collection.set_unassigned (unassigned);+		+		return glyph_collection;+	}+	+	public static void search () {+		Overview ow = MainWindow.get_overview ();+		TextListener listener = new TextListener (t_("Search"), ow.search_query, t_("Filter"));+		+		listener.signal_text_input.connect ((text) => {+			Overview o = MainWindow.get_overview ();+			o.search_query = text;+		});+		+		listener.signal_submit.connect (() => {+			Overview o = MainWindow.get_overview ();+			string q = o.search_query;+			+			if (q == "*") {+ 				q = "star";+ 			}+						+			if (q == "?") {+				q = "question";+			}++			if (q.char_count () > 1) {+				q = q.down ();+			}+			+			GlyphRange r = CharDatabase.search (q);+			o.set_current_glyph_range (r);+			MainWindow.get_tab_bar ().select_tab_name ("Overview");+	+			TextListener tl = new TextListener (t_("Search"), o.search_query, t_("Filter"));+			TabContent.show_text_input (tl);+		});+		+		TabContent.show_text_input (listener);+	}+	+	public Glyph? get_current_glyph () {+		OverviewItem oi = selected_item;+		if (oi.glyphs != null) {+			return ((!) oi.glyphs).get_current ();+		}+		return null;+	}+	+	public void set_glyph_zoom (GlyphCollection glyphs) {+		GlyphCanvas canvas;+		canvas = MainWindow.get_glyph_canvas ();+		canvas.set_current_glyph_collection (glyphs);+		Toolbox tools = MainWindow.get_toolbox ();+		ZoomTool z = (ZoomTool) tools.get_tool ("zoom_tool");+		z.store_current_view ();+		glyphs.get_current ().default_zoom ();+		z.store_current_view ();+		OverviewItem.reset_label ();+	}+	+	public double get_height () {+		double l;+		Font f;+		+		if (rows == 0) {+			return 0;+		}+				+		if (all_available) {+			f = BirdFont.get_current_font ();+			l = f.length ();+		} else {+			l = glyph_range.length ();+		}+				+		return 2.0 * OverviewItem.height * (l / rows);+	}++	public bool selected_char_is_visible () {+		return first_visible <= selected <= first_visible + items_per_row * rows;+	}++	public override bool has_scrollbar () {+		return true;+	}++	public bool all_characters_in_view () {+		double length;+		Font f;+		+		if (all_available) {+			f = BirdFont.get_current_font ();+			length = f.length ();+		} else {+			length = glyph_range.length ();+		}+		+		return length < items_per_row * rows;+	}+	+	public void move_up () {+		first_visible -= items_per_row;+		selected += items_per_row;+		+		if (first_visible < 0) {+			selected -= items_per_row;+			first_visible = 0;+			view_offset_y = 0;+		}+	}++	public void move_down () {+		if (!at_bottom ()) {+			first_visible += items_per_row;+			selected -= items_per_row;+		}+	}+	+	public override void scroll_wheel (double x, double y, double dx, double dy) {+		double pixel_delta = 3 * dy;+		+		if (dy > 0) {+			view_offset_y += pixel_delta;+			+			while (view_offset_y > 0) {+				view_offset_y -= OverviewItem.height;+				move_up ();+			}						+		} else {+			if (at_bottom ()) {+				if (view_offset_y > -2 * OverviewItem.height && !all_characters_in_view ()) {+					view_offset_y += pixel_delta;+				}+			} else {+				view_offset_y += pixel_delta;+				while (view_offset_y < -OverviewItem.height) {+					view_offset_y += OverviewItem.height;+					move_down ();+				}+			}+		}+				+		if (view_offset_y < -2 * OverviewItem.height) {+			view_offset_y = -2 * OverviewItem.height;+		}+		+		update_item_list ();+		update_scrollbar ();+		hide_menu ();	+		GlyphCanvas.redraw ();+	}+	+	public override void selected_canvas () {+		OverviewTools.update_overview_characterset ();+		KeyBindings.set_require_modifier (true);+		update_scrollbar ();+		update_zoom_bar ();+		OverviewItem.glyph_scale = 1;+		update_item_list ();+		selected_item = get_selected_item ();+		GlyphCanvas.redraw ();+	}+	+	public void update_zoom_bar () {+		double z = OverviewItem.width / OverviewItem.DEFAULT_WIDTH - 0.5;+		Toolbox.overview_tools.zoom_bar.set_zoom (z);+		Toolbox.redraw_tool_box ();+		update_item_list ();+	}+	+	public void set_zoom (double zoom) {+		double z = zoom + 0.5;+		OverviewItem.glyph_scale = 1;+		OverviewItem.width = OverviewItem.DEFAULT_WIDTH * z;+		OverviewItem.height = OverviewItem.DEFAULT_HEIGHT * z;+		OverviewItem.margin = OverviewItem.DEFAULT_MARGIN * z;+		update_item_list ();+		OverviewItem.reset_label ();+		Preferences.set ("overview_zoom", @"$zoom");++		Font font = BirdFont.get_current_font ();+		for (int index = 0; index < font.length (); index++) {+			GlyphCollection? glyphs = font.get_glyph_collection_index ((uint32) index);+			return_if_fail (glyphs != null);+			GlyphCollection g = (!) glyphs;+			g.get_current ().overview_thumbnail = null;+		}+		+		GlyphCanvas.redraw ();+	}+	+	public override void zoom_min () {+		OverviewItem.width = OverviewItem.DEFAULT_WIDTH * 0.5;+		OverviewItem.height = OverviewItem.DEFAULT_HEIGHT * 0.5;+		OverviewItem.margin = OverviewItem.DEFAULT_MARGIN * 0.5;+		update_item_list ();+		OverviewItem.reset_label ();+		GlyphCanvas.redraw ();+		update_zoom_bar ();+	}+	+	public override void reset_zoom () {+		OverviewItem.width = OverviewItem.DEFAULT_WIDTH;+		OverviewItem.height = OverviewItem.DEFAULT_HEIGHT;+		OverviewItem.margin = OverviewItem.DEFAULT_MARGIN;+		update_item_list ();+		OverviewItem.reset_label ();+		GlyphCanvas.redraw ();+		update_zoom_bar ();+	}++	public override void zoom_max () {+		OverviewItem.width = allocation.width;+		OverviewItem.height = allocation.height;+		update_item_list ();+		OverviewItem.reset_label ();+		GlyphCanvas.redraw ();+	}+	+	public override void zoom_in () {+		OverviewItem.width *= 1.1;+		OverviewItem.height *= 1.1;+		OverviewItem.margin *= 1.1;+		update_item_list ();+		OverviewItem.reset_label ();+		GlyphCanvas.redraw ();+		update_zoom_bar ();+	}+	+	public override void zoom_out () {+		OverviewItem.width *= 0.9;+		OverviewItem.height *= 0.9;+		OverviewItem.margin *= 0.9;+		update_item_list ();+		OverviewItem.reset_label ();+		GlyphCanvas.redraw ();+		update_zoom_bar ();+	}++	public override void store_current_view () {+	}+	+	public override void restore_last_view () {+	}++	public override void next_view () {+	}++	public override string get_label () {+		return t_("Overview");+	}+	+	public override string get_name () {+		return "Overview";+	}+	+	public void display_all_available_glyphs () {+		all_available = true;++		view_offset_y = 0;+		first_visible = 0;+		selected = 0;+		+		update_item_list ();+		selected_item = get_selected_item ();+		GlyphCanvas.redraw ();+	}+	+	OverviewItem get_selected_item () {+		if (visible_items.size == 0) {+			return new OverviewItem ();+		}+		+		if (!(0 <= selected < visible_items.size)) { +			return selected_item;+		}++		OverviewItem item = visible_items.get (selected);+		item.selected = true;+		return item;+	}+	+	int get_items_per_row () {+		int i = 1;+		double tab_with = allocation.width - 30; // 30 px for the scroll bar+		OverviewItem.margin = OverviewItem.width * 0.1;+		double l = OverviewItem.margin + OverviewItem.full_width ();+		+		while (l <= tab_with) {+			l += OverviewItem.full_width ();+			i++;+		}+		+		return i - 1;+	}+	+	public void update_item_list () {+		update_scheduled = true;+	}+	+	public void process_item_list_update () {+		string character_string;+		Font f = BirdFont.get_current_font ();+		GlyphCollection? glyphs = null;+		uint32 index;+		OverviewItem item;+		double x, y;+		unichar character;+		Glyph glyph;+		double tab_with;+		int item_list_length;+		int visible_size;+		+		tab_with = allocation.width - 30; // scrollbar+		+		items_per_row = get_items_per_row ();+		rows = (int) (allocation.height /  OverviewItem.full_height ()) + 2;+		+		item_list_length = items_per_row * rows;+		visible_items.clear ();+		+		index = (uint32) first_visible;+		x = OverviewItem.margin;+		y = OverviewItem.margin;+		+		if (all_available) {+			uint font_length = f.length ();+			+			for (int i = 0; i < item_list_length && index < font_length; i++) {+				glyphs = f.get_glyph_collection_index ((uint32) index);+				return_if_fail (glyphs != null);+				+				glyph = ((!) glyphs).get_current ();+				character_string = glyph.name;+				character = glyph.unichar_code;+				+				item = new OverviewItem ();+				item.set_character (character);+				item.set_glyphs (glyphs);+				item.x = x;+				item.y = y;+				visible_items.add (item);+				index++;+			}+		} else {+			uint32 glyph_range_size = glyph_range.get_length ();+			+			uint max_length = glyph_range.length () - first_visible;+			+			if (item_list_length > max_length) {+				item_list_length = (int) max_length;+			}+			+			for (int i = 0; i < item_list_length && index < glyph_range_size; i++) {			+				item = new OverviewItem ();+				visible_items.add (item);+			}+			+			index = (uint32) first_visible;+			visible_size = visible_items.size;+			for (int i = 0; i < visible_size; i++) {+				item = visible_items.get (i);+				character = glyph_range.get_character ((uint32) index);+				item.set_character (character);+				index++;+			}++			visible_size = visible_items.size;+			for (int i = 0; i < visible_size; i++) {+				item = visible_items.get (i);+				glyphs = f.get_glyph_collection_by_name ((!) item.character.to_string ());+				item.set_glyphs (glyphs);+			}+		}+		+		x = OverviewItem.margin;+		y = OverviewItem.margin;+		+		visible_size = visible_items.size;+		int selected_index;+		bool selected_item;+		double full_width = OverviewItem.full_width ();+		+		for (int i = 0; i < visible_size; i++) {+			item = visible_items.get (i);++			selected_item = false;+	+			if (all_available) {+				glyphs = f.get_glyph_collection_index ((uint32) i);+			} else {			+				glyphs = f.get_glyph_collection_by_name ((!) item.character.to_string ());+			}+			+			if (glyphs != null) {+				selected_index = selected_items.index_of ((!) glyphs);+				selected_item = (selected_index != -1);+			}+						+			selected_item |= (i == selected);+			item.selected = selected_item;+			+			item.x = x + view_offset_x;+			item.y = y + view_offset_y;+			+			x += full_width;+			+			if (x + full_width >= tab_with) {+				x = OverviewItem.margin;+				y += OverviewItem.full_height ();+			}+		}+		+		update_scheduled = false;+	}+	+	public override void draw (WidgetAllocation allocation, Context cr) {+		if (update_scheduled+			|| this.allocation.width != allocation.width+			|| this.allocation.height != allocation.height+			|| this.allocation.width == 0) {+			this.allocation = allocation;+			process_item_list_update ();+		}+		+		this.allocation = allocation;+		+		// clear canvas+		cr.save ();+		Theme.color (cr, "Background 1");+		cr.rectangle (0, 0, allocation.width, allocation.height);+		cr.fill ();+		cr.restore ();+		+		foreach (OverviewItem i in visible_items) {+			i.draw (allocation, cr);+		}+		+		if (unlikely (visible_items.size == 0)) {+			draw_empty_canvas (allocation, cr);+		}+		+		if (unlikely (character_info != null)) {+			draw_character_info (cr);+		}+	}+		+	void draw_empty_canvas (WidgetAllocation allocation, Context cr) {+		Text t;+		+		cr.save ();+		t = new Text (t_("No glyphs in this view."), 24);+		Theme.text_color (t, "Text Foreground");+		t.widget_x = 40;+		t.widget_y = 30;+		t.draw (cr);+		cr.restore ();+	}+	+	public void scroll_rows (int row_adjustment) {+		for (int i = 0; i < row_adjustment; i++) {+			scroll (-OverviewItem.height);+		}+		+		for (int i = 0; i > row_adjustment; i--) {+			scroll (OverviewItem.height);+		}+	}+	+	public void scroll_adjustment (double pixel_adjustment) {+		double l;+		Font f;+				+		if (all_available) {+			f = BirdFont.get_current_font ();+			l = f.length ();+		} else {+			l = glyph_range.length ();+		}+		+		if (first_visible <= 0) {+			return;+		}++		if (first_visible + rows * items_per_row >= l) {+			return;+		}+		+		scroll ((int64) pixel_adjustment);+	}+	+	void scroll_to_position (int64 r) {+		if (r < 0) {+			scroll_top ();+			return;+		}+		+		selected -= (int) (r - first_visible);+		first_visible = (int) r;+		update_item_list ();+	}+	+	public override void scroll_to (double position) requires (items_per_row > 0) {+		double r;+		int nrows;+		Font f;+		+		if (all_available) {+			f = BirdFont.get_current_font ();+			nrows = (int) (f.length () / items_per_row);+		} else {+			nrows = (int) (glyph_range.length () / items_per_row);+		}+		+		view_offset_y = 0;+		r = (int64) (position * (nrows - rows + 3)); // 3 invisible rows+		r *= items_per_row;+		+		scroll_to_position ((int64) r);+		update_item_list ();+		GlyphCanvas.redraw ();+	}+		+	private void scroll (double pixel_adjustment) {+		if (first_visible < 0 && pixel_adjustment < 0) {+			scroll_top ();+			return;+		}+				+		view_offset_y += pixel_adjustment;+		+		if (view_offset_y >= 0) {+			while (view_offset_y > OverviewItem.height) {			+				view_offset_y -= OverviewItem.height;+				first_visible -= items_per_row;+			}++			first_visible -= items_per_row;+			view_offset_y -= OverviewItem.height;+		} else if (view_offset_y < -OverviewItem.height) {+			view_offset_y = 0;+			first_visible += items_per_row;+		}+		+		update_item_list ();+	}+	+	public void scroll_top () {+		first_visible = 0;+		view_offset_y = 0;+		+		update_item_list ();+		+		if (visible_items.size != 0) {+			selected_item = get_selected_item ();+		}+	}++	/** Returns true if the selected glyph is at the last row. */+	private bool last_row () {+		return visible_items.size - selected <= items_per_row;+	}++	public void key_down () {+		Font f = BirdFont.get_current_font ();+		int64 len = (all_available) ? f.length () : glyph_range.length ();+		+		if (at_bottom () && last_row ()) {+			return;+		}+		+		selected += items_per_row;+		+		if (selected >= items_per_row * rows) {+			first_visible += items_per_row;+			selected -= items_per_row;+		}+		+		if (first_visible + selected >= len) {+			selected = (int) (len - first_visible - 1);+			+			if (selected < items_per_row * (rows - 1)) {+				first_visible -= items_per_row;+				selected += items_per_row;+			}+		}+		+		if (selected >= visible_items.size) { +			selected = (int) (visible_items.size - 1); +		}++		selected_item = get_selected_item ();+		update_item_list ();+	}++	public void key_right () {+		Font f = BirdFont.get_current_font ();+		int64 len = (all_available) ? f.length () : glyph_range.length ();++		if (at_bottom () && first_visible + selected + 1 >= len) {+			selected = (int) (visible_items.size - 1);+			selected_item = get_selected_item ();+			return;+		}+		+		selected += 1;+		+		if (selected >= items_per_row * rows) {+			first_visible += items_per_row;+			selected -= items_per_row;+			selected -= 1;+		}		++		if (first_visible + selected > len) {+			first_visible -= items_per_row;+			selected = (int) (len - first_visible - 1);+			selected_item = get_selected_item ();+		}+		update_item_list ();+	}+	+	public void key_up () {+		selected -= items_per_row;+		+		if (selected < 0) {+			first_visible -= items_per_row;+			selected += items_per_row;			+		}+		+		if (first_visible < 0) {+			first_visible = 0;		+		}+		update_item_list ();+	}+	+	public void key_left () {+		selected -= 1;++		if (selected < 0) {+			first_visible -= items_per_row;+			selected += items_per_row;+			selected += 1;			+		}++		if (first_visible < 0) {+			scroll_top ();+		}+		update_item_list ();+	}+	+	public string get_selected_char () {+		Font f;+		Glyph? g;+		+		if (all_available) {+			f = BirdFont.get_current_font ();+			g = f.get_glyph_index (selected);+			return_val_if_fail (g != null, "".dup ());+			return ((!) g).get_name ();+		}+		+		return glyph_range.get_char (selected);+	}+	+	public override void key_press (uint keyval) {+		hide_menu ();+		update_item_list ();+		GlyphCanvas.redraw ();++		if (KeyBindings.has_ctrl () || KeyBindings.has_logo ()) {+			return;+		}++		switch (keyval) {+			case Key.ENTER:+				open_current_glyph ();+				return;+			+			case Key.UP:+				get_selected_item ().selected = false;+			+				key_up ();+				selected_item = get_selected_item ();+				+				selected_items.clear ();+				if (selected_item.glyphs != null) {+					selected_items.add ((!) selected_item.glyphs);+				}+				+				update_scrollbar ();+				return;+				+			case Key.RIGHT:+				get_selected_item ().selected = false;+			+				key_right ();+				selected_item = get_selected_item ();+				+				selected_items.clear ();+				if (selected_item.glyphs != null) {+					selected_items.add ((!) selected_item.glyphs);+				}+				+				update_scrollbar ();+				return;+				+			case Key.LEFT:+				get_selected_item ().selected = false;+				+				key_left ();+				selected_item = get_selected_item ();+				+				selected_items.clear ();+				if (selected_item.glyphs != null) {+					selected_items.add ((!) selected_item.glyphs);+				}+				+				update_scrollbar();+				return;+				+			case Key.DOWN:+				get_selected_item ().selected = false;+				+				key_down ();+				selected_item = get_selected_item ();+				+				selected_items.clear ();+				if (selected_item.glyphs != null) {+					selected_items.add ((!) selected_item.glyphs);+				}+				+				update_scrollbar ();+				return;+				+			case Key.PG_UP:+				get_selected_item ().selected = false;+				+				for (int i = 0; i < rows; i++) {+					key_up ();+				}+				selected_item = get_selected_item ();+				+				selected_items.clear ();+				if (selected_item.glyphs != null) {+					selected_items.add ((!) selected_item.glyphs);+				}+				+				update_scrollbar ();+				return;+				+			case Key.PG_DOWN:+				get_selected_item ().selected = false;+				+				for (int i = 0; i < rows; i++) {+					key_down ();+				}+				selected_item = get_selected_item ();++				selected_items.clear ();+				if (selected_item.glyphs != null) {+					selected_items.add ((!) selected_item.glyphs);+				}+				+				update_scrollbar ();+				return;+				+			case Key.DEL:+				delete_selected_glyph ();+				selected_item = get_selected_item ();+				return;+				+			case Key.BACK_SPACE:+				delete_selected_glyph ();+				selected_item = get_selected_item ();+				return;+		}++		if (!KeyBindings.has_ctrl () && !KeyBindings.has_logo ()) {+			scroll_to_char (keyval);+		}+		+		selected_item = get_selected_item ();++		selected_items.clear ();+		if (selected_item.glyphs != null) {+			selected_items.add ((!) selected_item.glyphs);+		}+		+		update_item_list ();+		GlyphCanvas.redraw ();+	}+	+	public void delete_selected_glyph () {+		Font font = BirdFont.get_current_font ();+		OverviewUndoItem undo_item = new OverviewUndoItem ();+		+		undo_item.alternate_sets = font.alternates.copy ();+		+		foreach (GlyphCollection g in selected_items) {+			undo_item.glyphs.add (g.copy ());+		}+		store_undo_items (undo_item);++		foreach (GlyphCollection glyph_collection in selected_items) {+			font.delete_glyph (glyph_collection);+			string name = glyph_collection.get_name ();+			MainWindow.get_tab_bar ().close_background_tab_by_name (name);+		}++		update_item_list ();+		GlyphCanvas.redraw ();+	}+	+	public override void undo () {+		Font font = BirdFont.get_current_font ();+		OverviewUndoItem previous_collection;+		+		if (undo_items.size == 0) {+			return;+		}+		+		previous_collection = undo_items.get (undo_items.size - 1);+		redo_items.add (get_current_state (previous_collection));+		+		// remove the old glyph and add the new one+		foreach (GlyphCollection g in previous_collection.glyphs) {+			font.delete_glyph (g);+			+			if (g.length () > 0) {+				font.add_glyph_collection (g);+			}++			TabBar tabs = MainWindow.get_tab_bar ();+			Tab? tab = tabs.get_tab (g.get_name ());+			+			if (tab != null) {+				Tab t = (!) tab;+				set_glyph_zoom (g);+				t.set_glyph_collection (g);+				t.set_display (new GlyphTab (g));+			}+		}+		+		Font f = BirdFont.get_current_font ();+		f.alternates = previous_collection.alternate_sets.copy ();++		undo_items.remove_at (undo_items.size - 1);+		update_item_list ();+		GlyphCanvas.redraw ();+	}+	+	public override void redo () {+		Font font = BirdFont.get_current_font ();+		OverviewUndoItem previous_collection;++		if (redo_items.size == 0) {+			return;+		}+		+		previous_collection = redo_items.get (redo_items.size - 1);+		undo_items.add (get_current_state (previous_collection));++		// remove the old glyph and add the new one+		foreach (GlyphCollection g in previous_collection.glyphs) {+			font.delete_glyph (g);+			font.add_glyph_collection (g);++			TabBar tabs = MainWindow.get_tab_bar ();+			Tab? tab = tabs.get_tab (g.get_name ());+			+			if (tab != null) {+				Tab t = (!) tab;+				set_glyph_zoom (g);+				t.set_glyph_collection (g);+				t.set_display (new GlyphTab (g));+			}+		}+		font.alternates = previous_collection.alternate_sets.copy ();++		redo_items.remove_at (redo_items.size - 1);+		GlyphCanvas.redraw ();+	}	+	+	public OverviewUndoItem get_current_state (OverviewUndoItem previous_collection) {+		GlyphCollection? gc;+		OverviewUndoItem ui = new OverviewUndoItem ();+		Font font = BirdFont.get_current_font ();+		+		ui.alternate_sets = font.alternates.copy ();+		+		foreach (GlyphCollection g in previous_collection.glyphs) {+			gc = font.get_glyph_collection (g.get_name ());+			+			if (gc != null) {+				ui.glyphs.add (((!) gc).copy ());+			} else {+				ui.glyphs.add (new GlyphCollection (g.get_unicode_character (), g.get_name ()));+			}+		}+		+		return ui;		+	}+	+	public void store_undo_state (GlyphCollection gc) {+		OverviewUndoItem i = new OverviewUndoItem ();+		Font f = BirdFont.get_current_font ();+		i.alternate_sets = f.alternates.copy ();+		i.glyphs.add (gc);+		store_undo_items (i);+	}++	public void store_undo_items (OverviewUndoItem i) {+		undo_items.add (i);+		redo_items.clear ();+	}+	+	bool select_visible_glyph (string name) {+		int i = 0;+		+		foreach (OverviewItem o in visible_items) {+			if (o.get_name () == name) {+				selected = i;+				selected_item = get_selected_item ();++				if (selected_item.y > allocation.height - OverviewItem.height) {+					view_offset_y -= (selected_item.y + OverviewItem.height) - allocation.height;+				}++				if (selected_item.y < 0) {+					view_offset_y = 0;+				}		++				return true;+			}+			+			if (i > 1000) {+				warning ("selected character not found");+				return true;+			}+			+			i++;+		}+		+		return false;+	}+	+	public void scroll_to_char (unichar c) {+		StringBuilder s = new StringBuilder ();++		if (is_modifier_key (c)) {+			return;+		}+		+		s.append_unichar (c);+		scroll_to_glyph (s.str);+	}+		+	public void scroll_to_glyph (string name) {+		GlyphRange gr = glyph_range;+		int i, r, index;+		string ch;+		Font font = BirdFont.get_current_font ();+		GlyphCollection? glyphs = null;+		Glyph glyph;+		+		index = -1;+		+		if (items_per_row <= 0) {+			return;+		}++		ch = name;++		// selected char is visible+		if (select_visible_glyph (ch)) {+			return;+		}+		+		// scroll to char+		if (all_available) {+			+			// don't search for glyphs in huge CJK fonts +			if (font.length () > 500) {+				r = 0;+			} else {+				// FIXME: too slow+				for (r = 0; r < font.length (); r += items_per_row) {+					for (i = 0; i < items_per_row && i < font.length (); i++) {+						glyphs = font.get_glyph_collection_index ((uint32) r + i);+						return_if_fail (glyphs != null);+						glyph = ((!) glyphs).get_current ();+						+						if (glyph.name == ch) {+							index = i;+						}+					}+					+					if (index > -1) {+						break;+					}+				}+			}+		} else {+			+			if (ch.char_count () > 1) {+				warning ("Can't scroll to ligature in this view");+				return;+			}+			+			for (r = 0; r < gr.length (); r += items_per_row) {+				for (i = 0; i < items_per_row; i++) {+					if (gr.get_char (r + i) == ch) {+						index = i;+					}+				}+				+				if (index > -1) {+					break;+				}+			}+		}+		+		if (index > -1) {+			first_visible = r;+			process_item_list_update ();+			update_item_list ();+			select_visible_glyph (ch);+		}+	}+	+	public override void double_click (uint button, double ex, double ey) +		requires (!is_null (visible_items) && !is_null (allocation)) {+		+		return_if_fail (!is_null (this));+		+		foreach (OverviewItem i in visible_items) {+			if (i.double_click (button, ex, ey)) {+				open_overview_item (i);+			}+		}+	+		GlyphCanvas.redraw ();+	}++	public void open_overview_item (OverviewItem i) {+		return_if_fail (!is_null (i));+		+		if (i.glyphs != null) {+			open_glyph_signal ((!) i.glyphs);+			GlyphCollection gc = (!) i.glyphs;+			gc.get_current ().close_path ();+		} else {+			open_new_glyph_signal (i.character);+		}+	}+	+	public void set_character_info (CharacterInfo i) {+		character_info = i;+	}++	public int get_selected_index () {+		GlyphCollection gc;+		int index = 0;+		+		if (selected_items.size == 0) {+			return 0;+		}+		+		gc = selected_items.get (0);+		+		foreach (OverviewItem i in visible_items) {+			if (i.glyphs != null && gc == ((!) i.glyphs)) {+				break;+			}+			+			index++;+		}+		+		return index;+	}++	public void hide_menu () {+		foreach (OverviewItem i in visible_items) {+			i.hide_menu ();+		}	+	}++	public override void button_press (uint button, double x, double y) {+		OverviewItem i;+		int index = 0;+		int selected_index = -1;+		bool update = false;+		+		if (character_info != null) {+			character_info = null;+			GlyphCanvas.redraw ();+			return;+		}+		+		if (!KeyBindings.has_shift ()) {+			selected_items.clear ();+		}+		+		for (int j = 0; j < visible_items.size; j++) {+			i = visible_items.get (j);+			if (i.click_menu (button, x, y)) {+				GlyphCanvas.redraw ();+				return;+			}+		}++		for (int j = 0; j < visible_items.size; j++) {+			i = visible_items.get (j);+			if (i.click_info (button, x, y)) {+				GlyphCanvas.redraw ();+				return;+			}+		}+				+		for (int j = 0; j < visible_items.size; j++) {+			i = visible_items.get (j);+			+			if (i.click (button, x, y)) {+				selected = index;+				selected_item = get_selected_item ();+				+				if (KeyBindings.has_shift ()) {+					if (selected_item.glyphs != null) {+						+						selected_index = selected_items.index_of ((!) selected_item.glyphs);+						if (selected_index == -1) {+							selected_items.add ((!) selected_item.glyphs);+						} else {+							return_if_fail (0 <= selected_index < selected_items.size);+							selected_items.remove_at (selected_index);+							selected = get_selected_index ();+							selected_item = get_selected_item ();+						}+					}+				} else {+					selected_items.clear ();+					if (selected_item.glyphs != null) {+						selected_items.add ((!) selected_item.glyphs);+					}+				}+				+				if (!is_null (i.version_menu)) {+					update = !((!)i).version_menu.menu_visible;+				} else {+					update = true;+				}+			}+			index++;+		}+	+		if (update) {+			update_item_list ();+		}+		+		GlyphCanvas.redraw ();+	}++	/** Returns true if overview shows the last character. */+	private bool at_bottom () {+		Font f;+		double t = rows * items_per_row + first_visible;++		if (all_available) {+			f = BirdFont.get_current_font ();+			return t >= f.length () + 2 * items_per_row;+		}+		+		return t >= glyph_range.length () + 2 * items_per_row;+	}+	+	public void set_current_glyph_range (GlyphRange range) {+		GlyphRange? current = glyph_range;+		string c;+		+		if (current != null) {+			c = glyph_range.get_char (selected);+		}+		+		all_available = false;+		+		glyph_range = range;+		scroll_top ();++		// TODO: scroll down to c+		update_item_list ();+		selected_item = get_selected_item ();++		GlyphCanvas.redraw ();+	}++	public void select_next_glyph () {+		key_right ();+	}+	+	public void open_current_glyph () {+		// keep this object even if open_glyph_signal closes the display+		this.ref ();+		 +		selected_item = get_selected_item ();+		if (selected_item.glyphs != null) {+			open_glyph_signal ((!) selected_item.glyphs);+			GlyphCollection gc = (!) selected_item.glyphs;+			gc.get_current ().close_path ();+		} else {+			open_new_glyph_signal (selected_item.character);+		}+		+		this.unref ();+	}++	public double update_scrollbar () {+		Font f;+		double nrows = 0;+		double pos = 0;+		double size;+		double visible_rows;+		+		if (rows == 0) {+			MainWindow.set_scrollbar_size (0);+			MainWindow.set_scrollbar_position (0);+		} else {+			if (all_available) {+				f = BirdFont.get_current_font ();+				nrows = Math.ceil ((f.length ()) / (double) rows);+				size = f.length ();+			} else {+				nrows = Math.ceil ((glyph_range.length ()) / (double) rows);+				size = glyph_range.length ();+			}+			+			if (nrows <= 0) {+				nrows = 1;+			}++			visible_rows = allocation.height / (OverviewItem.height + OverviewItem.margin);+			scroll_size = visible_rows / nrows;+			MainWindow.set_scrollbar_size (scroll_size);+			pos = first_visible / (size - visible_rows * items_per_row);+			+			if (pos > 1) {+				pos = 1;+			}+								+			MainWindow.set_scrollbar_position (pos);+			+			if (at_bottom () && first_visible == 0) {+				MainWindow.hide_scrollbar ();+			} else {+				MainWindow.show_scrollbar ();+			}+		}+		+		return pos;+	}++	/** Display one entry from the Unicode Character Database. */+	void draw_character_info (Context cr) +	requires (character_info != null) {+		double x, y, w, h;+		int i;+		string unicode_value, unicode_description;+		string[] column;+		string entry;+		int len = 0;+		int length = 0;+		bool see_also = false;+		WidgetAllocation allocation = MainWindow.get_overview ().allocation;+		string name;+		string[] lines;+		double character_start;+		double character_height;+		+		entry = ((!)character_info).get_entry ();++		lines = entry.split ("\n");+		+		foreach (string line in entry.split ("\n")) {+			len = line.char_count ();+			if (len > length) {+				length = len;+			}+		}+		+		x = allocation.width * 0.1;+		y = allocation.height * 0.1;+		w = allocation.width * 0.9 - x; +		h = allocation.height * 0.9 - y;+		+		if (w < 8 * length) {+			w = 8 * length;+			x = (allocation.width - w) / 2.0;+		}+		+		if (x < 0) {+			x = 2;+		}+		+		// background	+		cr.save ();+		Theme.color_opacity (cr, "Background 1", 0.98);+		cr.rectangle (x, y, w, h);+		cr.fill ();+		cr.restore ();++		cr.save ();+		Theme.color_opacity (cr, "Foreground 1", 0.98);+		cr.set_line_width (2);+		cr.rectangle (x, y, w, h);+		cr.stroke ();+		cr.restore ();++		// database entry+		+		if (((!)character_info).is_ligature ()) {+			name = ((!)character_info).get_name ();+			draw_info_line (name, cr, x, y, 0);+		} else {+			i = 0;+			foreach (string line in lines) {+				if (i == 0) {+					column = line.split ("\t");+					return_if_fail (column.length == 2);+					unicode_value = "U+" + column[0];+					unicode_description = column[1];++					draw_info_line (unicode_description, cr, x, y, i);+					i++;++					draw_info_line (unicode_value, cr, x, y, i);+					i++;			+				} else {+					+					if (line.has_prefix ("\t*")) {+						draw_info_line (line.replace ("\t*", "•"), cr, x, y, i);+						i++;					+					} else if (line.has_prefix ("\tx (")) {+						if (!see_also) {+							i++;+							draw_info_line (t_("See also:"), cr, x, y, i);+							i++;+							see_also = true;+						}+						+						draw_info_line (line.replace ("\tx (", "•").replace (")", ""), cr, x, y, i);+						i++;+					} else {+						i++;+					}+				}+			}+			+			character_start = y + 10 + i * UCD_LINE_HEIGHT;+			character_height = h - character_start;++			draw_fallback_character (cr, x, character_start, character_height);+		}+	}+	+	/** Fallback character in UCD info. */+	void draw_fallback_character (Context cr, double x, double y, double height)+	requires (character_info != null) {+		unichar c = ((!)character_info).unicode;++		if (height < 0) {+			return;+		}++		cr.save ();+		Text character = new Text ();+		character.set_use_cache (false);+		Theme.text_color (character, "Foreground 1");+		character.set_text ((!) c.to_string ());+		character.set_font_size (height);+		character.draw_at_top (cr, x + 10, y);+		cr.restore ();+	}++	void draw_info_line (string line, Context cr, double x, double y, int row) {+		Text ucd_entry = new Text (line);+		cr.save ();+		Theme.text_color (ucd_entry, "Foreground 1");+		ucd_entry.widget_x = 10 + x;+		ucd_entry.widget_y = 10 + y + row * UCD_LINE_HEIGHT;+		ucd_entry.draw (cr);+		cr.restore ();		+	}+	+	public void paste () {+		GlyphCollection gc;+		GlyphCollection? c;+		Glyph glyph;+		uint32 index;+		int i;+		int skip = 0;+		int s;+		string character_string;+		Gee.ArrayList<GlyphCollection> glyps;+		Font f;+		OverviewUndoItem undo_item;+		+		f = BirdFont.get_current_font ();+		gc = new GlyphCollection ('\0', "");+		glyps = new Gee.ArrayList<GlyphCollection> ();+		+		copied_glyphs.sort ((a, b) => {+			return (int) ((GlyphCollection) a).get_unicode_character () +				- (int) ((GlyphCollection) b).get_unicode_character ();+		});++		index = (uint32) first_visible + selected;+		for (i = 0; i < copied_glyphs.size; i++) {+			if (all_available) {+				if (f.length () == 0) {+					c = add_empty_character_to_font (copied_glyphs.get (i).get_unicode_character (),+						copied_glyphs.get (i).is_unassigned (), +						copied_glyphs.get (i).get_name ());+				} else if (index >= f.length ()) {+					// FIXME: duplicated unicodes?+					c = add_empty_character_to_font (copied_glyphs.get (i).get_unicode_character (),+						copied_glyphs.get (i).is_unassigned (), +						copied_glyphs.get (i).get_name ());+				} else {+					c = f.get_glyph_collection_index ((uint32) index);+				}+				+				if (c == null) {+					c = add_empty_character_to_font (copied_glyphs.get (i).get_unicode_character (),+						copied_glyphs.get (i).is_unassigned (),+						copied_glyphs.get (i).get_name ());+				}+				+				return_if_fail (c != null);+				gc = (!) c; +			} else {			+				if (i != 0) {+					s = (int) copied_glyphs.get (i).get_unicode_character ();+					s -= (int) copied_glyphs.get (i - 1).get_unicode_character ();+					s -= 1;+					skip += s;+				}++				character_string = glyph_range.get_char ((uint32) (index + skip));+				c = f.get_glyph_collection_by_name (character_string);+				+				if (c == null) {+					gc = add_empty_character_to_font (character_string.get_char (), +						copied_glyphs.get (i).is_unassigned (),+						copied_glyphs.get (i).get_name ());+				} else {+					gc = (!) c;+				}+			}+			+			glyps.add (gc);+			index++;+		}++		undo_item = new OverviewUndoItem ();+		undo_item.alternate_sets = f.alternates.copy ();+		foreach (GlyphCollection g in glyps) {+			undo_item.glyphs.add (g.copy ());+		}+		store_undo_items (undo_item);++		if (glyps.size != copied_glyphs.size) {+			warning ("glyps.size != copied_glyphs.size");+			return;+		}++		if (copied_glyphs.size < i) {+			warning ("Array index out of bounds.");+			return;+		}+		+		i = 0;+		foreach (GlyphCollection g in glyps) {+			glyph = copied_glyphs.get (i).get_current ().copy ();+			glyph.version_id = (glyph.version_id == -1 || g.length () == 0) ? 1 : g.get_last_id () + 1;+			glyph.unichar_code = g.get_unicode_character ();++			if (!g.is_unassigned ()) {+				glyph.name = (!) glyph.unichar_code.to_string ();+			} else {+				glyph.name = g.get_name ();+			}+			+			g.insert_glyph (glyph, true);+			i++;+		}+		+		f.touch ();+		+		update_item_list ();+		GlyphCanvas.redraw ();+	}++	public override bool needs_modifier () {+		return true;+	}+	+	public class OverviewUndoItem {+		public AlternateSets alternate_sets = new AlternateSets ();+		public Gee.ArrayList<GlyphCollection> glyphs = new Gee.ArrayList<GlyphCollection> ();+	}+}++}diff --git a/libbirdfont/OverviewItem.vala b/libbirdfont/OverviewItem.valanew file mode 100644index 0000000..179c319--- /dev/null+++ b/libbirdfont/OverviewItem.vala@@ -0,0 +1,482 @@+/*+	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 +	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;+using Math;++[CCode (cname = "draw_overview_glyph")]+public extern bool draw_overview_glyph (Context context, string font_file, double width, double height, unichar character);++namespace BirdFont {+	+public class OverviewItem : GLib.Object {+	public unichar character = '\0';+	public GlyphCollection? glyphs;+	public double x;+	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;+	+	public static double width = 100;+	public static double height = 130;+	public static double margin = 20;++	public static double glyph_scale = 1.0;+	+	public VersionList version_menu;+	Text label;+	+	private Surface? cache = null;+	+	public static Surface? label_background = null;+	public static Surface? selected_label_background = null;+	public static Surface? label_background_no_menu = null;+	public static Surface? selected_label_background_no_menu = null;+		+	public OverviewItem () {	+	}++	public void set_character (unichar character) {+		this.character = character;+	}+	+	public void set_glyphs (GlyphCollection? gc) {+		glyphs = gc;+		+		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 ();+			});+		}	++		info = new CharacterInfo (character, glyphs);+		+		if (glyphs == null) {+			label = new Text ();+		} else {+			if (character != '\0') {+				label = new Text ((!) character.to_string (), 17);+			} else {+				label = new Text ((!) info.get_name (), 17);+			}+			+			truncate_label ();+		}+		+		draw_background ();		+	}++	public void clear_cache () {+		cache = null;+		+		if (glyphs != null) {+			Glyph g = ((!) glyphs).get_current ();+			g.overview_thumbnail = null;+		}+	}++	public void draw_glyph_from_font () {+		if (glyphs == null) {+			return;+		}+		+		Glyph g;+		double gx, gy;+		double x1, x2, y1, y2;+		double scale_box;+		double w, h;+		double glyph_width, glyph_height;+		Surface s;+		Context c;+		Color color = Color.black ();+		+		g = ((!) glyphs).get_current ();+		+		if (likely (g.overview_thumbnail != null)) {+			cache = g.overview_thumbnail;+			return;+		}+		+		w = width;+		h = height;++		scale_box = (height / DEFAULT_HEIGHT) * 0.65;++		s = Screen.create_background_surface ((int) width, (int) height - 20);+		c = new Context (s);+		+		c.save ();+		g.boundaries (out x1, out y1, out x2, out y2);+	+		glyph_width = x2 - x1;+		glyph_height = y2 - y1;+		+		c.save ();+		c.scale (scale_box * Screen.get_scale (), scale_box * Screen.get_scale ());++		g.add_help_lines ();+		+		gx = ((w / scale_box) - glyph_width) / 2 - g.get_left_side_bearing ();+		gy = h / scale_box + g.get_baseline () - 20 / scale_box - 20;++		c.translate (gx - Glyph.xc () - g.get_lsb (), gy - Glyph.yc ());++		g.draw_paths (c, color);+		c.restore ();+		+		cache = s;+		g.overview_thumbnail = s;+		+		GlyphCanvas.redraw ();+	}++	public void draw_background () {+		double scale_box;+		double w, h;+		Surface s;+		Context c;+		+		w = width;+		h = height;+		+		scale_box = width / DEFAULT_WIDTH;+		s = Screen.create_background_surface ((int) width, (int) height - 20);+		c = new Context (s);+		+		if (glyphs != null) { // FIXME: lock+			draw_glyph_from_font ();+		} else {+			c.scale (Screen.get_scale (), Screen.get_scale ());+			+			c.save ();+			+			bool glyph_found;+			string? font_file;+			+			Theme.color (c, "Overview Glyph");+			+			font_file = FontCache.fallback_font.get_default_font_file ();	+			glyph_found = draw_overview_glyph (c, (!) font_file, width, height, character);+			+			if (!glyph_found) {+				font_file = find_font (FallbackFont.font_config, (!) character.to_string ());+				+				if (font_file != null) {+					string path = (!) font_file;+					+					if (!path.has_suffix("LastResort.ttf")) {+						draw_overview_glyph (c, path, width, height, character);+					}+				}+			}+			+			c.restore ();+			+			cache = s;+			GlyphCanvas.redraw ();+		}+	}++	public static void reset_label () {+		label_background = null;+		selected_label_background = null;+	}+	+	void truncate_label () {+		double w = has_icons () ? width - 43 : width;+		label.truncate (w);+	}++	public string get_name () {+		StringBuilder s;+		+		if (glyphs != null) {+			return ((!) glyphs).get_name ();+		}+		+		s = new StringBuilder ();+		s.append_unichar (character);+		+		return s.str;+	}+	+	public void set_selected (bool s) {+		selected = s;+	}+	+	public static double full_width () {+		return width + margin;+	}++	public static double full_height () {+		return height + margin;+	}+	+	public bool click_menu (uint button, double px, double py) {+		bool a;+		GlyphCollection g;++		if (has_icons () && glyphs != null) {+			g = (!) glyphs;+			version_menu.set_position (x + width - 21, y + height - 18);+			a = version_menu.menu_item_action (px, py); // select one item on the menu+			+			if (a) {+				MainWindow.get_overview ().reset_cache ();+				MainWindow.get_overview ().update_item_list ();++				GlyphCanvas.redraw ();+				return true;+			}+			+			version_menu.menu_icon_action (px, py); // click in the open menu+		}+		+		return false;+	}+	+	public bool click_info (uint button, double px, double py) {+		info.set_position (x + width - 17, y + height - 22.5);+		+		if (has_icons () && info.is_over_icon (px, py)) {+			MainWindow.get_overview ().set_character_info (info);+			return true;+		}+		+		return false;+	}+	+	public bool click (uint button, double px, double py) {+		bool s = (x <= px <= x + width) && (y <= py <= y + height);		+		return s;+	}++	public bool double_click (uint button, double px, double py) {+		selected = (x <= px <= x + width) && (y <= py <= y + height);+		return selected;+	}++	public bool is_on_screen (WidgetAllocation allocation) {+		return y + height > 0 && y < allocation.height;+	}++	public void draw (WidgetAllocation allocation, Context cr) {+		if (!is_on_screen (allocation)) {+			return;+		}++		cr.save ();+		Theme.color (cr, "Background 1");+		cr.rectangle (x, y, width, height);+		cr.fill ();+		cr.restore ();++		cr.save ();+		Theme.color (cr, "Overview Item Border");+		cr.rectangle (x, y, width, height);+		cr.set_line_width (1);+		cr.stroke ();+		cr.restore ();+		+		draw_thumbnail (cr, x, y + height);+		+		draw_caption (cr);+		draw_menu (cr);+	}++	private void draw_thumbnail (Context cr, double x, double y) {		+		if (cache != null) {+			cr.save ();+			cr.set_antialias (Cairo.Antialias.NONE);+			cr.scale (1 / Screen.get_scale (), 1 / Screen.get_scale ());	+			cr.set_source_surface ((!) cache, (int) (x * Screen.get_scale ()), (int) ((y - height)) * Screen.get_scale ());+			cr.paint ();+			cr.restore ();+		}+	}++	public bool has_icons () {+		return width > 50;+	}++	public void draw_caption (Context cr) {+		draw_label_background (cr);+		+		cr.save ();+		+		if (glyphs != null) {+			if (selected) {+				Theme.text_color (label, "Overview Selected Foreground");+			} else {+				Theme.text_color (label, "Overview Foreground");+			}+		+			label.draw_at_baseline (cr, x + 0.08 * width, y + height - 6);+		}+		+		cr.restore ();+	}+	+	public void create_label_background_cache (Context cr) {+		Context cc;+		Cairo.Pattern p;+		Surface cache;+			+		// unselected item+		cache = Screen.create_background_surface ((int) width + 1, 20);+		cc = new Context (cache);+		cc.scale(Screen.get_scale(), Screen.get_scale());++		cc.rectangle (0, 0, width, 20 - 1);+		p = new Cairo.Pattern.linear (0.0, 0, 0.0, 20);+		Theme.gradient (p, "Overview Item 1", "Overview Item 2");+		cc.set_source (p);+			+		cc.fill ();+		+		if (has_icons ()) {+			draw_menu_icon (cc, false);+			draw_character_info_icon (cc);+		}++		label_background = (!) cache;	++		// selected item+		cache = Screen.create_background_surface ((int) width + 1, 20);+		cc = new Context (cache);+		cc.scale(Screen.get_scale(), Screen.get_scale());++		cc.rectangle (0, 0, width, 20 - 1);++		Theme.color (cc, "Selected Overview Item");+			+		cc.fill ();+		+		if (has_icons ()) {+			draw_menu_icon (cc, true);+			draw_character_info_icon (cc);+		}++		selected_label_background = (!) cache;	+	+		// deselected item without menu icon+		cache = Screen.create_background_surface ((int) width, 20);+		cc = new Context (cache);+		cc.scale(Screen.get_scale(), Screen.get_scale());+		cc.rectangle (0, 0, width - 1, 20 - 1);+		p = new Cairo.Pattern.linear (0.0, 0, 0.0, 20);+		Theme.gradient (p, "Overview Item 1", "Overview Item 2");+		cc.set_source (p);+		cc.fill ();++		if (has_icons ()) {+			draw_character_info_icon (cc);+		}+		+		label_background_no_menu = (!) cache;++		// selected item+		cache = Screen.create_background_surface ((int) width + 1, 20);+		cc = new Context (cache);+		cc.scale(Screen.get_scale(), Screen.get_scale());+		cc.rectangle (0, 0, width, 20 - 1);+		Theme.color (cc, "Selected Overview Item");+		cc.fill ();++		if (has_icons ()) {+			draw_character_info_icon (cc);+		}+				+		selected_label_background_no_menu = (!) cache;		+	}+	+	bool has_menu () {+		return glyphs != null;+	}+	+	public void draw_label_background (Context cr) {+		Surface cache;+		bool icon;+		+		if (unlikely (label_background == null)) {+			create_label_background_cache (cr);+		}+		+		if (label_background != null +			&& selected_label_background != null+			&& label_background_no_menu != null+			&& selected_label_background_no_menu != null) {+			+			icon = has_menu ();+			if (selected && icon) {+				cache = (!) selected_label_background;+			} else if (!selected && icon) {+				cache = (!) label_background;+			} else if (selected && !icon) {+				cache = (!) selected_label_background_no_menu;+			} else {+				cache = (!) label_background_no_menu;+			}+			+			Screen.paint_background_surface (cr, cache, (int) x, (int) (y + height - 19));+		}+	}+	+	private void draw_character_info_icon (Context cr) {+		info.draw_icon (cr, selected, width - 17, -1.5);+	}+	+	public void hide_menu () {+		if (!is_null (version_menu)) {+			version_menu.menu_visible = false;+		}+	}+	+	private void draw_menu_icon (Context cc, bool selected) {+		Text icon;++		icon = new Text ("dropdown_menu", 17);+		icon.load_font ("icons.birdfont");++		if (selected) {+			Theme.text_color (icon, "Overview Selected Foreground");+		} else {+			Theme.text_color (icon, "Overview Foreground");+		}+		+		icon.draw_at_top (cc, width - 32, 0);+	}+	+	private void draw_menu (Context cr) {+		if (likely (glyphs == null || !version_menu.menu_visible)) {+			return;+		}+		+		version_menu.draw_menu (cr);+	}+}++}diff --git a/libbirdfont/OverviewTools.vala b/libbirdfont/OverviewTools.valaindex 978f578..70df7a0 100644--- a/libbirdfont/OverviewTools.vala+++ b/libbirdfont/OverviewTools.vala@@ -62,7 +62,7 @@ public class OverviewTools : ToolCollection  { 		all_glyphs = new LabelTool (t_("All Glyphs")); 		all_glyphs.has_counter = true; 		all_glyphs.select_action.connect ((self) => {-			OverView overview = get_overview ();+			Overview overview = get_overview (); 			overview.display_all_available_glyphs (); 			update_overview_characterset (overview); 			FontDisplay.dirty_scrollbar = true;@@ -72,7 +72,7 @@ public class OverviewTools : ToolCollection  { 		default_glyphs = new LabelTool (t_("Default")); 		default_glyphs.has_counter = true; 		default_glyphs.select_action.connect ((self) => {-			OverView overview = get_overview ();+			Overview overview = get_overview (); 			GlyphRange gr = new GlyphRange (); 			DefaultCharacterSet.use_default_range (gr); 			overview.set_current_glyph_range (gr);@@ -84,7 +84,7 @@ public class OverviewTools : ToolCollection  { 		unicode = new LabelTool (t_("Unicode")); 		unicode.has_counter = true; 		unicode.select_action.connect ((self) => {-			OverView overview = get_overview ();+			Overview overview = get_overview (); 			GlyphRange gr = new GlyphRange (); 			DefaultCharacterSet.use_full_unicode_range (gr); 			overview.set_current_glyph_range (gr);@@ -248,12 +248,12 @@ public class OverviewTools : ToolCollection  { 	}  	void fix_curve_orientation () {-		OverView o;+		Overview o; 		Glyph g;-		OverView.OverViewUndoItem ui;+		Overview.OverviewUndoItem ui; 		 		o = get_overview ();-		ui = new OverView.OverViewUndoItem ();+		ui = new Overview.OverviewUndoItem (); 		 		Font f = BirdFont.get_current_font (); 		ui.alternate_sets = f.alternates.copy ();@@ -273,12 +273,12 @@ public class OverviewTools : ToolCollection  { 	 	public void search_for_glyph (Tool tool) { 		tool.set_selected (false);-		OverView.search ();+		Overview.search (); 	} 	 	public void add_new_alternate (Tool tool) {-		OverView o = MainWindow.get_overview ();-		OverViewItem oi = o.selected_item;+		Overview o = MainWindow.get_overview ();+		OverviewItem oi = o.selected_item; 		GlyphCollection? gc; 		 		tool.set_selected (false);@@ -293,12 +293,12 @@ public class OverviewTools : ToolCollection  { 	} 	 	public void process_transform (Transform transform) {-		OverView o;+		Overview o; 		Glyph g;-		OverView.OverViewUndoItem ui;+		Overview.OverviewUndoItem ui; 		 		o = get_overview ();-		ui = new OverView.OverViewUndoItem ();+		ui = new Overview.OverviewUndoItem (); 		 		Font f = BirdFont.get_current_font (); 		ui.alternate_sets = f.alternates.copy ();@@ -324,7 +324,7 @@ public class OverviewTools : ToolCollection  { 			} 		} 		-		foreach (OverViewItem item in o.visible_items) {+		foreach (OverviewItem item in o.visible_items) { 			item.clear_cache (); 			item.draw_glyph_from_font (); 		}@@ -335,26 +335,26 @@ public class OverviewTools : ToolCollection  { 		GlyphCanvas.redraw (); 	} 	-	public OverView get_overview () {+	public Overview get_overview () { 		FontDisplay fd = MainWindow.get_current_display (); 		-		if (fd is OverView || fd is GlyphSelection) {-			return (OverView) fd;+		if (fd is Overview || fd is GlyphSelection) {+			return (Overview) fd; 		} 		 		warning ("Current tab is not overview."); 		-		return new OverView ();+		return new Overview (); 	} 	 	public static void show_all_available_characters () { 		all_glyphs.select_action (all_glyphs); 	} 	-	public static void update_overview_characterset (OverView? tab = null) {+	public static void update_overview_characterset (Overview? tab = null) { 		GlyphRange gr; 		uint size;-		OverView overview;+		Overview overview;  		// All characters 		size = BirdFont.get_current_font ().length ();diff --git a/libbirdfont/TestCases.vala b/libbirdfont/TestCases.valaindex f92a3ce..0dddd52 100644--- a/libbirdfont/TestCases.vala+++ b/libbirdfont/TestCases.vala@@ -677,7 +677,7 @@ class TestCases { 	}  	public static void test_overview () {-		OverView o = MainWindow.get_overview ();+		Overview o = MainWindow.get_overview ();  		warn_if_fail (o.selected_char_is_visible ()); 	@@ -1202,7 +1202,7 @@ class TestCases { 	}  	public static void test_open_next_glyph () {-		OverView o = MainWindow.get_overview ();+		Overview o = MainWindow.get_overview (); 		 		MainWindow.get_tab_bar ().select_overview (); 		Toolbox.select_tool_by_name ("utf_8");diff --git a/libbirdfont/ThemeTab.vala b/libbirdfont/ThemeTab.valaindex 075d3e2..a74f48a 100644--- a/libbirdfont/ThemeTab.vala+++ b/libbirdfont/ThemeTab.vala@@ -139,10 +139,10 @@ internal class ThemeTab : SettingsDisplay { 		tb = MainWindow.get_tab_bar (); 		tb.redraw (0, 0, tb.width, tb.height); 			-		OverViewItem.label_background = null;-		OverViewItem.selected_label_background = null;-		OverViewItem.label_background_no_menu = null;-		OverViewItem.selected_label_background_no_menu = null;		+		OverviewItem.label_background = null;+		OverviewItem.selected_label_background = null;+		OverviewItem.label_background_no_menu = null;+		OverviewItem.selected_label_background_no_menu = null;		 	} 	 	public static string get_label_from_file_name (string theme) {diff --git a/libbirdfont/VersionList.vala b/libbirdfont/VersionList.valaindex 4d82cd5..1c16848 100644--- a/libbirdfont/VersionList.vala+++ b/libbirdfont/VersionList.vala@@ -84,7 +84,7 @@ public class VersionList : GLib.Object { 	private void delete_item (int index) { 		int current_version; 		Font font = BirdFont.get_current_font ();-		OverView over_view = MainWindow.get_overview ();+		Overview over_view = MainWindow.get_overview (); 		 		font.touch (); 		

Contact

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