.
1 /*
2 Copyright (C) 2013 2014 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 using Math;
17
18 namespace BirdFont {
19
20 public class KerningTools : ToolCollection {
21 public static Gee.ArrayList<Expander> expanders;
22 public static int next_class = 0;
23 public static Expander classes;
24
25 public static double font_size = 1;
26 public static ZoomBar zoom_bar;
27
28 public static Tool previous_kerning_string;
29 public static Tool next_kerning_string;
30
31 public KerningTools () {
32 init ();
33 }
34
35 public static void init () {
36 Expander kerning_tools = new Expander (t_("Kerning Tools"));
37 classes = new Expander ();
38 expanders = new Gee.ArrayList<Expander> ();
39
40 Expander font_name = new Expander ();
41 font_name.add_tool (new FontName ());
42
43 Expander zoom_expander = new Expander (t_("Font Size"));
44
45 zoom_bar = new ZoomBar ();
46 zoom_bar.new_zoom.connect ((z) => {
47 font_size = 3 * z;
48
49 if (font_size < 0.1) {
50 font_size = 0.1;
51 }
52
53 GlyphCanvas.redraw ();
54 });
55 zoom_expander.add_tool (zoom_bar);
56
57 Tool new_kerning_class = new Tool ("kerning_class", t_("Create new kerning class."));
58 new_kerning_class.select_action.connect ((self) => {
59 Font font = BirdFont.get_current_font ();
60 string label = t_("Kerning class");
61 KerningRange kr = new KerningRange (font, @"$label $(++next_class)");
62 classes.add_tool (kr);
63 classes.redraw ();
64 });
65 kerning_tools.add_tool (new_kerning_class);
66
67 Tool text_kerning = new Tool ("kerning_text_input", t_("Use text input to enter kerning values."));
68 text_kerning.select_action.connect ((self) => {
69 KerningDisplay d = MainWindow.get_kerning_display ();
70 d.set_kerning_by_text ();
71 });
72 kerning_tools.add_tool (text_kerning);
73
74 Tool insert_last = new Tool ("insert_glyph_from_overview", t_("Insert glyph from overview"));
75 insert_last.select_action.connect ((self) => {
76 KerningDisplay d = MainWindow.get_kerning_display ();
77 GlyphSelection gs = new GlyphSelection ();
78
79 gs.selected_glyph.connect ((gc) => {
80 d.inser_glyph (gc.get_current ());
81 MainWindow.get_tab_bar ().select_tab_name ("Kerning");
82 });
83
84 GlyphCanvas.set_display (gs);
85 });
86 kerning_tools.add_tool (insert_last);
87
88 Tool insert_unicode = new Tool ("insert_unichar", t_("Insert character by unicode value"));
89 insert_unicode.select_action.connect ((self) => {
90 KerningDisplay d = MainWindow.get_kerning_display ();
91 d.insert_unichar ();
92 });
93 kerning_tools.add_tool (insert_unicode);
94
95 string empty_kerning_text = t_("Open a text file with kerning strings first.");
96
97 previous_kerning_string = new Tool ("previous_kerning_string", t_("Previous kerning string"));
98 previous_kerning_string.select_action.connect ((self) => {
99 FontDisplay fd = MainWindow.get_current_display ();
100 KerningDisplay d = (KerningDisplay) fd;
101 Font f = BirdFont.get_current_font ();
102 string w = f.kerning_strings.previous ();
103
104 if (f.kerning_strings.is_empty ()) {
105 MainWindow.show_message (empty_kerning_text);
106 } else if (w == "") {
107 MainWindow.show_message (t_("You have reached the beginning of the list."));
108 } else {
109 d.new_line ();
110 d.add_text (w);
111 }
112 });
113 kerning_tools.add_tool (previous_kerning_string);
114
115 next_kerning_string = new Tool ("next_kerning_string", t_("Next kerning string"));
116 next_kerning_string.select_action.connect ((self) => {
117 FontDisplay fd = MainWindow.get_current_display ();
118 KerningDisplay d = (KerningDisplay) fd;
119 Font f = BirdFont.get_current_font ();
120 string w = f.kerning_strings.next ();
121
122 if (f.kerning_strings.is_empty ()) {
123 MainWindow.show_message (empty_kerning_text);
124 } else if (w == "") {
125 MainWindow.show_message (t_("You have reached the end of the list."));
126 } else {
127 d.new_line ();
128 d.add_text (w);
129 }
130 });
131 kerning_tools.add_tool (next_kerning_string);
132
133 kerning_tools.set_persistent (false);
134 kerning_tools.set_unique (false);
135
136 classes.set_persistent (true);
137 classes.set_unique (true);
138
139 expanders.add (font_name);
140 expanders.add (zoom_expander);
141 expanders.add (kerning_tools);
142 expanders.add (classes);
143 }
144
145 public static void add_unique_class (KerningRange kerning_class) {
146 KerningRange k;
147
148 if (is_null (classes)) { // FIXME: export without tools
149 init ();
150 }
151
152 foreach (Tool t in classes.tool) {
153 if (!(t is KerningRange)) {
154 warning ("Tool is not kerning range");
155 return;
156 }
157
158 k = (KerningRange) t;
159 if (k.glyph_range.get_all_ranges () == kerning_class.glyph_range.get_all_ranges ()) {
160 return;
161 }
162 }
163
164 classes.add_tool (kerning_class);
165 }
166
167 public static GlyphRange get_kerning_class (int index) {
168 if (likely (0 <= index < classes.tool.size)) {
169 return ((KerningRange) classes.tool.get (index)).glyph_range;
170 } else {
171 warning ("Index out of bounds.");
172 return new GlyphRange ();
173 }
174 }
175
176 public static void update_kerning_classes () {
177 Font font = BirdFont.get_current_font ();
178 KerningClasses k = font.get_kerning_classes ();
179 KerningRange kr;
180 GlyphRange r;
181 int i;
182
183 remove_all_kerning_classes ();
184
185 for (i = 0; i < k.classes_first.size; i++) {
186 r = k.classes_first.get (i);
187 if (r.is_class ()) {
188 kr = new KerningRange (font);
189 kr.set_ranges (r.get_all_ranges ());
190 add_unique_class (kr);
191 }
192
193 r = k.classes_last.get (i);
194 if (r.is_class ()) {
195 kr = new KerningRange (font);
196 kr.set_ranges (r.get_all_ranges ());
197 add_unique_class (kr);
198 }
199 }
200 }
201
202 private static void remove_all_kerning_classes () {
203 if (is_null (classes)) { // FIXME: export without tools
204 init ();
205 }
206
207 classes.tool.clear ();
208
209 if (!is_null (MainWindow.get_toolbox ())) {
210 MainWindow.get_toolbox ().update_expanders ();
211 }
212 }
213
214 public static void remove_empty_classes () {
215 KerningRange kr;
216 int i;
217
218 if (classes.tool.size == 0) {
219 return;
220 }
221
222 i = 0;
223 foreach (Tool t in classes.tool) {
224 return_if_fail (t is KerningRange);
225
226 kr = (KerningRange) t;
227 if (kr.glyph_range.is_empty ()) {
228 classes.tool.remove_at (i);
229 remove_empty_classes ();
230 Toolbox.redraw_tool_box ();
231 return;
232 }
233
234 i++;
235 }
236 }
237
238 public override Gee.ArrayList<Expander> get_expanders () {
239 return expanders;
240 }
241
242 public static void update_spacing_classes () {
243 KerningRange kr;
244
245 if (classes.tool.size == 0) {
246 return;
247 }
248
249 foreach (Tool t in classes.tool) {
250 return_if_fail (t is KerningRange);
251
252 kr = (KerningRange) t;
253 kr.update_spacing_class ();
254 }
255 }
256
257 public override Gee.ArrayList<string> get_displays () {
258 Gee.ArrayList<string> d = new Gee.ArrayList<string> ();
259 d.add ("Kerning");
260 d.add ("Spacing");
261 return d;
262 }
263 }
264
265 }
266