[krita/kazakov/svg-loading] libs/flake: Implement two modes of selecting shapes

Dmitry Kazakov null at kde.org
Tue Dec 27 13:28:09 UTC 2016


Git commit 5a9c73990f5cd91d7d82a2704cce900d5ce40bd0 by Dmitry Kazakov.
Committed on 27/12/2016 at 10:26.
Pushed by dkazakov into branch 'kazakov/svg-loading'.

Implement two modes of selecting shapes

1) Left-to-right mode selects only shapes that that completely inside
   the selection frame.
2) Right-to-left mode selects the shapes that are crossed by the frame.
3) Blue frame means "covering" (or "containing") selection
4) Green frame means "crossing" selection
5) TODO: make two cursors/icons for the two modes, so people could
         understand it without reading the manual.

See point 4A in the requirements for the details:
https://phabricator.kde.org/w/krita/vector_tool_requirements/

CC:kimageshop at kde.org

M  +42   -0    libs/flake/KoRTree.h
M  +21   -10   libs/flake/KoShapeManager.cpp
M  +1    -1    libs/flake/KoShapeManager.h
M  +33   -10   libs/flake/tools/KoShapeRubberSelectStrategy.cpp
M  +10   -0    libs/flake/tools/KoShapeRubberSelectStrategy.h
M  +5    -0    libs/flake/tools/KoZoomStrategy.cpp
M  +3    -0    libs/flake/tools/KoZoomStrategy.h

https://commits.kde.org/krita/5a9c73990f5cd91d7d82a2704cce900d5ce40bd0

diff --git a/libs/flake/KoRTree.h b/libs/flake/KoRTree.h
index bcc8fa4ba5b..0675f80c5be 100644
--- a/libs/flake/KoRTree.h
+++ b/libs/flake/KoRTree.h
@@ -105,6 +105,16 @@ public:
     QList<T> contains(const QPointF &point) const;
 
     /**
+     * @brief Find all data item which contain the point
+     * The items are sorted by insertion time in ascending order.
+     *
+     * @param point which should be contained in the objects
+     *
+     * @return objects which contain the point
+     */
+    QList<T> contained(const QRectF &point) const;
+
+    /**
      * @brief Find all data rectangles
      * The order is NOT guaranteed to be the same as that used by values().
      *
@@ -162,6 +172,7 @@ protected:
 
         virtual void intersects(const QRectF& rect, QMap<int, T> & result) const = 0;
         virtual void contains(const QPointF & point, QMap<int, T> & result) const = 0;
+        virtual void contained(const QRectF & point, QMap<int, T> & result) const = 0;
 
         virtual void keys(QList<QRectF> & result) const = 0;
         virtual void values(QMap<int, T> & result) const = 0;
@@ -252,6 +263,7 @@ class NonLeafNode : virtual public Node
 
         virtual void intersects(const QRectF& rect, QMap<int, T> & result) const;
         virtual void contains(const QPointF & point, QMap<int, T> & result) const;
+        virtual void contained(const QRectF & point, QMap<int, T> & result) const;
 
         virtual void keys(QList<QRectF> & result) const;
         virtual void values(QMap<int, T> & result) const;
@@ -286,6 +298,7 @@ class LeafNode : virtual public Node
 
         virtual void intersects(const QRectF& rect, QMap<int, T> & result) const;
         virtual void contains(const QPointF & point, QMap<int, T> & result) const;
+        virtual void contained(const QRectF & point, QMap<int, T> & result) const;
 
         virtual void keys(QList<QRectF> & result) const;
         virtual void values(QMap<int, T> & result) const;
@@ -471,6 +484,15 @@ QList<T> KoRTree<T>::contains(const QPointF &point) const
 }
 
 template <typename T>
+QList<T> KoRTree<T>::contained(const QRectF& rect) const
+{
+    QMap<int, T> found;
+    m_root->contained(rect, found);
+    return found.values();
+}
+
+
+template <typename T>
 QList<QRectF> KoRTree<T>::keys() const
 {
     QList<QRectF> found;
@@ -871,6 +893,16 @@ void KoRTree<T>::NonLeafNode::contains(const QPointF & point, QMap<int, T> & res
 }
 
 template <typename T>
+void KoRTree<T>::NonLeafNode::contained(const QRectF& rect, QMap<int, T> & result) const
+{
+    for (int i = 0; i < this->m_counter; ++i) {
+        if (this->m_childBoundingBox[i].intersects(rect)) {
+            m_childs[i]->contained(rect, result);
+        }
+    }
+}
+
+template <typename T>
 void KoRTree<T>::NonLeafNode::keys(QList<QRectF> & result) const
 {
     for (int i = 0; i < this->m_counter; ++i) {
@@ -1041,6 +1073,16 @@ void KoRTree<T>::LeafNode::contains(const QPointF & point, QMap<int, T> & result
 }
 
 template <typename T>
+void KoRTree<T>::LeafNode::contained(const QRectF& rect, QMap<int, T> & result) const
+{
+    for (int i = 0; i < this->m_counter; ++i) {
+        if (rect.contains(this->m_childBoundingBox[i])) {
+            result.insert(m_dataIds[i], m_data[i]);
+        }
+    }
+}
+
+template <typename T>
 void KoRTree<T>::LeafNode::keys(QList<QRectF> & result) const
 {
     for (int i = 0; i < this->m_counter; ++i) {
diff --git a/libs/flake/KoShapeManager.cpp b/libs/flake/KoShapeManager.cpp
index 5f8f8cdc06a..691d6c4b69b 100644
--- a/libs/flake/KoShapeManager.cpp
+++ b/libs/flake/KoShapeManager.cpp
@@ -497,25 +497,36 @@ KoShape *KoShapeManager::shapeAt(const QPointF &position, KoFlake::ShapeSelectio
     return 0; // missed everything
 }
 
-QList<KoShape *> KoShapeManager::shapesAt(const QRectF &rect, bool omitHiddenShapes)
+QList<KoShape *> KoShapeManager::shapesAt(const QRectF &rect, bool omitHiddenShapes, bool containedMode)
 { 
     d->updateTree();
-    QList<KoShape*> intersectedShapes(d->tree.intersects(rect));
-    
-    for (int count = intersectedShapes.count() - 1; count >= 0; count--) {
+    QList<KoShape*> shapes(containedMode ? d->tree.contained(rect) : d->tree.intersects(rect));
+
+    for (int count = shapes.count() - 1; count >= 0; count--) {
      
-        KoShape *shape = intersectedShapes.at(count);
+        KoShape *shape = shapes.at(count);
        
-        if (omitHiddenShapes && ! shape->isVisible(true)) {
-            intersectedShapes.removeAt(count);
+        if (omitHiddenShapes && !shape->isVisible(true)) {
+            shapes.removeAt(count);
         } else {
             const QPainterPath outline = shape->absoluteTransformation(0).map(shape->outline());
-            if (! outline.intersects(rect) && ! outline.contains(rect)) { 
-                intersectedShapes.removeAt(count);
+
+            if (!containedMode && !outline.intersects(rect) && !outline.contains(rect)) {
+                shapes.removeAt(count);
+
+            } else if (containedMode) {
+
+                QPainterPath containingPath;
+                containingPath.addRect(rect);
+
+                if (!containingPath.contains(outline)) {
+                    shapes.removeAt(count);
+                }
             }
         }
     }
-    return intersectedShapes;
+
+    return shapes;
 }
 
 void KoShapeManager::update(QRectF &rect, const KoShape *shape, bool selectionHandles)
diff --git a/libs/flake/KoShapeManager.h b/libs/flake/KoShapeManager.h
index c5f3128f42f..ca164c82bbd 100644
--- a/libs/flake/KoShapeManager.h
+++ b/libs/flake/KoShapeManager.h
@@ -147,7 +147,7 @@ public:
      * @param rect the rectangle in the document coordinate system.
      * @param omitHiddenShapes if true, only visible shapes are considered
      */
