Commit adafa8b7 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Fix transforming layers that have Onion Skins enabled

The patch implements a concept of KisDecoratedNodeInterface. All layers
that spit decorations data into the layers stack should inherit from it
and handle the requests properly.

BUG:408152
parent 938bf9ec
......@@ -141,6 +141,7 @@ set(kritaimage_LIB_SRCS
lazybrush/kis_colorize_stroke_strategy.cpp
KisDelayedUpdateNodeInterface.cpp
KisCroppedOriginalLayerInterface.cpp
KisDecoratedNodeInterface.cpp
kis_adjustment_layer.cc
kis_selection_based_layer.cpp
kis_node_filter_interface.cpp
......
/*
* Copyright (c) 2019 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "KisDecoratedNodeInterface.h"
KisDecoratedNodeInterface::~KisDecoratedNodeInterface()
{
}
void KisDecoratedNodeInterface::setDecorationsVisible(bool value)
{
setDecorationsVisible(value, true);
}
/*
* Copyright (c) 2019 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KISDECORATEDNODEINTERFACE_H
#define KISDECORATEDNODEINTERFACE_H
#include "kritaimage_export.h"
/**
* A special interface for layer that have a "decorations",
* that is, a data that is written into layer stack, but is
* not a part of user's image.
*/
class KRITAIMAGE_EXPORT KisDecoratedNodeInterface
{
public:
virtual ~KisDecoratedNodeInterface();
/**
* \return true is the layer is allowed to write
* its decorative information into the stack. The
* value should be "true" by default.
*/
virtual bool decorationsVisible() const = 0;
/**
* Enable or disable writing decorative information into
* layer stack.
*/
virtual void setDecorationsVisible(bool value, bool update) = 0;
/**
* Convenience override for setDecorationsVisible()
*/
void setDecorationsVisible(bool value);
};
#endif // KISDECORATEDNODEINTERFACE_H
......@@ -59,6 +59,8 @@ public:
KisSignalAutoConnectionsStore onionSkinConnection;
KisOnionSkinCache onionSkinCache;
bool onionSkinVisibleOverride = true;
};
KisPaintLayer::KisPaintLayer(KisImageWSP image, const QString& name, quint8 opacity, KisPaintDeviceSP dev)
......@@ -163,6 +165,7 @@ void KisPaintLayer::copyOriginalToProjection(const KisPaintDeviceSP original,
if (m_d->contentChannel &&
m_d->contentChannel->keyframeCount() > 1 &&
onionSkinEnabled() &&
m_d->onionSkinVisibleOverride &&
!m_d->paintDevice->defaultBounds()->externalFrameActive()) {
KisPaintDeviceSP skins = m_d->onionSkinCache.projection(m_d->paintDevice);
......@@ -248,7 +251,7 @@ QRect KisPaintLayer::extent() const
{
KisPaintDeviceSP t = temporaryTarget();
QRect rect = t ? t->extent() : QRect();
if (onionSkinEnabled()) rect |= KisOnionSkinCompositor::instance()->calculateExtent(m_d->paintDevice);
if (onionSkinEnabled() && m_d->onionSkinVisibleOverride) rect |= KisOnionSkinCompositor::instance()->calculateExtent(m_d->paintDevice);
return rect | KisLayer::extent();
}
......@@ -256,7 +259,7 @@ QRect KisPaintLayer::exactBounds() const
{
KisPaintDeviceSP t = temporaryTarget();
QRect rect = t ? t->extent() : QRect();
if (onionSkinEnabled()) rect |= KisOnionSkinCompositor::instance()->calculateExtent(m_d->paintDevice);
if (onionSkinEnabled() && m_d->onionSkinVisibleOverride) rect |= KisOnionSkinCompositor::instance()->calculateExtent(m_d->paintDevice);
return rect | KisLayer::exactBounds();
}
......@@ -345,3 +348,21 @@ KisPaintDeviceList KisPaintLayer::getLodCapableDevices() const
return list;
}
bool KisPaintLayer::decorationsVisible() const
{
return m_d->onionSkinVisibleOverride;
}
void KisPaintLayer::setDecorationsVisible(bool value, bool update)
{
if (value == decorationsVisible()) return;
const QRect oldExtent = extent();
m_d->onionSkinVisibleOverride = value;
if (update) {
setDirty(oldExtent | extent());
}
}
......@@ -22,6 +22,7 @@
#include "kis_types.h"
#include "kis_layer.h"
#include "kis_indirect_painting_support.h"
#include "KisDecoratedNodeInterface.h"
#include <QBitArray>
......@@ -36,7 +37,7 @@ class KoColorSpace;
* The transparency mask has two rendering forms: as a selection mask
* and by changing the transparency of the paint layer's pixels.
*/
class KRITAIMAGE_EXPORT KisPaintLayer : public KisLayer, public KisIndirectPaintingSupport
class KRITAIMAGE_EXPORT KisPaintLayer : public KisLayer, public KisIndirectPaintingSupport, public KisDecoratedNodeInterface
{
Q_OBJECT
......@@ -145,6 +146,10 @@ public:
KisPaintDeviceList getLodCapableDevices() const override;
bool decorationsVisible() const override;
void setDecorationsVisible(bool value, bool update) override;
using KisDecoratedNodeInterface::setDecorationsVisible;
public Q_SLOTS:
void slotExternalUpdateOnionSkins();
......
......@@ -290,6 +290,24 @@ void KisSelectionMask::notifySelectionChangedCompressed()
m_d->updatesCompressor->start();
}
bool KisSelectionMask::decorationsVisible() const
{
return selection()->isVisible();
}
void KisSelectionMask::setDecorationsVisible(bool value, bool update)
{
if (value == decorationsVisible()) return;
const QRect oldExtent = extent();
selection()->setVisible(value);
if (update) {
setDirty(oldExtent | extent());
}
}
void KisSelectionMask::flattenSelectionProjection(KisSelectionSP selection, const QRect &dirtyRect) const
{
Q_UNUSED(selection);
......
......@@ -24,13 +24,14 @@
#include "kis_types.h"
#include "kis_effect_mask.h"
#include "KisDecoratedNodeInterface.h"
/**
* An selection mask is a single channel mask that applies a
* particular selection to the layer the mask belongs to. A selection
* can contain both vector and pixel selection components.
*/
class KRITAIMAGE_EXPORT KisSelectionMask : public KisEffectMask
class KRITAIMAGE_EXPORT KisSelectionMask : public KisEffectMask, public KisDecoratedNodeInterface
{
Q_OBJECT
public:
......@@ -76,6 +77,10 @@ public:
*/
void notifySelectionChangedCompressed();
bool decorationsVisible() const override;
void setDecorationsVisible(bool value, bool update) override;
using KisDecoratedNodeInterface::setDecorationsVisible;
protected:
void flattenSelectionProjection(KisSelectionSP selection, const QRect &dirtyRect) const override;
......
......@@ -51,6 +51,7 @@
#include "kis_command_ids.h"
#include "KisRunnableStrokeJobUtils.h"
#include "commands_new/KisHoldUIUpdatesCommand.h"
#include "KisDecoratedNodeInterface.h"
TransformStrokeStrategy::TransformStrokeStrategy(ToolTransformArgs::TransformMode mode,
......@@ -525,12 +526,10 @@ void TransformStrokeStrategy::initStrokeCallback()
KisSelectionMaskSP overlaySelectionMask =
dynamic_cast<KisSelectionMask*>(m_rootNode->graphListener()->graphOverlayNode());
if (overlaySelectionMask) {
overlaySelectionMask->selection()->setVisible(false);
overlaySelectionMask->setDirty();
overlaySelectionMask->setDecorationsVisible(false);
m_deactivatedOverlaySelectionMask = overlaySelectionMask;
}
ToolTransformArgs initialTransformArgs;
m_processedNodes = fetchNodesList(m_mode, m_rootNode, m_workRecursively);
......@@ -568,6 +567,19 @@ void TransformStrokeStrategy::initStrokeCallback()
KisLayerUtils::forceAllDelayedNodesUpdate(m_rootNode);
});
/// Disable all decorated nodes to generate outline
/// and preview correctly. We will enable them back
/// as soon as preview generation is finished.
KritaUtils::addJobBarrier(extraInitJobs, [this]() {
Q_FOREACH (KisNodeSP node, m_processedNodes) {
KisDecoratedNodeInterface *decoratedNode = dynamic_cast<KisDecoratedNodeInterface*>(node.data());
if (decoratedNode && decoratedNode->decorationsVisible()) {
decoratedNode->setDecorationsVisible(false);
m_disabledDecoratedNodes << decoratedNode;
}
}
});
KritaUtils::addJobBarrier(extraInitJobs, [this, initialTransformArgs, argsAreInitialized]() mutable {
QRect srcRect;
......@@ -605,6 +617,14 @@ void TransformStrokeStrategy::initStrokeCallback()
extraInitJobs << new ClearSelectionData(node);
}
/// recover back visibility of decorated nodes
KritaUtils::addJobBarrier(extraInitJobs, [this]() {
Q_FOREACH (KisDecoratedNodeInterface *decoratedNode, m_disabledDecoratedNodes) {
decoratedNode->setDecorationsVisible(true);
}
m_disabledDecoratedNodes.clear();
});
extraInitJobs << new Data(toQShared(new KisHoldUIUpdatesCommand(m_updatesFacade, KisCommandUtils::FlipFlopCommand::FINALIZING)), false, KisStrokeJobData::BARRIER);
if (!lastCommandUndoJobs.isEmpty()) {
......
......@@ -33,6 +33,7 @@
class KisPostExecutionUndoAdapter;
class TransformTransactionProperties;
class KisUpdatesFacade;
class KisDecoratedNodeInterface;
class TransformStrokeStrategy : public QObject, public KisStrokeStrategyUndoCommandBased
......@@ -168,6 +169,7 @@ private:
QList<KisSelectionSP> m_deactivatedSelections;
QList<KisNodeSP> m_hiddenProjectionLeaves;
KisSelectionMaskSP m_deactivatedOverlaySelectionMask;
QVector<KisDecoratedNodeInterface*> m_disabledDecoratedNodes;
const KisSavedMacroCommand *m_overriddenCommand = 0;
QVector<const KUndo2Command*> m_skippedWhileMergeCommands;
......
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