From 31bb8269c26a781036448ed8f8cd93cc84fb2118 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 29 Nov 2009 16:33:18 +0100 Subject: First GSoC node tool commit to Bazaar (bzr r8846.1.1) --- src/ui/tool/multi-path-manipulator.cpp | 568 +++++++++++++++++++++++++++++++++ 1 file changed, 568 insertions(+) create mode 100644 src/ui/tool/multi-path-manipulator.cpp (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp new file mode 100644 index 000000000..6b245702a --- /dev/null +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -0,0 +1,568 @@ +/** @file + * Path manipulator - implementation + */ +/* Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2009 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include +#include +#include +#include "desktop.h" +#include "desktop-handles.h" +#include "document.h" +#include "message-stack.h" +#include "sp-path.h" +#include "ui/tool/control-point-selection.h" +#include "ui/tool/event-utils.h" +#include "ui/tool/node.h" +#include "ui/tool/multi-path-manipulator.h" +#include "ui/tool/path-manipulator.h" + +namespace std { using namespace tr1; } + +namespace Inkscape { +namespace UI { + +namespace { +typedef std::pair IterPair; +typedef std::vector IterPairList; +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 */ +void find_join_iterators(ControlPointSelection &sel, IterPairList &pairs) +{ + IterSet join_iters; + DistanceMap dists; + + // find all endnodes in selection + for (ControlPointSelection::iterator i = sel.begin(); i != sel.end(); ++i) { + Node *node = dynamic_cast(i->first); + if (!node) continue; + NodeList::iterator iter = NodeList::get_iterator(node); + if (!iter.next() || !iter.prev()) join_iters.insert(iter); + } + + if (join_iters.size() < 2) return; + + // Below we find the closest pairs. The algorithm is O(N^3). + // We can go down to O(N^2 log N) by using O(N^2) memory, by putting all pairs + // with their distances in a multimap (not worth it IMO). + while (join_iters.size() >= 2) { + double closest = DBL_MAX; + IterPair closest_pair; + for (IterSet::iterator i = join_iters.begin(); i != join_iters.end(); ++i) { + for (IterSet::iterator j = join_iters.begin(); j != i; ++j) { + double dist = Geom::distance(**i, **j); + if (dist < closest) { + closest = dist; + closest_pair = std::make_pair(*i, *j); + } + } + } + pairs.push_back(closest_pair); + join_iters.erase(closest_pair.first); + join_iters.erase(closest_pair.second); + } +} + +/** After this function, first should be at the end of path and second at the beginnning. + * @returns True if the nodes are in the same subpath */ +bool prepare_join(IterPair &join_iters) +{ + if (&NodeList::get(join_iters.first) == &NodeList::get(join_iters.second)) { + if (join_iters.first.next()) // if first is begin, swap the iterators + std::swap(join_iters.first, join_iters.second); + return true; + } + + NodeList &sp_first = NodeList::get(join_iters.first); + NodeList &sp_second = NodeList::get(join_iters.second); + if (join_iters.first.next()) { // first is begin + if (join_iters.second.next()) { // second is begin + sp_first.reverse(); + } else { // second is end + std::swap(join_iters.first, join_iters.second); + } + } else { // first is end + if (join_iters.second.next()) { // second is begin + // do nothing + } else { // second is end + sp_second.reverse(); + } + } + return false; +} +} // anonymous namespace + + +MultiPathManipulator::MultiPathManipulator(PathSharedData const &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( + sigc::hide( sigc::hide( + signal_coords_changed.make_slot()))); +} + +MultiPathManipulator::~MultiPathManipulator() +{ + _mmap.clear(); +} + +/** Remove empty manipulators. */ +void MultiPathManipulator::cleanup() +{ + for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ) { + if (i->second->empty()) _mmap.erase(i++); + else ++i; + } +} + +void MultiPathManipulator::setItems(std::map > const &items) +{ + typedef std::map > TransMap; + typedef std::set ItemSet; + ItemSet to_remove, to_add, current, new_items; + + for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { + current.insert(i->first); + } + for (TransMap::const_iterator i = items.begin(); i != items.end(); ++i) { + new_items.insert(i->first); + } + + std::set_difference(current.begin(), current.end(), new_items.begin(), new_items.end(), + std::inserter(to_remove, to_remove.end())); + std::set_difference(new_items.begin(), new_items.end(), current.begin(), current.end(), + std::inserter(to_add, to_add.end())); + + for (ItemSet::iterator i = to_remove.begin(); i != to_remove.end(); ++i) { + _mmap.erase(*i); + } + for (ItemSet::iterator i = to_add.begin(); i != to_add.end(); ++i) { + boost::shared_ptr pm; + TransMap::const_iterator f = items.find(*i); + pm.reset(new PathManipulator(_path_data, *i, f->second.first, f->second.second)); + pm->showHandles(_show_handles); + pm->showOutline(_show_outline); + pm->showPathDirection(_show_path_direction); + _mmap.insert(std::make_pair(*i, pm)); + } +} + +void MultiPathManipulator::selectSubpaths() +{ + if (_selection.empty()) { + invokeForAll(&PathManipulator::selectAll); + } else { + invokeForAll(&PathManipulator::selectSubpaths); + } +} +void MultiPathManipulator::selectAll() +{ + invokeForAll(&PathManipulator::selectAll); +} + +void MultiPathManipulator::selectArea(Geom::Rect const &area, bool take) +{ + if (take) _selection.clear(); + invokeForAll(&PathManipulator::selectArea, area); +} + +void MultiPathManipulator::shiftSelection(int dir) +{ + invokeForAll(&PathManipulator::shiftSelection, dir); +} +void MultiPathManipulator::invertSelection() +{ + invokeForAll(&PathManipulator::invertSelection); +} +void MultiPathManipulator::invertSelectionInSubpaths() +{ + invokeForAll(&PathManipulator::invertSelectionInSubpaths); +} +void MultiPathManipulator::deselect() +{ + _selection.clear(); +} + +void MultiPathManipulator::setNodeType(NodeType type) +{ + if (_selection.empty()) return; + for (ControlPointSelection::iterator i = _selection.begin(); i != _selection.end(); ++i) { + Node *node = dynamic_cast(i->first); + if (node) node->setType(type); + } + _done(_("Change node type")); +} + +void MultiPathManipulator::setSegmentType(SegmentType type) +{ + if (_selection.empty()) return; + invokeForAll(&PathManipulator::setSegmentType, type); + if (type == SEGMENT_STRAIGHT) { + _done(_("Straighten segments")); + } else { + _done(_("Make segments curves")); + } +} + +void MultiPathManipulator::insertNodes() +{ + invokeForAll(&PathManipulator::insertNodes); + _done(_("Add nodes")); +} + +void MultiPathManipulator::joinNodes() +{ + // Node join has two parts. In the first one we join two subpaths by fusing endpoints + // into one. In the second we fuse nodes in each subpath. + IterPairList joins; + NodeList::iterator preserve_pos; + Node *mouseover_node = dynamic_cast(ControlPoint::mouseovered_point); + if (mouseover_node) { + preserve_pos = NodeList::get_iterator(mouseover_node); + } + find_join_iterators(_selection, joins); + + for (IterPairList::iterator i = joins.begin(); i != joins.end(); ++i) { + bool same_path = prepare_join(*i); + bool mouseover = true; + NodeList &sp_first = NodeList::get(i->first); + NodeList &sp_second = NodeList::get(i->second); + i->first->setType(NODE_CUSP, false); + + Geom::Point joined_pos, pos_front, pos_back; + pos_front = *i->second->front(); + pos_back = *i->first->back(); + if (i->first == preserve_pos) { + joined_pos = *i->first; + } else if (i->second == preserve_pos) { + joined_pos = *i->second; + } else { + joined_pos = Geom::middle_point(pos_back, pos_front); + mouseover = false; + } + + // if the handles aren't degenerate, don't move them + i->first->move(joined_pos); + Node *joined_node = i->first.ptr(); + if (!i->second->front()->isDegenerate()) { + joined_node->front()->setPosition(pos_front); + } + if (!i->first->back()->isDegenerate()) { + joined_node->back()->setPosition(pos_back); + } + if (mouseover) { + // Second node could be mouseovered, but it will be deleted, so we must change + // the preserve_pos iterator to the first node. + preserve_pos = i->first; + } + sp_second.erase(i->second); + + if (same_path) { + sp_first.setClosed(true); + } else { + sp_first.splice(sp_first.end(), sp_second); + sp_second.kill(); + } + _selection.insert(i->first.ptr()); + } + // Second part replaces contiguous selections of nodes with single nodes + invokeForAll(&PathManipulator::weldNodes, preserve_pos); + _doneWithCleanup(_("Join nodes")); +} + +void MultiPathManipulator::breakNodes() +{ + if (_selection.empty()) return; + invokeForAll(&PathManipulator::breakNodes); + _done(_("Break nodes")); +} + +void MultiPathManipulator::deleteNodes(bool keep_shape) +{ + if (_selection.empty()) return; + invokeForAll(&PathManipulator::deleteNodes, keep_shape); + _doneWithCleanup(_("Delete nodes")); +} + +/** Join selected endpoints to create segments. */ +void MultiPathManipulator::joinSegment() +{ + IterPairList joins; + find_join_iterators(_selection, joins); + if (joins.empty()) { + _desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, + _("There must be at least 2 endnodes in selection")); + return; + } + + for (IterPairList::iterator i = joins.begin(); i != joins.end(); ++i) { + bool same_path = prepare_join(*i); + NodeList &sp_first = NodeList::get(i->first); + NodeList &sp_second = NodeList::get(i->second); + i->first->setType(NODE_CUSP, false); + i->second->setType(NODE_CUSP, false); + if (same_path) { + sp_first.setClosed(true); + } else { + sp_first.splice(sp_first.end(), sp_second); + sp_second.kill(); + } + } + + _doneWithCleanup("Join segment"); +} + +void MultiPathManipulator::deleteSegments() +{ + if (_selection.empty()) return; + invokeForAll(&PathManipulator::deleteSegments); + _doneWithCleanup("Delete segments"); +} + +void MultiPathManipulator::alignNodes(Geom::Dim2 d) +{ + _selection.align(d); + if (d == Geom::X) { + _done("Align nodes to a horizontal line"); + } else { + _done("Align nodes to a vertical line"); + } +} + +void MultiPathManipulator::distributeNodes(Geom::Dim2 d) +{ + _selection.distribute(d); + if (d == Geom::X) { + _done("Distrubute nodes horizontally"); + } else { + _done("Distribute nodes vertically"); + } +} + +void MultiPathManipulator::reverseSubpaths() +{ + invokeForAll(&PathManipulator::reverseSubpaths); + _done("Reverse selected subpaths"); +} + +void MultiPathManipulator::move(Geom::Point const &delta) +{ + _selection.transform(Geom::Translate(delta)); + _done("Move nodes"); +} + +void MultiPathManipulator::showOutline(bool show) +{ + invokeForAll(&PathManipulator::showOutline, show); + _show_outline = show; +} + +void MultiPathManipulator::showHandles(bool show) +{ + invokeForAll(&PathManipulator::showHandles, show); + _show_handles = show; +} + +void MultiPathManipulator::showPathDirection(bool show) +{ + invokeForAll(&PathManipulator::showPathDirection, show); + _show_path_direction = show; +} + +bool MultiPathManipulator::event(GdkEvent *event) +{ + switch (event->type) { + case GDK_KEY_PRESS: + switch (shortcut_key(event->key)) { + case GDK_Insert: + case GDK_KP_Insert: + insertNodes(); + return true; + case GDK_i: + case GDK_I: + if (held_only_shift(event->key)) { + insertNodes(); + return true; + } + break; + case GDK_j: + case GDK_J: + if (held_only_shift(event->key)) { + joinNodes(); + return true; + } + if (held_only_alt(event->key)) { + joinSegment(); + return true; + } + break; + case GDK_b: + case GDK_B: + if (held_only_shift(event->key)) { + breakNodes(); + return true; + } + break; + case GDK_Delete: + case GDK_KP_Delete: + case GDK_BackSpace: + if (held_shift(event->key)) break; + if (held_alt(event->key)) { + deleteSegments(); + } else { + deleteNodes(!held_control(event->key)); + } + return true; + case GDK_c: + case GDK_C: + if (held_only_shift(event->key)) { + setNodeType(NODE_CUSP); + return true; + } + break; + case GDK_s: + case GDK_S: + if (held_only_shift(event->key)) { + setNodeType(NODE_SMOOTH); + return true; + } + break; + case GDK_a: + case GDK_A: + if (held_only_shift(event->key)) { + setNodeType(NODE_AUTO); + return true; + } + break; + case GDK_y: + case GDK_Y: + if (held_only_shift(event->key)) { + setNodeType(NODE_SYMMETRIC); + return true; + } + break; + case GDK_r: + case GDK_R: + if (held_only_shift(event->key)) { + reverseSubpaths(); + break; + } + break; + default: + break; + } + break; + default: break; + } + + for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { + if (i->second->event(event)) return true; + } + return false; +} + +void MultiPathManipulator::_commit(CommitEvent cps) +{ + gchar const *reason = NULL; + gchar const *key = NULL; + switch(cps) { + case COMMIT_MOUSE_MOVE: + reason = _("Move nodes"); + break; + case COMMIT_KEYBOARD_MOVE_X: + reason = _("Move nodes horizontally"); + key = "node:move:x"; + break; + case COMMIT_KEYBOARD_MOVE_Y: + reason = _("Move nodes vertically"); + key = "node:move:y"; + break; + case COMMIT_MOUSE_ROTATE: + reason = _("Rotate nodes"); + break; + case COMMIT_KEYBOARD_ROTATE: + reason = _("Rotate nodes"); + key = "node:rotate"; + break; + case COMMIT_MOUSE_SCALE_UNIFORM: + reason = _("Scale nodes uniformly"); + break; + case COMMIT_MOUSE_SCALE: + reason = _("Scale nodes"); + break; + case COMMIT_KEYBOARD_SCALE_UNIFORM: + reason = _("Scale nodes uniformly"); + key = "node:scale:uniform"; + break; + case COMMIT_KEYBOARD_SCALE_X: + reason = _("Scale nodes horizontally"); + key = "node:scale:x"; + break; + case COMMIT_KEYBOARD_SCALE_Y: + reason = _("Scale nodes vertically"); + key = "node:scale:y"; + break; + case COMMIT_FLIP_X: + reason = _("Flip nodes horizontally"); + break; + case COMMIT_FLIP_Y: + reason = _("Flip nodes vertically"); + break; + default: return; + } + + _selection.signal_update.emit(); + invokeForAll(&PathManipulator::writeXML); + if (key) { + sp_document_maybe_done(sp_desktop_document(_desktop), key, SP_VERB_CONTEXT_NODE, reason); + } else { + sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_NODE, reason); + } + signal_coords_changed.emit(); +} + +/** Commits changes to XML and adds undo stack entry. */ +void MultiPathManipulator::_done(gchar const *reason) { + invokeForAll(&PathManipulator::update); + invokeForAll(&PathManipulator::writeXML); + sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_NODE, reason); + signal_coords_changed.emit(); +} + +/** Commits changes to XML, adds undo stack entry and removes empty manipulators. */ +void MultiPathManipulator::_doneWithCleanup(gchar const *reason) { + _changed.block(); + _done(reason); + cleanup(); + _changed.unblock(); +} + +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : -- cgit v1.2.3 From a79eab7e518e7c1b3540075552ecb3e7aa62b0df Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 5 Dec 2009 03:48:07 +0100 Subject: Fix mask editing behavior on undo and outline display for masks/clips; prepare to fix LPE path parameters (bzr r8846.2.2) --- src/ui/tool/multi-path-manipulator.cpp | 95 ++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 28 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 6b245702a..7c539f6b9 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -16,6 +16,7 @@ #include "desktop-handles.h" #include "document.h" #include "message-stack.h" +#include "preferences.h" #include "sp-path.h" #include "ui/tool/control-point-selection.h" #include "ui/tool/event-utils.h" @@ -130,36 +131,48 @@ void MultiPathManipulator::cleanup() } } -void MultiPathManipulator::setItems(std::map > const &items) +void MultiPathManipulator::setItems(std::set const &s) { - typedef std::map > TransMap; - typedef std::set ItemSet; - ItemSet to_remove, to_add, current, new_items; - - for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { - current.insert(i->first); - } - for (TransMap::const_iterator i = items.begin(); i != items.end(); ++i) { - new_items.insert(i->first); + std::set shapes(s); + + // iterate over currently edited items, modifying / removing them as necessary + for (MapType::iterator i = _mmap.begin(); i != _mmap.end();) { + std::set::iterator si = shapes.find(i->first); + if (si == shapes.end()) { + // This item is no longer supposed to be edited - remove its manipulator + _mmap.erase(i++); + } else { + ShapeRecord const &sr = i->first; + ShapeRecord const &sr_new = *si; + // if the shape record differs, replace the key only and modify other values + if (sr.edit_transform != sr_new.edit_transform || + sr.role != sr_new.role) + { + boost::shared_ptr hold(i->second); + if (sr.edit_transform != sr_new.edit_transform) + hold->setControlsTransform(sr_new.edit_transform); + if (sr.role != sr_new.role) { + //hold->setOutlineColor(_getOutlineColor(sr_new.role)); + } + _mmap.erase(sr); + _mmap.insert(std::make_pair(sr_new, hold)); + } + shapes.erase(si); // remove the processed record + ++i; + } } - std::set_difference(current.begin(), current.end(), new_items.begin(), new_items.end(), - std::inserter(to_remove, to_remove.end())); - std::set_difference(new_items.begin(), new_items.end(), current.begin(), current.end(), - std::inserter(to_add, to_add.end())); - - for (ItemSet::iterator i = to_remove.begin(); i != to_remove.end(); ++i) { - _mmap.erase(*i); - } - for (ItemSet::iterator i = to_add.begin(); i != to_add.end(); ++i) { - boost::shared_ptr pm; - TransMap::const_iterator f = items.find(*i); - pm.reset(new PathManipulator(_path_data, *i, f->second.first, f->second.second)); - pm->showHandles(_show_handles); - pm->showOutline(_show_outline); - pm->showPathDirection(_show_path_direction); - _mmap.insert(std::make_pair(*i, pm)); + // add newly selected items + for (std::set::iterator i = shapes.begin(); i != shapes.end(); ++i) { + ShapeRecord const &r = *i; + if (!SP_IS_PATH(r.item)) continue; + boost::shared_ptr newpm(new PathManipulator(_path_data, (SPPath*) r.item, + r.edit_transform, _getOutlineColor(r.role))); + newpm->showHandles(_show_handles); + // always show outlines for clips and masks + newpm->showOutline(_show_outline || r.role != SHAPE_ROLE_NORMAL); + newpm->showPathDirection(_show_path_direction); + _mmap.insert(std::make_pair(r, newpm)); } } @@ -369,7 +382,10 @@ void MultiPathManipulator::move(Geom::Point const &delta) void MultiPathManipulator::showOutline(bool show) { - invokeForAll(&PathManipulator::showOutline, show); + for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { + // always show outlines for clipping paths and masks + i->second->showOutline(show || i->first.role != SHAPE_ROLE_NORMAL); + } _show_outline = show; } @@ -385,6 +401,13 @@ void MultiPathManipulator::showPathDirection(bool show) _show_path_direction = show; } +void MultiPathManipulator::updateOutlineColors() +{ + //for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { + // i->second->setOutlineColor(_getOutlineColor(i->first.role)); + //} +} + bool MultiPathManipulator::event(GdkEvent *event) { switch (event->type) { @@ -553,6 +576,22 @@ void MultiPathManipulator::_doneWithCleanup(gchar const *reason) { _changed.unblock(); } +guint32 MultiPathManipulator::_getOutlineColor(ShapeRole role) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + switch(role) { + case SHAPE_ROLE_CLIPPING_PATH: + return prefs->getColor("/tools/nodes/clipping_path_color", 0x00ff00ff); + case SHAPE_ROLE_MASK: + return prefs->getColor("/tools/nodes/mask_color", 0x0000ffff); + case SHAPE_ROLE_LPE_PARAM: + return prefs->getColor("/tools/nodes/lpe_param_color", 0xb700ffff); + case SHAPE_ROLE_NORMAL: + default: + return prefs->getColor("/tools/nodes/outline_color", 0xff0000ff); + } +} + } // namespace UI } // namespace Inkscape -- cgit v1.2.3 From e2b9f78d271e5fea988138d49020e704e72c83b1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 8 Dec 2009 03:21:08 +0100 Subject: Fix LPEs and break mask transform undo (bzr r8846.2.3) --- src/ui/tool/multi-path-manipulator.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 7c539f6b9..aaf7e413c 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -15,6 +15,7 @@ #include "desktop.h" #include "desktop-handles.h" #include "document.h" +#include "live_effects/lpeobject.h" #include "message-stack.h" #include "preferences.h" #include "sp-path.h" @@ -131,6 +132,9 @@ void MultiPathManipulator::cleanup() } } +/** @brief Change the set of items to edit. + * + * This method attempts to preserve as much of the state as possible. */ void MultiPathManipulator::setItems(std::set const &s) { std::set shapes(s); @@ -165,9 +169,9 @@ void MultiPathManipulator::setItems(std::set const &s) // add newly selected items for (std::set::iterator i = shapes.begin(); i != shapes.end(); ++i) { ShapeRecord const &r = *i; - if (!SP_IS_PATH(r.item)) continue; + if (!SP_IS_PATH(r.item) && !IS_LIVEPATHEFFECT(r.item)) continue; boost::shared_ptr newpm(new PathManipulator(_path_data, (SPPath*) r.item, - r.edit_transform, _getOutlineColor(r.role))); + r.edit_transform, _getOutlineColor(r.role), r.lpe_key)); newpm->showHandles(_show_handles); // always show outlines for clips and masks newpm->showOutline(_show_outline || r.role != SHAPE_ROLE_NORMAL); @@ -241,6 +245,7 @@ void MultiPathManipulator::insertNodes() void MultiPathManipulator::joinNodes() { + invokeForAll(&PathManipulator::hideDragPoint); // Node join has two parts. In the first one we join two subpaths by fusing endpoints // into one. In the second we fuse nodes in each subpath. IterPairList joins; @@ -585,7 +590,7 @@ guint32 MultiPathManipulator::_getOutlineColor(ShapeRole role) case SHAPE_ROLE_MASK: return prefs->getColor("/tools/nodes/mask_color", 0x0000ffff); case SHAPE_ROLE_LPE_PARAM: - return prefs->getColor("/tools/nodes/lpe_param_color", 0xb700ffff); + return prefs->getColor("/tools/nodes/lpe_param_color", 0x009000ff); case SHAPE_ROLE_NORMAL: default: return prefs->getColor("/tools/nodes/outline_color", 0xff0000ff); -- cgit v1.2.3 From 1075267dd1ba150a82b7e1aad543fbf0a69a1c00 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 26 Dec 2009 04:13:01 +0100 Subject: Implement selection spatial grow (bzr r8846.2.7) --- src/ui/tool/multi-path-manipulator.cpp | 46 +++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') 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(); -- cgit v1.2.3 From b52865a71a9f83da9719a3ec5f50a4a2cd7cdace Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 10 Jan 2010 01:46:28 +0100 Subject: * Implement node snapping. * Fix minor bug in linear grow. * Add --fixes. * Move some node selection-related functions to ControlPointSelection. Fixed bugs: - https://launchpad.net/bugs/170561 - https://launchpad.net/bugs/171893 - https://launchpad.net/bugs/182585 - https://launchpad.net/bugs/446773 (bzr r8846.2.9) --- src/ui/tool/multi-path-manipulator.cpp | 52 +--------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index ac0165e1a..33d96c706 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -181,71 +181,21 @@ void MultiPathManipulator::setItems(std::set const &s) void MultiPathManipulator::selectSubpaths() { if (_selection.empty()) { - invokeForAll(&PathManipulator::selectAll); + _selection.selectAll(); } else { invokeForAll(&PathManipulator::selectSubpaths); } } -void MultiPathManipulator::selectAll() -{ - invokeForAll(&PathManipulator::selectAll); -} - -void MultiPathManipulator::selectArea(Geom::Rect const &area, bool take) -{ - if (take) _selection.clear(); - invokeForAll(&PathManipulator::selectArea, area); -} 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); -} void MultiPathManipulator::invertSelectionInSubpaths() { invokeForAll(&PathManipulator::invertSelectionInSubpaths); } -void MultiPathManipulator::deselect() -{ - _selection.clear(); -} void MultiPathManipulator::setNodeType(NodeType type) { -- cgit v1.2.3 From dd3076a51d8a53223c771a39fa5f976db0c85af5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 14 Jan 2010 09:42:20 +0100 Subject: Implement segment weld to make segment join similar to node join (bzr r8846.2.12) --- src/ui/tool/multi-path-manipulator.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 2cc9bc97b..3ae7e4d24 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -304,15 +304,10 @@ void MultiPathManipulator::deleteNodes(bool keep_shape) } /** Join selected endpoints to create segments. */ -void MultiPathManipulator::joinSegment() +void MultiPathManipulator::joinSegments() { IterPairList joins; find_join_iterators(_selection, joins); - if (joins.empty()) { - _desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, - _("There must be at least 2 endnodes in selection")); - return; - } for (IterPairList::iterator i = joins.begin(); i != joins.end(); ++i) { bool same_path = prepare_join(*i); @@ -328,6 +323,9 @@ void MultiPathManipulator::joinSegment() } } + if (joins.empty()) { + invokeForAll(&PathManipulator::weldSegments); + } _doneWithCleanup("Join segments"); } @@ -421,7 +419,7 @@ bool MultiPathManipulator::event(GdkEvent *event) return true; } if (held_only_alt(event->key)) { - joinSegment(); + joinSegments(); return true; } break; -- cgit v1.2.3 From 4756aa99f5756a6cac199c1aae6c37514cf1c562 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 14 Jan 2010 23:38:54 +0100 Subject: Replace std::tr1::unordered_(map|set) with __gnu_cxx::hash_(map|set), to work around broken headers in some GCC versions. (bzr r8980) --- src/ui/tool/multi-path-manipulator.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 3ae7e4d24..818bdaedc 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -8,7 +8,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include +//#include +#include #include #include #include @@ -25,7 +26,16 @@ #include "ui/tool/multi-path-manipulator.h" #include "ui/tool/path-manipulator.h" -namespace std { using namespace tr1; } +namespace std { using namespace __gnu_cxx; } + +namespace __gnu_cxx { +template<> +struct hash { + size_t operator()(Inkscape::UI::NodeList::iterator const &n) const { + return reinterpret_cast(n.ptr()); + } +}; +} namespace Inkscape { namespace UI { @@ -33,7 +43,7 @@ namespace UI { namespace { typedef std::pair IterPair; typedef std::vector IterPairList; -typedef std::unordered_set IterSet; +typedef std::hash_set IterSet; typedef std::multimap DistanceMap; typedef std::pair DistanceMapItem; -- cgit v1.2.3 From ef88d874ff89882a9222234591b328584a172799 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 20 Jan 2010 16:31:22 +0100 Subject: Fix path reverse action (Shift+R) in the node tool. (bzr r9003) --- src/ui/tool/multi-path-manipulator.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 818bdaedc..c05b71cd4 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -368,8 +368,13 @@ void MultiPathManipulator::distributeNodes(Geom::Dim2 d) void MultiPathManipulator::reverseSubpaths() { - invokeForAll(&PathManipulator::reverseSubpaths); - _done("Reverse selected subpaths"); + if (_selection.empty()) { + invokeForAll(&PathManipulator::reverseSubpaths, false); + _done("Reverse subpaths"); + } else { + invokeForAll(&PathManipulator::reverseSubpaths, true); + _done("Reverse selected subpaths"); + } } void MultiPathManipulator::move(Geom::Point const &delta) @@ -413,11 +418,14 @@ bool MultiPathManipulator::event(GdkEvent *event) switch (shortcut_key(event->key)) { case GDK_Insert: case GDK_KP_Insert: + // Insert - insert nodes in the middle of selected segments insertNodes(); return true; case GDK_i: case GDK_I: if (held_only_shift(event->key)) { + // Shift+I - insert nodes (alternate keybinding for Mac keyboards + // that don't have the Insert key) insertNodes(); return true; } @@ -425,10 +433,12 @@ bool MultiPathManipulator::event(GdkEvent *event) case GDK_j: case GDK_J: if (held_only_shift(event->key)) { + // Shift+J - join nodes joinNodes(); return true; } if (held_only_alt(event->key)) { + // Alt+J - join segments joinSegments(); return true; } @@ -436,6 +446,7 @@ bool MultiPathManipulator::event(GdkEvent *event) case GDK_b: case GDK_B: if (held_only_shift(event->key)) { + // Shift+B - break nodes breakNodes(); return true; } @@ -445,14 +456,18 @@ bool MultiPathManipulator::event(GdkEvent *event) case GDK_BackSpace: if (held_shift(event->key)) break; if (held_alt(event->key)) { + // Alt+Delete - delete segments deleteSegments(); } else { + // Control+Delete - delete nodes + // Delete - delete nodes preserving shape deleteNodes(!held_control(event->key)); } return true; case GDK_c: case GDK_C: if (held_only_shift(event->key)) { + // Shift+C - make nodes cusp setNodeType(NODE_CUSP); return true; } @@ -460,6 +475,7 @@ bool MultiPathManipulator::event(GdkEvent *event) case GDK_s: case GDK_S: if (held_only_shift(event->key)) { + // Shift+S - make nodes smooth setNodeType(NODE_SMOOTH); return true; } @@ -467,6 +483,7 @@ bool MultiPathManipulator::event(GdkEvent *event) case GDK_a: case GDK_A: if (held_only_shift(event->key)) { + // Shift+A - make nodes auto-smooth setNodeType(NODE_AUTO); return true; } @@ -474,6 +491,7 @@ bool MultiPathManipulator::event(GdkEvent *event) case GDK_y: case GDK_Y: if (held_only_shift(event->key)) { + // Shift+Y - make nodes symmetric setNodeType(NODE_SYMMETRIC); return true; } @@ -481,8 +499,8 @@ bool MultiPathManipulator::event(GdkEvent *event) case GDK_r: case GDK_R: if (held_only_shift(event->key)) { + // Shift+R - reverse subpaths reverseSubpaths(); - break; } break; default: -- cgit v1.2.3 From 906f78949458732f138e4e2b79843c75e9d52f87 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 20 Jan 2010 20:31:57 +0100 Subject: Go back to using TR1 unordered containers to fix warnings. Add configure code to detect the broken header and display Wiki page URL. (bzr r9006) --- src/ui/tool/multi-path-manipulator.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index c05b71cd4..d1138abd5 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -1,5 +1,5 @@ /** @file - * Path manipulator - implementation + * Multi path manipulator - implementation */ /* Authors: * Krzysztof Kosiński @@ -8,8 +8,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -//#include -#include +#include #include #include #include @@ -26,16 +25,7 @@ #include "ui/tool/multi-path-manipulator.h" #include "ui/tool/path-manipulator.h" -namespace std { using namespace __gnu_cxx; } - -namespace __gnu_cxx { -template<> -struct hash { - size_t operator()(Inkscape::UI::NodeList::iterator const &n) const { - return reinterpret_cast(n.ptr()); - } -}; -} +namespace std { using namespace tr1; } namespace Inkscape { namespace UI { @@ -43,7 +33,7 @@ namespace UI { namespace { typedef std::pair IterPair; typedef std::vector IterPairList; -typedef std::hash_set IterSet; +typedef std::unordered_set IterSet; typedef std::multimap DistanceMap; typedef std::pair DistanceMapItem; -- cgit v1.2.3 From bb4d4442a7ec92e15c976689756aa9566cd2430e Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 31 Jan 2010 20:31:21 +0100 Subject: Add pref settings that control updating the display of paths when dragging or transforming nodes them. Fixed bugs: - https://launchpad.net/bugs/380762 (bzr r9038) --- src/ui/tool/multi-path-manipulator.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index d1138abd5..734ddf15b 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -174,6 +174,8 @@ void MultiPathManipulator::setItems(std::set const &s) // always show outlines for clips and masks newpm->showOutline(_show_outline || r.role != SHAPE_ROLE_NORMAL); newpm->showPathDirection(_show_path_direction); + newpm->setLiveOutline(_live_outline); + newpm->setLiveObjects(_live_objects); _mmap.insert(std::make_pair(r, newpm)); } } @@ -394,6 +396,26 @@ void MultiPathManipulator::showPathDirection(bool show) _show_path_direction = show; } +/** @brief Set live outline update status + * When set to true, outline will be updated continuously when dragging + * or transforming nodes. Otherwise it will only update when changes are committed + * to XML. */ +void MultiPathManipulator::setLiveOutline(bool set) +{ + invokeForAll(&PathManipulator::setLiveOutline, set); + _live_outline = set; +} + +/** @brief Set live object update status + * When set to true, objects will be updated continuously when dragging + * or transforming nodes. Otherwise they will only update when changes are committed + * to XML. */ +void MultiPathManipulator::setLiveObjects(bool set) +{ + invokeForAll(&PathManipulator::setLiveObjects, set); + _live_objects = set; +} + void MultiPathManipulator::updateOutlineColors() { //for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { -- cgit v1.2.3 From ec40d28e9f82da40d6efbb93ba6821e7e0976c42 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 31 Jan 2010 21:02:28 +0100 Subject: Fix the position of joined nodes to match 0.47 Fixed bugs: - https://launchpad.net/bugs/514516 (bzr r9039) --- src/ui/tool/multi-path-manipulator.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 734ddf15b..d133fcf25 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -241,36 +241,33 @@ void MultiPathManipulator::joinNodes() for (IterPairList::iterator i = joins.begin(); i != joins.end(); ++i) { bool same_path = prepare_join(*i); - bool mouseover = true; NodeList &sp_first = NodeList::get(i->first); NodeList &sp_second = NodeList::get(i->second); i->first->setType(NODE_CUSP, false); - Geom::Point joined_pos, pos_front, pos_back; - pos_front = *i->second->front(); - pos_back = *i->first->back(); + Geom::Point joined_pos, pos_handle_front, pos_handle_back; + pos_handle_front = *i->second->front(); + pos_handle_back = *i->first->back(); + + // When we encounter the mouseover node, we unset the iterator - it will be invalidated if (i->first == preserve_pos) { joined_pos = *i->first; + preserve_pos = NodeList::iterator(); } else if (i->second == preserve_pos) { joined_pos = *i->second; + preserve_pos = NodeList::iterator(); } else { - joined_pos = Geom::middle_point(pos_back, pos_front); - mouseover = false; + joined_pos = Geom::middle_point(*i->first, *i->second); } // if the handles aren't degenerate, don't move them i->first->move(joined_pos); Node *joined_node = i->first.ptr(); if (!i->second->front()->isDegenerate()) { - joined_node->front()->setPosition(pos_front); + joined_node->front()->setPosition(pos_handle_front); } if (!i->first->back()->isDegenerate()) { - joined_node->back()->setPosition(pos_back); - } - if (mouseover) { - // Second node could be mouseovered, but it will be deleted, so we must change - // the preserve_pos iterator to the first node. - preserve_pos = i->first; + joined_node->back()->setPosition(pos_handle_back); } sp_second.erase(i->second); -- cgit v1.2.3 From 7ce8847f2410a24a6bce4ca8a43ad7ebdb4839eb Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 4 Feb 2010 03:14:09 +0100 Subject: Reduce libsigc++ usage to partially fix performance regressions in the new node tool. (bzr r9044) --- src/ui/tool/multi-path-manipulator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index d133fcf25..c34ef066e 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -45,7 +45,7 @@ void find_join_iterators(ControlPointSelection &sel, IterPairList &pairs) // find all endnodes in selection for (ControlPointSelection::iterator i = sel.begin(); i != sel.end(); ++i) { - Node *node = dynamic_cast(i->first); + Node *node = dynamic_cast(*i); if (!node) continue; NodeList::iterator iter = NodeList::get_iterator(node); if (!iter.next() || !iter.prev()) join_iters.insert(iter); @@ -203,7 +203,7 @@ void MultiPathManipulator::setNodeType(NodeType type) { if (_selection.empty()) return; for (ControlPointSelection::iterator i = _selection.begin(); i != _selection.end(); ++i) { - Node *node = dynamic_cast(i->first); + Node *node = dynamic_cast(*i); if (node) node->setType(type); } _done(_("Change node type")); -- cgit v1.2.3 From 9d9e9264afc4e6f83d59bd25ccae505eadb739d8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 6 Feb 2010 22:45:14 +0100 Subject: Fix performance regressions in the node tool and a stupid crash bug when deleting more than one stretch of selected nodes (bzr r9061) --- src/ui/tool/multi-path-manipulator.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index c34ef066e..5d7b520c8 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -516,12 +516,15 @@ bool MultiPathManipulator::event(GdkEvent *event) break; } break; + case GDK_MOTION_NOTIFY: + combine_motion_events(_desktop->canvas, event->motion, 0); + for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { + if (i->second->event(event)) return true; + } + break; default: break; } - for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { - if (i->second->event(event)) return true; - } return false; } -- cgit v1.2.3 From 84fc09c9c921a31ac826c53e419d4ea61584f8a9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 2 Mar 2010 23:52:32 +0100 Subject: Use Boost unordeed containers instead of TR1 to minimize pain when using Apple compilers. (bzr r9129) --- src/ui/tool/multi-path-manipulator.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 5d7b520c8..f5646ac36 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -8,7 +8,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include +#include #include #include #include @@ -25,15 +25,13 @@ #include "ui/tool/multi-path-manipulator.h" #include "ui/tool/path-manipulator.h" -namespace std { using namespace tr1; } - namespace Inkscape { namespace UI { namespace { typedef std::pair IterPair; typedef std::vector IterPairList; -typedef std::unordered_set IterSet; +typedef boost::unordered_set IterSet; typedef std::multimap DistanceMap; typedef std::pair DistanceMapItem; -- cgit v1.2.3 From 669ba0151fefdfd7ed0d5dd54978698587b1e309 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 3 Mar 2010 00:22:31 +0100 Subject: Implement a preference that determines whether deleting nodes preserves the shape (bzr r9130) --- src/ui/tool/multi-path-manipulator.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index f5646ac36..3b0852e6e 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -466,9 +466,13 @@ bool MultiPathManipulator::event(GdkEvent *event) // Alt+Delete - delete segments deleteSegments(); } else { - // Control+Delete - delete nodes - // Delete - delete nodes preserving shape - deleteNodes(!held_control(event->key)); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool del_preserves_shape = prefs->getBool("/tools/nodes/delete_preserves_shape", true); + // pass keep_shape = true when: + // a) del preserves shape, and control is not pressed + // b) ctrl+del preserves shape (del_preserves_shape is false), and control is pressed + // Hence xor + deleteNodes(del_preserves_shape ^ held_control(event->key)); } return true; case GDK_c: -- cgit v1.2.3 From 46fd0e8c49da44226151096546905589819bbdf5 Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Thu, 4 Mar 2010 00:44:53 -0800 Subject: Fixing build breakage with more proper autoconf usage. (bzr r9138) --- src/ui/tool/multi-path-manipulator.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 3b0852e6e..d86a7e9e0 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -8,7 +8,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include +#include "util/set-types.h" #include #include #include @@ -25,13 +25,24 @@ #include "ui/tool/multi-path-manipulator.h" #include "ui/tool/path-manipulator.h" +#ifdef USE_GNU_HASHES +namespace __gnu_cxx { +template<> +struct hash { + size_t operator()(Inkscape::UI::NodeList::iterator const &n) const { + return reinterpret_cast(n.ptr()); + } +}; +} // namespace __gnu_cxx +#endif // USE_GNU_HASHES + namespace Inkscape { namespace UI { namespace { typedef std::pair IterPair; typedef std::vector IterPairList; -typedef boost::unordered_set IterSet; +typedef optim_set IterSet; typedef std::multimap DistanceMap; typedef std::pair DistanceMapItem; -- cgit v1.2.3 From 91b1b6cec4776d8c2e48b54e16d698abcea6bbfe Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 4 Mar 2010 22:54:38 +0100 Subject: Clean up the unordered containers fix. (bzr r9142) --- src/ui/tool/multi-path-manipulator.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index d86a7e9e0..b79a29437 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -8,7 +8,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "util/set-types.h" #include #include #include @@ -24,6 +23,7 @@ #include "ui/tool/node.h" #include "ui/tool/multi-path-manipulator.h" #include "ui/tool/path-manipulator.h" +#include "util/unordered-containers.h" #ifdef USE_GNU_HASHES namespace __gnu_cxx { @@ -40,9 +40,18 @@ namespace Inkscape { namespace UI { namespace { + +struct hash_nodelist_iterator + : public std::unary_function +{ + std::size_t operator()(NodeList::iterator i) const { + return INK_HASH()(&*i); + } +}; + typedef std::pair IterPair; typedef std::vector IterPairList; -typedef optim_set IterSet; +typedef INK_UNORDERED_SET IterSet; typedef std::multimap DistanceMap; typedef std::pair DistanceMapItem; -- cgit v1.2.3 From df9b184c006242551462ec431b1d79d33dcb92a3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 5 Mar 2010 01:53:14 +0100 Subject: Fix double reverse with Shift+R in the node tool. (bzr r9145) --- src/ui/tool/multi-path-manipulator.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index b79a29437..9accbd0ae 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -532,6 +532,7 @@ bool MultiPathManipulator::event(GdkEvent *event) if (held_only_shift(event->key)) { // Shift+R - reverse subpaths reverseSubpaths(); + return true; } break; default: -- cgit v1.2.3 From 90e813701a7865bc36755fb0f35ab74c4b6963a2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 14 Mar 2010 18:38:50 +0100 Subject: Implement keyboard shortcuts for single handle adjustments. Minor disambiguating cleanup in node.h. (bzr r9190) --- src/ui/tool/multi-path-manipulator.cpp | 53 +++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 9accbd0ae..fe97058c4 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -440,9 +440,60 @@ void MultiPathManipulator::updateOutlineColors() bool MultiPathManipulator::event(GdkEvent *event) { + _tracker.event(event); + guint key = 0; + if (event->type == GDK_KEY_PRESS) { + key = shortcut_key(event->key); + } + + // Single handle adjustments go here. + if (_selection.size() == 1 && event->type == GDK_KEY_PRESS) { + do { + Node *n = dynamic_cast(*_selection.begin()); + if (!n) break; + + PathManipulator &pm = n->nodeList().subpathList().pm(); + + int which = 0; + if (_tracker.rightAlt() || _tracker.rightControl()) { + which = 1; + } + if (_tracker.leftAlt() || _tracker.leftControl()) { + if (which != 0) break; // ambiguous + which = -1; + } + if (which == 0) break; // no handle chosen + bool one_pixel = _tracker.leftAlt() || _tracker.rightAlt(); + + switch (key) { + // single handle functions + // rotation + case GDK_bracketleft: + case GDK_braceleft: + pm.rotateHandle(n, which, 1, one_pixel); + break; + case GDK_bracketright: + case GDK_braceright: + pm.rotateHandle(n, which, -1, one_pixel); + break; + // adjust length + case GDK_period: + case GDK_greater: + pm.scaleHandle(n, which, 1, one_pixel); + break; + case GDK_comma: + case GDK_less: + pm.scaleHandle(n, which, -1, one_pixel); + break; + } + return true; + } while(0); + } + + switch (event->type) { case GDK_KEY_PRESS: - switch (shortcut_key(event->key)) { + switch (key) { case GDK_Insert: case GDK_KP_Insert: // Insert - insert nodes in the middle of selected segments -- cgit v1.2.3 From e46805d62ddb2975490a42c16a44d2232c7dbf37 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 18 Mar 2010 03:59:43 +0100 Subject: Fix a few remaining oddities in handle scaling via keyboard (bzr r9205) --- src/ui/tool/multi-path-manipulator.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/ui/tool/multi-path-manipulator.cpp') diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index fe97058c4..2025a12d7 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -464,6 +464,7 @@ bool MultiPathManipulator::event(GdkEvent *event) } if (which == 0) break; // no handle chosen bool one_pixel = _tracker.leftAlt() || _tracker.rightAlt(); + bool handled = true; switch (key) { // single handle functions @@ -485,8 +486,12 @@ bool MultiPathManipulator::event(GdkEvent *event) case GDK_less: pm.scaleHandle(n, which, -1, one_pixel); break; + default: + handled = false; + break; } - return true; + + if (handled) return true; } while(0); } -- cgit v1.2.3