-    QList<KoShape *> shapesAt(const QRectF &rect, bool omitHiddenShapes = true);
+    QList<KoShape *> shapesAt(const QRectF &rect, bool omitHiddenShapes = true, bool containedMode = false);
 
     /**
      * Request a repaint to be queued.
diff --git a/libs/flake/tools/KoShapeRubberSelectStrategy.cpp b/libs/flake/tools/KoShapeRubberSelectStrategy.cpp
index 0b0a0e8a3d4..727c5d5d6c0 100644
--- a/libs/flake/tools/KoShapeRubberSelectStrategy.cpp
+++ b/libs/flake/tools/KoShapeRubberSelectStrategy.cpp
@@ -29,6 +29,7 @@
 #include "KoSelection.h"
 #include "KoCanvasBase.h"
 
+
 KoShapeRubberSelectStrategy::KoShapeRubberSelectStrategy(KoToolBase *tool, const QPointF &clicked, bool useSnapToGrid)
     : KoInteractionStrategy(*(new KoShapeRubberSelectStrategyPrivate(tool)))
 {
@@ -44,14 +45,23 @@ void KoShapeRubberSelectStrategy::paint(QPainter &painter, const KoViewConverter
     Q_D(KoShapeRubberSelectStrategy);
     painter.setRenderHint(QPainter::Antialiasing, false);
 
-    QColor selectColor(Qt::blue);   // TODO make configurable
-    selectColor.setAlphaF(0.5);
-    QBrush sb(selectColor, Qt::SolidPattern);
-    painter.setPen(QPen(sb, 0));
-    painter.setBrush(sb);
+    const QColor crossingColor(80,130,8);
+    const QColor coveringColor(8,60,167);
+
+    QColor selectColor(
+        currentMode() == CrossingSelection ?
+        crossingColor : coveringColor);
+
+    selectColor.setAlphaF(0.8);
+    painter.setPen(QPen(selectColor, 0));
+
+    selectColor.setAlphaF(0.4);
+    const QBrush fillBrush(selectColor);
+    painter.setBrush(fillBrush);
+
     QRectF paintRect = converter.documentToView(d->selectedRect());
     paintRect = paintRect.normalized();
-    paintRect.adjust(0., -0.5, 0.5, 0.);
+
     painter.drawRect(paintRect);
 }
 
@@ -59,7 +69,7 @@ void KoShapeRubberSelectStrategy::handleMouseMove(const QPointF &p, Qt::Keyboard
 {
     Q_D(KoShapeRubberSelectStrategy);
     QPointF point = d->snapGuide->snap(p, modifiers);
-    if ((modifiers & Qt::AltModifier) != 0) {
+    if (modifiers & Qt::AltModifier || modifiers & Qt::ControlModifier) {
         d->tool->canvas()->updateCanvas(d->selectedRect());
         d->selectRect.moveTopLeft(d->selectRect.topLeft() - (d->lastPos - point));
         d->lastPos = point;
@@ -101,16 +111,29 @@ void KoShapeRubberSelectStrategy::finishInteraction(Qt::KeyboardModifiers modifi
     Q_D(KoShapeRubberSelectStrategy);
     Q_UNUSED(modifiers);
     KoSelection * selection = d->tool->canvas()->shapeManager()->selection();
-    QList<KoShape *> shapes(d->tool->canvas()->shapeManager()->shapesAt(d->selectRect));
+
+    const bool useContainedMode = currentMode() == CoveringSelection;
+
+    QList<KoShape *> shapes =
+        d->tool->canvas()->shapeManager()->
+            shapesAt(d->selectedRect(), true, useContainedMode);
+
     Q_FOREACH (KoShape * shape, shapes) {
-        if (!(shape->isSelectable() && shape->isVisible()))
-            continue;
+        if (!shape->isSelectable()) continue;
+
         selection->select(shape);
     }
+
     d->tool->repaintDecorations();
     d->tool->canvas()->updateCanvas(d->selectedRect());
 }
 
+KoShapeRubberSelectStrategy::SelectionMode KoShapeRubberSelectStrategy::currentMode() const
+{
+    Q_D(const KoShapeRubberSelectStrategy);
+    return d->selectRect.left() < d->selectRect.right() ? CoveringSelection : CrossingSelection;
+}
+
 KUndo2Command *KoShapeRubberSelectStrategy::createCommand()
 {
     return 0;
diff --git a/libs/flake/tools/KoShapeRubberSelectStrategy.h b/libs/flake/tools/KoShapeRubberSelectStrategy.h
index f0ec46fc3b7..5981814e133 100644
--- a/libs/flake/tools/KoShapeRubberSelectStrategy.h
+++ b/libs/flake/tools/KoShapeRubberSelectStrategy.h
@@ -33,6 +33,9 @@ class KoShapeRubberSelectStrategyPrivate;
 
 /**
  * Implement the rubber band selection of flake objects.
+ *
+ * When the user selects stuff in left-to-right way, selection is in "covering"
+ * (or "containing") mode, when in "left-to-right" in "crossing" mode
  */
 class KRITAFLAKE_EXPORT KoShapeRubberSelectStrategy : public KoInteractionStrategy
 {
@@ -57,6 +60,13 @@ protected:
     /// constructor
     KoShapeRubberSelectStrategy(KoShapeRubberSelectStrategyPrivate &);
 
+    enum SelectionMode {
+        CrossingSelection,
+        CoveringSelection
+    };
+
+    virtual SelectionMode currentMode() const;
+
 private:
     Q_DECLARE_PRIVATE(KoShapeRubberSelectStrategy)
 };
