Commit d1cae04
select multiple paths
Changed files (8)
modifiedicons/new_point.pngmodifiedsrc/ClipTool.valamodifiedsrc/CutTool.valamodifiedsrc/Glyph.valamodifiedsrc/MoveTool.valamodifiedsrc/Path.valamodifiedsrc/PenTool.valamodifiedsrc/Toolbox.vala
Diff
Binary files a/icons/new_point.png and b/icons/new_point.png differ@@ -39,7 +39,7 @@ class ClipTool : Tool { if (fd is Glyph) { glyph = null;- path = MainWindow.get_current_glyph ().active_path;+ path = MainWindow.get_current_glyph ().get_active_path (); if (path == null) { glyph = MainWindow.get_current_glyph ();@@ -43,24 +43,18 @@ class CutTool : Tool { public static void force_direction () { Glyph g = MainWindow.get_current_glyph ();- Path p; Tool current_tool = MainWindow.get_toolbox ().get_current_tool (); - if (g.active_path == null) {- return;- }- - p = (!) g.active_path;- - if (p.is_editable () && p.is_open ()) {- - if (current_tool is PenTool) {- p.force_direction (Direction.CLOCKWISE);- } else if (current_tool is CutTool) {- p.force_direction (Direction.COUNTER_CLOCKWISE);+ foreach (Path p in g.active_paths) {+ if (p.is_editable () && p.is_open ()) {+ + if (current_tool is PenTool) {+ p.force_direction (Direction.CLOCKWISE);+ } else if (current_tool is CutTool) {+ p.force_direction (Direction.COUNTER_CLOCKWISE);+ } }- - } + } } }@@ -39,8 +39,8 @@ class Glyph : FontDisplay { // Paths public List<Path> path_list; // outline // FIXME: private- public Path? active_path = null;- Path? union_path = null; // add this to active path+ public List<Path> active_paths = new List<Path> ();+ bool move_edit_point = false; double last_move_offset_x = 0; double last_move_offset_y = 0;@@ -117,6 +117,30 @@ class Glyph : FontDisplay { path_list.append (new Path ()); } + public void clear_active_paths () {+ while (active_paths.length () > 0) {+ active_paths.remove_link (active_paths.first ());+ }+ }+ + public void add_active_path (Path? p) {+ if (p != null) {+ + foreach (Path pi in active_paths) {+ if (pi == p) {+ return;+ }+ }+ + active_paths.append ((!) p);+ }+ }+ + public Path? get_active_path () {+ return active_paths.last ().data;+ }+ + public void add_kerning (string right_glyph, double val) { Kerning? kl = null; @@ -471,11 +495,14 @@ class Glyph : FontDisplay { public override void key_press (EventKey e) { if (e.keyval == Key.DEL) {- if (active_path != null) {- Path p = (!) active_path;- close_path ();- path_list.remove (p);- redraw_area (0, 0, allocation.width, allocation.height);+ if (active_paths.length () != 0) {+ foreach (Path p in active_paths) {+ close_path ();+ path_list.remove (p);+ redraw_area (0, 0, allocation.width, allocation.height); + }+ + clear_active_paths (); } if (selected_point != null) {@@ -587,7 +614,10 @@ class Glyph : FontDisplay { public EditPoint add_new_edit_point (int x, int y) { insert_edit_point (x, y); move_edit_point = true;- last_added_edit_point = ((!) active_path).get_last_point ();+ + return_if_fail (active_paths.length () > 0);+ + last_added_edit_point = active_paths.last ().data.get_last_point (); return (!) last_added_edit_point; } @@ -716,48 +746,35 @@ class Glyph : FontDisplay { ry = Glyph.reverse_path_coordinate_y (y); } - public void move_selected_path (double x, double y) { - if (active_path == null) {- return;+ public bool select_path (double x, double y) {+ Path? p = null;+ bool found = false;+ + foreach (Path pt in path_list) {+ if (pt.is_over (x, y)) {+ p = pt;+ found = true;+ } }- - move_selected_path_freely (path_coordinate_x (x), path_coordinate_y (y));- }- - public void move_selected_path_freely (double coordinate_x, double coordinate_y) - requires (active_path != null)- {- double dx = coordinate_x - path_coordinate_x (pointer_begin_x);- double dy = coordinate_y - path_coordinate_y (pointer_begin_y);-- Path path = (!) active_path;-- path.move (dx - last_move_offset_x, dy - last_move_offset_y); - last_move_offset_x = dx;- last_move_offset_y = dy;+ if (!KeyBindings.has_shift ()) {+ clear_active_paths ();+ }+ + add_active_path (p); - queue_redraw_path (path);+ return found; } - public void move_path_begin (double x, double y) {- Supplement.get_current_font ().touch ();- Path? p = null;- - foreach (var pt in path_list) {+ public bool is_over_selected_path (double x, double y) {+ foreach (Path pt in active_paths) { if (pt.is_over (x, y)) {- p = pt;+ return true; } }- - active_path = p;- - last_move_offset_x = 0;- last_move_offset_y = 0;-- move_selected_path (x, y);+ return false; }- + public void queue_redraw_path (Path path) { redraw_path (path.xmin, path.ymin, path.xmax, path.ymax); }@@ -815,38 +832,39 @@ class Glyph : FontDisplay { return min_point; } - public Path? get_active_path () {- return active_path;- }- private void insert_edit_point (double x, double y) { unowned List<Path> paths; double xt, yt; bool added; Path np; - if (active_path == null) {+ if (active_paths.length () == 0) {+ print ("ADD empty\n"); np = new Path ();- active_path = np;+ clear_active_paths ();+ active_paths.append (np); path_list.append (np); } paths = path_list; - xt = path_coordinate_x (x);- yt = path_coordinate_y (y);- + xt = x - xc () - view_offset_x;+ yt = -y + yc () + view_offset_y;++ xt *= view_zoom;+ yt *= view_zoom; + added = false; if (new_point_on_path != null) {- return_if_fail (active_path != null);+ print ("ADD np\n");+ return_if_fail (active_paths.length () > 0); Path p = new Path (); EditPoint e = (!) new_point_on_path; return_if_fail (e.prev != null); - union_path = p; p.add_point (e); e.type = PointType.CURVE; @@ -854,27 +872,20 @@ class Glyph : FontDisplay { e.left_handle.type = PointType.CURVE; paths.append (p);- active_path = p;+ add_active_path (p); flipping_point_on_path = new_point_on_path; new_point_on_path = null; added = true; return; } - if (!added && union_path != null) {- Path p = (!) union_path;- if (p.is_open ()) {- p.add (xt, yt);- active_path = p;- added = true;- }- }- if (!added) {+ print ("ADD a\n"); foreach (Path p in paths) { if (p.is_open ()) { p.add (xt, yt);- active_path = p;+ clear_active_paths ();+ add_active_path (p); added = true; break; }@@ -882,10 +893,11 @@ class Glyph : FontDisplay { } if (!added) {+ print ("ADD X\n"); foreach (Path p in paths) { if (p.is_over (xt, yt)) { p.add (xt, yt);- active_path = p;+ paths.append (p); added = true; queue_draw_area (0, 0, allocation.width, allocation.height); break;@@ -894,6 +906,7 @@ class Glyph : FontDisplay { } if (!added) {+ print ("ADD NEW\n"); if (paths.length () > 0 && paths.last ().data.is_open ()) { paths.last().data.add (xt, yt); }@@ -906,13 +919,15 @@ class Glyph : FontDisplay { paths.append (np); np.add (xt, yt); - active_path = np;+ clear_active_paths ();+ add_active_path (np); } - return_if_fail (active_path != null);- - selected_point = ((!) active_path).get_last_point ();- + assert (active_paths.length () > 0);+ + selected_point = active_paths.last ().data.get_last_point ();+ assert (selected_point != null);+ move_selected_edit_point (x, y); } @@ -965,37 +980,39 @@ class Glyph : FontDisplay { private void redraw_last_stroke (double x, double y) { // redraw line, if we have more than one new point on path- double px;- double py;- int tw;- int th;+ double px = 0;+ double py = 0;+ int tw = 0;+ int th = 0; double xc = (allocation.width / 2.0); - if (active_path == null) {+ if (active_paths.length () == 0) { return; } - EditPoint? pt = ((!) active_path).get_second_last_point ();- if (pt != null) {- EditPoint p = (!) pt;- - px = p.x + xc;- py = p.y - xc;- - tw = (px > x) ? (int) (px - x) : (int) (x - px);- th = (py > y) ? (int) (py - y) : (int) (y - py);- - if (px > x) px -= tw + 60;- if (py > y) py -= th + 60;- - } else {- px = x - 60;- py = y - 60;- tw = 0;- th = 0;+ foreach (Path path in active_paths) {+ EditPoint? pt = path.get_second_last_point ();+ if (pt != null) {+ EditPoint p = (!) pt;+ + px = p.x + xc;+ py = p.y - xc;+ + tw = (px > x) ? (int) (px - x) : (int) (x - px);+ th = (py > y) ? (int) (py - y) : (int) (y - py);+ + if (px > x) px -= tw + 60;+ if (py > y) py -= th + 60;+ + } else {+ px = x - 60;+ py = y - 60;+ tw = 0;+ th = 0;+ } }-+ queue_draw_area ((int)px - 20, (int)py - 20, tw + 120, th + 120); } @@ -1007,7 +1024,7 @@ class Glyph : FontDisplay { } public bool has_active_path () {- return (active_path != null);+ return active_paths.length () > 0; } public bool is_editable () {@@ -1030,8 +1047,7 @@ class Glyph : FontDisplay { editable = false; - active_path = null;- union_path = null; + clear_active_paths (); new_point_on_path = null; flipping_point_on_path = null; selected_point = null;@@ -1567,7 +1583,9 @@ class Glyph : FontDisplay { g.add_path (p.copy ()); } - g.active_path = active_path;+ foreach (Path p in active_paths) {+ g.active_paths.append (p);+ } return g; }@@ -1595,8 +1613,11 @@ class Glyph : FontDisplay { } add_help_lines ();- - active_path = g.active_path;+ + clear_active_paths ();+ foreach (Path p in g.active_paths) {+ add_path (p);+ } undo_list.remove_link (undo_list.last ()); }@@ -21,6 +21,9 @@ class MoveTool : Tool { bool move_path = false; + double last_x = 0;+ double last_y = 0;+ public MoveTool (string n) { base (n, "Move paths", 'm', CTRL); @@ -30,6 +33,8 @@ class MoveTool : Tool { deselect_action.connect((self) => { Glyph glyph = MainWindow.get_current_glyph (); + glyph.clear_active_paths ();+ foreach (Path p in glyph.path_list) { p.set_color (0, 0, 0, 1); p.set_selected (false);@@ -38,14 +43,13 @@ class MoveTool : Tool { press_action.connect((self, b, x, y) => { Glyph glyph = MainWindow.get_current_glyph ();- Path path; glyph.store_undo_state (); - glyph.move_path_begin (x, y);- - if (glyph.active_path == null) {- return;+ if (!glyph.is_over_selected_path (x, y)) {+ if (!glyph.select_path (x, y)) {+ glyph.clear_active_paths ();+ } } move_path = true;@@ -55,36 +59,48 @@ class MoveTool : Tool { p.set_selected (false); } - return_if_fail (glyph.active_path != null);- - path = (!) glyph.active_path;+ return_if_fail (glyph.active_paths.length () != 0); - if (path.is_clockwise ()) {- path.set_color (0.2, 0.2, 0.4, 0.8);- path.set_selected (true);- } else {- path.set_color (0.5, 0.5, 0.7, 0.8);- path.set_selected (true);+ foreach (Path path in glyph.active_paths) {+ if (path.is_clockwise ()) {+ path.set_color (0.2, 0.2, 0.4, 0.8);+ path.set_selected (true);+ } else {+ path.set_color (0.5, 0.5, 0.7, 0.8);+ path.set_selected (true);+ } }- + + last_x = x;+ last_y = y; }); release_action.connect((self, b, x, y) => { Glyph glyph = MainWindow.get_current_glyph (); move_path = false;- - - if (GridTool.is_visible () && glyph.active_path != null) {- tie_path_to_grid ((!) glyph.active_path, x, y);+ + if (GridTool.is_visible ()) {+ foreach (Path p in glyph.active_paths) {+ tie_path_to_grid (p, x, y);+ } }- }); move_action.connect ((self, x, y) => { if (move_path) { Glyph glyph = MainWindow.get_current_glyph ();- glyph.move_selected_path (x, y);++ double dx = last_x - x;+ double dy = last_y - y; ++ foreach (Path path in glyph.active_paths) {+ path.move (glyph.ivz () * -dx, glyph.ivz () * dy);+ }+ MainWindow.get_glyph_canvas ().redraw ();+ + last_x = x;+ last_y = y; } }); }@@ -1538,7 +1538,7 @@ class Path { if (pl != null) { points.delete_link ((!) pl); reopen ();- MainWindow.get_current_glyph ().active_path = this;+ MainWindow.get_current_glyph ().add_active_path (this); create_list (); } }@@ -1582,11 +1582,11 @@ class Path { IntersectionList il = IntersectionList.create_intersection_list (this, p); Path np = new Path (); Intersection s = new Intersection (0, 0, 1);- EditPoint ex = points.last ().data;- EditPoint ix = points.last ().data;+ EditPoint ex;+ EditPoint ix; uint offset_i = 0; uint offset_j;- uint len_i = points.length ();+ uint len_i; int i, j; uint len_j; @@ -1613,8 +1613,12 @@ class Path { } // create a new path + ex = points.last ().data;+ ix = points.last ().data;+ len_i = points.length ();+ for (i = 0; i < points.length (); i++) {- ex = points.nth (i).data;+ ex = points.nth ((i + offset_i) % len_i).data; if (ex == points.first ().data && i != 0) { break;@@ -1687,7 +1691,6 @@ class Path { offset_i = 0; i = k; }- } return np;@@ -218,12 +218,10 @@ class PenTool : Tool { } public void select_active_point (double x, double y) {- Path cp; Glyph? g = MainWindow.get_current_glyph (); Glyph glyph = (!) g; - if (glyph.has_active_path ()) {- cp = (!) glyph.active_path;+ foreach (Path cp in glyph.active_paths) { foreach (var e in cp.points) { e.set_active (false); }@@ -256,11 +254,11 @@ class PenTool : Tool { GridTool.tie (ref x, ref y); } - return_if_fail (g.active_path != null);+ return_if_fail (g.active_paths.length () > 0); return_if_fail (g.new_point_on_path != null); EditPoint ep = (!) g.new_point_on_path;- Path p = (!) g.active_path;+ Path p = (!) g.get_active_path (); double rax, ray; double pax, pay;@@ -283,7 +281,8 @@ class PenTool : Tool { return_if_fail (ap.is_editable ()); - g.active_path = ap;+ g.clear_active_paths ();+ g.add_active_path (ap); if (g.new_point_on_path == null) { g.new_point_on_path = new EditPoint (0, 0, PointType.FLOATING);@@ -329,7 +328,7 @@ class PenTool : Tool { if (d < m && d * g.view_zoom < 14 && !is_over_handle (x, y)) { m = d; set_active_edit_point (e);- active_path = current_path;+ g.add_active_path (active_path); } } @@ -381,7 +380,9 @@ class PenTool : Tool { void set_linear_handles_for_last_point () { Glyph glyph; glyph = MainWindow.get_current_glyph ();- ((!)glyph.active_path).points.last ().data.right_handle.parent.recalculate_linear_handles ();+ return_if_fail (glyph.active_paths.length () > 0);+ return_if_fail (glyph.active_paths.last ().data.points.length () > 0);+ glyph.active_paths.last ().data.points.last ().data.right_handle.parent.recalculate_linear_handles (); } public static void set_default_handle_positions () {@@ -203,12 +203,11 @@ class Toolbox : DrawingArea { Tool reverse_path_tool = new Tool ("reverse_path", "Create counter from outline", 'r'); reverse_path_tool.select_action.connect((self) => { Glyph g = MainWindow.get_current_glyph ();- Path? p = g.active_path; - if (p != null) {- ((!)p).reverse ();+ foreach (Path p in g.active_paths) {+ p.reverse (); }- + g.redraw_area (0, 0, g.allocation.width, g.allocation.height); }); path_tool_modifiers.add_tool (reverse_path_tool);@@ -216,11 +215,8 @@ class Toolbox : DrawingArea { Tool move_layer = new Tool ("move_layer", "Move to path to bottom layer", 'd'); move_layer.select_action.connect((self) => { Glyph g = MainWindow.get_current_glyph ();- Path p;- - if (g.active_path != null) {- p = (!) g.active_path;- ++ foreach (Path p in g.active_paths) { g.path_list.remove (p); g.path_list.prepend (p); }