Commit c7ab988
A new spacing tab
Changed files (10)
modifiedlibbirdfont/ForesightTool.valamodifiedlibbirdfont/Glyph.valamodifiedlibbirdfont/KerningDisplay.valamodifiedlibbirdfont/KerningTools.valamodifiedlibbirdfont/Line.valamodifiedlibbirdfont/MainWindow.valamodifiedlibbirdfont/Menu.valamodifiedlibbirdfont/MenuTab.valamodifiedlibbirdfont/OverView.valaaddedlibbirdfont/SpacingTab.vala
Diff
@@ -57,8 +57,8 @@ public class ForesightTool : Tool { state = MOVE_POINT; add_new_point (x, y); - p.last_point_x = Glyph.path_coordinate_x (x);- p.last_point_y = Glyph.path_coordinate_y (y);+ PenTool.last_point_x = Glyph.path_coordinate_x (x);+ PenTool.last_point_y = Glyph.path_coordinate_y (y); move_action (this, x, y); @@ -83,10 +83,10 @@ public class ForesightTool : Tool { first_point = PenTool.active_path.points.get (0); clockwise = PenTool.active_path.is_clockwise (); - p.move_selected = false;+ PenTool.move_selected = false; p.release_action (p, 2, x, y); - p.move_selected = false;+ PenTool.move_selected = false; p.press_action (p, 2, x, y); if (ps.path.has_point (first_point)) {@@ -95,8 +95,10 @@ public class Glyph : FontDisplay { /** Cache quadratic form on export. */ GlyfData? ttf_data = null; - /** Cache for Cairo rendering */+ Line left_line;+ Line right_line; + /** Cache for Cairo rendering */ HashMap<int64?, Surface> glyph_cache = new HashMap<int64?, Surface> ((v) => { int? t = (int?) v; int i = (!) t;@@ -441,8 +443,8 @@ public class Glyph : FontDisplay { bottom_margin_line.position_updated.connect ((pos) => { BirdFont.get_current_font ().bottom_limit = pos; });- - Line left_line = new Line ("left", left_limit, true);+ + left_line = new Line ("left", left_limit, true); left_line.position_updated.connect ((pos) => { double x1, y1, x2, y2; @@ -454,7 +456,7 @@ public class Glyph : FontDisplay { }); left_line.position_updated (left_limit); - Line right_line = new Line ("right", right_limit, true);+ right_line = new Line ("right", right_limit, true); right_line.position_updated.connect ((pos) => { double x1, y1, x2, y2; @@ -493,6 +495,18 @@ public class Glyph : FontDisplay { add_line (bottom_margin_line); bottom_margin_line.set_visible (margin_boundaries_visible); }++ public double get_left_side_bearing () {+ double x1, y1, x2, y2;+ boundaries (out x1, out y1, out x2, out y2);+ return x1 - left_limit;+ }++ public double get_right_side_bearing () {+ double x1, y1, x2, y2;+ boundaries (out x1, out y1, out x2, out y2);+ return right_limit - x2; + } bool has_top_line () { return !unichar_code.islower () || CharDatabase.has_ascender (unichar_code);@@ -26,6 +26,7 @@ public class KerningDisplay : FontDisplay { int selected_handle = -1; bool moving = false; Glyph left_active_glyph = new Glyph ("null", '\0');+ Glyph right_active_glyph = new Glyph ("null", '\0'); double begin_handle_x = 0; double begin_handle_y = 0;@@ -41,6 +42,9 @@ public class KerningDisplay : FontDisplay { Font current_font = new Font (); Text kerning_label = new Text (); + public bool adjust_side_bearings = false;+ bool right_side_bearing = true;+ public KerningDisplay () { GlyphSequence w = new GlyphSequence (); row = new Gee.ArrayList <GlyphSequence> ();@@ -49,6 +53,10 @@ public class KerningDisplay : FontDisplay { row.add (w); } + public GlyphSequence get_first_row () {+ return row.size > 0 ? row.get (0) : new GlyphSequence ();+ }+ public override string get_label () { return t_("Kerning"); }@@ -86,6 +94,7 @@ public class KerningDisplay : FontDisplay { double row_height; Font font; double item_size = 1.0 / KerningTools.font_size;+ double item_size2 = 2.0 / KerningTools.font_size; font = current_font; i = 0;@@ -162,24 +171,34 @@ public class KerningDisplay : FontDisplay { cr.set_source_rgba (123/255.0, 123/255.0, 123/255.0, 1); } - cr.move_to (x2 - 5 * item_size, y + 20 * item_size);- cr.line_to (x2 + 0, y + 20 * item_size - 5 * item_size);- cr.line_to (x2 + 5 * item_size, y + 20* item_size);- cr.fill ();- - if (gr_left != null || gr_right != null) {- cr.move_to (x2 - 5 * item_size, y + 20 * item_size);- cr.line_to (x2 + 5 * item_size, y + 20 * item_size);- cr.line_to (x2 + 5 * item_size, y + 24 * item_size);- cr.line_to (x2 - 5 * item_size, y + 24 * item_size);+ if (!adjust_side_bearings) {+ cr.move_to (x2 - 5 * item_size, y + 20 * item_size);+ cr.line_to (x2, y + 20 * item_size - 5 * item_size);+ cr.line_to (x2 + 5 * item_size, y + 20* item_size); cr.fill ();+ + if (gr_left != null || gr_right != null) {+ cr.move_to (x2 - 5 * item_size, y + 20 * item_size);+ cr.line_to (x2 + 5 * item_size, y + 20 * item_size);+ cr.line_to (x2 + 5 * item_size, y + 24 * item_size);+ cr.line_to (x2 - 5 * item_size, y + 24 * item_size);+ cr.fill ();+ }+ } else {+ if (right_side_bearing) {+ cr.move_to (x2 - 5 * item_size2, y + 20 * item_size2);+ cr.line_to (x2, y + 20 * item_size2 - 5 * item_size2);+ cr.line_to (x2, y + 20* item_size2);+ cr.fill ();+ } else {+ cr.move_to (x2, y + 20 * item_size2);+ cr.line_to (x2, y + 20 * item_size2 - 5 * item_size2);+ cr.line_to (x2 + 5 * item_size2, y + 20* item_size2);+ cr.fill ();+ } } - cr.set_font_size (10);- cr.show_text (((!)g).get_name ());- cr.restore ();- - if (active_handle == i) {+ if (active_handle == i && !adjust_side_bearings) { cr.save (); cr.scale (1 / KerningTools.font_size, 1 / KerningTools.font_size); kerning_label.widget_x = x2 * KerningTools.font_size;@@ -341,7 +360,7 @@ public class KerningDisplay : FontDisplay { return; } - if (!KerningTools.adjust_side_bearings) {+ if (!adjust_side_bearings) { kern = get_kerning_for_handle (handle); set_space (handle, val - kern); }@@ -357,14 +376,21 @@ public class KerningDisplay : FontDisplay { font = current_font; font.touch (); - if (!KerningTools.adjust_side_bearings) {+ if (!adjust_side_bearings) { get_kerning_pair (handle, out a, out b, out gr_left, out gr_right); set_kerning_pair (a, b, ref gr_left, ref gr_right, val); } else {- left_active_glyph.right_limit += val;- left_active_glyph.remove_lines ();- left_active_glyph.add_help_lines ();- left_active_glyph.update_other_spacing_classes ();+ if (right_side_bearing) {+ left_active_glyph.right_limit += val;+ left_active_glyph.remove_lines ();+ left_active_glyph.add_help_lines ();+ left_active_glyph.update_other_spacing_classes ();+ } else {+ right_active_glyph.left_limit -= val;+ right_active_glyph.remove_lines ();+ right_active_glyph.add_help_lines ();+ right_active_glyph.update_other_spacing_classes ();+ } } } @@ -496,6 +522,13 @@ public class KerningDisplay : FontDisplay { left_active_glyph = (!) g; } }++ if (0 <= selected_handle < sequence_with_ligatures.glyph.size) {+ g = sequence_with_ligatures.glyph.get (selected_handle);+ if (g != null) {+ right_active_glyph = (!) g;+ }+ } GlyphCanvas.redraw (); }@@ -731,6 +764,10 @@ public class KerningDisplay : FontDisplay { if (d < min) { min = d; + if (ex != fs * (x + kern)) { // don't swap direction after button release+ right_side_bearing = ex < fs * (x + kern); // right or left side bearing handle+ }+ if (active_handle != i - row_index) { set_active_handle_index (i - row_index); GlyphCanvas.redraw ();@@ -21,7 +21,6 @@ public class KerningTools : ToolCollection { public static Gee.ArrayList<Expander> expanders; public static int next_class = 0; public static Expander classes;- public static bool adjust_side_bearings = false; public static double font_size = 1; public static ZoomBar zoom_bar;@@ -67,14 +66,6 @@ public class KerningTools : ToolCollection { }); kerning_tools.add_tool (text_kerning); - Tool side_bearings = new Tool ("side_bearings", t_("Adjust right side bearing."));- side_bearings.select_action.connect ((self) => {- KerningTools.adjust_side_bearings = !KerningTools.adjust_side_bearings;- side_bearings.set_selected (KerningTools.adjust_side_bearings);- });- side_bearings.set_persistent (true);- kerning_tools.add_tool (side_bearings);- Tool insert_last = new Tool ("insert_last_glyph", t_("Insert glyph from overview")); insert_last.select_action.connect ((self) => { KerningDisplay d = MainWindow.get_kerning_display ();@@ -327,11 +327,13 @@ public class Line : GLib.Object { cr.close_path(); cr.fill (); - glyph_metrics = new Text (metrics, 17);- glyph_metrics.set_source_rgba (72 / 255.0, 72 / 255.0, 72 / 255.0, 1);- glyph_metrics.widget_x = p + 10;- glyph_metrics.widget_y = h - 25;- glyph_metrics.draw (cr);+ if (get_active ()) { + glyph_metrics = new Text (metrics, 17);+ glyph_metrics.set_source_rgba (72 / 255.0, 72 / 255.0, 72 / 255.0, 1);+ glyph_metrics.widget_x = p + 10;+ glyph_metrics.widget_y = h - 25;+ glyph_metrics.draw (cr);+ } } } else {@@ -353,7 +355,7 @@ public class Line : GLib.Object { } // Label- if (get_active ()) { + if (get_active ()) { if (is_vertical ()) { h = g.allocation.height; cr.move_to (p + 8 , h - 30);@@ -31,6 +31,7 @@ public class MainWindow : GLib.Object { public static SpacingClassTab spacing_class_tab; public static Menu menu; public static Dialog dialog; + public static SpacingTab spacing_tab; /** Number of pixels per mm */ public static double units = 1; @@ -50,8 +51,12 @@ public class MainWindow : GLib.Object { ligature_display = new LigatureList (); spacing_class_tab = new SpacingClassTab (); menu = new Menu (); - dialog = new Dialog (); + spacing_tab = new SpacingTab (); + } + + public static SpacingTab get_spacing_tab () { + return spacing_tab; } public static Dialog get_dialog () { @@ -318,12 +318,19 @@ public class Menu : GLib.Object { tab_menu.items.add (close_all_tabs); // tab menu- MenuItem kerning = add_menu_item (t_("Kerning"));+ MenuItem kerning = add_menu_item (t_("Spacing and Kerning")); kerning.action.connect (() => { set_menu (kerning_menu); }); menu.items.add (kerning); + MenuItem spacing_tab = add_menu_item (t_("Show Spacing Tab"), "show spacing tab");+ spacing_tab.action.connect (() => {+ MenuTab.show_spacing_tab ();+ show_menu = false;+ });+ kerning_menu.items.add (spacing_tab);+ MenuItem kerning_tab = add_menu_item (t_("Show Kerning Tab"), "show kerning tab"); kerning_tab.action.connect (() => { MenuTab.show_kerning_context ();@@ -338,9 +345,9 @@ public class Menu : GLib.Object { }); kerning_menu.items.add (list_kernings); - MenuItem show_spacing = add_menu_item (t_("Show Spacing Tab"), "show spacing tab");+ MenuItem show_spacing = add_menu_item (t_("Spacing Classes"), "show spacing tab"); show_spacing.action.connect (() => {- MenuTab.show_spacing_tab ();+ MenuTab.show_spacing_class_tab (); show_menu = false; }); kerning_menu.items.add (show_spacing);@@ -312,6 +312,16 @@ public class MenuTab : FontDisplay { MainWindow.get_tab_bar ().add_unique_tab (kd); } + public static void show_spacing_tab () {+ if (suppress_event) {+ warn_if_test ("Event suppressed");+ return;+ }+ + SpacingTab s = MainWindow.get_spacing_tab ();+ MainWindow.get_tab_bar ().add_unique_tab (s);+ }+ public static void show_ligature_tab () { if (suppress_event) { warn_if_test ("Event suppressed");@@ -501,7 +511,7 @@ public class MenuTab : FontDisplay { g.update_view (); } - public static void show_spacing_tab () {+ public static void show_spacing_class_tab () { SpacingClassTab t = MainWindow.get_spacing_class_tab (); MainWindow.get_tab_bar ().add_unique_tab (t); }@@ -1196,10 +1196,8 @@ public class OverView : FontDisplay { - (int) ((GlyphCollection) b).get_unicode_character (); }); - print ("A\n"); index = (uint32) first_visible + selected; for (i = 0; i < copied_glyphs.size; i++) {- print ("b\n"); if (all_available) { if (f.length () == 0) { c = add_empty_character_to_font (glyps.get (i).get_unicode_character (),@@ -1222,23 +1220,18 @@ public class OverView : FontDisplay { return_if_fail (c != null); gc = (!) c; - } else {- print ("c\n"); + } else { if (i != 0) { s = (int) copied_glyphs.get (i).get_unicode_character (); s -= (int) copied_glyphs.get (i - 1).get_unicode_character (); s -= 1; skip += s; }- - print ("d\n");+ character_string = glyph_range.get_char ((uint32) (index + skip));- print ("e\n"); c = f.get_glyph_collection_by_name (character_string);- - print ("f\n");+ if (c == null) {- print ("g\n"); gc = add_empty_character_to_font (character_string.get_char (), copied_glyphs.get (i).is_unassigned (), copied_glyphs.get (i).get_name ());new file mode 100644@@ -0,0 +1,161 @@+/*+ 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;++namespace BirdFont {++/** Kerning context. */+public class SpacingTab : KerningDisplay {++ double height = 44 * MainWindow.units;+ double character_height = 20 * MainWindow.units;+ + public SpacingTab () {+ adjust_side_bearings = true;+ }++ public override string get_label () {+ return t_("Spacing");+ }+ + public override string get_name () {+ return "Spacing";+ }++ public override void draw (WidgetAllocation allocation, Context cr) {+ base.draw (allocation, cr);+ draw_spacing_metrix (allocation, cr);+ }+ + void draw_spacing_metrix (WidgetAllocation allocation, Context cr) {++ GlyphSequence row;+ int index;++ // background+ cr.save ();+ cr.set_source_rgba (1, 1, 1, 1);+ cr.rectangle (0, allocation.height - height, allocation.width, height);+ cr.fill ();+ cr.restore ();+ + // character bar+ cr.save ();+ cr.set_source_rgba (0.5, 0.5, 0.5, 1);+ cr.set_line_width (0.8);+ cr.move_to (0, allocation.height - height);+ cr.line_to (allocation.width, allocation.height - height);+ cr.stroke ();+ + cr.move_to (0, allocation.height - height + character_height);+ cr.line_to (allocation.width, allocation.height - height + character_height);+ cr.stroke ();+ cr.restore ();+ + // TODO: add button for processing ligatures+ row = get_first_row ().process_ligatures ();+ index = 0;+ foreach (Glyph? g in row.glyph) {+ draw_glyph_spacing (allocation, cr, g, index);+ index++;+ }+ }+ + void draw_glyph_spacing (WidgetAllocation allocation, Context cr, Glyph? glyph, int index) {+ Glyph g;+ double end, middle;+ double l, r;+ Text left, right, cap;+ double box_size;+ unichar c;+ + box_size = 122 * MainWindow.units;+ + // end mark+ end = (index + 1) * box_size;+ cr.save ();+ cr.set_source_rgba (0.5, 0.5, 0.5, 1);+ cr.set_line_width (2);+ cr.move_to (end, allocation.height - height);+ cr.line_to (end, allocation.height);+ cr.stroke ();+ cr.restore ();+ + // boxes+ middle = end - box_size / 2.0;+ cr.save ();+ cr.set_source_rgba (0.5, 0.5, 0.5, 1);+ cr.set_line_width (0.8);+ cr.move_to (middle, allocation.height - height + character_height);+ cr.line_to (middle, allocation.height);+ cr.stroke ();+ cr.restore ();+ + if (glyph != null) {+ g = (!) glyph;+ + c = g.get_unichar ();+ cap = new Text ((!) c.to_string (), 17);+ cap.set_source_rgba (72 / 255.0, 72 / 255.0, 72 / 255.0, 1);+ cap.widget_x = middle - cap.get_extent () / 2.0;+ cap.widget_y = allocation.height - height + character_height - 4 * MainWindow.units;+ cap.draw_at_baseline (cr, cap.widget_x, cap.widget_y); + + l = g.get_left_side_bearing ();+ left = new Text (truncate (l, 5), 17);+ left.set_source_rgba (72 / 255.0, 72 / 255.0, 72 / 255.0, 1);+ left.widget_x = middle - box_size / 2.0 + (box_size / 2.0 - left.get_extent ()) / 2.0;+ left.widget_y = allocation.height - 7 * MainWindow.units;+ left.draw_at_baseline (cr, left.widget_x, left.widget_y);++ r = g.get_right_side_bearing ();+ right = new Text (truncate (r, 5), 17);+ right.set_source_rgba (72 / 255.0, 72 / 255.0, 72 / 255.0, 1);+ right.widget_x = end - (box_size / 2.0 - right.get_extent ()) / 2.0 - right.get_extent ();+ right.widget_y = allocation.height - 7 * MainWindow.units;+ right.draw_at_baseline (cr, right.widget_x, right.widget_y); + }+ }++ public string truncate (double f, int digits) {+ string t = @"$f";+ string s = "";+ + int d = digits;+ int i;+ unichar c;+ + if (t.index_of ("-") != -1) {+ d++;+ }++ if (t.index_of (".") != -1) {+ d++;+ }+ + i = 0;+ while (t.get_next_char (ref i, out c)) {+ s = s + (!) c.to_string ();+ + if (i >= d) {+ break;+ }+ }+ + return s;+ }+}++}