[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