[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-kimageshop
Subject:    [krita] krita: Implement D&D of frames across different layers
From:       Dmitry Kazakov <dimula73 () gmail ! com>
Date:       2015-12-11 10:22:43
Message-ID: E1a7KqZ-0001t6-At () scm ! kde ! org
[Download RAW message or body]

Git commit 979701e8278583fb2b76ec960d72ad90e8d517c4 by Dmitry Kazakov.
Committed on 11/12/2015 at 08:49.
Pushed by dkazakov into branch 'master'.

Implement D&D of frames across different layers

It was planned long ago, and now just implemented

CC:kimageshop@kde.org

M  +23   -0    krita/image/kis_keyframe_channel.cpp
M  +2    -0    krita/image/kis_keyframe_channel.h
M  +34   -0    krita/image/kis_paint_device.cc
M  +8    -0    krita/image/kis_paint_device_frames_interface.h
M  +14   -0    krita/image/kis_raster_keyframe_channel.cpp
M  +1    -0    krita/image/kis_raster_keyframe_channel.h
M  +15   -0    krita/image/kis_scalar_keyframe_channel.cpp
M  +1    -0    krita/image/kis_scalar_keyframe_channel.h
M  +111  -0    krita/image/tests/kis_paint_device_test.cpp
M  +2    -0    krita/image/tests/kis_paint_device_test.h
M  +26   -10   krita/plugins/extensions/dockers/animation/kis_animation_utils.cpp
M  +5    -7    krita/plugins/extensions/dockers/animation/timeline_frames_model.cpp

http://commits.kde.org/krita/979701e8278583fb2b76ec960d72ad90e8d517c4

diff --git a/krita/image/kis_keyframe_channel.cpp \
b/krita/image/kis_keyframe_channel.cpp index 89815b0..8ccb6e8 100644
--- a/krita/image/kis_keyframe_channel.cpp
+++ b/krita/image/kis_keyframe_channel.cpp
@@ -415,6 +415,29 @@ KisKeyframeSP KisKeyframeChannel::insertKeyframe(int time, const \
KisKeyframeSP c  return keyframe;
 }
 
+KisKeyframeSP KisKeyframeChannel::copyExternalKeyframe(KisKeyframeChannel \
*srcChannel, int srcTime, int dstTime, KUndo2Command *parentCommand) +{
+    if (srcChannel->id() != id()) {
+        warnKrita << "Cannot copy frames from different ids:" << \
ppVar(srcChannel->id()) << ppVar(id()); +        return KisKeyframeSP();
+    }
+
+    LAZY_INITIALIZE_PARENT_COMMAND(parentCommand);
+
+    KisKeyframeSP dstFrame = keyframeAt(dstTime);
+    if (dstFrame) {
+        deleteKeyframeImpl(dstFrame, parentCommand, false);
+    }
+
+    KisKeyframeSP newKeyframe = createKeyframe(dstTime, KisKeyframeSP(), \
parentCommand); +    uploadExternalKeyframe(srcChannel, srcTime, newKeyframe);
+
+    KUndo2Command *cmd = new InsertFrameCommand(this, newKeyframe, true, \
parentCommand); +    cmd->redo();
+
+    return newKeyframe;
+}
+
 KisKeyframeChannel::KeyframesMap::const_iterator
 KisKeyframeChannel::activeKeyIterator(int time) const
 {
diff --git a/krita/image/kis_keyframe_channel.h b/krita/image/kis_keyframe_channel.h
index ca961ca..7bb5e67 100644
--- a/krita/image/kis_keyframe_channel.h
+++ b/krita/image/kis_keyframe_channel.h
@@ -52,6 +52,7 @@ public:
     bool deleteKeyframe(KisKeyframeSP keyframe, KUndo2Command *parentCommand = 0);
     bool moveKeyframe(KisKeyframeSP keyframe, int newTime, KUndo2Command \
                *parentCommand = 0);
     KisKeyframeSP copyKeyframe(const KisKeyframeSP keyframe, int newTime, \
KUndo2Command *parentCommand = 0); +    KisKeyframeSP \
copyExternalKeyframe(KisKeyframeChannel *srcChannel, int srcTime, int dstTime, \
KUndo2Command *parentCommand = 0);  
     KisKeyframeSP keyframeAt(int time) const;
     KisKeyframeSP activeKeyframeAt(int time) const;
@@ -109,6 +110,7 @@ protected:
 
     virtual KisKeyframeSP createKeyframe(int time, const KisKeyframeSP copySrc, \
                KUndo2Command *parentCommand) = 0;
     virtual void destroyKeyframe(KisKeyframeSP key, KUndo2Command *parentCommand) = \
0; +    virtual void uploadExternalKeyframe(KisKeyframeChannel *srcChannel, int \
srcTime, KisKeyframeSP dstFrame) = 0;  
     virtual QRect affectedRect(KisKeyframeSP key) = 0;
     virtual void requestUpdate(const KisTimeRange &range, const QRect &rect);
diff --git a/krita/image/kis_paint_device.cc b/krita/image/kis_paint_device.cc
index 8daebd7..76dcdb2 100644
--- a/krita/image/kis_paint_device.cc
+++ b/krita/image/kis_paint_device.cc
@@ -319,6 +319,8 @@ public:
     }
 
     void fetchFrame(int frameId, KisPaintDeviceSP targetDevice);
+    void uploadFrame(int srcFrameId, int dstFrameId, KisPaintDeviceSP srcDevice);
+
     QRegion syncLodData(int newLod);
 
     void tesingFetchLodDevice(KisPaintDeviceSP targetDevice);
@@ -636,6 +638,33 @@ void KisPaintDevice::Private::fetchFrame(int frameId, \
KisPaintDeviceSP targetDev  transferFromData(data, targetDevice);
 }
 
+void KisPaintDevice::Private::uploadFrame(int srcFrameId, int dstFrameId, \
KisPaintDeviceSP srcDevice) +{
+    DataSP dstData = m_frames[dstFrameId];
+    KIS_ASSERT_RECOVER_RETURN(dstData);
+
+    DataSP srcData = srcDevice->m_d->m_frames[srcFrameId];
+    KIS_ASSERT_RECOVER_RETURN(srcData);
+
+    if (srcData->colorSpace() != dstData->colorSpace() &&
+        !(*srcData->colorSpace() == *dstData->colorSpace())) {
+
+        KUndo2Command tempCommand;
+
+        srcData = toQShared(new Data(srcData.data(), true));
+        srcData->convertDataColorSpace(dstData->colorSpace(),
+                                       \
KoColorConversionTransformation::internalRenderingIntent(), +                         \
KoColorConversionTransformation::internalConversionFlags(), +                         \
&tempCommand); +    }
+
+    dstData->dataManager()->clear();
+    dstData->cache()->invalidate();
+
+    const QRect rect = srcData->dataManager()->extent();
+    dstData->dataManager()->bitBltRough(srcData->dataManager(), rect);
+}
+
 void KisPaintDevice::Private::tesingFetchLodDevice(KisPaintDeviceSP targetDevice)
 {
     Data *data = m_lodData.data();
@@ -1679,6 +1708,11 @@ void KisPaintDeviceFramesInterface::fetchFrame(int frameId, \
KisPaintDeviceSP tar  q->m_d->fetchFrame(frameId, targetDevice);
 }
 
+void KisPaintDeviceFramesInterface::uploadFrame(int srcFrameId, int dstFrameId, \
KisPaintDeviceSP srcDevice) +{
+    q->m_d->uploadFrame(srcFrameId, dstFrameId, srcDevice);
+}
+
 QRect KisPaintDeviceFramesInterface::frameBounds(int frameId)
 {
     return q->m_d->frameBounds(frameId);
diff --git a/krita/image/kis_paint_device_frames_interface.h \
b/krita/image/kis_paint_device_frames_interface.h index 49388ce..b34dabc 100644
--- a/krita/image/kis_paint_device_frames_interface.h
+++ b/krita/image/kis_paint_device_frames_interface.h
@@ -59,6 +59,14 @@ public:
     void fetchFrame(int frameId, KisPaintDeviceSP targetDevice);
 
     /**
+     * Copy the given paint device contents into the specified frame
+     * @param dstFrameId ID of the frame to be overwritten (must exist)
+     * @param srcFrameId ID of the frame to copy from (must exist)
+     * @param sourceDevice paint device to copy from
+     */
+    void uploadFrame(int srcFrameId, int dstFrameId, KisPaintDeviceSP srcDevice);
+
+    /**
      * @return extent() of \p frameId
      */
     QRect frameBounds(int frameId);
diff --git a/krita/image/kis_raster_keyframe_channel.cpp \
b/krita/image/kis_raster_keyframe_channel.cpp index b46574f..94e4c0c 100644
--- a/krita/image/kis_raster_keyframe_channel.cpp
+++ b/krita/image/kis_raster_keyframe_channel.cpp
@@ -111,6 +111,20 @@ void KisRasterKeyframeChannel::destroyKeyframe(KisKeyframeSP \
                key, KUndo2Command
     m_d->paintDevice->framesInterface()->deleteFrame(key->value(), parentCommand);
 }
 
+void KisRasterKeyframeChannel::uploadExternalKeyframe(KisKeyframeChannel \
*srcChannel, int srcTime, KisKeyframeSP dstFrame) +{
+    KisRasterKeyframeChannel *srcRasterChannel = \
dynamic_cast<KisRasterKeyframeChannel*>(srcChannel); +    \
KIS_ASSERT_RECOVER_RETURN(srcRasterChannel); +
+    const int srcId = srcRasterChannel->frameIdAt(srcTime);
+    const int dstId = dstFrame->value();
+
+    m_d->paintDevice->framesInterface()->
+        uploadFrame(srcId,
+                    dstId,
+                    srcRasterChannel->m_d->paintDevice);
+}
+
 QRect KisRasterKeyframeChannel::affectedRect(KisKeyframeSP key)
 {
     KeyframesMap::iterator it = keys().find(key->time());
diff --git a/krita/image/kis_raster_keyframe_channel.h \
b/krita/image/kis_raster_keyframe_channel.h index f832c55..1505309 100644
--- a/krita/image/kis_raster_keyframe_channel.h
+++ b/krita/image/kis_raster_keyframe_channel.h
@@ -66,6 +66,7 @@ public:
 protected:
     KisKeyframeSP createKeyframe(int time, const KisKeyframeSP copySrc, \
                KUndo2Command *parentCommand);
     void destroyKeyframe(KisKeyframeSP key, KUndo2Command *parentCommand);
+    void uploadExternalKeyframe(KisKeyframeChannel *srcChannel, int srcTime, \
KisKeyframeSP dstFrame);  
     QRect affectedRect(KisKeyframeSP key);
     void requestUpdate(const KisTimeRange &range, const QRect &rect);
diff --git a/krita/image/kis_scalar_keyframe_channel.cpp \
b/krita/image/kis_scalar_keyframe_channel.cpp index 42bfd68..e3d33ae 100644
--- a/krita/image/kis_scalar_keyframe_channel.cpp
+++ b/krita/image/kis_scalar_keyframe_channel.cpp
@@ -163,6 +163,21 @@ void KisScalarKeyframeChannel::destroyKeyframe(KisKeyframeSP \
key, KUndo2Command  cmd->redo();
 }
 
+void KisScalarKeyframeChannel::uploadExternalKeyframe(KisKeyframeChannel \
*srcChannel, int srcTime, KisKeyframeSP dstFrame) +{
+    KisScalarKeyframeChannel *srcScalarChannel = \
dynamic_cast<KisScalarKeyframeChannel*>(srcChannel); +    \
KIS_ASSERT_RECOVER_RETURN(srcScalarChannel); +
+    KisKeyframeSP srcFrame = srcScalarChannel->keyframeAt(srcTime);
+    KIS_ASSERT_RECOVER_RETURN(srcFrame);
+
+    const qreal newValue = scalarValue(srcFrame);
+
+    const int dstId = dstFrame->value();
+    KIS_ASSERT_RECOVER_RETURN(m_d->values.contains(dstId));
+    m_d->values[dstId] = newValue;
+}
+
 QRect KisScalarKeyframeChannel::affectedRect(KisKeyframeSP key)
 {
     Q_UNUSED(key);
diff --git a/krita/image/kis_scalar_keyframe_channel.h \
b/krita/image/kis_scalar_keyframe_channel.h index 206f92e..85b659e 100644
--- a/krita/image/kis_scalar_keyframe_channel.h
+++ b/krita/image/kis_scalar_keyframe_channel.h
@@ -37,6 +37,7 @@ public:
 protected:
     KisKeyframeSP createKeyframe(int time, const KisKeyframeSP copySrc, \
                KUndo2Command *parentCommand);
     void destroyKeyframe(KisKeyframeSP key, KUndo2Command *parentCommand);
+    void uploadExternalKeyframe(KisKeyframeChannel *srcChannel, int srcTime, \
KisKeyframeSP dstFrame);  
     QRect affectedRect(KisKeyframeSP key);
 
diff --git a/krita/image/tests/kis_paint_device_test.cpp \
b/krita/image/tests/kis_paint_device_test.cpp index 840c891..3e48bb9 100644
--- a/krita/image/tests/kis_paint_device_test.cpp
+++ b/krita/image/tests/kis_paint_device_test.cpp
@@ -1912,6 +1912,117 @@ void KisPaintDeviceTest::testFramesUndoRedoWithChannel()
     QVERIFY(o.m_currentData == o.m_frames.begin().value());
 }
 
+void fillRect(KisPaintDeviceSP dev, int time, const QRect &rc, \
TestUtil::TestingTimedDefaultBounds *bounds) +{
+    KUndo2Command parentCommand;
+    KisRasterKeyframeChannel *channel = dev->keyframeChannel();
+    KisKeyframeSP frame = channel->addKeyframe(time, &parentCommand);
+
+    const int oldTime = bounds->currentTime();
+    bounds->testingSetTime(time);
+
+    KoColor color(Qt::red, dev->colorSpace());
+    dev->fill(rc, color);
+
+    bounds->testingSetTime(oldTime);
+}
+
+bool checkRect(KisPaintDeviceSP dev, int time, const QRect &rc, \
TestUtil::TestingTimedDefaultBounds *bounds) +{
+    const int oldTime = bounds->currentTime();
+    bounds->testingSetTime(time);
+
+    bool result = dev->exactBounds() == rc;
+
+    if (!result) {
+        qDebug() << "Failed to check frame:" << ppVar(time) << ppVar(rc) << \
ppVar(dev->exactBounds()); +    }
+
+    bounds->testingSetTime(oldTime);
+
+    return result;
+}
+
+void testCrossDeviceFrameCopyImpl(bool useChannel)
+{
+    const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
+    KisPaintDeviceSP dev1 = new KisPaintDevice(cs);
+    KisPaintDeviceSP dev2 = new KisPaintDevice(cs);
+
+    const KoColorSpace *cs3 = KoColorSpaceRegistry::instance()->rgb16();
+    KisPaintDeviceSP dev3 = new KisPaintDevice(cs3);
+
+    TestUtil::TestingTimedDefaultBounds *bounds = new \
TestUtil::TestingTimedDefaultBounds(); +    dev1->setDefaultBounds(bounds);
+    dev2->setDefaultBounds(bounds);
+    dev3->setDefaultBounds(bounds);
+
+    KisRasterKeyframeChannel *channel1 = \
dev1->createKeyframeChannel(KisKeyframeChannel::Content, 0); +    \
KisPaintDeviceFramesInterface *i1 = dev1->framesInterface(); +    QVERIFY(channel1);
+    QVERIFY(i1);
+
+    KisRasterKeyframeChannel *channel2 = \
dev2->createKeyframeChannel(KisKeyframeChannel::Content, 0); +    \
KisPaintDeviceFramesInterface *i2 = dev2->framesInterface(); +    QVERIFY(channel2);
+    QVERIFY(i2);
+
+    KisRasterKeyframeChannel *channel3 = \
dev3->createKeyframeChannel(KisKeyframeChannel::Content, 0); +    \
KisPaintDeviceFramesInterface *i3 = dev3->framesInterface(); +    QVERIFY(channel3);
+    QVERIFY(i3);
+
+    fillRect(dev1, 10, QRect(100,100,100,100), bounds);
+    fillRect(dev2, 20, QRect(200,200,100,100), bounds);
+    fillRect(dev3, 30, QRect(300,300,100,100), bounds);
+
+    QCOMPARE(dev1->exactBounds(), QRect());
+
+    const int dstFrameId1 = channel1->frameIdAt(10);
+    const int srcFrameId2 = channel2->frameIdAt(20);
+    const int srcFrameId3 = channel3->frameIdAt(30);
+
+    KUndo2Command cmd1;
+    if (!useChannel) {
+        dev1->framesInterface()->uploadFrame(srcFrameId2, dstFrameId1, dev2);
+    } else {
+        KisKeyframeSP k = channel1->copyExternalKeyframe(channel2, 20, 10, &cmd1);
+    }
+
+    QCOMPARE(dev1->exactBounds(), QRect());
+    QVERIFY(checkRect(dev1, 10, QRect(200,200,100,100), bounds));
+
+    if (useChannel) {
+        cmd1.undo();
+        QVERIFY(checkRect(dev1, 10, QRect(100,100,100,100), bounds));
+    }
+
+    KUndo2Command cmd2;
+    if (!useChannel) {
+        dev1->framesInterface()->uploadFrame(srcFrameId3, dstFrameId1, dev3);
+    } else {
+        KisKeyframeSP k = channel1->copyExternalKeyframe(channel3, 30, 10, &cmd2);
+    }
+
+    QCOMPARE(dev1->exactBounds(), QRect());
+    QVERIFY(checkRect(dev1, 10, QRect(300,300,100,100), bounds));
+
+    if (useChannel) {
+        cmd2.undo();
+        QVERIFY(checkRect(dev1, 10, QRect(100,100,100,100), bounds));
+    }
+}
+
+void KisPaintDeviceTest::testCrossDeviceFrameCopyDirect()
+{
+    testCrossDeviceFrameCopyImpl(false);
+}
+
+void KisPaintDeviceTest::testCrossDeviceFrameCopyChannel()
+{
+    testCrossDeviceFrameCopyImpl(true);
+}
+
 #include "kis_surrogate_undo_adapter.h"
 
 void KisPaintDeviceTest::testLazyFrameCreation()
diff --git a/krita/image/tests/kis_paint_device_test.h \
b/krita/image/tests/kis_paint_device_test.h index f193592..9a2c89f 100644
--- a/krita/image/tests/kis_paint_device_test.h
+++ b/krita/image/tests/kis_paint_device_test.h
@@ -71,6 +71,8 @@ private Q_SLOTS:
     void testFramesLeaking();
     void testFramesUndoRedo();
     void testFramesUndoRedoWithChannel();
+    void testCrossDeviceFrameCopyDirect();
+    void testCrossDeviceFrameCopyChannel();
     void testLazyFrameCreation();
 
     void testCompositionAssociativity();
diff --git a/krita/plugins/extensions/dockers/animation/kis_animation_utils.cpp \
b/krita/plugins/extensions/dockers/animation/kis_animation_utils.cpp index \
                861585d..67df50e 100644
--- a/krita/plugins/extensions/dockers/animation/kis_animation_utils.cpp
+++ b/krita/plugins/extensions/dockers/animation/kis_animation_utils.cpp
@@ -154,19 +154,35 @@ namespace KisAnimationUtils {
             const int dstTime = dstFrames[i].time;
             KisNodeSP dstNode = dstFrames[i].node;
 
-            if (srcNode != dstNode) continue;
+            if (srcNode == dstNode) {
+                KisKeyframeChannel *content =
+                    srcNode->getKeyframeChannel(KisKeyframeChannel::Content.id());
+
+                if (!content) continue;
+
+                KisKeyframeSP srcKeyframe = content->keyframeAt(srcTime);
+                if (srcKeyframe) {
+                    if (copy) {
+                        content->copyKeyframe(srcKeyframe, dstTime, cmd.data());
+                    } else {
+                        content->moveKeyframe(srcKeyframe, dstTime, cmd.data());
+                    }
+                }
+            } else {
+                KisKeyframeChannel *srcContent =
+                    srcNode->getKeyframeChannel(KisKeyframeChannel::Content.id());
+                KisKeyframeChannel *dstContent =
+                    dstNode->getKeyframeChannel(KisKeyframeChannel::Content.id());
 
-            KisKeyframeChannel *content =
-                srcNode->getKeyframeChannel(KisKeyframeChannel::Content.id());
+                if (!srcContent || !dstContent) continue;
 
-            if (!content) continue;
+                KisKeyframeSP srcKeyframe = srcContent->keyframeAt(srcTime);
+                if (!srcKeyframe) continue;
+
+                dstContent->copyExternalKeyframe(srcContent, srcTime, dstTime, \
cmd.data());  
-            KisKeyframeSP srcKeyframe = content->keyframeAt(srcTime);
-            if (srcKeyframe) {
-                if (copy) {
-                    content->copyKeyframe(srcKeyframe, dstTime, cmd.data());
-                } else {
-                    content->moveKeyframe(srcKeyframe, dstTime, cmd.data());
+                if (!copy) {
+                    srcContent->deleteKeyframe(srcKeyframe, cmd.data());
                 }
             }
 
diff --git a/krita/plugins/extensions/dockers/animation/timeline_frames_model.cpp \
b/krita/plugins/extensions/dockers/animation/timeline_frames_model.cpp index \
                343fd33..d3fe5a2 100644
--- a/krita/plugins/extensions/dockers/animation/timeline_frames_model.cpp
+++ b/krita/plugins/extensions/dockers/animation/timeline_frames_model.cpp
@@ -604,11 +604,11 @@ bool TimelineFramesModel::canDropFrameData(const QMimeData \
*data, const QModelIn  {
     if (!index.isValid()) return false;
 
-    QByteArray encoded = data->data("application/x-krita-frame");
-    int baseRow, baseColumn;
-    decodeBaseIndex(&encoded, &baseRow, &baseColumn);
-
-    return baseRow == index.row();
+    /**
+     * Now we support D&D around any layer, so just return 'true' all
+     * the time.
+     */
+    return true;
 }
 
 bool TimelineFramesModel::offsetFrames(QVector<QPoint> srcIndexes, const QPoint \
&offset, bool copyFrames) @@ -675,8 +675,6 @@ bool \
TimelineFramesModel::dropMimeData(const QMimeData *data, Qt::DropAction act  int \
size, baseRow, baseColumn;  stream >> size >> baseRow >> baseColumn;
 
-    if (baseRow != parent.row()) return result;
-
     QVector<QPoint> srcIndexes;
 
     for (int i = 0; i < size; i++) {

_______________________________________________
Krita mailing list
kimageshop@kde.org
https://mail.kde.org/mailman/listinfo/kimageshop


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic