[calligra/krita-animation-pentikainen] krita: Initial port of the Move Tool to LoD framework

Dmitry Kazakov dimula73 at gmail.com
Fri Sep 4 13:02:04 UTC 2015


Git commit 9402f93d8093b9fa2afcc72583581f9311bc1650 by Dmitry Kazakov.
Committed on 04/09/2015 at 13:01.
Pushed by dkazakov into branch 'krita-animation-pentikainen'.

Initial port of the Move Tool to LoD framework

Known issues:

1) Clone layers are moved incorrectly
2) Shape layers are also moved incorrectly
3) "Move Selection" action is not ported yet, so it is slow.

The rest seem to work fine! :)

CC:kimageshop at kde.org

M  +10   -13   krita/image/kis_group_layer.cc
M  +4    -6    krita/image/kis_stroke_strategy_undo_command_based.cpp
M  +1    -2    krita/image/kis_stroke_strategy_undo_command_based.h
M  +4    -3    krita/plugins/tools/defaulttools/kis_tool_move.cc
M  +1    -1    krita/plugins/tools/defaulttools/kis_tool_move.h
M  +10   -4    krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.cpp
M  +1    -0    krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.h
M  +71   -7    krita/plugins/tools/defaulttools/strokes/move_stroke_strategy.cpp
M  +27   -0    krita/plugins/tools/defaulttools/strokes/move_stroke_strategy.h

http://commits.kde.org/calligra/9402f93d8093b9fa2afcc72583581f9311bc1650

diff --git a/krita/image/kis_group_layer.cc b/krita/image/kis_group_layer.cc
index acefd80..3d8210d 100644
--- a/krita/image/kis_group_layer.cc
+++ b/krita/image/kis_group_layer.cc
@@ -170,15 +170,16 @@ void KisGroupLayer::resetCache(const KoColorSpace *colorSpace)
 
     if (!m_d->paintDevice) {
 
-        m_d->paintDevice = new KisPaintDevice(this, colorSpace, new KisDefaultBounds(image()));
-        m_d->paintDevice->setX(m_d->x);
-        m_d->paintDevice->setY(m_d->y);
+        KisPaintDeviceSP dev = new KisPaintDevice(this, colorSpace, new KisDefaultBounds(image()));
+        dev->setX(this->x());
+        dev->setY(this->y());
+        m_d->paintDevice = dev;
     }
     else if(!(*m_d->paintDevice->colorSpace() == *colorSpace)) {
 
         KisPaintDeviceSP dev = new KisPaintDevice(this, colorSpace, new KisDefaultBounds(image()));
-        dev->setX(m_d->x);
-        dev->setY(m_d->y);
+        dev->setX(this->x());
+        dev->setY(this->y());
         quint8* defaultPixel = new quint8[colorSpace->pixelSize()];
 
         m_d->paintDevice->colorSpace()->
@@ -310,31 +311,27 @@ void KisGroupLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAd
 
 qint32 KisGroupLayer::x() const
 {
-    return m_d->x;
+    return m_d->paintDevice ? m_d->paintDevice->x() : m_d->x;
 }
 
 qint32 KisGroupLayer::y() const
 {
-    return m_d->y;
+    return m_d->paintDevice ? m_d->paintDevice->y() : m_d->y;
 }
 
 void KisGroupLayer::setX(qint32 x)
 {
-    qint32 delta = x - m_d->x;
     m_d->x = x;
     if(m_d->paintDevice) {
-        m_d->paintDevice->setX(m_d->paintDevice->x() + delta);
-        Q_ASSERT(m_d->paintDevice->x() == m_d->x);
+        m_d->paintDevice->setX(x);
     }
 }
 
 void KisGroupLayer::setY(qint32 y)
 {
-    qint32 delta = y - m_d->y;
     m_d->y = y;
     if(m_d->paintDevice) {
-        m_d->paintDevice->setY(m_d->paintDevice->y() + delta);
-        Q_ASSERT(m_d->paintDevice->y() == m_d->y);
+        m_d->paintDevice->setY(y);
     }
 }
 
diff --git a/krita/image/kis_stroke_strategy_undo_command_based.cpp b/krita/image/kis_stroke_strategy_undo_command_based.cpp
index 20541c2..f8f8cd9 100644
--- a/krita/image/kis_stroke_strategy_undo_command_based.cpp
+++ b/krita/image/kis_stroke_strategy_undo_command_based.cpp
@@ -44,16 +44,14 @@ KisStrokeStrategyUndoCommandBased(const KUndo2MagicString &name,
 
 KisStrokeStrategyUndoCommandBased::
 KisStrokeStrategyUndoCommandBased(const KisStrokeStrategyUndoCommandBased &rhs,
-                                  int levelOfDetail)
+                                  bool suppressUndo)
   : KisSimpleStrokeStrategy(rhs),
-    m_supportsLevelOfDetail(rhs.m_supportsLevelOfDetail),
+    m_undo(false),
     m_initCommand(rhs.m_initCommand),
     m_finishCommand(rhs.m_finishCommand),
-    m_undoAdapter(rhs.m_undoAdapter)
+    m_undoAdapter(!suppressUndo ? rhs.m_undoAdapter : 0),
+    m_macroCommand(0)
 {
-    // LOD_MERGE_FIXME:
-    Q_UNUSED(levelOfDetail);
-
     KIS_ASSERT_RECOVER_NOOP(!rhs.m_macroCommand &&
                             !rhs.m_undo &&
                             "After the stroke has been started, no copying must happen");
diff --git a/krita/image/kis_stroke_strategy_undo_command_based.h b/krita/image/kis_stroke_strategy_undo_command_based.h
index af20509..bd9a02f 100644
--- a/krita/image/kis_stroke_strategy_undo_command_based.h
+++ b/krita/image/kis_stroke_strategy_undo_command_based.h
@@ -109,7 +109,7 @@ protected:
                            KisStrokeJobData::Exclusivity exclusivity);
 
     KisStrokeStrategyUndoCommandBased(const KisStrokeStrategyUndoCommandBased &rhs,
-                                      int levelOfDetail);
+                                      bool suppressUndo);
 
     virtual void postProcessToplevelCommand(KUndo2Command *command);
 
