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