The Birdfont Source Code
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
New bezier drawing tool
--- /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 ()) {
--- 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"/>