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