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