Commit 9a7f952
Add contextual ligatures to the GUI and fix directory privileges
Changed files (11)
modifiedlibbirdfont/BackgroundImage.valamodifiedlibbirdfont/BirdFont.valamodifiedlibbirdfont/BirdFontFile.valamodifiedlibbirdfont/BirdFontPart.valamodifiedlibbirdfont/CutBackgroundTool.valamodifiedlibbirdfont/LigatureList.valamodifiedlibbirdfont/Ligatures.valaaddedlibbirdfont/OpenFontFormat/ContextualLigature.valamodifiedlibbirdfont/OpenFontFormat/GsubTable.valamodifiedlibbirdfont/OpenFontFormat/Ligature.valamodifiedlibbirdfont/Row.vala
Diff
@@ -225,17 +225,17 @@ public class BackgroundImage { dir = BirdFont.get_settings_directory (); if (!dir.query_exists ()) {- DirUtils.create ((!) dir.get_path (), 0xFFFFFF);+ DirUtils.create ((!) dir.get_path (), 0755); } dir = font.get_backgrounds_folder (); if (!dir.query_exists ()) {- DirUtils.create ((!) dir.get_path (), 0xFFFFFF);+ DirUtils.create ((!) dir.get_path (), 0755); } dir = font.get_backgrounds_folder ().get_child ("parts"); if (!dir.query_exists ()) {- DirUtils.create ((!) dir.get_path (), 0xFFFFFF);+ DirUtils.create ((!) dir.get_path (), 0755); } } @@ -535,7 +535,7 @@ public class BirdFont { File backup = settings.get_child ("preview"); if (!backup.query_exists ()) {- DirUtils.create ((!) backup.get_path (), 0xFFFFFF);+ DirUtils.create ((!) backup.get_path (), 0755); } return backup;@@ -545,7 +545,7 @@ public class BirdFont { File thumbnails = get_settings_directory ().get_child ("thumbnails"); if (!thumbnails.query_exists ()) {- DirUtils.create ((!) thumbnails.get_path (), 0xFFFFFF);+ DirUtils.create ((!) thumbnails.get_path (), 0755); } return thumbnails;@@ -562,12 +562,12 @@ public class BirdFont { if (!home.query_exists ()) { printd ("Create settings directory.");- DirUtils.create ((!) home.get_path (), 0xFFFFFF);+ DirUtils.create ((!) home.get_path (),0755); } #else home_path = (settings_directory != null) - ? (!) settings_directory : Environment.get_home_dir ();- + ? (!) settings_directory : Environment.get_user_config_dir ();+ if (is_null (home_path)) { warning ("No home directory set."); home_path = ".";@@ -575,10 +575,10 @@ public class BirdFont { home = File.new_for_path (home_path); #endif- settings = home.get_child (".birdfont");+ settings = home.get_child ("birdfont"); if (!settings.query_exists ()) {- DirUtils.create ((!) settings.get_path (), 0xFFFFFF);+ DirUtils.create ((!) settings.get_path (), 0755); } return settings;@@ -589,7 +589,7 @@ public class BirdFont { File backup = settings.get_child ("backup"); if (!backup.query_exists ()) {- DirUtils.create ((!) backup.get_path (), 0xFFFFFF);+ DirUtils.create ((!) backup.get_path (), 0755); } return backup;@@ -793,13 +793,13 @@ class BirdFontFile : GLib.Object { } if (!font.get_backgrounds_folder ().query_exists ()) {- DirUtils.create ((!) font.get_backgrounds_folder ().get_path (), 0xFFFFFF);+ DirUtils.create ((!) font.get_backgrounds_folder ().get_path (), 0755); } img_dir = font.get_backgrounds_folder ().get_child ("parts"); if (!img_dir.query_exists ()) {- DirUtils.create ((!) img_dir.get_path (), 0xFFFFFF);+ DirUtils.create ((!) img_dir.get_path (), 0755); } img_file = img_dir.get_child (@"$(file).png");@@ -1359,16 +1359,16 @@ class BirdFontFile : GLib.Object { public void write_ligatures (DataOutputStream os) { Ligatures ligatures = font.get_ligatures ();- - try {- ligatures.get_ligatures ((subst, liga) => {++ ligatures.get_ligatures ((subst, liga) => {+ try { string lig = serialize_attribute (liga); string sequence = serialize_attribute (subst); os.put_string (@"<ligature sequence=\"$(sequence)\" replacement=\"$(lig)\"/>\n");- });- } catch (GLib.IOError e) {- warning (e.message);- }+ } catch (GLib.IOError e) {+ warning (e.message);+ }+ }); } public void parse_ligature (Tag t) {@@ -386,11 +386,11 @@ public class BirdFontPart : GLib.Object{ } if (!dir.query_exists ()) {- DirUtils.create ((!) dir.get_path (), 0xFFFFFF);+ DirUtils.create ((!) dir.get_path (), 0755); } root_directory = (!) bfp_dir.get_path ();- DirUtils.create (root_directory, 0xFFFFFF);+ DirUtils.create (root_directory, 0755); } private void find_all_parts (string bfp_file) throws GLib.Error { @@ -473,7 +473,7 @@ public class BirdFontPart : GLib.Object{ dir = dir.get_child (subdir); if (!dir.query_exists ()) {- DirUtils.create ((!) dir.get_path (), 0xFFFFFF);+ DirUtils.create ((!) dir.get_path (), 0755); } else { info = dir.query_info (FILE_ATTRIBUTES, FileQueryInfoFlags.NONE); if (info.get_file_type () != FileType.DIRECTORY) {@@ -220,7 +220,7 @@ class CutBackgroundTool : Tool { img_dir = f.get_backgrounds_folder ().get_child ("parts"); if (!img_dir.query_exists ()) {- if (DirUtils.create_with_parents ((!) img_dir.get_path (), 0xFFFFFF) != 0) {+ if (DirUtils.create_with_parents ((!) img_dir.get_path (), 755) != 0) { warning (@"Can not create directory $((!) img_dir.get_path ())"); } }@@ -29,6 +29,12 @@ public class LigatureList : Table { return rows; } + void add_contextual_ligature (string backtrack, string input, string lookahead) {+ Font font = BirdFont.get_current_font ();+ Ligatures ligatures = font.get_ligatures ();+ ligatures.add_contextual_ligature (backtrack, input, lookahead);+ }+ void add_ligature (string subst, string liga) { Font font = BirdFont.get_current_font (); Ligatures ligatures = font.get_ligatures ();@@ -38,27 +44,59 @@ public class LigatureList : Table { public override void selected_row (Row row, int column, bool delete_button) { Font font = BirdFont.get_current_font (); Ligatures ligatures = font.get_ligatures ();+ int i;+ ContextualLigature cl; - if (row.get_index () == NEW_LIGATURE) {+ if (row.get_index () == NEW_LIGATURE && column == 0) { add_ligature (t_("character sequence"), t_("ligature")); MainWindow.native_window.hide_text_input ();- } else if (ligatures.count () != 0) {+ } else if (row.get_index () == NEW_LIGATURE && column == 1) {+ add_contextual_ligature (t_("beginning"), t_("middle"), t_("end"));+ MainWindow.native_window.hide_text_input ();+ } else if (row.has_row_data ()) {+ i = row.get_index ();+ cl = (ContextualLigature) ((!) row.get_row_data ());+ if (delete_button) {- return_if_fail (0 <= row.get_index () < ligatures.count ());- ligatures.remove_at (row.get_index ());- MainWindow.native_window.hide_text_input ();+ cl.remove_ligature_at (i); } else if (column == 0) {- if (!(0 <= row.get_index () < ligatures.count ())) {- warning (@"Index: $(row.get_index ()) ligatures.count (): $(ligatures.count ())");- return;- }- ligatures.set_ligature (row.get_index ()); + cl.set_ligature (i); } else if (column == 2) {- return_if_fail (0 <= row.get_index () < ligatures.count ());- ligatures.set_substitution (row.get_index ());+ cl.set_substitution (i);+ }+ } else if (row.get_index () < ligatures.count ()) {+ if (ligatures.count () != 0) {+ if (delete_button) {+ return_if_fail (0 <= row.get_index () < ligatures.count ());+ ligatures.remove_at (row.get_index ());+ MainWindow.native_window.hide_text_input ();+ } else if (column == 0) {+ return_if_fail (0 <= row.get_index () < ligatures.count ());+ ligatures.set_ligature (row.get_index ());+ } else if (column == 2) {+ return_if_fail (0 <= row.get_index () < ligatures.count ());+ ligatures.set_substitution (row.get_index ());+ }+ }+ } else {+ i = row.get_index () - ligatures.count ();+ if (i < ligatures.count_contextual_ligatures ()) {+ return_if_fail (0 <= i < ligatures.count_contextual_ligatures ());+ if (delete_button) {+ ligatures.remove_contextual_ligatures_at (i);+ MainWindow.native_window.hide_text_input ();+ } else if (column == 0) {+ ligatures.set_beginning (i);+ } else if (column == 1) {+ ligatures.set_middle (i);+ } else if (column == 2) {+ ligatures.set_end (i);+ } else if (column == 3) {+ ligatures.add_substitution_at (i);+ } } }-+ update_rows (); update_scrollbar (); font.touch ();@@ -71,16 +109,34 @@ public class LigatureList : Table { Row row; rows.clear ();- row = new Row (t_("New Ligature"), NEW_LIGATURE, false);+ row = new Row.columns_2 (t_("New Ligature"), t_("New Contextual Substitution"), NEW_LIGATURE, false); rows.add (row); i = 0; ligatures.get_ligatures ((subst, liga) => {- row = new Row.columns_3 (@"$liga", "", @"$subst", i);+ row = new Row.columns_3 (liga, "", subst, i); rows.add (row); i++; });- ++ ligatures.get_contextual_ligatures ((liga) => {+ int j;+ + row = new Row.columns_4 (liga.backtrack, liga.input, liga.lookahead,+ t_("Add Ligature"), i);+ rows.add (row);+ + j = 0;+ foreach (Ligature l in liga.ligatures) {+ row = new Row.columns_3 (l.ligature, "", l.substitution, j);+ row.set_row_data (liga);+ rows.add (row);+ j++;+ }+ + i++;+ });+ GlyphCanvas.redraw (); } @@ -20,10 +20,13 @@ namespace BirdFont { public class Ligatures : GLib.Object { Gee.ArrayList<Ligature> ligatures = new Gee.ArrayList<Ligature> ();+ Gee.ArrayList<ContextualLigature> contextual_ligatures = new Gee.ArrayList<ContextualLigature> (); public delegate void LigatureIterator (string substitution, string ligature); public delegate void SingleLigatureIterator (GlyphSequence substitution, GlyphCollection ligature); + public delegate void ContextualLigatureIterator (ContextualLigature lig);+ public Ligatures () { } @@ -33,6 +36,12 @@ public class Ligatures : GLib.Object { } } + public void get_contextual_ligatures (ContextualLigatureIterator iter) {+ foreach (ContextualLigature l in contextual_ligatures) {+ iter (l);+ } + }+ public void get_single_substitution_ligatures (SingleLigatureIterator iter) { get_ligatures ((substitution, ligature) => { Font font = BirdFont.get_current_font ();@@ -67,23 +76,38 @@ public class Ligatures : GLib.Object { public int count () { return ligatures.size; }++ public int count_contextual_ligatures () {+ return contextual_ligatures.size;+ } public void remove_at (int i) { return_if_fail (0 <= i < ligatures.size); ligatures.remove_at (i); }++ public void remove_contextual_ligatures_at (int i) {+ return_if_fail (0 <= i < contextual_ligatures.size);+ contextual_ligatures.remove_at (i);+ } - public void set_ligature (int index) {- Ligature lig;+ /** Add ligaure for a chained substitution. */+ public void add_substitution_at (int index) {+ return_if_fail (0 <= index < contextual_ligatures.size);+ contextual_ligatures.get (index).add_ligature ();+ }+ + public void set_beginning (int index) {+ ContextualLigature lig; TextListener listener; - return_if_fail (0 <= index < ligatures.size);- - lig = ligatures.get (index);- listener = new TextListener (t_("Ligature"), "", t_("Set"));+ return_if_fail (0 <= index < contextual_ligatures.size);++ lig = contextual_ligatures.get (index);+ listener = new TextListener (t_("Beginning"), lig.backtrack, t_("Set")); listener.signal_text_input.connect ((text) => {- lig.ligature = text;+ lig.backtrack = text; }); listener.signal_submit.connect (() => {@@ -91,21 +115,20 @@ public class Ligatures : GLib.Object { MainWindow.get_ligature_display ().update_rows (); }); - MainWindow.native_window.set_text_listener (listener);+ MainWindow.native_window.set_text_listener (listener); } - public void set_substitution (int index) {- Ligature lig;+ public void set_middle (int index) {+ ContextualLigature lig; TextListener listener; - return_if_fail (0 <= index < ligatures.size);- - lig = ligatures.get (index);- listener = new TextListener (t_("Text"), "", t_("Set"));+ return_if_fail (0 <= index < contextual_ligatures.size);++ lig = contextual_ligatures.get (index);+ listener = new TextListener (t_("Middle"), lig.input, t_("Set")); listener.signal_text_input.connect ((text) => {- lig.substitution = text;- sort_ligatures ();+ lig.input = text; }); listener.signal_submit.connect (() => {@@ -113,19 +136,64 @@ public class Ligatures : GLib.Object { MainWindow.get_ligature_display ().update_rows (); }); - MainWindow.native_window.set_text_listener (listener);- } + MainWindow.native_window.set_text_listener (listener); + }++ public void set_end (int index) {+ ContextualLigature lig;+ TextListener listener;+ + return_if_fail (0 <= index < contextual_ligatures.size); + lig = contextual_ligatures.get (index);+ listener = new TextListener (t_("End"), lig.lookahead, t_("Set"));+ + listener.signal_text_input.connect ((text) => {+ lig.lookahead = text;+ });+ + listener.signal_submit.connect (() => {+ MainWindow.native_window.hide_text_input ();+ MainWindow.get_ligature_display ().update_rows ();+ });+ + MainWindow.native_window.set_text_listener (listener); + }+ + public void set_ligature (int index) {+ Ligature lig;+ TextListener listener;+ + return_if_fail (0 <= index < ligatures.size);+ + lig = ligatures.get (index);+ lig.set_ligature ();+ }+ + public void set_substitution (int index) {+ Ligature lig;+ TextListener listener;+ + return_if_fail (0 <= index < ligatures.size);+ + lig = ligatures.get (index);+ lig.set_substitution ();+ }+ public void add_ligature (string subst, string liga) { ligatures.insert (0, new Ligature (liga, subst)); sort_ligatures (); }++ public void add_contextual_ligature (string backtrack, string input, string lookahead) {+ ContextualLigature l = new ContextualLigature (backtrack, input, lookahead);+ contextual_ligatures.insert (0, l);+ sort_ligatures ();+ } - void sort_ligatures () {- print (@"\n");+ public void sort_ligatures () { ligatures.sort ((a, b) => { Ligature first, next;- bool r; int chars_first, chars_next; first = (Ligature) a;@@ -135,7 +203,29 @@ public class Ligatures : GLib.Object { chars_next = next.substitution.split (" ").length; return chars_next - chars_first;- }); + });+ + contextual_ligatures.sort ((a, b) => {+ ContextualLigature first, next;+ int chars_first, chars_next;+ + first = (ContextualLigature) a;+ next = (ContextualLigature) b;+ + chars_first = first.backtrack.split (" ").length;+ chars_first += first.input.split (" ").length;+ chars_first += first.lookahead.split (" ").length;+ + chars_next = next.backtrack.split (" ").length;+ chars_next += next.input.split (" ").length;+ chars_next += next.lookahead.split (" ").length; + + return chars_next - chars_first;+ });+ + foreach (ContextualLigature c in contextual_ligatures) {+ c.sort ();+ } } } new file mode 100644@@ -0,0 +1,69 @@+/*+ Copyright (C) 2014 Johan Mattsson++ This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details.+*/++namespace BirdFont {++public class ContextualLigature : GLib.Object {++ public string backtrack = "";+ public string input = "";+ public string lookahead = "";++ public Gee.ArrayList<Ligature> ligatures;++ public ContextualLigature (string backtrack, string input, string lookahead) {+ this.backtrack = backtrack;+ this.input = input;+ this.lookahead = lookahead;+ + ligatures = new Gee.ArrayList<Ligature> ();+ }++ public void remove_ligature_at (int i) {+ return_if_fail (0 <= i < ligatures.size);+ ligatures.remove_at (i);+ }++ public void add_ligature () {+ Ligature l = new Ligature (t_("ligature"), t_("glyph sequence"));+ ligatures.add (l); + }+ + public void set_ligature (int i) {+ return_if_fail (0 <= i < ligatures.size);+ ligatures.get (i).set_ligature ();+ }++ public void set_substitution (int i) {+ return_if_fail (0 <= i < ligatures.size);+ ligatures.get (i).set_substitution (this);+ }+ + public void sort () {+ ligatures.sort ((a, b) => {+ Ligature first, next;+ int chars_first, chars_next;+ + first = (Ligature) a;+ next = (Ligature) b;+ + chars_first = first.substitution.split (" ").length;+ chars_next = next.substitution.split (" ").length;+ + return chars_next - chars_first;+ }); + }+}++}@@ -24,7 +24,7 @@ public class GsubTable : OtfTable { id = "GSUB"; } - public override void parse (FontData dis) throws Error {+ public override void parse (FontData dis) throws GLib.Error { } public void process () throws GLib.Error {@@ -110,7 +110,7 @@ public class GsubTable : OtfTable { this.font_data = fd; } - FontData get_ligature_subtable (LigatureSetList liga_list) {+ FontData get_ligature_subtable (LigatureSetList liga_list) throws GLib.Error { FontData set_data; Gee.ArrayList<LigatureSet> liga_sets; uint16 ligature_pos;@@ -17,7 +17,7 @@ namespace BirdFont { public class Ligature : GLib.Object { public string ligature = ""; public string substitution = "";- + public Ligature (string ligature, string substitution) { this.ligature = ligature; this.substitution = substitution;@@ -26,6 +26,48 @@ public class Ligature : GLib.Object { public unichar get_first_char () { return substitution.get (0); }+ + public void set_ligature () {+ TextListener listener;+ + listener = new TextListener (t_("Ligature"), ligature, t_("Set"));+ + listener.signal_text_input.connect ((text) => {+ ligature = text;+ });+ + listener.signal_submit.connect (() => {+ MainWindow.native_window.hide_text_input ();+ MainWindow.get_ligature_display ().update_rows ();+ });+ + MainWindow.native_window.set_text_listener (listener);+ }+ + public void set_substitution (ContextualLigature? clig = null) {+ TextListener listener;+ ContextualLigature? cl = clig;+ + listener = new TextListener (t_("Text"), substitution, t_("Set"));+ + listener.signal_text_input.connect ((text) => {+ Font f = BirdFont.get_current_font ();+ Ligatures l = f.get_ligatures ();+ substitution = text;+ l.sort_ligatures ();+ + if (cl != null) {+ ((!) cl).sort ();+ }+ });+ + listener.signal_submit.connect (() => {+ MainWindow.native_window.hide_text_input ();+ MainWindow.get_ligature_display ().update_rows ();+ });+ + MainWindow.native_window.set_text_listener (listener);+ } } }@@ -20,8 +20,8 @@ public class Row : GLib.Object { int index = 0; bool delete_button = true;- Gee.ArrayList<string> columns_labels = new Gee.ArrayList<string> ();+ GLib.Object? row_data = null; public int columns { get {@@ -34,12 +34,59 @@ public class Row : GLib.Object { columns_labels.add (label); this.delete_button = delete_button; }++ public Row.columns_2 (string label0, string label1, int index,+ bool delete_button = true) {+ + columns_labels.add (label0);+ columns_labels.add (label1);+ this.index = index;+ this.delete_button = delete_button;+ }+ + public Row.columns_3 (string label0, string label1, string label2,+ int index, bool delete_button = true) {+ + columns_labels.add (label0);+ columns_labels.add (label1);+ columns_labels.add (label2);+ this.index = index;+ this.delete_button = delete_button;+ }++ public Row.columns_4 (string label0, string label1, string label2, + string label3, int index, bool delete_button = true) {+ + columns_labels.add (label0);+ columns_labels.add (label1);+ columns_labels.add (label2);+ columns_labels.add (label3);+ this.index = index;+ this.delete_button = delete_button;+ } - public Row.columns_3 (string label0, string label1, string label2, int index) {+ public Row.columns_5 (string label0, string label1, string label2,+ string label3, string label4, int index, bool delete_button = true) {+ columns_labels.add (label0); columns_labels.add (label1); columns_labels.add (label2);+ columns_labels.add (label3);+ columns_labels.add (label4); this.index = index;+ this.delete_button = delete_button;+ }++ public bool has_row_data () {+ return row_data != null;+ }++ public GLib.Object? get_row_data () {+ return row_data;+ }++ public void set_row_data (GLib.Object o) {+ row_data = o; } public bool has_delete_button () {