Commit 59925fc
Merge branch 'master' of gitorious.org:birdfont/birdfont
Changed files (19)
modifiedbirdfont/GtkWindow.valamodifiedconfiguremodifieddodo.pymodifiedlibbirdfont/BirdFont.valamodifiedlibbirdfont/BirdFontFile.valamodifiedlibbirdfont/CharDatabase.valamodifiedlibbirdfont/Font.valamodifiedlibbirdfont/GlyphTable.valamodifiedlibbirdfont/KerningList.valamodifiedlibbirdfont/MainWindow.valamodifiedlibbirdfont/MoveTool.valamodifiedlibbirdfont/OpenFontFormat/GlyfTable.valamodifiedlibbirdfont/OpenFontFormat/OpenFontFormatWriter.valamodifiedlibbirdfont/OverView.valamodifiedlibbirdfont/PenTool.valamodifiedlibbirdfont/ResizeTool.valamodifiedlibbirdfont/TabBar.valamodifiedlibbirdfont/TestCases.valamodifiedlibbirdfont/ZoomTool.vala
Diff
@@ -259,21 +259,6 @@ public class GtkWindow : Gtk.Window, NativeWindow { MainWindow.glyph_canvas.key_press (event.keyval); KeyBindings.add_modifier_from_keyval (event.keyval);- - if (KeyBindings.modifier == CTRL) {- switch (event.keyval) {- case 'a':- Toolbox.select_tool_by_name ("move");- MainWindow.get_current_glyph ().select_all_paths ();- break;- case 'c':- ClipTool.copy ();- break;- case 'v':- ClipTool.paste ();- break;- }- } } return false;@@ -371,7 +356,7 @@ public class GtkWindow : Gtk.Window, NativeWindow { public void set_scrollbar_position (double position) { scrollbar_supress_signal = true;- scrollbar.adjustment.value = (1 - scrollbar.adjustment.page_size) * position;+ scrollbar.adjustment.value = position * (1 - scrollbar.adjustment.page_size); scrollbar_supress_signal = false; } @@ -567,10 +552,10 @@ public class GtkWindow : Gtk.Window, NativeWindow { Gtk.MenuItem select_all_item = new Gtk.MenuItem.with_mnemonic (_("Select All Pa_ths")); edit_menu.append (select_all_item); select_all_item.activate.connect (() => {- Toolbox.select_tool_by_name ("move");- MainWindow.get_current_glyph ().select_all_paths ();+ MainWindow.select_all_paths (); });-+ select_all_item.add_accelerator ("activate", accel_group, 'A', Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);+ Gtk.MenuItem search_item = new Gtk.MenuItem.with_mnemonic (_("_Search")); edit_menu.append (search_item); search_item.activate.connect (() => { OverView.search (); }); @@ -54,7 +54,7 @@ def configure (): libs = [ 'cairo', 'gdk-pixbuf-2.0', - 'gee-1.0',+ 'gee-0.8', 'gio-2.0', 'glib-2.0', 'gtk+-2.0',@@ -45,7 +45,7 @@ LIBS = [ 'cairo', 'gdk-pixbuf-2.0', 'webkit-1.0',- 'gee-1.0'+ 'gee-0.8' ] def task_build ():@@ -43,6 +43,8 @@ public static int run_export (string[] arg) { return -1; } + init_logfile ();+ for (int i = 1; i < arg.length; i++) { if (arg[i] == "-f" || arg[i] == "--fatal-warnings") {@@ -183,6 +185,9 @@ public class BirdFont { public static string exec_path = ""; public static string bundle_path = ""; + public static bool logging = false;+ public static DataOutputStream? logstream = null;+ public static Font current_font; public static Glyph current_glyph; @@ -363,4 +368,58 @@ public class BirdFont { } } +void init_logfile () {+ DateTime t;+ File settings;+ string s;+ File log;+ + try {+ t = new DateTime.now_local ();+ settings = BirdFont.get_settings_directory ();+ s = t.to_string ().replace (":", "_");+ log = settings.get_child (@"birdfont_$s.log");+ + BirdFont.logstream = new DataOutputStream (log.create (FileCreateFlags.REPLACE_DESTINATION));+ ((!)BirdFont.logstream).put_string ((!) log.get_path ());+ ((!)BirdFont.logstream).put_string ("\n");+ + warning ("Logging to " + (!) log.get_path ());+ } catch (GLib.Error e) {+ warning (e.message);+ warning ((!) log.get_path ());+ }++ LogLevelFlags levels = LogLevelFlags.LEVEL_ERROR | LogLevelFlags.LEVEL_CRITICAL | LogLevelFlags.LEVEL_WARNING | LogLevelFlags.LEVEL_DEBUG;+ Log.set_handler (null, levels, log_warning); + + BirdFont.logging = true;+}++internal static void log_warning (string? log_domain, LogLevelFlags log_levels, string message) {+ if (log_domain != null) {+ printd ((!) log_domain);+ }+ + printd ("\n");+ printd (message);+ printd ("\n");+ printd ("\n");+}++/** Write debug output to logfile. */+void printd (string s) {+ if (unlikely (BirdFont.logging)) {+ try {+ if (BirdFont.logstream != null) {+ ((!)BirdFont.logstream).put_string (s);+ } else {+ warning ("No logstream.");+ }+ } catch (GLib.Error e) {+ warning (e.message);+ }+ }+}+ }@@ -36,7 +36,9 @@ class BirdFontFile { Xml.Node* root; Parser.init ();-+ + printd (@"Loading $path\n");+ font.font_file = path; // this will be updated if we are loading a backup file doc = Parser.parse_file (path);@@ -464,7 +466,10 @@ class BirdFontFile { Xml.Node* node = root; for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {-+ + printd (iter->name); // FIXME: delete+ printd ("\n");+ // this is a backup file set path to the original if (iter->name == "backup") { font.font_file = iter->children->content;@@ -498,6 +503,15 @@ class BirdFontFile { if (iter->name == "postscript_name" && iter->children != null) { font.postscript_name = iter->children->content;+ + printd ("PostScript name:"); // FIXME: delete when debugging is done+ printd (iter->children->content);+ printd ("\n");+ }+ + // FIXME: delete when debugging is done+ if (iter->name == "postscript_name" && iter->children == null) {+ printd ("Found PostScipt name but content for this node is null in libxml.\n"); } if (iter->name == "name" && iter->children != null) {@@ -702,6 +716,10 @@ class BirdFontFile { data = attr_content; } }++ if (!font.get_backgrounds_folder ().query_exists ()) {+ DirUtils.create ((!) font.get_backgrounds_folder ().get_path (), 0xFFFFFF);+ } img_dir = font.get_backgrounds_folder ().get_child ("parts"); @@ -56,8 +56,7 @@ public class CharDatabase { result.add_single (s.get_char ()); } - var it = index.get (s).iterator ();- for (var has_next = it.first (); has_next; has_next = it.next ()) {+ for (var it = index.get (s).iterator (); it.has_next (); it.next ()) { iv = it.get (); if (iv != null) { i = (string) iv;@@ -333,6 +333,8 @@ public class Font : GLib.Object { } glyph_cache.insert (glyph_collection.get_unicode (), glyph_collection);+ + printd (@"Adding $(glyph_collection.get_current ().get_name ())\n"); } public string get_name_for_character (unichar c) {@@ -12,413 +12,67 @@ Lesser General Public License for more details. */ +using Gee;+ namespace BirdFont { /** A sorted table of glyphs with search index. */ public class GlyphTable : GLib.Object {- List<Item> data = new List<Item> (); - List<RowItem> row1 = new List<RowItem> ();- List<RowItem> row2 = new List<RowItem> ();- List<RowItem> row3 = new List<RowItem> ();+ TreeMap<string, GlyphCollection> map; public GlyphTable () {+ map = new TreeMap<string, GlyphCollection> (); } public void remove_all () {- while (data.length () > 0) {- data.remove_link (data.first ());- }- build_index ();+ map.clear (); } public void @for_each (Func<GlyphCollection> func) {- if (unlikely (is_null (data))) {+ if (unlikely (is_null (map))) { warning ("No data in table"); return; } - data.foreach ((v) => {- if (unlikely (is_null (v))) {- warning ("No value found in GlyphTable.");- return;- }- - func (v.glyph_collection);- });+ foreach (var entry in map.entries) {+ func (entry.value);+ } } public bool has_key (string n) {- return find (n) != null;- }-- unowned List<Item>? find (string n) {- return find_index (n);- }-- unowned List<Item>? find_next (string n) {- return find_next_index (n);+ return map.has_key (n); } public void remove (string name) {- unowned List<Item>? d = find (name);- - if (d == null) {- warning (@"did not find $name");- return;- }- - data.remove_link ((!) d);- build_index ();+ map.unset (name); } public uint length () {- return data.length ();+ return map.size; } public new GlyphCollection? @get (string name) {- unowned List<Item>? d = find_index (name);- - if (d == null) {- return null;- }- - return ((!) d).data.glyph_collection;+ return map.get (name); } public new GlyphCollection? nth (uint index) {- unowned List<Item>? d = data.nth (index);- - if (d == null) {- return null;- }- - return ((!) d).data.glyph_collection;- }-- public bool insert (string key, GlyphCollection g) {- Item item;- unowned List<Item>? next;-- if (find (key) != null) {- warning (@"Table does already contains a glyph for key \"$key\".");- stderr.printf ("char: %u\n", (uint) key.get_char (0));- return false;- }- - next = find_next (key);- - item = new Item (key, g);- - if (next == null) {- data.append (item);- } else {- data.insert_before ((!) next, item); // _sorted- }- - build_index ();- - if (find (key) == null) {- warning (@"Can not find glyph \"$(key)\".");- validate_index ();- print_all ();- return false;- }- - return true;- }-- public void print_all () {- int indice = 0;- - print ("Data:\n");- foreach (Item i in data) {- print (@"key: $(i.name) indice: $(indice)\n");- indice++;- }- - print ("Index:\n");- print ("\n");- print ("row3\n");- foreach (RowItem i in row3) {- print (@"$(i.item.data.name)\n");- }- - print ("\n");- print ("row2\n");- foreach (RowItem i in row2) {- print (@"$(i.item.data.name)\n");- }- - print ("\n");- print ("row1\n");- foreach (RowItem i in row1) {- print (@"$(i.item.data.name)\n");- } - }-- static int compare (string an, Item b) {- string? bt = b.name;- string bn = (!) bt;- - uint32 ac = 0;- uint32 bc = 0;- - int i1 = 0;- int i2 = 0;- - return_val_if_fail (bt != null, 0);- - int ca = an.char_count ();- int cb = bn.char_count ();- - if (ca != cb) {- return ca < cb ? 1 : -1;- }- - while (true) {- an.get_next_char (ref i1, out ac);- bn.get_next_char (ref i2, out bc);- - if (ac == bc && ac != 0) {- continue;- }- - if (ac == bc) return 0;- - return (ac < bc) ? 1 : -1;- }- }- - public void build_index () {- uint len;- RowItem r;- - while (row1.length () > 0) {- row1.remove_link (row1.first ());- }-- while (row2.length () > 0) {- row2.remove_link (row2.first ());- }-- while (row3.length () > 0) {- row3.remove_link (row3.first ());- }+ uint i = 0; - if (data.length () == 0) {- return;- }- - // row 1- len = data.length () / 5;- if (len == 0) len++;- for (int i = 0; i < len; i++) {- r = new RowItem ();- r.item = data.nth (i * 5);- r.level = 1;- row1.append (r);- }- r = new RowItem ();- r.item = data.last ();- r.level = 1;- r.last = true;- row1.append (r); - - // row 2- len = row1.length () / 5;- if (len == 0) len++;- for (int i = 0; i < len; i++) {- r = new RowItem ();- r.next_row = row1.nth (i * 5);- r.item = r.next_row.data.item; - r.level = 2;- row2.append (r);- }- r = new RowItem ();- r.item = data.last ();- r.level = 2;- r.next_row = row1.last (); - r.last = true;- row2.append (r);- - // row 3- len = row2.length () / 5;- if (len == 0) len++;- for (int i = 0; i < len; i++) {- r = new RowItem ();- r.next_row = row2.nth (i * 5);- r.item = r.next_row.data.item; - r.level = 3;- row3.append (r);- }- r = new RowItem ();- r.item = data.last ();- r.level = 3;- r.next_row = row2.last ();- r.last = true; - row3.append (r);- }-- unowned List<Item>? find_next_index (string n) {- unowned List<Item>? next = find_next_via_index (n);- return next;- }-- unowned List<Item>? find_index (string n) {- unowned List<Item>? next = find_next_via_index (n);- - if (next == null) {- return null;- }- - if (compare (n, ((!)next).data) == 0) {- return next;- }- - if (((!)next) != data.first () && compare (n, ((!)next).prev.data) == 0) {- return ((!)next).prev; // fetch previous since we are searching for the next one- }- - return null; - }- - unowned List<Item>? find_next_via_index (string n) {- unowned List<Item> i = data.first ();- unowned List<RowItem> r;- int cmp;- - if (data.length () == 0) {- return null;- }-- r = row3.first ();- int ti = 0;- while (true) {- cmp = compare (n, r.data.item.data);- - ti++;- - if (cmp == 1) {- break;- }- - if (cmp == 0) {- return r.data.item;- }- - if (r != row3.last ()) {- r = r.next;- } else {- return null;+ foreach (var k in map.keys) {+ if (i == index) {+ return map.get (k); }- } - r = r.data.next_row;-- while (true) {- cmp = compare (n, r.data.item.data);- - if (cmp == -1) {- break;- }-- if (cmp == 0) {- return r.data.item;- }- - if (r == row2.first ()) {;- return r.data.item;- } else r = r.prev;+ i++; }- r = r.data.next_row;- - while (true) {- cmp = compare (n, r.data.item.data);- - if (cmp == 1) {- break;- }- - if (cmp == 0) {- return r.data.item;- }- - if (r == row1.last ()) return null;- else r = r.next;- }- i = r.data.item;- - - while (true) {- cmp = compare (n, i.data); - if (cmp == -1) {- // null?- return i.next;- }-- if (cmp == 0) {- return i;- }- - if (i == data.first ()) {- return i;- } else { - i = i.prev;- }- } + return null; } - public bool validate_index () {- int cmp;- Item prev;- int index;- - if (data.length () == 0) {- return true;- }- - prev = data.first ().data;- index = 0;- foreach (Item i in data) {- cmp = compare (prev.name, i);- - if (cmp == 1) {- continue;- }- - if (cmp == 0 && index != 0) {- warning (@"Value is not unique: $(i.name).");- return false;- }-- if (cmp == -1) {- warning (@"Value is not sorted: $cmp == cmp $(prev.name) $(i.name).");- return false;- }- - index++;- }- + public bool insert (string key, GlyphCollection g) {+ map.set (key, g); return true; }-- class Item : GLib.Object {- public string name;- public GlyphCollection glyph_collection;- - public Item (string n, GlyphCollection gc) {- glyph_collection = gc;- name = n;- }- }-- class RowItem : GLib.Object {- public unowned List<RowItem> next_row;- public unowned List<Item> item;- public int level = 0;- public bool last = false;- } } }@@ -104,6 +104,10 @@ public class KerningList : FontDisplay { scroll = (int) (pairs - visible_rows); } + if (visible_rows > pairs) {+ scroll = 0;+ } + update_scrollbar (); redraw_area (0, 0, allocation.width, allocation.height); }@@ -54,6 +54,16 @@ public class MainWindow { idle.attach (null); } + public static void select_all_paths () { + Tool t = tools.get_current_tool (); + + if (! (t is MoveTool || t is ResizeTool)) { + Toolbox.select_tool_by_name ("move"); + } + + get_current_glyph ().select_all_paths (); + } + public static DrawingTools get_drawing_tools () { return tools.drawing_tools; } @@ -19,23 +19,19 @@ namespace BirdFont { class MoveTool : Tool { - bool move_path = false;- bool moved = false;- double last_x = 0;- double last_y = 0;+ static bool move_path = false;+ static bool moved = false;+ static double last_x = 0;+ static double last_y = 0; - double selection_x = 0;- double selection_y = 0; - bool group_selection= false;+ static double selection_x = 0;+ static double selection_y = 0; + static bool group_selection= false; - bool rotate_path = false;- double last_rotate_y; static double selection_box_width = 0; static double selection_box_height = 0; static double selection_box_center_x = 0; static double selection_box_center_y = 0;- double rotation = 0;- double last_rotate = 0; public MoveTool (string n) { base (n, _("Move paths"), 'm', CTRL);@@ -44,137 +40,126 @@ class MoveTool : Tool { }); deselect_action.connect((self) => {- Glyph glyph = MainWindow.get_current_glyph ();- glyph.clear_active_paths (); }); press_action.connect((self, b, x, y) => {- Glyph glyph = MainWindow.get_current_glyph ();- - glyph.store_undo_state ();- group_selection = false;- - foreach (Path p in glyph.active_paths) {- if (is_over_rotate_handle (p, x, y)) {- rotate_path = true;- return;- }- }- - if (!glyph.is_over_selected_path (x, y)) {- if (!glyph.select_path (x, y)) {- glyph.clear_active_paths ();- }- }- - move_path = true;-- last_rotate = 0;- rotation = 0;- last_rotate_y = y;-- update_selection_boundries ();- - last_x = x;- last_y = y;- - if (glyph.active_paths.length () == 0) {- group_selection = true;- selection_x = x;- selection_y = y; - }- - update_boundries_for_selection ();+ press (b, x, y); }); release_action.connect((self, b, x, y) => {- Glyph glyph = MainWindow.get_current_glyph ();- - move_path = false;- rotate_path = false;- - if (GridTool.is_visible () && moved) {- foreach (Path p in glyph.active_paths) {- tie_path_to_grid (p, x, y);- }- } else if (GridTool.has_ttf_grid ()) {- foreach (Path p in glyph.active_paths) {- tie_path_to_ttf_grid (p, x, y);- }- } - - if (group_selection) {- select_group ();- }- - group_selection = false;- moved = false;+ release (b, x, y); }); move_action.connect ((self, x, y) => {- Glyph glyph = MainWindow.get_current_glyph ();- double dx = last_x - x;- double dy = last_y - y; - double p = PenTool.precision;- - if (move_path && (fabs(dx) > 0 || fabs (dy) > 0)) {- moved = true;- foreach (Path path in glyph.active_paths) {- path.move (Glyph.ivz () * -dx * p, Glyph.ivz () * dy * p);- }- }- - if (rotate_path) {- rotate (x, y);+ move (x, y);+ });+ + key_press_action.connect ((self, keyval) => {+ key_press (keyval);+ });+ + draw_action.connect ((self, cr, glyph) => {+ draw_actions (cr);+ });+ }++ public static void draw_actions (Context cr) {+ if (group_selection) {+ draw_selection_box (cr);+ }+ }+ + public static void key_press (uint32 keyval) {+ Glyph g = MainWindow.get_current_glyph ();+ + // delete selected paths+ if (keyval == Key.DEL || keyval == Key.BACK_SPACE) {+ foreach (Path p in g.active_paths) {+ g.path_list.remove (p);+ g.update_view (); } - if (!rotate_path) {- update_boundries_for_selection ();- get_selection_box_boundries (out selection_box_center_x,- out selection_box_center_y, out selection_box_width,- out selection_box_height); + while (g.active_paths.length () > 0) {+ g.active_paths.remove_link (g.active_paths.first ());+ }+ }+ + if (is_arrow_key (keyval)) {+ move_selected_paths (keyval);+ }+ }+ + public static void move (int x, int y) {+ Glyph glyph = MainWindow.get_current_glyph ();+ double dx = last_x - x;+ double dy = last_y - y; + double p = PenTool.precision;+ + if (move_path && (fabs(dx) > 0 || fabs (dy) > 0)) {+ moved = true;+ foreach (Path path in glyph.active_paths) {+ path.move (Glyph.ivz () * -dx * p, Glyph.ivz () * dy * p); }+ } - last_x = x;- last_y = y;+ last_x = x;+ last_y = y; - GlyphCanvas.redraw ();- });+ GlyphCanvas.redraw ();+ }+ + public static void release (int b, int x, int y) {+ Glyph glyph = MainWindow.get_current_glyph (); - key_press_action.connect ((self, keyval) => {- Glyph g = MainWindow.get_current_glyph ();- - // delete selected paths- if (keyval == Key.DEL || keyval == Key.BACK_SPACE) {- foreach (Path p in g.active_paths) {- g.path_list.remove (p);- g.update_view ();- }-- while (g.active_paths.length () > 0) {- g.active_paths.remove_link (g.active_paths.first ());- }+ move_path = false;+ + if (GridTool.is_visible () && moved) {+ foreach (Path p in glyph.active_paths) {+ tie_path_to_grid (p, x, y); }- - if (is_arrow_key (keyval)) {- move_selected_paths (keyval);+ } else if (GridTool.has_ttf_grid ()) {+ foreach (Path p in glyph.active_paths) {+ tie_path_to_ttf_grid (p, x, y); }- });+ } - draw_action.connect ((self, cr, glyph) => {- Glyph g = MainWindow.get_current_glyph ();- - if (g.active_paths.length () > 0) {- draw_rotate_handle (cr);- }- - if (group_selection) {- draw_selection_box (cr);+ if (group_selection) {+ select_group ();+ }+ + group_selection = false;+ moved = false; + }+ + public static void press (int b, int x, int y) {+ Glyph glyph = MainWindow.get_current_glyph ();+ + glyph.store_undo_state ();+ group_selection = false;+ + if (!glyph.is_over_selected_path (x, y)) {+ if (!glyph.select_path (x, y)) {+ glyph.clear_active_paths (); }- });+ }+ + move_path = true;++ update_selection_boundries ();+ + last_x = x;+ last_y = y;+ + if (glyph.active_paths.length () == 0) {+ group_selection = true;+ selection_x = x;+ selection_y = y; + }+ + update_boundries_for_selection (); } - void select_group () {+ static void select_group () { double x1 = Glyph.path_coordinate_x (Math.fmin (selection_x, last_x)); double y1 = Glyph.path_coordinate_y (Math.fmin (selection_y, last_y)); double x2 = Glyph.path_coordinate_x (Math.fmax (selection_x, last_x));@@ -185,18 +170,20 @@ class MoveTool : Tool { foreach (Path p in glyph.path_list) { if (p.xmin > x1 && p.xmax < x2 && p.ymin < y1 && p.ymax > y2) {- glyph.active_paths.append (p);+ if (p.points.length () > 0) {+ glyph.active_paths.append (p);+ } } } } - static void update_selection_boundries () {+ public static void update_selection_boundries () { get_selection_box_boundries (out selection_box_center_x, out selection_box_center_y, out selection_box_width, out selection_box_height); } - void draw_selection_box (Context cr) {+ static void draw_selection_box (Context cr) { double x = Math.fmin (selection_x, last_x); double y = Math.fmin (selection_y, last_y); @@ -212,33 +199,6 @@ class MoveTool : Tool { cr.restore (); }-- void draw_rotate_handle (Context cr) {- double cx, cy, hx, hy;- - cx = Glyph.reverse_path_coordinate_x (selection_box_center_x);- cy = Glyph.reverse_path_coordinate_y (selection_box_center_y);- - cr.save ();- - cr.set_source_rgba (0, 0, 0.3, 1);- cr.rectangle (cx - 2.5, cy - 2.5, 5, 5);- cr.fill ();-- hx = cos (rotation) * 75;- hy = sin (rotation) * 75;-- cr.set_line_width (1);- cr.move_to (cx, cy);- cr.line_to (cx + hx, cy + hy);- cr.stroke ();-- cr.set_source_rgba (0, 0, 0.3, 1);- cr.rectangle (cx + hx - 2.5, cy + hy - 2.5, 5, 5);- cr.fill ();- - cr.restore (); - } public static void get_selection_box_boundries (out double x, out double y, out double w, out double h) { double px, py, px2, py2;@@ -273,7 +233,7 @@ class MoveTool : Tool { y = py + (h / 2); } - void move_selected_paths (uint key) {+ static void move_selected_paths (uint key) { Glyph glyph = MainWindow.get_current_glyph (); double x, y; @@ -304,11 +264,11 @@ class MoveTool : Tool { glyph.redraw_area (0, 0, glyph.allocation.width, glyph.allocation.height); } - void tie_path_to_ttf_grid (Path p, double x, double y) {+ static void tie_path_to_ttf_grid (Path p, double x, double y) { tie_path_to_grid (p, x, y, true); } - void tie_path_to_grid (Path p, double x, double y, bool ttf_grid = false) {+ static void tie_path_to_grid (Path p, double x, double y, bool ttf_grid = false) { double sx, sy, qx, qy; // tie to grid@@ -345,62 +305,6 @@ class MoveTool : Tool { } } - /** Move rotate handle to pixel x,y. */- void rotate (double x, double y) {- double cx, cy, xc, yc, xc2, yc2, a, b, w, h; - Glyph glyph = MainWindow.get_current_glyph (); - double dx, dy;- - cx = Glyph.reverse_path_coordinate_x (selection_box_center_x);- cy = Glyph.reverse_path_coordinate_y (selection_box_center_y);- xc = selection_box_center_x;- yc = selection_box_center_y;- - a = x - cx;- b = y - cy;- - rotation = atan (b / a);- - if (a < 0) {- rotation += PI;- }- - foreach (Path p in glyph.active_paths) {- p.rotate (rotation - last_rotate, selection_box_center_x, selection_box_center_y);- }-- get_selection_box_boundries (out xc2, out yc2, out w, out h); -- dx = -(xc2 - xc);- dy = -(yc2 - yc);- - foreach (Path p in glyph.active_paths) {- p.move (dx, dy);- }- - last_rotate = rotation;- - update_selection_boundries ();- }-- bool is_over_rotate_handle (Path p, double x, double y) {- double cx, cy, hx, hy;- double size = 10;- bool inx, iny;- - cx = Glyph.reverse_path_coordinate_x (selection_box_center_x);- cy = Glyph.reverse_path_coordinate_y (selection_box_center_y);-- hx = cos (rotation) * 75;- hy = sin (rotation) * 75;-- inx = x - size <= cx + hx - 2.5 <= x + size;- iny = y - size <= cy + hy - 2.5 <= y + size;- - return inx && iny;- }-- public static void flip_vertical () { flip (true); }@@ -116,6 +116,10 @@ class GlyfTable : Table { num_glyphs = glyphs.length (); + if (glyphs.length () == 0) {+ warning ("No glyphs in glyf table.");+ }+ foreach (Glyph g in glyphs) { // set values for loca table assert (fd.length () % 4 == 0);@@ -155,6 +159,10 @@ class GlyfTable : Table { unassigned_glyphs = new List<Glyph> (); + if (font.get_glyph_indice (0) == null) {+ warning ("No glyphs in font.");+ }+ // add glyphs, first all assigned then the unassigned ones for (indice = 0; (gl = font.get_glyph_indice (indice)) != null; indice++) { g = (!) gl;@@ -176,6 +184,7 @@ class GlyfTable : Table { if (!g.is_unassigned ()) { glyphs.append (g); } else {+ printd ("Adding unassigned glyph."); unassigned_glyphs.append (g); } }@@ -75,8 +75,4 @@ class OpenFontFormatWriter : Object { } } -void printd (string s) {- //print (s);-}- }@@ -791,6 +791,7 @@ public class OverView : FontDisplay { double nrows = 0; double pos = 0; double size;+ double visible_rows; if (rows == 0) { MainWindow.set_scrollbar_size (0);@@ -809,9 +810,11 @@ public class OverView : FontDisplay { nrows = 1; } - scroll_size = rows / (nrows - rows);+ // FIXME: this is not correct+ visible_rows = allocation.height / OverViewItem.height;+ scroll_size = visible_rows / nrows; MainWindow.set_scrollbar_size (scroll_size);- pos = first_visible / (nrows * items_per_row - rows * items_per_row);+ pos = first_visible / (nrows * items_per_row - visible_rows * items_per_row); MainWindow.set_scrollbar_position (pos); } }@@ -465,6 +465,8 @@ public class PenTool : Tool { } } }+ + update_selected_points (); } public static bool is_counter_path (Path path) {@@ -29,9 +29,14 @@ class ResizeTool : Tool { static double selection_box_height = 0; static double selection_box_center_x = 0; static double selection_box_center_y = 0;- ++ static bool rotate_path = false;+ static double last_rotate_y;+ static double rotation = 0;+ static double last_rotate = 0;+ public ResizeTool (string n) {- base (n, _("Resize paths"));+ base (n, _("Resize and rotate paths")); resize_handle = Icons.get_icon ("resize_handle.png"); @@ -39,8 +44,6 @@ class ResizeTool : Tool { }); deselect_action.connect((self) => {- Glyph glyph = MainWindow.get_current_glyph ();- glyph.clear_active_paths (); }); press_action.connect((self, b, x, y) => {@@ -64,18 +67,26 @@ class ResizeTool : Tool { return; } }- - if (!glyph.is_over_selected_path (x, y)) {- if (!glyph.select_path (x, y)) {- glyph.clear_active_paths ();++ foreach (Path p in glyph.active_paths) {+ if (is_over_rotate_handle (p, x, y)) {+ rotate_path = true;+ return; } }+ + last_rotate = 0;+ rotation = 0;+ last_rotate_y = y; - update_selection_boundries ();++ MoveTool.press (b, x, y); }); release_action.connect((self, b, x, y) => { resize_path = false;+ rotate_path = false;+ MoveTool.release (b, x, y); }); move_action.connect ((self, x, y) => {@@ -83,7 +94,19 @@ class ResizeTool : Tool { resize (x, y); } + if (rotate_path) {+ rotate (x, y);+ }++ if (!rotate_path) {+ MoveTool.update_boundries_for_selection ();+ MoveTool.get_selection_box_boundries (out selection_box_center_x,+ out selection_box_center_y, out selection_box_width,+ out selection_box_height); + }+ GlyphCanvas.redraw ();+ MoveTool.move (x, y); }); draw_action.connect ((self, cr, glyph) => {@@ -95,15 +118,94 @@ class ResizeTool : Tool { cr.paint (); } -+ if (g.active_paths.length () > 0) {+ draw_rotate_handle (cr);+ }+ + MoveTool.draw_actions (cr); }); } - static void update_selection_boundries () {- MoveTool.update_boundries_for_selection ();- MoveTool.get_selection_box_boundries (out selection_box_center_x,- out selection_box_center_y, out selection_box_width,- out selection_box_height); + /** Move rotate handle to pixel x,y. */+ static void rotate (double x, double y) {+ double cx, cy, xc, yc, xc2, yc2, a, b, w, h; + Glyph glyph = MainWindow.get_current_glyph (); + double dx, dy;+ + cx = Glyph.reverse_path_coordinate_x (selection_box_center_x);+ cy = Glyph.reverse_path_coordinate_y (selection_box_center_y);+ xc = selection_box_center_x;+ yc = selection_box_center_y;+ + a = x - cx;+ b = y - cy;+ + rotation = atan (b / a);+ + if (a < 0) {+ rotation += PI;+ }+ + foreach (Path p in glyph.active_paths) {+ p.rotate (rotation - last_rotate, selection_box_center_x, selection_box_center_y);+ }++ MoveTool.get_selection_box_boundries (out xc2, out yc2, out w, out h); ++ dx = -(xc2 - xc);+ dy = -(yc2 - yc);+ + foreach (Path p in glyph.active_paths) {+ p.move (dx, dy);+ }+ + last_rotate = rotation;+ + MoveTool.update_selection_boundries ();+ }++ static bool is_over_rotate_handle (Path p, double x, double y) {+ double cx, cy, hx, hy;+ double size = 10;+ bool inx, iny;+ + cx = Glyph.reverse_path_coordinate_x (selection_box_center_x);+ cy = Glyph.reverse_path_coordinate_y (selection_box_center_y);++ hx = cos (rotation) * 75;+ hy = sin (rotation) * 75;++ inx = x - size <= cx + hx - 2.5 <= x + size;+ iny = y - size <= cy + hy - 2.5 <= y + size;+ + return inx && iny;+ }+ + static void draw_rotate_handle (Context cr) {+ double cx, cy, hx, hy;+ + cx = Glyph.reverse_path_coordinate_x (selection_box_center_x);+ cy = Glyph.reverse_path_coordinate_y (selection_box_center_y);+ + cr.save ();+ + cr.set_source_rgba (0, 0, 0.3, 1);+ cr.rectangle (cx - 2.5, cy - 2.5, 5, 5);+ cr.fill ();++ hx = cos (rotation) * 75;+ hy = sin (rotation) * 75;++ cr.set_line_width (1);+ cr.move_to (cx, cy);+ cr.line_to (cx + hx, cy + hy);+ cr.stroke ();++ cr.set_source_rgba (0, 0, 0.3, 1);+ cr.rectangle (cx + hx - 2.5, cy + hy - 2.5, 5, 5);+ cr.fill ();+ + cr.restore (); } double get_resize_ratio (double x, double y) {@@ -186,13 +186,18 @@ public class TabBar : GLib.Object { public bool close_tab (int index, bool background_tab = false) { unowned List<Tab?>? lt; Tab t;+ EmptyTab empty_tab_canvas;+ Tab empty_tab; - if (tabs.length () <= 1) {+ if (!(0 <= index < tabs.length ())) { return false; } - if (!(0 <= index < tabs.length ())) {- return false;+ if (tabs.length () == 1) {+ empty_tab_canvas = new EmptyTab ("", "");+ MainWindow.get_glyph_canvas ().set_current_glyph (empty_tab_canvas);+ empty_tab = new Tab (empty_tab_canvas, 0, false);+ signal_tab_selected (empty_tab); } lt = tabs.nth(index);@@ -218,6 +223,7 @@ public class TabBar : GLib.Object { } select_tab (index);+ return false; } @@ -24,7 +24,6 @@ class TestCases { add (test_data_reader, "Font data reader"); add (test_argument, "Argument list"); add (test_glyph_ranges, "Glyph ranges");- add (test_glyph_table, "Glyph table"); add (test_hex, "Unicode hex values"); add (test_reverse_path, "Reverse path"); add (test_reverse_random_triangles, "Reverse random paths");@@ -742,79 +741,6 @@ class TestCases { } } - public static void test_glyph_table () {- GlyphTable table = new GlyphTable ();- List<GlyphCollection> gc = new List<GlyphCollection> ();- List<unowned GlyphCollection> gc_copy;- GlyphCollection g;- - return_if_fail (table.length () == 0);- return_if_fail (table.get ("Some glyph") == null);- - // generate test data- for (uint i = 0; i < 1000; i++) {- gc.append (new GlyphCollection (new Glyph (@"TEST $i", i + 'a')));- }-- g = gc.first ().data;- if (!table.insert (g.get_unicode (), g)) {- warning (@"Failed to insert $(g.get_name ())");- return;- }- gc.append (g);- - // insert in random order- gc_copy = gc.copy ();- for (uint i = 0; gc_copy.length () > 0; i++) {- int t = (int) ((gc_copy.length () - 1) * Random.next_double ());- g = gc_copy.nth (t).data;- - if (!table.insert (g.get_name (), g)) {- warning (@"Failed to insert $(g.get_name ())");- return;- }- - gc_copy.remove_all (g);- - if (!table.validate_index ()) {- table.print_all ();- warning ("index is invalid");- return;- }- }- - if (table.length () != gc.length ()) {- warning ("Table length does not match number of glyphs, $(table.length ()) != $(gc.length ())");- return;- }- - // validate table- for (uint i = 0; i > 1000; i++) {- g = (!) table.get (gc.nth (i).data.get_name ());- return_if_fail (gc.nth (i).data == g);- }- - // search - for (int i = 0; i < 2000; i++) {- int t = (int) (999 * Random.next_double ());- if (table.get (@"TEST $t") == null) {- table.print_all ();- warning (@"Did't find TEST $t in glyph table.");- return;- }- }- - // remove- table.remove ("TEST 0");- table.remove ("TEST 53");- return_if_fail (table.get ("TEST 0") == null);- return_if_fail (table.get ("TEST 53") == null);- - // search - return_if_fail (table.get ("TEST 52") != null);- return_if_fail (table.get ("TEST 54") != null);- }- public static void test_hex () { test_hex_conv ('H', "U+48", 72); test_hex_conv ('1', "U+31", 49);@@ -23,7 +23,7 @@ class ZoomTool : Tool { List<Tab> views = new List<Tab> (); public ZoomTool (string n) {- base (n, "Zoom");+ base (n, "Zoom", 'z'); select_action.connect((self) => { });