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