@@ -118,7 +118,6 @@ private:
 
 private:
     bool m_undo;
-    bool m_supportsLevelOfDetail;
     KUndo2CommandSP m_initCommand;
     KUndo2CommandSP m_finishCommand;
     KisPostExecutionUndoAdapter *m_undoAdapter;
diff --git a/krita/plugins/tools/defaulttools/kis_tool_move.cc b/krita/plugins/tools/defaulttools/kis_tool_move.cc
index b692b8c..2b9e908 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_move.cc
+++ b/krita/plugins/tools/defaulttools/kis_tool_move.cc
@@ -144,7 +144,6 @@ void KisToolMove::startAction(KoPointerEvent *event, MoveToolMode mode)
 {
     QPoint pos = convertToPixelCoord(event).toPoint();
     m_dragStart = pos;
-    m_lastDragPos = m_dragStart;
     m_moveInProgress = true;
     emit moveInProgressChanged();
 
@@ -200,6 +199,7 @@ void KisToolMove::startAction(KoPointerEvent *event, MoveToolMode mode)
 
     m_strokeId = image->startStroke(strategy);
     m_currentlyProcessingNode = node;
+    m_accumulatedOffset = QPoint();
 }
 
 void KisToolMove::continueAction(KoPointerEvent *event)
@@ -222,14 +222,15 @@ void KisToolMove::endAction(KoPointerEvent *event)
     QPoint pos = convertToPixelCoord(event).toPoint();
     pos = applyModifiers(event->modifiers(), pos);
     drag(pos);
+
+    m_accumulatedOffset += pos - m_dragStart;
 }
 
 void KisToolMove::drag(const QPoint& newPos)
 {
     KisImageWSP image = currentImage();
 
-    QPoint offset = newPos - m_lastDragPos;
-    m_lastDragPos = newPos;
+    QPoint offset = m_accumulatedOffset + newPos - m_dragStart;
 
     image->addJob(m_strokeId,
                   new MoveStrokeStrategy::Data(offset));
diff --git a/krita/plugins/tools/defaulttools/kis_tool_move.h b/krita/plugins/tools/defaulttools/kis_tool_move.h
index eac0e88..367014d 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_move.h
+++ b/krita/plugins/tools/defaulttools/kis_tool_move.h
@@ -104,7 +104,7 @@ private:
     MoveToolOptionsWidget* m_optionsWidget;
 
     QPoint m_dragStart;
-    QPoint m_lastDragPos;
+    QPoint m_accumulatedOffset;
 
     KisStrokeId m_strokeId;
 
diff --git a/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.cpp b/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.cpp
index e2a737c..76e3e35 100644
--- a/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.cpp
+++ b/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.cpp
@@ -69,6 +69,8 @@ void MoveSelectionStrokeStrategy::initStrokeCallback()
     indirect->setTemporaryCompositeOp(paintDevice->colorSpace()->compositeOp(COMPOSITE_OVER));
     indirect->setTemporaryOpacity(OPACITY_OPAQUE_U8);
 
+    m_initialDeviceOffset = QPoint(movedDevice->x(), movedDevice->y());
+
     m_selection->setVisible(false);
 }
 
@@ -128,11 +130,15 @@ void MoveSelectionStrokeStrategy::doStrokeCallback(KisStrokeJobData *data)
         KisPaintDeviceSP movedDevice = indirect->temporaryTarget();
 
         QRegion dirtyRegion = movedDevice->region();
