From 0feb781e42d3bd6b555051c1464fbe046ade4fa2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Krzysztof=20Kosi=C5=84ski?= Date: Sat, 26 Dec 2009 04:13:01 +0100 Subject: [PATCH] Implement selection spatial grow --- src/ui/tool/curve-drag-point.cpp | 5 +- src/ui/tool/manipulator.h | 29 ++------ src/ui/tool/multi-path-manipulator.cpp | 46 ++++++++++-- src/ui/tool/multi-path-manipulator.h | 16 +++-- src/ui/tool/node.cpp | 98 +++++++++++++++++--------- src/ui/tool/node.h | 5 +- src/ui/tool/path-manipulator.cpp | 58 ++++++++++++--- src/ui/tool/path-manipulator.h | 15 ++-- src/ui/tool/transform-handle-set.cpp | 2 +- 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 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 > { -friend class Manipulator; -public: - ManipulatorGroup(SPDesktop *d); - ~ManipulatorGroup(); - void add(boost::shared_ptr m); - void remove(boost::shared_ptr m); - void clear(); - bool event(GdkEvent *); -private: - void _grabEvents(boost::shared_ptr m); - void _ungrabEvents(boost::shared_ptr m); - - SPDesktop *_desktop; - boost::shared_ptr _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 IterSet; typedef std::multimap DistanceMap; typedef std::pair 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 const &s) for (std::set::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 newpm(new PathManipulator(_path_data, (SPPath*) r.item, + boost::shared_ptr 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 const &); - //std::map > 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 signal_coords_changed; + sigc::signal signal_coords_changed; /// Emitted whenever the coordinates + /// shown in the status bar need updating private: typedef std::pair > MapPair; typedef std::map > 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 #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", "Shift: drag out a handle, click to toggle selection"); } - return C_("Path node statusbar tip", "Shift: click to toggle selection"); + return C_("Path node tip", "Shift: 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(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 > { public: typedef std::list< boost::shared_ptr > list_type; - SubpathList() {} + SubpathList(PathManipulator &pm) : _path_manipulator(pm) {} sigc::signal signal_insert_node; sigc::signal 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 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(); -- 2.30.2