The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

Ligatures.vala in /libbirdfont

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
Circle boundaries heads/master
1 /* 2 Copyright (C) 2014 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 15 using Cairo; 16 using Math; 17 18 namespace BirdFont { 19 20 public class Ligatures : GLib.Object { 21 22 public Gee.ArrayList<Ligature> ligatures = new Gee.ArrayList<Ligature> (); 23 public Gee.ArrayList<ContextualLigature> contextual_ligatures = new Gee.ArrayList<ContextualLigature> (); 24 25 public delegate void LigatureIterator (string substitution, string ligature); 26 public delegate void SingleLigatureIterator (GlyphSequence substitution, GlyphSequence ligature); 27 28 public delegate void ContextualLigatureIterator (ContextualLigature lig); 29 30 unowned Font font; 31 32 public Ligatures (Font font) { 33 this.font = font; 34 35 font.font_deleted.connect (() => { 36 this.font = Font.empty; 37 }); 38 } 39 40 public void get_ligatures (LigatureIterator iter) { 41 foreach (Ligature l in ligatures) { 42 iter (l.substitution, l.ligature); 43 } 44 } 45 46 public void get_contextual_ligatures (ContextualLigatureIterator iter) { 47 foreach (ContextualLigature l in contextual_ligatures) { 48 iter (l); 49 } 50 } 51 52 public void get_single_substitution_ligatures (SingleLigatureIterator iter) { 53 get_ligatures ((substitution, ligature) => { 54 GlyphCollection? gc; 55 GlyphSequence lig; 56 GlyphSequence gs; 57 string[] subst_names = substitution.split (" "); 58 59 lig = new GlyphSequence (); 60 foreach (string n in font.get_names (ligature)) { 61 if (n == "space") { 62 n = " "; 63 } 64 65 gc = font.get_glyph_collection_by_name (n); 66 67 if (gc == null) { 68 return; 69 } 70 71 lig.add (((!) gc).get_current ()); 72 } 73 74 gs = new GlyphSequence (); 75 foreach (string s in subst_names) { 76 if (s == "space") { 77 s = " "; 78 } 79 80 gc = font.get_glyph_collection_by_name (s); 81 82 if (gc == null) { 83 return; 84 } 85 86 gs.glyph.add (((!) gc).get_current ()); 87 } 88 89 iter (gs, lig); 90 }); 91 } 92 93 public int count () { 94 return ligatures.size; 95 } 96 97 public int count_contextual_ligatures () { 98 return contextual_ligatures.size; 99 } 100 101 public void remove_at (int i) { 102 return_if_fail (0 <= i < ligatures.size); 103 ligatures.remove_at (i); 104 } 105 106 public void remove_contextual_ligatures_at (int i) { 107 return_if_fail (0 <= i < contextual_ligatures.size); 108 contextual_ligatures.remove_at (i); 109 } 110 111 public void set_beginning (int index) { 112 ContextualLigature lig; 113 TextListener listener; 114 115 return_if_fail (0 <= index < contextual_ligatures.size); 116 117 lig = contextual_ligatures.get (index); 118 listener = new TextListener (t_("Beginning"), lig.backtrack, t_("Set")); 119 120 listener.signal_text_input.connect ((text) => { 121 lig.backtrack = text; 122 }); 123 124 listener.signal_submit.connect (() => { 125 TabContent.hide_text_input (); 126 MainWindow.get_ligature_display ().update_rows (); 127 sort_ligatures (); 128 GlyphCanvas.redraw (); 129 }); 130 131 TabContent.show_text_input (listener); 132 } 133 134 public void set_middle (int index) { 135 ContextualLigature lig; 136 TextListener listener; 137 138 return_if_fail (0 <= index < contextual_ligatures.size); 139 140 lig = contextual_ligatures.get (index); 141 listener = new TextListener (t_("Middle"), lig.input, t_("Set")); 142 143 listener.signal_text_input.connect ((text) => { 144 lig.input = text; 145 }); 146 147 listener.signal_submit.connect (() => { 148 TabContent.hide_text_input (); 149 MainWindow.get_ligature_display ().update_rows (); 150 sort_ligatures (); 151 GlyphCanvas.redraw (); 152 }); 153 154 TabContent.show_text_input (listener); 155 } 156 157 public void set_end (int index) { 158 ContextualLigature lig; 159 TextListener listener; 160 161 return_if_fail (0 <= index < contextual_ligatures.size); 162 163 lig = contextual_ligatures.get (index); 164 listener = new TextListener (t_("End"), lig.lookahead, t_("Set")); 165 166 listener.signal_text_input.connect ((text) => { 167 lig.lookahead = text; 168 }); 169 170 listener.signal_submit.connect (() => { 171 TabContent.hide_text_input (); 172 MainWindow.get_ligature_display ().update_rows (); 173 sort_ligatures (); 174 GlyphCanvas.redraw (); 175 }); 176 177 TabContent.show_text_input (listener); 178 } 179 180 public void set_ligature (int index) { 181 Ligature lig; 182 183 return_if_fail (0 <= index < ligatures.size); 184 185 lig = ligatures.get (index); 186 lig.set_ligature (); 187 } 188 189 public void set_contextual_ligature (int index) { 190 ContextualLigature lig; 191 TextListener listener; 192 193 return_if_fail (0 <= index < contextual_ligatures.size); 194 195 lig = contextual_ligatures.get (index); 196 listener = new TextListener (t_("Ligature"), lig.ligatures, t_("Set")); 197 198 listener.signal_text_input.connect ((text) => { 199 lig.ligatures = text; 200 }); 201 202 listener.signal_submit.connect (() => { 203 TabContent.hide_text_input (); 204 MainWindow.get_ligature_display ().update_rows (); 205 sort_ligatures (); 206 GlyphCanvas.redraw (); 207 }); 208 209 TabContent.show_text_input (listener); 210 211 } 212 213 public void set_substitution (int index) { 214 Ligature lig; 215 216 return_if_fail (0 <= index < ligatures.size); 217 218 lig = ligatures.get (index); 219 lig.set_substitution (); 220 } 221 222 public void add_ligature (string subst, string liga) { 223 ligatures.insert (0, new Ligature (liga, subst)); 224 sort_ligatures (); 225 } 226 227 public void add_contextual_ligature (string ligature, string backtrack, string input, string lookahead) { 228 ContextualLigature l = new ContextualLigature (font, ligature, backtrack, input, lookahead); 229 contextual_ligatures.insert (0, l); 230 sort_ligatures (); 231 } 232 233 public void sort_ligatures () { 234 ligatures.sort ((a, b) => { 235 Ligature first, next; 236 int chars_first, chars_next; 237 238 first = (Ligature) a; 239 next = (Ligature) b; 240 241 chars_first = first.substitution.split (" ").length; 242 chars_next = next.substitution.split (" ").length; 243 244 return chars_next - chars_first; 245 }); 246 247 contextual_ligatures.sort ((a, b) => { 248 ContextualLigature first, next; 249 int chars_first, chars_next; 250 251 first = (ContextualLigature) a; 252 next = (ContextualLigature) b; 253 254 chars_first = first.backtrack.split (" ").length; 255 chars_first += first.input.split (" ").length; 256 chars_first += first.lookahead.split (" ").length; 257 258 chars_next = next.backtrack.split (" ").length; 259 chars_next += next.input.split (" ").length; 260 chars_next += next.lookahead.split (" ").length; 261 262 return chars_next - chars_first; 263 }); 264 } 265 } 266 267 } 268