-        dirtyRegion |= dirtyRegion.translated(d->offset);
 
-        movedDevice->setX(movedDevice->x() + d->offset.x());
-        movedDevice->setY(movedDevice->y() + d->offset.y());
-        m_finalOffset += d->offset;
+        QPoint currentDeviceOffset(movedDevice->x(), movedDevice->y());
+        QPoint newDeviceOffset(m_initialDeviceOffset + d->offset);
+
+        dirtyRegion |= dirtyRegion.translated(newDeviceOffset - currentDeviceOffset);
+
+        movedDevice->setX(newDeviceOffset.x());
+        movedDevice->setY(newDeviceOffset.y());
+        m_finalOffset = d->offset;
 
         m_paintLayer->setDirty(dirtyRegion);
     } else {
diff --git a/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.h b/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.h
index 3682c57..6b2edf2 100644
--- a/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.h
+++ b/krita/plugins/tools/defaulttools/strokes/move_selection_stroke_strategy.h
@@ -44,6 +44,7 @@ private:
     KisSelectionSP m_selection;
     KisUpdatesFacade *m_updatesFacade;
     QPoint m_finalOffset;
+    QPoint m_initialDeviceOffset;
 };
 
 #endif /* __MOVE_SELECTION_STROKE_STRATEGY_H */
diff --git a/krita/plugins/tools/defaulttools/strokes/move_stroke_strategy.cpp b/krita/plugins/tools/defaulttools/strokes/move_stroke_strategy.cpp
index 618a166..c8c53d63 100644
--- a/krita/plugins/tools/defaulttools/strokes/move_stroke_strategy.cpp
+++ b/krita/plugins/tools/defaulttools/strokes/move_stroke_strategy.cpp
@@ -30,20 +30,53 @@ MoveStrokeStrategy::MoveStrokeStrategy(KisNodeSP node,
                                        KisPostExecutionUndoAdapter *undoAdapter)
     : KisStrokeStrategyUndoCommandBased(kundo2_i18n("Move"), false, undoAdapter),
       m_node(node),
-      m_updatesFacade(updatesFacade)
+      m_updatesFacade(updatesFacade),
+      m_undoEnabled(true),
+      m_updatesEnabled(true)
 {
     setSupportsWrapAroundMode(true);
 }
 
+MoveStrokeStrategy::MoveStrokeStrategy(const MoveStrokeStrategy &rhs, bool suppressUndo)
+    : KisStrokeStrategyUndoCommandBased(rhs, suppressUndo),
+      m_node(rhs.m_node),
+      m_updatesFacade(rhs.m_updatesFacade),
+      m_finalOffset(rhs.m_finalOffset),
+      m_dirtyRect(rhs.m_dirtyRect),
+      m_undoEnabled(rhs.m_undoEnabled),
+      m_updatesEnabled(rhs.m_updatesEnabled)
+{
+}
+
 void MoveStrokeStrategy::setNode(KisNodeSP node)
 {
     Q_ASSERT(!m_node);
     m_node = node;
 }
 
+void MoveStrokeStrategy::saveInitialNodeOffsets(KisNodeSP node)
+{
+    m_initialNodeOffsets.insert(node, QPoint(node->x(), node->y()));
+
+    KisNodeSP child = node->firstChild();
+    while(child) {
+        saveInitialNodeOffsets(child);
+        child = child->nextSibling();
+    }
+}
+
+void MoveStrokeStrategy::initStrokeCallback()
+{
+    if (m_node) {
+        saveInitialNodeOffsets(m_node);
+    }
+
+    KisStrokeStrategyUndoCommandBased::initStrokeCallback();
+}
+
 void MoveStrokeStrategy::finishStrokeCallback()
 {
-    if(m_node) {
+    if(m_node && m_undoEnabled) {
         KUndo2Command *updateCommand =
             new KisUpdateCommand(m_node, m_dirtyRect, m_updatesFacade, true);
 
@@ -54,6 +87,10 @@ void MoveStrokeStrategy::finishStrokeCallback()
                           KisStrokeJobData::EXCLUSIVE);
     }
 
+    if (m_node && !m_updatesEnabled) {
+        m_updatesFacade->refreshGraphAsync(m_node, m_dirtyRect);
+    }
+
     KisStrokeStrategyUndoCommandBased::finishStrokeCallback();
 }
 
@@ -81,7 +118,7 @@ void MoveStrokeStrategy::doStrokeCallback(KisStrokeJobData *data)
          * NOTE: we do not care about threading here, because
          * all our jobs are declared sequential
          */
