.
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 scrollbar.set_visible (size != 0);
244 }
245
246 public void set_scrollbar_position (double position) {
247 scrollbar_supress_signal = true;
248 scrollbar.adjustment.value = position * (1 - scrollbar.adjustment.page_size);
249 scrollbar_supress_signal = false;
250 }
251
252 public void color_selection (ColorTool color_tool) {
253 new ColorWindow (color_tool);
254 }
255
256 class ColorWindow : Gtk.Window {
257
258 ColorChooserWidget color_selection;
259
260 public ColorWindow (ColorTool color_tool) {
261 Gtk.Button set_button;
262
263 title = t_("Select color");
264 window_position = Gtk.WindowPosition.CENTER;
265
266 Box box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
267 add (box);
268
269 color_selection = new Gtk.ColorChooserWidget ();
270 box.add (color_selection);
271
272 color_selection.show_editor = true;
273
274 color_selection.color_activated.connect ((color) => {
275 Gdk.RGBA c = color_selection.rgba;
276 color_tool.color_r = c.red;
277 color_tool.color_g = c.green;
278 color_tool.color_b = c.blue;
279 color_tool.color_a = c.alpha;
280 color_tool.color_updated ();
281 });
282
283 color_selection.color_activated.connect (() => {
284 Gdk.RGBA c = new Gdk.RGBA ();
285 c.red = color_tool.color_r;
286 c.green = color_tool.color_g;
287 c.blue = color_tool.color_b;
288 c.alpha = color_tool.color_a;
289 color_selection.rgba = c;
290 });
291
292 set_button = new Gtk.Button.with_label (_("Set"));
293 box.add (set_button);
294
295 set_button.clicked.connect (() => {
296 Gdk.RGBA c = color_selection.rgba;
297 color_tool.color_r = c.red;
298 color_tool.color_g = c.green;
299 color_tool.color_b = c.blue;
300 color_tool.color_a = c.alpha;
301 color_tool.color_updated ();
302 });
303
304 show_all ();
305 }
306 }
307
308 public void dump_clipboard_content (Clipboard clipboard, SelectionData selection_data) {
309 string d;
310 return_if_fail (!is_null (selection_data));
311 d = (string) ((!) selection_data);
312 stdout.printf (d);
313 }
314
315 public void dump_clipboard_target (Clipboard clipboard, Atom[] atoms) {
316 foreach (Atom target in atoms) {
317 print ("Target: " + target.name () + "\n");
318 clipboard.request_contents (target, dump_clipboard_content);
319 }
320 }
321
322 public void dump_clipboard () {
323 clipboard.request_targets (dump_clipboard_target);
324 }
325
326 public string get_clipboard_data () {
327 SelectionData? selection_data;
328 Atom target;
329 string? t;
330
331 target = Atom.intern_static_string ("image/x-inkscape-svg");
332 selection_data = clipboard.wait_for_contents (target);
333
334 if (!is_null (selection_data)) {
335 return (string) (((!) selection_data).get_data ());
336 }
337
338 t = clipboard.wait_for_text ();
339 if (t != null) {
340 return (!) t;
341 }
342
343 return "";
344 }
345
346 public void set_inkscape_clipboard (string inkscape_clipboard_data) {
347 if (BirdFont.mac) {
348 clipboard.set_text (inkscape_clipboard_data, -1);
349 } else {
350 TargetEntry t = { "image/x-inkscape-svg", 0, 0 };
351 TargetEntry[] targets = { t };
352 inkscape_clipboard = inkscape_clipboard_data;
353
354 // we can not add data to this closure because the third argument
355 // is owner and not private data.
356 clipboard.set_with_owner (targets,
357
358 // obtain clipboard data
359 (clipboard, selection_data, info, owner) => {
360 Atom type;
361 uchar[] data = (uchar[])(!)((GtkWindow*)owner)->inkscape_clipboard.to_utf8 ();
362 type = Atom.intern_static_string ("image/x-inkscape-svg");
363 selection_data.set (type, 8, data);
364 },
365
366 // clear clipboard data
367 (clipboard, user_data) => {
368 },
369
370 this);
371 }
372 }
373
374 public void set_clipboard_text (string text) {
375 clipboard.set_text (text, -1);
376 }
377
378 public string get_clipboard_text () {
379 string? t;
380
381 t = clipboard.wait_for_text ();
382 if (t != null) {
383 return ((!) t).dup ();
384 }
385
386 return "".dup ();
387 }
388
389 public void set_clipboard (string svg) {
390 TargetEntry t = { "image/svg+xml", 0, 0 };
391 TargetEntry[] targets = { t };
392 clipboard_svg = svg;
393 clipboard.set_with_owner (targets,
394
395 // obtain clipboard data
396 (clipboard, selection_data, info, owner) => {
397 Atom type;
398 uchar[] data = (uchar[])(!)((GtkWindow*)owner)->clipboard_svg.to_utf8 ();
399 type = Atom.intern_static_string ("image/svg+xml");
400 selection_data.set (type, 0, data);
401 },
402
403 // clear clipboard data
404 (clipboard, user_data) => {
405 },
406
407 this);
408 }
409
410 public void update_window_size () {
411 int w, h;
412 get_size (out w, out h);
413
414 Preferences.set ("window_width", @"$w");
415 Preferences.set ("window_height", @"$h");
416 }
417
418 private void set_size_and_position () {
419 int w = Preferences.get_window_width ();
420 int h = Preferences.get_window_height ();
421 set_default_size (w, h);
422 }
423
424 public void quit () {
425 Gtk.main_quit ();
426 }
427
428 public void file_chooser (string title, FileChooser fc, uint flags) {
429 string? fn = null;
430
431 if (BirdFont.get_arguments () .has_argument ("--windows")) {
432 MenuTab.show_file_dialog_tab (title, fc);
433 } else {
434 if ((flags & FileChooser.LOAD) > 0) {
435 fn = show_file_chooser (title, FileChooserAction.OPEN, Stock.OPEN);
436 } else if ((flags & FileChooser.SAVE) > 0) {
437 fn = show_file_chooser (title, FileChooserAction.SAVE, Stock.SAVE);
438 } else {
439 warning ("Unknown type");
440 }
441 }
442
443 fc.selected (fn);
444 }
445
446 public string? show_file_chooser (string title, FileChooserAction action, string label) {
447 string? fn = null;
448 FileChooserDialog file_chooser = new FileChooserDialog (title, this, action, Stock.CANCEL, ResponseType.CANCEL, label, ResponseType.ACCEPT);
449 Font font = BirdFont.get_current_font ();
450 int i;
451 string last_folder;
452
453 last_folder = Preferences.get ("last_folder");
454
455 try {
456 if (last_folder == "") {
457 file_chooser.set_current_folder_file (font.get_folder ());
458 } else {
459 file_chooser.set_current_folder_file (File.new_for_path (last_folder));
460 }
461 } catch (GLib.Error e) {
462 stderr.printf (e.message);
463 }
464
465 if (file_chooser.run () == ResponseType.ACCEPT) {
466 GlyphCanvas.redraw ();
467 fn = file_chooser.get_filename ();
468 }
469
470 file_chooser.destroy ();
471
472 if (fn != null) {
473 i = ((!) fn).last_index_of ("/");
474 if (i > -1) {
475 last_folder = ((!) fn).substring (0, i);
476 Preferences.set ("last_folder", @"$last_folder");
477 }
478 }
479
480 return fn;
481 }
482
483 public void hide_text_input () {
484 text_listener = new TextListener ("", "", "");
485 text_box.hide ();
486 text_input_is_active = false;
487 }
488
489 public void set_text_listener (TextListener listener) {
490 text_listener = listener;
491 text_input_label.set_text (" " + listener.label);
492 submit_text_button.set_label (listener.button_label);
493 text_box.show ();
494 text_entry.set_text (listener.default_text);
495 text_entry.activate.connect (() => {
496 text_listener.signal_submit (text_entry.text);
497 text_input_is_active = false;
498 });
499 text_entry.grab_focus ();
500 text_input_is_active = true;
501 }
502
503 public bool convert_to_png (string from, string to) {
504 Pixbuf pixbuf;
505 string folder;
506 int i;
507
508 try {
509 i = to.last_index_of ("/");
510 if (i != -1) {
511 folder = to.substring (0, i);
512 DirUtils.create (folder, 0xFFFFFF);
513 }
514
515 pixbuf = new Pixbuf.from_file (from);
516 pixbuf.save (to, "png");
517 } catch (GLib.Error e) {
518 warning (e.message);
519 return false;
520 }
521
522 return true;
523 }
524
525 public void run_background_thread (Task t) {
526 unowned Thread<void*> bg;
527
528 MenuTab.start_background_thread ();
529 background_task = t;
530
531 try {
532 bg = Thread.create<void*> (this.background_thread, true);
533 } catch (GLib.Error e) {
534 warning (e.message);
535 }
536 }
537
538 public void* background_thread () {
539 background_task.run ();
540 MenuTab.stop_background_thread ();
541 return null;
542 }
543
544 /** Run export in a background thread. */
545 public void export_font () {
546 unowned Thread<void*> export_thread;
547
548 MenuTab.start_background_thread ();
549
550 try {
551 export_thread = Thread.create<void*> (this.export_thread, true);
552 } catch (GLib.Error e) {
553 warning (e.message);
554 }
555 }
556
557 public void* export_thread () {
558 IdleSource idle = new IdleSource ();
559
560 ExportCallback.export_fonts ();
561 MenuTab.stop_background_thread ();
562 MenuTab.signal_file_exported ();
563
564 idle.set_callback (() => {
565 Notify.Notification export_notification;
566 export_notification = new Notify.Notification ("BirdFont", t_("Your fonts have been exported."), null);
567 export_notification.show ();
568 return false;
569 });
570 idle.attach (null);
571
572 return null;
573 }
574
575 /** Load font in a background thread. */
576 public void load () {
577 unowned Thread<void*> thread;
578
579 MenuTab.start_background_thread ();
580
581 try {
582 thread = Thread.create<void*> (this.loading_thread, true);
583 } catch (GLib.Error e) {
584 warning (e.message);
585 }
586 }
587
588 public void* loading_thread () {
589 BirdFont.get_current_font ().load ();
590 MenuTab.stop_background_thread ();
591 MenuTab.signal_file_loaded ();
592 return null;
593 }
594
595 /** Save font in a background thread. */
596 public void save () {
597 unowned Thread<void*> thread;
598
599 MenuTab.start_background_thread ();
600
601 try {
602 thread = Thread.create<void*> (this.saving_thread, true);
603 } catch (GLib.Error e) {
604 warning (e.message);
605 }
606 }
607
608 public void* saving_thread () {
609 BirdFont.get_current_font ().save ();
610 MenuTab.stop_background_thread ();
611 MenuTab.signal_file_saved ();
612 return null;
613 }
614
615 public void load_background_image () {
616 unowned Thread<void*> thread;
617
618 MenuTab.start_background_thread ();
619
620 try {
621 thread = Thread.create<void*> (this.background_image_thread, true);
622 } catch (GLib.Error e) {
623 warning (e.message);
624 }
625 }
626
627 public void* background_image_thread () {
628 BackgroundTool.load_background_image ();
629 MenuTab.stop_background_thread ();
630 return null;
631 }
632
633 public bool can_export () {
634 return true;
635 }
636 }
637
638 class TabbarCanvas : DrawingArea {
639 TabBar tabbar;
640
641 public TabbarCanvas (TabBar tb) {
642 tabbar = tb;
643
644 // FIXME: DELETE set_extension_events (ExtensionMode.CURSOR | EventMask.POINTER_MOTION_MASK);
645 add_events (EventMask.BUTTON_PRESS_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK);
646
647 motion_notify_event.connect ((t, e)=> {
648 Gtk.Allocation alloc;
649 tabbar.motion (e.x, e.y);
650 get_allocation (out alloc);
651 queue_draw_area (0, 0, alloc.width, alloc.height);
652 return true;
653 });
654
655 button_press_event.connect ((t, e)=> {
656 Gtk.Allocation alloc;
657 get_allocation (out alloc);
658 tabbar.select_tab_click (e.x, e.y, alloc.width, alloc.height);
659 queue_draw_area (0, 0, alloc.width, alloc.height);
660 return true;
661 });
662
663 draw.connect ((t, e)=> {
664 Gtk.Allocation alloc;
665 Context cr;
666 StyleContext context;
667 Gdk.RGBA color;
668
669 cr = cairo_create (get_window ());
670 get_allocation (out alloc);
671
672 context = get_style_context ();
673 context.add_class (STYLE_CLASS_BUTTON);
674 color = context.get_background_color (Gtk.StateFlags.NORMAL);
675
676 if (color.alpha > 0) {
677 tabbar.set_background_color (color.red, color.green, color.blue);
678 }
679
680 tabbar.draw (cr, alloc.width, alloc.height);
681 return true;
682 });
683
684 tabbar.signal_tab_selected.connect ((t) => {
685 Gtk.Allocation alloc;
686 get_allocation (out alloc);
687 queue_draw_area (0, 0, alloc.width, alloc.height);
688 });
689
690 tabbar.redraw_tab_bar.connect ((x, y, w, h) => {
691 queue_draw_area (x, y, w, h);
692 });
693
694 set_size_request (20, 38);
695 }
696
697 }
698
699 class ToolboxCanvas : DrawingArea {
700 Toolbox tb;
701
702 public ToolboxCanvas (Toolbox toolbox) {
703 tb = toolbox;
704
705 realize.connect (() => {
706 Gtk.Allocation allocation;
707 get_allocation (out allocation);
708 Toolbox.allocation_width = allocation.width;
709 Toolbox.allocation_height = allocation.height;
710 Toolbox.redraw_tool_box ();
711 });
712
713 tb.redraw.connect ((x, y, w, h) => {
714 queue_draw_area (x, y, w, h);
715 });
716
717 button_press_event.connect ((se, e)=> {
718 if (e.type != EventType.2BUTTON_PRESS) {
719 tb.press (e.button, e.x, e.y);
720 }
721 return true;
722 });
723
724 button_release_event.connect ((se, e)=> {
725 tb.release (e.button, e.x, e.y);
726 return true;
727 });
728
729 motion_notify_event.connect ((sen, e)=> {
730 tb.move (e.x, e.y);
731 return true;
732 });
733
734 draw.connect ((t, e)=> {
735 Gtk.Allocation allocation;
736 get_allocation (out allocation);
737
738 Context cw = cairo_create(get_window());
739 Toolbox.allocation_width = allocation.width;
740 Toolbox.allocation_height = allocation.height;
741 tb.draw (allocation.width, allocation.height, cw);
742
743 return true;
744 });
745
746 scroll_event.connect ((t, e)=> {
747 if (e.direction == Gdk.ScrollDirection.UP) {
748 tb.scroll_up (e.x, e.y);
749 } else if (e.direction == Gdk.ScrollDirection.DOWN) {
750 tb.scroll_down (e.x, e.y);
751 }
752 return true;
753 });
754
755 add_events (EventMask.BUTTON_PRESS_MASK | EventMask.BUTTON_RELEASE_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK | EventMask.SCROLL_MASK);
756
757 set_size_request (170, 100);
758
759 leave_notify_event.connect ((t, e)=> {
760 tb.reset_active_tool ();
761 return true;
762 });
763
764 }
765 }
766
767 public class GlyphCanvasArea : DrawingArea {
768 GlyphCanvas glyph_canvas;
769 WidgetAllocation alloc = new WidgetAllocation ();
770
771 public GlyphCanvasArea (GlyphCanvas gc) {
772 int event_flags;
773
774 glyph_canvas = gc;
775
776 event_flags = EventMask.BUTTON_PRESS_MASK;
777 event_flags |= EventMask.BUTTON_RELEASE_MASK;
778 event_flags |= EventMask.POINTER_MOTION_MASK;
779 event_flags |= EventMask.LEAVE_NOTIFY_MASK;
780 event_flags |= EventMask.SCROLL_MASK;
781
782 add_events (event_flags);
783
784 glyph_canvas.signal_redraw_area.connect ((x, y, w, h) => {
785 queue_draw_area ((int)x, (int)y, (int)w, (int)h);
786 });
787
788 draw.connect ((t, e)=> {
789 Gtk.Allocation allocation;
790 get_allocation (out allocation);
791
792 alloc = new WidgetAllocation ();
793
794 alloc.width = allocation.width;
795 alloc.height = allocation.height;
796 alloc.x = allocation.x;
797 alloc.y = allocation.y;
798
799 Context cw = cairo_create (get_window());
800
801 Surface s = new Surface.similar (cw.get_target (), Cairo.Content.COLOR_ALPHA, alloc.width, alloc.height);
802 Context c = new Context (s);
803
804 TabContent.draw (alloc, c);
805
806 cw.save ();
807 cw.set_source_surface (c.get_target (), 0, 0);
808 cw.paint ();
809 cw.restore ();
810
811 return true;
812 });
813
814 button_press_event.connect ((t, e)=> {
815 if (e.type == EventType.BUTTON_PRESS) {
816 TabContent.button_press (e.button, e.x, e.y);
817 } else if (e.type == EventType.2BUTTON_PRESS) {
818 TabContent.double_click (e.button, e.x, e.y);
819 }
820
821 return true;
822 });
823
824 button_release_event.connect ((t, e)=> {
825 TabContent.button_release ((int) e.button, e.x, e.y);
826 return true;
827 });
828
829 motion_notify_event.connect ((t, e)=> {
830 TabContent.motion_notify (e.x, e.y);
831 return true;
832 });
833
834 scroll_event.connect ((t, e)=> {
835 if (e.direction == Gdk.ScrollDirection.UP) {
836 TabContent.scroll_wheel_up (e.x, e.y);
837 } else if (e.direction == Gdk.ScrollDirection.DOWN) {
838 TabContent.scroll_wheel_down (e.x, e.y) ;
839 }
840
841 TabContent.button_release (2, e.x, e.y);
842 return true;
843 });
844
845 can_focus = true;
846 }
847 }
848
849 public class DescriptionForm : GLib.Object {
850
851 public ScrolledWindow canvas;
852 public Box box;
853
854 Entry postscript_name;
855 Entry font_name;
856 Entry style;
857 CheckButton bold;
858 CheckButton italic;
859 Entry weight;
860 Entry full_name;
861 Entry id;
862 Entry version;
863
864 TextView description;
865 TextView copyright;
866
867 public DescriptionForm () {
868 box = new Box (Orientation.VERTICAL, 6);
869 canvas = new ScrolledWindow (null, null);
870 canvas.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
871
872 postscript_name = new Entry ();
873 add_entry (postscript_name, t_("PostScript Name"));
874 postscript_name.changed.connect (() => {
875 Font f = BirdFont.get_current_font ();
876 f.postscript_name = postscript_name.text;
877 });
878
879 font_name = new Entry ();
880 add_entry (font_name, t_("Name"));
881 font_name.changed.connect (() => {
882 Font f = BirdFont.get_current_font ();
883 f.name = font_name.text;
884 });
885
886 style = new Entry ();
887 add_entry (style, t_("Style"));
888 style.changed.connect (() => {
889 Font f = BirdFont.get_current_font ();
890 f.subfamily = style.text;
891 });
892
893 bold = new CheckButton.with_label (t_("Bold"));
894 bold.toggled.connect (() => {
895 Font f = BirdFont.get_current_font ();
896 f.bold = bold.active;;
897 });
898 box.pack_start (bold, false, false, 0);
899
900 italic = new CheckButton.with_label (t_("Italic"));
901 italic.toggled.connect (() => {
902 Font f = BirdFont.get_current_font ();
903 f.italic = italic.active;;
904 });
905 box.pack_start (italic, false, false, 0);
906
907 weight = new Entry ();
908 add_entry (weight, t_("Weight"));
909 weight.changed.connect (() => {
910 Font f = BirdFont.get_current_font ();
911 f.set_weight (weight.text);
912 });
913
914 full_name = new Entry ();
915 add_entry (full_name, t_("Full name (name and style)"));
916 full_name.changed.connect (() => {
917 Font f = BirdFont.get_current_font ();
918 f.full_name = full_name.text;
919 });
920
921 id = new Entry ();
922 add_entry (id, t_("Unique identifier"));
923 id.changed.connect (() => {
924 Font f = BirdFont.get_current_font ();
925 f.unique_identifier = id.text;
926 });
927
928 version = new Entry ();
929 add_entry (version, t_("Version"));
930 version.changed.connect (() => {
931 Font f = BirdFont.get_current_font ();
932 f.version = version.text;
933 });
934
935 description = new TextView ();
936 add_textview (description, t_("Description"));
937 description.get_buffer ().changed.connect (() => {
938 Font f = BirdFont.get_current_font ();
939 f.description = description.get_buffer ().text;
940 });
941 description.set_wrap_mode (Gtk.WrapMode.WORD);
942
943 copyright = new TextView ();
944 add_textview (copyright, t_("Copyright"));
945 copyright.get_buffer ().changed.connect (() => {
946 Font f = BirdFont.get_current_font ();
947 f.copyright = copyright.get_buffer ().text;
948 });
949 copyright.set_wrap_mode (Gtk.WrapMode.WORD);
950
951 update_fields ();
952
953 canvas.add_with_viewport (box);
954 canvas.show_all ();
955 }
956
957 public void update_fields () {
958 Font font = BirdFont.get_current_font ();
959
960 return_if_fail (font.postscript_name.validate ());
961 return_if_fail (font.name.validate ());
962 return_if_fail (font.subfamily.validate ());
963 return_if_fail (font.full_name.validate ());
964 return_if_fail (font.unique_identifier.validate ());
965 return_if_fail (font.version.validate ());
966 return_if_fail (font.description.validate ());
967 return_if_fail (font.copyright.validate ());
968
969 postscript_name.set_text (font.postscript_name);
970 font_name.set_text (font.name);
971 style.set_text (font.subfamily);
972 bold.active = font.bold;
973 italic.active = font.italic;
974 weight.set_text (font.get_weight ());
975 full_name.set_text (font.full_name);
976 id.set_text (font.unique_identifier);
977 version.set_text (font.version);
978
979 description.get_buffer ().set_text (font.description.dup ());
980 copyright.get_buffer ().set_text (font.copyright.dup ());
981
982 }
983
984 void add_entry (Entry e, string label) {
985 Box vb;
986 Box hb;
987 Label l;
988 Box margin;
989
990 margin = new Box (Orientation.HORIZONTAL, 6);
991 l = new Label (label);
992 vb = new Box (Orientation.VERTICAL, 2);
993 hb = new Box (Orientation.HORIZONTAL, 2);
994 hb.pack_start (l, false, false, 0);
995 vb.pack_start (hb, true, true, 5);
996 vb.pack_start (e, true, true, 0);
997 margin.pack_start (vb, true, true, 5);
998 box.pack_start (margin, false, false, 5);
999 }
1000
1001 void add_textview (TextView t, string label) {
1002 Box vb;
1003 Box hb;
1004 Label l;
1005 Box margin;
1006
1007 margin = new Box (Orientation.HORIZONTAL, 6);
1008 l = new Label (label);
1009 vb = new Box (Orientation.VERTICAL, 2);
1010 hb = new Box (Orientation.HORIZONTAL, 2);
1011 hb.pack_start (l, false, false, 0);
1012 vb.pack_start (hb, true, true, 5);
1013 vb.pack_start (t, true, true, 0);
1014 margin.pack_start (vb, true, true, 5);
1015 box.pack_start (margin, false, false, 5);
1016 }
1017 }
1018
1019 }
1020