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