The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

MenuTab.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/MenuTab.vala.
Parse more style attributes in SVG files
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 MenuTab : FontDisplay { 18 19 /** Ignore input events when the background thread is running. 20 * 21 * Do always check the return value of set_suppress_event when this 22 * variable is updated. 23 * 24 * This variable is used only in the gui thread. 25 */ 26 private static bool suppress_event; 27 28 /** True if the background thread is running. */ 29 public static bool background_thread; 30 31 /** A notification sent when the file has been saved. */ 32 public static SaveCallback save_callback; 33 34 /** A notification sent when the file has been loaded. */ 35 public static LoadCallback load_callback; 36 37 /** A notification sent when the file has been loaded. */ 38 public static ExportCallback export_callback; 39 40 public MenuTab () { 41 save_callback = new SaveCallback (); 42 save_callback.is_done = true; 43 44 load_callback = new LoadCallback (); 45 export_callback = new ExportCallback (); 46 47 suppress_event = false; 48 background_thread = false; 49 } 50 51 public static bool has_suppress_event () { 52 bool suppress; 53 54 lock (suppress_event) { 55 suppress = suppress_event; 56 } 57 58 return suppress; 59 } 60 61 public static void set_save_callback (SaveCallback c) { 62 if (!save_callback.is_done) { 63 warning ("Prevoius save command has not finished"); 64 } 65 66 save_callback = c; 67 } 68 69 public static void start_background_thread () { 70 if (!set_suppress_event (true)) { 71 warning ("suppressed event"); 72 return; 73 } 74 75 TabBar.start_wheel (); 76 } 77 78 public static void stop_background_thread () { 79 IdleSource idle = new IdleSource (); 80 idle.set_callback (() => { 81 set_suppress_event (false); 82 TabBar.stop_wheel (); 83 GlyphCanvas.redraw (); 84 return false; 85 }); 86 idle.attach (null); 87 } 88 89 public static bool validate_metadata () { 90 Font font = BirdFont.get_current_font (); 91 string m = t_("Missing metadata in font:") + "\n"; 92 93 if (font.postscript_name == "") { 94 MainWindow.show_message (m + t_("PostScript Name")); 95 return false; 96 } 97 98 if (font.name == "") { 99 MainWindow.show_message (m + t_("Name")); 100 return false; 101 } 102 103 if (font.subfamily == "") { 104 MainWindow.show_message (m + t_("Style")); 105 return false; 106 } 107 108 if (font.full_name == "") { 109 MainWindow.show_message (m + t_("Full Name (Name and Style)")); 110 return false; 111 } 112 113 if (font.unique_identifier == "") { 114 MainWindow.show_message (m + t_("Unique Identifier")); 115 return false; 116 } 117 118 Font current_font = BirdFont.get_current_font (); 119 string ttf_name = ExportSettings.get_file_name (current_font) + ".ttf"; 120 string ttf_name_mac = ExportSettings.get_file_name_mac (current_font) + ".ttf"; 121 122 print (@"$ttf_name == $ttf_name_mac"); 123 if (ttf_name == ttf_name_mac) { 124 MainWindow.show_message (t_("You need to choose a different name for the TTF file with Mac adjustmets.")); 125 ttf_name_mac = ExportSettings.get_file_name_mac (current_font) + " Mac.ttf"; 126 return false; 127 } 128 129 return true; 130 } 131 132 public static void export_fonts_in_background () { 133 Font f; 134 135 if (suppress_event || !MainWindow.native_window.can_export ()) { 136 return; 137 } 138 139 f = BirdFont.get_current_font (); 140 141 if (f.font_file == null) { 142 MainWindow.show_message (t_("You need to save your font before exporting it.")); 143 return; 144 } 145 146 if (!validate_metadata ()) { 147 return; 148 } 149 150 if (!ExportSettings.has_export_settings (f)) { 151 show_export_settings_tab (); 152 } else { 153 MenuTab.export_callback = new ExportCallback (); 154 MenuTab.export_callback.export_fonts_in_background (); 155 } 156 } 157 158 public static bool set_suppress_event (bool e) { 159 if (suppress_event && e) { 160 warning ("suppress_event is already set"); 161 return false; 162 } 163 164 if (e) { 165 TabContent.create_pause_surface (); 166 } 167 168 background_thread = e; 169 suppress_event = e; 170 171 // key up will be ignored if events are suppressed 172 if (suppress_event) { 173 IdleSource idle = new IdleSource (); 174 idle.set_callback (() => { 175 KeyBindings.reset (); 176 return false; 177 }); 178 idle.attach (null); 179 } 180 181 return true; 182 } 183 184 public override string get_label () { 185 return t_("Menu"); 186 } 187 188 public override string get_name () { 189 return "Menu"; 190 } 191 192 public static void select_overview () { 193 if (suppress_event) { 194 warn_if_test ("Event suppressed"); 195 return; 196 } 197 198 if (BirdFont.get_current_font ().is_empty ()) { 199 show_default_characters (); 200 } else { 201 MainWindow.get_tab_bar ().add_unique_tab (new OverView ()); 202 MainWindow.get_tab_bar ().select_tab_name ("Overview"); 203 } 204 } 205 206 public static void signal_file_exported () { 207 IdleSource idle = new IdleSource (); 208 idle.set_callback (() => { 209 export_callback.file_exported (); 210 return false; 211 }); 212 idle.attach (null); 213 } 214 215 public static void signal_file_saved () { 216 IdleSource idle = new IdleSource (); 217 idle.set_callback (() => { 218 save_callback.file_saved (); 219 return false; 220 }); 221 idle.attach (null); 222 } 223 224 public static void signal_file_loaded () { 225 IdleSource idle = new IdleSource (); 226 idle.set_callback (() => { 227 load_callback.file_loaded (); 228 MainWindow.native_window.font_loaded (); 229 return false; 230 }); 231 idle.attach (null); 232 } 233 234 public static void apply_font_setting (Font f) { 235 DrawingTools.background_scale.set_value (f.background_scale); 236 237 DrawingTools.grid_expander.tool.clear (); 238 239 if (f.grid_width.size == 0) { 240 f.grid_width.add ("1"); 241 f.grid_width.add ("2"); 242 f.grid_width.add ("4"); 243 } 244 245 foreach (string grid in f.grid_width) { 246 DrawingTools.add_new_grid (double.parse (grid), false); 247 } 248 249 string sw = f.settings.get_setting ("stroke_width"); 250 if (sw != ""){ 251 StrokeTool.stroke_width = double.parse (sw); 252 DrawingTools.object_stroke.set_value_round (StrokeTool.stroke_width); 253 } 254 255 string pt = f.settings.get_setting ("point_type"); 256 DrawingTools.set_default_point_type (pt); 257 258 string stroke = f.settings.get_setting ("apply_stroke"); 259 bool s = bool.parse (stroke); 260 DrawingTools.add_stroke.set_selected (s); 261 StrokeTool.add_stroke = s; 262 263 string lc = f.settings.get_setting ("line_cap"); 264 265 if (lc == "butt") { 266 StrokeTool.line_cap = LineCap.BUTT; 267 } else if (lc == "square") { 268 StrokeTool.line_cap = LineCap.SQUARE; 269 } else if (lc == "round") { 270 StrokeTool.line_cap = LineCap.ROUND; 271 } 272 273 DrawingTools.set_stroke_tool_visibility (); 274 275 string lock_grid = f.settings.get_setting ("lock_grid"); 276 bool lg = bool.parse (lock_grid); 277 GridTool.lock_grid = lg; 278 DrawingTools.lock_grid.selected = GridTool.lock_grid; 279 280 string skew_overview = f.settings.get_setting ("skew_overview"); 281 if (skew_overview != "") { 282 double so = double.parse (skew_overview); 283 OverviewTools.skew.set_value_round (so); 284 } 285 286 string autotrace_resolution = f.settings.get_setting ("autotrace_resolution"); 287 if (autotrace_resolution != "") { 288 double ar = double.parse (autotrace_resolution); 289 DrawingTools.background_threshold.set_value_round (ar); 290 } 291 292 string autotrace_threshold = f.settings.get_setting ("autotrace_threshold"); 293 if (autotrace_threshold != "") { 294 double at = double.parse (autotrace_threshold); 295 DrawingTools.auto_trace_resolution.set_value_round (at); 296 } 297 298 string autotrace_simplification = f.settings.get_setting ("autotrace_simplification"); 299 if (autotrace_simplification != "") { 300 double asi = double.parse (autotrace_simplification); 301 DrawingTools.auto_trace_simplify.set_value_round (asi); 302 } 303 304 string kerning_zoom = f.settings.get_setting ("kerning_zoom"); 305 if (kerning_zoom != "") { 306 double k = double.parse (kerning_zoom); 307 if (!is_null (KerningTools.zoom_bar)) { 308 KerningTools.zoom_bar.zoom_level = k; 309 KerningTools.zoom_bar.new_zoom (k); 310 } 311 } 312 313 string spacing_zoom = f.settings.get_setting ("spacing_zoom"); 314 if (spacing_zoom != "") { 315 double sz = double.parse (spacing_zoom); 316 if (!is_null (SpacingTools.zoom_bar)) { 317 SpacingTools.zoom_bar.zoom_level = sz; 318 SpacingTools.zoom_bar.new_zoom (sz); 319 } 320 } 321 322 MainWindow.get_toolbox ().update_expanders (); 323 MainWindow.get_toolbox ().update_all_expanders (); 324 Toolbox.redraw_tool_box (); 325 } 326 327 // FIXME: background thread 328 public static void save_as_bfp () { 329 FileChooser fc = new FileChooser (); 330 331 if (suppress_event) { 332 warn_if_test ("Event suppressed"); 333 return; 334 } 335 336 if (!set_suppress_event (true)) { 337 return; 338 } 339 340 fc.file_selected.connect((fn) => { 341 Font f = BirdFont.get_current_font (); 342 343 if (fn != null) { 344 f.init_bfp ((!) fn); 345 } 346 347 set_suppress_event (false); 348 }); 349 350 MainWindow.file_chooser (t_("Save"), fc, FileChooser.SAVE); 351 } 352 353 public static void new_file () { 354 Font font; 355 SaveDialogListener dialog = new SaveDialogListener (); 356 357 if (suppress_event) { 358 warn_if_test ("Event suppressed"); 359 return; 360 } 361 362 font = BirdFont.get_current_font (); 363 364 dialog.signal_discard.connect (() => { 365 MainWindow.close_all_tabs (); 366 367 BirdFont.new_font (); 368 MainWindow.native_window.font_loaded (); 369 370 show_default_characters (); 371 372 GlyphCanvas.redraw (); 373 }); 374 375 dialog.signal_save.connect (() => { 376 MenuTab.save_callback = new SaveCallback (); 377 MenuTab.save_callback.file_saved.connect (() => { 378 dialog.signal_discard (); 379 }); 380 save_callback.save (); 381 }); 382 383 dialog.signal_cancel.connect (() => { 384 MainWindow.hide_dialog (); 385 }); 386 387 if (!font.is_modified ()) { 388 dialog.signal_discard (); 389 } else { 390 MainWindow.show_dialog (new SaveDialog (dialog)); 391 } 392 393 return; 394 } 395 396 public static void quit () { 397 if (suppress_event) { 398 warn_if_test ("Event suppressed"); 399 return; 400 } 401 402 TabContent.hide_text_input (); 403 404 SaveDialogListener dialog = new SaveDialogListener (); 405 Font font = BirdFont.get_current_font (); 406 407 Preferences.save (); 408 409 dialog.signal_discard.connect (() => { 410 ensure_main_loop_is_empty (); 411 MainWindow.native_window.quit (); 412 }); 413 414 dialog.signal_save.connect (() => { 415 MenuTab.set_save_callback (new SaveCallback ()); 416 MenuTab.save_callback.file_saved.connect (() => { 417 ensure_main_loop_is_empty (); 418 MainWindow.native_window.quit (); 419 }); 420 save_callback.save (); 421 }); 422 423 dialog.signal_cancel.connect (() => { 424 MainWindow.hide_dialog (); 425 }); 426 427 if (!font.is_modified ()) { 428 dialog.signal_discard (); 429 } else { 430 MainWindow.show_dialog (new SaveDialog (dialog)); 431 } 432 } 433 434 public static void show_export_settings_tab () { 435 MainWindow.get_tab_bar ().add_unique_tab (new ExportSettings ()); 436 } 437 438 public static void show_description () { 439 MainWindow.get_tab_bar ().add_unique_tab (new DescriptionDisplay ()); 440 } 441 442 public static void show_kerning_context () { 443 if (suppress_event) { 444 warn_if_test ("Event suppressed"); 445 return; 446 } 447 448 KerningDisplay kd = MainWindow.get_kerning_display (); 449 MainWindow.get_tab_bar ().add_unique_tab (kd); 450 } 451 452 public static void show_spacing_tab () { 453 if (suppress_event) { 454 warn_if_test ("Event suppressed"); 455 return; 456 } 457 458 SpacingTab s = MainWindow.get_spacing_tab (); 459 MainWindow.get_tab_bar ().add_unique_tab (s); 460 } 461 462 public static void show_ligature_tab () { 463 if (suppress_event) { 464 warn_if_test ("Event suppressed"); 465 return; 466 } 467 468 LigatureList d = MainWindow.get_ligature_display (); 469 MainWindow.get_tab_bar ().add_unique_tab (d); 470 } 471 472 public static void preview () { 473 Font font = BirdFont.get_current_font (); 474 475 if (suppress_event) { 476 warn_if_test ("Event suppressed"); 477 return; 478 } 479 480 if (font.font_file == null) { 481 save_callback = new SaveCallback (); 482 save_callback.file_saved.connect (() => { 483 show_preview_tab (); 484 }); 485 save_callback.save (); 486 } else { 487 show_preview_tab (); 488 } 489 } 490 491 public static void show_preview_tab () { 492 OverWriteDialogListener listener = new OverWriteDialogListener (); 493 TabBar tab_bar = MainWindow.get_tab_bar (); 494 FontFormat format = BirdFont.get_current_font ().format; 495 496 if (suppress_event) { 497 warn_if_test ("Event suppressed"); 498 return; 499 } 500 501 listener.overwrite_signal.connect (() => { 502 KeyBindings.set_modifier (NONE); 503 tab_bar.add_unique_tab (new Preview (), true); 504 PreviewTools.update_preview (); 505 }); 506 507 if ((format == FontFormat.SVG || format == FontFormat.FREETYPE) && !OverWriteDialogListener.dont_ask_again) { 508 MainWindow.show_dialog (new OverwriteDialog (listener)); 509 } else { 510 listener.overwrite (); 511 } 512 } 513 514 /** Display the language selection tab. */ 515 public static void select_language () { 516 if (suppress_event) { 517 warn_if_test ("Event suppressed"); 518 return; 519 } 520 521 MainWindow.get_tab_bar ().add_unique_tab (new LanguageSelectionTab ()); 522 } 523 524 public static void use_current_glyph_as_background () { 525 if (suppress_event) { 526 warn_if_test ("Event suppressed"); 527 return; 528 } 529 530 Glyph.background_glyph = MainWindow.get_current_glyph (); 531 532 if (MainWindow.get_current_display () is OverView) { 533 Glyph.background_glyph = MainWindow.get_overview ().get_current_glyph (); 534 } 535 } 536 537 public static void reset_glyph_background () { 538 Glyph.background_glyph = null; 539 } 540 541 public static void remove_all_kerning_pairs () { 542 if (suppress_event) { 543 warn_if_test ("Event suppressed"); 544 return; 545 } 546 547 KerningClasses classes = BirdFont.get_current_font ().get_kerning_classes (); 548 classes.remove_all_pairs (); 549 KerningTools.update_kerning_classes (); 550 } 551 552 public static void list_all_kerning_pairs () { 553 if (suppress_event) { 554 warn_if_test ("Event suppressed"); 555 return; 556 } 557 558 MainWindow.get_tab_bar ().add_unique_tab (new KerningList ()); 559 } 560 561 public static void ensure_main_loop_is_empty () { 562 unowned MainContext context; 563 bool acquired; 564 565 context = MainContext.default (); 566 acquired = context.acquire (); 567 568 if (unlikely (!acquired)) { 569 warning ("Failed to acquire main loop.\n"); 570 return; 571 } 572 573 while (context.pending ()) { 574 context.iteration (true); 575 } 576 context.release (); 577 } 578 579 public static void save_as () { 580 if (MenuTab.has_suppress_event () || !save_callback.is_done) { 581 warn_if_test ("Event suppressed"); 582 return; 583 } 584 585 MenuTab.set_save_callback (new SaveCallback ()); 586 MenuTab.save_callback.save_as(); 587 } 588 589 public static void save () { 590 if (MenuTab.has_suppress_event () && !save_callback.is_done) { 591 warn_if_test ("Event suppressed"); 592 return; 593 } 594 595 MenuTab.set_save_callback (new SaveCallback ()); 596 MenuTab.save_callback.save (); 597 } 598 599 public static void load () { 600 if (MenuTab.has_suppress_event ()) { 601 warn_if_test ("Event suppressed"); 602 return; 603 } 604 605 MenuTab.load_callback = new LoadCallback (); 606 MenuTab.load_callback.load (); 607 608 MenuTab.load_callback.file_loaded.connect (() => { 609 Font f = BirdFont.get_current_font (); 610 MenuTab.apply_font_setting (f); 611 }); 612 } 613 614 public static void move_to_baseline () { 615 if (suppress_event) { 616 warn_if_test ("Event suppressed"); 617 return; 618 } 619 620 DrawingTools.move_tool.move_to_baseline (); 621 } 622 623 public static void show_file_dialog_tab (string title, FileChooser action, bool folder) { 624 FileDialogTab ft = new FileDialogTab (title, action, folder); 625 MainWindow.get_tab_bar ().add_tab (ft); 626 } 627 628 public static void simplify_path () { 629 if (suppress_event) { 630 warn_if_test ("Event suppressed"); 631 return; 632 } 633 634 Task t = new Task (simplify); 635 MainWindow.native_window.run_background_thread (t); 636 } 637 638 private static void simplify () { 639 Glyph g = MainWindow.get_current_glyph (); 640 Gee.ArrayList<Path> paths = new Gee.ArrayList<Path> (); 641 642 // selected objects 643 foreach (Path p in g.active_paths) { 644 paths.add (PenTool.simplify (p, false, PenTool.simplification_threshold)); 645 } 646 647 // selected segments 648 if (paths.size == 0) { 649 foreach (Path p in g.get_all_paths ()) { 650 g.add_active_path (null, p); 651 } 652 653 foreach (Path p in g.active_paths) { 654 paths.add (PenTool.simplify (p, true, PenTool.simplification_threshold)); 655 } 656 } 657 658 g.store_undo_state (); 659 660 foreach (Path p in g.active_paths) { 661 g.layers.remove_path (p); 662 } 663 664 foreach (Path p in g.active_paths) { 665 g.layers.remove_path (p); 666 } 667 668 foreach (Path p in paths) { 669 g.add_path (p); 670 g.add_active_path (null, p); 671 } 672 673 g.active_paths.clear (); 674 g.update_view (); 675 } 676 677 public static void show_spacing_class_tab () { 678 SpacingClassTab t = MainWindow.get_spacing_class_tab (); 679 MainWindow.get_tab_bar ().add_unique_tab (t); 680 } 681 682 public static void add_ligature () { 683 TextListener listener; 684 string ligature_name = ""; 685 686 if (suppress_event) { 687 warn_if_test ("Event suppressed"); 688 return; 689 } 690 691 listener = new TextListener (t_("Name"), "", t_("Add ligature")); 692 693 listener.signal_text_input.connect ((text) => { 694 ligature_name = text; 695 }); 696 697 listener.signal_submit.connect (() => { 698 Font font = BirdFont.get_current_font (); 699 GlyphCollection? fg; 700 Glyph glyph; 701 GlyphCollection glyph_collection; 702 OverView o = MainWindow.get_overview (); 703 704 fg = font.get_glyph_collection_by_name (ligature_name); 705 706 if (fg == null) { 707 glyph_collection = new GlyphCollection ('\0', ligature_name); 708 709 glyph = new Glyph (ligature_name, '\0'); 710 glyph_collection.set_unassigned (true); 711 glyph_collection.insert_glyph (glyph, true); 712 713 font.add_glyph_collection (glyph_collection); 714 } 715 716 o.display_all_available_glyphs (); 717 o.scroll_to_glyph (ligature_name); 718 719 TabContent.hide_text_input (); 720 show_all_available_characters (); 721 }); 722 723 TabContent.show_text_input (listener); 724 } 725 726 public static void show_default_characters () { 727 MainWindow.get_tab_bar ().add_unique_tab (new OverView ()); 728 OverView o = MainWindow.get_overview (); 729 GlyphRange gr = new GlyphRange (); 730 731 if (!BirdFont.get_current_font ().initialised) { 732 MenuTab.new_file (); 733 } 734 735 DefaultCharacterSet.use_default_range (gr); 736 o.set_current_glyph_range (gr); 737 738 MainWindow.get_tab_bar ().select_tab_name ("Overview"); 739 } 740 741 public static void show_all_available_characters () { 742 MainWindow.get_tab_bar ().add_unique_tab (new OverView ()); 743 744 if (!BirdFont.get_current_font ().initialised) { 745 MenuTab.new_file (); 746 } 747 748 MainWindow.get_tab_bar ().select_tab_name ("Overview"); 749 OverviewTools.show_all_available_characters (); 750 } 751 752 public static void show_background_tab () { 753 BackgroundTab bt; 754 755 if (suppress_event) { 756 warn_if_test ("Event suppressed"); 757 return; 758 } 759 760 bt = BackgroundTab.get_instance (); 761 MainWindow.get_tab_bar ().add_unique_tab (bt); 762 } 763 764 public static void show_settings_tab () { 765 MainWindow.get_tab_bar ().add_unique_tab (new SettingsTab ()); 766 } 767 768 public static void show_theme_tab () { 769 MainWindow.get_tab_bar ().add_unique_tab (new ThemeTab ()); 770 } 771 772 public static void show_guide_tab () { 773 MainWindow.get_tab_bar ().add_unique_tab (new GuideTab ()); 774 } 775 } 776 777 } 778