Commit 963e81c
Spacing classes Update side bearings and all kerning pairs for one or more glyphs at the same time.
Changed files (18)
modifiedbirdfont/GtkWindow.valamodifiedlibbirdfont/BirdFontFile.valamodifiedlibbirdfont/BirdFontPart.valamodifiedlibbirdfont/DrawingTools.valamodifiedlibbirdfont/Glyph.valamodifiedlibbirdfont/KerningClasses.valamodifiedlibbirdfont/KerningDisplay.valamodifiedlibbirdfont/KerningRange.valamodifiedlibbirdfont/KerningTools.valamodifiedlibbirdfont/MainWindow.valamodifiedlibbirdfont/MenuTab.valamodifiedlibbirdfont/OverView.valamodifiedlibbirdfont/PenTool.valamodifiedlibbirdfont/PreviewTools.valaaddedlibbirdfont/Row.valaaddedlibbirdfont/SpacingClass.valaaddedlibbirdfont/SpacingClassTab.valamodifiedlibbirdfont/ToolCollection.vala
Diff
@@ -717,6 +717,14 @@ public class GtkWindow : Gtk.Window, NativeWindow { MenuTab.list_all_kerning_pairs (); }); + Gtk.MenuItem spacing_kerning_tab = new Gtk.MenuItem.with_mnemonic (t_("Show _Spacing Tab"));+ kerning_menu.append (spacing_kerning_tab);+ spacing_kerning_tab.activate.connect (() => { + MenuTab.show_spacing_tab ();+ });+ spacing_kerning_tab.add_accelerator ("activate", accel_group, 'k', Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);++ kerning_menu.append (new SeparatorMenuItem ()); Gtk.MenuItem select_next_kerning_pair = new Gtk.MenuItem.with_mnemonic (" Ctrl+→ " + t_("Select _Next Kerning Pair"));@@ -162,7 +162,7 @@ class BirdFontFile : GLib.Object { TooltipArea.show_text (t_("Saving")); });- + font.glyph_cache.for_each ((gc) => { BackgroundImage bg; @@ -193,6 +193,7 @@ class BirdFontFile : GLib.Object { TooltipArea.show_text (t_("Saving")); }); + write_spacing_classes (os); write_kerning (os); write_closing_root_tag (os); @@ -216,6 +217,23 @@ class BirdFontFile : GLib.Object { os.put_string ("</font>\n"); } + public void write_spacing_classes (DataOutputStream os) throws GLib.Error {+ SpacingClassTab s = MainWindow.get_spacing_class_tab ();+ + foreach (SpacingClass sc in s.classes) {+ os.put_string ("<spacing ");+ os.put_string ("first=\"");+ os.put_string (Font.to_hex (sc.first.get_char ()));+ os.put_string ("\" ");+ + os.put_string ("next=\"");+ os.put_string (Font.to_hex (sc.next.get_char ()));+ os.put_string ("\" ");+ + os.put_string (" />\n");+ }+ }+ public void write_kerning (DataOutputStream os) throws GLib.Error { uint num_kerning_pairs; string range;@@ -657,7 +675,11 @@ class BirdFontFile : GLib.Object { if (iter->name == "kerning") { parse_kerning (iter); }- ++ if (iter->name == "spacing") {+ parse_spacing_class (iter);+ }+ TooltipArea.show_text (t_("Loading XML data.")); } @@ -696,6 +718,31 @@ class BirdFontFile : GLib.Object { return GlyphRange.get_serialized_char (c); } + private void parse_spacing_class (Xml.Node* node) {+ string attr_name;+ string attr_content;+ string first, next;+ SpacingClassTab spacing_class_tab = MainWindow.get_spacing_class_tab ();+ + first = "";+ next = "";+ + for (Xml.Attr* prop = node->properties; prop != null; prop = prop->next) {+ attr_name = prop->name;+ attr_content = prop->children->content;+ + if (attr_name == "first") {+ first = (!) Font.to_unichar (attr_content).to_string ();+ }++ if (attr_name == "next") {+ next = (!) Font.to_unichar (attr_content).to_string ();+ } + }+ + spacing_class_tab.add_class (first, next);+ }+ private void parse_kerning (Xml.Node* node) { string attr_name; string attr_content;@@ -742,7 +789,7 @@ class BirdFontFile : GLib.Object { warning (e.message); } }- + private void parse_old_kerning (Xml.Node* node) { string attr_name; string attr_content;@@ -172,6 +172,12 @@ class BirdFontPart : GLib.Object{ bf.write_closing_root_tag (os); os.close (); + os = create_file ("spacing.bfp");+ bf.write_root_tag (os);+ bf.write_spacing_classes (os);+ bf.write_closing_root_tag (os);+ os.close ();+ font.glyph_cache.for_each ((gc) => { try { string selected_file_name;@@ -20,7 +20,7 @@ namespace BirdFont { public class DrawingTools : ToolCollection { GlyphCanvas glyph_canvas; - public List<Expander> expanders;+ public Gee.ArrayList<Expander> expanders = new Gee.ArrayList<Expander> (); Expander draw_tools; Expander grid_expander;@@ -92,7 +92,6 @@ public class DrawingTools : ToolCollection { Expander view_tools = new Expander (); Expander grid = new Expander (); - Expander background_tools = new Expander (); Expander style_tools = new Expander (); grid_expander = grid;@@ -1354,7 +1353,7 @@ public class DrawingTools : ToolCollection { idle.attach (null); } - public override unowned List<Expander> get_expanders () {+ public override Gee.ArrayList<Expander> get_expanders () { return expanders; } @@ -1433,7 +1432,7 @@ public class DrawingTools : ToolCollection { } private void add_expander (Expander e) {- expanders.append (e);+ expanders.add (e); } } @@ -450,13 +450,15 @@ public class Glyph : FontDisplay { Line left_line = new Line ("left", left_limit, true); left_line.position_updated.connect ((pos) => {- left_limit = pos;- });+ left_limit = pos;+ update_other_spacing_classes ();+ }); Line right_line = new Line ("right", right_limit, true); right_line.position_updated.connect ((pos) => {- right_limit = pos;- });+ right_limit = pos;+ update_other_spacing_classes ();+ }); // lists of lines are sorted and lines are added only if // they are relevant for a particular glyph.@@ -2015,6 +2017,50 @@ public class Glyph : FontDisplay { last_tap1_y = y; } }+ + public void update_spacing_class () {+ Font font = BirdFont.get_current_font ();+ GlyphCollection? g;+ GlyphCollection gc;+ Glyph glyph;+ + foreach (string l in MainWindow.get_spacing_class_tab ()+ .get_all_connections ((!) unichar_code.to_string ())) {+ if (l != (!) unichar_code.to_string ()) {+ g = font.get_glyph_collection (l);+ if (g != null) {+ gc = (!) g;+ glyph = gc.get_current ();+ left_limit = glyph.left_limit;+ right_limit = glyph.right_limit;+ break;+ }+ }+ }+ + add_help_lines ();+ }++ public void update_other_spacing_classes () {+ Font font = BirdFont.get_current_font ();+ GlyphCollection? g;+ GlyphCollection gc;+ Glyph glyph;+ + foreach (string l in MainWindow.get_spacing_class_tab ()+ .get_all_connections ((!) unichar_code.to_string ())) {+ if (l != (!) unichar_code.to_string ()) {+ g = font.get_glyph_collection (l);+ if (g != null) {+ gc = (!) g;+ glyph = gc.get_current ();+ glyph.left_limit = left_limit;+ glyph.right_limit = right_limit;+ glyph.add_help_lines ();+ }+ }+ } + } } }@@ -52,15 +52,43 @@ public class KerningClasses : GLib.Object { return BirdFont.get_current_font ().get_kerning_classes (); } - public double? get_kerning_for_single_glyphs (string l, string r) {- string left = GlyphRange.serialize (l);- string right = GlyphRange.serialize (r);- return single_kerning.get (@"$left - $right");+ public void update_space_class (string c) {+ double? k;+ + foreach (string l in single_kerning_letters_left) { + k = get_kerning_for_single_glyphs (l, c);+ + if (k != null) {+ set_kerning_for_single_glyphs (l, c, (!) k);+ }+ }++ foreach (string r in single_kerning_letters_right) { + k = get_kerning_for_single_glyphs (c, r);+ + if (k != null) {+ set_kerning_for_single_glyphs (c, r, (!) k);+ }+ } + }++ public double? get_kerning_for_single_glyphs (string first, string next) {+ double? k = null;+ string left = GlyphRange.unserialize (first);+ string right = GlyphRange.unserialize (next);++ foreach (string l in get_spacing_class (left)) {+ foreach (string r in get_spacing_class (right)) {+ k = single_kerning.get (@"$l - $r");+ }+ }+ + return k; } - public void set_kerning_for_single_glyphs (string l, string r, double k) {- string left = GlyphRange.serialize (l);- string right = GlyphRange.serialize (r);+ public void set_kerning_for_single_glyphs (string le, string ri, double k) {+ string left = GlyphRange.serialize (le);+ string right = GlyphRange.serialize (ri); string cleft = (!)GlyphRange.unserialize (left).get_char ().to_string (); string cright = (!)GlyphRange.unserialize (right).get_char ().to_string (); @@ -68,16 +96,22 @@ public class KerningClasses : GLib.Object { warning ("Map is protected."); return; }- - if (!single_kerning_letters_left.contains (cleft)) {- single_kerning_letters_left.add (cleft);- } - if (!single_kerning_letters_right.contains (cright)) {- single_kerning_letters_right.add (cright);+ foreach (string l in get_spacing_class (cleft)) {+ foreach (string r in get_spacing_class (cright)) {+ if (!single_kerning_letters_left.contains (cleft)) {+ single_kerning_letters_left.add (cleft);+ }++ if (!single_kerning_letters_right.contains (cright)) {+ single_kerning_letters_right.add (cright);+ }++ left = GlyphRange.serialize (l);+ right = GlyphRange.serialize (r);+ single_kerning.set (@"$left - $right", k);+ } }- - single_kerning.set (@"$left - $right", k); } public void set_kerning (GlyphRange left_range, GlyphRange right_range, double k, int class_index = -1) {@@ -118,14 +152,20 @@ public class KerningClasses : GLib.Object { } public bool has_kerning (string first, string next) {- string f = GlyphRange.serialize (first);- string n = GlyphRange.serialize (next); + string f = "";+ string n = ""; GlyphRange gf, gn; - if (single_kerning.has_key (@"$f - $n")) {- return true;+ foreach (string l in get_spacing_class (first)) {+ foreach (string r in get_spacing_class (next)) {+ f = GlyphRange.serialize (l);+ n = GlyphRange.serialize (r); + if (single_kerning.has_key (@"$f - $n")) {+ return true;+ }+ } }-+ gf = new GlyphRange (); gn = new GlyphRange (); @@ -171,7 +211,7 @@ public class KerningClasses : GLib.Object { GlyphRange l; int len = (int) classes_first.size; - len = (int)classes_first.size;+ len = (int) classes_first.size; return_val_if_fail (len == classes_last.size, 0); return_val_if_fail (len == classes_kerning.size, 0); @@ -236,19 +276,23 @@ public class KerningClasses : GLib.Object { return -1; } - for (int i = len - 1; i >= 0; i--) {- l = classes_first.get (i);- r = classes_last.get (i);- - if (l.get_all_ranges () == left_range.get_all_ranges ()- && r.has_character (right_char)) {- return classes_kerning.get (i).val;+ foreach (string right in get_spacing_class (right_char)) {+ for (int i = len - 1; i >= 0; i--) {+ l = classes_first.get (i);+ r = classes_last.get (i);+ + if (l.get_all_ranges () == left_range.get_all_ranges ()+ && r.has_character (right)) {+ return classes_kerning.get (i).val;+ } } } return 0; } ++ public double get_kern_for_char_to_range (string left_char, GlyphRange right_range) { GlyphRange r; GlyphRange l;@@ -263,13 +307,15 @@ public class KerningClasses : GLib.Object { return 0; } - for (int i = len - 1; i >= 0; i--) {- l = classes_first.get (i);- r = classes_last.get (i);- - if (l.has_character (left_char)- && r.get_all_ranges () == right_range.get_all_ranges ()) {- return classes_kerning.get (i).val;+ foreach (string left in get_spacing_class (left_char)) {+ for (int i = len - 1; i >= 0; i--) {+ l = classes_first.get (i);+ r = classes_last.get (i);+ + if (l.has_character (left)+ && r.get_all_ranges () == right_range.get_all_ranges ()) {+ return classes_kerning.get (i).val;+ } } } @@ -333,6 +379,7 @@ public class KerningClasses : GLib.Object { kerningIterator (chars[0], chars[1], k); } }+ set_protect_map (false); } @@ -457,8 +504,20 @@ public class KerningClasses : GLib.Object { classes_last.remove_at (index); classes_kerning.remove_at (index); }-+ + private Gee.ArrayList<string> get_spacing_class (string c) {+ return MainWindow.get_spacing_class_tab ().get_all_connections (c);+ }+ public void delete_kerning_for_pair (string left, string right) {+ foreach (string l in get_spacing_class (left)) {+ foreach (string r in get_spacing_class (right)) {+ delete_kerning_for_one_pair (l, r);+ }+ }+ }++ private void delete_kerning_for_one_pair (string left, string right) { bool has_left, has_right; string[] p; @@ -379,6 +379,7 @@ public class KerningDisplay : FontDisplay { left_active_glyph.right_limit += val; left_active_glyph.remove_lines (); left_active_glyph.add_help_lines ();+ left_active_glyph.update_other_spacing_classes (); } } @@ -58,20 +58,37 @@ public class KerningRange : Tool { } public void set_ranges (string r) {- ranges = r;- name = r;-- try {- glyph_range.empty ();- glyph_range.parse_ranges (r);- glyph_range.set_class (true);+ GlyphRange glyph_range = new GlyphRange ();+ string new_range;+ string ch;+ try { + glyph_range.parse_ranges (r);+ new_range = glyph_range.get_all_ranges ();+ + for (int i = 0; i < glyph_range.get_length (); i++) {+ ch = glyph_range.get_char (i); - malformed = false;- } catch (MarkupError e) {- KerningClasses.get_instance ().print_all ();- warning (e.message);- malformed = true;+ foreach (string c in MainWindow.get_spacing_class_tab ().get_all_connections (ch)) {+ new_range += " " + GlyphRange.serialize (c);+ } }+ + set_one_range (new_range);+ malformed = false;+ } catch (MarkupError e) {+ KerningClasses.get_instance ().print_all ();+ warning (e.message);+ malformed = true;+ }+ }+ + private void set_one_range (string r) throws MarkupError {+ ranges = r;+ name = r;++ glyph_range.empty ();+ glyph_range.parse_ranges (r);+ glyph_range.set_class (true); } public void update_kerning_classes () {@@ -18,7 +18,7 @@ using Math; namespace BirdFont { public class KerningTools : ToolCollection {- public static List<Expander> expanders;+ public static Gee.ArrayList<Expander> expanders = new Gee.ArrayList<Expander> (); public static int next_class = 0; public static Expander classes; public static bool adjust_side_bearings = false;@@ -118,8 +118,8 @@ public class KerningTools : ToolCollection { classes.set_persistent (true); classes.set_unique (true); - expanders.append (kerning_tools);- expanders.append (classes);+ expanders.add (kerning_tools);+ expanders.add (classes); } public static void add_unique_class (KerningRange kerning_class) {@@ -210,7 +210,7 @@ public class KerningTools : ToolCollection { } } - public override unowned List<Expander> get_expanders () {+ public override Gee.ArrayList<Expander> get_expanders () { return expanders; } }@@ -28,6 +28,7 @@ public class MainWindow : GLib.Object { public static KerningDisplay kerning_display; public static CharDatabase character_database; public static LigatureList ligature_display; + public static SpacingClassTab spacing_class_tab; /** Number of pixels per mm */ public static double units = 1; @@ -45,6 +46,7 @@ public class MainWindow : GLib.Object { kerning_display = new KerningDisplay (); character_database = new CharDatabase (); ligature_display = new LigatureList (); + spacing_class_tab = new SpacingClassTab (); } /** Set the number of picels per millimeter for the current screen. */ @@ -145,6 +147,10 @@ public class MainWindow : GLib.Object { return over_view; } + public static SpacingClassTab get_spacing_class_tab () { + return spacing_class_tab; + } + public static void update_glyph_sequence () { TextListener listener = new TextListener (t_("Glyph sequence"), Preferences.get ("glyph_sequence"), t_("Close")); listener.signal_text_input.connect ((text) => { @@ -221,6 +221,8 @@ public class MenuTab : FontDisplay { return; } + MainWindow.native_window.hide_text_input ();+ SaveDialogListener dialog = new SaveDialogListener (); Font font = BirdFont.get_current_font (); @@ -448,6 +450,11 @@ public class MenuTab : FontDisplay { g.active_paths.clear (); g.update_view (); }+ + public static void show_spacing_tab () {+ SpacingClassTab t = MainWindow.get_spacing_class_tab ();+ MainWindow.get_tab_bar ().add_unique_tab (t);+ } } }@@ -80,9 +80,7 @@ public class OverView : FontDisplay { this.open_new_glyph_signal.connect ((character) => { StringBuilder name = new StringBuilder (); TabBar tabs = MainWindow.get_tab_bar ();- Font font = BirdFont.get_current_font (); bool selected;- GlyphCollection? fg; Glyph glyph; GlyphCollection glyph_collection; GlyphCanvas canvas;@@ -114,13 +112,11 @@ public class OverView : FontDisplay { public GlyphCollection add_character_to_font (unichar character, bool empty = false) { StringBuilder name = new StringBuilder ();- TabBar tabs = MainWindow.get_tab_bar (); Font font = BirdFont.get_current_font (); GlyphCollection? fg; Glyph glyph; GlyphCollection glyph_collection;- GlyphCanvas canvas;- + name.append_unichar (character); if (all_available) {@@ -2003,7 +2003,7 @@ public class PenTool : Tool { public static Path simplify (Path path, bool selected_segments = false, double threshold = 0.3) { PointSelection ps; EditPoint ep;- Path p1, p2, new_path;+ Path p1, new_path; double d, sumd; int i; @@ -15,7 +15,7 @@ namespace BirdFont { public class PreviewTools : ToolCollection {- public List<Expander> expanders;+ public Gee.ArrayList<Expander> expanders = new Gee.ArrayList<Expander> (); public Expander classes; public PreviewTools () {@@ -39,7 +39,7 @@ public class PreviewTools : ToolCollection { }); webview_tools.add_tool (generate_html_button); - expanders.append (webview_tools);+ expanders.add (webview_tools); } /** Export fonts and update html canvas. */@@ -70,7 +70,7 @@ public class PreviewTools : ToolCollection { Preview.generate_html_document (); } - public override unowned List<Expander> get_expanders () {+ public override Gee.ArrayList<Expander> get_expanders () { return expanders; } }new file mode 100644@@ -0,0 +1,63 @@+/*+ Copyright (C) 2014 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 Row : GLib.Object {++ int index = 0;+ bool delete_button = true;+ + Gee.ArrayList<string> columns_labels = new Gee.ArrayList<string> ();+ + public int columns {+ get {+ return columns_labels.size;+ }+ }+ + public Row (string label, int index, bool delete_button = true) {+ this.index = index;+ columns_labels.add (label);+ this.delete_button = delete_button;+ }+ + public Row.columns_3 (string label0, string label1, string label2, int index) {+ columns_labels.add (label0);+ columns_labels.add (label1);+ columns_labels.add (label2);+ this.index = index;+ }+ + public bool has_delete_button () {+ return delete_button;+ }+ + public string get_column (int i) {+ return_val_if_fail (0 <= i < columns, "".dup ());+ return columns_labels.get (i);+ }++ public int get_index () {+ return index;+ }++ public void set_index (int index) { + this.index = index;+ }+}++}new file mode 100644@@ -0,0 +1,71 @@+/*+ Copyright (C) 2014 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 SpacingClass : GLib.Object {++ public string first;+ public string next;++ bool update_first = true;+ TextListener listener;+ + public signal void updated (SpacingClass s);+ + public SpacingClass (string first, string next) {+ this.first = first;+ this.next = next;+ }+ + public void set_first () { + update_first = true;+ update (first);+ }+ + public void set_next () { + update_first = false;+ update (next);+ }+ + void update (string val) {+ listener = new TextListener (t_("Character"), val, t_("Set"));+ + listener.signal_text_input.connect ((text) => {+ string v = text;+ + if (v.has_prefix ("U+") || v.has_prefix ("u+")) {+ v = (!) Font.to_unichar (val).to_string ();+ }+ + if (update_first) {+ first = v.dup ();+ } else {+ next = v.dup ();+ }+ + updated (this);+ });+ + listener.signal_submit.connect (() => {+ MainWindow.native_window.hide_text_input ();+ });+ + MainWindow.native_window.set_text_listener (listener);+ }+}++}new file mode 100644@@ -0,0 +1,325 @@+/*+ Copyright (C) 2014 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 SpacingClassTab : FontDisplay {++ int scroll = 0;+ int visible_rows = 0;+ WidgetAllocation allocation = new WidgetAllocation ();+ Gee.ArrayList<Row> rows = new Gee.ArrayList<Row> ();+ + public Gee.ArrayList<SpacingClass> classes = new Gee.ArrayList<SpacingClass> ();+ + public static int NEW_CLASS = -1;+ + Gee.ArrayList<string> connections = new Gee.ArrayList<string> ();+ + public SpacingClassTab () {+ }++ public Gee.ArrayList<string> get_all_connections (string glyph) {+ Gee.ArrayList<string> c = new Gee.ArrayList<string> ();+ + connections.clear ();+ add_connections (glyph);+ + foreach (string t in connections) {+ c.add (t);+ }+ + connections.clear ();+ + return c;+ }+ + public void add_connections (string glyph) {+ connections.add (glyph);+ + foreach (SpacingClass s in classes) {+ if (s.first == glyph) {+ if (connections.index_of (s.next) == -1) {+ add_connections (s.next);+ }+ }++ if (s.next == glyph) {+ if (connections.index_of (s.first) == -1) {+ add_connections (s.first);+ }+ }+ }+ + connections.sort ((a, b) => {+ return strcmp (a, b);+ });+ }++ public void add_class (string first, string next) {+ SpacingClass s = new SpacingClass (first, next);+ s.updated.connect (update_all_rows);+ s.updated.connect (update_kerning);+ classes.add (s);+ update_kerning (s);+ }++ public void update_kerning (SpacingClass s) {+ Font font = BirdFont.get_current_font ();+ GlyphCollection? g;+ GlyphCollection gc;+ + if (s.next != "?") {+ KerningClasses.get_instance ().update_space_class (s.next);+ g = font.get_glyph_collection (s.next);+ if (g != null) {+ gc = (!) g;+ gc.get_current ().update_spacing_class ();+ }+ }+ + if (s.first != "?") {+ KerningClasses.get_instance ().update_space_class (s.first);+ g = font.get_glyph_collection (s.first);+ if (g != null) {+ gc = (!) g;+ gc.get_current ().update_spacing_class ();+ }+ }+ }++ public void selected_row (Row row, int column, bool delete_button) {+ Font font = BirdFont.get_current_font ();+ + if (row.get_index () == -1) {+ add_class ("?", "?");+ MainWindow.native_window.hide_text_input ();+ update_rows ();+ update_scrollbar ();+ font.touch ();+ } else if (classes.size != 0) {+ if (delete_button) {+ return_if_fail (0 <= row.get_index () < classes.size);+ classes.remove_at (row.get_index ());+ MainWindow.native_window.hide_text_input ();+ update_rows ();+ update_scrollbar ();+ font.touch ();+ } else if (column == 0) {+ if (!(0 <= row.get_index () < classes.size)) {+ warning (@"Index: $(row.get_index ()) classes.size: $(classes.size)");+ return;+ }+ classes.get (row.get_index ()).set_first ();+ font.touch ();+ } else if (column == 2) {+ return_if_fail (0 <= row.get_index () < classes.size);+ classes.get (row.get_index ()).set_next ();+ font.touch ();+ }+ }+ }++ public override void selected_canvas () {+ update_rows ();+ update_scrollbar ();+ }+ + void update_all_rows (SpacingClass s) {+ update_rows ();+ }+ + void update_rows () {+ int i = 0;+ + rows.clear ();+ rows.add (new Row (t_("New spacing class"), NEW_CLASS, false));+ + foreach (SpacingClass c in classes) {+ rows.add (new Row.columns_3 (@"$(c.first)", "=", @"$(c.next)", i));+ i++;+ }+ + GlyphCanvas.redraw ();+ }+ + public override void draw (WidgetAllocation allocation, Context cr) {+ double y = 20 * MainWindow.units;+ int s = 0;+ bool color = (scroll + 1 % 2) == 0;+ + if (allocation.width != this.allocation.width+ || allocation.height != this.allocation.height) {+ this.allocation = allocation;+ update_rows ();+ update_scrollbar ();+ }+ + visible_rows = (int) (allocation.height / 18.0);+ + cr.save ();+ cr.set_source_rgba (1, 1, 1, 1);+ cr.rectangle (0, 0, allocation.width, allocation.height);+ cr.fill ();+ cr.restore ();+ + cr.save ();+ cr.set_source_rgba (0.3, 0.3, 0.3, 1);+ cr.set_font_size (12);++ foreach (Row r in rows) {+ if (s++ >= scroll) {+ draw_row (allocation, cr, r, y, color, true);+ y += 18 * MainWindow.units;+ color = !color;+ }+ }+ + cr.restore ();+ } ++ private static void draw_row (WidgetAllocation allocation, Context cr,+ Row row, double y, bool color, bool dark) {+ + double margin;+ + if (color) {+ cr.save ();+ cr.set_source_rgba (224/255.0, 224/255.0, 224/255.0, 1);+ cr.rectangle (0, y - 14 * MainWindow.units, allocation.width, 18 * MainWindow.units);+ cr.fill ();+ cr.restore ();+ }++ if (row.has_delete_button ()) {+ cr.save ();+ cr.set_line_width (1);+ cr.move_to (10 * MainWindow.units, y - 8 * MainWindow.units);+ cr.line_to (15 * MainWindow.units, y - 3 * MainWindow.units);+ cr.move_to (10 * MainWindow.units, y - 3 * MainWindow.units);+ cr.line_to (15 * MainWindow.units, y - 8 * MainWindow.units); + cr.stroke ();+ cr.restore ();+ }+ + for (int i = 0; i < row.columns; i++) {+ cr.save ();+ margin = (row.has_delete_button ()) ? 120 * MainWindow.units : 3* MainWindow.units;+ cr.move_to (margin + i * 120 * MainWindow.units, y);+ cr.set_font_size (12 * MainWindow.units);+ cr.show_text (row.get_column (i));+ cr.restore ();+ }+ }++ public override void button_release (int button, double ex, double ey) {+ int s = 0;+ double y = 0;+ int colum = -1;+ Row? selected = null;+ bool over_delete = false;++ foreach (Row r in rows) {+ if (s++ >= scroll) {+ y += 18 * MainWindow.units;+ + if (y - 10 * MainWindow.units <= ey * MainWindow.units <= y + 5 * MainWindow.units) {+ + if (r.has_delete_button ()) {+ colum = (int) ((ex - 120) / 120 * MainWindow.units);+ } else {+ colum = (int) ((ex) / 120 * MainWindow.units);+ }+ + over_delete = (ex < 18 && r.has_delete_button ());+ selected = r;+ break;+ }+ }+ }+ + if (selected != null) {+ selected_row ((!) selected, colum, over_delete); + }+ + update_scrollbar ();+ redraw_area (0, 0, allocation.width, allocation.height);+ }++ public override string get_label () {+ return t_("Spacing Classes");+ }++ public override string get_name () {+ return "SpacingClasses";+ }++ public override bool has_scrollbar () {+ return true;+ }+ + public override void scroll_wheel_down (double x, double y) {+ int nrows = rows.size;+ scroll += 3;++ if (scroll > nrows - visible_rows) {+ scroll = (int) (nrows - visible_rows);+ }+ + if (visible_rows > nrows) {+ scroll = 0;+ } + + update_scrollbar ();+ redraw_area (0, 0, allocation.width, allocation.height);+ }+ + public override void scroll_wheel_up (double x, double y) {+ scroll -= 3;+ + if (scroll < 0) {+ scroll = 0;+ }+ + update_scrollbar ();+ redraw_area (0, 0, allocation.width, allocation.height);+ }+ + public void update_scrollbar () {+ uint rows = rows.size;++ if (rows == 0 || visible_rows == 0) {+ MainWindow.set_scrollbar_size (0);+ MainWindow.set_scrollbar_position (0);+ } else {+ MainWindow.set_scrollbar_size ((double) visible_rows / rows);+ MainWindow.set_scrollbar_position ((double) scroll / rows);+ }+ }++ public override void scroll_to (double percent) {+ uint rows = rows.size;+ scroll = (int) (percent * rows);+ + if (scroll > rows - visible_rows) {+ scroll = (int) (rows - visible_rows);+ }+ + redraw_area (0, 0, allocation.width, allocation.height);+ }+}++}@@ -20,7 +20,7 @@ namespace BirdFont { public abstract class ToolCollection : GLib.Object { public double scroll = 0; public double content_height = 0;- public abstract unowned List<Expander> get_expanders ();+ public abstract Gee.ArrayList<Expander> get_expanders (); } }