diff --git a/libs/flake/tools/KoZoomStrategy.cpp b/libs/flake/tools/KoZoomStrategy.cpp
index f4c22ed984a..36dd71ac039 100644
--- a/libs/flake/tools/KoZoomStrategy.cpp
+++ b/libs/flake/tools/KoZoomStrategy.cpp
@@ -60,6 +60,11 @@ void KoZoomStrategy::cancelInteraction()
     d->tool->canvas()->updateCanvas(d->selectedRect().toRect().normalized());
 }
 
+KoShapeRubberSelectStrategy::SelectionMode KoZoomStrategy::currentMode() const
+{
+    return CoveringSelection;
+}
+
 void KoZoomStrategy::forceZoomOut()
 {
     m_forceZoomOut = true;
diff --git a/libs/flake/tools/KoZoomStrategy.h b/libs/flake/tools/KoZoomStrategy.h
index 1db4d09d914..bff94e6e2bb 100644
--- a/libs/flake/tools/KoZoomStrategy.h
+++ b/libs/flake/tools/KoZoomStrategy.h
@@ -46,6 +46,9 @@ public:
     /// Execute the zoom
     virtual void finishInteraction(Qt::KeyboardModifiers modifiers);
     virtual void cancelInteraction();
+
+protected:
+    SelectionMode currentMode() const override;
 private:
     KoCanvasController *m_controller;
 



More information about the kimageshop mailing list