ContentDisplay.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 Gtk;
using Gdk;
using Cairo;
namespace Supplement {
class ContentDisplay : FontDisplay {
List<Font> recent_fonts = new List<Font> ();
int recent_active = -1;
int open_active = -1;
const int NEW_FONT = 0;
const int LOAD_FONT = 1;
const int SAVE_FONT = 2;
Allocation allocation;
int num_collumns = 0;
Tool new_file_tool;
Tool open_tool;
Tool save_tool;
Tool browser_tool;
Tool export_preferences;
ExportTool export_tool;
Tool kerning_context_tool;
Tool add_new_grid_tool;
Tool delete_grid_tool;
public List<Tool> tools;
StringBuilder name;
int has_modifier = 0;
bool marker = true;
bool show_marker = true;
TimeoutSource marker_blink;
public ContentDisplay () {
new_file_tool = new Tool ("new_file", "New file", 'n', CTRL);
new_file_tool.x = 15;
new_file_tool.y = 25;
new_file_tool.select_action.connect((self) => {
new_file ();
});
open_tool = new Tool ("open", "Open", 'o', CTRL);
open_tool.x = 50;
open_tool.y = 25;
open_tool.select_action.connect((self) => {
load ();
});
save_tool = new Tool ("save", "Save", 's', CTRL);
save_tool.x = 85;
save_tool.y = 25;
save_tool.select_action.connect((self) => {
save ();
});
browser_tool = new Tool ("view_result", "Export font and view result in web browser", ',', CTRL);
browser_tool.x = 120;
browser_tool.y = 25;
browser_tool.select_action.connect((self) => {
export_to_browser ();
});
export_tool = new ExportTool ("export");
export_tool.x = 155;
export_tool.y = 25;
kerning_context_tool = new Tool ("kerning_context", "Show kerning context", 'k', CTRL);
kerning_context_tool.x = 200;
kerning_context_tool.y = 25;
kerning_context_tool.select_action.connect((self) => {
MainWindow.get_tab_bar ().add_unique_tab (new ContextDisplay (), 65, false);
});
export_preferences = new Tool ("export_preferences", "Export preferences");
export_preferences.x = 250;
export_preferences.y = 25;
export_preferences.select_action.connect((self) => {
TabBar t = MainWindow.get_tab_bar ();
t.add_unique_tab (new ExportPreferences (), 75, false);
});
add_new_grid_tool = new Tool ("add_new_grid", "Add new grid");
add_new_grid_tool.x = 15;
add_new_grid_tool.y = 95;
add_new_grid_tool.select_action.connect((self) => {
MainWindow.get_toolbox ().add_new_grid ();
});
delete_grid_tool = new Tool ("delete_grid", "Remove grid");
delete_grid_tool.x = 50;
delete_grid_tool.y = 95;
delete_grid_tool.select_action.connect((self) => {
MainWindow.get_toolbox ().remove_current_grid ();
});
tools = new List<Tool> ();
tools.append (new_file_tool);
tools.append (open_tool);
tools.append (save_tool);
tools.append (browser_tool);
tools.append (kerning_context_tool);
tools.append (add_new_grid_tool);
tools.append (delete_grid_tool);
tools.append (export_tool);
tools.append (export_preferences);
name = new StringBuilder ();
name.append (Supplement.get_current_font ().get_name ());
marker = true;
marker_blink = new TimeoutSource (1200);
marker_blink.set_callback (() => {
show_marker = !show_marker;
MainWindow.get_glyph_canvas ().redraw ();
return marker;
});
marker_blink.attach (null);
propagate_recent_files ();
foreach (Tool t in tools) {
t.set_default_color (1, 1, 1);
}
}
private void save () {
SaveDialog s = new SaveDialog ();
save_dialog (s);
}
private void save_dialog (SaveDialog s) {
FontDisplay fd = MainWindow.get_current_display ();
// display save tab or save font if save dialog is open
if (fd is SaveDialog) {
s = ((SaveDialog) fd);
s.save.select_action (s.save);
} else if (Supplement.get_current_font ().is_modified ()) {
MainWindow.get_tab_bar ().add_unique_tab (s, 50);
} else {
s.finished ();
}
}
private void new_file () {
SaveDialog save = new SaveDialog ();
save.finished.connect (() => {
Font f = Supplement.get_current_font ();
f.delete_backup ();
Supplement.new_font ();
MainWindow.close_all_tabs ();
select_overview ();
});
save_dialog (save);
}
private void load () {
SaveDialog save = new SaveDialog ();
save.finished.connect (() => {
load_new_font ();
});
save_dialog (save);
}
private void export_to_browser () {
export_tool.view_result ();
}
public override string get_name () {
return "Content";
}
public override void draw (Allocation allocation, Context cr) {
this.allocation = allocation;
if (num_collumns == 0) {
propagate_recent_files ();
}
// bg color
cr.save ();
cr.set_source_rgba (1, 1, 1, 1);
cr.rectangle (0, 0, allocation.width, allocation.height);
cr.fill ();
cr.restore ();
// draw recent fonts
draw_recent_fonts (allocation, cr);
// new and open
draw_menu (allocation, cr);
}
public override void selected_canvas () {
KeyBindings.singleton.set_require_modifier (true);
name.erase ();
name.append (Supplement.get_current_font ().get_name ());
propagate_recent_files ();
}
public void propagate_recent_files () {
Font font;
this.num_collumns = (int) (allocation.width / 150.0);
while (recent_fonts.length () != 0) {
recent_fonts.delete_link (recent_fonts.first ());
}
foreach (var f in Preferences.get_recent_files ()) {
if (f == "") continue;
File file = File.new_for_path (f);
font = new Font ();
font.set_font_file (f);
if (file.query_exists ()) {
recent_fonts.append (font);
}
}
recent_fonts.reverse ();
}
private void draw_recent_fonts (Allocation allocation, Context cr) {
double x = 10;
double y = 260 + 25;
int i = 0;
int columns = (int) (allocation.width / 150.0);
string fn;
if (recent_fonts.length () == 0) {
return;
}
cr.save ();
cr.set_font_size (14);
cr.select_font_face ("Cantarell", FontSlant.NORMAL, FontWeight.BOLD);
cr.move_to (x, y);
cr.show_text ("Recent fonts");
y = 260 + 45;
x = 10;
foreach (var font in recent_fonts) {
string svg = "";
string font_file = (!) font.font_file;
cr.save ();
if (recent_active == i)
cr.set_source_rgba (84/255.0, 134/255.0, 148/255.0, 1);
else
cr.set_source_rgba (176/255.0, 211/255.0, 230/255.0, 1);
cr.set_line_join (LineJoin.ROUND);
cr.set_line_width (7);
cr.rectangle (x, y, 130, 130);
cr.fill_preserve ();
cr.stroke ();
cr.restore ();
Svg.draw_svg_path (cr, svg, x + 40, y + 90);
cr.save ();
cr.move_to (x + 3, y + 155);
cr.set_font_size (10);
cr.set_source_rgba(0, 0, 0, 1);
font_file = (!) font.font_file;
fn = font_file.substring (font_file.replace ("\\", "/").last_index_of ("/") + 1);
if (fn.char_count () > 17) {
fn = fn.substring (0, 17) + " ...";
}
cr.show_text (fn);
cr.restore ();
x += 150;
i++;
if (--columns <= 0) {
break;
}
}
cr.stroke ();
cr.restore ();
}
private void draw_menu (Allocation allocation, Context cr) {
draw_file_menu (allocation, cr);
draw_grid_menu (allocation, cr);
draw_font_name (allocation, cr);
}
private void draw_file_menu (Allocation allocation, Context cr) {
double x;
double y;
x = 10;
y = 25;
cr.save ();
cr.move_to (x, y);
cr.set_font_size (14);
cr.select_font_face ("Cantarell", FontSlant.NORMAL, FontWeight.BOLD);
cr.move_to (x, y);
cr.show_text ("File");
cr.move_to (200, y);
cr.show_text ("Views");
cr.restore ();
save_tool.draw (allocation, cr);
new_file_tool.draw (allocation, cr);
open_tool.draw (allocation, cr);
browser_tool.draw (allocation, cr);
export_tool.draw (allocation, cr);
export_preferences.draw (allocation, cr);
kerning_context_tool.draw (allocation, cr);
}
private void draw_grid_menu (Allocation allocation, Context cr) {
double x;
double y;
x = 10;
y = 95;
cr.save ();
cr.set_font_size (14);
cr.select_font_face ("Cantarell", FontSlant.NORMAL, FontWeight.BOLD);
cr.move_to (x, y);
cr.show_text ("Grid width");
cr.move_to (x + 100, y);
cr.show_text (""); // Grid angle
cr.restore ();
add_new_grid_tool.draw (allocation, cr);
delete_grid_tool.draw (allocation, cr);
}
private void draw_font_name (Allocation allocation, Context cr) {
double x;
double y;
string m;
x = 10;
y = 165;
cr.save ();
cr.set_font_size (14);
cr.select_font_face ("Cantarell", FontSlant.NORMAL, FontWeight.BOLD);
cr.move_to (x, y);
cr.show_text ("Name");
cr.select_font_face ("Cantarell", FontSlant.NORMAL, FontWeight.NORMAL);
cr.set_font_size (16);
cr.move_to (x + 1, y + 20);
m = (show_marker) ? "|" : "";
cr.show_text (name.str + m);
cr.restore ();
}
public override void key_press (EventKey e) {
unichar c = (unichar) e.keyval;
Font f;
if (e.type != EventType.KEY_PRESS) {
return;
}
if (is_mod (e)) {
return;
}
if (KeyBindings.singleton.modifier != NONE && KeyBindings.singleton.modifier != SHIFT) {
return;
}
if (e.keyval == Key.BACK_SPACE) {
name.truncate (name.len - 1);
while (!name.str.validate ()) {
name.truncate (name.len - 1);
if (name.str.length == 0) {
break;
}
}
}
if (has_modifier == 0 && !is_modifier_key (e.keyval) && c.validate ()) {
// webkit does not allow full unicode characters or space in name
// replace non-ansi characters with _
if ('0' <= c <= '9' || 'a' <= c <= 'z' || 'A' <= c <= 'Z') {
name.append_unichar (c);
} else {
name.append_unichar ('_');
}
f = Supplement.get_current_font ();
f.set_name (name.str);
f.touch ();
}
MainWindow.get_glyph_canvas ().redraw ();
}
public override void key_release (EventKey e) {
if (is_mod (e)) {
has_modifier--;
}
}
public override void motion_notify (EventMotion e) {
int column = (int)(e.x / 160);
bool a;
if (280 < e.y < 280 + 150) {
recent_active = column;
} else {
recent_active = -1;
}
if (44 < e.y < 181) {
open_active = column;
} else {
open_active = -1;
}
foreach (Tool t in tools) {
a = t.is_over (e.x, e.y);
t.set_active (a);
if (a) {
MainWindow.get_tool_tip ().set_text_from_tool ();
}
}
MainWindow.get_glyph_canvas ().redraw ();
}
public override void button_release (EventButton event) {
int columns = (int) (allocation.width / 150.0) - 1;
SaveDialog save = new SaveDialog ();
Font cf = Supplement.get_current_font ();
string f, f2;
foreach (Tool t in tools) {
if (t.is_over (event.x, event.y)) {
activate (t);
}
}
if (0 <= recent_active <= columns) {
return_if_fail (recent_fonts.nth (recent_active).data.font_file != null);
f = (!) cf.font_file;
f2 = (!) recent_fonts.nth (recent_active).data.font_file;
if (cf.font_file != null && f == f2) { // recent font is already loaded
MainWindow.get_toolbox ().select_tool_by_name ("available_characters");
} else {
save.finished.connect (() => {
Supplement.get_current_font ().delete_backup ();
load_recent_font ();
});
save_dialog (save);
}
}
}
private void activate (Tool t) {
t.select_action (t);
MainWindow.get_tool_tip ().set_text_from_tool ();
}
private void load_new_font () {
string? fn;
FileChooserDialog file_chooser = new FileChooserDialog ("Open font file", MainWindow.get_current_window (), FileChooserAction.OPEN, Stock.CANCEL, ResponseType.CANCEL, Stock.OPEN, ResponseType.ACCEPT);
Font f = Supplement.get_current_font ();
try {
file_chooser.set_current_folder_file (f.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 ();
if (fn != null) {
f.delete_backup ();
MainWindow.clear_glyph_cache ();
MainWindow.close_all_tabs ();
f.load ((!)fn);
MainWindow.get_singleton ().set_title (f.get_name ());
select_overview ();
Preferences.add_recent_files ((!) fn);
}
}
file_chooser.destroy ();
}
private void select_overview () {
Toolbox tb = MainWindow.get_toolbox ();
if (Supplement.get_current_font ().is_empty ()) {
tb.select_tool_by_name ("custom_character_set");
} else {
tb.select_tool_by_name ("available_characters");
}
}
private void load_recent_font () {
string? fnn;
string fn;
Font f;
bool loaded;
if (0 <= recent_active < recent_fonts.length ()) {
fnn = recent_fonts.nth (recent_active).data.font_file;
return_if_fail (fnn != null);
fn = (!) fnn;
f = Supplement.get_current_font ();
f.delete_backup ();
MainWindow.clear_glyph_cache ();
MainWindow.close_all_tabs ();
loaded = f.load (fn);
if (!unlikely (loaded)) {
warning (@"Failed to load fond $fn");
return;
}
MainWindow.get_singleton ().set_title (f.get_name ());
Preferences.add_recent_files (fn);
select_overview ();
}
}
public override void button_press (EventButton event) {
bool a;
foreach (Tool t in tools) {
a = t.is_over (event.x, event.y);
t.set_active (a);
if (a) {
MainWindow.get_tool_tip ().set_text_from_tool ();
}
}
if (167 < event.y < 193) {
}
}
}
}