.
1 /*
2 Copyright (C) 2012 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 namespace BirdFont {
16
17 public class ClipTool : Tool {
18
19 public static void copy_text (TextArea t) {
20 MainWindow.native_window.set_clipboard_text (t.get_selected_text ());
21 }
22
23 public static void paste_text (TextArea t) {
24 if (t.carret_is_visible) {
25 t.insert_text (MainWindow.native_window.get_clipboard_text ());
26 }
27 }
28
29 public static void copy () {
30 FontDisplay fd = MainWindow.get_current_display ();
31 string svg_data;
32 string bf_data;
33 string data;
34
35 if (fd is GlyphTab) {
36 svg_data = ExportTool.export_selected_paths_to_svg ();
37
38 bf_data = export_selected_paths_to_birdfont_clipboard ();
39 data = svg_data + bf_data;
40 MainWindow.native_window.set_clipboard (data);
41 MainWindow.native_window.set_inkscape_clipboard (data);
42 } else if (fd is OverView) {
43 copy_overview_glyphs ();
44 }
45 }
46
47 /** Copy entire glyph. */
48 public static void copy_glyph (Glyph glyph) {
49 string svg_data;
50 string bf_data;
51 string data;
52
53 svg_data = ExportTool.export_to_inkscape_clipboard (glyph, false);
54 bf_data = export_paths_to_birdfont_clipboard (false, false);
55
56 data = svg_data + bf_data;
57 MainWindow.native_window.set_clipboard (data);
58 MainWindow.native_window.set_inkscape_clipboard (data);
59 }
60
61 public static void copy_overview_glyphs () {
62 string svg_data = "";
63 string bf_data = "";
64 string data;
65 OverView o = MainWindow.get_overview ();
66
67 if (o.selected_items.size > 0) {
68 svg_data = ExportTool.export_to_inkscape_clipboard (
69 o.selected_items.get (0).get_current (), false);
70
71 bf_data = export_paths_to_birdfont_clipboard (true, false);
72
73 data = svg_data + bf_data;
74 MainWindow.native_window.set_clipboard (data);
75 MainWindow.native_window.set_inkscape_clipboard (data);
76 }
77 }
78
79 public static void paste_in_place () {
80 paste_paths (true);
81 }
82
83 /** Paste at cursor. */
84 public static void paste () {
85 FontDisplay fd = MainWindow.get_current_display ();
86 Glyph g = MainWindow.get_current_glyph ();
87 double x, y, w, h;
88 double dx, dy;
89
90 if (fd is GlyphTab) {
91 paste_paths (false);
92
93 g.selection_boundaries (out x, out y, out w, out h);
94
95 dx = g.motion_x - x - w / 2.0;
96 dy = g.motion_y - y + h / 2.0;
97
98 foreach (Path path in g.active_paths) {
99 path.move (dx, dy);
100 }
101 } else if (fd is KerningDisplay) {
102 paste_letters_to_kerning_tab ();
103 } else if (fd is OverView) {
104 paste_to_overview ();
105 }
106 }
107
108 static void paste_paths (bool paste_guide_lines) {
109 bool is_bf_clipboard;
110 FontDisplay fd;
111 string clipboard_data = MainWindow.native_window.get_clipboard_data ();
112
113 fd = MainWindow.get_current_display ();
114
115 // Determine if clipboard contains data in birdfont format.
116 is_bf_clipboard = clipboard_data.index_of ("BirdFontClipboard") > -1;
117
118 if (fd is GlyphTab) {
119 paste_to_glyph (is_bf_clipboard, paste_guide_lines);
120 }
121
122 BirdFont.get_current_font ().touch ();
123 }
124
125 static void paste_to_overview () {
126 string data = MainWindow.native_window.get_clipboard_data ();
127 import_birdfont_clipboard (data, true, true);
128 GlyphCanvas.redraw ();
129 }
130
131 static void paste_to_glyph (bool bf_clipboard_data, bool paste_guide_lines) {
132 FontDisplay fd = MainWindow.get_current_display ();
133 Glyph? destination = null;
134 string data;
135 return_if_fail (fd is GlyphTab);
136
137 GlyphTab glyph_tab = (GlyphTab) fd;
138 destination = glyph_tab.glyphs.get_current ();
139 ((!)destination).store_undo_state ();
140 ((!)destination).clear_active_paths ();
141
142 data = MainWindow.native_window.get_clipboard_data ();
143
144 if (bf_clipboard_data) {
145 import_birdfont_clipboard (data, paste_guide_lines, false);
146 } else if (data != "") {
147 SvgParser.import_svg_data (data, SvgFormat.INKSCAPE);
148 }
149
150 ((!)destination).update_view ();
151 }
152
153 static string export_selected_paths_to_birdfont_clipboard () {
154 return export_paths_to_birdfont_clipboard (false, true);
155 }
156
157 static string export_paths_to_birdfont_clipboard (bool overview, bool selected = false) {
158 StringBuilder s = new StringBuilder ();
159 Gee.ArrayList<Path> paths = new Gee.ArrayList<Path> ();
160 Path new_path;
161 Glyph glyph;
162 GlyphCollection glyph_collection;
163 OverView o;
164
165 if (overview) {
166 o = MainWindow.get_overview ();
167 unichar last_assigned = '\0';
168 foreach (GlyphCollection gc in o.selected_items) {
169 s.append ("\n");
170 s.append ("<!-- BirdFontClipboard\n");
171
172 if (!gc.is_unassigned ()) {
173 last_assigned = gc.get_unicode_character ();
174
175 s.append ("BF glyph: ");
176 s.append (@"$(Font.to_hex (gc.get_unicode_character ()))");
177 s.append ("\n");
178 } else {
179 last_assigned++;
180
181 s.append ("BF glyph: ");
182 s.append (@"$(Font.to_hex (last_assigned))");
183 s.append ("\n");
184 }
185
186 s.append ("BF name: ");
187 s.append (@"$(gc.get_name ())");
188 s.append ("\n");
189
190 s.append ("BF unassigned: ");
191 s.append (@"$(gc.is_unassigned ())");
192 s.append ("\n");
193
194 s.append ("BF left: ");
195 s.append (@"$(gc.get_current ().left_limit)");
196 s.append ("\n");
197
198 s.append ("BF right: ");
199 s.append (@"$(gc.get_current ().right_limit)");
200 s.append ("\n");
201
202 foreach (Path path in gc.get_current ().get_visible_paths ()) {
203 s.append ("BF path: ");
204 s.append (BirdFontFile.get_point_data (path));
205 s.append ("\n");
206
207 s.append ("BF stroke: ");
208 s.append (@"$(path.stroke)");
209 s.append ("\n");
210
211 if (path.line_cap == LineCap.ROUND) {
212 s.append ("BF cap: round\n");
213 } else if (path.line_cap == LineCap.SQUARE) {
214 s.append ("BF cap: square\n");
215 }
216 }
217
218 s.append ("BF end -->");
219 }
220 } else {
221 glyph = MainWindow.get_current_glyph ();
222 glyph_collection = MainWindow.get_current_glyph_collection ();
223
224 s.append ("\n");
225 s.append ("<!-- BirdFontClipboard\n");
226
227 s.append ("BF glyph: ");
228 s.append (@"$(Font.to_hex (glyph.unichar_code))");
229 s.append ("\n");
230
231 s.append ("BF name: ");
232 s.append (@"$(glyph_collection.get_name ())");
233 s.append ("\n");
234
235 s.append ("BF unassigned: ");
236 s.append (@"$(glyph_collection.is_unassigned ())");
237 s.append ("\n");
238
239 s.append ("BF left: ");
240 s.append (@"$(glyph.left_limit)");
241 s.append ("\n");
242
243 s.append ("BF right: ");
244 s.append (@"$(glyph.right_limit)");
245 s.append ("\n");
246
247 if (!selected) {
248 foreach (Path path in glyph.get_visible_paths ()) {
249 s.append ("BF path: ");
250 s.append (BirdFontFile.get_point_data (path));
251 s.append ("\n");
252
253 s.append ("BF stroke: ");
254 s.append (@"$(path.stroke)");
255 s.append ("\n");
256
257 if (path.line_cap == LineCap.ROUND) {
258 s.append ("BF cap: round\n");
259 } else if (path.line_cap == LineCap.SQUARE) {
260 s.append ("BF cap: square\n");
261 }
262 }
263 } else if (glyph.get_visible_paths ().size > 0) {
264 foreach (Path path in glyph.active_paths) {
265 s.append ("BF path: ");
266 s.append (BirdFontFile.get_point_data (path));
267 s.append ("\n");
268
269 s.append ("BF stroke: ");
270 s.append (@"$(path.stroke)");
271 s.append ("\n");
272
273 if (path.line_cap == LineCap.ROUND) {
274 s.append ("BF cap: round\n");
275 } else if (path.line_cap == LineCap.SQUARE) {
276 s.append ("BF cap: square\n");
277 }
278 }
279 } else {
280 new_path = new Path ();
281 foreach (Path path in glyph.get_visible_paths ()) {
282 if (path.points.size > 0
283 && path.points.get (0).is_selected ()
284 && path.points.get (path.points.size - 1).is_selected ()) {
285
286 foreach (EditPoint ep in path.points) {
287 if (!ep.is_selected ()) {
288 path.set_new_start (ep);
289 break;
290 }
291 }
292 }
293
294 foreach (EditPoint ep in path.points) {
295 if (!ep.is_selected ()) {
296 if (path.points.size > 0) {
297 paths.add (new_path);
298 new_path = new Path ();
299 }
300 } else {
301 new_path.add_point (ep);
302 }
303 }
304
305 if (all_points_selected (path)) {
306 new_path.close ();
307 }
308 }
309
310 paths.add (new_path);
311
312 foreach (Path path in paths) {
313 if (path.points.size > 0) {
314 s.append ("BF path: ");
315 s.append (BirdFontFile.get_point_data (path));
316 s.append ("\n");
317
318 s.append ("BF stroke: ");
319 s.append (@"$(path.stroke)");
320 s.append ("\n");
321
322 if (path.line_cap == LineCap.ROUND) {
323 s.append ("BF cap: round\n");
324 } else if (path.line_cap == LineCap.SQUARE) {
325 s.append ("BF cap: square\n");
326 }
327 }
328 }
329 }
330
331 s.append ("BF end -->");
332 }
333
334 return s.str;
335 }
336
337 static bool all_points_selected (Path p) {
338 foreach (EditPoint ep in p.points) {
339 if (!ep.is_selected ()) {
340 return false;
341 }
342 }
343 return true;
344 }
345
346 static void import_birdfont_clipboard (string data, bool paste_guide_lines, bool overview) {
347 Gee.ArrayList<GlyphCollection> glyphs = new Gee.ArrayList<GlyphCollection> ();
348 Glyph glyph = new Glyph ("null", '\0');
349 string[] items = data.split ("\nBF ");
350 unichar c;
351 Glyph destination;
352 GlyphCollection glyph_collection = new GlyphCollection ('\0', "");
353 OverView o;
354 Path path = new Path ();
355
356 foreach (string p in items) {
357 if (p.has_prefix ("glyph:")) {
358 p = p.replace ("glyph: ", "");
359 p = p.replace ("\n", "");
360 c = Font.to_unichar (p);
361 glyph_collection = new GlyphCollection (c, (!) c.to_string ());
362 glyphs.add (glyph_collection);
363
364 glyph = new Glyph ((!) c.to_string (), c);
365 GlyphMaster master = new GlyphMaster ();
366 master.add_glyph (glyph);
367 glyph_collection.add_master (master);
368 }
369
370 if (p.has_prefix ("unassigned:")) {
371 p = p.replace ("unassigned: ", "");
372 p = p.replace ("\n", "");
373 glyph_collection.set_unassigned (bool.parse (p));
374 }
375
376 if (p.has_prefix ("name:")) {
377 p = p.replace ("name: ", "");
378 p = p.replace ("\n", "");
379 glyph_collection.set_name (p);
380 glyph.name = p;
381 }
382
383 if (p.has_prefix ("path:")) {
384 p = p.replace ("path: ", "");
385 p = p.replace ("\n", "");
386 path = import_birdfont_path (glyph, p);
387 }
388
389 if (p.has_prefix ("left:")) {
390 glyph.left_limit = double.parse (p.replace ("left: ", ""));
391 glyph.remove_lines ();
392 glyph.add_help_lines ();
393 }
394
395 if (p.has_prefix ("right:")) {
396 glyph.right_limit = double.parse (p.replace ("right: ", ""));
397 glyph.remove_lines ();
398 glyph.add_help_lines ();
399 }
400
401 if (p.has_prefix ("stroke:")) {
402 path.stroke = double.parse (p.replace ("stroke: ", ""));
403 }
404
405 if (p.has_prefix ("cap:")) {
406 string cap = p.replace ("cap: ", "");
407
408 if (cap == "round") {
409 path.line_cap = LineCap.ROUND;
410 } else if (cap == "square") {
411 path.line_cap = LineCap.SQUARE;
412 }
413 }
414 }
415
416 if (!overview) {
417 return_if_fail (glyphs.size > 0);
418 destination = MainWindow.get_current_glyph ();
419 glyph = glyphs.get (0).get_current ();
420
421 foreach (Path p in glyph.get_visible_paths ()) {
422 PenTool.clear_directions ();
423 destination.add_path (p);
424 destination.add_active_path (null, p);
425 }
426
427 if (paste_guide_lines) {
428 destination.left_limit = glyph.left_limit;
429 destination.right_limit = glyph.right_limit;
430 destination.add_help_lines ();
431 destination.update_other_spacing_classes ();
432 }
433 } else {
434 o = MainWindow.get_overview ();
435 o.copied_glyphs.clear ();
436 foreach (GlyphCollection gc in glyphs) {
437 o.copied_glyphs.add (gc);
438 }
439 o.paste ();
440 }
441 }
442
443 static Path import_birdfont_path (Glyph glyph, string data) {
444 Path path = new Path ();
445
446 BirdFontFile.parse_path_data (data, path);
447
448 if (path.points.size > 0) {
449 PenTool.clear_directions ();
450 glyph.add_path (path);
451 glyph.active_paths.add (path);
452 path.update_region_boundaries ();
453 }
454
455 PenTool.remove_all_selected_points ();
456
457 foreach (Path p in glyph.active_paths) {
458 if (p.is_open ()) {
459 foreach (EditPoint e in p.points) {
460 e.set_selected (true);
461 }
462 }
463 }
464
465 PenTool.update_selection ();
466 return path;
467 }
468
469 static void paste_letters_to_kerning_tab () {
470 string clipboard_data = MainWindow.native_window.get_clipboard_data ();
471 KerningDisplay kerning_display = MainWindow.get_kerning_display ();
472
473 if (!clipboard_data.has_prefix ("<?xml")) {
474 kerning_display.add_text (clipboard_data);
475 }
476 }
477 }
478
479 }
480