-        m_finalOffset += d->offset;
+        m_finalOffset = d->offset;
     }
     else {
         KisStrokeStrategyUndoCommandBased::doStrokeCallback(data);
@@ -93,16 +130,25 @@ void MoveStrokeStrategy::moveAndUpdate(QPoint offset)
     QRect dirtyRect = moveNode(m_node, offset);
     m_dirtyRect |= dirtyRect;
 
-    m_updatesFacade->refreshGraphAsync(m_node, dirtyRect);
+    if (m_updatesEnabled) {
+        m_updatesFacade->refreshGraphAsync(m_node, dirtyRect);
+    }
 }
 
 QRect MoveStrokeStrategy::moveNode(KisNodeSP node, QPoint offset)
 {
     QRect dirtyRect = node->extent();
-    dirtyRect |= dirtyRect.translated(offset);
+    QPoint newOffset = m_initialNodeOffsets[node] + offset;
+
+    /**
+     * Some layers, e.g. clones need an update to change extent(), so
+     * calculate the dirty rect manually
+     */
+    QPoint currentOffset(node->x(), node->y());
+    dirtyRect |= dirtyRect.translated(newOffset - currentOffset);
 
-    node->setX(node->x() + offset.x());
-    node->setY(node->y() + offset.y());
+    node->setX(newOffset.x());
+    node->setY(newOffset.y());
     KisNodeMoveCommand2::tryNotifySelection(node);
 
     KisNodeSP child = node->firstChild();
@@ -126,3 +172,21 @@ void MoveStrokeStrategy::addMoveCommands(KisNodeSP node, KUndo2Command *parent)
         child = child->nextSibling();
     }
 }
+
+void MoveStrokeStrategy::setUndoEnabled(bool value)
+{
+    m_undoEnabled = value;
+}
+
+void MoveStrokeStrategy::setUpdatesEnabled(bool value)
+{
+    m_updatesEnabled = value;
+}
+
+KisStrokeStrategy* MoveStrokeStrategy::createLodClone(int levelOfDetail)
+{
+    MoveStrokeStrategy *clone = new MoveStrokeStrategy(*this, levelOfDetail > 0);
+    clone->setUndoEnabled(false);
+    this->setUpdatesEnabled(false);
+    return clone;
+}
diff --git a/krita/plugins/tools/defaulttools/strokes/move_stroke_strategy.h b/krita/plugins/tools/defaulttools/strokes/move_stroke_strategy.h
index e962a6a..a0bd3b0 100644
--- a/krita/plugins/tools/defaulttools/strokes/move_stroke_strategy.h
+++ b/krita/plugins/tools/defaulttools/strokes/move_stroke_strategy.h
@@ -19,9 +19,12 @@
 #ifndef __MOVE_STROKE_STRATEGY_H
 #define __MOVE_STROKE_STRATEGY_H
 
+#include <QHash>
+
 #include "kis_stroke_strategy_undo_command_based.h"
 #include "kis_types.h"
 #include "kritadefaulttools_export.h"
+#include "kis_lod_transform.h"
 
 class KisUpdatesFacade;
 class KisPostExecutionUndoAdapter;
@@ -37,7 +40,20 @@ public:
               offset(_offset)
         {
         }
+
+        KisStrokeJobData* createLodClone(int levelOfDetail) {
+            return new Data(*this, levelOfDetail);
+        }
+
         QPoint offset;
+
+    private:
+        Data(const Data &rhs, int levelOfDetail)
+            : KisStrokeJobData(rhs)
+        {
+            KisLodTransform t(levelOfDetail);
+            offset = t.map(rhs.offset);
+        }
     };
 
 public:
@@ -54,20 +70,31 @@ public:
 
     void setNode(KisNodeSP node);
 
+    void initStrokeCallback();
     void finishStrokeCallback();
     void cancelStrokeCallback();
     void doStrokeCallback(KisStrokeJobData *data);
 
+    KisStrokeStrategy* createLodClone(int levelOfDetail);
+
+private:
+    MoveStrokeStrategy(const MoveStrokeStrategy &rhs, bool suppressUndo);
+    void setUndoEnabled(bool value);
+    void setUpdatesEnabled(bool value);
 private:
     void moveAndUpdate(QPoint offset);
     QRect moveNode(KisNodeSP node, QPoint offset);
     void addMoveCommands(KisNodeSP node, KUndo2Command *parent);
+    void saveInitialNodeOffsets(KisNodeSP node);
 
 private:
     KisNodeSP m_node;
     KisUpdatesFacade *m_updatesFacade;
     QPoint m_finalOffset;
     QRect m_dirtyRect;
+    bool m_undoEnabled;
+    bool m_updatesEnabled;
+    QHash<KisNodeSP, QPoint> m_initialNodeOffsets;
 };
 
 #endif /* __MOVE_STROKE_STRATEGY_H */


More information about the kimageshop mailing list