.
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 public void run_background_thread (Task t) {
525 unowned Thread<void*> bg;
526
527 MenuTab.start_background_thread ();
528 background_task = t;
529
530 try {
531 bg = Thread.create<void*> (this.background_thread, true);
532 } catch (GLib.Error e) {
533 warning (e.message);
534 }
535 }
536
537 public void* background_thread () {
538 background_task.run ();
539 MenuTab.stop_background_thread ();
540 return null;
541 }
542
543 /** Run export in a background thread. */
544 public void export_font () {
545 unowned Thread<void*> export_thread;
546
547 MenuTab.start_background_thread ();
548
549 try {
550 export_thread = Thread.create<void*> (this.export_thread, true);
551 } catch (GLib.Error e) {
552 warning (e.message);
553 }
554 }
555
556 public void* export_thread () {
557 IdleSource idle = new IdleSource ();
558
559 ExportCallback.export_fonts ();
560 MenuTab.stop_background_thread ();
561 MenuTab.signal_file_exported ();
562
563 idle.set_callback (() => {
564 Notify.Notification export_notification;
565 export_notification = new Notify.Notification ("BirdFont", t_("Your fonts have been exported."), null);
566 export_notification.show ();
567 return false;
568 });
569 idle.attach (null);
570
571 return null;
572 }
573
574 /** Load font in a background thread. */
575 public void load () {
576 unowned Thread<void*> thread;
577
578 MenuTab.start_background_thread ();
579
580 try {
581 thread = Thread.create<void*> (this.loading_thread, true);
582 } catch (GLib.Error e) {
583 warning (e.message);
584 }
585 }
586
587 public void* loading_thread () {
588 BirdFont.get_current_font ().load ();
589 MenuTab.stop_background_thread ();
590 MenuTab.signal_file_loaded ();
591 return null;
592 }
593
594 /** Save font in a background thread. */
595 public void save () {
596 unowned Thread<void*> thread;
597
598 MenuTab.start_background_thread ();
599
600 try {
601 thread = Thread.create<void*> (this.saving_thread, true);
602 } catch (GLib.Error e) {
603 warning (e.message);
604 }
605 }
606
607 public void* saving_thread () {
608 BirdFont.get_current_font ().save ();
609 MenuTab.stop_background_thread ();
610 MenuTab.signal_file_saved ();
611 return null;
612 }
613
614 public void load_background_image () {
615 unowned Thread<void*> thread;
616
617 MenuTab.start_background_thread ();
618
619 try {
620 thread = Thread.create<void*> (this.background_image_thread, true);
621 } catch (GLib.Error e) {
622 warning (e.message);
623 }
624 }
625
626 public void* background_image_thread () {
627 BackgroundTool.load_background_image ();
628 MenuTab.stop_background_thread ();
629 return null;
630 }
631
632 public bool can_export () {
633 return true;
634 }
635 }
636
637 class TabbarCanvas : DrawingArea {
638 TabBar tabbar;
639
640 public TabbarCanvas (TabBar tb) {
641 tabbar = tb;
642
643 // FIXME: DELETE set_extension_events (ExtensionMode.CURSOR | EventMask.POINTER_MOTION_MASK);
644 add_events (EventMask.BUTTON_PRESS_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK);
645
646 motion_notify_event.connect ((t, e)=> {
647 Gtk.Allocation alloc;
648 tabbar.motion (e.x, e.y);
649 get_allocation (out alloc);
650 queue_draw_area (0, 0, alloc.width, alloc.height);
651 return true;
652 });
653
654 button_press_event.connect ((t, e)=> {
655 Gtk.Allocation alloc;
656 get_allocation (out alloc);
657 tabbar.select_tab_click (e.x, e.y, alloc.width, alloc.height);
658 queue_draw_area (0, 0, alloc.width, alloc.height);
659 return true;
660 });
661
662 draw.connect ((t, e)=> {
663 Gtk.Allocation alloc;
664 Context cr;
665 StyleContext context;
666 Gdk.RGBA color;
667
668 cr = cairo_create (get_window ());
669 get_allocation (out alloc);
670
671 context = get_style_context ();
672 context.add_class (STYLE_CLASS_BUTTON);
673 color = context.get_background_color (Gtk.StateFlags.NORMAL);
674
675 if (color.alpha > 0) {
676 tabbar.set_background_color (color.red, color.green, color.blue);
677 }
678
679 tabbar.draw (cr, alloc.width, alloc.height);
680 return true;
681 });
682
683 tabbar.signal_tab_selected.connect ((t) => {
684 Gtk.Allocation alloc;
685 get_allocation (out alloc);
686 queue_draw_area (0, 0, alloc.width, alloc.height);
687 });
688
689 tabbar.redraw_tab_bar.connect ((x, y, w, h) => {
690 queue_draw_area (x, y, w, h);
691 });
692
693 set_size_request (20, 38);
694 }
695
696 }
697
698 class ToolboxCanvas : DrawingArea {
699 Toolbox tb;
700
701 public ToolboxCanvas (Toolbox toolbox) {
702 tb = toolbox;
703
704 realize.connect (() => {
705 Gtk.Allocation allocation;
706 get_allocation (out allocation);
707 Toolbox.allocation_width = allocation.width;
708 Toolbox.allocation_height = allocation.height;
709 Toolbox.redraw_tool_box ();
710 });
711
712 tb.redraw.connect ((x, y, w, h) => {
713 queue_draw_area (x, y, w, h);
714 });
715
716 button_press_event.connect ((se, e)=> {
717 if (e.type != EventType.2BUTTON_PRESS) {
718 tb.press (e.button, e.x, e.y);
719 }
720 return true;
721 });
722
723 button_release_event.connect ((se, e)=> {
724 tb.release (e.button, e.x, e.y);
725 return true;
726 });
727
728 motion_notify_event.connect ((sen, e)=> {
729 tb.move (e.x, e.y);
730 return true;
731 });
732
733 draw.connect ((t, e)=> {
734 Gtk.Allocation allocation;
735 get_allocation (out allocation);
736
737 Context cw = cairo_create(get_window());
738 Toolbox.allocation_width = allocation.width;
739 Toolbox.allocation_height = allocation.height;
740 tb.draw (allocation.width, allocation.height, cw);
741
742 return true;
743 });
744
745 scroll_event.connect ((t, e)=> {
746 if (e.direction == Gdk.ScrollDirection.UP) {
747 tb.scroll_up (e.x, e.y);
748 } else if (e.direction == Gdk.ScrollDirection.DOWN) {
749 tb.scroll_down (e.x, e.y);
750 }
751 return true;
752 });
753
754 add_events (EventMask.BUTTON_PRESS_MASK | EventMask.BUTTON_RELEASE_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK | EventMask.SCROLL_MASK);
755
756 set_size_request (170, 100);
757
758 leave_notify_event.connect ((t, e)=> {
759 tb.reset_active_tool ();
760 return true;
761 });
762
763 }
764 }
765
766 public class GlyphCanvasArea : DrawingArea {
767 GlyphCanvas glyph_canvas;
768 WidgetAllocation alloc = new WidgetAllocation ();
769
770 public GlyphCanvasArea (GlyphCanvas gc) {
771 int event_flags;
772
773 glyph_canvas = gc;
774
775 event_flags = EventMask.BUTTON_PRESS_MASK;
776 event_flags |= EventMask.BUTTON_RELEASE_MASK;
777 event_flags |= EventMask.POINTER_MOTION_MASK;
778 event_flags |= EventMask.LEAVE_NOTIFY_MASK;
779 event_flags |= EventMask.SCROLL_MASK;
780
781 add_events (event_flags);
782
783 glyph_canvas.signal_redraw_area.connect ((x, y, w, h) => {
784 queue_draw_area ((int)x, (int)y, (int)w, (int)h);
785 });
786
787 draw.connect ((t, e)=> {
788 Gtk.Allocation allocation;
789 get_allocation (out allocation);
790
791 alloc = new WidgetAllocation ();
792
793 alloc.width = allocation.width;
794 alloc.height = allocation.height;
795 alloc.x = allocation.x;
796 alloc.y = allocation.y;
797
798 Context cw = cairo_create (get_window());
799
800 Surface s = new Surface.similar (cw.get_target (), Cairo.Content.COLOR_ALPHA, alloc.width, alloc.height);
801 Context c = new Context (s);
802
803 TabContent.draw (alloc, c);
804
805 cw.save ();
806 cw.set_source_surface (c.get_target (), 0, 0);
807 cw.paint ();
808 cw.restore ();
809
810 return true;
811 });
812
813 button_press_event.connect ((t, e)=> {
814 if (e.type == EventType.BUTTON_PRESS) {
815 TabContent.button_press (e.button, e.x, e.y);
816 } else if (e.type == EventType.2BUTTON_PRESS) {
817 TabContent.double_click (e.button, e.x, e.y);
818 }
819
820 return true;
821 });
822
823 button_release_event.connect ((t, e)=> {
824 TabContent.button_release ((int) e.button, e.x, e.y);
825 return true;
826 });
827
828 motion_notify_event.connect ((t, e)=> {
829 TabContent.motion_notify (e.x, e.y);
830 return true;
831 });
832
833 scroll_event.connect ((t, e)=> {
834 if (e.direction == Gdk.ScrollDirection.UP) {
835 TabContent.scroll_wheel_up (e.x, e.y);
836 } else if (e.direction == Gdk.ScrollDirection.DOWN) {
837 TabContent.scroll_wheel_down (e.x, e.y) ;
838 }
839
840 TabContent.button_release (2, e.x, e.y);
841 return true;
842 });
843
844 can_focus = true;
845 }
846 }
847
848 public class DescriptionForm : GLib.Object {
849
850 public ScrolledWindow canvas;
851 public Box box;
852
853 Entry postscript_name;
854 Entry font_name;
855 Entry style;
856 CheckButton bold;
857 CheckButton italic;
858 Entry weight;
859 Entry full_name;
860 Entry id;
861 Entry version;
862
863 TextView description;
864 TextView copyright;
865
866 public DescriptionForm () {
867 box = new Box (Orientation.VERTICAL, 6);
868 canvas = new ScrolledWindow (null, null);
869 canvas.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
870
871 postscript_name = new Entry ();
872 add_entry (postscript_name, t_("PostScript Name"));
873 postscript_name.changed.connect (() => {
874 Font f = BirdFont.get_current_font ();
875 f.postscript_name = postscript_name.text;
876 });
877
878 font_name = new Entry ();
879 add_entry (font_name, t_("Name"));
880 font_name.changed.connect (() => {
881 Font f = BirdFont.get_current_font ();
882 f.name = font_name.text;
883 });
884
885 style = new Entry ();
886 add_entry (style, t_("Style"));
887 style.changed.connect (() => {
888 Font f = BirdFont.get_current_font ();
889 f.subfamily = style.text;
890 });
891
892 bold = new CheckButton.with_label (t_("Bold"));
893 bold.toggled.connect (() => {
894 Font f = BirdFont.get_current_font ();
895 f.bold = bold.active;;
896 });
897 box.pack_start (bold, false, false, 0);
898
899 italic = new CheckButton.with_label (t_("Italic"));
900 italic.toggled.connect (() => {
901 Font f = BirdFont.get_current_font ();
902 f.italic = italic.active;;
903 });
904 box.pack_start (italic, false, false, 0);
905
906 weight = new Entry ();
907 add_entry (weight, t_("Weight"));
908 weight.changed.connect (() => {
909 Font f = BirdFont.get_current_font ();
910 f.set_weight (weight.text);
911 });
912
913 full_name = new Entry ();
914 add_entry (full_name, t_("Full name (name and style)"));
915 full_name.changed.connect (() => {
916 Font f = BirdFont.get_current_font ();
917 f.full_name = full_name.text;
918 });
919
920 id = new Entry ();
921 add_entry (id, t_("Unique identifier"));
922 id.changed.connect (() => {
923 Font f = BirdFont.get_current_font ();
924 f.unique_identifier = id.text;
925 });
926
927 version = new Entry ();
928 add_entry (version, t_("Version"));
929 version.changed.connect (() => {
930 Font f = BirdFont.get_current_font ();
931 f.version = version.text;
932 });
933
934 description = new TextView ();
935 add_textview (description, t_("Description"));
936 description.get_buffer ().changed.connect (() => {
937 Font f = BirdFont.get_current_font ();
938 f.description = description.get_buffer ().text;
939 });
940 description.set_wrap_mode (Gtk.WrapMode.WORD);
941
942 copyright = new TextView ();
943 add_textview (copyright, t_("Copyright"));
944 copyright.get_buffer ().changed.connect (() => {
945 Font f = BirdFont.get_current_font ();
946 f.copyright = copyright.get_buffer ().text;
947 });
948 copyright.set_wrap_mode (Gtk.WrapMode.WORD);
949
950 update_fields ();
951
952 canvas.add_with_viewport (box);
953 canvas.show_all ();
954 }
955
956 public void update_fields () {
957 Font font = BirdFont.get_current_font ();
958
959 return_if_fail (font.postscript_name.validate ());
960 return_if_fail (font.name.validate ());
961 return_if_fail (font.subfamily.validate ());
962 return_if_fail (font.full_name.validate ());
963 return_if_fail (font.unique_identifier.validate ());
964 return_if_fail (font.version.validate ());
965 return_if_fail (font.description.validate ());
966 return_if_fail (font.copyright.validate ());
967
968 postscript_name.set_text (font.postscript_name);
969 font_name.set_text (font.name);
970 style.set_text (font.subfamily);
971 bold.active = font.bold;
972 italic.active = font.italic;
973 weight.set_text (font.get_weight ());
974 full_name.set_text (font.full_name);
975 id.set_text (font.unique_identifier);
976 version.set_text (font.version);
977
978 description.get_buffer ().set_text (font.description.dup ());
979 copyright.get_buffer ().set_text (font.copyright.dup ());
980
981 }
982
983 void add_entry (Entry e, string label) {
984 Box vb;
985 Box hb;
986 Label l;
987 Box margin;
988
989 margin = new Box (Orientation.HORIZONTAL, 6);
990 l = new Label (label);
991 vb = new Box (Orientation.VERTICAL, 2);
992 hb = new Box (Orientation.HORIZONTAL, 2);
993 hb.pack_start (l, false, false, 0);
994 vb.pack_start (hb, true, true, 5);
995 vb.pack_start (e, true, true, 0);
996 margin.pack_start (vb, true, true, 5);
997 box.pack_start (margin, false, false, 5);
998 }
999
1000 void add_textview (TextView t, string label) {
1001 Box vb;
1002 Box hb;
1003 Label l;
1004 Box margin;
1005
1006 margin = new Box (Orientation.HORIZONTAL, 6);
1007 l = new Label (label);
1008 vb = new Box (Orientation.VERTICAL, 2);
1009 hb = new Box (Orientation.HORIZONTAL, 2);
1010 hb.pack_start (l, false, false, 0);
1011 vb.pack_start (hb, true, true, 5);
1012 vb.pack_start (t, true, true, 0);
1013 margin.pack_start (vb, true, true, 5);
1014 box.pack_start (margin, false, false, 5);
1015 }
1016 }
1017
1018 }
1019