GtkInterface.vala
/*
Copyright (C) 2012 Johan Mattsson
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Cairo;
using Gtk;
using Gdk;
using Supplement;
using WebKit;
namespace Supplement {
public class GtkWindow : Gtk.Window, NativeWindow {
HBox list_box;
HBox canvas_box;
WebView html_canvas;
ScrolledWindow html_box;
VBox tab_box;
static DrawingArea margin_bottom;
static DrawingArea margin_right;
GlyphCanvasArea glyph_canvas_area;
public GtkWindow (string title) {
// set_title (title);
}
public void init () {
margin_bottom = new DrawingArea ();
margin_right = new DrawingArea ();
margin_bottom.set_size_request (0, 0);
margin_right.set_size_request (0, 0);
delete_event.connect (quit);
set_size_and_position ();
html_canvas = new WebView ();
WebKit.set_cache_model (CacheModel.DOCUMENT_VIEWER);
html_canvas.get_settings ().enable_default_context_menu = false;
html_canvas.title_changed.connect ((p, s) => {
webkit_callback (s);
});
html_box = new ScrolledWindow (null, null);
html_box.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
html_box.add (html_canvas);
html_canvas.set_editable (true);
MainWindow.get_tab_bar ().signal_tab_selected.connect ((f, tab) => {
bool n;
File layout_dir;
File layout_uri;
string uri = "";
FontDisplay fd = tab.get_display ();
MainWindow.glyph_canvas.set_current_glyph (fd);
n = fd.is_html_canvas ();
if (n) {
layout_dir = FontDisplay.find_layout_dir ();
uri = fd.get_uri ();
if (uri == "") {
layout_uri = layout_dir.get_child (fd.get_html_file ());
uri = fd.path_to_uri ((!) layout_uri.get_path ());
}
if (fd.get_name () == "Preview") {
ExportTool.export_all ();
}
if (fd.get_html () == "") {
html_canvas.load_html_string ("<html></html>", "file:///");
html_canvas.reload_bypass_cache ();
html_canvas.load_uri (uri);
html_canvas.reload_bypass_cache ();
html_canvas.load_uri (uri);
} else {
html_canvas.load_html_string (fd.get_html (), uri);
}
html_box.set_visible (n);
glyph_canvas_area.set_visible (!n);
} else {
html_box.set_visible (false);
glyph_canvas_area.set_visible (true);
}
});
// Hide this canvas when window is realized and flip canvas
// visibility in tab selection signal.
html_canvas.expose_event.connect ((t, e) => {
glyph_canvas_area.set_visible (false);
return false;
});
MainWindow.tabs.add_unique_tab (MainWindow.content, 60, true);
MainWindow.tabs.select_tab_name ("Menu");
glyph_canvas_area = new GlyphCanvasArea (MainWindow.glyph_canvas);
canvas_box = new HBox (false, 0);
canvas_box.pack_start (glyph_canvas_area, true, true, 0);
canvas_box.pack_start (html_box, true, true, 0);
tab_box = new VBox (false, 0);
tab_box.pack_start (new TabbarCanvas (MainWindow.tabs), false, false, 0);
tab_box.pack_start (canvas_box, true, true, 0);
tab_box.pack_start (MainWindow.tool_tip, false, false, 0);
tab_box.pack_start (margin_bottom, false, false, 0);
list_box = new HBox (false, 0);
list_box.pack_start (tab_box, true, true, 0);
list_box.pack_start (new ToolboxCanvas (MainWindow.tools), false, false, 0);
list_box.pack_start (margin_right, false, false, 0);
add (list_box);
key_snooper_install (MainWindow.global_key_bindings, null);
add_events (EventMask.FOCUS_CHANGE_MASK);
focus_in_event.connect ((t, e)=> {
MainWindow.key_bindings.reset ();
return true;
});
set_icon_from_file ((!) Icons.find_icon ("window_icon.png").get_path ());
show_all ();
}
internal void toggle_expanded_margin_bottom () {
int w, h;
margin_bottom.get_size_request (out w, out h);
if (h == 1) h = 2;
else h = 1;
margin_bottom.set_size_request (w, h);
}
internal void toggle_expanded_margin_right () {
int w, h;
margin_right.get_size_request (out w, out h);
if (w == 1) w = 2;
else w = 1;
margin_right.set_size_request (w, h);
}
public static void hide_cursor () {
Pixmap pixmap = new Pixmap (null, 1, 1, 1);
Color color = { 0, 0, 0, 0 };
Cursor cursor = new Cursor.from_pixmap (pixmap, pixmap, color, color, 0, 0);
// Fixa: But why?
// (Supplement.exe:1300): Gdk-CRITICAL **: gdk_window_set_cursor: assertion `GDK_IS_WINDOW (window)' failed
// singleton.frame.set_cursor (cursor);
}
public void update_window_size () {
int w, h;
get_size (out w, out h);
Preferences.set ("window_width", @"$w");
Preferences.set ("window_height", @"$h");
}
private void set_size_and_position () {
int w = Preferences.get_window_width ();
int h = Preferences.get_window_height ();
set_default_size (w, h);
// move (10, 240);
}
public bool quit () {
bool added;
SaveDialog s = new SaveDialog ();
if (Supplement.get_current_font ().is_modified ()) {
added = MainWindow.get_tab_bar ().add_unique_tab (s, 50);
} else {
added = false;
}
if (!added) {
Supplement.get_current_font ().save_backup ();
Gtk.main_quit ();
}
s.finished.connect (() => {
Supplement.get_current_font ().delete_backup ();
Gtk.main_quit ();
});
return true;
}
public string? file_chooser (string title) {
string? fn = null;
FileChooserDialog file_chooser = new FileChooserDialog (title, this, FileChooserAction.SAVE, Stock.CANCEL, ResponseType.CANCEL, Stock.SAVE, ResponseType.ACCEPT);
Font font = Supplement.get_current_font ();
try {
file_chooser.set_current_folder_file (font.get_folder ());
} catch (GLib.Error e) {
stderr.printf (e.message);
}
if (file_chooser.run () == ResponseType.ACCEPT) {
MainWindow.get_glyph_canvas ().redraw ();
fn = file_chooser.get_filename ();
}
file_chooser.destroy ();
return fn;
}
}
class TabbarCanvas : DrawingArea {
TabBar tabbar;
public TabbarCanvas (TabBar tb) {
tabbar = tb;
set_extension_events (ExtensionMode.CURSOR | EventMask.POINTER_MOTION_MASK);
add_events (EventMask.BUTTON_PRESS_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK);
motion_notify_event.connect ((t, e)=> {
Allocation alloc;
tabbar.motion (e.x, e.y);
get_allocation (out alloc);
queue_draw_area (0, 0, alloc.width, alloc.height);
return true;
});
button_press_event.connect ((t, e)=> {
Allocation alloc;
get_allocation (out alloc);
tabbar.select_tab_click (e.x, e.y, alloc.width, alloc.height);
queue_draw_area (0, 0, alloc.width, alloc.height);
return true;
});
expose_event.connect ((t, e)=> {
Context cr = cairo_create (get_window ());
Allocation alloc;
get_allocation (out alloc);
tabbar.draw (cr, alloc.width, alloc.height);
return true;
});
tabbar.signal_tab_selected.connect ((t) => {
Allocation alloc;
get_allocation (out alloc);
queue_draw_area (0, 0, alloc.width, alloc.height);
});
set_size_request (20, 25);
}
}
class ToolboxCanvas : DrawingArea {
Toolbox tb;
public ToolboxCanvas (Toolbox toolbox) {
tb = toolbox;
tb.redraw.connect ((x, y, w, h) => {
queue_draw_area (x, y, w, h);
});
button_press_event.connect ((se, e)=> {
tb.press (e.button, e.x, e.y);
return true;
});
button_release_event.connect ((se, e)=> {
tb.release (e.button, e.x, e.y);
return true;
});
motion_notify_event.connect ((sen, e)=> {
tb.move (e.x, e.y);
return true;
});
expose_event.connect ((t, e)=> {
Allocation allocation;
get_allocation (out allocation);
Context cw = cairo_create(get_window());
tb.allocation_width = allocation.width;
tb.allocation_height = allocation.height;
tb.draw (allocation.width, allocation.height, cw);
return true;
});
add_events (EventMask.BUTTON_PRESS_MASK | EventMask.BUTTON_RELEASE_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK);
set_size_request (160, 100);
leave_notify_event.connect ((t, e)=> {
tb.reset_active_tool ();
return true;
});
}
}
public class GlyphCanvasArea : DrawingArea {
GlyphCanvas glyph_canvas;
Allocation alloc;
public GlyphCanvasArea (GlyphCanvas gc) {
glyph_canvas = gc;
add_events (EventMask.BUTTON_PRESS_MASK | EventMask.BUTTON_RELEASE_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK | EventMask.SCROLL_MASK);
glyph_canvas.signal_redraw_area.connect ((x, y, w, h) => {
queue_draw_area ((int)x, (int)y, (int)w, (int)h);
});
expose_event.connect ((t, e)=> {
Allocation allocation;
get_allocation (out allocation);
glyph_canvas.allocation = allocation;
if (unlikely (allocation != alloc && alloc.width != 0)) {
// Set size of glyph widget to an even number and notify
// set new allocation for glyph
bool ug = false;
if (allocation.height % 2 != 0) {
MainWindow.native_window.toggle_expanded_margin_bottom ();
ug = true;
}
if (allocation.width % 2 != 0) {
MainWindow.native_window.toggle_expanded_margin_right ();
ug = true;
}
if (ug) {
//redraw_area (1, 1, 2, 2);
} else if (unlikely (allocation.width % 2 != 0 || allocation.height % 2 != 0)) {
warning (@"\nGlyph canvas is not divisible by two.\nWidth: $(allocation.width)\nHeight: $(allocation.height)");
}
Supplement.current_glyph.resized ();
}
alloc = allocation;
Context cw = cairo_create (get_window());
Surface s = new Surface.similar (cw.get_target (), Cairo.Content.COLOR_ALPHA, allocation.width, allocation.height);
Context c = new Context (s);
glyph_canvas.current_display.draw (allocation, c);
cw.save ();
cw.set_source_surface (c.get_target (), 0, 0);
cw.paint ();
cw.restore ();
return true;
});
button_press_event.connect ((t, e)=> {
if (e.type == EventType.BUTTON_PRESS) {
glyph_canvas.current_display.button_press (e.button, e.x, e.y);
} else if (e.type == EventType.2BUTTON_PRESS) {
glyph_canvas.current_display.double_click (e.button, e.x, e.y);
}
return true;
});
button_release_event.connect ((t, e)=> {
glyph_canvas.current_display.button_release ((int) e.button, e.x, e.y);
return true;
});
motion_notify_event.connect ((t, e)=> {
glyph_canvas.current_display.motion_notify (e.x, e.y);
return true;
});
scroll_event.connect ((t, e)=> {
if (e.direction == Gdk.ScrollDirection.UP) {
glyph_canvas.current_display.scroll_wheel_up (e.x, e.y);
} else if (e.direction == Gdk.ScrollDirection.DOWN) {
glyph_canvas.current_display.scroll_wheel_down (e.x, e.y);
}
return true;
});
}
}
}