The Birdfont Source Code


All Repositories / birdfont.git / commitdiff – RSS feed

New bezier drawing tool

These changes was commited to the Birdfont repository Tue, 05 May 2015 10:44:27 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
[Tue, 05 May 2015 10:44:27 +0000]

Updated Files

libbirdfont/BezierTool.vala
libbirdfont/DrawingTools.vala
libbirdfont/ForesightTool.vala
libbirdfont/Glyph.vala
libbirdfont/MainWindow.vala
libbirdfont/PenTool.vala
resources/icons.bf
diff --git libbirdfont/BezierTool.vala(new)
--- /dev/null +++ b/libbirdfont/BezierTool.vala @@ -1,1 +1,229 @@ + /* + 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 Math; + using Cairo; + + namespace BirdFont { + + /** Create Beziér curves. */ + public class BezierTool : Tool { + + public const uint NONE = 0; + public const uint MOVE_POINT = 1; + public const uint MOVE_HANDLES = 2; + public const uint MOVE_LAST_HANDLE = 3; + public const uint MOVE_FIRST_HANDLE = 4; + + uint state = NONE; + bool move_right_handle = true; + int previous_point = 0; + + Path current_path = new Path (); + EditPoint current_point = new EditPoint (); + + int last_x = 0; + int last_y = 0; + + double last_release_time = 0; + + public BezierTool (string name) { + base (name, t_ ("Create Beziér curves")); + + select_action.connect ((self) => { + state = NONE; + MainWindow.set_cursor (NativeWindow.VISIBLE); + }); + + deselect_action.connect ((self) => { + state = NONE; + MainWindow.set_cursor (NativeWindow.VISIBLE); + }); + + press_action.connect ((self, b, x, y) => { + press (b, x, y); + }); + + double_click_action.connect ((self, b, x, y) => { + }); + + release_action.connect ((self, b, x, y) => { + release (b, x, y); + }); + + move_action.connect ((self, x, y) => { + move (x, y); + }); + + key_press_action.connect ((self, keyval) => { + }); + + key_release_action.connect ((self, keyval) => { + }); + + draw_action.connect ((tool, cairo_context, glyph) => { + if (PenTool.can_join (current_point)) { + PenTool.draw_join_icon (cairo_context, last_x, last_y); + } + }); + } + + public void press (int b, int x, int y) { + Glyph g = MainWindow.get_current_glyph (); + double px, py; + Path? p; + Path path; + + if (b == 2) { + if (g.is_open ()) { + g.close_path (); + } else { + g.open_path (); + } + + MainWindow.set_cursor (NativeWindow.VISIBLE); + state = NONE; + + return; + } + + PenTool.update_orientation (); + + MainWindow.set_cursor (NativeWindow.HIDDEN); + g.open_path (); + + px = Glyph.path_coordinate_x (x); + py = Glyph.path_coordinate_y (y); + + if (state == NONE) { + g.open_path (); + current_path = new Path (); + current_path.reopen (); + current_path.hide_end_handle = true; + current_point = current_path.add (px, py); + current_point.get_left_handle ().convert_to_line (); + current_point.recalculate_linear_handles (); + g.add_path (current_path); + GlyphCanvas.redraw (); + state = MOVE_POINT; + } else if (state == MOVE_POINT) { + if (PenTool.can_join (current_point)) { + p = PenTool.join_paths (current_point); + + return_if_fail (p != null); + path = (!) p; + + if (current_path.points.size == 1) { + return_if_fail (path.is_open ()); + current_path = path; + current_point = path.get_last_point (); + state = MOVE_POINT; + } else { + g.open_path (); + current_path = path; + current_point = path.get_first_point (); + state = MOVE_LAST_HANDLE; + } + } else { + state = MOVE_HANDLES; + } + } + } + + public void release (int b, int x, int y) { + double px, py; + Glyph g; + + // ignore double clicks + if ((GLib.get_real_time () - last_release_time) / 1000000.0 < 0.2) { + last_release_time = GLib.get_real_time (); + return; + } + last_release_time = GLib.get_real_time (); + + px = Glyph.path_coordinate_x (x); + py = Glyph.path_coordinate_y (y); + + if (state == MOVE_HANDLES) { + current_point = current_path.add (px, py); + current_path.hide_end_handle = true; + current_point.get_left_handle ().convert_to_line (); + current_point.recalculate_linear_handles (); + GlyphCanvas.redraw (); + state = MOVE_POINT; + } else if (state == MOVE_LAST_HANDLE) { + current_path.update_region_boundaries (); + g = MainWindow.get_current_glyph (); + g.close_path (); + MainWindow.set_cursor (NativeWindow.VISIBLE); + + if (Path.is_counter (g.get_paths (), current_path)) { + current_path.force_direction (Direction.COUNTER_CLOCKWISE); + } else { + current_path.force_direction (Direction.CLOCKWISE); + } + + state = NONE; + } + } + + public void move (int x, int y) { + double px, py; + + last_x = x; + last_y = y; + + px = Glyph.path_coordinate_x (x); + py = Glyph.path_coordinate_y (y); + + if (state == MOVE_POINT) { + current_point.x = px; + current_point.y = py; + current_path.hide_end_handle = true; + current_point.recalculate_linear_handles (); + GlyphCanvas.redraw (); + } else if (state == MOVE_HANDLES || state == MOVE_LAST_HANDLE) { + current_path.hide_end_handle = false; + current_point.set_reflective_handles (true); + current_point.convert_to_curve (); + current_point.get_right_handle ().move_to_coordinate (px, py); + GlyphCanvas.redraw (); + } + + if (current_path.points.size > 0) { + current_path.get_first_point ().set_reflective_handles (false); + current_path.get_last_point ().set_reflective_handles (false); + } + } + + public void switch_to_line_mode () { + int s = current_path.points.size; + if (s > 2) { + current_path.points.get (s - 2).get_right_handle ().convert_to_line (); + current_point.get_left_handle ().convert_to_line (); + } + } + + public void stop_drawing () { + if (state == MOVE_POINT && current_path.points.size > 0) { + current_path.delete_last_point (); + } + + state = NONE; + } + + } + + }
--- a/libbirdfont/DrawingTools.vala +++ b/libbirdfont/DrawingTools.vala @@ -40,7 +40,7 @@ public static MoveTool move_tool; public static PenTool pen_tool; - public static ForesightTool foresight_tool; + public static BezierTool bezier_tool; PointTool point_tool; public static ZoomTool zoom_tool; public static ResizeTool resize_tool; @@ -121,15 +121,15 @@ font_name.add_tool (new FontName ()); // Draw tools - foresight_tool = new ForesightTool ("foresight"); - foresight_tool.select_action.connect ((self) => { + bezier_tool = new BezierTool ("bezier_tool"); + bezier_tool.select_action.connect ((self) => { update_drawing_and_background_tools (self); }); - draw_tools.add_tool (foresight_tool); + draw_tools.add_tool (bezier_tool); Tool bezier_line = new Tool ("bezier_line", t_("Convert the last segment to a straight line")); bezier_line.select_action.connect ((self) => { - foresight_tool.switch_to_line_mode (); + bezier_tool.switch_to_line_mode (); }); bezier_line.is_tool_modifier = true; draw_tools.add_tool (bezier_line); @@ -589,8 +589,8 @@ current = MainWindow.get_toolbox ().get_current_tool (); - if (current is ForesightTool) { - ((ForesightTool) current).stop_drawing (); + if (current is BezierTool) { + ((BezierTool) current).stop_drawing (); } PenTool.reset_stroke (); @@ -821,7 +821,7 @@ || pen_tool.is_selected () || track_tool.is_selected () || point_tool.is_selected () - || foresight_tool.is_selected (); + || bezier_tool.is_selected (); StrokeTool.stroke_width = object_stroke.get_value (); @@ -1097,9 +1097,9 @@ Toolbox tb = MainWindow.get_toolbox (); tb.reset_active_tool (); - update_drawing_and_background_tools (foresight_tool); - tb.select_tool (foresight_tool); - tb.set_current_tool (foresight_tool); + update_drawing_and_background_tools (bezier_tool); + tb.select_tool (bezier_tool); + tb.set_current_tool (bezier_tool); set_point_type_from_preferences (); @@ -1269,7 +1269,7 @@ move_background.set_selected (false); cut_background.set_selected (false); - foresight_tool.set_selected (false); + bezier_tool.set_selected (false); pen_tool.set_selected (false); point_tool.set_selected (false); zoom_tool.set_selected (false); @@ -1296,7 +1296,7 @@ if (resize_tool.is_selected () || move_tool.is_selected ()) { show_object_tool_modifiers (); - } else if (foresight_tool.is_selected () + } else if (bezier_tool.is_selected () || pen_tool.is_selected () || point_tool.is_selected () || track_tool.is_selected ()) {
diff --git libbirdfont/ForesightTool.vala(deleted)
--- a/libbirdfont/ForesightTool.vala +++ /dev/null @@ -1,516 +1,1 @@ - /* - Copyright (C) 2014 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 Math; - using Cairo; - - namespace BirdFont { - - /** Create Beziér curves and preview the path. */ - public class ForesightTool : Tool { - - public const uint NONE = 0; - public const uint MOVE_POINT = 1; - public const uint MOVE_HANDLES = 2; - public const uint MOVE_LAST_HANDLE = 3; - public const uint MOVE_FIRST_HANDLE = 4; - - uint state = NONE; - bool move_right_handle = true; - int previous_point = 0; - - Path current_path = new Path (); - - int last_move_x = 0; - int last_move_y = 0; - - public bool skip_deselect = false; - - static int press_counter = 0; - double last_release_time = 0; - - public ForesightTool (string name) { - base (name, t_ ("Create Beziér curves")); - - select_action.connect ((self) => { - PenTool p = (PenTool) PointTool.pen (); - - if (state != NONE) { - p.release_action (p, 1, last_move_x, last_move_y); - } - - MainWindow.get_current_glyph ().clear_active_paths (); - MainWindow.set_cursor (NativeWindow.VISIBLE); - state = NONE; - }); - - deselect_action.connect ((self) => { - PenTool p = (PenTool) PointTool.pen (); - - if (state != NONE) { - p.release_action (p, 1, last_move_x, last_move_y); - } - - MainWindow.set_cursor (NativeWindow.VISIBLE); - state = NONE; - }); - - press_action.connect ((self, b, x, y) => { - // ignore double clicks - if ((GLib.get_real_time () - last_release_time) / 1000000.0 < 0.2) { - print ("Double click."); - last_release_time = GLib.get_real_time (); - MainWindow.set_cursor (NativeWindow.VISIBLE); - return; - } - last_release_time = GLib.get_real_time (); - - press (b, x, y); - }); - - double_click_action.connect ((self, b, x, y) => { - EditPoint last; - get_active_path ().delete_last_point (); - - last = get_active_path ().get_last_point (); - - PenTool.selected_points.clear (); - PenTool.selected_points.add (new PointSelection (last, get_active_path ())); - PenTool.selected_point = last; - PenTool.active_edit_point = null; - }); - - release_action.connect ((self, b, x, y) => { - PenTool p = (PenTool) PointTool.pen (); - PointSelection last; - - last_move_x = x; - last_move_y = y; - - if (b == 2) { - return; - } - - if (state == MOVE_HANDLES || state == MOVE_FIRST_HANDLE) { - if (state != MOVE_FIRST_HANDLE) { - last = add_new_point (x, y); - } - - state = MOVE_POINT; - move_action (this, x, y); - } else if (state == MOVE_LAST_HANDLE) { - previous_point = 0; - - if (unlikely (PenTool.selected_points.size == 0)) { - warning ("No point in move last handle."); - return; - } - - last = PenTool.selected_points.get (PenTool.selected_points.size - 1); - - p.release_action (p, 2, x, y); - - PenTool.selected_points.add (last); - PenTool.active_path.highlight_last_segment = false; - - last.path.direction_is_set = false; - PenTool.force_direction (); - - state = NONE; - MainWindow.set_cursor (NativeWindow.VISIBLE); - } else if (state == MOVE_POINT) { - } else if (state == NONE) { - } else { - warning (@"Unknown state $state."); - } - - current_path.hide_end_handle = true; - }); - - move_action.connect ((self, x, y) => { - Tool p = PointTool.pen (); - PointSelection last; - bool lh; - EditPointHandle h; - Path a; - - last_move_x = x; - last_move_y = y; - - a = get_active_path (); - if (a.is_open () && a.points.size > 1) { - a.get_first_point ().set_reflective_handles (false); - a.get_first_point ().set_tie_handle (false); - } - - if (MainWindow.dialog.visible && state != NONE) { - state = NONE; - p.release_action (p, 1, last_move_x, last_move_y); - } - - if (state == NONE) { - MainWindow.set_cursor (NativeWindow.VISIBLE); - } - - PenTool.active_path = current_path; - PenTool.active_path.hide_end_handle = (state == MOVE_POINT); - - if (state == MOVE_HANDLES || state == MOVE_LAST_HANDLE) { - if (previous_point > 0) { - return_if_fail (PenTool.active_path.points.size >= previous_point + 1); - return_if_fail (PenTool.active_path.points.size > 0); - last = new PointSelection (PenTool.active_path.points.get (PenTool.active_path.points.size - (previous_point + 1)), PenTool.active_path); - } else { - if (unlikely (PenTool.selected_points.size == 0)) { - warning ("No point to move in state %u", state); - return; - } - last = PenTool.selected_points.get (PenTool.selected_points.size - 1); - - if (last.point.get_right_handle ().is_line () || last.point.get_left_handle ().is_line ()) { - last.point.convert_to_curve (); - last.point.get_right_handle ().length = 0.1; - last.point.get_left_handle ().length = 0.1; - } - } - - PenTool.move_selected_handle = true; - PenTool.move_selected = false; - - lh = (state == MOVE_LAST_HANDLE); - - if (!move_right_handle) { - lh = !lh; - } - - if (previous_point > 0) { - lh = false; - } - - h = (lh) ? last.point.get_left_handle () : last.point.get_right_handle (); - PenTool.selected_handle = h; - PenTool.active_handle = h; - - if (previous_point == 0 - && !last.point.reflective_point - && !last.point.tie_handles) { - - last.point.convert_to_curve (); - last.point.set_reflective_handles (true); - last.point.get_right_handle ().length = 0.1; - last.point.get_left_handle ().length = 0.1; - } - - if (previous_point == 0) { - last.point.set_reflective_handles (true); - } - - if (previous_point > 0) { - PenTool.retain_angle = last.point.tie_handles; - } - - if (h.is_line ()) { - last.point.convert_to_curve (); - last.point.get_right_handle ().length = 0.1; - last.point.get_left_handle ().length = 0.1; - } - - p.move_action (p, x, y); - last.point.set_reflective_handles (false); - - PenTool.selected_handle = h; - PenTool.active_handle = h; - - PenTool.move_selected_handle = false; - last.path.highlight_last_segment = true; - - if (previous_point == 0) { - last.point.set_tie_handle (true); - p.move_action (p, x, y); - } - - PenTool.retain_angle = false; - - MainWindow.set_cursor (NativeWindow.HIDDEN); - } else { - if (DrawingTools.get_selected_point_type () != PointType.QUADRATIC) { - p.move_action (p, x, y); - } else { - PenTool.move_point_independent_of_handle = true; - p.move_action (p, x, y); - PenTool.move_point_independent_of_handle = false; - } - } - - if (PenTool.active_path.points.size < 3) { - PenTool.active_edit_point = null; - } - }); - - key_press_action.connect ((self, keyval) => { - PenTool p = (PenTool) PointTool.pen (); - p.key_press_action (p, keyval); - }); - - key_release_action.connect ((self, keyval) => { - Tool p = PointTool.pen (); - p.key_release_action (p, keyval); - MainWindow.set_cursor (NativeWindow.VISIBLE); - }); - - draw_action.connect ((tool, cairo_context, glyph) => { - Tool p = PointTool.pen (); - p.draw_action (p, cairo_context, glyph); - }); - } - - public void press (int b, int x, int y) { - PenTool p = (PenTool) PointTool.pen (); - PointSelection ps; - EditPoint first_point; - bool clockwise; - Path? path = null; - bool one_point = false; - Glyph g; - - MainWindow.set_cursor (NativeWindow.HIDDEN); - - BirdFont.get_current_font ().touch (); - g = MainWindow.get_current_glyph (); - g.store_undo_state (); - - if (b == 2) { - last_move_x = x; - last_move_y = y; - - stop_drawing (); - - move_action (this, x, y); - return; - } - - if (state == NONE) { - state = MOVE_POINT; - - PenTool.active_path = get_active_path (); - - add_new_point (x, y); - - PenTool.last_point_x = Glyph.path_coordinate_x (x); - PenTool.last_point_y = Glyph.path_coordinate_y (y); - - move_action (this, x, y); - state = MOVE_FIRST_HANDLE; - - press_action(this, b, x, y); - release_action(this, b, x, y); - } - - if (previous_point > 0) { - previous_point = 0; - state = MOVE_POINT; - } - - if (previous_point == 0) { - if (state == MOVE_POINT) { - state = MOVE_HANDLES; - - path = PenTool.find_path_to_join (); - - if (path != null) { - one_point = (((!) path).points.size == 1); - } - - if (p.has_join_icon ()) { - // FIXME: last activa path in list - ps = new PointSelection (PenTool.active_path.points.get (PenTool.active_path.points.size - 1), PenTool.active_path); - ps.point.set_tie_handle (false); - - ps = new PointSelection (PenTool.active_path.points.get (0), PenTool.active_path); - ps.point.set_tie_handle (false); - - first_point = PenTool.active_path.points.get (0); - clockwise = PenTool.active_path.is_clockwise (); - - PenTool.move_selected = false; - p.release_action (p, 2, x, y); - - PenTool.move_selected = false; - p.press_action (p, 2, x, y); - - if (ps.path.has_point (first_point)) { - ps.path.reverse (); - } - - if (clockwise && PenTool.active_path.is_clockwise ()) { - ps = new PointSelection (PenTool.active_path.points.get (0), PenTool.active_path); - } else { - ps = new PointSelection (PenTool.active_path.points.get (PenTool.active_path.points.size - 1), PenTool.active_path); - } - - PenTool.selected_points.clear (); - PenTool.selected_points.add (ps); - PenTool.selected_point = ps.point; - - state = MOVE_LAST_HANDLE; - - if (one_point) { - p.press_action (p, 2, x, y); - state = NONE; - } - } - } - } - - last_move_x = x; - last_move_y = y; - } - - public void stop_drawing () { - PenTool p = (PenTool) PointTool.pen (); - Path a; - - p.release_action (p, 1, last_move_x, last_move_y); - - if (state != NONE) { - a = get_active_path (); - if (a.is_open () && a.points.size > 0) { - a.delete_last_point (); - - a.get_first_point ().set_reflective_handles (false); - a.get_first_point ().set_tie_handle (false); - - a.get_last_point ().set_reflective_handles (false); - a.get_last_point ().set_tie_handle (false); - } - } - - p.press_action (p, 2, last_move_x, last_move_y); - p.release_action (p, 2, last_move_x, last_move_y); - current_path.hide_end_handle = true; - - previous_point = 0; - state = NONE; - - MainWindow.get_current_glyph ().clear_active_paths (); - PenTool.active_path = new Path (); - } - - public Path get_active_path () { - Glyph g = MainWindow.get_current_glyph (); - if (g.active_paths.size == 0) { - return new Path (); - } - return g.active_paths.get (g.active_paths.size -1); - } - - public void switch_to_line_mode () { - EditPoint ep; - EditPoint last; - - if (PenTool.active_path.points.size > 2) { - ep = PenTool.active_path.points.get (PenTool.active_path.points.size - 2); - ep.get_right_handle ().convert_to_line (); - ep.set_tie_handle (false); - - last = PenTool.active_path.points.get (PenTool.active_path.points.size - 1); - last.convert_to_line (); - - move_action (this, last_move_x, last_move_y); - } - } - - PointSelection add_new_point (int x, int y) { - PointSelection last; - double handle_x, handle_y; - - PenTool p = (PenTool) PointTool.pen (); - - if (PenTool.active_path.points.size == 0) { - last = p.new_point_action (x, y); - } else { - if (PenTool.selected_points.size == 0) { - last = p.new_point_action (x, y); - } - - if (PenTool.selected_points.size == 0) { - warning ("No selected points."); - return new PointSelection.empty (); - } - - last = PenTool.selected_points.get (PenTool.selected_points.size - 1); - - PenTool.selected_points.clear (); - PenTool.selected_handle = new EditPointHandle.empty (); - - if (DrawingTools.get_selected_point_type () != PointType.QUADRATIC) { - last = p.new_point_action (x, y); - } else { - last.point.get_right_handle ().length *= 0.999999; - handle_x = last.point.get_right_handle ().x; - handle_y = last.point.get_right_handle ().y; - - last = p.new_point_action (x, y); - - last.point.get_left_handle ().x = handle_x; - last.point.get_left_handle ().y = handle_y; - } - - PenTool.move_selected = true; - p.move_action (p, x, y); - } - - PenTool.selected_points.clear (); - PenTool.selected_points.add (last); - PenTool.selected_point = last.point; - PenTool.active_edit_point = null; - PenTool.show_selection_box = false; - - PenTool.move_selected_handle = false; - PenTool.move_selected = true; - - PenTool.active_path.hide_end_handle = (state == MOVE_POINT); - - current_path = last.path; - - return last; - } - - // FIXME: solve the straight line issue in undo - public override void before_undo () { - EditPoint last; - - if (PenTool.active_path.points.size > 1) { - last = PenTool.active_path.points.get (PenTool.active_path.points.size - 2); - last.convert_to_curve (); - } - } - - public override void after_undo () { - PenTool.selected_points.clear (); - PenTool.active_edit_point = null; - state = NONE; - - EditPoint last; - - if (PenTool.active_path.points.size > 0) { - last = PenTool.active_path.points.get (PenTool.active_path.points.size - 1); - last.convert_to_curve (); - } - } - - } - - }
--- a/libbirdfont/Glyph.vala +++ b/libbirdfont/Glyph.vala @@ -1559,7 +1559,7 @@ if (!(MainWindow.get_toolbox ().get_current_tool () is PenTool) && !(MainWindow.get_toolbox ().get_current_tool () is PointTool) && !(MainWindow.get_toolbox ().get_current_tool () is TrackTool) - && !(MainWindow.get_toolbox ().get_current_tool () is ForesightTool)) { + && !(MainWindow.get_toolbox ().get_current_tool () is BezierTool)) { cr.save (); cr.new_path (); foreach (Path p in active_paths) { @@ -2277,8 +2277,18 @@ }); TabContent.show_text_input (listener); + } + + public PathList get_paths () { + PathList pl = new PathList (); + + foreach (Path p in path_list) { + pl.add (p); + } + + return pl; } } }
--- a/libbirdfont/MainWindow.vala +++ b/libbirdfont/MainWindow.vala @@ -52,7 +52,7 @@ dialog = new Dialog (); spacing_tab = new SpacingTab (); - tools.select_tool (DrawingTools.foresight_tool); + tools.select_tool (DrawingTools.bezier_tool); } public static SpacingTab get_spacing_tab () {
--- a/libbirdfont/PenTool.vala +++ b/libbirdfont/PenTool.vala @@ -161,8 +161,8 @@ x = Glyph.path_coordinate_x (ix); y = Glyph.path_coordinate_y (iy); - if (has_join_icon ()) { - join_paths (x, y); + if (has_join_icon () && active_edit_point != null) { + join_paths ((!) active_edit_point); } active_handle = new EditPointHandle.empty (); @@ -176,20 +176,7 @@ edit_active_corner = false; show_selection_box = false; - // update path direction if it has changed - foreach (Path p in clockwise) { - if (!p.is_open () && !p.is_clockwise ()) { - p.reverse (); - update_selection (); - } - } - - foreach (Path p in counter_clockwise) { - if (!p.is_open () && p.is_clockwise ()) { - p.reverse (); - update_selection (); - } - } + set_orientation (); MainWindow.set_cursor (NativeWindow.VISIBLE); @@ -252,10 +239,10 @@ key_release_action.connect ((self, keyval) => { double x, y; if (is_arrow_key (keyval)) { - if (KeyBindings.modifier != CTRL) { + if (KeyBindings.modifier != CTRL && active_edit_point != null) { x = Glyph.reverse_path_coordinate_x (selected_point.x); y = Glyph.reverse_path_coordinate_y (selected_point.y); - join_paths (x, y); + join_paths ((!) active_edit_point); reset_stroke (); } } @@ -278,11 +265,36 @@ counter_clockwise.add (p); } } + } + + public static void set_orientation () { + // update path direction if it has changed + foreach (Path p in clockwise) { + if (!p.is_open () && !p.is_clockwise ()) { + p.reverse (); + update_selection (); + } + } + + foreach (Path p in counter_clockwise) { + if (!p.is_open () && p.is_clockwise ()) { + p.reverse (); + update_selection (); + } + } } public bool has_join_icon () { + if (active_edit_point != null) { + return can_join ((!) active_edit_point); + } + + return false; + } + + public static bool can_join (EditPoint ep) { double mx, my; - get_tie_position (out mx, out my); + get_tie_position (ep, out mx, out my); return (mx > -10 * MainWindow.units && my > -10 * MainWindow.units); } @@ -1055,7 +1067,7 @@ } } - public static Path? find_path_to_join () { + public static Path? find_path_to_join (EditPoint end_point) { Path? m = null; Glyph glyph = MainWindow.get_current_glyph (); EditPoint ep_last, ep_first; @@ -1068,12 +1080,12 @@ ep_last = path.points.get (path.points.size - 1); ep_first = path.points.get (0); - if (active_edit_point == ep_last) { + if (end_point == ep_last) { m = path; break; } - if (active_edit_point == ep_first) { + if (end_point == ep_first) { m = path; break; } @@ -1162,7 +1174,8 @@ } } - private static void join_paths (double x, double y) { + /** @return the new path or null if no path could be merged with the end point. */ + public static Path? join_paths (EditPoint end_point) { Glyph glyph = MainWindow.get_current_glyph (); Path? p; Path path; @@ -1171,25 +1184,26 @@ int px, py; if (glyph.path_list.size == 0) { - return; + warning ("No paths."); + return null; } - p = find_path_to_join (); + p = find_path_to_join (end_point); if (p == null) { warning ("No path to join."); - return; + return null; } path = (!) p; if (!path.is_open ()) { warning ("Path is closed."); - return; + return null; } return_if_fail (path.points.size > 0); - px = Glyph.reverse_path_coordinate_x (((!) active_edit_point).x); - py = Glyph.reverse_path_coordinate_y (((!) active_edit_point).y); + px = Glyph.reverse_path_coordinate_x (end_point.x); + py = Glyph.reverse_path_coordinate_y (end_point.y); if (path.points.size == 1) { glyph.delete_path (path); @@ -1202,10 +1216,7 @@ active_path = merge; merge.reopen (); glyph.open_path (); - - print ("CONTINUE FIRST\n"); - - return; + return merge; } if (is_close_to_point (merge.points.get (0), px, py)) { @@ -1215,15 +1226,12 @@ merge.reopen (); glyph.open_path (); merge.reverse (); - - print ("CONTINUE\n"); - - return; + return merge; } } } - return; + return null; } if (active_edit_point == path.points.get (0)) { @@ -1237,11 +1245,11 @@ if (path.points.get (0) == active_edit_point) { warning ("Wrong direction."); - return; + return null; } // join path with it self - if (is_endpoint ((!) active_edit_point) + if (is_endpoint (end_point) && is_close_to_point (path.points.get (0), px, py)) { close_path (path); @@ -1258,7 +1266,7 @@ remove_all_selected_points (); - return; + return path; } foreach (Path merge in glyph.path_list) { @@ -1306,7 +1314,7 @@ union.update_region_boundaries (); - return; + return union; } } } @@ -1315,6 +1323,8 @@ path.reverse (); update_selection (); } + + return null; } /** Merge paths if ends are close. */ @@ -1390,29 +1400,27 @@ void draw_merge_icon (Context cr) { double x, y; - get_tie_position (out x, out y); - draw_join_icon (cr, x, y); + if (active_edit_point != null) { + get_tie_position ((!) active_edit_point, out x, out y); + draw_join_icon (cr, x, y); + } } /** Obtain the position where to ends meet. */ - void get_tie_position (out double x, out double y) { + static void get_tie_position (EditPoint current_point, out double x, out double y) { Glyph glyph; EditPoint active; double px, py; x = -100; y = -100; - - if (active_edit_point == null) { - return; - } - if (!is_endpoint ((!) active_edit_point)) { + if (!is_endpoint (current_point)) { return; } glyph = MainWindow.get_current_glyph (); - active = (!) active_edit_point; + active = current_point; return_if_fail (!is_null (glyph));
--- a/resources/icons.bf +++ b/resources/icons.bf @@ -197,6 +197,17 @@ <path stroke="0" skew="0" data="B 27.7861863406,22.2108278413 C 23.9343338559,18.2055131235 24.0569386642,11.9290716829 28.0622714717,8.0772300520 C 32.0675861895,4.2255331388 38.4190999204,4.2759672461 42.2709053719,8.2812819639 C 46.1227470028,12.2865966817 45.9972767846,18.7102883495 41.9919620668,22.5621299804 C 37.9866111696,26.4138268936 31.6379917921,26.2161425591 27.7861863406,22.2108278413" /> <path stroke="0" skew="0" data="B 4.0220618989,40.1137420113 M -13.6154038886,22.4762762238 M -16.2157994855,24.9636111426 M 1.4216663020,42.6010769301 M 4.0220618989,40.1137420113" /> <path stroke="0" skew="0" data="B 28.7823504083,25.8680965676 M 26.2950154895,23.2677009707 M 9.6750958051,39.5484386207 M 12.1624307239,42.1488342176 M 28.7823504083,25.8680965676" /> + </glyph> + </collection> + <collection name="bezier_tool"> + <selected id="2"/> + <glyph id="1" left="-28" right="28"> + </glyph> + <glyph id="2" left="-28" right="44.054140127388528"> + <path stroke="0" skew="0" data="B 2.5292812784,44.7926187215 M 3.8367822764,44.0794363589 C 3.8367822764,44.0794363589 5.6698701483,42.9721208955 7.9970127245,41.8210255443 C 10.3241553008,40.6699301929 13.1430703979,39.5057503226 14.8911088956,39.0871598212 C 19.3725947163,38.0139630021 26.1831629693,36.8287490065 26.1831629693,36.8287490065 M 27.3718002401,36.5910215523 M 27.3718002401,35.4023842815 M 27.2527463310,22.0896468474 M 27.1336924219,21.2576007579 M 26.4205100595,20.9011997585 C 14.7034373343,14.4397295176 4.6763976082,5.9023851103 -3.6520128941,-5.3676839283 M -4.1274678025,-5.9620025637 M -4.8406501651,-5.9620025637 M -12.2102012447,-5.6056015645 M -13.8742934239,-5.4865476553 M -13.5178924246,-3.8224554761 C -11.9078879957,3.0714124768 -9.7659065790,13.9251351612 -4.7219766199,31.0046165611 M -4.7219766199,31.2423440153 M -4.6029227109,31.3613979244 M 1.9345822790,43.4854980875 M 2.5289009145,44.7929990855 M 2.5292812784,44.7926187215" /> + <path stroke="0" skew="0" data="B -6.0814353303,7.6780380292 C -3.5720984332,13.3816711826 -0.0943930151,18.9058105991 -0.0943930151,18.9058105991 C -0.1213608175,21.2315838652 1.2735097744,23.8255517361 3.7141149100,24.8070428125 C 3.9112575332,22.5672698301 3.4487349984,20.0078770403 1.1973228799,18.3312708879 C 1.2685270069,18.4826557306 -1.6727511654,13.8106836556 -4.5064243827,7.6525916825 C -6.0859768756,4.2199593898 -7.8261540635,-0.4207775145 -8.7011999798,-2.8886939252 M -5.4349688005,-3.1090829315 C 2.8294264529,7.8699316302 12.8614869829,16.3623550577 24.2809629719,22.8032095738 M 24.5186904260,34.2141273744 C 23.3475879321,34.4153018553 18.4726536657,35.2347198626 14.2964098964,36.2348107351 C 12.0221759422,36.7794158052 9.0907872321,38.1373150235 6.6891313626,39.3252676394 C 5.0266747482,40.1476144488 4.4331929135,40.4779605192 3.7175381854,40.8704960915 C 3.7176015794,40.8705594855 3.7176649733,40.8706228794 3.7177283673,40.8706862734 C 1.8159087339,37.3443957031 -0.0859108995,33.8181051328 -1.9877305330,30.2918145624 C -2.0242454699,30.1693373781 -2.0725516886,30.1761839288 -2.1067844420,30.0540871083 M -2.1067844420,29.9350331993 C -6.7668891626,14.0819211717 -8.7232149468,4.0716935311 -10.3083816112,-2.8713554774 C -9.4782492743,-0.6638813021 -7.6385524745,4.1387053056 -6.0814353303,7.6780380292" /> + <path stroke="0" skew="0" data="B 27.6008011519,43.5614898312 C 27.5611165156,43.5771398250 27.6856077556,43.5107018807 27.7280110575,43.4853079055 M 27.3716100582,35.1648470092 M 24.5188806080,35.2839009183 M 24.8752816073,42.4157245437 C 21.8079888660,42.7833462789 18.5182973370,42.7399847911 15.2473197131,43.8420892688 C 12.5363138619,44.7555332387 9.9518170529,46.4453760558 7.8777686335,47.8834559898 M 4.3118568209,42.0591333624 M 1.9345822790,43.6043618145 C 3.3609470041,45.8627726292 4.7873117292,48.1211834440 6.2136764543,50.3795942587 C 6.4910251508,50.8550491670 6.7683738473,51.3305040754 7.0457225439,51.8059589838 C 7.0457859379,51.8058955898 7.0458493318,51.8058321958 7.0459127258,51.8057688018 M 9.4229970857,57.7491453382 C 9.6211032975,58.1453577619 9.8192095093,58.5415701855 10.0173157211,58.9377826091 C 10.4135281448,58.7792976396 10.8097405684,58.6208126702 11.2059529921,58.4623277007 C 17.3076243160,56.3227806132 23.4092956399,54.1832335256 29.5109669638,52.0436864380 C 29.9864218721,51.8852014685 30.4618767805,51.7267164990 30.9373316888,51.5682315295 C 30.7392254770,51.1323978636 30.5411192652,50.6965641976 30.3430130534,50.2607305316 C 29.4317244791,48.0023197169 28.5148717858,45.7945700646 27.6008011519,43.5614898312" /> + <path stroke="0" skew="0" data="B 25.0586929962,45.1476024612 C 25.7093155024,46.7741587267 26.4420259467,48.3186270539 27.1336924219,49.9041393503 M 11.4436804462,55.3718707964 C 10.6555237791,53.6766937351 9.8673671120,51.9815166738 9.0792104449,50.2863396124 C 9.2940350824,50.2199310451 9.4702169488,50.0445714056 9.6005524501,49.9639820033 C 11.4474465869,48.7280947041 14.0174099645,47.3106270615 16.1984197118,46.5757648098 C 18.7674832545,45.7101735478 21.9871036230,45.4530142351 25.0586929962,45.1476024612" /> </glyph> </collection> <collection unicode="U+63"> @@ -348,15 +359,6 @@ <path stroke="0" skew="0" data="B 41.0236679454,30.0974646889 M -26.3243021946,30.0974646889 M -26.3243021946,55.9141643389 M 41.0236679454,30.0974646889" /> <path stroke="0" skew="0" data="S -25.3665421546,24.3211646889 L 40.1345454976,24.3205002780 D 40.3596169139,24.3000700543 40.8020370918,24.1875663112 40.9953527269,24.0748119023 T D 41.1886683620,23.9620574934 41.5173997715,23.6381388541 41.6329928586,23.4465070986 T D 41.7485859457,23.2548753431 41.8817800303,22.8130077607 41.8913493501,22.5894167957 T D 41.9009186699,22.3658258307 41.8059648722,21.9141939001 41.7071675216,21.7133865919 T D 41.6083701710,21.5125792837 41.2910233967,21.1835652090 41.1255415084,21.0328992336 T D 41.0421499153,20.9569738508 40.8325488577,20.8614401622 40.7272079454,20.8211646889 T M -25.0385673174,-4.3233652999 D -25.2628928274,-4.3507988934 -25.7190842527,-4.3340033741 -25.9318120724,-4.2644953439 T D -26.1445398920,-4.1949873137 -26.5341220322,-3.9475739339 -26.6874843324,-3.7845877493 T D -26.8408466326,-3.6216015647 -27.0375617464,-3.2089729173 -27.1205691734,-3.0011406328 T D -27.1623992592,-2.8964073263 -27.1792330921,-2.6666129025 -27.1790421937,-2.5538353111 T M -27.1359325093,22.9141950272 D -27.0731826331,23.1313055739 -26.8788049353,23.5443552279 -26.7314301420,23.7127748283 T D -26.5840553487,23.8811944287 -26.1924072083,24.1169293871 -25.9935863668,24.2196657707 T D -25.8933942136,24.2714379059 -25.4414845990,24.3282087104 -25.5540421546,24.3211646889 T D -25.5925260836,24.3187563066 -25.4134171546,24.3211651644 -25.3665421546,24.3211646889 T" /> <path stroke="0" skew="0" data="B -23.5540421546,0.0711646889 M 30.3522079454,20.7274646889 M -23.5540421546,20.7274646889 M -23.5540421546,0.0711646889" /> - </glyph> - </collection> - <collection name="foresight"> - <selected id="1"/> - <glyph id="1" left="-28" right="44.054140127388528"> - <path stroke="0" skew="0" data="B 2.5292812784,44.7926187215 M 3.8367822764,44.0794363589 C 3.8367822764,44.0794363589 5.6698701483,42.9721208955 7.9970127245,41.8210255443 C 10.3241553008,40.6699301929 13.1430703979,39.5057503226 14.8911088956,39.0871598212 C 19.3725947163,38.0139630021 26.1831629693,36.8287490065 26.1831629693,36.8287490065 M 27.3718002401,36.5910215523 M 27.3718002401,35.4023842815 M 27.2527463310,22.0896468474 M 27.1336924219,21.2576007579 M 26.4205100595,20.9011997585 C 14.7034373343,14.4397295176 4.6763976082,5.9023851103 -3.6520128941,-5.3676839283 M -4.1274678025,-5.9620025637 M -4.8406501651,-5.9620025637 M -12.2102012447,-5.6056015645 M -13.8742934239,-5.4865476553 M -13.5178924246,-3.8224554761 C -11.9078879957,3.0714124768 -9.7659065790,13.9251351612 -4.7219766199,31.0046165611 M -4.7219766199,31.2423440153 M -4.6029227109,31.3613979244 M 1.9345822790,43.4854980875 M 2.5289009145,44.7929990855 M 2.5292812784,44.7926187215" /> - <path stroke="0" skew="0" data="B -6.0814353303,7.6780380292 C -3.5720984332,13.3816711826 -0.0943930151,18.9058105991 -0.0943930151,18.9058105991 C -0.1213608175,21.2315838652 1.2735097744,23.8255517361 3.7141149100,24.8070428125 C 3.9112575332,22.5672698301 3.4487349984,20.0078770403 1.1973228799,18.3312708879 C 1.2685270069,18.4826557306 -1.6727511654,13.8106836556 -4.5064243827,7.6525916825 C -6.0859768756,4.2199593898 -7.8261540635,-0.4207775145 -8.7011999798,-2.8886939252 M -5.4349688005,-3.1090829315 C 2.8294264529,7.8699316302 12.8614869829,16.3623550577 24.2809629719,22.8032095738 M 24.5186904260,34.2141273744 C 23.3475879321,34.4153018553 18.4726536657,35.2347198626 14.2964098964,36.2348107351 C 12.0221759422,36.7794158052 9.0907872321,38.1373150235 6.6891313626,39.3252676394 C 5.0266747482,40.1476144488 4.4331929135,40.4779605192 3.7175381854,40.8704960915 C 3.7176015794,40.8705594855 3.7176649733,40.8706228794 3.7177283673,40.8706862734 C 1.8159087339,37.3443957031 -0.0859108995,33.8181051328 -1.9877305330,30.2918145624 C -2.0242454699,30.1693373781 -2.0725516886,30.1761839288 -2.1067844420,30.0540871083 M -2.1067844420,29.9350331993 C -6.7668891626,14.0819211717 -8.7232149468,4.0716935311 -10.3083816112,-2.8713554774 C -9.4782492743,-0.6638813021 -7.6385524745,4.1387053056 -6.0814353303,7.6780380292" /> - <path stroke="0" skew="0" data="B 27.6008011519,43.5614898312 C 27.5611165156,43.5771398250 27.6856077556,43.5107018807 27.7280110575,43.4853079055 M 27.3716100582,35.1648470092 M 24.5188806080,35.2839009183 M 24.8752816073,42.4157245437 C 21.8079888660,42.7833462789 18.5182973370,42.7399847911 15.2473197131,43.8420892688 C 12.5363138619,44.7555332387 9.9518170529,46.4453760558 7.8777686335,47.8834559898 M 4.3118568209,42.0591333624 M 1.9345822790,43.6043618145 C 3.3609470041,45.8627726292 4.7873117292,48.1211834440 6.2136764543,50.3795942587 C 6.4910251508,50.8550491670 6.7683738473,51.3305040754 7.0457225439,51.8059589838 C 7.0457859379,51.8058955898 7.0458493318,51.8058321958 7.0459127258,51.8057688018 M 9.4229970857,57.7491453382 C 9.6211032975,58.1453577619 9.8192095093,58.5415701855 10.0173157211,58.9377826091 C 10.4135281448,58.7792976396 10.8097405684,58.6208126702 11.2059529921,58.4623277007 C 17.3076243160,56.3227806132 23.4092956399,54.1832335256 29.5109669638,52.0436864380 C 29.9864218721,51.8852014685 30.4618767805,51.7267164990 30.9373316888,51.5682315295 C 30.7392254770,51.1323978636 30.5411192652,50.6965641976 30.3430130534,50.2607305316 C 29.4317244791,48.0023197169 28.5148717858,45.7945700646 27.6008011519,43.5614898312" /> - <path stroke="0" skew="0" data="B 25.0586929962,45.1476024612 C 25.7093155024,46.7741587267 26.4420259467,48.3186270539 27.1336924219,49.9041393503 M 11.4436804462,55.3718707964 C 10.6555237791,53.6766937351 9.8673671120,51.9815166738 9.0792104449,50.2863396124 C 9.2940350824,50.2199310451 9.4702169488,50.0445714056 9.6005524501,49.9639820033 C 11.4474465869,48.7280947041 14.0174099645,47.3106270615 16.1984197118,46.5757648098 C 18.7674832545,45.7101735478 21.9871036230,45.4530142351 25.0586929962,45.1476024612" /> </glyph> </collection> <collection name="full_glyph"> @@ -1103,6 +1105,7 @@ <ligature sequence="r e v e r s e _ p a t h" replacement="reverse_path"/> <ligature sequence="e x p o r t _ f o n t s" replacement="export_fonts"/> <ligature sequence="a p p l y _ s t r o k e" replacement="apply_stroke"/> + <ligature sequence="b e z i e r _ t o o l" replacement="bezier_tool"/> <ligature sequence="r i g h t _ a r r o w" replacement="right_arrow"/> <ligature sequence="b e z i e r _ l i n e" replacement="bezier_line"/> <ligature sequence="c r e a t e _ l i n e" replacement="create_line"/>