summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2009-12-26 03:13:01 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2009-12-26 03:13:01 +0000
commit1075267dd1ba150a82b7e1aad543fbf0a69a1c00 (patch)
treecf7cf4a7cca2f27cb0b304769f92e63739290358 /src
parentRemove remnants of old node tool (diff)
downloadinkscape-1075267dd1ba150a82b7e1aad543fbf0a69a1c00.tar.gz
inkscape-1075267dd1ba150a82b7e1aad543fbf0a69a1c00.zip
Implement selection spatial grow
(bzr r8846.2.7)
Diffstat (limited to 'src')
-rw-r--r--src/ui/tool/curve-drag-point.cpp5
-rw-r--r--src/ui/tool/manipulator.h29
-rw-r--r--src/ui/tool/multi-path-manipulator.cpp46
-rw-r--r--src/ui/tool/multi-path-manipulator.h16
-rw-r--r--src/ui/tool/node.cpp98
-rw-r--r--src/ui/tool/node.h5
-rw-r--r--src/ui/tool/path-manipulator.cpp58
-rw-r--r--src/ui/tool/path-manipulator.h15
-rw-r--r--src/ui/tool/transform-handle-set.cpp2
9 files changed, 186 insertions, 88 deletions
diff --git a/src/ui/tool/curve-drag-point.cpp b/src/ui/tool/curve-drag-point.cpp
index 889e245c6..182362259 100644
--- a/src/ui/tool/curve-drag-point.cpp
+++ b/src/ui/tool/curve-drag-point.cpp
@@ -36,8 +36,9 @@ namespace UI {
bool CurveDragPoint::_drags_stroke = false;
CurveDragPoint::CurveDragPoint(PathManipulator &pm)
- : ControlPoint(pm._path_data.node_data.desktop, Geom::Point(), Gtk::ANCHOR_CENTER,
- SP_CTRL_SHAPE_CIRCLE, 1.0, &invisible_cset, pm._path_data.dragpoint_group)
+ : ControlPoint(pm._multi_path_manipulator._path_data.node_data.desktop, Geom::Point(),
+ Gtk::ANCHOR_CENTER, SP_CTRL_SHAPE_CIRCLE, 1.0, &invisible_cset,
+ pm._multi_path_manipulator._path_data.dragpoint_group)
, _pm(pm)
{
setVisible(false);
diff --git a/src/ui/tool/manipulator.h b/src/ui/tool/manipulator.h
index c441f7016..799dad0d3 100644
--- a/src/ui/tool/manipulator.h
+++ b/src/ui/tool/manipulator.h
@@ -27,6 +27,7 @@ class ControlPointSelection;
/**
* @brief Tool component that processes events and does something in response to them.
+ * Note: this class is probably redundant.
*/
class Manipulator {
friend class ManipulatorGroup;
@@ -38,15 +39,13 @@ public:
/// Handle input event. Returns true if handled.
virtual bool event(GdkEvent *)=0;
- /// Commits changes to XML (repr).
- //virtual void commitToXML();
- //Manipulator *_parent;
protected:
SPDesktop *const _desktop;
};
/**
* @brief Tool component that edits something on the canvas using selectable control points.
+ * Note: this class is probably redundant.
*/
class PointManipulator : public Manipulator, public sigc::trackable {
public:
@@ -61,7 +60,9 @@ protected:
/** Manipulator that aggregates several manipulators of the same type.
* The order of invoking events on the member manipulators is undefined.
* To make this class more useful, derive from it and add actions that can be performed
- * on all manipulators in the set. */
+ * on all manipulators in the set.
+ *
+ * This is not used at the moment and is probably useless. */
template <typename T>
class MultiManipulator : public PointManipulator {
public:
@@ -147,26 +148,6 @@ protected:
MapType _mmap;
};
-/*
- * @brief Set of manipulators. Takes care of routing events to appropriate manipulators.
- */
-/*class ManipulatorGroup : private std::list<boost::shared_ptr<Manipulator> > {
-friend class Manipulator;
-public:
- ManipulatorGroup(SPDesktop *d);
- ~ManipulatorGroup();
- void add(boost::shared_ptr<Manipulator> m);
- void remove(boost::shared_ptr<Manipulator> m);
- void clear();
- bool event(GdkEvent *);
-private:
- void _grabEvents(boost::shared_ptr<Manipulator> m);
- void _ungrabEvents(boost::shared_ptr<Manipulator> m);
-
- SPDesktop *_desktop;
- boost::shared_ptr<Manipulator> _grab;
-};*/
-
} // namespace UI
} // namespace Inkscape
diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp
index aaf7e413c..ac0165e1a 100644
--- a/src/ui/tool/multi-path-manipulator.cpp
+++ b/src/ui/tool/multi-path-manipulator.cpp
@@ -37,8 +37,7 @@ typedef std::unordered_set<NodeList::iterator> IterSet;
typedef std::multimap<double, IterPair> DistanceMap;
typedef std::pair<double, IterPair> DistanceMapItem;
-/** Find two selected endnodes.
- * @returns -1 if not enough endnodes selected, 1 if too many, 0 if OK */
+/** Find pairs of selected endnodes suitable for joining. */
void find_join_iterators(ControlPointSelection &sel, IterPairList &pairs)
{
IterSet join_iters;
@@ -105,12 +104,11 @@ bool prepare_join(IterPair &join_iters)
} // anonymous namespace
-MultiPathManipulator::MultiPathManipulator(PathSharedData const &data, sigc::connection &chg)
+MultiPathManipulator::MultiPathManipulator(PathSharedData &data, sigc::connection &chg)
: PointManipulator(data.node_data.desktop, *data.node_data.selection)
, _path_data(data)
, _changed(chg)
{
- //
_selection.signal_commit.connect(
sigc::mem_fun(*this, &MultiPathManipulator::_commit));
_selection.signal_point_changed.connect(
@@ -170,7 +168,7 @@ void MultiPathManipulator::setItems(std::set<ShapeRecord> const &s)
for (std::set<ShapeRecord>::iterator i = shapes.begin(); i != shapes.end(); ++i) {
ShapeRecord const &r = *i;
if (!SP_IS_PATH(r.item) && !IS_LIVEPATHEFFECT(r.item)) continue;
- boost::shared_ptr<PathManipulator> newpm(new PathManipulator(_path_data, (SPPath*) r.item,
+ boost::shared_ptr<PathManipulator> newpm(new PathManipulator(*this, (SPPath*) r.item,
r.edit_transform, _getOutlineColor(r.role), r.lpe_key));
newpm->showHandles(_show_handles);
// always show outlines for clips and masks
@@ -203,6 +201,39 @@ void MultiPathManipulator::shiftSelection(int dir)
{
invokeForAll(&PathManipulator::shiftSelection, dir);
}
+void MultiPathManipulator::spatialGrow(NodeList::iterator origin, int dir)
+{
+ double extr_dist = dir > 0 ? HUGE_VAL : -HUGE_VAL;
+ NodeList::iterator target;
+
+ do { // this substitutes for goto
+ if ((dir > 0 && !origin->selected())) {
+ target = origin;
+ break;
+ }
+
+ bool closest = dir > 0; // when growing, find closest node
+ bool selected = dir < 0; // when growing, consider only unselected nodes
+
+ for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) {
+ NodeList::iterator t = i->second->extremeNode(origin, selected, !selected, closest);
+ if (!t) continue;
+ double dist = Geom::distance(*t, *origin);
+ bool cond = closest ? (dist < extr_dist) : (dist > extr_dist);
+ if (cond) {
+ extr_dist = dist;
+ target = t;
+ }
+ }
+ } while (0);
+
+ if (!target) return;
+ if (dir > 0) {
+ _selection.insert(target.ptr());
+ } else {
+ _selection.erase(target.ptr());
+ }
+}
void MultiPathManipulator::invertSelection()
{
invokeForAll(&PathManipulator::invertSelection);
@@ -343,7 +374,7 @@ void MultiPathManipulator::joinSegment()
}
}
- _doneWithCleanup("Join segment");
+ _doneWithCleanup("Join segments");
}
void MultiPathManipulator::deleteSegments()
@@ -505,6 +536,8 @@ bool MultiPathManipulator::event(GdkEvent *event)
return false;
}
+/** Commit changes to XML and add undo stack entry based on the action that was done. Invoked
+ * by sub-manipulators, for example TransformHandleSet and ControlPointSelection. */
void MultiPathManipulator::_commit(CommitEvent cps)
{
gchar const *reason = NULL;
@@ -581,6 +614,7 @@ void MultiPathManipulator::_doneWithCleanup(gchar const *reason) {
_changed.unblock();
}
+/** Get an outline color based on the shape's role (normal, mask, LPE parameter, etc.). */
guint32 MultiPathManipulator::_getOutlineColor(ShapeRole role)
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h
index b66451ad3..4fbbf1b05 100644
--- a/src/ui/tool/multi-path-manipulator.h
+++ b/src/ui/tool/multi-path-manipulator.h
@@ -16,6 +16,7 @@
#include "forward.h"
#include "ui/tool/commit-events.h"
#include "ui/tool/manipulator.h"
+#include "ui/tool/node.h"
#include "ui/tool/node-types.h"
#include "ui/tool/shape-record.h"
@@ -30,19 +31,16 @@ struct PathSharedData;
/**
* Manipulator that manages multiple path manipulators active at the same time.
- * It functions like a boost::ptr_set - manipulators added via insert() are retained.
*/
class MultiPathManipulator : public PointManipulator {
public:
- MultiPathManipulator(PathSharedData const &data, sigc::connection &chg);
+ MultiPathManipulator(PathSharedData &data, sigc::connection &chg);
virtual ~MultiPathManipulator();
virtual bool event(GdkEvent *event);
bool empty() { return _mmap.empty(); }
unsigned size() { return _mmap.empty(); }
- // TODO fix this garbage!
void setItems(std::set<ShapeRecord> const &);
- //std::map<SPPath*, std::pair<Geom::Matrix, guint32> > const &items);
void clear() { _mmap.clear(); }
void cleanup();
@@ -50,8 +48,7 @@ public:
void selectAll();
void selectArea(Geom::Rect const &area, bool take);
void shiftSelection(int dir);
- void linearGrow(int dir);
- void spatialGrow(int dir);
+ void spatialGrow(NodeList::iterator center, int dir);
void invertSelection();
void invertSelectionInSubpaths();
void deselect();
@@ -75,7 +72,8 @@ public:
void showPathDirection(bool show);
void updateOutlineColors();
- sigc::signal<void> signal_coords_changed;
+ sigc::signal<void> signal_coords_changed; /// Emitted whenever the coordinates
+ /// shown in the status bar need updating
private:
typedef std::pair<ShapeRecord, boost::shared_ptr<PathManipulator> > MapPair;
typedef std::map<ShapeRecord, boost::shared_ptr<PathManipulator> > MapType;
@@ -111,11 +109,15 @@ private:
guint32 _getOutlineColor(ShapeRole role);
MapType _mmap;
+public:
PathSharedData const &_path_data;
+private:
sigc::connection &_changed;
bool _show_handles;
bool _show_outline;
bool _show_path_direction;
+
+ friend class PathManipulator;
};
} // namespace UI
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index 5f792cfc7..4f6d0d5d7 100644
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
@@ -15,7 +15,9 @@
#include <glib/gi18n.h>
#include <2geom/transforms.h>
#include "ui/tool/event-utils.h"
+#include "ui/tool/multi-path-manipulator.h"
#include "ui/tool/node.h"
+#include "ui/tool/path-manipulator.h"
#include "display/sp-ctrlline.h"
#include "display/sp-canvas.h"
#include "display/sp-canvas-util.h"
@@ -409,37 +411,38 @@ void Node::_fixNeighbors(Geom::Point const &old_pos, Geom::Point const &new_pos)
if (_type == NODE_SMOOTH && !handle->isDegenerate()) {
handle->setDirection(other->position(), new_pos);
- /*Geom::Point handle_delta = handle->position() - position();
- Geom::Point new_delta = Geom::unit_vector(new_direction) * handle_delta.length();
- handle->setPosition(position() + new_delta);*/
}
// also update the handle on the other end of the segment
if (other->_type == NODE_SMOOTH && !other_handle->isDegenerate()) {
other_handle->setDirection(new_pos, other->position());
- /*
- Geom::Point handle_delta2 = other_handle->position() - other->position();
- Geom::Point new_delta2 = Geom::unit_vector(new_direction) * handle_delta2.length();
- other_handle->setPosition(other->position() + new_delta2);*/
}
}
void Node::_updateAutoHandles()
{
// Recompute the position of automatic handles.
- if (!_prev() || !_next()) {
+ // For endnodes, retract both handles. (It's only possible to create an end auto node
+ // through the XML editor.)
+ if (isEndNode()) {
_front.retract();
_back.retract();
return;
}
- // TODO describe in detail what the code below does
+
+ // Auto nodes automaticaly adjust their handles to give an appearance of smoothness,
+ // no matter what their surroundings are.
Geom::Point vec_next = _next()->position() - position();
Geom::Point vec_prev = _prev()->position() - position();
double len_next = vec_next.length(), len_prev = vec_prev.length();
if (len_next > 0 && len_prev > 0) {
+ // "dir" is an unit vector perpendicular to the bisector of the angle created
+ // by the previous node, this auto node and the next node.
Geom::Point dir = Geom::unit_vector((len_prev / len_next) * vec_next - vec_prev);
+ // Handle lengths are equal to 1/3 of the distance from the adjacent node.
_back.setRelativePos(-dir * (len_prev / 3));
_front.setRelativePos(dir * (len_next / 3));
} else {
+ // If any of the adjacent nodes coincides, retract both handles.
_front.retract();
_back.retract();
}
@@ -618,6 +621,33 @@ NodeType Node::parse_nodetype(char x)
}
}
+bool Node::_eventHandler(GdkEvent *event)
+{
+ static NodeList::iterator origin;
+ static int dir;
+
+ switch (event->type)
+ {
+ case GDK_SCROLL:
+ if (event->scroll.direction == GDK_SCROLL_UP) {
+ dir = 1;
+ } else if (event->scroll.direction == GDK_SCROLL_DOWN) {
+ dir = -1;
+ } else break;
+ origin = NodeList::get_iterator(this);
+
+ if (held_control(event->scroll)) {
+ list()->_list._path_manipulator._multi_path_manipulator.spatialGrow(origin, dir);
+ } else {
+ list()->_list._path_manipulator.linearGrow(origin, dir);
+ }
+ return true;
+ default:
+ break;
+ }
+ return ControlPoint::_eventHandler(event);
+}
+
void Node::_setState(State state)
{
// change node size to match type and selection state
@@ -673,29 +703,31 @@ bool Node::_grabbedHandler(GdkEventMotion *event)
void Node::_draggedHandler(Geom::Point &new_pos, GdkEventMotion *event)
{
- if (!held_control(*event)) return;
- if (held_alt(*event)) {
- // with Ctrl+Alt, constrain to handle lines
- // project the new position onto a handle line that is closer
- Geom::Point origin = _last_drag_origin();
- Geom::Line line_front(origin, origin + _front.relativePos());
- Geom::Line line_back(origin, origin + _back.relativePos());
- double dist_front, dist_back;
- dist_front = Geom::distance(new_pos, line_front);
- dist_back = Geom::distance(new_pos, line_back);
- if (dist_front < dist_back) {
- new_pos = Geom::projection(new_pos, line_front);
+ if (held_control(*event)) {
+ if (held_alt(*event)) {
+ // with Ctrl+Alt, constrain to handle lines
+ // project the new position onto a handle line that is closer
+ Geom::Point origin = _last_drag_origin();
+ Geom::Line line_front(origin, origin + _front.relativePos());
+ Geom::Line line_back(origin, origin + _back.relativePos());
+ double dist_front, dist_back;
+ dist_front = Geom::distance(new_pos, line_front);
+ dist_back = Geom::distance(new_pos, line_back);
+ if (dist_front < dist_back) {
+ new_pos = Geom::projection(new_pos, line_front);
+ } else {
+ new_pos = Geom::projection(new_pos, line_back);
+ }
} else {
- new_pos = Geom::projection(new_pos, line_back);
+ // with Ctrl, constrain to axes
+ // TODO maybe add diagonals when the distance from origin is large enough?
+ Geom::Point origin = _last_drag_origin();
+ Geom::Point delta = new_pos - origin;
+ Geom::Dim2 d = (fabs(delta[Geom::X]) < fabs(delta[Geom::Y])) ? Geom::X : Geom::Y;
+ new_pos[d] = origin[d];
}
} else {
- // with Ctrl, constrain to axes
- // TODO this probably has to be separated into an AxisConstrainablePoint class
- // TODO maybe add diagonals when the distance from origin is large enough?
- Geom::Point origin = _last_drag_origin();
- Geom::Point delta = new_pos - origin;
- Geom::Dim2 d = (fabs(delta[Geom::X]) < fabs(delta[Geom::Y])) ? Geom::X : Geom::Y;
- new_pos[d] = origin[d];
+ // snapping?
}
}
@@ -711,7 +743,7 @@ Glib::ustring Node::_getTip(unsigned state)
return C_("Path node tip",
"<b>Shift:</b> drag out a handle, click to toggle selection");
}
- return C_("Path node statusbar tip", "<b>Shift:</b> click to toggle selection");
+ return C_("Path node tip", "<b>Shift:</b> click to toggle selection");
}
if (state_held_control(state)) {
@@ -733,7 +765,7 @@ Glib::ustring Node::_getDragTip(GdkEventMotion *event)
Geom::Point dist = position() - _last_drag_origin();
GString *x = SP_PX_TO_METRIC_STRING(dist[Geom::X], _desktop->namedview->getDefaultMetric());
GString *y = SP_PX_TO_METRIC_STRING(dist[Geom::Y], _desktop->namedview->getDefaultMetric());
- Glib::ustring ret = format_tip(C_("Path node statusbar tip", "Move by %s, %s"),
+ Glib::ustring ret = format_tip(C_("Path node tip", "Move by %s, %s"),
x->str, y->str);
g_string_free(x, TRUE);
g_string_free(y, TRUE);
@@ -915,7 +947,7 @@ void NodeList::clear()
NodeList::iterator NodeList::erase(iterator i)
{
- // some acrobatics are required to ensure that the node is valid when deleted;
+ // some gymnastics are required to ensure that the node is valid when deleted;
// otherwise the code that updates handle visibility will break
Node *rm = static_cast<Node*>(i._node);
ListNode *rmnext = rm->next, *rmprev = rm->prev;
@@ -927,6 +959,8 @@ NodeList::iterator NodeList::erase(iterator i)
return i;
}
+// TODO this method is nasty and ugly!
+// converting SubpathList to an intrusive list might allow us to get rid of it
void NodeList::kill()
{
for (SubpathList::iterator i = _list.begin(); i != _list.end(); ++i) {
diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h
index 9a36642eb..68ad63ba9 100644
--- a/src/ui/tool/node.h
+++ b/src/ui/tool/node.h
@@ -39,6 +39,7 @@ namespace Inkscape {
namespace UI {
class PathManipulator;
+class MultiPathManipulator;
class Node;
class Handle;
@@ -136,6 +137,7 @@ public:
static char const *node_type_to_localized_string(NodeType type);
protected:
+ virtual bool _eventHandler(GdkEvent *event);
virtual void _setState(State state);
virtual Glib::ustring _getTip(unsigned state);
virtual Glib::ustring _getDragTip(GdkEventMotion *event);
@@ -294,12 +296,13 @@ class SubpathList : public std::list< boost::shared_ptr<NodeList> > {
public:
typedef std::list< boost::shared_ptr<NodeList> > list_type;
- SubpathList() {}
+ SubpathList(PathManipulator &pm) : _path_manipulator(pm) {}
sigc::signal<void, Node *> signal_insert_node;
sigc::signal<void, Node *> signal_remove_node;
private:
list_type _nodelists;
+ PathManipulator &_path_manipulator;
friend class NodeList;
friend class Node;
friend class Handle;
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp
index f247e5537..42db45321 100644
--- a/src/ui/tool/path-manipulator.cpp
+++ b/src/ui/tool/path-manipulator.cpp
@@ -85,10 +85,11 @@ private:
void build_segment(Geom::PathBuilder &, Node *, Node *);
-PathManipulator::PathManipulator(PathSharedData const &data, SPPath *path,
+PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path,
Geom::Matrix const &et, guint32 outline_color, Glib::ustring lpe_key)
- : PointManipulator(data.node_data.desktop, *data.node_data.selection)
- , _path_data(data)
+ : PointManipulator(mpm._path_data.node_data.desktop, *mpm._path_data.node_data.selection)
+ , _subpaths(*this)
+ , _multi_path_manipulator(mpm)
, _path(path)
, _spcurve(NULL)
, _dragpoint(new CurveDragPoint(*this))
@@ -109,7 +110,7 @@ PathManipulator::PathManipulator(PathSharedData const &data, SPPath *path,
_getGeometry();
- _outline = sp_canvas_bpath_new(_path_data.outline_group, NULL);
+ _outline = sp_canvas_bpath_new(_multi_path_manipulator._path_data.outline_group, NULL);
sp_canvas_item_hide(_outline);
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(_outline), outline_color, 1.0,
SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
@@ -297,6 +298,11 @@ void PathManipulator::shiftSelection(int dir)
}
}
+void PathManipulator::linearGrow(NodeList::iterator center, int dir)
+{
+ g_message("linearGrow unimplemented");
+}
+
/** Invert selection in the entire path. */
void PathManipulator::invertSelection()
{
@@ -343,7 +349,7 @@ void PathManipulator::insertNodes()
}
/** Replace contiguous selections of nodes in each subpath with one node. */
-void PathManipulator::weldNodes(NodeList::iterator const &preserve_pos)
+void PathManipulator::weldNodes(NodeList::iterator preserve_pos)
{
if (!_num_selected) return;
_dragpoint->setVisible(false);
@@ -453,7 +459,7 @@ void PathManipulator::breakNodes()
ins = new_sp;
}
- Node *n = new Node(_path_data.node_data, cur->position());
+ Node *n = new Node(_multi_path_manipulator._path_data.node_data, cur->position());
ins->insert(ins->end(), n);
cur->setType(NODE_CUSP, false);
n->back()->setRelativePos(cur->back()->relativePos());
@@ -747,7 +753,7 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d
NodeList::iterator inserted;
if (first->front()->isDegenerate() && second->back()->isDegenerate()) {
// for a line segment, insert a cusp node
- Node *n = new Node(_path_data.node_data,
+ Node *n = new Node(_multi_path_manipulator._path_data.node_data,
Geom::lerp(t, first->position(), second->position()));
n->setType(NODE_CUSP, false);
inserted = list.insert(insert_at, n);
@@ -759,7 +765,7 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d
std::vector<Geom::Point> seg1 = div.first.points(), seg2 = div.second.points();
// set new handle positions
- Node *n = new Node(_path_data.node_data, seg2[0]);
+ Node *n = new Node(_multi_path_manipulator._path_data.node_data, seg2[0]);
n->back()->setPosition(seg1[2]);
n->front()->setPosition(seg2[1]);
n->setType(NODE_SMOOTH, false);
@@ -771,6 +777,38 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d
return inserted;
}
+/** Find the node that is closest/farthest from the origin
+ * @param origin Point of reference
+ * @param search_selected Consider selected nodes
+ * @param search_unselected Consider unselected nodes
+ * @param closest If true, return closest node, if false, return farthest
+ * @return The matching node, or an empty iterator if none found
+ */
+NodeList::iterator PathManipulator::extremeNode(NodeList::iterator origin, bool search_selected,
+ bool search_unselected, bool closest)
+{
+ NodeList::iterator match;
+ double extr_dist = closest ? HUGE_VAL : -HUGE_VAL;
+ if (_num_selected == 0 && !search_unselected) return match;
+
+ for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
+ for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
+ if(j->selected()) {
+ if (!search_selected) continue;
+ } else {
+ if (!search_unselected) continue;
+ }
+ double dist = Geom::distance(*j, *origin);
+ bool cond = closest ? (dist < extr_dist) : (dist > extr_dist);
+ if (cond) {
+ match = j;
+ extr_dist = dist;
+ }
+ }
+ }
+ return match;
+}
+
/** Called by the XML observer when something else than us modifies the path. */
void PathManipulator::_externalChange(unsigned type)
{
@@ -839,7 +877,7 @@ void PathManipulator::_createControlPointsFromGeometry()
SubpathPtr subpath(new NodeList(_subpaths));
_subpaths.push_back(subpath);
- Node *previous_node = new Node(_path_data.node_data, pit->initialPoint());
+ Node *previous_node = new Node(_multi_path_manipulator._path_data.node_data, pit->initialPoint());
subpath->push_back(previous_node);
Geom::Curve const &cseg = pit->back_closed();
bool fuse_ends = pit->closed()
@@ -856,7 +894,7 @@ void PathManipulator::_createControlPointsFromGeometry()
/* regardless of segment type, create a new node at the end
* of this segment (unless this is the last segment of a closed path
* with a degenerate closing segment */
- current_node = new Node(_path_data.node_data, pos);
+ current_node = new Node(_multi_path_manipulator._path_data.node_data, pos);
subpath->push_back(current_node);
}
// if this is a bezier segment, move handles appropriately
diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h
index e0d8c68ca..82ce7fd5d 100644
--- a/src/ui/tool/path-manipulator.h
+++ b/src/ui/tool/path-manipulator.h
@@ -26,6 +26,7 @@ struct SPCanvasItem;
namespace Inkscape {
namespace XML { class Node; }
+
namespace UI {
class PathManipulator;
@@ -33,6 +34,8 @@ class ControlPointSelection;
class PathManipulatorObserver;
class CurveDragPoint;
class PathCanvasGroups;
+class MultiPathManipulator;
+class Node;
struct PathSharedData {
NodeSharedData node_data;
@@ -49,7 +52,7 @@ class PathManipulator : public PointManipulator {
public:
typedef SPPath *ItemType;
- PathManipulator(PathSharedData const &data, SPPath *path, Geom::Matrix const &edit_trans,
+ PathManipulator(MultiPathManipulator &mpm, SPPath *path, Geom::Matrix const &edit_trans,
guint32 outline_color, Glib::ustring lpe_key);
~PathManipulator();
virtual bool event(GdkEvent *);
@@ -64,13 +67,12 @@ public:
void selectAll();
void selectArea(Geom::Rect const &);
void shiftSelection(int dir);
- void linearGrow(int dir);
- void spatialGrow(int dir);
+ void linearGrow(NodeList::iterator center, int dir);
void invertSelection();
void invertSelectionInSubpaths();
void insertNodes();
- void weldNodes(NodeList::iterator const &preserve_pos = NodeList::iterator());
+ void weldNodes(NodeList::iterator preserve_pos = NodeList::iterator());
void weldSegments();
void breakNodes();
void deleteNodes(bool keep_shape = true);
@@ -85,6 +87,8 @@ public:
void hideDragPoint();
NodeList::iterator subdivideSegment(NodeList::iterator after, double t);
+ NodeList::iterator extremeNode(NodeList::iterator origin, bool search_selected,
+ bool search_unselected, bool closest);
static bool is_item_type(void *item);
private:
@@ -117,7 +121,7 @@ private:
double _getStrokeTolerance();
SubpathList _subpaths;
- PathSharedData const &_path_data;
+ MultiPathManipulator &_multi_path_manipulator;
SPPath *_path;
SPCurve *_spcurve; // in item coordinates
SPCanvasItem *_outline;
@@ -134,6 +138,7 @@ private:
friend class PathManipulatorObserver;
friend class CurveDragPoint;
+ friend class Node;
};
} // namespace UI
diff --git a/src/ui/tool/transform-handle-set.cpp b/src/ui/tool/transform-handle-set.cpp
index f3e2847e4..d6181dbf4 100644
--- a/src/ui/tool/transform-handle-set.cpp
+++ b/src/ui/tool/transform-handle-set.cpp
@@ -24,7 +24,7 @@
#include "ui/tool/transform-handle-set.h"
// FIXME BRAIN DAMAGE WARNING: this is a global variable in select-context.cpp
-// Should be moved to a location where it can be accessed globally
+// It should be moved to a header
extern GdkPixbuf *handles[];
GType sp_select_context_get_type();