.
1 /*
2 Copyright (C) 2015 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
17 namespace BirdFont {
18
19 /** A table for managing feature tags in Open Type tables. */
20 public class OtfFeatureTable : Table {
21 Gee.ArrayList<Row> rows = new Gee.ArrayList<Row> ();
22
23 static const int NONE = 0;
24 static const int OTF_FEATURE = 1;
25 static const int SOURCE_GLYPH = 2; // the glyph to replace
26 static const int REPLACEMENT_GLYPH = 3;
27 static const int ALTERNATE_ENTRY = 4;
28
29 GlyphCollection glyph_collection;
30 GlyphCollection? replacement_glyph = null;
31 string alternate_name = "";
32 TextListener listener;
33
34 Gee.ArrayList<AlternateItem> undo_items;
35 // FIXME: implement redo
36
37 public OtfFeatureTable (GlyphCollection gc) {
38 glyph_collection = gc;
39 undo_items = new Gee.ArrayList<AlternateItem> ();
40 }
41
42 public override Gee.ArrayList<Row> get_rows () {
43 return rows;
44 }
45
46 public override void selected_row (Row row, int column, bool delete_button) {
47 int row_index = row.get_index ();
48 GLib.Object o;
49 String s;
50 AlternateItem a;
51
52 if (row_index == SOURCE_GLYPH) {
53 GlyphSelection gs = new GlyphSelection ();
54
55 gs.selected_glyph.connect ((gc) => {
56 glyph_collection = gc;
57 MainWindow.get_tab_bar ().select_tab_name (get_name ());
58 });
59
60 GlyphCanvas.set_display (gs);
61 } else if (row_index == REPLACEMENT_GLYPH) {
62 GlyphSelection gs = new GlyphSelection ();
63
64 gs.selected_glyph.connect ((gc) => {
65 replacement_glyph = gc;
66 MainWindow.get_tab_bar ().select_tab_name (get_name ());
67 });
68
69 GlyphCanvas.set_display (gs);
70 } else if (row_index == OTF_FEATURE) {
71 return_if_fail (row.has_row_data ());
72 o = (!) row.get_row_data ();
73 return_if_fail (o is String);
74 s = (String) o;
75 add_new_alternate (s.data);
76 } else if (row_index == ALTERNATE_ENTRY) {
77 if (delete_button) {
78 return_if_fail (row.has_row_data ());
79 o = (!) row.get_row_data ();
80 return_if_fail (o is AlternateItem);
81 a = (AlternateItem) o;
82
83 a.delete_item_from_list ();
84 Font f = BirdFont.get_current_font ();
85 f.alternates.remove_empty_sets ();
86
87 undo_items.add (a);
88
89 update_rows ();
90 GlyphCanvas.redraw ();
91 }
92 }
93 }
94
95 public override void update_rows () {
96 Row row;
97 Font font;
98
99 font = BirdFont.get_current_font ();
100 rows.clear ();
101
102 row = new Row.headline (t_("Glyph Substitutions"));
103 rows.add (row);
104
105 row = new Row.columns_1 (t_("Glyph") + ": " + glyph_collection.get_name (), SOURCE_GLYPH, false);
106 rows.add (row);
107
108 string replacement = t_("New glyph");
109
110 if (replacement_glyph != null) {
111 GlyphCollection gc = (!) replacement_glyph;
112 replacement = gc.get_name ();
113 }
114
115 row = new Row.columns_1 (t_("Replacement") + ": " + replacement, REPLACEMENT_GLYPH, false);
116 rows.add (row);
117
118 // FIXME: reuse parts of this for fractions etc.
119
120 row = new Row.headline (t_("Tag"));
121 rows.add (row);
122
123 row = new Row.columns_1 (OtfLabel.get_string ("salt"), OTF_FEATURE, false);
124 row.set_row_data (new String ("salt"));
125 rows.add (row);
126
127 row = new Row.columns_1 (OtfLabel.get_string ("smcp"), OTF_FEATURE, false);
128 row.set_row_data (new String ("smcp"));
129 rows.add (row);
130
131 row = new Row.columns_1 (OtfLabel.get_string ("c2sc"), OTF_FEATURE, false);
132 row.set_row_data (new String ("c2sc"));
133 rows.add (row);
134
135 row = new Row.columns_1 (OtfLabel.get_string ("swsh"), OTF_FEATURE, false);
136 row.set_row_data (new String ("swsh"));
137 rows.add (row);
138
139 Gee.ArrayList<string> tags = font.alternates.get_all_tags ();
140 foreach (string tag in tags) {
141 row = new Row.headline (OtfLabel.get_string (tag));
142 rows.add (row);
143 add_alternate_items (tag);
144 }
145
146 GlyphCanvas.redraw ();
147 }
148
149 void add_alternate_items (string tag) {
150 Font font = BirdFont.get_current_font ();
151 foreach (Alternate alt in font.alternates.get_alt (tag)) {
152 add_alternate_rows (alt);
153 }
154 }
155
156 void add_alternate_rows (Alternate alt) {
157 Row row;
158
159 foreach (string a in alt.alternates) {
160 row = new Row.columns_2 (alt.glyph_name, a, ALTERNATE_ENTRY, true);
161 row.set_row_data (new AlternateItem (alt, a));
162 rows.add (row);
163 }
164 }
165
166 public override string get_label () {
167 return t_("Glyph Substitutions");
168 }
169
170 public override string get_name () {
171 return "Glyph Substitutions";
172 }
173
174 public override void draw (WidgetAllocation allocation, Context cr) {
175 base.draw (allocation, cr);
176 }
177
178 public void add_new_alternate (string tag) {
179 GlyphCollection gc = glyph_collection;
180
181 listener = new TextListener (t_("Glyph name"), "", t_("Add"));
182
183 listener.signal_text_input.connect ((text) => {
184 alternate_name = text;
185 });
186
187 listener.signal_submit.connect (() => {
188 GlyphCollection alt;
189 Font font;
190 OverView overview = MainWindow.get_overview ();
191
192 font = BirdFont.get_current_font ();
193
194 if (alternate_name == "" || gc.is_unassigned ()) {
195 MainWindow.tabs.close_display (this);
196 return;
197 }
198
199 if (font.glyph_name.has_key (alternate_name)) {
200 MainWindow.show_message (t_("All glyphs must have unique names."));
201 } else {
202 alt = new GlyphCollection.with_glyph ('\0', alternate_name);
203 alt.set_unassigned (true);
204 font.add_new_alternate (gc, alt, tag);
205 MainWindow.tabs.close_display (this);
206 MainWindow.get_overview ().update_item_list ();
207 overview.open_glyph_signal (alt);
208 }
209 });
210
211 if (replacement_glyph != null) {
212 GlyphCollection replacement = (!) replacement_glyph;
213 Font f = BirdFont.get_current_font ();
214 f.add_alternate (gc.get_name (), replacement.get_name (), tag);
215 MainWindow.tabs.close_display (this);
216 } else {
217 TabContent.show_text_input (listener);
218 }
219 }
220
221 public override void undo () {
222 AlternateItem item;
223 Font font;
224
225 font = BirdFont.get_current_font ();
226
227 if (undo_items.size > 0) {
228 item = undo_items.get (undo_items.size - 1);
229 undo_items.remove_at (undo_items.size - 1);
230
231 font.add_alternate (item.alternate_list.glyph_name,
232 item.alternate,
233 item.alternate_list.tag);
234
235 update_rows ();
236 GlyphCanvas.redraw ();
237 }
238 }
239 }
240
241 }
242