Commit b832c52
Refactoring
Changed files (18)
modifiedlibbirdfont/ClipTool.valamodifiedlibbirdfont/ExportTool.valamodifiedlibbirdfont/FileTools.valamodifiedlibbirdfont/Glyph.valamodifiedlibbirdfont/GlyphSelection.valamodifiedlibbirdfont/LanguageSelectionTab.valamodifiedlibbirdfont/MainWindow.valamodifiedlibbirdfont/Menu.valamodifiedlibbirdfont/MenuTab.valamodifiedlibbirdfont/OtfFeatureTable.valadeletedlibbirdfont/OverView.valadeletedlibbirdfont/OverViewItem.valaaddedlibbirdfont/Overview.valaaddedlibbirdfont/OverviewItem.valamodifiedlibbirdfont/OverviewTools.valamodifiedlibbirdfont/TestCases.valamodifiedlibbirdfont/ThemeTab.valamodifiedlibbirdfont/VersionList.vala
Diff
@@ -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) {@@ -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) {@@ -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);@@ -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 (); }); @@ -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); @@ -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 (); @@ -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 (); } } @@ -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);@@ -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 ();@@ -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 (); deleted file mode 100644@@ -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> ();- }-}--}deleted file mode 100644@@ -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);- }-}--}new file mode 100644@@ -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> ();+ }+}++}new file mode 100644@@ -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);+ }+}++}@@ -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 ();@@ -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");@@ -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) {@@ -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 ();