Commit 84c0fa7
Create versions of glyphs in order to support multi-master fonts
Changed files (11)
modifiedlibbirdfont/BackgroundTab.valamodifiedlibbirdfont/BirdFontFile.valamodifiedlibbirdfont/BirdFontPart.valamodifiedlibbirdfont/ClipTool.valamodifiedlibbirdfont/Font.valamodifiedlibbirdfont/GlyphCollection.valamodifiedlibbirdfont/MainWindow.valamodifiedlibbirdfont/OverView.valamodifiedlibbirdfont/OverViewItem.valamodifiedlibbirdfont/OverviewTools.valamodifiedlibbirdfont/VersionList.vala
Diff
@@ -52,7 +52,11 @@ public class BackgroundTab : Glyph { GlyphCanvas canvas = MainWindow.get_glyph_canvas (); GlyphCollection gc = new GlyphCollection ('\0', "");- gc.add_glyph (this);+ + GlyphMaster master = new GlyphMaster ();+ master.add_glyph (this);+ gc.add_master (master);+ canvas.set_current_glyph_collection (gc, false); DrawingTools.background_scale.set_tool_visibility (true); ZoomTool.zoom_full_background_image ();@@ -152,7 +152,7 @@ class BirdFontFile : GLib.Object { try { string data;- foreach (Glyph g in gc.glyphs) {+ foreach (Glyph g in gc.get_all_glyph_masters ()) { if (g.get_background_image () != null) { bg = (!) g.get_background_image (); data = bg.get_png_base64 ();@@ -383,33 +383,50 @@ class BirdFontFile : GLib.Object { os.put_string ("</horizontal>\n"); } - public void write_glyph_collection_start (GlyphCollection gc, DataOutputStream os) throws GLib.Error {+ public void write_glyph_collection_start (GlyphCollection gc, GlyphMaster master, DataOutputStream os) throws GLib.Error { os.put_string ("<collection "); if (gc.is_unassigned ()) {- os.put_string (@"name=\"$(gc.get_current ().get_name ())\"");+ os.put_string (@"name=\"$(gc.get_name ())\""); } else {- os.put_string (@"unicode=\"$(Font.to_hex (gc.get_current ().unichar_code))\"");+ os.put_string (@"unicode=\"$(Font.to_hex (gc.get_unicode_character ()))\"");+ }+ + if (gc.is_multimaster ()) {+ os.put_string (" ");+ os.put_string (@"master=\"$(master.get_id ())\""); } os.put_string (">\n"); } public void write_glyph_collection_end (DataOutputStream os) throws GLib.Error {- os.put_string ("</collection>\n");+ os.put_string ("</collection>\n\n"); } - public void write_selected (GlyphCollection gc, DataOutputStream os) throws GLib.Error {- os.put_string (@"\t<selected id=\"$(gc.get_current ().version_id)\"/>\n");+ public void write_selected (GlyphMaster master, DataOutputStream os) throws GLib.Error {+ Glyph? g = master.get_current ();+ Glyph glyph;+ + if (g != null) {+ glyph = (!) g;+ os.put_string (@"\t<selected id=\"$(glyph.version_id)\"/>\n");+ } } public void write_glyph_collection (GlyphCollection gc, DataOutputStream os) throws GLib.Error {- write_glyph_collection_start (gc, os);- write_selected (gc, os);- foreach (Glyph g in gc.glyphs) {+ foreach (GlyphMaster master in gc.glyph_masters) {+ write_glyph_collection_start (gc, master, os);+ write_selected (master, os);+ write_glyph_master (master, os);+ write_glyph_collection_end (os);+ }+ }++ public void write_glyph_master (GlyphMaster master, DataOutputStream os) throws GLib.Error {+ foreach (Glyph g in master.glyphs) { write_glyph (g, os); }- write_glyph_collection_end (os); } public void write_glyph (Glyph g, DataOutputStream os) throws GLib.Error {@@ -1234,6 +1251,8 @@ class BirdFontFile : GLib.Object { string name = ""; int selected_id = -1; bool unassigned = false;+ string master_id = "";+ GlyphMaster master; foreach (Attribute attribute in tag.get_attributes ()) { if (attribute.get_name () == "unicode") {@@ -1249,11 +1268,16 @@ class BirdFontFile : GLib.Object { unassigned = false; } - if (attribute.get_name () == "name") {+ // set name because either name or unicode is set in the bf file+ if (attribute.get_name () == "name") { unicode = '\0'; name = attribute.get_content (); unassigned = true; }++ if (attribute.get_name () == "master") {+ master_id = attribute.get_content ();+ } } current_gc = font.get_glyph_collection_by_name (name);@@ -1264,17 +1288,24 @@ class BirdFontFile : GLib.Object { } else { gc = new GlyphCollection (unicode, name); }- + + if (gc.has_master (master_id)) {+ master = gc.get_master (master_id);+ } else {+ master = new GlyphMaster.for_id (master_id);+ gc.add_master (master);+ }+ foreach (Tag t in tag) { if (t.get_name () == "selected") { selected_id = parse_selected (t);- gc.set_selected_version (selected_id);+ master.set_selected_version (selected_id); } } foreach (Tag t in tag) { if (t.get_name () == "glyph") {- parse_glyph (t, gc, name, unicode, selected_id, unassigned);+ parse_glyph (t, gc, master, name, unicode, selected_id, unassigned); } } @@ -1302,8 +1333,8 @@ class BirdFontFile : GLib.Object { return id; } - public void parse_glyph (Tag tag, GlyphCollection gc, string name, - unichar unicode, int selected_id, bool unassigned) { + public void parse_glyph (Tag tag, GlyphCollection gc, GlyphMaster master,+ string name, unichar unicode, int selected_id, bool unassigned) { Glyph glyph = new Glyph (name, unicode); Path path; bool selected = false;@@ -1360,8 +1391,7 @@ class BirdFontFile : GLib.Object { glyph.version_id = (has_id) ? id : (int) gc.length () + 1; gc.set_unassigned (unassigned); - gc.insert_glyph (glyph, selected || selected_id == id);- glyph = new Glyph.no_lines ("");+ master.insert_glyph (glyph, selected || selected_id == id); } Layer parse_layer (Tag tag) {@@ -92,8 +92,8 @@ public class BirdFontPart : GLib.Object{ try { // remove deleted glyphs- foreach (Glyph g in font.deleted_glyphs) {- file_name = get_glyph_base_file_name (g) + ".bfp";+ foreach (string deleted_glyph in font.deleted_glyphs) {+ file_name = deleted_glyph; glyph_dir_name = get_subdir_name (file_name); glyph_file = get_destination_file (file_name, "glyphs", glyph_dir_name); @@ -156,21 +156,27 @@ public class BirdFontPart : GLib.Object{ selected_file_name = get_first_number_in_unicode (((!)gc).get_current ()); dir_name = get_subdir_name (selected_file_name);- - os = create_file (@"selected_$(selected_file_name).bfp", "glyphs", dir_name);- bf.write_root_tag (os);- bf.write_glyph_collection_start (gc, os);- bf.write_selected ((!) gc, os);- bf.write_glyph_collection_end (os);- bf.write_closing_root_tag (os);- os.close ();- - foreach (Glyph g in gc.glyphs) {- try {- write_glyph (bf, gc, g);- write_glyph_background_image (bf, gc, g);- } catch (GLib.Error e) {- warning (e.message);+ + // selected glyph+ foreach (GlyphMaster master in gc.glyph_masters) {+ os = create_file (@"selected_$(selected_file_name)_$(master.get_id ()).bfp", "glyphs", dir_name);+ bf.write_root_tag (os);+ bf.write_glyph_collection_start (gc, master, os);+ bf.write_selected ((!) master, os);+ bf.write_glyph_collection_end (os);+ bf.write_closing_root_tag (os);+ os.close ();+ }+ + + foreach (GlyphMaster master in gc.glyph_masters) {+ foreach (Glyph g in master.glyphs) {+ try {+ write_glyph (bf, gc, master, g);+ write_glyph_background_image (bf, gc, g);+ } catch (GLib.Error e) {+ warning (e.message);+ } } } } catch (GLib.Error e) {@@ -243,15 +249,15 @@ public class BirdFontPart : GLib.Object{ } } - string get_first_number_in_unicode (Glyph g) throws GLib.Error {+ static string get_first_number_in_unicode (Glyph g) { string s = Font.to_hex (g.unichar_code); s = s.replace ("U+", ""); return s; } - string get_glyph_base_file_name (Glyph g) throws GLib.Error {+ public static string get_glyph_base_file_name (Glyph g, GlyphMaster master) { string s = get_first_number_in_unicode (g);- s = @"U+$(s)_$(g.version_id)";+ s = @"U+$(s)_$(g.version_id)_$(master.get_id ())"; return s; } @@ -265,17 +271,17 @@ public class BirdFontPart : GLib.Object{ return (!) d.get_char ().to_string (); } - void write_glyph (BirdFontFile bf, GlyphCollection gc, Glyph g) throws GLib.Error {+ void write_glyph (BirdFontFile bf, GlyphCollection gc, GlyphMaster master, Glyph g) throws GLib.Error { string file_name; string dir_name; DataOutputStream os; - file_name = get_glyph_base_file_name (g);+ file_name = get_glyph_base_file_name (g, master); dir_name = get_subdir_name (file_name); os = create_file (@"$(file_name).bfp", "glyphs", dir_name); bf.write_root_tag (os);- bf.write_glyph_collection_start (gc, os);+ bf.write_glyph_collection_start (gc, master, os); bf.write_glyph (g, os); bf.write_glyph_collection_end (os); bf.write_closing_root_tag (os);@@ -361,7 +361,9 @@ public class ClipTool : Tool { glyphs.add (glyph_collection); glyph = new Glyph ((!) c.to_string (), c);- glyph_collection.add_glyph (glyph); + GlyphMaster master = new GlyphMaster ();+ master.add_glyph (glyph);+ glyph_collection.add_master (master); } if (p.has_prefix ("unassigned:")) {@@ -106,7 +106,8 @@ public class Font : GLib.Object { bool bfp = false; BirdFontPart bfp_file; - public Gee.ArrayList<Glyph> deleted_glyphs;+ /** File names of deleted glyphs in bfp directories. */+ public Gee.ArrayList<string> deleted_glyphs; public Ligatures ligature_substitution; @@ -171,7 +172,7 @@ public class Font : GLib.Object { bfp_file = new BirdFontPart (this); - deleted_glyphs = new Gee.ArrayList<Glyph> ();+ deleted_glyphs = new Gee.ArrayList<string> (); ligature_substitution = new Ligatures (this); background_images = new Gee.ArrayList<BackgroundImage> ();@@ -445,7 +446,10 @@ public class Font : GLib.Object { g.remove_empty_paths (); gc.set_unassigned (false);- gc.add_glyph (g);+ + GlyphMaster master = new GlyphMaster ();+ master.add_glyph (g);+ gc.add_master (master); return gc; }@@ -461,7 +465,10 @@ public class Font : GLib.Object { gc = new GlyphCollection ('\0', "null"); n = new Glyph ("null", '\0'); - gc.add_glyph (n);+ GlyphMaster master = new GlyphMaster ();+ master.add_glyph (n);+ gc.add_master (master);+ gc.set_unassigned (false); n.left_limit = 0;@@ -490,7 +497,10 @@ public class Font : GLib.Object { n.right_limit = 27; n.remove_empty_paths (); - gc.add_glyph (n);+ GlyphMaster master = new GlyphMaster ();+ master.add_glyph (n);+ gc.add_master (master);+ gc.set_unassigned (false); return gc; @@ -513,7 +523,10 @@ public class Font : GLib.Object { i = new Path (); gc.set_unassigned (true);- gc.add_glyph (g);+ + GlyphMaster master = new GlyphMaster ();+ master.add_glyph (g);+ gc.add_master (master); g.left_limit = -20; g.right_limit = 33;@@ -595,10 +608,18 @@ public class Font : GLib.Object { a.remove (glyph); } - foreach (Glyph g in glyph.glyphs) {- deleted_glyphs.add (g);+ foreach (GlyphMaster master in glyph.glyph_masters) {+ foreach (Glyph g in master.glyphs) {+ add_deleted_glyph (g, master);+ } } }+ + public void add_deleted_glyph (Glyph g, GlyphMaster master) {+ string file_name;+ file_name = BirdFontPart.get_glyph_base_file_name (g, master) + ".bfp";+ deleted_glyphs.add (file_name); + } // FIXME: the order of ligature substitutions public GlyphCollection? get_ligature (uint indice) {@@ -21,52 +21,85 @@ public class GlyphCollection : GLib.Object { unichar unicode_character; string name; bool unassigned;- Gee.ArrayList<GlyphMaster> glyph_masters;-+ public Gee.ArrayList<GlyphMaster> glyph_masters;+ + // FIXME: move this somewhere+ static int current_master = 0;+ public GlyphCollection (unichar unicode_character, string name) { this.unicode_character = unicode_character; this.name = name; glyph_masters = new Gee.ArrayList<GlyphMaster> ();- unassigned = false+ unassigned = false; } public GlyphCollection.with_glyph (unichar unicode_character, string name) { Glyph g;+ GlyphMaster master; glyph_masters = new Gee.ArrayList<GlyphMaster> ();- unassigned = false+ master = new GlyphMaster ();+ glyph_masters.add (master);+ + unassigned = false; this.unicode_character = unicode_character; this.name = name; g = new Glyph (name, unicode_character);- glyphs.add (g);- set_selected (g);+ master.glyphs.add (g);+ master.set_selected (g);+ }++ public bool has_masters () {+ return glyph_masters.size > 0; } - public void remove (int index) {- return_if_fail (0 <= index < glyphs.size);+ /** This method returns the current master, it has global state. */+ public GlyphMaster get_current_master () {+ int i = current_master; - if (selected >= index) {- selected--;+ if (i >= glyph_masters.size) {+ warning("No master is set for glyph.");+ i = glyph_masters.size - 1; } - glyphs.remove_at (index);+ return_val_if_fail (0 <= i < glyph_masters.size, new GlyphMaster ());+ + return glyph_masters.get (i);+ }++ public bool has_master (string id) {+ foreach (GlyphMaster m in glyph_masters) {+ if (m.get_id () == id) {+ return true;+ }+ }+ + return false; }- - public void set_selected (Glyph g) {- int i = 0; - foreach (Glyph gl in glyphs) {- if (gl == g) {- selected = i;- return;+ public GlyphMaster get_master (string id) {+ foreach (GlyphMaster m in glyph_masters) {+ if (m.get_id () == id) {+ return m; }- i++; } - selected = 0;- warning ("Glyph is not a part of the collection.");+ warning ("Master not found for id $(id).");+ return new GlyphMaster ();+ }+ + public bool is_multimaster() {+ return glyph_masters.size > 1;+ }+ + public void remove (int index) {+ get_current_master ().remove (index);+ }+ + public void set_selected (Glyph g) {+ get_current_master ().set_selected (g); } public void set_unassigned (bool a) {@@ -77,30 +110,35 @@ public class GlyphCollection : GLib.Object { return unassigned; } - public void add_glyph (Glyph g) {- glyphs.add (g);+ public void add_master (GlyphMaster master) {+ glyph_masters.add (master); } public Glyph get_current () {- if (likely (0 <= selected < glyphs.size)) {- return glyphs.get (selected);- }+ Glyph? g = get_current_master ().get_current (); - warning (@"No glyph selected for $(name): $selected glyphs.size: $(glyphs.size)");+ if (likely (g != null)) {+ return (!) g;+ } + warning (@"No glyph selected for $(name)"); return new Glyph ("", '\0'); } + public Glyph get_interpolated (double weight) {+ return get_current ();+ }+ public void insert_glyph (Glyph g, bool selected_glyph) {- glyphs.add (g);- - if (selected_glyph) {- selected = glyphs.size - 1;- }+ get_current_master ().insert_glyph (g, selected_glyph); } public uint length () {- return glyphs.size;+ if (!has_masters ()) {+ return 0;+ }+ + return get_current_master ().glyphs.size; } public string get_unicode () {@@ -124,18 +162,7 @@ public class GlyphCollection : GLib.Object { public void set_name (string n) { name = n; }- - public void set_selected_version (int version_id) {- int i = 0;- foreach (Glyph g in glyphs) {- if (g.version_id == version_id) {- selected = i;- break;- }- i++;- }- }- + /** Create a copy of this list. This method will copy the list data but * keep pointers to the original glyphs. * @return a new list with copies of pointers to the glyphs@@ -143,11 +170,10 @@ public class GlyphCollection : GLib.Object { public GlyphCollection copy () { GlyphCollection n = new GlyphCollection (unicode_character, name); - foreach (Glyph g in glyphs) {- n.insert_glyph (g, false);+ foreach (GlyphMaster g in glyph_masters) {+ n.glyph_masters.add (g.copy ()); } - n.selected = selected; n.unassigned = unassigned; return n;@@ -156,19 +182,30 @@ public class GlyphCollection : GLib.Object { public GlyphCollection copy_deep () { GlyphCollection n = new GlyphCollection (unicode_character, name); - foreach (Glyph g in glyphs) {- n.insert_glyph (g.copy (), false);+ foreach (GlyphMaster g in glyph_masters) {+ n.glyph_masters.add (g.copy_deep ()); } - n.selected = selected; n.unassigned = unassigned; return n; } public int get_last_id () {- return_val_if_fail (glyphs.size > 0, 0);- return glyphs.get (glyphs.size - 1).version_id;+ return get_current_master ().get_last_id ();+ }++ /** @return all versions of all masters */+ public Gee.ArrayList<Glyph> get_all_glyph_masters () {+ Gee.ArrayList<Glyph> glyphs = new Gee.ArrayList<Glyph> ();+ + foreach (GlyphMaster master in glyph_masters) {+ foreach (Glyph g in master.glyphs) {+ glyphs.add (g);+ }+ }+ + return glyphs; } } @@ -183,8 +183,7 @@ public class MainWindow : GLib.Object { GlyphCollection gc; warning ("No default glyph have been set yet.\n"); - gc = new GlyphCollection ('\0', ""); - gc.add_glyph (new Glyph ("", '\0')); + gc = new GlyphCollection.with_glyph ('\0', ""); return gc; } @@ -164,9 +164,10 @@ public class OverView : FontDisplay { TabBar tabs = MainWindow.get_tab_bar (); bool selected; Glyph glyph;- GlyphCollection glyph_collection = MainWindow.get_current_glyph_collection ();+ GlyphCollection glyph_collection; GlyphCanvas canvas;- + + glyph_collection = MainWindow.get_current_glyph_collection (); name.append_unichar (character); selected = tabs.select_char (name.str); @@ -221,7 +222,8 @@ public class OverView : FontDisplay { glyph_collection = new GlyphCollection (character, name.str); if (!empty) {- glyph = new Glyph (name.str, (!unassigned) ? character : '\0');+ glyph = new Glyph (name.str, !unassigned ? character : '\0');+ glyph_collection.add_master (new GlyphMaster ()); glyph_collection.insert_glyph (glyph, true); } @@ -211,7 +211,7 @@ public class OverViewItem : GLib.Object { if (gl != null) { font = BirdFont.get_current_font ();- g = ((!) gl).get_current ();+ g = ((!) gl).get_interpolated (OverviewTools.current_master_size); c.save (); g.boundaries (out x1, out y1, out x2, out y2);@@ -32,12 +32,15 @@ public class OverviewTools : ToolCollection { public static SpinButton skew; public static SpinButton resize; + public static double current_master_size;+ public OverviewTools () { Expander font_name = new Expander (); Expander character_sets = new Expander (t_("Character Sets")); Expander zoom_expander = new Expander (t_("Zoom")); Expander transform_expander = new Expander (t_("Transform")); Expander glyph_expander = new Expander (t_("Glyph"));+ Expander multi_master = new Expander (t_("Multi-Master")); expanders = new Gee.ArrayList<Expander> (); custom_character_sets = new Gee.ArrayList<LabelTool> ();@@ -148,11 +151,30 @@ public class OverviewTools : ToolCollection { }); glyph_expander.add_tool (curve_orientation); + SpinButton master_size;+ current_master_size = 1+ master_size = new SpinButton ("master_size", t_("Master Size")); /// master refers to a master in a multi-master font+ master_size.set_big_number (false);+ master_size.set_int_value ("1.000");+ master_size.set_int_step (1);+ master_size.set_min (0.001);+ master_size.set_max (9);+ master_size.show_icon (true);+ master_size.set_persistent (false);+ master_size.new_value_action.connect ((self) => {+ current_master_size = self.get_value ();+ });+ multi_master.add_tool (master_size);+ expanders.add (font_name); expanders.add (zoom_expander); expanders.add (character_sets); expanders.add (transform_expander); expanders.add (glyph_expander);+ + if (BirdFont.has_argument ("--test")) {+ expanders.add (multi_master);+ } } void fix_curve_orientation () {@@ -70,8 +70,10 @@ public class VersionList : GLib.Object { glyphs = new Gee.ArrayList<Glyph> (); - foreach (Glyph g in gc.glyphs) {- add_glyph (g, false);+ if (gc.has_masters ()) {+ foreach (Glyph g in gc.get_current_master ().glyphs) {+ add_glyph (g, false);+ } } if (gc.length () > 0) {@@ -96,8 +98,11 @@ public class VersionList : GLib.Object { } return_if_fail (0 <= index < glyphs.size);++ Glyph g = glyph_collection.get_current ();+ GlyphMaster m = glyph_collection.get_current_master ();+ font.add_deleted_glyph (g, m); - font.deleted_glyphs.add (glyph_collection.get_current ()); over_view.store_undo_state (glyph_collection.copy ()); current_version = get_current_version_index ();