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 MainWindow.native_window.update_window_size (); 446 } 447 448 public static void show_export_settings_tab () { 449 MainWindow.get_tab_bar ().add_unique_tab (new ExportSettings ()); 450 } 451 452 public static void show_description () { 453 MainWindow.get_tab_bar ().add_unique_tab (new DescriptionDisplay ()); 454 } 455 456 public static void show_kerning_context () { 457 if (suppress_event) { 458 warn_if_test ("Event suppressed"); 459 return; 460 } 461 462 KerningDisplay kd = MainWindow.get_kerning_display (); 463 MainWindow.get_tab_bar ().add_unique_tab (kd); 464 } 465 466 public static void show_spacing_tab () { 467 if (suppress_event) { 468 warn_if_test ("Event suppressed"); 469 return; 470 } 471 472 SpacingTab s = MainWindow.get_spacing_tab (); 473 MainWindow.get_tab_bar ().add_unique_tab (s); 474 } 475 476 public static void show_ligature_tab () { 477 if (suppress_event) { 478 warn_if_test ("Event suppressed"); 479 return; 480 } 481 482 LigatureList d = MainWindow.get_ligature_display (); 483 MainWindow.get_tab_bar ().add_unique_tab (d); 484 } 485 486 public static void preview () { 487 Font font = BirdFont.get_current_font (); 488 489 if (suppress_event) { 490 warn_if_test ("Event suppressed"); 491 return; 492 } 493 494 if (font.font_file == null) { 495 save_callback = new SaveCallback (); 496 save_callback.file_saved.connect (() => { 497 show_preview_tab (); 498 }); 499 save_callback.save (); 500 } else { 501 show_preview_tab (); 502 } 503 } 504 505 public static void show_preview_tab () { 506 OverWriteDialogListener listener = new OverWriteDialogListener (); 507 TabBar tab_bar = MainWindow.get_tab_bar (); 508 FontFormat format = BirdFont.get_current_font ().format; 509 510 if (suppress_event) { 511 warn_if_test ("Event suppressed"); 512 return; 513 } 514 515 listener.overwrite_signal.connect (() => { 516 KeyBindings.set_modifier (NONE); 517 tab_bar.add_unique_tab (new Preview (), true); 518 PreviewTools.update_preview (); 519 }); 520 521 if ((format == FontFormat.SVG || format == FontFormat.FREETYPE) && !OverWriteDialogListener.dont_ask_again) { 522 MainWindow.show_dialog (new OverwriteDialog (listener)); 523 } else { 524 listener.overwrite (); 525 } 526 } 527 528 /** Display the language selection tab. */ 529 public static void select_language () { 530 if (suppress_event) { 531 warn_if_test ("Event suppressed"); 532 return; 533 } 534 535 MainWindow.get_tab_bar ().add_unique_tab (new LanguageSelectionTab ()); 536 } 537 538 public static void use_current_glyph_as_background () { 539 if (suppress_event) { 540 warn_if_test ("Event suppressed"); 541 return; 542 } 543 544 Glyph.background_glyph = MainWindow.get_current_glyph (); 545 546 if (MainWindow.get_current_display () is OverView) { 547 Glyph.background_glyph = MainWindow.get_overview ().get_current_glyph (); 548 } 549 } 550 551 public static void reset_glyph_background () { 552 Glyph.background_glyph = null; 553 } 554 555 public static void remove_all_kerning_pairs () { 556 if (suppress_event) { 557 warn_if_test ("Event suppressed"); 558 return; 559 } 560 561 KerningClasses classes = BirdFont.get_current_font ().get_kerning_classes (); 562 classes.remove_all_pairs (); 563 KerningTools.update_kerning_classes (); 564 } 565 566 public static void list_all_kerning_pairs () { 567 if (suppress_event) { 568 warn_if_test ("Event suppressed"); 569 return; 570 } 571 572 MainWindow.get_tab_bar ().add_unique_tab (new KerningList ()); 573 } 574 575 public static void ensure_main_loop_is_empty () { 576 unowned MainContext context; 577 bool acquired; 578 579 context = MainContext.default (); 580 acquired = context.acquire (); 581 582 if (unlikely (!acquired)) { 583 warning ("Failed to acquire main loop.\n"); 584 return; 585 } 586 587 while (context.pending ()) { 588 context.iteration (true); 589 } 590 context.release (); 591 } 592 593 public static void save_as () { 594 if (MenuTab.has_suppress_event () || !save_callback.is_done) { 595 warn_if_test ("Event suppressed"); 596 return; 597 } 598 599 MenuTab.set_save_callback (new SaveCallback ()); 600 MenuTab.save_callback.save_as(); 601 } 602 603 public static void save () { 604 if (MenuTab.has_suppress_event () && !save_callback.is_done) { 605 warn_if_test ("Event suppressed"); 606 return; 607 } 608 609 MenuTab.set_save_callback (new SaveCallback ()); 610 MenuTab.save_callback.save (); 611 } 612 613 public static void load () { 614 if (MenuTab.has_suppress_event ()) { 615 warn_if_test ("Event suppressed"); 616 return; 617 } 618 619 MenuTab.load_callback = new LoadCallback (); 620 MenuTab.load_callback.load (); 621 622 MenuTab.load_callback.file_loaded.connect (() => { 623 Font f = BirdFont.get_current_font (); 624 MenuTab.apply_font_setting (f); 625 }); 626 } 627 628 public static void move_to_baseline () { 629 if (suppress_event) { 630 warn_if_test ("Event suppressed"); 631 return; 632 } 633 634 DrawingTools.move_tool.move_to_baseline (); 635 } 636 637 public static void show_file_dialog_tab (string title, FileChooser action, bool folder) { 638 FileDialogTab ft = new FileDialogTab (title, action, folder); 639 MainWindow.get_tab_bar ().add_tab (ft); 640 } 641 642 public static void simplify_path () { 643 if (suppress_event) { 644 warn_if_test ("Event suppressed"); 645 return; 646 } 647 648 Task t = new Task (simplify); 649 MainWindow.run_blocking_task (t); 650 } 651 652 private static void simplify () { 653 Glyph g = MainWindow.get_current_glyph (); 654 Gee.ArrayList<Path> paths = new Gee.ArrayList<Path> (); 655 656 // selected objects 657 foreach (Path p in g.get_active_paths ()) { 658 paths.add (PenTool.simplify (p, false, PenTool.simplification_threshold)); 659 } 660 661 // selected segments 662 if (paths.size == 0) { 663 foreach (Path p in g.get_active_paths ()) { 664 g.add_active_path (p); 665 } 666 667 foreach (Path p in g.get_active_paths ()) { 668 paths.add (PenTool.simplify (p, true, PenTool.simplification_threshold)); 669 } 670 } 671 672 g.store_undo_state (); 673 674 foreach (SvgBird.Object o in g.active_paths) { 675 g.layers.remove (o); 676 } 677 678 foreach (Path p in g.get_active_paths ()) { 679 LayerUtils.remove_path (g.layers, p); 680 } 681 682 foreach (Path p in paths) { 683 g.add_path (p); 684 g.add_active_path (p); 685 } 686 687 g.active_paths.clear (); 688 g.update_view (); 689 } 690 691 public static void show_spacing_class_tab () { 692 SpacingClassTab t = MainWindow.get_spacing_class_tab (); 693 MainWindow.get_tab_bar ().add_unique_tab (t); 694 } 695 696 public static void add_ligature () { 697 TextListener listener; 698 string ligature_name = ""; 699 700 if (suppress_event) { 701 warn_if_test ("Event suppressed"); 702 return; 703 } 704 705 listener = new TextListener (t_("Name"), "", t_("Add ligature")); 706 707 listener.signal_text_input.connect ((text) => { 708 ligature_name = text; 709 }); 710 711 listener.signal_submit.connect (() => { 712 Font font = BirdFont.get_current_font (); 713 GlyphCollection? fg; 714 Glyph glyph; 715 GlyphCollection glyph_collection; 716 OverView o = MainWindow.get_overview (); 717 718 fg = font.get_glyph_collection_by_name (ligature_name); 719 720 if (fg == null) { 721 glyph_collection = new GlyphCollection ('\0', ligature_name); 722 723 glyph = new Glyph (ligature_name, '\0'); 724 glyph_collection.set_unassigned (true); 725 glyph_collection.insert_glyph (glyph, true); 726 727 font.add_glyph_collection (glyph_collection); 728 } 729 730 o.display_all_available_glyphs (); 731 o.scroll_to_glyph (ligature_name); 732 733 TabContent.hide_text_input (); 734 show_all_available_characters (); 735 }); 736 737 TabContent.show_text_input (listener); 738 } 739 740 public static void show_default_characters () { 741 MainWindow.get_tab_bar ().add_unique_tab (new OverView ()); 742 OverView o = MainWindow.get_overview (); 743 GlyphRange gr = new GlyphRange (); 744 745 if (!BirdFont.get_current_font ().initialised) { 746 MenuTab.new_file (); 747 } 748 749 DefaultCharacterSet.use_default_range (gr); 750 o.set_current_glyph_range (gr); 751 752 MainWindow.get_tab_bar ().select_tab_name ("Overview"); 753 } 754 755 public static void show_all_available_characters () { 756 MainWindow.get_tab_bar ().add_unique_tab (new OverView ()); 757 758 if (!BirdFont.get_current_font ().initialised) { 759 MenuTab.new_file (); 760 } 761 762 MainWindow.get_tab_bar ().select_tab_name ("Overview"); 763 OverviewTools.show_all_available_characters (); 764 } 765 766 public static void show_background_tab () { 767 BackgroundTab bt; 768 769 if (suppress_event) { 770 warn_if_test ("Event suppressed"); 771 return; 772 } 773 774 bt = BackgroundTab.get_instance (); 775 MainWindow.get_tab_bar ().add_unique_tab (bt); 776 } 777 778 public static void show_settings_tab () { 779 MainWindow.get_tab_bar ().add_unique_tab (new SettingsTab ()); 780 } 781 782 public static void show_theme_tab () { 783 MainWindow.get_tab_bar ().add_unique_tab (new ThemeTab ()); 784 } 785 786 public static void show_guide_tab () { 787 MainWindow.get_tab_bar ().add_unique_tab (new GuideTab ()); 788 } 789 } 790 791 } 792