Commit 19c31d4f authored by Dmitry Kazakov's avatar Dmitry Kazakov
Browse files

Implement proper undo/redo for KisOverlayPaintDeviceWrapper

It fixes the artifacts after using undo during painting with
lightness mode of the colorsmudge brush.
parent 1a09c5e5
......@@ -155,3 +155,14 @@ bool KisRectsGrid::contains(const QRect &rc) const
return true;
}
QRect KisRectsGrid::boundingRect() const {
QRect gridBounds;
for (int y = m_mappedAreaSize.y(); y <= m_mappedAreaSize.bottom(); y++) {
for (int x = m_mappedAreaSize.x(); x <= m_mappedAreaSize.right(); x++) {
gridBounds |= QRect(x, y, 1, 1);
}
}
return KisLodTransformBase::upscaledRect(gridBounds, m_logGridSize);
}
......@@ -26,6 +26,8 @@ public:
bool contains(const QRect &rc) const;
QRect boundingRect() const;
private:
void resize(const QRect &newMappedAreaSize);
static QRect shrinkRectToAlignedGrid(const QRect &srcRect, int lod);
......
......@@ -15,6 +15,12 @@
#include "KisRegion.h"
#include "kis_wrapped_rect.h"
#include <KoOptimizedRgbPixelDataScalerU8ToU16Factory.h>
#include <kundo2command.h>
#include <memory>
#include <kis_transaction.h>
#include "kis_command_utils.h"
struct KisChangeOverlayWrapperCommand;
struct KisOverlayPaintDeviceWrapper::Private
{
......@@ -24,6 +30,36 @@ struct KisOverlayPaintDeviceWrapper::Private
bool usePreciseMode = false;
QScopedPointer<KoOptimizedRgbPixelDataScalerU8ToU16Base> scaler;
KisPaintDeviceSP externalDestination;
QScopedPointer<KUndo2Command> rootTransactionData;
KisChangeOverlayWrapperCommand *changeOverlayCommand;
std::vector<std::unique_ptr<KisTransaction>> overlayTransactions;
QSharedPointer<KisRectsGrid> previousGrid;
};
struct KisChangeOverlayWrapperCommand : public KUndo2Command
{
KisChangeOverlayWrapperCommand(KisOverlayPaintDeviceWrapper::Private *d, KUndo2Command *parent = 0)
: KUndo2Command(parent)
, m_d(d)
{
}
void undo() override {
KUndo2Command::undo();
m_d->grid = *m_oldRectsGrid;
m_d->previousGrid = m_oldRectsGrid;
}
void redo() override {
KUndo2Command::redo();
m_d->grid = *m_newRectsGrid;
m_d->previousGrid = m_newRectsGrid;
}
QSharedPointer<KisRectsGrid> m_oldRectsGrid;
QSharedPointer<KisRectsGrid> m_newRectsGrid;
KisOverlayPaintDeviceWrapper::Private *m_d;
};
......@@ -234,3 +270,47 @@ KisPaintDeviceSP KisOverlayPaintDeviceWrapper::createPreciseCompositionSourceDev
return result;
}
void KisOverlayPaintDeviceWrapper::beginTransaction(KUndo2Command *parent)
{
KIS_SAFE_ASSERT_RECOVER(!m_d->rootTransactionData) {
m_d->rootTransactionData.reset();
}
if (!m_d->previousGrid) {
m_d->previousGrid.reset(new KisRectsGrid(m_d->grid));
}
m_d->rootTransactionData.reset(new KUndo2Command(parent));
m_d->changeOverlayCommand = new KisChangeOverlayWrapperCommand(m_d.data());
(void) new KisCommandUtils::SkipFirstRedoWrapper(m_d->changeOverlayCommand, m_d->rootTransactionData.data());
m_d->changeOverlayCommand->m_oldRectsGrid = m_d->previousGrid;
for (const auto &overlayDevice : m_d->overlays) {
m_d->overlayTransactions.emplace_back(new KisTransaction(overlayDevice, m_d->rootTransactionData.data()));
}
}
KUndo2Command *KisOverlayPaintDeviceWrapper::endTransaction()
{
KUndo2Command *result = nullptr;
KIS_SAFE_ASSERT_RECOVER(m_d->rootTransactionData) {
m_d->overlayTransactions.clear();
return result;
}
m_d->previousGrid.reset(new KisRectsGrid(m_d->grid));
m_d->changeOverlayCommand->m_newRectsGrid = m_d->previousGrid;
result = m_d->rootTransactionData.take();
for (auto &transactionPtr : m_d->overlayTransactions) {
// the transactions are assigned as children to m_d->changeOverlayCommand
(void) transactionPtr->endAndTake();
}
m_d->overlayTransactions.clear();
return result;
}
......@@ -124,8 +124,12 @@ public:
*/
KisPaintDeviceSP createPreciseCompositionSourceDevice();
void beginTransaction(KUndo2Command *parent = 0);
KUndo2Command *endTransaction();
private:
friend struct KisChangeOverlayWrapperCommand;
struct Private;
const QScopedPointer<Private> m_d;
};
......
......@@ -22,7 +22,9 @@ KisColorSmudgeInterstrokeData::KisColorSmudgeInterstrokeData(KisPaintDeviceSP so
KisColorSmudgeInterstrokeData::~KisColorSmudgeInterstrokeData()
{
KIS_SAFE_ASSERT_RECOVER_NOOP(!m_parentCommand);
KIS_SAFE_ASSERT_RECOVER(!m_parentCommand) {
(void) overlayDeviceWrapper.endTransaction();
}
}
void KisColorSmudgeInterstrokeData::beginTransaction()
......@@ -30,9 +32,8 @@ void KisColorSmudgeInterstrokeData::beginTransaction()
KIS_SAFE_ASSERT_RECOVER_RETURN(!m_parentCommand);
m_parentCommand.reset(new KUndo2Command());
m_colorBlendDeviceTransaction.reset(new KisTransaction(colorBlendDevice, m_parentCommand.data()));
m_heightmapDeviceTransaction.reset(new KisTransaction(heightmapDevice, m_parentCommand.data()));
m_projectionDeviceTransaction.reset(new KisTransaction(projectionDevice, m_parentCommand.data()));
overlayDeviceWrapper.beginTransaction(m_parentCommand.data());
}
KUndo2Command *KisColorSmudgeInterstrokeData::endTransaction()
......@@ -40,9 +41,8 @@ KUndo2Command *KisColorSmudgeInterstrokeData::endTransaction()
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_parentCommand, 0);
// the internal undo commands are owned by m_parentCommand
(void) m_colorBlendDeviceTransaction->endAndTake();
(void) m_heightmapDeviceTransaction->endAndTake();
(void) m_projectionDeviceTransaction->endAndTake();
(void) overlayDeviceWrapper.endTransaction();
return m_parentCommand.take();
}
......@@ -29,9 +29,7 @@ struct KisColorSmudgeInterstrokeData : public KisInterstrokeData
private:
QScopedPointer<KUndo2Command> m_parentCommand;
QScopedPointer<KisTransaction> m_colorBlendDeviceTransaction;
QScopedPointer<KisTransaction> m_heightmapDeviceTransaction;
QScopedPointer<KisTransaction> m_projectionDeviceTransaction;
};
#endif //KRITA_KISCOLORSMUDGEINTERSTROKEDATA_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment