index 818bdaedcf4c35940c18c6e033e3f29ada4389b6..c34ef066e48d448a88ce52b642e1830e9315715e 100644 (file)
/** @file
- * Path manipulator - implementation
+ * Multi path manipulator - implementation
*/
/* Authors:
* Krzysztof KosiĆski <tweenk.pl@gmail.com>
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-//#include <tr1/unordered_set>
-#include <ext/hash_set>
+#include <tr1/unordered_set>
#include <boost/shared_ptr.hpp>
#include <glib.h>
#include <glibmm/i18n.h>
#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<Inkscape::UI::NodeList::iterator> {
- size_t operator()(Inkscape::UI::NodeList::iterator const &n) const {
- return reinterpret_cast<size_t>(n.ptr());
- }
-};
-}
+namespace std { using namespace tr1; }
namespace Inkscape {
namespace UI {
namespace {
typedef std::pair<NodeList::iterator, NodeList::iterator> IterPair;
typedef std::vector<IterPair> IterPairList;
-typedef std::hash_set<NodeList::iterator> IterSet;
+typedef std::unordered_set<NodeList::iterator> IterSet;
typedef std::multimap<double, IterPair> DistanceMap;
typedef std::pair<double, IterPair> DistanceMapItem;
// find all endnodes in selection
for (ControlPointSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
- Node *node = dynamic_cast<Node*>(i->first);
+ Node *node = dynamic_cast<Node*>(*i);
if (!node) continue;
NodeList::iterator iter = NodeList::get_iterator(node);
if (!iter.next() || !iter.prev()) join_iters.insert(iter);
// 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));
}
}
{
if (_selection.empty()) return;
for (ControlPointSelection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
- Node *node = dynamic_cast<Node*>(i->first);
+ Node *node = dynamic_cast<Node*>(*i);
if (node) node->setType(type);
}
_done(_("Change node type"));
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);
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)
_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) {
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;
}
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;
}
case GDK_b:
case GDK_B:
if (held_only_shift(event->key)) {
+ // Shift+B - break nodes
breakNodes();
return true;
}
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;
}
case GDK_s:
case GDK_S:
if (held_only_shift(event->key)) {
+ // Shift+S - make nodes smooth
setNodeType(NODE_SMOOTH);
return true;
}
case GDK_a:
case GDK_A:
if (held_only_shift(event->key)) {
+ // Shift+A - make nodes auto-smooth
setNodeType(NODE_AUTO);
return true;
}
case GDK_y:
case GDK_Y:
if (held_only_shift(event->key)) {
+ // Shift+Y - make nodes symmetric
setNodeType(NODE_SYMMETRIC);
return true;
}
case GDK_r:
case GDK_R:
if (held_only_shift(event->key)) {
+ // Shift+R - reverse subpaths
reverseSubpaths();
- break;
}
break;
default: