Commit dd80093
Add ligatures
Changed files (11)
modifiedbirdfont/GtkWindow.valamodifiedlibbirdfont/BirdFontFile.valamodifiedlibbirdfont/ClipTool.valamodifiedlibbirdfont/Font.valamodifiedlibbirdfont/GlyphCollection.valamodifiedlibbirdfont/MenuTab.valamodifiedlibbirdfont/OpenFontFormat/Gsub.valamodifiedlibbirdfont/OverView.valamodifiedlibbirdfont/OverViewItem.valamodifiedlibbirdfont/PenTool.valamodifiedlibbirdfont/SvgParser.vala
Diff
@@ -731,6 +731,12 @@ public class GtkWindow : Gtk.Window, NativeWindow { show_ligatures.activate.connect (() => { MenuTab.show_ligature_tab (); });++ Gtk.MenuItem add_ligature = new Gtk.MenuItem.with_mnemonic (t_("_Add Ligature"));+ ligature_menu.append (add_ligature);+ add_ligature.activate.connect (() => { + MenuTab.add_ligature ();+ }); // Add menus Gtk.MenuItem file_launcher = new Gtk.MenuItem.with_mnemonic (t_("_File"));@@ -33,27 +33,35 @@ class BirdFontFile : GLib.Object { public bool load (string path) { string xml_data; XmlParser parser;- bool ok;+ bool ok = false; - FileUtils.get_contents(path, out xml_data);- - font.background_images.clear ();- font.font_file = path;- - parser = new XmlParser (xml_data);- ok = load_xml (parser);- + try {+ FileUtils.get_contents(path, out xml_data);+ + font.background_images.clear ();+ font.font_file = path;+ + parser = new XmlParser (xml_data);+ ok = load_xml (parser);+ } catch (GLib.FileError e) {+ warning (e.message);+ }+ return ok; } public bool load_part (string bfp_file) { string xml_data; XmlParser parser;- bool ok;+ bool ok = false; - FileUtils.get_contents(bfp_file, out xml_data);- parser = new XmlParser (xml_data);- ok = load_xml (parser);+ try {+ FileUtils.get_contents(bfp_file, out xml_data);+ parser = new XmlParser (xml_data);+ ok = load_xml (parser);+ } catch (GLib.FileError e) {+ warning (e.message);+ } return ok; }@@ -195,6 +203,7 @@ class BirdFontFile : GLib.Object { os.put_string ("""<?xml version="1.0" encoding="utf-8" standalone="yes"?>"""); os.put_string ("\n"); os.put_string ("<font>\n");+ os.put_string ("<format>1.0</format>\n"); } public void write_closing_root_tag (DataOutputStream os) throws GLib.Error {@@ -302,7 +311,15 @@ class BirdFontFile : GLib.Object { } public void write_glyph_collection_start (GlyphCollection gc, DataOutputStream os) throws GLib.Error {- os.put_string (@"<collection unicode=\"$(Font.to_hex (gc.get_current ().unichar_code))\">\n"); + os.put_string ("<collection ");+ + if (gc.get_current ().is_unassigned ()) {+ os.put_string (@"name=\"$(gc.get_current ().get_name ())\"");+ } else {+ os.put_string (@"unicode=\"$(Font.to_hex (gc.get_current ().unichar_code))\"");+ }+ + os.put_string (">\n"); } public void write_glyph_collection_end (DataOutputStream os) throws GLib.Error {@@ -902,10 +919,12 @@ class BirdFontFile : GLib.Object { int selected_id = -1; Attribute attribute; Tag t;+ bool unassigned = false; tag.reparse (); while (tag.has_more_attributes ()) { attribute = tag.get_next_attribute ();+ if (attribute.get_name () == "unicode") { unicode = Font.to_unichar (attribute.get_content ()); b = new StringBuilder ();@@ -915,6 +934,14 @@ class BirdFontFile : GLib.Object { if (name == "") { name = ".null"; }+ + unassigned = false;+ }++ if (attribute.get_name () == "name") {+ unicode = '\0';+ name = attribute.get_content ();+ unassigned = true; } } @@ -937,7 +964,7 @@ class BirdFontFile : GLib.Object { t = tag.get_next_tag (); if (t.get_name () == "glyph") {- parse_glyph (t, gc, name, unicode, selected_id);+ parse_glyph (t, gc, name, unicode, selected_id, unassigned); } } @@ -969,7 +996,8 @@ class BirdFontFile : GLib.Object { return id; } - private void parse_glyph (Tag tag, GlyphCollection gc, string name, unichar unicode, int selected_id) { + private void parse_glyph (Tag tag, GlyphCollection gc, string name, + unichar unicode, int selected_id, bool unassigned) { Glyph glyph = new Glyph (name, unicode); Path path; bool selected = false;@@ -1015,7 +1043,8 @@ class BirdFontFile : GLib.Object { } } - glyph.version_id = (has_id) ? id : (int) gc.length () + 1; + glyph.version_id = (has_id) ? id : (int) gc.length () + 1;+ glyph.set_unassigned (unassigned); gc.insert_glyph (glyph, selected || selected_id == id); } @@ -157,14 +157,29 @@ public class ClipTool : Tool { if (overview) { o = MainWindow.get_overview ();+ unichar last_assigned = '\0'; foreach (GlyphCollection gc in o.selected_items) { s.append ("\n"); s.append ("<!-- BirdFontClipboard\n"); - s.append ("BF glyph: ");- s.append (@"$(Font.to_hex (gc.get_unicode_character ()))");+ if (!gc.is_unassigned ()) {+ last_assigned = gc.get_unicode_character ();+ + s.append ("BF glyph: ");+ s.append (@"$(Font.to_hex (gc.get_unicode_character ()))");+ s.append ("\n");+ } else {+ last_assigned++;+ + s.append ("BF glyph: ");+ s.append (@"$(Font.to_hex (last_assigned))");+ s.append ("\n");+ }++ s.append ("BF unassigned: ");+ s.append (@"$(gc.is_unassigned ())"); s.append ("\n");- + s.append ("BF left: "); s.append (@"$(gc.get_current ().left_limit)"); s.append ("\n");@@ -191,6 +206,10 @@ public class ClipTool : Tool { s.append (@"$(Font.to_hex (glyph.unichar_code))"); s.append ("\n"); + s.append ("BF unassigned: ");+ s.append (@"$(glyph.is_unassigned ())");+ s.append ("\n");+ s.append ("BF left: "); s.append (@"$(glyph.left_limit)"); s.append ("\n");@@ -272,8 +291,6 @@ public class ClipTool : Tool { Gee.ArrayList<Glyph> glyphs = new Gee.ArrayList<Glyph> (); Glyph glyph = new Glyph ("null", '\0'); string[] items = data.split ("\nBF ");- string d;- int i; unichar c; Glyph destination; GlyphCollection gc;@@ -287,7 +304,13 @@ public class ClipTool : Tool { glyph = new Glyph ((!) c.to_string (), c); glyphs.add (glyph); }- ++ if (p.has_prefix ("unassigned:")) {+ p = p.replace ("unassigned: ", "");+ p = p.replace ("\n", "");+ glyph.set_unassigned (bool.parse (p)); // FIXME: move to gc+ }+ if (p.has_prefix ("path:")) { p = p.replace ("path: ", ""); p = p.replace ("\n", "");@@ -376,7 +376,8 @@ public class Font : GLib.Object { return; } - if (glyph_collection.get_unicode () != "") {+ // FIXME: move unassinged+ if (glyph_collection.get_unicode () != "" || glyph_collection.get_current ().is_unassigned ()) { glyph_name.insert (glyph_collection.get_name (), glyph_collection); } @@ -21,6 +21,7 @@ public class GlyphCollection : GLib.Object { VersionList versions; unichar unicode_character; string name;+ bool unassigned = false; public GlyphCollection (unichar unicode_character, string name) { this.unicode_character = unicode_character;@@ -28,6 +29,14 @@ public class GlyphCollection : GLib.Object { versions = new VersionList (null, this); } + public void set_unassigned (bool a) {+ unassigned = a;+ }++ public bool is_unassigned () {+ return unassigned;+ }+ public void add_glyph (Glyph g) { get_version_list ().add_glyph (g); }@@ -448,6 +448,50 @@ public class MenuTab : FontDisplay { SpacingClassTab t = MainWindow.get_spacing_class_tab (); MainWindow.get_tab_bar ().add_unique_tab (t); }++ public static void add_ligature () {+ TextListener listener;+ string ligature_name = "";+ + if (suppress_event) {+ warn_if_test ("Event suppressed");+ return;+ }+ + listener = new TextListener (t_("Name"), "", t_("Add ligature"));+ + listener.signal_text_input.connect ((text) => {+ ligature_name = text;+ });+ + listener.signal_submit.connect (() => {+ Font font = BirdFont.get_current_font ();+ GlyphCollection? fg;+ Glyph glyph;+ GlyphCollection glyph_collection;+ OverView o = MainWindow.get_overview ();++ fg = font.get_glyph_collection_by_name (ligature_name);++ if (fg == null) {+ glyph_collection = new GlyphCollection ('\0', ligature_name);+ + glyph = new Glyph (ligature_name, '\0');+ glyph.set_unassigned (true);+ glyph_collection.insert_glyph (glyph, true);++ font.add_glyph_collection (glyph_collection);+ }+ + o.display_all_available_glyphs ();+ o.scroll_to_glyph (ligature_name);+ + MainWindow.native_window.hide_text_input ();+ Toolbox.select_tool_by_name ("available_characters");+ });+ + MainWindow.native_window.set_text_listener (listener);+ } } }@@ -63,7 +63,7 @@ public class GsubTable : Table { fd.add_ushort (1); // number of lookups fd.add_ushort (4); // offset to lookup 1 - // ligature substitution+ // ligature substitution subtable fd.add_ushort (1); // lookup type, format identifier fd.add_ushort (20); // offset to coverage fd.add_ushort (1); // number of ligature set tables@@ -107,19 +107,24 @@ public class OverView : FontDisplay { update_scrollbar (); } - public GlyphCollection add_empty_character_to_font (unichar character) {- return add_character_to_font (character, true);+ 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) {+ 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; - name.append_unichar (character);-+ 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 {@@ -132,13 +137,15 @@ public class OverView : FontDisplay { glyph_collection = new GlyphCollection (character, name.str); if (!empty) {- glyph = new Glyph (name.str, character);+ glyph = new Glyph (name.str, (!unassigned) ? character : '\0'); glyph_collection.insert_glyph (glyph, true); } font.add_glyph_collection (glyph_collection); } + glyph_collection.set_unassigned (unassigned);+ return glyph_collection; } @@ -768,11 +775,11 @@ public class OverView : FontDisplay { redo_items.clear (); } - bool select_visible_character (unichar c) {+ bool select_visible_glyph (string name) { int i = 0; foreach (OverViewItem o in visible_items) {- if (o.character == c) {+ if (o.get_name () == name) { selected = i; selected_item = get_selected_item (); return true;@@ -788,11 +795,27 @@ public class OverView : FontDisplay { return false; }- + + bool select_visible_character (unichar c) {+ StringBuilder s = new StringBuilder ();+ s.append_unichar (c);+ return select_visible_glyph (s.str);+ }+ 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;- StringBuilder s = new StringBuilder (); string ch; Font font = BirdFont.get_current_font (); GlyphCollection? glyphs = null;@@ -804,16 +827,11 @@ public class OverView : FontDisplay { warning ("No items."); return; }- - if (is_modifier_key (c)) {- return;- }- - s.append_unichar (c);- ch = s.str;++ ch = name; // selected char is visible- if (select_visible_character (c)) {+ if (select_visible_glyph (ch)) { return; } @@ -842,6 +860,12 @@ public class OverView : FontDisplay { } } } 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) {@@ -858,7 +882,7 @@ public class OverView : FontDisplay { if (index > -1) { first_visible = r; update_item_list ();- select_visible_character (c);+ select_visible_glyph (ch); } } @@ -1125,24 +1149,27 @@ public class OverView : FontDisplay { return (int) ((GlyphCollection) a).get_unicode_character () - (int) ((GlyphCollection) b).get_unicode_character (); });- - // FIXME: copy and paste to unicode character + 1 - + 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 (- glyps.get (i).get_unicode_character ()); + c = add_empty_character_to_font (glyps.get (i).get_unicode_character (),+ glyps.get (i).is_unassigned (), glyps.get (i).get_name ()); } else if (index >= f.length ()) { c = add_empty_character_to_font (- ((!)f.get_glyph_collection_indice (f.length () - 1)).get_unicode_character () + i);+ ((!)f.get_glyph_collection_indice (f.length () - 1))+ .get_unicode_character () + i,+ glyps.get (i).is_unassigned (),+ glyps.get (i).get_name ()); } else { c = f.get_glyph_collection_indice ((uint32) index); } if (c == null) {- c = add_empty_character_to_font (copied_glyphs.get (i).get_unicode_character ());+ c = add_empty_character_to_font (copied_glyphs.get (i).get_unicode_character (),+ glyps.get (i).is_unassigned (),+ glyps.get (i).get_name ()); } return_if_fail (c != null);@@ -1159,7 +1186,9 @@ public class OverView : FontDisplay { c = f.get_glyph_collection_by_name (character_string); if (c == null) {- gc = add_empty_character_to_font (character_string.get_char ());+ gc = add_empty_character_to_font (character_string.get_char (), + glyps.get (i).is_unassigned (),+ glyps.get (i).get_name ()); } else { gc = (!) c; }@@ -18,7 +18,7 @@ using Math; namespace BirdFont { public class OverViewItem : GLib.Object {- public unichar character = 'A';+ public unichar character = '\0'; public GlyphCollection? glyphs; public double x; public double y;@@ -41,6 +41,19 @@ public class OverViewItem : GLib.Object { this.info = new CharacterInfo (character); } + 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; }@@ -530,9 +530,6 @@ public class PenTool : Tool { Glyph glyph = MainWindow.get_current_glyph (); double coordinate_x, coordinate_y; double delta_coordinate_x, delta_coordinate_y;- int px = 0;- int py = 0;- EditPoint p; double angle = 0; control_point_event (x, y);@@ -656,16 +653,7 @@ public class PenTool : Tool { } } }- - private static void tie_pixels (ref int x, ref int y) {- double coordinate_x, coordinate_y;- coordinate_x = Glyph.path_coordinate_x (x);- coordinate_y = Glyph.path_coordinate_y (y);- GridTool.tie_coordinate (ref coordinate_x, ref coordinate_y);- x = Glyph.reverse_path_coordinate_x (coordinate_x);- y = Glyph.reverse_path_coordinate_y (coordinate_y);- }- + public void press (int button, int x, int y, bool double_click) { Glyph? g = MainWindow.get_current_glyph (); Glyph glyph = (!) g;@@ -904,8 +892,7 @@ public class PenTool : Tool { Path path; bool direction_changed = false; Path union, second_path;- EditPoint last_point, first_point;- EditPointHandle last_rh, fist_lh;+ EditPoint first_point; int px, py; if (glyph.path_list.size == 0) {@@ -55,7 +55,6 @@ public class SvgParser { Glyph glyph; string[] lines = xml_data.split ("\n"); bool has_format = false;- StringBuilder sb = new StringBuilder (); SvgParser parser = new SvgParser (); XmlParser xmlparser; Tag root;@@ -363,7 +362,6 @@ public class SvgParser { private void parse_path (Tag tag, PathList pl) { Glyph glyph = MainWindow.get_current_glyph (); PathList path_list = new PathList ();- Tag t; Attribute attr; tag.reparse ();