1 /*
2 Copyright (C) 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
17 namespace BirdFont {
18
19 public enum Transform {
20 SLANT,
21 SIZE
22 }
23
24 public class OverviewTools : ToolCollection {
25
26 static LabelTool all_glyphs;
27 static LabelTool default_glyphs;
28 static LabelTool unicode;
29
30 static Gee.ArrayList<LabelTool> custom_character_sets;
31
32 public static Gee.ArrayList<Expander> expanders;
33 public ZoomBar zoom_bar;
34
35 public static Expander zoom_expander;
36
37 public static SpinButton skew;
38 public static SpinButton resize;
39
40 public static double current_master_size;
41
42 public OverviewTools () {
43 Expander font_name = new Expander ();
44 Expander character_sets = new Expander (t_("Character Sets"));
45 Expander zoom_expander = new Expander (t_("Zoom"));
46 Expander transform_slant_expander = new Expander (t_("Transform"));
47 Expander transform_size_expander = new Expander ();
48 Expander glyph_expander = new Expander (t_("Glyph"));
49 Expander multi_master = new Expander (t_("Multi-Master"));
50
51 expanders = new Gee.ArrayList<Expander> ();
52 custom_character_sets = new Gee.ArrayList<LabelTool> ();
53
54 font_name.add_tool (new FontName ());
55
56 zoom_bar = new ZoomBar ();
57 zoom_bar.new_zoom.connect ((z) => {
58 get_overview ().set_zoom (z);
59 });
60 zoom_expander.add_tool (zoom_bar);
61
62 all_glyphs = new LabelTool (t_("All Glyphs"));
63 all_glyphs.has_counter = true;
64 all_glyphs.select_action.connect ((self) => {
65 OverView overview = get_overview ();
66 overview.display_all_available_glyphs ();
67 update_overview_characterset (overview);
68 FontDisplay.dirty_scrollbar = true;
69 });
70 character_sets.add_tool (all_glyphs);
71
72 default_glyphs = new LabelTool (t_("Default"));
73 default_glyphs.has_counter = true;
74 default_glyphs.select_action.connect ((self) => {
75 OverView overview = get_overview ();
76 GlyphRange gr = new GlyphRange ();
77 DefaultCharacterSet.use_default_range (gr);
78 overview.set_current_glyph_range (gr);
79 update_overview_characterset (overview);
80 FontDisplay.dirty_scrollbar = true;
81 });
82 character_sets.add_tool (default_glyphs);
83
84 unicode = new LabelTool (t_("Unicode"));
85 unicode.has_counter = true;
86 unicode.select_action.connect ((self) => {
87 OverView overview = get_overview ();
88 GlyphRange gr = new GlyphRange ();
89 DefaultCharacterSet.use_full_unicode_range (gr);
90 overview.set_current_glyph_range (gr);
91 update_overview_characterset (overview);
92 FontDisplay.dirty_scrollbar = true;
93 });
94 character_sets.add_tool (unicode);
95
96 character_sets.set_persistent (true);
97 character_sets.set_unique (false);
98
99 skew = new SpinButton ("skew_overview", t_("Skew"));
100 skew.set_big_number (true);
101 skew.set_int_value ("0.000");
102
103 FontSettings settings = BirdFont.get_current_font ().settings;
104 string? skew_value = settings.get_setting ("skew_overview");
105
106 if (skew_value != null) {
107 skew.set_int_value ((!) skew_value);
108 }
109
110 skew.set_int_step (1);
111 skew.set_min (-100);
112 skew.set_max (100);
113 skew.show_icon (true);
114 skew.set_persistent (false);
115 transform_slant_expander.add_tool (skew);
116
117 Tool transform_slant = new Tool ("transform_slant", t_("Transform"));
118 transform_slant.set_icon ("transform");
119 transform_slant.select_action.connect ((self) => {
120 FontSettings fs = BirdFont.get_current_font ().settings;
121 fs.set_setting ("skew_overview", @"$(skew.get_value ())");
122 transform_slant.selected = false;
123
124 process_transform (Transform.SLANT);
125
126 BirdFont.get_current_font ().touch ();
127 });
128 transform_slant.selected = false;
129 transform_slant.set_persistent (false);
130 transform_slant_expander.add_tool (transform_slant);
131
132 resize = new SpinButton ("resize_overview", t_("Resize"));
133 resize.set_big_number (true);
134 resize.set_int_value ("100.0");
135
136 string? resize_value = settings.get_setting ("resize_overview");
137
138 if (resize_value != null) {
139 resize.set_int_value ((!) resize_value);
140
141 if (resize.get_value () <= 0) {
142 resize.set_int_value ("100.0");
143 }
144 }
145
146 resize.set_int_step (1);
147 resize.set_min (0);
148 resize.set_max (300);
149 resize.show_icon (true);
150 resize.set_persistent (false);
151 transform_size_expander.add_tool (resize);
152
153 Tool transform_size = new Tool ("transform_size", t_("Transform"));
154 transform_size.set_icon ("transform");
155 transform_size.select_action.connect ((self) => {
156 FontSettings fs = BirdFont.get_current_font ().settings;
157 fs.set_setting ("resize_overview", @"$(resize.get_value ())");
158 transform_size.selected = false;
159
160 process_transform (Transform.SIZE);
161
162 BirdFont.get_current_font ().touch ();
163 });
164 transform_size.selected = false;
165 transform_size.set_persistent (false);
166 transform_size_expander.add_tool (transform_size);
167
168 Tool alternate = new Tool ("alternate", t_("Create alternate"));
169 alternate.select_action.connect (add_new_alternate);
170 glyph_expander.add_tool (alternate);
171
172 Tool curve_orientation = new Tool ("curve_orientation", t_("Set curve orientation"));
173 curve_orientation.select_action.connect ((self) => {
174 Task t = new Task (fix_curve_orientation);
175
176 MainWindow.run_blocking_task (t);
177
178 IdleSource idle = new IdleSource ();
179 idle.set_callback (() => {
180 self.set_selected (false);
181 BirdFont.get_current_font ().touch ();
182 return false;
183 });
184 idle.attach (null);
185 });
186 glyph_expander.add_tool (curve_orientation);
187
188 Tool search_glyph = new Tool ("search", t_("Search"));
189 search_glyph.select_action.connect (search_for_glyph);
190 glyph_expander.add_tool (search_glyph);
191
192 SpinButton master_size;
193 current_master_size = 0;
194 master_size = new SpinButton ("master_size", t_("Master Size")); /// Master refers to a glyph master in a multi-master font.
195 master_size.set_big_number (false);
196 master_size.set_int_value ("0.000");
197 master_size.set_int_step (1);
198 master_size.set_min (-1);
199 master_size.set_max (1);
200 master_size.show_icon (true);
201 master_size.set_persistent (false);
202 master_size.new_value_action.connect ((self) => {
203 current_master_size = self.get_value ();
204 MainWindow.get_overview ().update_item_list ();
205 GlyphCanvas.redraw ();
206 });
207 multi_master.add_tool (master_size);
208
209 Tool create_new_master = new Tool ("new_master", t_("Create new master font")); /// Master is a master in a multi-master font.
210 create_new_master.select_action.connect (create_master);
211 multi_master.add_tool (create_new_master);
212
213 expanders.add (font_name);
214 expanders.add (zoom_expander);
215 expanders.add (character_sets);
216 expanders.add (transform_slant_expander);
217 expanders.add (transform_size_expander);
218 expanders.add (glyph_expander);
219
220 if (BirdFont.has_argument ("--test")) {
221 expanders.add (multi_master);
222 }
223 }
224
225 void create_master () {
226 Font font = BirdFont.get_current_font ();
227 int i = 0;
228 GlyphCollection glyph_collection;
229 GlyphCollection? gc = font.get_glyph_collection_index (i);
230 Glyph g;
231
232 while (gc != null) {
233 glyph_collection = (!) gc;
234
235 // FIXME: MASTER NAME
236 GlyphMaster master = new GlyphMaster.for_id("Master 2");
237 g = glyph_collection.get_interpolated (current_master_size);
238 master.add_glyph(g);
239 glyph_collection.add_master (master);
240 glyph_collection.set_selected_master (master);
241
242 i++;
243 gc = font.get_glyph_collection_index (i);
244 }
245
246 MainWindow.get_overview ().update_item_list ();
247 GlyphCanvas.redraw ();
248 }
249
250 void fix_curve_orientation () {
251 OverView o;
252 Glyph g;
253 OverView.OverViewUndoItem ui;
254
255 o = get_overview ();
256 ui = new OverView.OverViewUndoItem ();
257
258 Font f = BirdFont.get_current_font ();
259 ui.alternate_sets = f.alternates.copy ();
260
261 foreach (GlyphCollection gc in o.selected_items) {
262 if (gc.length () > 0) {
263 g = gc.get_current ();
264 ui.glyphs.add (gc.copy_deep ());
265 g.add_help_lines ();
266 g.fix_curve_orientation ();
267 }
268 }
269
270 o.undo_items.add (ui);
271 GlyphCanvas.redraw ();
272 }
273
274 public void search_for_glyph (Tool tool) {
275 tool.set_selected (false);
276 OverView.search ();
277 }
278
279 public void add_new_alternate (Tool tool) {
280 OverView o = MainWindow.get_overview ();
281 OverViewItem oi = o.selected_item;
282 GlyphCollection? gc;
283
284 tool.set_selected (false);
285
286 gc = (!) oi.glyphs;
287
288 if (oi.glyphs != null && ((!) oi.glyphs).is_unassigned ()) {
289 gc = null;
290 }
291
292 MainWindow.tabs.add_tab (new OtfFeatureTable (gc));
293 }
294
295 public void process_transform (Transform transform) {
296 OverView o;
297 Glyph g;
298 OverView.OverViewUndoItem ui;
299
300 o = get_overview ();
301 ui = new OverView.OverViewUndoItem ();
302
303 Font f = BirdFont.get_current_font ();
304 ui.alternate_sets = f.alternates.copy ();
305
306 foreach (GlyphCollection gc in o.selected_items) {
307 if (gc.length () > 0) {
308 g = gc.get_current ();
309 ui.glyphs.add (gc.copy_deep ());
310 g.add_help_lines ();
311
312 if (transform == Transform.SLANT) {
313 if (skew.get_value () != 0) {
314 DrawingTools.resize_tool.skew_glyph (g, -skew.get_value (), 0, false);
315 }
316 }
317
318 if (transform == Transform.SIZE) {
319 if (resize.get_value () != 100) {
320 double scale = resize.get_value () / 100;
321 DrawingTools.resize_tool.resize_glyph (g, scale, scale, false);
322 }
323 }
324 }
325 }
326
327 foreach (OverViewItem item in o.visible_items) {
328 item.clear_cache ();
329 item.draw_glyph_from_font ();
330 }
331
332 o.undo_items.add (ui);
333
334 MainWindow.get_overview ().update_item_list ();
335 GlyphCanvas.redraw ();
336 }
337
338 public OverView get_overview () {
339 FontDisplay fd = MainWindow.get_current_display ();
340
341 if (fd is OverView || fd is GlyphSelection) {
342 return (OverView) fd;
343 }
344
345 warning ("Current tab is not overview.");
346
347 return new OverView ();
348 }
349
350 public static void show_all_available_characters () {
351 all_glyphs.select_action (all_glyphs);
352 }
353
354 public static void update_overview_characterset (OverView? tab = null) {
355 GlyphRange gr;
356 uint size;
357 OverView overview;
358
359 // All characters
360 size = BirdFont.get_current_font ().length ();
361 all_glyphs.number = get_display_value (size);
362
363 // Default
364 gr = new GlyphRange ();
365 DefaultCharacterSet.use_default_range (gr);
366 size = gr.get_length ();
367 default_glyphs.number = get_display_value (size);
368
369 // Unicode
370 gr = new GlyphRange ();
371 DefaultCharacterSet.use_full_unicode_range (gr);
372 size = gr.get_length ();
373 unicode.number = get_display_value (size);
374
375 overview = (tab == null) ? MainWindow.get_overview () : (!) tab;
376
377 // set selected item
378 all_glyphs.set_selected (false);
379 default_glyphs.set_selected (false);
380 unicode.set_selected (false);
381
382 if (overview.all_available) {
383 all_glyphs.set_selected (true);
384 } else if (overview.glyph_range.name == "Default") {
385 default_glyphs.set_selected (true);
386 } else if (overview.glyph_range.name == "Unicode") {
387 unicode.set_selected (true);
388 }
389
390 Toolbox.redraw_tool_box ();
391 }
392
393 static string get_display_value (uint size) {
394 double k;
395 string display_size;
396
397 if (size >= 1000) {
398 k = size / 1000.0;
399 size = (uint) Math.rint (k);
400 display_size = @"$(size)k";
401 } else {
402 display_size = @"$(size)";
403 }
404
405 return display_size;
406 }
407
408 public override Gee.ArrayList<Expander> get_expanders () {
409 return expanders;
410 }
411
412 public override Gee.ArrayList<string> get_displays () {
413 Gee.ArrayList<string> d = new Gee.ArrayList<string> ();
414 d.add ("Overview");
415 return d;
416 }
417 }
418
419 }
420