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