summaryrefslogtreecommitdiffstats
path: root/src/ui/tool
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2011-04-07 23:42:04 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2011-04-07 23:42:04 +0000
commit945ce419c806c73d70203dec33ececafbe108a92 (patch)
treecfcdb59bf47e9db7f9e01f7eebb59924bdeaea94 /src/ui/tool
parentMerge from trunk (again) (diff)
parentExtensions. SVG+media fix (see Bug #400356). (diff)
downloadinkscape-945ce419c806c73d70203dec33ececafbe108a92.tar.gz
inkscape-945ce419c806c73d70203dec33ececafbe108a92.zip
Merge from trunk
(bzr r9508.1.73)
Diffstat (limited to 'src/ui/tool')
-rw-r--r--src/ui/tool/control-point-selection.cpp34
-rw-r--r--src/ui/tool/control-point-selection.h14
-rw-r--r--src/ui/tool/control-point.cpp3
-rw-r--r--src/ui/tool/control-point.h4
-rw-r--r--src/ui/tool/manipulator.h1
-rw-r--r--src/ui/tool/multi-path-manipulator.cpp81
-rw-r--r--src/ui/tool/multi-path-manipulator.h2
-rw-r--r--src/ui/tool/node-tool.cpp6
-rw-r--r--src/ui/tool/node-tool.h10
-rw-r--r--src/ui/tool/node.cpp121
-rw-r--r--src/ui/tool/node.h4
-rw-r--r--src/ui/tool/path-manipulator.cpp119
-rw-r--r--src/ui/tool/path-manipulator.h18
-rw-r--r--src/ui/tool/selector.h1
-rw-r--r--src/ui/tool/shape-record.h4
-rw-r--r--src/ui/tool/transform-handle-set.cpp113
-rw-r--r--src/ui/tool/transform-handle-set.h7
17 files changed, 363 insertions, 179 deletions
diff --git a/src/ui/tool/control-point-selection.cpp b/src/ui/tool/control-point-selection.cpp
index 91e0bc2c2..1fb98d78f 100644
--- a/src/ui/tool/control-point-selection.cpp
+++ b/src/ui/tool/control-point-selection.cpp
@@ -166,7 +166,7 @@ void ControlPointSelection::spatialGrow(SelectableControlPoint *origin, int dir)
}
/** Transform all selected control points by the given affine transformation. */
-void ControlPointSelection::transform(Geom::Matrix const &m)
+void ControlPointSelection::transform(Geom::Affine const &m)
{
for (iterator i = _points.begin(); i != _points.end(); ++i) {
SelectableControlPoint *cur = *i;
@@ -273,7 +273,7 @@ void ControlPointSelection::_pointGrabbed(SelectableControlPoint *point)
_grabbed_point = point;
_farthest_point = point;
double maxdist = 0;
- Geom::Matrix m;
+ Geom::Affine m;
m.setIdentity();
for (iterator i = _points.begin(); i != _points.end(); ++i) {
_original_positions.insert(std::make_pair(*i, (*i)->position()));
@@ -290,11 +290,11 @@ void ControlPointSelection::_pointDragged(Geom::Point &new_pos, GdkEventMotion *
{
Geom::Point abs_delta = new_pos - _original_positions[_grabbed_point];
double fdist = Geom::distance(_original_positions[_grabbed_point], _original_positions[_farthest_point]);
- if (held_alt(*event) && fdist > 0) {
+ if (held_only_alt(*event) && fdist > 0) {
// Sculpting
for (iterator i = _points.begin(); i != _points.end(); ++i) {
SelectableControlPoint *cur = (*i);
- Geom::Matrix trans;
+ Geom::Affine trans;
trans.setIdentity();
double dist = Geom::distance(_original_positions[cur], _original_positions[_grabbed_point]);
double deltafrac = 0.5 + 0.5 * cos(M_PI * dist/fdist);
@@ -323,7 +323,7 @@ void ControlPointSelection::_pointDragged(Geom::Point &new_pos, GdkEventMotion *
Geom::Point newdx = (newpx - newp) / Geom::EPSILON;
Geom::Point newdy = (newpy - newp) / Geom::EPSILON;
- Geom::Matrix itrans(newdx[Geom::X], newdx[Geom::Y], newdy[Geom::X], newdy[Geom::Y], 0, 0);
+ Geom::Affine itrans(newdx[Geom::X], newdx[Geom::Y], newdy[Geom::X], newdy[Geom::Y], 0, 0);
if (itrans.isSingular())
itrans.setIdentity();
@@ -502,7 +502,7 @@ bool ControlPointSelection::_keyboardRotate(GdkEventKey const &event, int dir)
}
// translate to origin, rotate, translate back to original position
- Geom::Matrix m = Geom::Translate(-rc)
+ Geom::Affine m = Geom::Translate(-rc)
* Geom::Rotate(angle) * Geom::Translate(rc);
transform(m);
signal_commit.emit(COMMIT_KEYBOARD_ROTATE);
@@ -538,7 +538,7 @@ bool ControlPointSelection::_keyboardScale(GdkEventKey const &event, int dir)
}
double scale = (maxext + length_change) / maxext;
- Geom::Matrix m = Geom::Translate(-center) * Geom::Scale(scale) * Geom::Translate(center);
+ Geom::Affine m = Geom::Translate(-center) * Geom::Scale(scale) * Geom::Translate(center);
transform(m);
signal_commit.emit(COMMIT_KEYBOARD_SCALE_UNIFORM);
return true;
@@ -559,7 +559,7 @@ bool ControlPointSelection::_keyboardFlip(Geom::Dim2 d)
dynamic_cast<SelectableControlPoint*>(ControlPoint::mouseovered_point);
Geom::Point center = scp ? scp->position() : _handles->rotationCenter().position();
- Geom::Matrix m = Geom::Translate(-center) * scale_transform * Geom::Translate(center);
+ Geom::Affine m = Geom::Translate(-center) * scale_transform * Geom::Translate(center);
transform(m);
signal_commit.emit(d == Geom::X ? COMMIT_FLIP_X : COMMIT_FLIP_Y);
return true;
@@ -642,6 +642,24 @@ bool ControlPointSelection::event(GdkEvent *event)
return false;
}
+std::vector<Inkscape::SnapCandidatePoint> ControlPointSelection::getOriginalPoints()
+{
+ std::vector<Inkscape::SnapCandidatePoint> points;
+ for (iterator i = _points.begin(); i != _points.end(); ++i) {
+ points.push_back(Inkscape::SnapCandidatePoint(_original_positions[*i], SNAPSOURCE_NODE_HANDLE));
+ }
+ return points;
+}
+
+void ControlPointSelection::setOriginalPoints()
+{
+ _original_positions.clear();
+ for (iterator i = _points.begin(); i != _points.end(); ++i) {
+ _original_positions.insert(std::make_pair(*i, (*i)->position()));
+ }
+}
+
+
} // namespace UI
} // namespace Inkscape
diff --git a/src/ui/tool/control-point-selection.h b/src/ui/tool/control-point-selection.h
index 3aed6ae93..7e09d50f5 100644
--- a/src/ui/tool/control-point-selection.h
+++ b/src/ui/tool/control-point-selection.h
@@ -14,17 +14,19 @@
#include <memory>
#include <boost/optional.hpp>
+#include <stddef.h>
#include <sigc++/sigc++.h>
#include <2geom/forward.h>
#include <2geom/point.h>
#include <2geom/rect.h>
-#include "display/display-forward.h"
#include "util/accumulators.h"
#include "util/unordered-containers.h"
#include "ui/tool/commit-events.h"
#include "ui/tool/manipulator.h"
+#include "snap-candidate.h"
class SPDesktop;
+struct SPCanvasGroup;
namespace Inkscape {
namespace UI {
@@ -90,7 +92,7 @@ public:
virtual bool event(GdkEvent *);
- void transform(Geom::Matrix const &m);
+ void transform(Geom::Affine const &m);
void align(Geom::Dim2 d);
void distribute(Geom::Dim2 d);
@@ -108,6 +110,10 @@ public:
sigc::signal<void> signal_update;
sigc::signal<void, SelectableControlPoint *, bool> signal_point_changed;
sigc::signal<void, CommitEvent> signal_commit;
+
+ std::vector<Inkscape::SnapCandidatePoint> getOriginalPoints();
+ void setOriginalPoints();
+
private:
// The functions below are invoked from SelectableControlPoint.
// Previously they were connected to handlers when selecting, but this
@@ -125,14 +131,14 @@ private:
bool _keyboardRotate(GdkEventKey const &, int);
bool _keyboardScale(GdkEventKey const &, int);
bool _keyboardFlip(Geom::Dim2);
- void _keyboardTransform(Geom::Matrix const &);
+ void _keyboardTransform(Geom::Affine const &);
void _commitHandlesTransform(CommitEvent ce);
double _rotationRadius(Geom::Point const &);
set_type _points;
set_type _all_points;
INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Point> _original_positions;
- INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Matrix> _last_trans;
+ INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Affine> _last_trans;
boost::optional<double> _rot_radius;
boost::optional<double> _mouseover_rot_radius;
Geom::OptRect _bounds;
diff --git a/src/ui/tool/control-point.cpp b/src/ui/tool/control-point.cpp
index d5e5b7dfe..bece1324b 100644
--- a/src/ui/tool/control-point.cpp
+++ b/src/ui/tool/control-point.cpp
@@ -14,6 +14,7 @@
#include <2geom/point.h>
#include "desktop.h"
#include "desktop-handles.h"
+#include "display/sp-canvas.h"
#include "display/snap-indicator.h"
#include "event-context.h"
#include "message-context.h"
@@ -213,7 +214,7 @@ void ControlPoint::move(Geom::Point const &pos)
/** Apply an arbitrary affine transformation to a control point. This is used
* by ControlPointSelection, and is important for things like nodes with handles.
* The default implementation simply moves the point according to the transform. */
-void ControlPoint::transform(Geom::Matrix const &m) {
+void ControlPoint::transform(Geom::Affine const &m) {
move(position() * m);
}
diff --git a/src/ui/tool/control-point.h b/src/ui/tool/control-point.h
index 4de5e5847..9f62fca42 100644
--- a/src/ui/tool/control-point.h
+++ b/src/ui/tool/control-point.h
@@ -12,12 +12,12 @@
#define SEEN_UI_TOOL_CONTROL_POINT_H
#include <boost/utility.hpp>
+#include <stddef.h>
#include <sigc++/sigc++.h>
#include <gdkmm.h>
#include <gtkmm.h>
#include <2geom/point.h>
-#include "display/display-forward.h"
#include "forward.h"
#include "util/accumulators.h"
#include "display/sodipodi-ctrl.h"
@@ -57,7 +57,7 @@ public:
operator Geom::Point const &() { return _position; }
virtual void move(Geom::Point const &pos);
virtual void setPosition(Geom::Point const &pos);
- virtual void transform(Geom::Matrix const &m);
+ virtual void transform(Geom::Affine const &m);
/// @}
/// @name Toggle the point's visibility
diff --git a/src/ui/tool/manipulator.h b/src/ui/tool/manipulator.h
index fd24e7b61..6866ec9dd 100644
--- a/src/ui/tool/manipulator.h
+++ b/src/ui/tool/manipulator.h
@@ -13,6 +13,7 @@
#include <set>
#include <map>
+#include <stddef.h>
#include <sigc++/sigc++.h>
#include <glib.h>
#include <gdk/gdk.h>
diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp
index ef1c764bb..082ac194b 100644
--- a/src/ui/tool/multi-path-manipulator.cpp
+++ b/src/ui/tool/multi-path-manipulator.cpp
@@ -210,7 +210,78 @@ void MultiPathManipulator::selectSubpaths()
void MultiPathManipulator::shiftSelection(int dir)
{
- invokeForAll(&PathManipulator::shiftSelection, dir);
+ if (empty()) return;
+
+ // 1. find last selected node
+ // 2. select the next node; if the last node or nothing is selected,
+ // select first node
+ MapType::iterator last_i;
+ SubpathList::iterator last_j;
+ NodeList::iterator last_k;
+ bool anything_found = false;
+
+ for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) {
+ SubpathList &sp = i->second->subpathList();
+ for (SubpathList::iterator j = sp.begin(); j != sp.end(); ++j) {
+ for (NodeList::iterator k = (*j)->begin(); k != (*j)->end(); ++k) {
+ if (k->selected()) {
+ last_i = i;
+ last_j = j;
+ last_k = k;
+ anything_found = true;
+ // when tabbing backwards, we want the first node
+ if (dir == -1) goto exit_loop;
+ }
+ }
+ }
+ }
+ exit_loop:
+
+ // NOTE: we should not assume the _selection contains only nodes
+ // in future it might also contain handles and other types of control points
+ // this is why we use a flag instead in the loop above, instead of calling
+ // selection.empty()
+ if (!anything_found) {
+ // select first / last node
+ // this should never fail because there must be at least 1 non-empty manipulator
+ if (dir == 1) {
+ _selection.insert((*_mmap.begin()->second->subpathList().begin())->begin().ptr());
+ } else {
+ _selection.insert((--(*--(--_mmap.end())->second->subpathList().end())->end()).ptr());
+ }
+ return;
+ }
+
+ // three levels deep - w00t!
+ if (dir == 1) {
+ if (++last_k == (*last_j)->end()) {
+ // here, last_k points to the node to be selected
+ ++last_j;
+ if (last_j == last_i->second->subpathList().end()) {
+ ++last_i;
+ if (last_i == _mmap.end()) {
+ last_i = _mmap.begin();
+ }
+ last_j = last_i->second->subpathList().begin();
+ }
+ last_k = (*last_j)->begin();
+ }
+ } else {
+ if (!last_k || last_k == (*last_j)->begin()) {
+ if (last_j == last_i->second->subpathList().begin()) {
+ if (last_i == _mmap.begin()) {
+ last_i = _mmap.end();
+ }
+ --last_i;
+ last_j = last_i->second->subpathList().end();
+ }
+ --last_j;
+ last_k = (*last_j)->end();
+ }
+ --last_k;
+ }
+ _selection.clear();
+ _selection.insert(last_k.ptr());
}
void MultiPathManipulator::invertSelectionInSubpaths()
@@ -695,6 +766,14 @@ void MultiPathManipulator::_commit(CommitEvent cps)
reason = _("Scale nodes vertically");
key = "node:scale:y";
break;
+ case COMMIT_MOUSE_SKEW_X:
+ reason = _("Skew nodes horizontally");
+ key = "node:skew:x";
+ break;
+ case COMMIT_MOUSE_SKEW_Y:
+ reason = _("Skew nodes vertically");
+ key = "node:skew:y";
+ break;
case COMMIT_FLIP_X:
reason = _("Flip nodes horizontally");
break;
diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h
index ddb74c1bc..c25719790 100644
--- a/src/ui/tool/multi-path-manipulator.h
+++ b/src/ui/tool/multi-path-manipulator.h
@@ -11,8 +11,8 @@
#ifndef SEEN_UI_TOOL_MULTI_PATH_MANIPULATOR_H
#define SEEN_UI_TOOL_MULTI_PATH_MANIPULATOR_H
+#include <stddef.h>
#include <sigc++/connection.h>
-#include "display/display-forward.h"
#include "forward.h"
#include "ui/tool/commit-events.h"
#include "ui/tool/manipulator.h"
diff --git a/src/ui/tool/node-tool.cpp b/src/ui/tool/node-tool.cpp
index 8661e7946..f83f8c473 100644
--- a/src/ui/tool/node-tool.cpp
+++ b/src/ui/tool/node-tool.cpp
@@ -13,6 +13,7 @@
#include <glib/gi18n.h>
#include "desktop.h"
#include "desktop-handles.h"
+#include "display/sp-canvas-group.h"
#include "display/canvas-bpath.h"
#include "display/curve.h"
#include "display/sp-canvas.h"
@@ -479,10 +480,11 @@ gint ink_node_tool_root_handler(SPEventContext *event_context, GdkEvent *event)
nt->flash_tempitem = NULL;
nt->flashed_item = NULL;
}
- if (!SP_IS_PATH(over_item)) break; // for now, handle only paths
+ if (!SP_IS_SHAPE(over_item)) break; // for now, handle only shapes
nt->flashed_item = over_item;
- SPCurve *c = sp_path_get_curve_for_edit(SP_PATH(over_item));
+ SPCurve *c = SP_SHAPE(over_item)->getCurveBeforeLPE();
+ if (!c) break; // break out when curve doesn't exist
c->transform(over_item->i2d_affine());
SPCanvasItem *flash = sp_canvas_bpath_new(sp_desktop_tempgroup(desktop), c);
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(flash),
diff --git a/src/ui/tool/node-tool.h b/src/ui/tool/node-tool.h
index 4d38e69e2..d005a0bdf 100644
--- a/src/ui/tool/node-tool.h
+++ b/src/ui/tool/node-tool.h
@@ -14,10 +14,10 @@
#include <memory>
#include <boost/ptr_container/ptr_map.hpp>
#include <glib.h>
+#include <stddef.h>
#include <sigc++/sigc++.h>
#include "event-context.h"
#include "forward.h"
-#include "display/display-forward.h"
#include "ui/tool/node-types.h"
#define INK_TYPE_NODE_TOOL (ink_node_tool_get_type ())
@@ -30,13 +30,17 @@ class InkNodeTool;
class InkNodeToolClass;
namespace Inkscape {
+
+namespace Display {
+class TemporaryItem;
+} // namespace Display
namespace UI {
class MultiPathManipulator;
class ControlPointSelection;
class Selector;
struct PathSharedData;
-}
-}
+} // namespace UI
+} // namespace Inkscape
typedef std::auto_ptr<Inkscape::UI::MultiPathManipulator> MultiPathPtr;
typedef std::auto_ptr<Inkscape::UI::ControlPointSelection> CSelPtr;
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index 12d04dd2b..8e3da266b 100644
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
@@ -113,12 +113,29 @@ void Handle::move(Geom::Point const &new_pos)
Handle *towards_second = node_towards ? node_towards->handleToward(_parent) : NULL;
if (Geom::are_near(new_pos, _parent->position())) {
- // The handle becomes degenerate. If the segment between it and the node
+ // The handle becomes degenerate.
+ // Adjust node type as necessary.
+ if (other->isDegenerate()) {
+ // If both handles become degenerate, convert to parent cusp node
+ _parent->setType(NODE_CUSP, false);
+ } else {
+ // Only 1 handle becomes degenerate
+ switch (_parent->type()) {
+ case NODE_AUTO:
+ case NODE_SYMMETRIC:
+ _parent->setType(NODE_SMOOTH, false);
+ break;
+ default:
+ // do nothing for other node types
+ break;
+ }
+ }
+ // If the segment between the handle and the node
// in its direction becomes linear and there are smooth nodes
// at its ends, make their handles colinear with the segment
- if (towards && towards->isDegenerate()) {
+ if (towards && towards_second->isDegenerate()) {
if (node_towards->type() == NODE_SMOOTH) {
- towards_second->setDirection(*_parent, *node_towards);
+ towards->setDirection(*_parent, *node_towards);
}
if (_parent->type() == NODE_SMOOTH) {
other->setDirection(*node_towards, *_parent);
@@ -160,6 +177,7 @@ void Handle::move(Geom::Point const &new_pos)
void Handle::setPosition(Geom::Point const &p)
{
+ Geom::Point old_pos = position();
ControlPoint::setPosition(p);
sp_ctrlline_set_coords(SP_CTRLLINE(_handle_line), _parent->position(), position());
@@ -167,15 +185,12 @@ void Handle::setPosition(Geom::Point const &p)
if (Geom::are_near(position(), _parent->position()))
_degenerate = true;
else _degenerate = false;
+
if (_parent->_handles_shown && _parent->visible() && !_degenerate) {
setVisible(true);
} else {
setVisible(false);
}
- // If both handles become degenerate, convert to parent cusp node
- if (_parent->isDegenerate()) {
- _parent->setType(NODE_CUSP, false);
- }
}
void Handle::setLength(double len)
@@ -187,7 +202,7 @@ void Handle::setLength(double len)
void Handle::retract()
{
- setPosition(_parent->position());
+ move(_parent->position());
}
void Handle::setDirection(Geom::Point const &from, Geom::Point const &to)
@@ -212,6 +227,35 @@ char const *Handle::handle_type_to_localized_string(NodeType type)
}
}
+bool Handle::_eventHandler(GdkEvent *event)
+{
+ switch (event->type)
+ {
+ case GDK_KEY_PRESS:
+ switch (shortcut_key(event->key))
+ {
+ case GDK_s:
+ case GDK_S:
+ if (held_only_shift(event->key) && _parent->_type == NODE_CUSP) {
+ // when Shift+S is pressed when hovering over a handle belonging to a cusp node,
+ // hold this handle in place; otherwise process normally
+ // this handle is guaranteed not to be degenerate
+ other()->move(_parent->position() - (position() - _parent->position()));
+ _parent->setType(NODE_SMOOTH, false);
+ _parent->_pm().update(); // magic triple combo to add undo event
+ _parent->_pm().writeXML();
+ _parent->_pm()._commit(_("Change node type"));
+ return true;
+ }
+ break;
+ default: break;
+ }
+ default: break;
+ }
+
+ return ControlPoint::_eventHandler(event);
+}
+
bool Handle::grabbed(GdkEventMotion *)
{
_saved_other_pos = other()->position();
@@ -226,6 +270,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event)
Geom::Point origin = _last_drag_origin();
SnapManager &sm = _desktop->namedview->snap_manager;
bool snap = sm.someSnapperMightSnap();
+ boost::optional<Inkscape::Snapper::SnapConstraint> ctrl_constraint;
// with Alt, preserve length
if (held_alt(*event)) {
@@ -241,16 +286,23 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event)
// note: if snapping to the original position is only desired in the original
// direction of the handle, change to Ray instead of Line
Geom::Line original_line(parent_pos, origin);
+ Geom::Line perp_line(parent_pos, parent_pos + Geom::rot90(origin - parent_pos));
Geom::Point snap_pos = parent_pos + Geom::constrain_angle(
Geom::Point(0,0), new_pos - parent_pos, snaps, Geom::Point(1,0));
Geom::Point orig_pos = original_line.pointAt(original_line.nearestPoint(new_pos));
+ Geom::Point perp_pos = perp_line.pointAt(perp_line.nearestPoint(new_pos));
- if (Geom::distance(snap_pos, new_pos) < Geom::distance(orig_pos, new_pos)) {
- new_pos = snap_pos;
- } else {
- new_pos = orig_pos;
+ Geom::Point result = snap_pos;
+ ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - snap_pos);
+ if (Geom::distance(orig_pos, new_pos) < Geom::distance(result, new_pos)) {
+ result = orig_pos;
+ ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - orig_pos);
}
- snap = false;
+ if (Geom::distance(perp_pos, new_pos) < Geom::distance(result, new_pos)) {
+ result = perp_pos;
+ ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - perp_pos);
+ }
+ new_pos = result;
}
std::vector<Inkscape::SnapCandidatePoint> unselected;
@@ -264,13 +316,20 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event)
}
sm.setupIgnoreSelection(_desktop, true, &unselected);
- Node *node_away = (this == &_parent->_front ? _parent->_prev() : _parent->_next());
+ Node *node_away = _parent->nodeAwayFrom(this);
if (_parent->type() == NODE_SMOOTH && Node::_is_line_segment(_parent, node_away)) {
Inkscape::Snapper::SnapConstraint cl(_parent->position(),
_parent->position() - node_away->position());
Inkscape::SnappedPoint p;
p = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, SNAPSOURCE_NODE_HANDLE), cl);
new_pos = p.getPoint();
+ } else if (ctrl_constraint) {
+ // NOTE: this is subtly wrong.
+ // We should get all possible constraints and snap along them using
+ // multipleConstrainedSnaps, instead of first snapping to angle and the to objects
+ Inkscape::SnappedPoint p;
+ p = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, SNAPSOURCE_NODE_HANDLE), *ctrl_constraint);
+ new_pos = p.getPoint();
} else {
sm.freeSnapReturnByRef(new_pos, SNAPSOURCE_NODE_HANDLE);
}
@@ -455,7 +514,7 @@ void Node::move(Geom::Point const &new_pos)
_fixNeighbors(old_pos, new_pos);
}
-void Node::transform(Geom::Matrix const &m)
+void Node::transform(Geom::Affine const &m)
{
Geom::Point old_pos = position();
setPosition(position() * m);
@@ -770,26 +829,6 @@ bool Node::_eventHandler(GdkEvent *event)
return ControlPoint::_eventHandler(event);
}
-// TODO Move this to 2Geom!
-static double bezier_length (Geom::Point a0, Geom::Point a1, Geom::Point a2, Geom::Point a3)
-{
- double lower = Geom::distance(a0, a3);
- double upper = Geom::distance(a0, a1) + Geom::distance(a1, a2) + Geom::distance(a2, a3);
-
- if (upper - lower < Geom::EPSILON) return (lower + upper)/2;
-
- Geom::Point // Casteljau subdivision
- b0 = a0,
- c0 = a3,
- b1 = 0.5*(a0 + a1),
- t0 = 0.5*(a1 + a2),
- c1 = 0.5*(a2 + a3),
- b2 = 0.5*(b1 + t0),
- c2 = 0.5*(t0 + c1),
- b3 = 0.5*(b2 + c2); // == c3
- return bezier_length(b0, b1, b2, b3) + bezier_length(b3, c2, c1, c0);
-}
-
/** Select or deselect a node in this node's subpath based on its path distance from this node.
* @param dir If negative, shrink selection by one node; if positive, grow by one node */
void Node::_linearGrow(int dir)
@@ -816,7 +855,7 @@ void Node::_linearGrow(int dir)
// find first unselected nodes on both sides
while (fwd && fwd->selected()) {
NodeList::iterator n = fwd.next();
- distance_front += bezier_length(*fwd, fwd->_front, n->_back, *n);
+ distance_front += Geom::bezier_length(*fwd, fwd->_front, n->_back, *n);
fwd = n;
if (fwd == this_iter)
// there is no unselected node in this cyclic subpath
@@ -827,7 +866,7 @@ void Node::_linearGrow(int dir)
// so we are guaranteed to stop.
while (rev && rev->selected()) {
NodeList::iterator p = rev.prev();
- distance_back += bezier_length(*rev, rev->_back, p->_front, *p);
+ distance_back += Geom::bezier_length(*rev, rev->_back, p->_front, *p);
rev = p;
}
@@ -858,7 +897,7 @@ void Node::_linearGrow(int dir)
last_distance_front = distance_front;
}
NodeList::iterator n = fwd.next();
- if (n) distance_front += bezier_length(*fwd, fwd->_front, n->_back, *n);
+ if (n) distance_front += Geom::bezier_length(*fwd, fwd->_front, n->_back, *n);
fwd = n;
} else if (rev && (!fwd || distance_front > distance_back)) {
if (rev->selected()) {
@@ -866,7 +905,7 @@ void Node::_linearGrow(int dir)
last_distance_back = distance_back;
}
NodeList::iterator p = rev.prev();
- if (p) distance_back += bezier_length(*rev, rev->_back, p->_front, *p);
+ if (p) distance_back += Geom::bezier_length(*rev, rev->_back, p->_front, *p);
rev = p;
}
// Check whether we walked the entire cyclic subpath.
@@ -876,8 +915,8 @@ void Node::_linearGrow(int dir)
if (fwd && fwd == rev) {
if (!fwd->selected()) break;
NodeList::iterator fwdp = fwd.prev(), revn = rev.next();
- double df = distance_front + bezier_length(*fwdp, fwdp->_front, fwd->_back, *fwd);
- double db = distance_back + bezier_length(*revn, revn->_back, rev->_front, *rev);
+ double df = distance_front + Geom::bezier_length(*fwdp, fwdp->_front, fwd->_back, *fwd);
+ double db = distance_back + Geom::bezier_length(*revn, revn->_back, rev->_front, *rev);
if (df > db) {
last_fwd = fwd;
last_distance_front = df;
diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h
index 0194f5053..b7145790b 100644
--- a/src/ui/tool/node.h
+++ b/src/ui/tool/node.h
@@ -15,6 +15,7 @@
#include <iterator>
#include <iosfwd>
#include <stdexcept>
+#include <cstddef>
#include <tr1/functional>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
@@ -102,6 +103,7 @@ public:
protected:
Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent);
+ virtual bool _eventHandler(GdkEvent *event);
virtual void dragged(Geom::Point &, GdkEventMotion *);
virtual bool grabbed(GdkEventMotion *);
virtual void ungrabbed(GdkEventButton *);
@@ -127,7 +129,7 @@ class Node : ListNode, public SelectableControlPoint {
public:
Node(NodeSharedData const &data, Geom::Point const &pos);
virtual void move(Geom::Point const &p);
- virtual void transform(Geom::Matrix const &m);
+ virtual void transform(Geom::Affine const &m);
virtual Geom::Rect bounds();
NodeType type() { return _type; }
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp
index 5ae9c4137..7c2013872 100644
--- a/src/ui/tool/path-manipulator.cpp
+++ b/src/ui/tool/path-manipulator.cpp
@@ -102,14 +102,14 @@ private:
void build_segment(Geom::PathBuilder &, Node *, Node *);
PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path,
- Geom::Matrix const &et, guint32 outline_color, Glib::ustring lpe_key)
+ Geom::Affine const &et, guint32 outline_color, Glib::ustring lpe_key)
: PointManipulator(mpm._path_data.node_data.desktop, *mpm._path_data.node_data.selection)
, _subpaths(*this)
, _multi_path_manipulator(mpm)
, _path(path)
, _spcurve(new SPCurve())
, _dragpoint(new CurveDragPoint(*this))
- , /* XML Tree being used here directly while it shouldn't be*/_observer(new PathManipulatorObserver(this, SP_OBJECT(path)->getRepr()))
+ , /* XML Tree being used here directly while it shouldn't be*/_observer(new PathManipulatorObserver(this, path->getRepr()))
, _edit_transform(et)
, _num_selected(0)
, _show_handles(true)
@@ -191,7 +191,7 @@ void PathManipulator::writeXML()
if (!_path) return;
_observer->block();
if (!empty()) {
- SP_OBJECT(_path)->updateRepr();
+ _path->updateRepr();
_getXMLNode()->setAttribute(_nodetypesKey().data(), _createTypeString().data());
} else {
// this manipulator will have to be destroyed right after this call
@@ -215,7 +215,7 @@ void PathManipulator::clear()
/** Select all nodes in subpaths that have something selected. */
void PathManipulator::selectSubpaths()
{
- for (std::list<SubpathPtr>::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
+ for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
NodeList::iterator sp_start = (*i)->begin(), sp_end = (*i)->end();
for (NodeList::iterator j = sp_start; j != sp_end; ++j) {
if (j->selected()) {
@@ -229,63 +229,6 @@ void PathManipulator::selectSubpaths()
}
}
-/** Move the selection forward or backward by one node in each subpath, based on the sign
- * of the parameter. */
-void PathManipulator::shiftSelection(int dir)
-{
- if (dir == 0) return;
- if (_num_selected == 0) {
- // select the first node of the path.
- SubpathList::iterator s = _subpaths.begin();
- if (s == _subpaths.end()) return;
- NodeList::iterator n = (*s)->begin();
- if (n != (*s)->end())
- _selection.insert(n.ptr());
- return;
- }
- // We cannot do any tricks here, like iterating in different directions based on
- // the sign and only setting the selection of nodes behind us, because it would break
- // for closed paths.
- for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
- std::deque<bool> sels; // I hope this is specialized for bools!
- unsigned num = 0;
-
- for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
- sels.push_back(j->selected());
- _selection.erase(j.ptr());
- ++num;
- }
- if (num == 0) continue; // should never happen! zero-node subpaths are not allowed
-
- num = 0;
- // In closed subpath, shift the selection cyclically. In an open one,
- // let the selection 'slide into nothing' at ends.
- if (dir > 0) {
- if ((*i)->closed()) {
- bool last = sels.back();
- sels.pop_back();
- sels.push_front(last);
- } else {
- sels.push_front(false);
- }
- } else {
- if ((*i)->closed()) {
- bool first = sels.front();
- sels.pop_front();
- sels.push_back(first);
- } else {
- sels.push_back(false);
- num = 1;
- }
- }
-
- for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
- if (sels[num]) _selection.insert(j.ptr());
- ++num;
- }
- }
-}
-
/** Invert selection in the selected subpaths. */
void PathManipulator::invertSelectionInSubpaths()
{
@@ -332,22 +275,31 @@ void PathManipulator::duplicateNodes()
NodeList::iterator k = j.next();
Node *n = new Node(_multi_path_manipulator._path_data.node_data, *j);
- // Move the new node to the bottom of the Z-order. This way you can drag all
- // nodes that were selected before this operation without deselecting
- // everything because there is a new node above.
- n->sink();
+ if (k) {
+ // Move the new node to the bottom of the Z-order. This way you can drag all
+ // nodes that were selected before this operation without deselecting
+ // everything because there is a new node above.
+ n->sink();
+ }
n->front()->setPosition(*j->front());
j->front()->retract();
j->setType(NODE_CUSP, false);
(*i)->insert(k, n);
- // We need to manually call the selection change callback to refresh
- // the handle display correctly.
- // This call changes num_selected, but we call this once for a selected node
- // and once for an unselected node, so in the end the number stays correct.
- _selectionChanged(j.ptr(), true);
- _selectionChanged(n, false);
+ if (k) {
+ // We need to manually call the selection change callback to refresh
+ // the handle display correctly.
+ // This call changes num_selected, but we call this once for a selected node
+ // and once for an unselected node, so in the end the number stays correct.
+ _selectionChanged(j.ptr(), true);
+ _selectionChanged(n, false);
+ } else {
+ // select the new end node instead of the node just before it
+ _selection.erase(j.ptr());
+ _selection.insert(n);
+ break; // this was the end node, nothing more to do
+ }
}
}
}
@@ -895,9 +847,9 @@ void PathManipulator::setLiveObjects(bool set)
_live_objects = set;
}
-void PathManipulator::setControlsTransform(Geom::Matrix const &tnew)
+void PathManipulator::setControlsTransform(Geom::Affine const &tnew)
{
- Geom::Matrix delta = _i2d_transform.inverse() * _edit_transform.inverse() * tnew * _i2d_transform;
+ Geom::Affine delta = _i2d_transform.inverse() * _edit_transform.inverse() * tnew * _i2d_transform;
_edit_transform = tnew;
for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
@@ -1023,7 +975,7 @@ void PathManipulator::_externalChange(unsigned type)
_updateOutline();
} break;
case PATH_CHANGE_TRANSFORM: {
- Geom::Matrix i2d_change = _d2i_transform;
+ Geom::Affine i2d_change = _d2i_transform;
_i2d_transform = SP_ITEM(_path)->i2d_affine();
_d2i_transform = _i2d_transform.inverse();
i2d_change *= _i2d_transform;
@@ -1087,13 +1039,14 @@ void PathManipulator::_createControlPointsFromGeometry()
subpath->push_back(current_node);
}
// if this is a bezier segment, move handles appropriately
- if (Geom::CubicBezier const *cubic_bezier =
- dynamic_cast<Geom::CubicBezier const*>(&*cit))
+ // TODO: I don't know why the dynamic cast below doesn't want to work
+ // when I replace BezierCurve with CubicBezier. Might be a bug
+ // somewhere in pathv_to_linear_and_cubic_beziers
+ Geom::BezierCurve const *bezier = dynamic_cast<Geom::BezierCurve const*>(&*cit);
+ if (bezier && bezier->order() == 3)
{
- std::vector<Geom::Point> points = cubic_bezier->points();
-
- previous_node->front()->setPosition(points[1]);
- current_node ->back() ->setPosition(points[2]);
+ previous_node->front()->setPosition((*bezier)[1]);
+ current_node ->back() ->setPosition((*bezier)[2]);
}
previous_node = current_node;
}
@@ -1436,7 +1389,7 @@ void PathManipulator::_commit(Glib::ustring const &annotation, gchar const *key)
* point of the path. */
void PathManipulator::_updateDragPoint(Geom::Point const &evp)
{
- Geom::Matrix to_desktop = _edit_transform * _i2d_transform;
+ Geom::Affine to_desktop = _edit_transform * _i2d_transform;
Geom::PathVector pv = _spcurve->get_pathvector();
boost::optional<Geom::PathVectorPosition> pvp
= Geom::nearestPoint(pv, _desktop->w2d(evp) * to_desktop.inverse());
@@ -1477,8 +1430,8 @@ double PathManipulator::_getStrokeTolerance()
* drag tolerance setting. */
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
double ret = prefs->getIntLimited("/options/dragtolerance/value", 2, 0, 100);
- if (_path && SP_OBJECT_STYLE(_path) && !SP_OBJECT_STYLE(_path)->stroke.isNone()) {
- ret += SP_OBJECT_STYLE(_path)->stroke_width.computed * 0.5
+ if (_path && _path->style && !_path->style->stroke.isNone()) {
+ ret += _path->style->stroke_width.computed * 0.5
* (_edit_transform * _i2d_transform).descrim() // scale to desktop coords
* _desktop->current_zoom(); // == _d2w.descrim() - scale to window coords
}
diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h
index 87b88fc77..27a83f06b 100644
--- a/src/ui/tool/path-manipulator.h
+++ b/src/ui/tool/path-manipulator.h
@@ -14,15 +14,15 @@
#include <string>
#include <memory>
#include <2geom/pathvector.h>
-#include <2geom/matrix.h>
+#include <2geom/affine.h>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
-#include "display/display-forward.h"
#include "forward.h"
#include "ui/tool/node.h"
#include "ui/tool/manipulator.h"
struct SPCanvasItem;
+struct SPCurve;
namespace Inkscape {
namespace XML { class Node; }
@@ -53,7 +53,7 @@ class PathManipulator : public PointManipulator {
public:
typedef SPPath *ItemType;
- PathManipulator(MultiPathManipulator &mpm, SPPath *path, Geom::Matrix const &edit_trans,
+ PathManipulator(MultiPathManipulator &mpm, SPPath *path, Geom::Affine const &edit_trans,
guint32 outline_color, Glib::ustring lpe_key);
~PathManipulator();
virtual bool event(GdkEvent *);
@@ -65,7 +65,6 @@ public:
SPPath *item() { return _path; }
void selectSubpaths();
- void shiftSelection(int dir);
void invertSelectionInSubpaths();
void insertNodes();
@@ -86,7 +85,7 @@ public:
void showPathDirection(bool show);
void setLiveOutline(bool set);
void setLiveObjects(bool set);
- void setControlsTransform(Geom::Matrix const &);
+ void setControlsTransform(Geom::Affine const &);
void hideDragPoint();
MultiPathManipulator &mpm() { return _multi_path_manipulator; }
@@ -94,6 +93,9 @@ public:
NodeList::iterator extremeNode(NodeList::iterator origin, bool search_selected,
bool search_unselected, bool closest);
+ // this is necessary for Tab-selection in MultiPathManipulator
+ SubpathList &subpathList() { return _subpaths; }
+
static bool is_item_type(void *item);
private:
typedef NodeList Subpath;
@@ -132,9 +134,9 @@ private:
SPCanvasItem *_outline;
CurveDragPoint *_dragpoint; // an invisible control point hoverng over curve
PathManipulatorObserver *_observer;
- Geom::Matrix _d2i_transform; ///< desktop-to-item transform
- Geom::Matrix _i2d_transform; ///< item-to-desktop transform, inverse of _d2i_transform
- Geom::Matrix _edit_transform; ///< additional transform to apply to editing controls
+ Geom::Affine _d2i_transform; ///< desktop-to-item transform
+ Geom::Affine _i2d_transform; ///< item-to-desktop transform, inverse of _d2i_transform
+ Geom::Affine _edit_transform; ///< additional transform to apply to editing controls
unsigned _num_selected; ///< number of selected nodes
bool _show_handles;
bool _show_outline;
diff --git a/src/ui/tool/selector.h b/src/ui/tool/selector.h
index e61668d9e..05d72c208 100644
--- a/src/ui/tool/selector.h
+++ b/src/ui/tool/selector.h
@@ -14,7 +14,6 @@
#include <memory>
#include <gdk/gdk.h>
#include <2geom/rect.h>
-#include "display/display-forward.h"
#include "ui/tool/manipulator.h"
class SPDesktop;
diff --git a/src/ui/tool/shape-record.h b/src/ui/tool/shape-record.h
index 893231404..646e6f4f6 100644
--- a/src/ui/tool/shape-record.h
+++ b/src/ui/tool/shape-record.h
@@ -14,7 +14,7 @@
#include <glibmm/ustring.h>
#include <boost/operators.hpp>
-#include <2geom/matrix.h>
+#include <2geom/affine.h>
class SPItem;
namespace Inkscape {
@@ -32,7 +32,7 @@ struct ShapeRecord :
public boost::totally_ordered<ShapeRecord>
{
SPItem *item; // SP node for the edited shape
- Geom::Matrix edit_transform; // how to transform controls - used for clipping paths and masks
+ Geom::Affine edit_transform; // how to transform controls - used for clipping paths and masks
ShapeRole role;
Glib::ustring lpe_key; // name of LPE shape param being edited
diff --git a/src/ui/tool/transform-handle-set.cpp b/src/ui/tool/transform-handle-set.cpp
index ef93a3767..26263c26b 100644
--- a/src/ui/tool/transform-handle-set.cpp
+++ b/src/ui/tool/transform-handle-set.cpp
@@ -18,10 +18,16 @@
#include "desktop-handles.h"
#include "display/sodipodi-ctrlrect.h"
#include "preferences.h"
+#include "snap.h"
+#include "snap-candidate.h"
+#include "sp-namedview.h"
#include "ui/tool/commit-events.h"
#include "ui/tool/control-point.h"
+#include "ui/tool/control-point-selection.h"
+#include "ui/tool/selectable-control-point.h"
#include "ui/tool/event-utils.h"
#include "ui/tool/transform-handle-set.h"
+#include "ui/tool/node-tool.h"
// FIXME BRAIN DAMAGE WARNING: this is a global variable in select-context.cpp
// It should be moved to a header
@@ -88,12 +94,14 @@ public:
protected:
virtual void startTransform() {}
virtual void endTransform() {}
- virtual Geom::Matrix computeTransform(Geom::Point const &pos, GdkEventMotion *event) = 0;
+ virtual Geom::Affine computeTransform(Geom::Point const &pos, GdkEventMotion *event) = 0;
virtual CommitEvent getCommitEvent() = 0;
- Geom::Matrix _last_transform;
+ Geom::Affine _last_transform;
Geom::Point _origin;
TransformHandleSet &_th;
+ std::vector<Inkscape::SnapCandidatePoint> _snap_points;
+
private:
virtual bool grabbed(GdkEventMotion *) {
_origin = position();
@@ -103,19 +111,34 @@ private:
_th._setActiveHandle(this);
_cset = &invisible_cset;
_setState(_state);
+
+ // Collect the snap-candidates, one for each selected node. These will be stored in the _snap_points vector.
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SnapManager &m = desktop->namedview->snap_manager;
+ InkNodeTool *nt = INK_NODE_TOOL(_desktop->event_context);
+ ControlPointSelection *selection = nt->_selected_nodes.get();
+
+ _snap_points = selection->getOriginalPoints();
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ if (prefs->getBool("/options/snapclosestonly/value", false)) {
+ m.keepClosestPointOnly(_snap_points, _origin);
+ }
+
return false;
}
virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event)
{
- Geom::Matrix t = computeTransform(new_pos, event);
+ Geom::Affine t = computeTransform(new_pos, event);
// protect against degeneracies
if (t.isSingular()) return;
- Geom::Matrix incr = _last_transform.inverse() * t;
+ Geom::Affine incr = _last_transform.inverse() * t;
if (incr.isSingular()) return;
_th.signal_transform.emit(incr);
_last_transform = t;
}
virtual void ungrabbed(GdkEventButton *) {
+ _snap_points.clear();
_th._clearActiveHandle();
_cset = &thandle_cset;
_setState(_state);
@@ -175,26 +198,66 @@ protected:
_sc_center = _th.rotationCenter();
_sc_opposite = _th.bounds().corner(_corner + 2);
_last_scale_x = _last_scale_y = 1.0;
+ InkNodeTool *nt = INK_NODE_TOOL(_desktop->event_context);
+ ControlPointSelection *selection = nt->_selected_nodes.get();
+ selection->setOriginalPoints();
}
- virtual Geom::Matrix computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) {
+ virtual Geom::Affine computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) {
Geom::Point scc = held_shift(*event) ? _sc_center : _sc_opposite;
Geom::Point vold = _origin - scc, vnew = new_pos - scc;
+
// avoid exploding the selection
if (Geom::are_near(vold[Geom::X], 0) || Geom::are_near(vold[Geom::Y], 0))
return Geom::identity();
double scale[2] = { vnew[Geom::X] / vold[Geom::X], vnew[Geom::Y] / vold[Geom::Y] };
+
if (held_alt(*event)) {
for (unsigned i = 0; i < 2; ++i) {
if (scale[i] >= 1.0) scale[i] = round(scale[i]);
else scale[i] = 1.0 / round(1.0 / scale[i]);
}
- } else if (held_control(*event)) {
- scale[0] = scale[1] = std::min(scale[0], scale[1]);
+ } else {
+ //SPDesktop *desktop = _th._desktop; // Won't work as _desktop is protected
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SnapManager &m = desktop->namedview->snap_manager;
+
+ // The lines below have been copied from Handle::dragged() in node.cpp, and need to be
+ // activated if we want to snap to unselected (i.e. stationary) nodes and stationary pieces of paths of the
+ // path that's currently being edited
+ /*
+ std::vector<Inkscape::SnapCandidatePoint> unselected;
+ typedef ControlPointSelection::Set Set;
+ Set &nodes = _parent->_selection.allPoints();
+ for (Set::iterator i = nodes.begin(); i != nodes.end(); ++i) {
+ Node *n = static_cast<Node*>(*i);
+ Inkscape::SnapCandidatePoint p(n->position(), n->_snapSourceType(), n->_snapTargetType());
+ unselected.push_back(p);
+ }
+ m.setupIgnoreSelection(_desktop, true, &unselected);
+ */
+
+ m.setupIgnoreSelection(_desktop);
+
+ Inkscape::SnappedPoint sp;
+ if (held_control(*event)) {
+ scale[0] = scale[1] = std::min(scale[0], scale[1]);
+ sp = m.constrainedSnapScale(_snap_points, _origin, Geom::Scale(scale[0], scale[1]), scc);
+ } else {
+ sp = m.freeSnapScale(_snap_points, _origin, Geom::Scale(scale[0], scale[1]), scc);
+ }
+ m.unSetup();
+
+ if (sp.getSnapped()) {
+ Geom::Point result = sp.getTransformation();
+ scale[0] = result[0];
+ scale[1] = result[1];
+ }
}
+
_last_scale_x = scale[0];
_last_scale_y = scale[1];
- Geom::Matrix t = Geom::Translate(-scc)
+ Geom::Affine t = Geom::Translate(-scc)
* Geom::Scale(scale[0], scale[1])
* Geom::Translate(scc);
return t;
@@ -231,7 +294,7 @@ protected:
_sc_opposite = Geom::middle_point(b.corner(_side + 2), b.corner(_side + 3));
_last_scale_x = _last_scale_y = 1.0;
}
- virtual Geom::Matrix computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) {
+ virtual Geom::Affine computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) {
Geom::Point scc = held_shift(*event) ? _sc_center : _sc_opposite;
Geom::Point vs;
Geom::Dim2 d1 = static_cast<Geom::Dim2>((_side + 1) % 2);
@@ -250,7 +313,7 @@ protected:
_last_scale_x = vs[Geom::X];
_last_scale_y = vs[Geom::Y];
- Geom::Matrix t = Geom::Translate(-scc)
+ Geom::Affine t = Geom::Translate(-scc)
* Geom::Scale(vs)
* Geom::Translate(scc);
return t;
@@ -288,7 +351,7 @@ protected:
_last_angle = 0;
}
- virtual Geom::Matrix computeTransform(Geom::Point const &new_pos, GdkEventMotion *event)
+ virtual Geom::Affine computeTransform(Geom::Point const &new_pos, GdkEventMotion *event)
{
Geom::Point rotc = held_shift(*event) ? _rot_opposite : _rot_center;
double angle = Geom::angle_between(_origin - rotc, new_pos - rotc);
@@ -296,7 +359,7 @@ protected:
angle = snap_angle(angle);
}
_last_angle = angle;
- Geom::Matrix t = Geom::Translate(-rotc)
+ Geom::Affine t = Geom::Translate(-rotc)
* Geom::Rotate(angle)
* Geom::Translate(rotc);
return t;
@@ -362,7 +425,7 @@ protected:
_last_horizontal = _side % 2;
}
- virtual Geom::Matrix computeTransform(Geom::Point const &new_pos, GdkEventMotion *event)
+ virtual Geom::Affine computeTransform(Geom::Point const &new_pos, GdkEventMotion *event)
{
Geom::Point scc = held_shift(*event) ? _skew_center : _skew_opposite;
// d1 and d2 are reversed with respect to ScaleSideHandle
@@ -395,12 +458,12 @@ protected:
// skew matrix has the from [[1, k],[0, 1]] for horizontal skew
// and [[1,0],[k,1]] for vertical skew.
- Geom::Matrix skew = Geom::identity();
+ Geom::Affine skew = Geom::identity();
// correct the sign of the tangent
skew[d2 + 1] = (d1 == Geom::X ? -1.0 : 1.0) * tan(angle);
_last_angle = angle;
- Geom::Matrix t = Geom::Translate(-scc)
+ Geom::Affine t = Geom::Translate(-scc)
* Geom::Scale(scale) * skew
* Geom::Translate(scc);
return t;
@@ -473,7 +536,23 @@ public:
}
protected:
-
+ virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event) {
+ SnapManager &sm = _desktop->namedview->snap_manager;
+ sm.setup(_desktop);
+ bool snap = !held_shift(*event) && sm.someSnapperMightSnap();
+ if (held_control(*event)) {
+ // constrain to axes
+ Geom::Point origin = _last_drag_origin();
+ std::vector<Inkscape::Snapper::SnapConstraint> constraints;
+ constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, Geom::Point(1, 0)));
+ constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, Geom::Point(0, 1)));
+ new_pos = sm.multipleConstrainedSnaps(Inkscape::SnapCandidatePoint(new_pos,
+ SNAPSOURCE_ROTATION_CENTER), constraints, held_shift(*event)).getPoint();
+ } else if (snap) {
+ sm.freeSnapReturnByRef(new_pos, SNAPSOURCE_ROTATION_CENTER);
+ }
+ sm.unSetup();
+ }
virtual Glib::ustring _getTip(unsigned /*state*/) {
return C_("Transform handle tip",
"<b>Rotation center</b>: drag to change the origin of transforms");
@@ -566,7 +645,7 @@ bool TransformHandleSet::event(GdkEvent*)
return false;
}
-void TransformHandleSet::_emitTransform(Geom::Matrix const &t)
+void TransformHandleSet::_emitTransform(Geom::Affine const &t)
{
signal_transform.emit(t);
_center->transform(t);
diff --git a/src/ui/tool/transform-handle-set.h b/src/ui/tool/transform-handle-set.h
index 2a4df8751..0557b1278 100644
--- a/src/ui/tool/transform-handle-set.h
+++ b/src/ui/tool/transform-handle-set.h
@@ -14,12 +14,11 @@
#include <memory>
#include <gdk/gdk.h>
#include <2geom/forward.h>
-#include "display/display-forward.h"
#include "ui/tool/commit-events.h"
#include "ui/tool/manipulator.h"
class SPDesktop;
-class CtrlRect; // this is not present in display-forward.h!
+class CtrlRect;
namespace Inkscape {
namespace UI {
@@ -51,10 +50,10 @@ public:
bool transforming() { return _in_transform; }
ControlPoint &rotationCenter();
- sigc::signal<void, Geom::Matrix const &> signal_transform;
+ sigc::signal<void, Geom::Affine const &> signal_transform;
sigc::signal<void, CommitEvent> signal_commit;
private:
- void _emitTransform(Geom::Matrix const &);
+ void _emitTransform(Geom::Affine const &);
void _setActiveHandle(ControlPoint *h);
void _clearActiveHandle();
void _updateVisibility(bool v);