Commit bfcd07b
Export settings Export only the selected format and remove TTF file if only an EOT file is exported.
Changed files (15)
modifiedlibbirdfont/BirdFont.valamodifiedlibbirdfont/Button.valamodifiedlibbirdfont/DescriptionDisplay.valamodifiedlibbirdfont/EditPoint.valamodifiedlibbirdfont/ExportCallback.valaaddedlibbirdfont/ExportSettings.valamodifiedlibbirdfont/ExportTool.valamodifiedlibbirdfont/Menu.valamodifiedlibbirdfont/MenuTab.valamodifiedlibbirdfont/Path.valamodifiedlibbirdfont/Preview.valamodifiedlibbirdfont/Renderer/TextArea.valamodifiedlibbirdfont/StrokeTool.valaaddedlibbirdfont/TableLayout.valamodifiedlibbirdfont/TestCases.vala
Diff
@@ -299,12 +299,12 @@ public static int run_export (string[] arg) { } if (!specific_formats || write_svg) {- print (@"Writing $(BirdFont.current_font.get_full_name ()).svg to $output_directory\n");+ print (@"Writing $(ExportSettings.get_file_name (font)).svg to $output_directory\n"); ExportTool.export_svg_font_path (File.new_for_path (output_directory)); } if (!specific_formats || write_ttf) {- print (@"Writing $(BirdFont.current_font.get_full_name ()).ttf to $output_directory\n");+ print (@"Writing $(ExportSettings.get_file_name (font)).ttf to $output_directory\n"); ExportTool.export_ttf_font_path (File.new_for_path (output_directory)); } @@ -24,7 +24,8 @@ public class Button : Widget { public signal void action (); - public Button (string label) {+ public Button (string label, double margin_bottom = 0) {+ this.margin_bottom = margin_bottom; font_size = 17 * MainWindow.units; this.label = new Text (label, font_size); padding = 15 * MainWindow.units;@@ -17,16 +17,7 @@ using Math; namespace BirdFont { -public class DescriptionDisplay : FontDisplay {- - double scroll = 0;- double content_height = 1;- WidgetAllocation allocation;- Gee.ArrayList<Widget> focus_ring = new Gee.ArrayList<Widget> ();- int focus_index = 0;- - Widget? keyboard_focus = null;- +public class DescriptionDisplay : TableLayout { TextArea postscript_name; TextArea name; TextArea style;@@ -39,8 +30,6 @@ public class DescriptionDisplay : FontDisplay { TextArea description; TextArea copyright; - Gee.ArrayList<Widget> widgets;- private static bool disable_copyright = false; public DescriptionDisplay () {@@ -50,10 +39,6 @@ public class DescriptionDisplay : FontDisplay { Headline headline; Font font = BirdFont.get_current_font (); - allocation = new WidgetAllocation ();- - widgets = new Gee.ArrayList<Widget> ();- postscript_name = new LineTextArea (label_size); name = new LineTextArea (label_size); style = new LineTextArea (label_size);@@ -187,166 +172,6 @@ public class DescriptionDisplay : FontDisplay { disable_copyright = !t; } - public override void draw (WidgetAllocation allocation, Context cr) {- this.allocation = allocation;- - layout ();- - // background- cr.save ();- cr.rectangle (0, 0, allocation.width, allocation.height);- cr.set_line_width (0);- - Theme.color (cr, "Background 4");-- cr.fill ();- cr.stroke ();- cr.restore ();-- foreach (Widget w in widgets) {- if (w.is_on_screen ()) { - if (w is Text) {- cr.save ();- Theme.color (cr, "Foreground 1");- w.draw (cr);- cr.restore ();- } else {- w.draw (cr);- }- }- }- } -- void layout () {- double y = -scroll;- - foreach (Widget w in widgets) {- w.widget_x = 17 * MainWindow.units;- w.widget_y = y;- w.allocation = allocation;- - if (w is TextArea) {- ((TextArea) w).layout ();- }- - y += w.get_height () + w.margin_bottom;- }- - content_height = y + scroll;- update_scrollbar ();- }-- public void scroll_event (double p) {- scroll += p;- layout ();- GlyphCanvas.redraw ();- }-- public override void key_press (uint keyval) {- Widget focus;-- if (keyval == Key.SHIFT_TAB) {- focus_previous ();- } else if (keyval == Key.TAB) {- focus_next ();- } else if (keyboard_focus != null) {- focus = (!) keyboard_focus;- focus.key_press (keyval);- }- - GlyphCanvas.redraw ();- }- - void focus_previous () {- focus_index--;- - if (focus_index < 0) {- focus_index = 0;- }- - set_focus (focus_ring.get (focus_index));- }- - void focus_next () {- focus_index++;- - if (focus_index >= focus_ring.size) {- focus_index = focus_ring.size - 1;- }- - set_focus (focus_ring.get (focus_index));- }- - public override void button_press (uint button, double x, double y) {- Widget t;- Widget old;- CheckBox c;- - foreach (Widget w in widgets) {- if (w.is_over (x, y)) {- if (w is TextArea) {- t = (TextArea) w;- if (keyboard_focus != null && (!) keyboard_focus != t) {- old = (!) keyboard_focus;- old.focus (false);- }- - set_focus (t);- t.button_press (button, x, y);- } else if (w is CheckBox) {- c = (CheckBox) w;- c.set_checked (!c.checked);- }- }- }-- GlyphCanvas.redraw ();- }- - public void set_focus (Widget w) {- Widget old;- - if (keyboard_focus != null && (!) keyboard_focus != w) {- old = (!) keyboard_focus;- old.focus (false);- }- - keyboard_focus = w;- w.focus (true);- - focus_index = focus_ring.index_of (w);-- if (!(0 <= focus_index < focus_ring.size)) {- focus_index = 0;- }-- update_scrollbar ();- GlyphCanvas.redraw ();- }- - public override void button_release (int button, double x, double y) {- Widget t;- - if (keyboard_focus != null) {- t = (!) keyboard_focus;- set_focus (t);- t.button_release (button, x, y);- }- - GlyphCanvas.redraw ();- }-- public override void motion_notify (double x, double y) {- Widget t;- - if (keyboard_focus != null) {- t = (!) keyboard_focus;- if (t.motion (x, y)) {- GlyphCanvas.redraw ();- }- }- }- public override string get_label () { return t_("Name and Description"); }@@ -354,49 +179,10 @@ public class DescriptionDisplay : FontDisplay { public override string get_name () { return "Description"; }-- public override bool has_scrollbar () {- return true;- }- - public override void scroll_wheel_down (double x, double y) {- scroll += 25 * MainWindow.units;- - if (scroll + allocation.height >= content_height) {- scroll = content_height - allocation.height;- }- - update_scrollbar ();- GlyphCanvas.redraw ();- } - public override void scroll_wheel_up (double x, double y) {- scroll -= 25 * MainWindow.units;- - if (scroll < 0) {- scroll = 0;- }- - update_scrollbar ();- GlyphCanvas.redraw ();- }- public override void selected_canvas () { copyright.set_editable (!disable_copyright);- update_scrollbar ();- GlyphCanvas.redraw ();- }- - public override void update_scrollbar () {- double h = content_height - allocation.height;- MainWindow.set_scrollbar_size (allocation.height / content_height);- MainWindow.set_scrollbar_position (scroll / h);- }-- public override void scroll_to (double percent) {- double h = content_height - allocation.height;- scroll = percent * h;- GlyphCanvas.redraw ();+ base.selected_canvas (); } } @@ -593,6 +593,62 @@ public class EditPoint : GLib.Object { s.append (@"Right handle: angle: $(right_handle.angle) l: $(right_handle.length)\n"); return s.str; }+ + public double max_x () {+ double mx = x;+ + if (get_right_handle ().x > mx) {+ mx = get_right_handle ().x;+ }++ if (get_left_handle ().x > mx) {+ mx = get_left_handle ().x;+ }+ + return mx;+ }++ public double min_x () {+ double mx = x;+ + if (get_right_handle ().x < mx) {+ mx = get_right_handle ().x;+ }++ if (get_left_handle ().x < mx) {+ mx = get_left_handle ().x;+ }+ + return mx;+ }+ + public double max_y () {+ double my = y;+ + if (get_right_handle ().y > my) {+ my = get_right_handle ().y;+ }++ if (get_left_handle ().y > my) {+ my = get_left_handle ().y;+ }+ + return my;+ }++ public double min_y () {+ double my = y;+ + if (get_right_handle ().y < my) {+ my = get_right_handle ().y;+ }++ if (get_left_handle ().y < my) {+ my = get_left_handle ().y;+ }+ + return my;+ } } }@@ -41,8 +41,15 @@ public class ExportCallback : GLib.Object { /** Export TTF, EOT and SVG fonts. */ public static void export_fonts () {- ExportTool.export_ttf_font ();- ExportTool.export_svg_font ();+ Font font = BirdFont.get_current_font ();+ + if (ExportSettings.export_ttf_setting (font) || ExportSettings.export_eot_setting (font)) {+ ExportTool.export_ttf_font ();+ }+ + if (ExportSettings.export_svg_setting (font)) {+ ExportTool.export_svg_font ();+ } } } new file mode 100644@@ -0,0 +1,141 @@+/*+ Copyright (C) 2015 Johan Mattsson++ This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library 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 + Lesser General Public License for more details.+*/++using Cairo;+using Math;++namespace BirdFont {++public class ExportSettings : TableLayout {+ TextArea file_name;+ CheckBox ttf;+ CheckBox eot;+ CheckBox svg;+ Button export_action;+ Button name_tab;+ + public ExportSettings () {+ Headline headline;+ Font font;+ double margin = 12 * MainWindow.units;+ double label_size = 20 * MainWindow.units;+ double label_margin = 4 * MainWindow.units;+ string fn;+ + font = BirdFont.get_current_font (); + font.settings.set_setting ("has_export_settings", "true");+ + headline = new Headline (t_("Export Settings"));+ headline.margin_bottom = 20 * MainWindow.units;+ widgets.add (headline);+ + widgets.add (new Text (t_("File Name"), label_size, label_margin));+ + file_name = new LineTextArea (label_size);+ file_name.margin_bottom = margin;+ + fn = get_file_name (font);+ file_name.set_text (fn);+ file_name.text_changed.connect ((t) => {+ Font f = BirdFont.get_current_font ();+ f.settings.set_setting ("file_name", t);+ });+ + widgets.add (file_name);+ focus_ring.add (file_name);+ + widgets.add (new Text (t_("Formats"), label_size, label_margin));++ ttf = new CheckBox ("TTF", label_size);+ ttf.updated.connect ((c) => {+ Font f = BirdFont.get_current_font ();+ string v = c ? "true" : "false";+ f.settings.set_setting ("export_ttf", v);+ });+ ttf.checked = export_ttf_setting (font);+ widgets.add (ttf);+ focus_ring.add (ttf);++ eot = new CheckBox ("EOT", label_size);+ eot.updated.connect ((c) => {+ Font f = BirdFont.get_current_font ();+ string v = c ? "true" : "false";+ f.settings.set_setting ("export_eot", v);+ });+ eot.checked = export_eot_setting (font);+ widgets.add (eot);+ focus_ring.add (eot);+ + svg = new CheckBox ("SVG", label_size);+ svg.updated.connect ((c) => {+ Font f = BirdFont.get_current_font ();+ string v = c ? "true" : "false";+ f.settings.set_setting ("export_eot", v);+ });+ svg.checked = export_svg_setting (font);+ svg.margin_bottom = margin;+ widgets.add (svg);+ focus_ring.add (svg);++ name_tab = new Button (t_("Name and Description"), margin);+ name_tab.action.connect ((c) => {+ MenuTab.show_description ();+ });+ widgets.add (name_tab);+ + export_action = new Button (t_("Export"), margin);+ export_action.action.connect ((c) => {+ MenuTab.export_fonts_in_background ();+ });+ widgets.add (export_action);+ + set_focus (file_name);+ }+ + public static string get_file_name (Font font) {+ string n = font.settings.get_setting ("file_name");+ + if (n == "") {+ n = font.full_name;+ }+ + return n;+ }++ public static bool export_ttf_setting (Font f) {+ return f.settings.get_setting ("export_ttf") != "false";+ }++ public static bool export_eot_setting (Font f) {+ return f.settings.get_setting ("export_eot") != "false";+ }+ + public static bool export_svg_setting (Font f) {+ return f.settings.get_setting ("export_svg") != "false";+ }+ + public static bool has_export_settings (Font f) {+ return f.settings.get_setting ("has_export_settings") == "true";+ }+ + public override string get_label () {+ return t_("Export Settings");+ }++ public override string get_name () {+ return "Export Settings";+ }+}++}@@ -159,40 +159,11 @@ public class ExportTool : GLib.Object { MainWindow.file_chooser (t_("Save"), fc, FileChooser.SAVE); }-- /* Font must be saved before export in order to know where the- * generated files should be stored.- */- internal static void export_all () {- Font font = BirdFont.get_current_font ();- - printd ("Exporting all fonts.\n");- - if (font.font_file == null) {- warning ("Font is not saved.");- } else {- do_export ();- }- }- - static void do_export () {- bool f;- - f = export_ttf_font ();- if (!f) {- warning ("Failed to export ttf font");- }-- f = export_svg_font ();- if (!f) {- warning ("Failed to export svg font");- }- }-+ public static void generate_html_document (string html_file, Font font) { File file = File.new_for_path (html_file); DataOutputStream os;- string name = font.get_full_name ();+ string name = ExportSettings.get_file_name (font); try { os = new DataOutputStream (file.create(FileCreateFlags.REPLACE_DESTINATION));@@ -384,15 +355,15 @@ os.put_string ( return export_ttf_font_path (f); } - public static bool export_ttf_font_path (File folder) {+ public static bool export_ttf_font_path (File folder, bool use_export_settings = true) { Font current_font = BirdFont.get_current_font (); File ttf_file; File eot_file; bool done = true; try {- ttf_file = get_child (folder, current_font.get_full_name () + ".ttf");- eot_file = get_child (folder, current_font.get_full_name () + ".eot");+ ttf_file = get_child (folder, ExportSettings.get_file_name (current_font) + ".ttf");+ eot_file = get_child (folder, ExportSettings.get_file_name (current_font) + ".eot"); printd (@"Writing TTF fonts to $((!) ttf_file.get_path ())\n"); @@ -405,7 +376,16 @@ os.put_string ( } write_ttf ((!) ttf_file.get_path ());- write_eot ((!) ttf_file.get_path (), (!) eot_file.get_path ());+ + if (!use_export_settings || ExportSettings.export_eot_setting (current_font)) {+ write_eot ((!) ttf_file.get_path (), (!) eot_file.get_path ());+ }+ + if (use_export_settings && !ExportSettings.export_ttf_setting (current_font)) {+ if (ttf_file.query_exists ()) {+ ttf_file.delete ();+ }+ } } catch (Error e) { critical (@"$(e.message)"); done = false;@@ -421,7 +401,7 @@ os.put_string ( public static bool export_svg_font_path (File folder) { Font font = BirdFont.get_current_font ();- string file_name = @"$(font.get_full_name ()).svg";+ string file_name = @"$(ExportSettings.get_file_name (font)).svg"; File file; SvgFontFormatWriter fo; @@ -110,6 +110,13 @@ public class Menu : GLib.Object { }); file_menu.items.add (export); + MenuItem export_settings = add_menu_item (t_("Export Settings"), "export settings");+ export_settings.action.connect (() => {+ MenuTab.show_export_settings_tab ();+ show_menu = false;+ });+ file_menu.items.add (export_settings);+ MenuItem preview = add_menu_item (t_("Preview"), "preview"); preview.action.connect (() => { MenuTab.preview ();@@ -78,7 +78,7 @@ public class MenuTab : FontDisplay { public static bool validate_metadata () { Font font = BirdFont.get_current_font ();- string m = t_("Missing metadata in font:") + "\n ";+ string m = t_("Missing metadata in font:") + "\n"; if (font.postscript_name == "") { MainWindow.show_message (m + t_("PostScript Name"));@@ -109,14 +109,22 @@ public class MenuTab : FontDisplay { } public static void export_fonts_in_background () {+ Font f;+ if (suppress_event || !MainWindow.native_window.can_export () || !validate_metadata ()) { return; } - MenuTab.export_callback = new ExportCallback ();- MenuTab.export_callback.export_fonts_in_background ();+ f = BirdFont.get_current_font ();+ + if (ExportSettings.has_export_settings (f)) {+ MenuTab.export_callback = new ExportCallback ();+ MenuTab.export_callback.export_fonts_in_background (); + } else {+ show_export_settings_tab ();+ } } public static bool set_suppress_event (bool e) {@@ -296,6 +304,10 @@ public class MenuTab : FontDisplay { } } + public static void show_export_settings_tab () {+ MainWindow.get_tab_bar ().add_unique_tab (new ExportSettings ());+ }+ public static void show_description () { MainWindow.get_tab_bar ().add_unique_tab (new DescriptionDisplay ()); }@@ -2174,29 +2174,14 @@ public class Path { } public bool boundaries_intersecting (Path p) {- bool xm1 = in_boundaries (p.xmin, p.ymin);- bool xm2 = in_boundaries (p.xmax, p.ymax);- bool xm3 = in_boundaries (p.xmin, p.ymax);- bool xm4 = in_boundaries (p.xmax, p.ymin);- - if (xm1 || xm2 || xm3 || xm3) {- return true;- }- - xm1 = p.in_boundaries (xmin, ymin);- xm2 = p.in_boundaries (xmax, ymax);- xm3 = p.in_boundaries (xmin, ymax);- xm4 = p.in_boundaries (xmax, ymin);- - if (xm1 || xm2 || xm3 || xm3) {- return true;- }- - return false;+ return in_boundaries (p.xmin, p.xmax, p.ymin, p.ymax); } - public bool in_boundaries (double x, double y) {- return xmin <= x <= xmax && ymin <= y <= ymax;+ public bool in_boundaries (double other_xmin, double other_xmax, double other_ymin, double other_ymax) {+ return ((xmin <= other_xmin <= xmax) || (xmin <= other_xmax <= xmax)+ || (other_xmin <= xmin <= other_xmax) || (other_xmin <= xmax <= other_xmax))+ && ((ymin <= other_ymin <= ymax) || (ymin <= other_ymax <= ymax)+ || (other_ymin <= ymin <= other_ymax) || (other_ymin <= ymax <= other_ymax)); } /** @param t smallest distance to other points. */@@ -77,7 +77,7 @@ public class Preview : FontDisplay { static string get_html_file_name () { Font font = BirdFont.get_current_font ();- return @"$(font.get_full_name ()).html";+ return @"$(ExportSettings.get_file_name (font)).html"; } public static File get_html_file () {@@ -115,9 +115,9 @@ public class Preview : FontDisplay { preview_directory = BirdFont.get_preview_directory (); - f_ttf = get_child (font.get_folder (), @"$(font.get_full_name ()).ttf");- f_eot = get_child (font.get_folder (), @"$(font.get_full_name ()).eot");- f_svg = get_child (font.get_folder (), @"$(font.get_full_name ()).svg");+ f_ttf = get_child (font.get_folder (), @"$(ExportSettings.get_file_name (font)).ttf");+ f_eot = get_child (font.get_folder (), @"$(ExportSettings.get_file_name (font)).eot");+ f_svg = get_child (font.get_folder (), @"$(ExportSettings.get_file_name (font)).svg"); if (!f_ttf.query_exists ()) { warning ("TTF file does not exist.");@@ -128,9 +128,9 @@ public class Preview : FontDisplay { } while ((line = dis.read_line (null)) != null) {- line = ((!) line).replace (@"$(font.get_full_name ()).ttf", @"$(TabContent.path_to_uri ((!) f_ttf.get_path ()))?$rid");- line = ((!) line).replace (@"$(font.get_full_name ()).eot", @"$(TabContent.path_to_uri ((!) f_eot.get_path ()))?$rid");- line = ((!) line).replace (@"$(font.get_full_name ()).svg", @"$(TabContent.path_to_uri ((!) f_svg.get_path ()))?$rid");+ line = ((!) line).replace (@"$(ExportSettings.get_file_name (font)).ttf", @"$(TabContent.path_to_uri ((!) f_ttf.get_path ()))?$rid");+ line = ((!) line).replace (@"$(ExportSettings.get_file_name (font)).eot", @"$(TabContent.path_to_uri ((!) f_eot.get_path ()))?$rid");+ line = ((!) line).replace (@"$(ExportSettings.get_file_name (font)).svg", @"$(TabContent.path_to_uri ((!) f_svg.get_path ()))?$rid"); sb.append ((!) line); } @@ -93,6 +93,11 @@ public class TextArea : Widget { int next_paragraph = -1; + if (is_null (text)) {+ warning ("No text");+ return false;+ }+ if (last_paragraph == DONE) { return false; }@@ -985,33 +985,66 @@ public class StrokeTool : Tool { out double ix, out double iy, bool skip_points_on_points = false) { double cross_x, cross_y;+ Path lines1, lines2;+ EditPoint a1, a2, b1, b2; ix = 0; iy = 0;-- Path.find_intersection_point (ep, next, p1, p2, out cross_x, out cross_y); - if (Glyph.CANVAS_MIN < cross_x < Glyph.CANVAS_MAX- && Glyph.CANVAS_MIN < cross_y < Glyph.CANVAS_MAX) {- // iterate to find intersection.+ lines1 = new Path ();+ lines2 = new Path ();+ SvgParser.create_lines_for_segment (lines1, p1, p2);+ SvgParser.create_lines_for_segment (lines2, ep, next);++ lines1.xmax = fmax (p1.max_x (), p2.max_x ());+ lines1.xmin = fmax (p1.min_x (), p2.min_x ());+ lines1.ymax = fmax (p1.max_y (), p2.max_y ());+ lines1.ymin = fmax (p1.min_y (), p2.min_y ()); - if (skip_points_on_points ||- !((ep.x == cross_x && ep.y == cross_y)- || (next.x == cross_x && next.y == cross_y)- || (p1.x == cross_x && p1.y == cross_y) - || (p2.x == cross_x && p2.y == cross_y))) {- - if (is_line (ep.x, ep.y, cross_x, cross_y, next.x, next.y)- && is_line (p1.x, p1.y, cross_x, cross_y, p2.x, p2.y)) {+ lines2.xmax = fmax (ep.max_x (), next.max_x ());+ lines2.xmin = fmax (ep.min_x (), next.min_x ());+ lines2.ymax = fmax (ep.max_y (), next.max_y ());+ lines2.ymin = fmax (ep.min_y (), next.min_y ());+ + if (!lines1.boundaries_intersecting (lines2)) {+ return false;+ }+ + // FIXME: two intersection on the same segment+ + for (int i = 0; i < lines1.points.size - 1; i++) {+ a1 = lines1.points.get (i);+ a2 = lines1.points.get (i + 1);+ + for (int j = 0; j < lines2.points.size - 1; j++) {+ b1 = lines2.points.get (j);+ b2 = lines2.points.get (j + 1); - ix = cross_x;- iy = cross_y;- - return true;+ Path.find_intersection_point (a1, a2, b1, b2, out cross_x, out cross_y);+ + if (Glyph.CANVAS_MIN < cross_x < Glyph.CANVAS_MAX+ && Glyph.CANVAS_MIN < cross_y < Glyph.CANVAS_MAX) {+ // iterate to find intersection.++ if (skip_points_on_points ||+ !((ep.x == cross_x && ep.y == cross_y)+ || (next.x == cross_x && next.y == cross_y)+ || (p1.x == cross_x && p1.y == cross_y) + || (p2.x == cross_x && p2.y == cross_y))) {+ + if (is_line (ep.x, ep.y, cross_x, cross_y, next.x, next.y)+ && is_line (p1.x, p1.y, cross_x, cross_y, p2.x, p2.y)) {+ + ix = cross_x;+ iy = cross_y;+ + return true;+ }+ } }- } + } }- + return false; } @@ -1902,9 +1935,7 @@ public class StrokeTool : Tool { int size, i, added_points; double step = 0.51; bool open = path.is_open ();- - print (@"open: $open\n");- + size = open ? path.points.size - 1 : path.points.size; path.add_hidden_double_points ();new file mode 100644@@ -0,0 +1,248 @@+/*+ Copyright (C) 2014 2015 Johan Mattsson++ This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library 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 + Lesser General Public License for more details.+*/++using Cairo;+using Math;++namespace BirdFont {++public class TableLayout : FontDisplay {+ + public double scroll = 0;+ public double content_height = 1;+ public WidgetAllocation allocation = new WidgetAllocation ();+ public Gee.ArrayList<Widget> widgets = new Gee.ArrayList<Widget> ();+ public Gee.ArrayList<Widget> focus_ring = new Gee.ArrayList<Widget> ();+ public int focus_index = 0;+ + public Widget? keyboard_focus = null;+ + public TableLayout () {+ }++ public override void draw (WidgetAllocation allocation, Context cr) {+ this.allocation = allocation;+ + layout ();+ + // background+ cr.save ();+ cr.rectangle (0, 0, allocation.width, allocation.height);+ cr.set_line_width (0);+ + Theme.color (cr, "Background 4");++ cr.fill ();+ cr.stroke ();+ cr.restore ();++ foreach (Widget w in widgets) {+ if (w.is_on_screen ()) { + if (w is Text) {+ cr.save ();+ Theme.color (cr, "Foreground 1");+ w.draw (cr);+ cr.restore ();+ } else {+ w.draw (cr);+ }+ }+ }+ } ++ void layout () {+ double y = -scroll;+ + foreach (Widget w in widgets) {+ w.widget_x = 17 * MainWindow.units;+ w.widget_y = y;+ w.allocation = allocation;+ + if (w is TextArea) {+ ((TextArea) w).layout ();+ }+ + y += w.get_height () + w.margin_bottom;+ }+ + content_height = y + scroll;+ update_scrollbar ();+ }++ public void scroll_event (double p) {+ scroll += p;+ layout ();+ GlyphCanvas.redraw ();+ }++ public override void key_press (uint keyval) {+ Widget focus;++ if (keyval == Key.SHIFT_TAB) {+ focus_previous ();+ } else if (keyval == Key.TAB) {+ focus_next ();+ } else if (keyboard_focus != null) {+ focus = (!) keyboard_focus;+ focus.key_press (keyval);+ }+ + GlyphCanvas.redraw ();+ }+ + void focus_previous () {+ focus_index--;+ + if (focus_index < 0) {+ focus_index = 0;+ }+ + set_focus (focus_ring.get (focus_index));+ }+ + void focus_next () {+ focus_index++;+ + if (focus_index >= focus_ring.size) {+ focus_index = focus_ring.size - 1;+ }+ + set_focus (focus_ring.get (focus_index));+ }+ + public override void button_press (uint button, double x, double y) {+ Widget t;+ Widget old;+ CheckBox c;+ + foreach (Widget w in widgets) {+ if (w.is_over (x, y)) {+ if (w is TextArea) {+ t = (TextArea) w;+ if (keyboard_focus != null && (!) keyboard_focus != t) {+ old = (!) keyboard_focus;+ old.focus (false);+ }+ + set_focus (t);+ t.button_press (button, x, y);+ } else if (w is CheckBox) {+ c = (CheckBox) w;+ c.set_checked (!c.checked);+ } else {+ w.button_press (button, x, y);+ }+ }+ }++ GlyphCanvas.redraw ();+ }+ + public void set_focus (Widget w) {+ Widget old;+ + if (keyboard_focus != null && (!) keyboard_focus != w) {+ old = (!) keyboard_focus;+ old.focus (false);+ }+ + keyboard_focus = w;+ w.focus (true);+ + focus_index = focus_ring.index_of (w);++ if (!(0 <= focus_index < focus_ring.size)) {+ focus_index = 0;+ }++ update_scrollbar ();+ GlyphCanvas.redraw ();+ }+ + public override void button_release (int button, double x, double y) {+ Widget t;+ + if (keyboard_focus != null) {+ t = (!) keyboard_focus;+ set_focus (t);+ t.button_release (button, x, y);+ }+ + GlyphCanvas.redraw ();+ }++ public override void motion_notify (double x, double y) {+ Widget t;+ + if (keyboard_focus != null) {+ t = (!) keyboard_focus;+ if (t.motion (x, y)) {+ GlyphCanvas.redraw ();+ }+ }+ }++ public override string get_label () {+ return t_("Name and Description");+ }++ public override string get_name () {+ return "Description";+ }++ public override bool has_scrollbar () {+ return true;+ }+ + public override void scroll_wheel_down (double x, double y) {+ scroll += 25 * MainWindow.units;+ + if (scroll + allocation.height >= content_height) {+ scroll = content_height - allocation.height;+ }+ + update_scrollbar ();+ GlyphCanvas.redraw ();+ }+ + public override void scroll_wheel_up (double x, double y) {+ scroll -= 25 * MainWindow.units;+ + if (scroll < 0) {+ scroll = 0;+ }+ + update_scrollbar ();+ GlyphCanvas.redraw ();+ }++ public override void selected_canvas () {+ update_scrollbar ();+ GlyphCanvas.redraw ();+ }+ + public override void update_scrollbar () {+ double h = content_height - allocation.height;+ MainWindow.set_scrollbar_size (allocation.height / content_height);+ MainWindow.set_scrollbar_position (scroll / h);+ }++ public override void scroll_to (double percent) {+ double h = content_height - allocation.height;+ scroll = percent * h;+ GlyphCanvas.redraw ();+ }+}++}@@ -546,12 +546,11 @@ class TestCases { // TODO: run this many times on big fonts for (int i = 0; i < 10; i++) {- ExportTool.export_all ();+ MenuTab.export_fonts_in_background (); Tool.yield ();- } + } } - public static void test_preview () { Glyph g; Path p = new Path ();