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