Code

Node tool: fix Tab and Shift+Tab
authorKrzysztof Kosiński <tweenk.pl@gmail.com>
Thu, 16 Dec 2010 23:01:36 +0000 (00:01 +0100)
committerKrzysztof Kosiński <tweenk.pl@gmail.com>
Thu, 16 Dec 2010 23:01:36 +0000 (00:01 +0100)
src/ui/tool/multi-path-manipulator.cpp
src/ui/tool/path-manipulator.cpp
src/ui/tool/path-manipulator.h

index 5f60f117a3d0ceb32aa4dfb5e03d58799613e9dc..082ac194b962e85a2501f99120814896689fbd27 100644 (file)
@@ -210,7 +210,78 @@ void MultiPathManipulator::selectSubpaths()
 
 void MultiPathManipulator::shiftSelection(int dir)
 {
-    invokeForAll(&PathManipulator::shiftSelection, dir);
+    if (empty()) return;
+
+    // 1. find last selected node
+    // 2. select the next node; if the last node or nothing is selected,
+    //    select first node
+    MapType::iterator last_i;
+    SubpathList::iterator last_j;
+    NodeList::iterator last_k;
+    bool anything_found = false;
+
+    for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) {
+        SubpathList &sp = i->second->subpathList();
+        for (SubpathList::iterator j = sp.begin(); j != sp.end(); ++j) {
+            for (NodeList::iterator k = (*j)->begin(); k != (*j)->end(); ++k) {
+                if (k->selected()) {
+                    last_i = i;
+                    last_j = j;
+                    last_k = k;
+                    anything_found = true;
+                    // when tabbing backwards, we want the first node
+                    if (dir == -1) goto exit_loop;
+                }
+            }
+        }
+    }
+    exit_loop:
+
+    // NOTE: we should not assume the _selection contains only nodes
+    // in future it might also contain handles and other types of control points
+    // this is why we use a flag instead in the loop above, instead of calling
+    // selection.empty()
+    if (!anything_found) {
+        // select first / last node
+        // this should never fail because there must be at least 1 non-empty manipulator
+        if (dir == 1) {
+            _selection.insert((*_mmap.begin()->second->subpathList().begin())->begin().ptr());
+        } else {
+            _selection.insert((--(*--(--_mmap.end())->second->subpathList().end())->end()).ptr());
+        }
+        return;
+    }
+
+    // three levels deep - w00t!
+    if (dir == 1) {
+        if (++last_k == (*last_j)->end()) {
+            // here, last_k points to the node to be selected
+            ++last_j;
+            if (last_j == last_i->second->subpathList().end()) {
+                ++last_i;
+                if (last_i == _mmap.end()) {
+                    last_i = _mmap.begin();
+                }
+                last_j = last_i->second->subpathList().begin();
+            }
+            last_k = (*last_j)->begin();
+        }
+    } else {
+        if (!last_k || last_k == (*last_j)->begin()) {
+            if (last_j == last_i->second->subpathList().begin()) {
+                if (last_i == _mmap.begin()) {
+                    last_i = _mmap.end();
+                }
+                --last_i;
+                last_j = last_i->second->subpathList().end();
+            }
+            --last_j;
+            last_k = (*last_j)->end();
+        }
+        --last_k;
+    }
+    _selection.clear();
+    _selection.insert(last_k.ptr());
 }
 
 void MultiPathManipulator::invertSelectionInSubpaths()
index 5ae9c4137255c7ab9cc1db66f7cb700045190448..7c60efbabbef193183547e4583c8d0daa0a9e626 100644 (file)
@@ -215,7 +215,7 @@ void PathManipulator::clear()
 /** Select all nodes in subpaths that have something selected. */
 void PathManipulator::selectSubpaths()
 {
-    for (std::list<SubpathPtr>::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
+    for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
         NodeList::iterator sp_start = (*i)->begin(), sp_end = (*i)->end();
         for (NodeList::iterator j = sp_start; j != sp_end; ++j) {
             if (j->selected()) {
@@ -229,63 +229,6 @@ void PathManipulator::selectSubpaths()
     }
 }
 
-/** Move the selection forward or backward by one node in each subpath, based on the sign
- * of the parameter. */
-void PathManipulator::shiftSelection(int dir)
-{
-    if (dir == 0) return;
-    if (_num_selected == 0) {
-        // select the first node of the path.
-        SubpathList::iterator s = _subpaths.begin();
-        if (s == _subpaths.end()) return;
-        NodeList::iterator n = (*s)->begin();
-        if (n != (*s)->end())
-            _selection.insert(n.ptr());
-        return;
-    }
-    // We cannot do any tricks here, like iterating in different directions based on
-    // the sign and only setting the selection of nodes behind us, because it would break
-    // for closed paths.
-    for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
-        std::deque<bool> sels; // I hope this is specialized for bools!
-        unsigned num = 0;
-        
-        for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
-            sels.push_back(j->selected());
-            _selection.erase(j.ptr());
-            ++num;
-        }
-        if (num == 0) continue; // should never happen! zero-node subpaths are not allowed
-
-        num = 0;
-        // In closed subpath, shift the selection cyclically. In an open one,
-        // let the selection 'slide into nothing' at ends.
-        if (dir > 0) {
-            if ((*i)->closed()) {
-                bool last = sels.back();
-                sels.pop_back();
-                sels.push_front(last);
-            } else {
-                sels.push_front(false);
-            }
-        } else {
-            if ((*i)->closed()) {
-                bool first = sels.front();
-                sels.pop_front();
-                sels.push_back(first);
-            } else {
-                sels.push_back(false);
-                num = 1;
-            }
-        }
-
-        for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
-            if (sels[num]) _selection.insert(j.ptr());
-            ++num;
-        }
-    }
-}
-
 /** Invert selection in the selected subpaths. */
 void PathManipulator::invertSelectionInSubpaths()
 {
index 87b88fc77495bfb4c141bb2a936eec1f1d968d53..8a0167e595111ff38785cce37c9fe1bbc8e859d5 100644 (file)
@@ -65,7 +65,6 @@ public:
     SPPath *item() { return _path; }
 
     void selectSubpaths();
-    void shiftSelection(int dir);
     void invertSelectionInSubpaths();
 
     void insertNodes();
@@ -94,6 +93,9 @@ public:
     NodeList::iterator extremeNode(NodeList::iterator origin, bool search_selected,
         bool search_unselected, bool closest);
 
+    // this is necessary for Tab-selection in MultiPathManipulator
+    SubpathList &subpathList() { return _subpaths; }
+
     static bool is_item_type(void *item);
 private:
     typedef NodeList Subpath;