The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

GtkWindow.vala in birdfont

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 birdfont/GtkWindow.vala.
Platform independent tool tip
1 /* 2 Copyright (C) 2012, 2013, 2014 Johan Mattsson 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 using Cairo; 19 using Gtk; 20 using Gdk; 21 using BirdFont; 22 using WebKit; 23 using Gdk; 24 using Notify; 25 26 namespace BirdFont { 27 28 public class GtkWindow : Gtk.Window, NativeWindow { 29 30 Box list_box; 31 Box canvas_box; 32 33 WebView html_canvas; 34 ScrolledWindow html_box; 35 36 Box tab_box; 37 38 GlyphCanvasArea glyph_canvas_area; 39 40 Clipboard clipboard; 41 string clipboard_svg = ""; 42 string inkscape_clipboard = ""; 43 44 Scrollbar scrollbar; 45 bool scrollbar_supress_signal = false; 46 47 DescriptionForm description; 48 49 /** Text input and callbacks. */ 50 public static bool text_input_is_active = false; 51 TextListener text_listener = new TextListener ("", "", ""); 52 Label text_input_label; 53 Entry text_entry; 54 Box text_box; 55 Gtk.Button submit_text_button; 56 57 Gtk.Window tooltip_window = new Gtk.Window (); 58 59 ToolboxCanvas toolbox; 60 61 Task background_task = new Task (); 62 63 public GtkWindow (string title) { 64 scrollbar = new Scrollbar (Orientation.VERTICAL, new Adjustment (0, 0, 1, 1, 0.01, 0.1)); 65 ((Gtk.Window)this).set_title ("BirdFont"); 66 } 67 68 public void init () { 69 Notify.init ("Fonts have been exported."); 70 71 description = new DescriptionForm (); 72 73 clipboard = Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); 74 75 scrollbar.value_changed.connect (() => { 76 double p; 77 78 if (!scrollbar_supress_signal) { 79 p = scrollbar.get_value () / (1 - scrollbar.adjustment.page_size); 80 FontDisplay display = MainWindow.get_current_display (); 81 display.scroll_to (p); 82 } 83 }); 84 85 delete_event.connect (() => { 86 MenuTab.quit (); 87 return true; 88 }); 89 90 set_size_and_position (); 91 92 glyph_canvas_area = new GlyphCanvasArea (MainWindow.glyph_canvas); 93 94 html_canvas = new WebView (); 95 WebKit.set_cache_model (CacheModel.DOCUMENT_VIEWER); 96 html_canvas.get_settings ().enable_default_context_menu = false; 97 98 html_box = new ScrolledWindow (null, null); 99 html_box.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC); 100 html_box.add (html_canvas); 101 html_canvas.set_editable (true); 102 103 MainWindow.get_tab_bar ().signal_tab_selected.connect ((f, tab) => { 104 string uri = ""; 105 string html = ""; 106 FontDisplay fd = tab.get_display (); 107 108 scrollbar.set_visible (fd.has_scrollbar ()); 109 110 if (fd.get_name () == "Preview") { 111 uri = Preview.get_uri (); 112 html = Preview.get_html_with_absolute_paths (); 113 114 try { 115 html_canvas.load_html_string (html, uri); 116 } catch (Error e) { 117 warning (e.message); 118 warning ("Failed to load html into canvas."); 119 } 120 121 // show the webview when loading has finished 122 html_box.set_visible (true); 123 glyph_canvas_area.set_visible (false); 124 description.canvas.set_visible (false); 125 126 } else { 127 html_box.set_visible (false); 128 glyph_canvas_area.set_visible (true); 129 description.canvas.set_visible (false); 130 } 131 }); 132 133 // Hide this canvas when window is realized and flip canvas 134 // visibility in tab selection signal. 135 html_canvas.draw.connect ((t, e) => { 136 glyph_canvas_area.set_visible (false); 137 return false; 138 }); 139 140 canvas_box = new Box (Orientation.HORIZONTAL, 0); 141 canvas_box.pack_start (glyph_canvas_area, true, true, 0); 142 canvas_box.pack_start (html_box, true, true, 0); 143 canvas_box.pack_start (description.canvas, true, true, 0); 144 canvas_box.pack_start (scrollbar, false, true, 0); 145 146 submit_text_button = new Gtk.Button (); 147 submit_text_button.set_label ("Submit"); 148 text_input_label = new Label (" " + "Text"); 149 text_entry = new Entry (); 150 text_box = new Box (Orientation.HORIZONTAL, 6); 151 text_box.pack_start (text_input_label, false, false, 0); 152 text_box.pack_start (text_entry, true, true, 0); 153 text_box.pack_start (submit_text_button, false, false, 0); 154 155 text_entry.changed.connect (() => { 156 text_listener.signal_text_input (text_entry.text); 157 }); 158 159 submit_text_button.clicked.connect (() => { 160 text_listener.signal_submit (text_entry.text); 161 text_input_is_active = false; 162 }); 163 164 tab_box = new Box (Orientation.VERTICAL, 0); 165 166 tab_box.pack_start (new TabbarCanvas (MainWindow.get_tab_bar ()), false, false, 0); 167 tab_box.pack_start (text_box, false, false, 5); 168 tab_box.pack_start (canvas_box, true, true, 0); 169 170 toolbox = new ToolboxCanvas (MainWindow.get_toolbox ()); 171 list_box = new Box (Orientation.HORIZONTAL, 0); 172 list_box.pack_start (toolbox, false, false, 0); 173 list_box.pack_start (tab_box, true, true, 0); 174 175 Box vbox = new Box (Orientation.VERTICAL, 0); 176 vbox.pack_start(list_box, true, true, 0); 177 add (vbox); 178 179 try { 180 set_icon_from_file ((!) Icons.find_icon ("window_icon.png").get_path ()); 181 } catch (GLib.Error e) { 182 warning (e.message); 183 } 184 185 key_press_event.connect ((t, event) => { 186 if (!GtkWindow.text_input_is_active) { 187 TabContent.key_press (event.keyval); 188 } 189 190 return false; 191 }); 192 193 key_release_event.connect ((t, event) => { 194 if (!GtkWindow.text_input_is_active) { 195 TabContent.key_release (event.keyval); 196 } 197 198 return false; 199 }); 200 201 show_all (); 202 203 scrollbar.set_visible (false); 204 description.canvas.set_visible (false); 205 206 hide_text_input (); 207 208 MainWindow.open_recent_files_tab (); 209 } 210 211 public void font_loaded () { 212 Font f = BirdFont.get_current_font (); 213 set_title (@"BirdFont $(f.full_name)"); 214 } 215 216 public void set_overwrite_dialog (OverWriteDialogListener d) { 217 Gtk.Dialog dialog = new Gtk.Dialog.with_buttons (d.message, null, 0); 218 219 dialog.add_button (d.overwrite_message, 0); 220 dialog.add_button (d.cancel_message, 1); 221 dialog.add_button (d.dont_ask_again_message, 2); 222 223 dialog.response.connect ((respons) => { 224 switch (respons) { 225 case 0: 226 d.overwrite (); 227 break; 228 case 1: 229 d.cancel (); 230 break; 231 case 2: 232 d.overwrite_dont_ask_again (); 233 break; 234 } 235 dialog.destroy (); 236 }); 237 238 dialog.show_all (); 239 } 240 241 public void set_scrollbar_size (double size) { 242 scrollbar.adjustment.page_size = size; 243 } 244 245 public void set_scrollbar_position (double position) { 246 scrollbar_supress_signal = true; 247 scrollbar.adjustment.value = position * (1 - scrollbar.adjustment.page_size); 248 scrollbar_supress_signal = false; 249 } 250 251 public void color_selection (ColorTool color_tool) { 252 new ColorWindow (color_tool); 253 } 254 255 class ColorWindow : Gtk.Window { 256 257 ColorChooserWidget color_selection; 258 259 public ColorWindow (ColorTool color_tool) { 260 Gtk.Button set_button; 261 262 title = t_("Select color"); 263 window_position = Gtk.WindowPosition.CENTER; 264 265 Box box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); 266 add (box); 267 268 color_selection = new Gtk.ColorChooserWidget (); 269 box.add (color_selection); 270 271 color_selection.show_editor = true; 272 273 color_selection.color_activated.connect ((color) => { 274 Gdk.RGBA c = color_selection.rgba; 275 color_tool.color_r = c.red; 276 color_tool.color_g = c.green; 277 color_tool.color_b = c.blue; 278 color_tool.color_a = c.alpha; 279 color_tool.color_updated (); 280 }); 281 282 color_selection.color_activated.connect (() => { 283 Gdk.RGBA c = new Gdk.RGBA (); 284 c.red = color_tool.color_r; 285 c.green = color_tool.color_g; 286 c.blue = color_tool.color_b; 287 c.alpha = color_tool.color_a; 288 color_selection.rgba = c; 289 }); 290 291 set_button = new Gtk.Button.with_label (_("Set")); 292 box.add (set_button); 293 294 set_button.clicked.connect (() => { 295 Gdk.RGBA c = color_selection.rgba; 296 color_tool.color_r = c.red; 297 color_tool.color_g = c.green; 298 color_tool.color_b = c.blue; 299 color_tool.color_a = c.alpha; 300 color_tool.color_updated (); 301 }); 302 303 show_all (); 304 } 305 } 306 307 public void dump_clipboard_content (Clipboard clipboard, SelectionData selection_data) { 308 string d; 309 return_if_fail (!is_null (selection_data)); 310 d = (string) ((!) selection_data); 311 stdout.printf (d); 312 } 313 314 public void dump_clipboard_target (Clipboard clipboard, Atom[] atoms) { 315 foreach (Atom target in atoms) { 316 print ("Target: " + target.name () + "\n"); 317 clipboard.request_contents (target, dump_clipboard_content); 318 } 319 } 320 321 public void dump_clipboard () { 322 clipboard.request_targets (dump_clipboard_target); 323 } 324 325 public string get_clipboard_data () { 326 SelectionData? selection_data; 327 Atom target; 328 string? t; 329 330 target = Atom.intern_static_string ("image/x-inkscape-svg"); 331 selection_data = clipboard.wait_for_contents (target); 332 333 if (!is_null (selection_data)) { 334 return (string) (((!) selection_data).get_data ()); 335 } 336 337 t = clipboard.wait_for_text (); 338 if (t != null) { 339 return (!) t; 340 } 341 342 return ""; 343 } 344 345 public void set_inkscape_clipboard (string inkscape_clipboard_data) { 346 if (BirdFont.mac) { 347 clipboard.set_text (inkscape_clipboard_data, -1); 348 } else { 349 TargetEntry t = { "image/x-inkscape-svg", 0, 0 }; 350 TargetEntry[] targets = { t }; 351 inkscape_clipboard = inkscape_clipboard_data; 352 353 // we can not add data to this closure because the third argument 354 // is owner and not private data. 355 clipboard.set_with_owner (targets, 356 357 // obtain clipboard data 358 (clipboard, selection_data, info, owner) => { 359 Atom type; 360 uchar[] data = (uchar[])(!)((GtkWindow*)owner)->inkscape_clipboard.to_utf8 (); 361 type = Atom.intern_static_string ("image/x-inkscape-svg"); 362 selection_data.set (type, 8, data); 363 }, 364 365 // clear clipboard data 366 (clipboard, user_data) => { 367 }, 368 369 this); 370 } 371 } 372 373 public void set_clipboard_text (string text) { 374 clipboard.set_text (text, -1); 375 } 376 377 public string get_clipboard_text () { 378 string? t; 379 380 t = clipboard.wait_for_text (); 381 if (t != null) { 382 return ((!) t).dup (); 383 } 384 385 return "".dup (); 386 } 387 388 public void set_clipboard (string svg) { 389 TargetEntry t = { "image/svg+xml", 0, 0 }; 390 TargetEntry[] targets = { t }; 391 clipboard_svg = svg; 392 clipboard.set_with_owner (targets, 393 394 // obtain clipboard data 395 (clipboard, selection_data, info, owner) => { 396 Atom type; 397 uchar[] data = (uchar[])(!)((GtkWindow*)owner)->clipboard_svg.to_utf8 (); 398 type = Atom.intern_static_string ("image/svg+xml"); 399 selection_data.set (type, 0, data); 400 }, 401 402 // clear clipboard data 403 (clipboard, user_data) => { 404 }, 405 406 this); 407 } 408 409 public void update_window_size () { 410 int w, h; 411 get_size (out w, out h); 412 413 Preferences.set ("window_width", @"$w"); 414 Preferences.set ("window_height", @"$h"); 415 } 416 417 private void set_size_and_position () { 418 int w = Preferences.get_window_width (); 419 int h = Preferences.get_window_height (); 420 set_default_size (w, h); 421 } 422 423 public void quit () { 424 Gtk.main_quit (); 425 } 426 427 public void file_chooser (string title, FileChooser fc, uint flags) { 428 string? fn = null; 429 430 if (BirdFont.get_arguments () .has_argument ("--windows")) { 431 MenuTab.show_file_dialog_tab (title, fc); 432 } else { 433 if ((flags & FileChooser.LOAD) > 0) { 434 fn = show_file_chooser (title, FileChooserAction.OPEN, Stock.OPEN); 435 } else if ((flags & FileChooser.SAVE) > 0) { 436 fn = show_file_chooser (title, FileChooserAction.SAVE, Stock.SAVE); 437 } else { 438 warning ("Unknown type"); 439 } 440 } 441 442 fc.selected (fn); 443 } 444 445 public string? show_file_chooser (string title, FileChooserAction action, string label) { 446 string? fn = null; 447 FileChooserDialog file_chooser = new FileChooserDialog (title, this, action, Stock.CANCEL, ResponseType.CANCEL, label, ResponseType.ACCEPT); 448 Font font = BirdFont.get_current_font (); 449 int i; 450 string last_folder; 451 452 last_folder = Preferences.get ("last_folder"); 453 454 try { 455 if (last_folder == "") { 456 file_chooser.set_current_folder_file (font.get_folder ()); 457 } else { 458 file_chooser.set_current_folder_file (File.new_for_path (last_folder)); 459 } 460 } catch (GLib.Error e) { 461 stderr.printf (e.message); 462 } 463 464 if (file_chooser.run () == ResponseType.ACCEPT) { 465 GlyphCanvas.redraw (); 466 fn = file_chooser.get_filename (); 467 } 468 469 file_chooser.destroy (); 470 471 if (fn != null) { 472 i = ((!) fn).last_index_of ("/"); 473 if (i > -1) { 474 last_folder = ((!) fn).substring (0, i); 475 Preferences.set ("last_folder", @"$last_folder"); 476 } 477 } 478 479 return fn; 480 } 481 482 public void hide_text_input () { 483 text_listener = new TextListener ("", "", ""); 484 text_box.hide (); 485 text_input_is_active = false; 486 } 487 488 public void set_text_listener (TextListener listener) { 489 text_listener = listener; 490 text_input_label.set_text (" " + listener.label); 491 submit_text_button.set_label (listener.button_label); 492 text_box.show (); 493 text_entry.set_text (listener.default_text); 494 text_entry.activate.connect (() => { 495 text_listener.signal_submit (text_entry.text); 496 text_input_is_active = false; 497 }); 498 text_entry.grab_focus (); 499 text_input_is_active = true; 500 } 501 502 public bool convert_to_png (string from, string to) { 503 Pixbuf pixbuf; 504 string folder; 505 int i; 506 507 try { 508 i = to.last_index_of ("/"); 509 if (i != -1) { 510 folder = to.substring (0, i); 511 DirUtils.create (folder, 0xFFFFFF); 512 } 513 514 pixbuf = new Pixbuf.from_file (from); 515 pixbuf.save (to, "png"); 516 } catch (GLib.Error e) { 517 warning (e.message); 518 return false; 519 } 520 521 return true; 522 } 523 524 // TODO: add the default tooltip style to the label 525 public void show_tooltip (string tooltip, int x, int y) { 526 Label tooltip_label; 527 int parent_x, parent_y; 528 int tool_box_x, tool_box_y; 529 int posx, posy; 530 Gtk.Allocation label_allocation; 531 Gtk.Box box; 532 533 box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); 534 535 get_position (out parent_x, out parent_y); 536 toolbox.translate_coordinates (toolbox.get_toplevel (), 0, 0, out tool_box_x, out tool_box_y); 537 538 tooltip_window.hide (); 539 540 tooltip_window = new Gtk.Window (Gtk.WindowType.POPUP); 541 tooltip_label = new Label(tooltip); 542 tooltip_label.margin = 0; 543 544 box.pack_start (tooltip_label, true, true, 0); 545 546 tooltip_window.add (box); 547 tooltip_label.show(); 548 box.show (); 549 550 posx = parent_x + tool_box_x + x; 551 posy = parent_y + tool_box_y + y - 7; 552 tooltip_window.move (posx, posy); 553 554 tooltip_window.show(); 555 556 label_allocation = new Gtk.Allocation (); 557 tooltip_label.size_allocate (label_allocation); 558 559 // move label to the left if it is off screen 560 if (posx + label_allocation.width > screen.get_width () - 20) { 561 tooltip_window.move (screen.get_width () - label_allocation.width - 20, posy); 562 } 563 564 } 565 566 public void hide_tooltip () { 567 tooltip_window.hide (); 568 } 569 570 public void run_background_thread (Task t) { 571 unowned Thread<void*> bg; 572 573 MenuTab.start_background_thread (); 574 background_task = t; 575 576 try { 577 bg = Thread.create<void*> (this.background_thread, true); 578 } catch (GLib.Error e) { 579 warning (e.message); 580 } 581 } 582 583 public void* background_thread () { 584 background_task.run (); 585 MenuTab.stop_background_thread (); 586 return null; 587 } 588 589 /** Run export in a background thread. */ 590 public void export_font () { 591 unowned Thread<void*> export_thread; 592 593 MenuTab.start_background_thread (); 594 595 try { 596 export_thread = Thread.create<void*> (this.export_thread, true); 597 } catch (GLib.Error e) { 598 warning (e.message); 599 } 600 } 601 602 public void* export_thread () { 603 IdleSource idle = new IdleSource (); 604 605 ExportCallback.export_fonts (); 606 MenuTab.stop_background_thread (); 607 MenuTab.signal_file_exported (); 608 609 idle.set_callback (() => { 610 Notify.Notification export_notification; 611 export_notification = new Notify.Notification ("BirdFont", t_("Your fonts have been exported."), null); 612 export_notification.show (); 613 return false; 614 }); 615 idle.attach (null); 616 617 return null; 618 } 619 620 /** Load font in a background thread. */ 621 public void load () { 622 unowned Thread<void*> thread; 623 624 MenuTab.start_background_thread (); 625 626 try { 627 thread = Thread.create<void*> (this.loading_thread, true); 628 } catch (GLib.Error e) { 629 warning (e.message); 630 } 631 } 632 633 public void* loading_thread () { 634 BirdFont.get_current_font ().load (); 635 MenuTab.stop_background_thread (); 636 MenuTab.signal_file_loaded (); 637 return null; 638 } 639 640 /** Save font in a background thread. */ 641 public void save () { 642 unowned Thread<void*> thread; 643 644 MenuTab.start_background_thread (); 645 646 try { 647 thread = Thread.create<void*> (this.saving_thread, true); 648 } catch (GLib.Error e) { 649 warning (e.message); 650 } 651 } 652 653 public void* saving_thread () { 654 BirdFont.get_current_font ().save (); 655 MenuTab.stop_background_thread (); 656 MenuTab.signal_file_saved (); 657 return null; 658 } 659 660 public void load_background_image () { 661 unowned Thread<void*> thread; 662 663 MenuTab.start_background_thread (); 664 665 try { 666 thread = Thread.create<void*> (this.background_image_thread, true); 667 } catch (GLib.Error e) { 668 warning (e.message); 669 } 670 } 671 672 public void* background_image_thread () { 673 BackgroundTool.load_background_image (); 674 MenuTab.stop_background_thread (); 675 return null; 676 } 677 678 public bool can_export () { 679 return true; 680 } 681 } 682 683 class TabbarCanvas : DrawingArea { 684 TabBar tabbar; 685 686 public TabbarCanvas (TabBar tb) { 687 tabbar = tb; 688 689 // FIXME: DELETE set_extension_events (ExtensionMode.CURSOR | EventMask.POINTER_MOTION_MASK); 690 add_events (EventMask.BUTTON_PRESS_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK); 691 692 motion_notify_event.connect ((t, e)=> { 693 Gtk.Allocation alloc; 694 tabbar.motion (e.x, e.y); 695 get_allocation (out alloc); 696 queue_draw_area (0, 0, alloc.width, alloc.height); 697 return true; 698 }); 699 700 button_press_event.connect ((t, e)=> { 701 Gtk.Allocation alloc; 702 get_allocation (out alloc); 703 tabbar.select_tab_click (e.x, e.y, alloc.width, alloc.height); 704 queue_draw_area (0, 0, alloc.width, alloc.height); 705 return true; 706 }); 707 708 draw.connect ((t, e)=> { 709 Gtk.Allocation alloc; 710 Context cr; 711 StyleContext context; 712 Gdk.RGBA color; 713 714 cr = cairo_create (get_window ()); 715 get_allocation (out alloc); 716 717 context = get_style_context (); 718 context.add_class (STYLE_CLASS_BUTTON); 719 color = context.get_background_color (Gtk.StateFlags.NORMAL); 720 721 if (color.alpha > 0) { 722 tabbar.set_background_color (color.red, color.green, color.blue); 723 } 724 725 tabbar.draw (cr, alloc.width, alloc.height); 726 return true; 727 }); 728 729 tabbar.signal_tab_selected.connect ((t) => { 730 Gtk.Allocation alloc; 731 get_allocation (out alloc); 732 queue_draw_area (0, 0, alloc.width, alloc.height); 733 }); 734 735 tabbar.redraw_tab_bar.connect ((x, y, w, h) => { 736 queue_draw_area (x, y, w, h); 737 }); 738 739 set_size_request (20, 38); 740 } 741 742 } 743 744 class ToolboxCanvas : DrawingArea { 745 Toolbox tb; 746 747 public ToolboxCanvas (Toolbox toolbox) { 748 tb = toolbox; 749 750 realize.connect (() => { 751 Gtk.Allocation allocation; 752 get_allocation (out allocation); 753 Toolbox.allocation_width = allocation.width; 754 Toolbox.allocation_height = allocation.height; 755 Toolbox.redraw_tool_box (); 756 }); 757 758 tb.redraw.connect ((x, y, w, h) => { 759 queue_draw_area (x, y, w, h); 760 }); 761 762 button_press_event.connect ((se, e)=> { 763 if (e.type != EventType.2BUTTON_PRESS) { 764 tb.press (e.button, e.x, e.y); 765 } 766 return true; 767 }); 768 769 button_release_event.connect ((se, e)=> { 770 tb.release (e.button, e.x, e.y); 771 return true; 772 }); 773 774 motion_notify_event.connect ((sen, e)=> { 775 tb.move (e.x, e.y); 776 return true; 777 }); 778 779 draw.connect ((t, e)=> { 780 Gtk.Allocation allocation; 781 get_allocation (out allocation); 782 783 Context cw = cairo_create(get_window()); 784 Toolbox.allocation_width = allocation.width; 785 Toolbox.allocation_height = allocation.height; 786 tb.draw (allocation.width, allocation.height, cw); 787 788 return true; 789 }); 790 791 scroll_event.connect ((t, e)=> { 792 if (e.direction == Gdk.ScrollDirection.UP) { 793 tb.scroll_up (e.x, e.y); 794 } else if (e.direction == Gdk.ScrollDirection.DOWN) { 795 tb.scroll_down (e.x, e.y); 796 } 797 return true; 798 }); 799 800 add_events (EventMask.BUTTON_PRESS_MASK | EventMask.BUTTON_RELEASE_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK | EventMask.SCROLL_MASK); 801 802 set_size_request (170, 100); 803 804 leave_notify_event.connect ((t, e)=> { 805 tb.reset_active_tool (); 806 return true; 807 }); 808 809 } 810 } 811 812 public class GlyphCanvasArea : DrawingArea { 813 GlyphCanvas glyph_canvas; 814 WidgetAllocation alloc = new WidgetAllocation (); 815 816 public GlyphCanvasArea (GlyphCanvas gc) { 817 int event_flags; 818 819 glyph_canvas = gc; 820 821 event_flags = EventMask.BUTTON_PRESS_MASK; 822 event_flags |= EventMask.BUTTON_RELEASE_MASK; 823 event_flags |= EventMask.POINTER_MOTION_MASK; 824 event_flags |= EventMask.LEAVE_NOTIFY_MASK; 825 event_flags |= EventMask.SCROLL_MASK; 826 827 add_events (event_flags); 828 829 glyph_canvas.signal_redraw_area.connect ((x, y, w, h) => { 830 queue_draw_area ((int)x, (int)y, (int)w, (int)h); 831 }); 832 833 draw.connect ((t, e)=> { 834 Gtk.Allocation allocation; 835 get_allocation (out allocation); 836 837 alloc = new WidgetAllocation (); 838 839 alloc.width = allocation.width; 840 alloc.height = allocation.height; 841 alloc.x = allocation.x; 842 alloc.y = allocation.y; 843 844 Context cw = cairo_create (get_window()); 845 846 Surface s = new Surface.similar (cw.get_target (), Cairo.Content.COLOR_ALPHA, alloc.width, alloc.height); 847 Context c = new Context (s); 848 849 TabContent.draw (alloc, c); 850 851 cw.save (); 852 cw.set_source_surface (c.get_target (), 0, 0); 853 cw.paint (); 854 cw.restore (); 855 856 return true; 857 }); 858 859 button_press_event.connect ((t, e)=> { 860 if (e.type == EventType.BUTTON_PRESS) { 861 TabContent.button_press (e.button, e.x, e.y); 862 } else if (e.type == EventType.2BUTTON_PRESS) { 863 TabContent.double_click (e.button, e.x, e.y); 864 } 865 866 return true; 867 }); 868 869 button_release_event.connect ((t, e)=> { 870 TabContent.button_release ((int) e.button, e.x, e.y); 871 return true; 872 }); 873 874 motion_notify_event.connect ((t, e)=> { 875 TabContent.motion_notify (e.x, e.y); 876 return true; 877 }); 878 879 scroll_event.connect ((t, e)=> { 880 if (e.direction == Gdk.ScrollDirection.UP) { 881 TabContent.scroll_wheel_up (e.x, e.y); 882 } else if (e.direction == Gdk.ScrollDirection.DOWN) { 883 TabContent.scroll_wheel_down (e.x, e.y) ; 884 } 885 886 TabContent.button_release (2, e.x, e.y); 887 return true; 888 }); 889 890 can_focus = true; 891 } 892 } 893 894 public class DescriptionForm : GLib.Object { 895 896 public ScrolledWindow canvas; 897 public Box box; 898 899 Entry postscript_name; 900 Entry font_name; 901 Entry style; 902 CheckButton bold; 903 CheckButton italic; 904 Entry weight; 905 Entry full_name; 906 Entry id; 907 Entry version; 908 909 TextView description; 910 TextView copyright; 911 912 public DescriptionForm () { 913 box = new Box (Orientation.VERTICAL, 6); 914 canvas = new ScrolledWindow (null, null); 915 canvas.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); 916 917 postscript_name = new Entry (); 918 add_entry (postscript_name, t_("PostScript Name")); 919 postscript_name.changed.connect (() => { 920 Font f = BirdFont.get_current_font (); 921 f.postscript_name = postscript_name.text; 922 }); 923 924 font_name = new Entry (); 925 add_entry (font_name, t_("Name")); 926 font_name.changed.connect (() => { 927 Font f = BirdFont.get_current_font (); 928 f.name = font_name.text; 929 }); 930 931 style = new Entry (); 932 add_entry (style, t_("Style")); 933 style.changed.connect (() => { 934 Font f = BirdFont.get_current_font (); 935 f.subfamily = style.text; 936 }); 937 938 bold = new CheckButton.with_label (t_("Bold")); 939 bold.toggled.connect (() => { 940 Font f = BirdFont.get_current_font (); 941 f.bold = bold.active;; 942 }); 943 box.pack_start (bold, false, false, 0); 944 945 italic = new CheckButton.with_label (t_("Italic")); 946 italic.toggled.connect (() => { 947 Font f = BirdFont.get_current_font (); 948 f.italic = italic.active;; 949 }); 950 box.pack_start (italic, false, false, 0); 951 952 weight = new Entry (); 953 add_entry (weight, t_("Weight")); 954 weight.changed.connect (() => { 955 Font f = BirdFont.get_current_font (); 956 f.set_weight (weight.text); 957 }); 958 959 full_name = new Entry (); 960 add_entry (full_name, t_("Full name (name and style)")); 961 full_name.changed.connect (() => { 962 Font f = BirdFont.get_current_font (); 963 f.full_name = full_name.text; 964 }); 965 966 id = new Entry (); 967 add_entry (id, t_("Unique identifier")); 968 id.changed.connect (() => { 969 Font f = BirdFont.get_current_font (); 970 f.unique_identifier = id.text; 971 }); 972 973 version = new Entry (); 974 add_entry (version, t_("Version")); 975 version.changed.connect (() => { 976 Font f = BirdFont.get_current_font (); 977 f.version = version.text; 978 }); 979 980 description = new TextView (); 981 add_textview (description, t_("Description")); 982 description.get_buffer ().changed.connect (() => { 983 Font f = BirdFont.get_current_font (); 984 f.description = description.get_buffer ().text; 985 }); 986 description.set_wrap_mode (Gtk.WrapMode.WORD); 987 988 copyright = new TextView (); 989 add_textview (copyright, t_("Copyright")); 990 copyright.get_buffer ().changed.connect (() => { 991 Font f = BirdFont.get_current_font (); 992 f.copyright = copyright.get_buffer ().text; 993 }); 994 copyright.set_wrap_mode (Gtk.WrapMode.WORD); 995 996 update_fields (); 997 998 canvas.add_with_viewport (box); 999 canvas.show_all (); 1000 } 1001 1002 public void update_fields () { 1003 Font font = BirdFont.get_current_font (); 1004 1005 return_if_fail (font.postscript_name.validate ()); 1006 return_if_fail (font.name.validate ()); 1007 return_if_fail (font.subfamily.validate ()); 1008 return_if_fail (font.full_name.validate ()); 1009 return_if_fail (font.unique_identifier.validate ()); 1010 return_if_fail (font.version.validate ()); 1011 return_if_fail (font.description.validate ()); 1012 return_if_fail (font.copyright.validate ()); 1013 1014 postscript_name.set_text (font.postscript_name); 1015 font_name.set_text (font.name); 1016 style.set_text (font.subfamily); 1017 bold.active = font.bold; 1018 italic.active = font.italic; 1019 weight.set_text (font.get_weight ()); 1020 full_name.set_text (font.full_name); 1021 id.set_text (font.unique_identifier); 1022 version.set_text (font.version); 1023 1024 description.get_buffer ().set_text (font.description.dup ()); 1025 copyright.get_buffer ().set_text (font.copyright.dup ()); 1026 1027 } 1028 1029 void add_entry (Entry e, string label) { 1030 Box vb; 1031 Box hb; 1032 Label l; 1033 Box margin; 1034 1035 margin = new Box (Orientation.HORIZONTAL, 6); 1036 l = new Label (label); 1037 vb = new Box (Orientation.VERTICAL, 2); 1038 hb = new Box (Orientation.HORIZONTAL, 2); 1039 hb.pack_start (l, false, false, 0); 1040 vb.pack_start (hb, true, true, 5); 1041 vb.pack_start (e, true, true, 0); 1042 margin.pack_start (vb, true, true, 5); 1043 box.pack_start (margin, false, false, 5); 1044 } 1045 1046 void add_textview (TextView t, string label) { 1047 Box vb; 1048 Box hb; 1049 Label l; 1050 Box margin; 1051 1052 margin = new Box (Orientation.HORIZONTAL, 6); 1053 l = new Label (label); 1054 vb = new Box (Orientation.VERTICAL, 2); 1055 hb = new Box (Orientation.HORIZONTAL, 2); 1056 hb.pack_start (l, false, false, 0); 1057 vb.pack_start (hb, true, true, 5); 1058 vb.pack_start (t, true, true, 0); 1059 margin.pack_start (vb, true, true, 5); 1060 box.pack_start (margin, false, false, 5); 1061 } 1062 } 1063 1064 } 1065