Commit b60e947
Two spin buttons for moving objects The tool moves the glyph in a cartesian coordinate system with 100 units per em. The position is relative to the lower left corner of the object.
Changed files (14)
modifiedbirdfont/GtkWindow.valaaddedicons/x_coordinate.pngaddedicons/y_coordinate.pngmodifiedlibbirdfont/BirdFont.valamodifiedlibbirdfont/DrawingTools.valamodifiedlibbirdfont/Glyph.valamodifiedlibbirdfont/KerningClasses.valamodifiedlibbirdfont/MainWindow.valamodifiedlibbirdfont/MenuTab.valamodifiedlibbirdfont/MoveTool.valamodifiedlibbirdfont/Path.valamodifiedlibbirdfont/ResizeTool.valamodifiedlibbirdfont/SpinButton.valamodifiedlibbirdfont/Tool.vala
Diff
@@ -733,7 +733,7 @@ public class GtkWindow : Gtk.Window, NativeWindow { menubar.append (git_launcher); menubar.append (ligature_launcher); }- + return menubar; } @@ -1053,6 +1053,14 @@ class ToolboxCanvas : DrawingArea { public ToolboxCanvas (Toolbox toolbox) { tb = toolbox; + realize.connect (() => {+ Gtk.Allocation allocation;+ get_allocation (out allocation);+ Toolbox.allocation_width = allocation.width;+ Toolbox.allocation_height = allocation.height;+ Toolbox.redraw_tool_box ();+ });+ tb.redraw.connect ((x, y, w, h) => { queue_draw_area (x, y, w, h); });@@ -1116,7 +1124,7 @@ public class GlyphCanvasArea : DrawingArea { int event_flags; glyph_canvas = gc;- + event_flags = EventMask.BUTTON_PRESS_MASK; event_flags |= EventMask.BUTTON_RELEASE_MASK; event_flags |= EventMask.POINTER_MOTION_MASK;new file mode 100644Binary files /dev/null and b/icons/x_coordinate.png differnew file mode 100644Binary files /dev/null and b/icons/y_coordinate.png differ@@ -468,8 +468,6 @@ public class BirdFont { DefaultCharacterSet.get_characters_for_prefered_language (); HeadTable.init ();- - printd ("Done"); } public static void set_bundle_path (string path) {@@ -32,7 +32,7 @@ public class DrawingTools : ToolCollection { public static SpinButton object_stroke; - public static Tool move_tool;+ public static MoveTool move_tool; public static PenTool pen_tool; PointTool point_tool;@@ -137,7 +137,7 @@ public class DrawingTools : ToolCollection { pen_tool.select_all_points (); g.open_path (); } else {- g.select_all_paths ();+ DrawingTools.move_tool.select_all_paths (); } }); key_tools.add_tool (select_all_button); @@ -195,6 +195,83 @@ public class DrawingTools : ToolCollection { convert_points.set_persistent (false); draw_tool_modifiers.add_tool (convert_points); + // x coordinate+ SpinButton x_coordinate = new SpinButton ("x_coordinate", t_("X coordinate"));+ x_coordinate.set_big_number (true);+ x_coordinate.set_int_value ("0.000");+ x_coordinate.set_int_step (0.001);+ x_coordinate.set_wait_for_submit (true);+ x_coordinate.set_min (-999.99);+ x_coordinate.set_max (999.99);+ x_coordinate.show_icon (true);+ x_coordinate.new_value_action.connect((self) => {+ Glyph glyph = MainWindow.get_current_glyph ();+ double x, y, w, h;+ double delta;+ + glyph.selection_boundaries (out x, out y, out w, out h);+ delta = x_coordinate.get_value () - x + glyph.left_limit;+ + foreach (Path path in glyph.active_paths) {+ path.move (delta, 0);+ }+ + GlyphCanvas.redraw ();+ });+ draw_tool_modifiers.add_tool (x_coordinate);++ move_tool.objects_moved.connect (() => {+ Glyph glyph = MainWindow.get_current_glyph ();+ x_coordinate.set_value_round (MoveTool.selection_box_center_x+ - (MoveTool.selection_box_width / 2)+ - glyph.left_limit, true, false);+ });+ + move_tool.selection_changed.connect (() => {+ Glyph glyph = MainWindow.get_current_glyph ();+ x_coordinate.set_value_round (MoveTool.selection_box_center_x+ - (MoveTool.selection_box_width / 2)+ - glyph.left_limit, true, false);+ });++ // y coordinate+ SpinButton y_coordinate = new SpinButton ("y_coordinate", t_("Y coordinate"));+ y_coordinate.set_big_number (true);+ y_coordinate.set_int_value ("0.000");+ y_coordinate.set_int_step (0.001);+ y_coordinate.set_wait_for_submit (true);+ y_coordinate.set_min (-999.99);+ y_coordinate.set_max (999.99);+ y_coordinate.show_icon (true);+ y_coordinate.new_value_action.connect((self) => {+ double x, y, w, h;+ Glyph glyph = MainWindow.get_current_glyph ();+ Font font = BirdFont.get_current_font ();+ + glyph.selection_boundaries (out x, out y, out w, out h);+ + foreach (Path path in glyph.active_paths) {+ path.move (0, y_coordinate.get_value () - (y - h) - font.base_line);+ }+ + GlyphCanvas.redraw ();+ });+ draw_tool_modifiers.add_tool (y_coordinate);++ move_tool.objects_moved.connect (() => {+ Font font = BirdFont.get_current_font ();+ y_coordinate.set_value_round (MoveTool.selection_box_center_y+ - (MoveTool.selection_box_height / 2)+ + font.base_line, true, false);+ });+ + move_tool.selection_changed.connect (() => {+ Font font = BirdFont.get_current_font ();+ y_coordinate.set_value_round (MoveTool.selection_box_center_y+ - (MoveTool.selection_box_height / 2)+ + font.base_line, true, false);+ });+ // edit stroke width object_stroke = new SpinButton ("object_stroke", t_("Stroke width")); object_stroke.set_int_value ("2.000");@@ -185,18 +185,6 @@ public class Glyph : FontDisplay { return ligature; } - public void select_all_paths () {- clear_active_paths ();- - foreach (Path p in path_list) {- if (p.points.size > 0) {- add_active_path (p);- }- }- - update_view ();- }- public void clear_active_paths () { active_paths.clear (); }@@ -198,14 +198,11 @@ public class KerningClasses : GLib.Object { GlyphRange l; int len = (int) classes_first.size; double? d;- double time; d = get_kerning_for_single_glyphs (left_glyph, right_glyph); if (d != null) { return (!)d; }-- time = GLib.get_real_time (); len = (int)classes_first.size; return_val_if_fail (len == classes_last.size, 0);@@ -78,7 +78,7 @@ public class MainWindow : GLib.Object { Toolbox.select_tool_by_name ("move"); } - get_current_glyph ().select_all_paths (); + DrawingTools.move_tool.select_all_paths (); } public static DrawingTools get_drawing_tools () { @@ -387,7 +387,7 @@ public class MenuTab : FontDisplay { return; } - MoveTool.move_to_baseline ();+ DrawingTools.move_tool.move_to_baseline (); } } @@ -17,7 +17,7 @@ using Cairo; namespace BirdFont { -private class MoveTool : Tool {+public class MoveTool : Tool { static bool move_path = false; static bool moved = false;@@ -28,10 +28,13 @@ private class MoveTool : Tool { static double selection_y = 0; static bool group_selection= false; - 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;+ public static static double selection_box_width = 0;+ public static static double selection_box_height = 0;+ public static static double selection_box_center_x = 0;+ public static static double selection_box_center_y = 0;+ + public signal void selection_changed ();+ public signal void objects_moved (); public MoveTool (string n) { base (n, t_("Move paths"), 'm', CTRL);@@ -71,7 +74,7 @@ private class MoveTool : Tool { } } - public static void key_press (uint32 keyval) {+ public void key_press (uint32 keyval) { Glyph g = MainWindow.get_current_glyph (); // delete selected paths@@ -89,7 +92,7 @@ private class MoveTool : Tool { } } - public static void move (int x, int y) {+ public void move (int x, int y) { Glyph glyph = MainWindow.get_current_glyph (); double dx = last_x - x; double dy = last_y - y; @@ -107,10 +110,16 @@ private class MoveTool : Tool { GlyphCanvas.redraw (); + update_selection_boundaries ();+ + if (moved) {+ objects_moved ();+ }+ BirdFont.get_current_font ().touch (); } - public static void release (int b, int x, int y) {+ public void release (int b, int x, int y) { Glyph glyph = MainWindow.get_current_glyph (); move_path = false;@@ -130,7 +139,11 @@ private class MoveTool : Tool { } group_selection = false;- moved = false; + moved = false;+ + if (glyph.active_paths.size > 0) {+ objects_moved ();+ } } public static void press (int b, int x, int y) {@@ -161,7 +174,8 @@ private class MoveTool : Tool { update_boundaries_for_selection (); } - static void select_group () {+ + 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));@@ -177,6 +191,8 @@ private class MoveTool : Tool { } } }+ + selection_changed (); } public static void update_selection_boundaries () {@@ -185,7 +201,7 @@ private class MoveTool : Tool { out selection_box_height); } - public static void move_to_baseline () {+ public void move_to_baseline () { Glyph glyph = MainWindow.get_current_glyph (); Font font = BirdFont.get_current_font (); double x, y, w, h;@@ -196,6 +212,8 @@ private class MoveTool : Tool { path.move (glyph.left_limit - x + w / 2, font.base_line - y + h / 2); } + update_selection_boundaries ();+ objects_moved (); GlyphCanvas.redraw (); } @@ -249,7 +267,7 @@ private class MoveTool : Tool { y = py + (h / 2); } - static void move_selected_paths (uint key) {+ void move_selected_paths (uint key) { Glyph glyph = MainWindow.get_current_glyph (); double x, y; @@ -277,6 +295,8 @@ private class MoveTool : Tool { path.move (x * Glyph.ivz (), y * Glyph.ivz ()); } + update_selection_boundaries ();+ objects_moved (); glyph.redraw_area (0, 0, glyph.allocation.width, glyph.allocation.height); } @@ -362,6 +382,23 @@ private class MoveTool : Tool { BirdFont.get_current_font ().touch (); }+ + public void select_all_paths () {+ Glyph g = MainWindow.get_current_glyph ();+ + g.clear_active_paths ();+ + foreach (Path p in g.path_list) {+ if (p.points.size > 0) {+ g.add_active_path (p);+ }+ }+ + g.update_view ();+ + update_selection_boundaries ();+ objects_moved ();+ } } }@@ -902,7 +902,7 @@ public class Path { update_region_boundaries (); }-+ private void update_region_boundaries_for_point (EditPoint p) { EditPointHandle left_handle; EditPointHandle right_handle;@@ -86,7 +86,7 @@ class ResizeTool : Tool { release_action.connect((self, b, x, y) => { resize_path = false; rotate_path = false;- MoveTool.release (b, x, y);+ DrawingTools.move_tool.release (b, x, y); }); move_action.connect ((self, x, y) => {@@ -106,7 +106,7 @@ class ResizeTool : Tool { } GlyphCanvas.redraw ();- MoveTool.move (x, y);+ DrawingTools.move_tool.move (x, y); }); draw_action.connect ((self, cr, glyph) => {@@ -126,7 +126,7 @@ class ResizeTool : Tool { }); key_press_action.connect ((self, keyval) => {- MoveTool.key_press (keyval);+ DrawingTools.move_tool.key_press (keyval); }); }@@ -1,5 +1,5 @@ /*- Copyright (C) 2012 2014 Johan Mattsson+ Copyright (C) 2012, 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 @@ -20,18 +20,31 @@ public class SpinButton : Tool { public signal void new_value_action (SpinButton selected); - public int8 deka = 2;- public int8 deci = 0;- public int8 centi = 0;- public int8 milli = 0;+ bool negative = false;+ + public int8 n0 = 2;+ public int8 n1 = 0;+ public int8 n2 = 0;+ public int8 n3 = 0;+ public int8 n4 = 0; bool value_from_motion = false; double begin_y = 0; int begin_value = 0; - int max = 9999;+ int max = 99999; int min = 0; int step = 1;++ /** Wait until button is pressed when the user sets value from text. */+ bool wait_for_submit = false;+ string text_input = "";+ + bool big_number = false;+ + double last_active_time = 0;+ bool waiting_for_icon_switch = false;+ bool show_icon_tool_icon = false; public SpinButton (string? name = null, string tip = "", unichar key = '\0', uint modifier_flag = 0) { base (null , tip, key, modifier_flag);@@ -39,9 +52,9 @@ public class SpinButton : Tool { if (name != null) { base.name = (!) name; }- + set_icon ("spin_button");- + panel_press_action.connect ((selected, button, tx, ty) => { double py = Math.fabs (y - ty); int n = 0;@@ -80,6 +93,10 @@ public class SpinButton : Tool { double d; int new_value; + if (is_active ()) {+ show_adjustmet_icon ();+ }+ if (value_from_motion) { d = (begin_y - ty) / 200; d = (d < 0) ? -Math.pow (d, 2) : Math.pow (d, 2);@@ -121,7 +138,47 @@ public class SpinButton : Tool { return true; }); }+ + public void show_icon (bool i) {+ show_icon_tool_icon = i;+ + if (!show_icon_tool_icon) {+ set_icon ("spin_button");+ } else {+ set_icon ((!) base.name);+ }+ }+ + void show_adjustmet_icon () {+ TimeoutSource timer;+ + set_icon ("spin_button");+ redraw ();+ + last_active_time = GLib.get_real_time ();+ + if (show_icon_tool_icon && !waiting_for_icon_switch) {+ waiting_for_icon_switch = true;+ + timer = new TimeoutSource (100);+ timer.set_callback (() => {+ if (GLib.get_real_time () - last_active_time > 4000000) {+ set_icon (base.name);+ redraw ();+ waiting_for_icon_switch = false;+ }+ + return waiting_for_icon_switch;+ }); + timer.attach (null);+ }+ }+ + public void set_big_number (bool b) {+ big_number = b;+ }+ public static string convert_to_string (double val) { SpinButton sb = new SpinButton (); sb.set_value_round (val);@@ -133,22 +190,29 @@ public class SpinButton : Tool { sb.set_int_value (val); return sb.get_value (); }- + + public void set_wait_for_submit (bool w) {+ wait_for_submit = w;+ }+ public void set_from_text () { TextListener listener = new TextListener (t_("Set"), get_display_value (), t_("Close")); - listener.signal_text_input.connect ((text) => {- int new_value = (int) Math.rint (double.parse (text) * 1000);- if (new_value < min) {- set_int_value (@"$min");- } else if (new_value > max) {- set_int_value (@"$max");- } else {- set_int_value (@"$new_value");- }+ if (!wait_for_submit) {+ listener.signal_text_input.connect ((text) => {+ set_value (text);+ redraw ();+ });+ } else {+ listener.signal_text_input.connect ((text) => {+ text_input = text;+ }); - redraw ();- });+ listener.signal_submit.connect ((text) => {+ set_value (text_input);+ redraw ();+ });+ } listener.signal_submit.connect (() => { MainWindow.native_window.hide_text_input ();@@ -158,16 +222,36 @@ public class SpinButton : Tool { MainWindow.native_window.set_text_listener (listener); } + void set_value_check_boundaries (string text) {+ int new_value = (int) Math.rint (double.parse (text) * 1000);+ if (new_value < min) {+ set_int_value (@"$min");+ } else if (new_value > max) {+ set_int_value (@"$max");+ } else {+ set_int_value (@"$new_value");+ } + }+ public void set_max (double max) {- this.max = (int) Math.rint (max * 1000);+ if (big_number) {+ max /= 100;+ }+ this.max = (int) Math.rint (max * 10000); } public void set_min (double min) {- this.min = (int) Math.rint (min * 1000);+ if (big_number) {+ min /= 100;+ }+ this.min = (int) Math.rint (min * 10000); } public void set_int_step (double step) {- this.step = (int) Math.rint (step * 1000);+ if (big_number) {+ step /= 100;+ } + this.step = (int) Math.rint (step * 10000); } public void increase () { @@ -205,15 +289,22 @@ public class SpinButton : Tool { public void set_int_value (string new_value) { string v = new_value; - while (!(v.char_count () >= 4)) {+ negative = v.has_prefix ("-");+ if (negative) {+ v = v.replace ("-", "");+ }+ + while (!(v.char_count () >= 5)) { v = "0" + v; } - deka = parse (v.substring (v.index_of_nth_char (0), 1));- deci = parse (v.substring (v.index_of_nth_char (1), 1));- centi = parse (v.substring (v.index_of_nth_char (2), 1));- milli = parse (v.substring (v.index_of_nth_char (3), 1));+ n0 = parse (v.substring (v.index_of_nth_char (0), 1));+ n1 = parse (v.substring (v.index_of_nth_char (1), 1));+ n2 = parse (v.substring (v.index_of_nth_char (2), 1));+ n3 = parse (v.substring (v.index_of_nth_char (3), 1));+ n4 = parse (v.substring (v.index_of_nth_char (4), 1)); + show_adjustmet_icon (); new_value_action (this); redraw (); }@@ -229,8 +320,25 @@ public class SpinButton : Tool { public void set_value (string new_value, bool check_boundaries = true, bool emit_signal = true) { string v = new_value.replace (",", ".");+ int fv;+ string separator = "";+ + negative = v.has_prefix ("-");+ if (negative) {+ v = v.replace ("-", "");+ }+ + if (big_number) {+ fv = int.parse (v);+ fv = (fv < 0) ? -fv : fv;+ if (fv < 10) {+ v = @"00$v";+ } else if (fv < 100) {+ v = @"0$v";+ }+ } - while (v.char_count () < 5) {+ while (v.char_count () < 6) { if (v.index_of (".") == -1) { v += "."; } else {@@ -238,21 +346,32 @@ public class SpinButton : Tool { } } - if (v.substring (v.index_of_nth_char (1), 1) != ".") {- warning (@"Expecting \".\" in $v");+ if (!big_number) {+ n0 = (int8) int.parse (v.substring (v.index_of_nth_char (0), 1));+ separator = v.substring (v.index_of_nth_char (1), 1);+ n1 = (int8) int.parse (v.substring (v.index_of_nth_char (2), 1));+ n2 = (int8) int.parse (v.substring (v.index_of_nth_char (3), 1));+ n3 = (int8) int.parse (v.substring (v.index_of_nth_char (4), 1));+ n4 = (int8) int.parse (v.substring (v.index_of_nth_char (5), 1));+ } else {+ n0 = (int8) int.parse (v.substring (v.index_of_nth_char (0), 1));+ n1 = (int8) int.parse (v.substring (v.index_of_nth_char (1), 1));+ n2 = (int8) int.parse (v.substring (v.index_of_nth_char (2), 1));+ separator = v.substring (v.index_of_nth_char (3), 1);+ n3 = (int8) int.parse (v.substring (v.index_of_nth_char (4), 1));+ n4 = (int8) int.parse (v.substring (v.index_of_nth_char (5), 1)); }-- deka = (int8) int.parse (v.substring (v.index_of_nth_char (0), 1));- deci = (int8) int.parse (v.substring (v.index_of_nth_char (2), 1));- centi = (int8) int.parse (v.substring (v.index_of_nth_char (3), 1));- milli = (int8) int.parse (v.substring (v.index_of_nth_char (4), 1)); - if (check_boundaries && get_value () > max / 1000.0) {+ if (separator != ".") {+ warning (@"Expecting \".\" $new_value -> ($(v))");+ }+ + if (check_boundaries && get_int_value () > max) { warning (@"Out of bounds ($new_value > $max)."); set_value_round (max, false); } - if (check_boundaries && get_value () < min / 1000.0) {+ if (check_boundaries && get_int_value () < min) { warning (@"Out of bounds ($new_value < $min)."); set_value_round (min, false); }@@ -261,6 +380,7 @@ public class SpinButton : Tool { new_value_action (this); } + show_adjustmet_icon (); redraw (); } @@ -269,17 +389,63 @@ public class SpinButton : Tool { } public double get_value () {- return deka + (deci / 10.0) + (centi / 100.0) + (milli / 1000.0);+ double r;+ + if (!big_number) {+ r = n0 + (n1 / 10.0) + (n2 / 100.0) + (n3 / 1000.0) + (n4 / 1000.0);+ } else {+ r = (n0 * 100) + (n1 * 10) + n2 + (n3 / 10.0) + (n4 / 100.0);+ }+ + return (negative) ? -r : r; } private int get_int_value () {- return deka * 1000 + deci * 100 + centi * 10 + milli;+ int r = n0 * 10000 + n1 * 1000 + n2 * 100 + n3 * 10 + n4;+ return (negative) ? -r : r; } - public string get_display_value () {- return @"$deka.$deci$centi$milli";+ public string get_short_display_value () {+ + if (!big_number) {+ return @"$n0.$n1$n2$n3";+ }+ + if (negative) {+ if (n0 == 0 && n1 == 0) {+ return @" -$n2.$n3$n4";+ }+ + if (n0 == 0) {+ return @" -$n1$n2.$n3";+ }+ + return @" -$n0$n1$n2";+ }++ if (n0 == 0 && n1 == 0) {+ return @" $n2.$n3$n4";+ }+ + if (n0 == 0) {+ return @"$n1$n2.$n3$n4";+ }+ + return @"$n0$n1$n2.$n3"; } + public string get_display_value () {+ if (!big_number) {+ return @"$n0.$n1$n2$n3$n4";+ }+ + if (negative) {+ return @"-$n0$n1$n2.$n3$n4";+ }+ + return @"$n0$n1$n2.$n3$n4";+ }+ public override void draw (Context cr) { double scale = Toolbox.get_scale (); @@ -291,24 +457,26 @@ public class SpinButton : Tool { base.draw (cr); - cr.save ();- - cr.set_source_rgba (99/255.0, 99/255.0, 99/255.0, 1);- - cr.set_font_size (10 * scale);- cr.select_font_face ("Cantarell", FontSlant.NORMAL, FontWeight.NORMAL);+ if (!show_icon_tool_icon || waiting_for_icon_switch) {+ cr.save (); - if (BirdFont.android) {- cr.move_to (xt + text_x + 0.6 * MainWindow.units, yt + text_y);- } else if (BirdFont.mac || BirdFont.win32) {- cr.move_to (xt + text_x + 2, yt + text_y);- } else {- cr.move_to (xt + text_x, yt + text_y);+ cr.set_source_rgba (99/255.0, 99/255.0, 99/255.0, 1);+ + cr.set_font_size (10 * scale);+ cr.select_font_face ("Cantarell", FontSlant.NORMAL, FontWeight.NORMAL);+ + if (BirdFont.android) {+ cr.move_to (xt + text_x + 0.6 * MainWindow.units, yt + text_y);+ } else if (BirdFont.mac || BirdFont.win32) {+ cr.move_to (xt + text_x + 2, yt + text_y);+ } else {+ cr.move_to (xt + text_x, yt + text_y);+ }+ + cr.show_text (get_short_display_value ());+ + cr.restore (); }- - cr.show_text (get_display_value ());- - cr.restore (); } public void redraw () {@@ -175,7 +175,7 @@ public class Tool : GLib.Object { public void set_icon (string name) { StringBuilder n = new StringBuilder ();- n.append ((!) name);+ n.append (name); n.append (".png"); icon = Icons.get_icon (n.str); }