Commit 3014d62c authored by Dmitry Kazakov's avatar Dmitry Kazakov

FEATURE: actions for rotate/scale/mirror/shear selection

Now Rotate/Scale/Mirror/Shear Layer actions also support
handling a selection. If there is a selection active, then
the action will transform selected content only.

Now there are also 8 new actions, that will rotate/scale/
mirror/shear *all* layers without resizing the image. These
actions can also handle selections.

Animation Note:

* when no selection present, the actions transform *all*
  the frames of the layers in question

* when there is a selection active, only current frame
  is transformed

BUG:365595
Ref T3920
CC:kimageshop@kde.org
parent 6069c8a3
......@@ -3303,6 +3303,102 @@
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="mirrorAllNodesX">
<icon>symmetry-horizontal</icon>
<text>Mirror All Layers Hori&amp;zontally</text>
<whatsThis></whatsThis>
<toolTip>Mirror All Layers Horizontally</toolTip>
<iconText>Mirror All Layers Horizontally</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="mirrorAllNodesY">
<icon>symmetry-vertical</icon>
<text>Mirror All Layers &amp;Vertically</text>
<whatsThis></whatsThis>
<toolTip>Mirror All Layers Vertically</toolTip>
<iconText>Mirror All Layers Vertically</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="rotateAllLayers">
<icon></icon>
<text>&amp;Rotate All Layers...</text>
<whatsThis></whatsThis>
<toolTip>Rotate All Layers</toolTip>
<iconText>Rotate All Layers</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="rotateAllLayersCW90">
<icon>object-rotate-right</icon>
<text>Rotate All &amp;Layers 90° to the Right</text>
<whatsThis></whatsThis>
<toolTip>Rotate All Layers 90° to the Right</toolTip>
<iconText>Rotate All Layers 90° to the Right</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="rotateAllLayersCCW90">
<icon>object-rotate-left</icon>
<text>Rotate All Layers &amp;90° to the Left</text>
<whatsThis></whatsThis>
<toolTip>Rotate All Layers 90° to the Left</toolTip>
<iconText>Rotate All Layers 90° to the Left</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="rotateAllLayers180">
<icon></icon>
<text>Rotate All Layers &amp;180°</text>
<whatsThis></whatsThis>
<toolTip>Rotate All Layers 180°</toolTip>
<iconText>Rotate All Layers 180°</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="scaleAllLayers">
<icon></icon>
<text>Scale All &amp;Layers to new Size...</text>
<whatsThis></whatsThis>
<toolTip>Scale All Layers to new Size</toolTip>
<iconText>Scale All Layers to new Size</iconText>
<activationFlags>100000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="shearAllLayers">
<icon></icon>
<text>&amp;Shear All Layers...</text>
<whatsThis></whatsThis>
<toolTip>Shear All Layers</toolTip>
<iconText>Shear All Layers</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="offsetlayer">
<icon></icon>
<text>&amp;Offset Layer...</text>
......
......@@ -236,6 +236,21 @@ xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0 http://www.kde.org
<Action name="shearlayer"/>
<Action name="offsetlayer"/>
</Menu>
<Menu name="LayerTransformAll">
<text>Transform &amp;All Layers</text>
<Action name="mirrorAllNodesX"/>
<Action name="mirrorAllNodesY"/>
<Action name="scaleAllLayers"/>
<Menu name="Rotate">
<text>&amp;Rotate</text>
<Action name="rotateAllLayers"/>
<Separator/>
<Action name="rotateAllLayersCW90"/>
<Action name="rotateAllLayersCCW90"/>
<Action name="rotateAllLayers180"/>
</Menu>
<Action name="shearAllLayers"/>
</Menu>
<Menu name="LayerSplitAlpha">
<text>S&amp;plit</text>
<Menu name="LayerSplitAlpha">
......
......@@ -110,12 +110,14 @@ set(kritaimage_LIB_SRCS
commands_new/kis_switch_current_time_command.cpp
commands_new/kis_change_projection_color_command.cpp
commands_new/kis_activate_selection_mask_command.cpp
commands_new/kis_transaction_based_command.cpp
processing/kis_do_nothing_processing_visitor.cpp
processing/kis_simple_processing_visitor.cpp
processing/kis_crop_processing_visitor.cpp
processing/kis_crop_selections_processing_visitor.cpp
processing/kis_transform_processing_visitor.cpp
processing/kis_mirror_processing_visitor.cpp
processing/KisSelectionBasedProcessingHelper.cpp
filter/kis_filter.cc
filter/kis_filter_category_ids.cpp
filter/kis_filter_configuration.cc
......
......@@ -19,10 +19,10 @@
#ifndef KIS_TRANSACTION_BASED_COMMAND_H
#define KIS_TRANSACTION_BASED_COMMAND_H
#include <kritaui_export.h>
#include <kritaimage_export.h>
#include <kundo2command.h>
class KRITAUI_EXPORT KisTransactionBasedCommand : public KUndo2Command
class KRITAIMAGE_EXPORT KisTransactionBasedCommand : public KUndo2Command
{
public:
KisTransactionBasedCommand(const KUndo2MagicString &text = KUndo2MagicString(), KUndo2Command *parent = 0);
......
......@@ -741,33 +741,64 @@ void KisImage::scaleImage(const QSize &size, qreal xres, qreal yres, KisFilterSt
applicator.end();
}
void KisImage::scaleNode(KisNodeSP node, qreal scaleX, qreal scaleY, KisFilterStrategy *filterStrategy)
void KisImage::scaleNode(KisNodeSP node, const QPointF &center, qreal scaleX, qreal scaleY, KisFilterStrategy *filterStrategy, KisSelectionSP selection)
{
KUndo2MagicString actionName(kundo2_i18n("Scale Layer"));
KisImageSignalVector emitSignals;
emitSignals << ModifiedSignal;
QPointF offset;
{
KisTransformWorker worker(0,
scaleX, scaleY,
0, 0, 0, 0,
0.0,
0, 0, 0, 0);
QTransform transform = worker.transform();
offset = center - transform.map(center);
}
KisProcessingApplicator applicator(this, node,
KisProcessingApplicator::RECURSIVE,
emitSignals, actionName);
KisProcessingVisitorSP visitor =
KisTransformProcessingVisitor *visitor =
new KisTransformProcessingVisitor(scaleX, scaleY,
0, 0,
QPointF(),
0,
0, 0,
offset.x(), offset.y(),
filterStrategy);
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
visitor->setSelection(selection);
if (selection) {
applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT);
} else {
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
}
applicator.end();
}
void KisImage::rotateImpl(const KUndo2MagicString &actionName,
KisNodeSP rootNode,
double radians,
bool resizeImage,
double radians)
KisSelectionSP selection)
{
// we can either transform (and resize) the whole image or
// transform a selection, we cannot do both at the same time
KIS_SAFE_ASSERT_RECOVER(!(bool(selection) && resizeImage)) {
selection = 0;
}
const QRect baseBounds =
resizeImage ? bounds() :
selection ? selection->selectedExactRect() :
rootNode->exactBounds();
QPointF offset;
QSize newSize;
......@@ -780,12 +811,12 @@ void KisImage::rotateImpl(const KUndo2MagicString &actionName,
QTransform transform = worker.transform();
if (resizeImage) {
QRect newRect = transform.mapRect(bounds());
QRect newRect = transform.mapRect(baseBounds);
newSize = newRect.size();
offset = -newRect.topLeft();
}
else {
QPointF origin = QRectF(rootNode->exactBounds()).center();
QPointF origin = QRectF(baseBounds).center();
newSize = size();
offset = -(transform.map(origin) - origin);
......@@ -793,11 +824,12 @@ void KisImage::rotateImpl(const KUndo2MagicString &actionName,
}
bool sizeChanged = resizeImage &&
(newSize.width() != width() || newSize.height() != height());
(newSize.width() != baseBounds.width() ||
newSize.height() != baseBounds.height());
// These signals will be emitted after processing is done
KisImageSignalVector emitSignals;
if (sizeChanged) emitSignals << ComplexSizeChangedSignal(bounds(), newSize);
if (sizeChanged) emitSignals << ComplexSizeChangedSignal(baseBounds, newSize);
emitSignals << ModifiedSignal;
// These flags determine whether updates are transferred to the UI during processing
......@@ -813,14 +845,21 @@ void KisImage::rotateImpl(const KUndo2MagicString &actionName,
KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value("Bicubic");
KisProcessingVisitorSP visitor =
KisTransformProcessingVisitor *visitor =
new KisTransformProcessingVisitor(1.0, 1.0, 0.0, 0.0,
QPointF(),
radians,
offset.x(), offset.y(),
filter);
if (selection) {
visitor->setSelection(selection);
}
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
if (selection) {
applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT);
} else {
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
}
if (sizeChanged) {
applicator.applyCommand(new KisImageResizeCommand(this, newSize));
......@@ -831,15 +870,15 @@ void KisImage::rotateImpl(const KUndo2MagicString &actionName,
void KisImage::rotateImage(double radians)
{
rotateImpl(kundo2_i18n("Rotate Image"), root(), true, radians);
rotateImpl(kundo2_i18n("Rotate Image"), root(), radians, true, 0);
}
void KisImage::rotateNode(KisNodeSP node, double radians)
void KisImage::rotateNode(KisNodeSP node, double radians, KisSelectionSP selection)
{
if (node->inherits("KisMask")) {
rotateImpl(kundo2_i18n("Rotate Mask"), node, false, radians);
rotateImpl(kundo2_i18n("Rotate Mask"), node, radians, false, selection);
} else {
rotateImpl(kundo2_i18n("Rotate Layer"), node, false, radians);
rotateImpl(kundo2_i18n("Rotate Layer"), node, radians, false, selection);
}
}
......@@ -847,8 +886,15 @@ void KisImage::shearImpl(const KUndo2MagicString &actionName,
KisNodeSP rootNode,
bool resizeImage,
double angleX, double angleY,
const QPointF &origin)
KisSelectionSP selection)
{
const QRect baseBounds =
resizeImage ? bounds() :
selection ? selection->selectedExactRect() :
rootNode->exactBounds();
const QPointF origin = QRectF(baseBounds).center();
//angleX, angleY are in degrees
const qreal pi = 3.1415926535897932385;
const qreal deg2rad = pi / 180.0;
......@@ -866,15 +912,15 @@ void KisImage::shearImpl(const KUndo2MagicString &actionName,
0,
0, 0, 0, 0);
QRect newRect = worker.transform().mapRect(bounds());
QRect newRect = worker.transform().mapRect(baseBounds);
newSize = newRect.size();
if (resizeImage) offset = -newRect.topLeft();
}
if (newSize == size()) return;
if (newSize == baseBounds.size()) return;
KisImageSignalVector emitSignals;
if (resizeImage) emitSignals << ComplexSizeChangedSignal(bounds(), newSize);
if (resizeImage) emitSignals << ComplexSizeChangedSignal(baseBounds, newSize);
emitSignals << ModifiedSignal;
KisProcessingApplicator::ProcessingFlags signalFlags =
......@@ -887,14 +933,22 @@ void KisImage::shearImpl(const KUndo2MagicString &actionName,
KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value("Bilinear");
KisProcessingVisitorSP visitor =
KisTransformProcessingVisitor *visitor =
new KisTransformProcessingVisitor(1.0, 1.0,
tanX, tanY, origin,
0,
offset.x(), offset.y(),
filter);
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
if (selection) {
visitor->setSelection(selection);
}
if (selection) {
applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT);
} else {
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
}
if (resizeImage) {
applicator.applyCommand(new KisImageResizeCommand(this, newSize));
......@@ -903,23 +957,21 @@ void KisImage::shearImpl(const KUndo2MagicString &actionName,
applicator.end();
}
void KisImage::shearNode(KisNodeSP node, double angleX, double angleY)
void KisImage::shearNode(KisNodeSP node, double angleX, double angleY, KisSelectionSP selection)
{
QPointF shearOrigin = QRectF(bounds()).center();
if (node->inherits("KisMask")) {
shearImpl(kundo2_i18n("Shear Mask"), node, false,
angleX, angleY, shearOrigin);
angleX, angleY, selection);
} else {
shearImpl(kundo2_i18n("Shear Layer"), node, false,
angleX, angleY, shearOrigin);
angleX, angleY, selection);
}
}
void KisImage::shear(double angleX, double angleY)
{
shearImpl(kundo2_i18n("Shear Image"), m_d->rootLayer, true,
angleX, angleY, QPointF());
angleX, angleY, 0);
}
void KisImage::convertImageColorSpace(const KoColorSpace *dstColorSpace,
......
......@@ -285,7 +285,7 @@ public:
* a background, so you cannot expect the image having new size
* right after ths call.
*/
void scaleNode(KisNodeSP node, qreal scaleX, qreal scaleY, KisFilterStrategy *filterStrategy);
void scaleNode(KisNodeSP node, const QPointF &center, qreal scaleX, qreal scaleY, KisFilterStrategy *filterStrategy, KisSelectionSP selection);
/**
* @brief start asynchronous operation on rotating the image
......@@ -312,7 +312,7 @@ public:
* a background, so you cannot expect the operation being completed
* right after the call
*/
void rotateNode(KisNodeSP node, double radians);
void rotateNode(KisNodeSP node, double radians, KisSelectionSP selection);
/**
* @brief start asynchronous operation on shearing the image
......@@ -339,7 +339,7 @@ public:
* a background, so you cannot expect the operation being completed
* right after the call
*/
void shearNode(KisNodeSP node, double angleX, double angleY);
void shearNode(KisNodeSP node, double angleX, double angleY, KisSelectionSP selection);
/**
* Convert the image and all its layers to the dstColorSpace
......@@ -1066,11 +1066,10 @@ private:
void emitSizeChanged();
void resizeImageImpl(const QRect& newRect, bool cropLayers);
void rotateImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode,
bool resizeImage, double radians);
void rotateImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, double radians,
bool resizeImage, KisSelectionSP selection);
void shearImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode,
bool resizeImage, double angleX, double angleY,
const QPointF &origin);
bool resizeImage, double angleX, double angleY, KisSelectionSP selection);
void safeRemoveTwoNodes(KisNodeSP node1, KisNodeSP node2);
......
......@@ -207,6 +207,12 @@ void KisProcessingApplicator::applyVisitor(KisProcessingVisitorSP visitor,
KisStrokeJobData::Sequentiality sequentiality,
KisStrokeJobData::Exclusivity exclusivity)
{
KUndo2Command *initCommand = visitor->createInitCommand();
if (initCommand) {
applyCommand(initCommand,
KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::NORMAL);
}
if(!m_flags.testFlag(RECURSIVE)) {
applyCommand(new KisProcessingCommand(visitor, m_node),
sequentiality, exclusivity);
......@@ -220,6 +226,12 @@ void KisProcessingApplicator::applyVisitorAllFrames(KisProcessingVisitorSP visit
KisStrokeJobData::Sequentiality sequentiality,
KisStrokeJobData::Exclusivity exclusivity)
{
KUndo2Command *initCommand = visitor->createInitCommand();
if (initCommand) {
applyCommand(initCommand,
KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::NORMAL);
}
KisLayerUtils::FrameJobs jobs;
// TODO: implement a nonrecursive case when !m_flags.testFlag(RECURSIVE)
......
......@@ -56,3 +56,8 @@ KoUpdater* KisProcessingVisitor::ProgressHelper::updater() const
KisProcessingVisitor::~KisProcessingVisitor()
{
}
KUndo2Command *KisProcessingVisitor::createInitCommand()
{
return 0;
}
......@@ -39,6 +39,7 @@ class KisTransparencyMask;
class KisSelectionMask;
class KisGeneratorLayer;
class KisColorizeMask;
class KUndo2Command;
/**
* A visitor that processes a single layer; it does not recurse into the
......@@ -63,6 +64,13 @@ public:
virtual void visit(KisColorizeMask *mask, KisUndoAdapter *undoAdapter) = 0;
virtual void visit(KisSelectionMask *mask, KisUndoAdapter *undoAdapter) = 0;
/**
* Create a command that initializes the processing visitor before running
* on all the layers. The command is executed sequentially, non-exclusively
* on the image by applicator.
*/
virtual KUndo2Command* createInitCommand();
public:
class KRITAIMAGE_EXPORT ProgressHelper {
public:
......
#include "KisSelectionBasedProcessingHelper.h"
#include "kis_paint_device.h"
#include "kis_painter.h"
#include "kis_selection.h"
#include "kis_transaction_based_command.h"
#include "kis_transaction.h"
#include "kis_undo_adapter.h"
KisSelectionBasedProcessingHelper::KisSelectionBasedProcessingHelper(KisSelectionSP selection, Functor func)
: m_selection(selection),
m_func(func)
{
}
void KisSelectionBasedProcessingHelper::setSelection(KisSelectionSP selection)
{
m_selection = selection;
}
KUndo2Command *KisSelectionBasedProcessingHelper::createInitCommand(Functor func)
{
if (!m_selection) return 0;
struct ProcessSelectionCommand : KisTransactionBasedCommand {
ProcessSelectionCommand(KisSelectionSP selection,
KisSelectionSP cutSelection,
std::function<void(KisPaintDeviceSP)> func)
: m_selection(selection),
m_cutSelection(cutSelection),
m_func(func)
{
}
KUndo2Command* paint() {
m_cutSelection->pixelSelection()->makeCloneFromRough(m_selection->pixelSelection(), m_selection->selectedRect());
KisTransaction t(m_selection->pixelSelection());
m_func(m_selection->pixelSelection());
return t.endAndTake();
}
KisSelectionSP m_selection;
KisSelectionSP m_cutSelection;
Functor m_func;
};
m_cutSelection = new KisSelection();
return new ProcessSelectionCommand(m_selection, m_cutSelection, func);
}
KUndo2Command *KisSelectionBasedProcessingHelper::createInitCommand()
{
return createInitCommand(m_func);
}
void KisSelectionBasedProcessingHelper::transformPaintDevice(KisPaintDeviceSP device, KisUndoAdapter *undoAdapter)
{
transformPaintDevice(device, undoAdapter, m_func);
}
void KisSelectionBasedProcessingHelper::transformPaintDevice(KisPaintDeviceSP device, KisUndoAdapter *undoAdapter, Functor func)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(!!m_selection == !!m_cutSelection);
if (m_selection && m_cutSelection) {
// we have already processed the selection in the init command so try to skip it
if (device != static_cast<KisPaintDevice*>(m_selection->pixelSelection().data())) {
KisTransaction transaction(device);
const QRect cutBounds = m_cutSelection->selectedExactRect();
const QRect pasteBounds = m_selection->selectedExactRect();
KisPaintDeviceSP tempDev = new KisPaintDevice(device->colorSpace());
tempDev->makeCloneFromRough(device, cutBounds);
func(tempDev);
device->clearSelection(m_cutSelection);
KisPainter::copyAreaOptimized(pasteBounds.topLeft(), tempDev, device, pasteBounds, m_selection);
transaction.commit(undoAdapter);
}
} else {
KisTransaction transaction(device);
func(device);
transaction.commit(undoAdapter);
}
}
#ifndef KISSELECTIONBASEDPROCESSINGHELPER_H
#define KISSELECTIONBASEDPROCESSINGHELPER_H
#include "kritaimage_export.h"
#include "kis_types.h"
#include <functional>
#include <QRect>
class KisUndoAdapter;
class KisSelectionBasedProcessingHelper
{
public:
using Functor = std::function<void(KisPaintDeviceSP)>;
public:
KisSelectionBasedProcessingHelper(KisSelectionSP selection, Functor func);
void setSelection(KisSelectionSP selection);
KUndo2Command *createInitCommand();
KUndo2Command *createInitCommand(Functor func);
void transformPaintDevice(KisPaintDeviceSP device, KisUndoAdapter *undoAdapter);
void transformPaintDevice(KisPaintDeviceSP device, KisUndoAdapter *undoAdapter, Functor func);
private:
KisSelectionSP m_selection;
KisSelectionSP m_cutSelection;
Functor m_func;
};
#endif // KISSELECTIONBASEDPROCESSINGHELPER_H
......@@ -22,33 +22,50 @@
#include "kis_transaction.h"
#include "kis_node.h"
#include "kis_image.h"
#include "kis_painter.h"
#include "kis_transform_worker.h"
#include "lazybrush/kis_colorize_mask.h"
#include "processing/kis_transform_processing_visitor.h"
#include "commands_new/kis_transaction_based_command.h"
#include <functional>
KisMirrorProcessingVisitor::KisMirrorProcessingVisitor(const QRect &bounds, Qt::Orientation orientation)
: m_bounds(bounds), m_orientation(orientation)
: m_bounds(bounds),
m_orientation(orientation),
m_selectionHelper(0, std::bind(&KisMirrorProcessingVisitor::mirrorDevice, this, std::placeholders::_1))
{
m_axis = m_orientation == Qt::Horizontal ?
m_bounds.x() + 0.5 * m_bounds.width() :
m_bounds.y() + 0.5 * m_bounds.height();
}
void KisMirrorProcessingVisitor::transformPaintDevice(KisPaintDeviceSP device, KisUndoAdapter *undoAdapter)
KisMirrorProcessingVisitor::KisMirrorProcessingVisitor(KisSelectionSP selection, Qt::Orientation orientation)
: KisMirrorProcessingVisitor(selection->selectedExactRect(), orientation)
{
KisTransaction transaction(device);
m_selectionHelper.setSelection(selection);
}
qreal axis = m_orientation == Qt::Horizontal ?
m_bounds.x() + 0.5 * m_bounds.width() :
m_bounds.y() + 0.5 * m_bounds.height();
KUndo2Command *KisMirrorProcessingVisitor::createInitCommand()
{
return m_selectionHelper.createInitCommand();
}
KisTransformWorker::mirror(device, axis, m_orientation);
transaction.commit(undoAdapter);
void KisMirrorProcessingVisitor::mirrorDevice(KisPaintDeviceSP device)
{
KisTransformWorker::mirror(device, m_axis, m_orientation);
}
void KisMirrorProcessingVisitor::transformPaintDevice(KisPaintDeviceSP device, KisUndoAdapter *undoAdapter)
{
m_selectionHelper.transformPaintDevice(device, undoAdapter);
}
void KisMirrorProcessingVisitor::visitNodeWithPaintDevice(KisNode *node, KisUndoAdapter *undoAdapter)
{
transformPaintDevice(node->paintDevice(), undoAdapter);
}
void KisMirrorProcessingVisitor::visitExternalLayer(KisExternalLayer *layer, KisUndoAdapter *undoAdapter)
......
......@@ -23,11 +23,14 @@
#include <QRect>
#include "kis_types.h"
#include "KisSelectionBasedProcessingHelper.h"
class KRITAIMAGE_EXPORT KisMirrorProcessingVisitor : public KisSimpleProcessingVisitor
{
public:
KisMirrorProcessingVisitor(const QRect &bounds, Qt::Orientation orientation);
KisMirrorProcessingVisitor(KisSelectionSP selection, Qt::Orientation orientation);
private:
void visitNodeWithPaintDevice(KisNode *node, KisUndoAdapter *undoAdapter) override;
......@@ -35,11 +38,18 @@ private:
void visitColorizeMask(KisColorizeMask *node, KisUndoAdapter *undoAdapter) override;
KUndo2Command* createInitCommand() override;
void mirrorDevice(KisPaintDeviceSP device);
private:
void transformPaintDevice(KisPaintDeviceSP device, KisUndoAdapter *undoAdapter);
QRect m_bounds;
Qt::Orientation m_orientation;
qreal m_axis = 0.0;
KisSelectionBasedProcessingHelper m_selectionHelper;
};