The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

ClipTool.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

Revisions

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