File indexing completed on 2024-06-23 04:28:24

0001 /*
0002  *  SPDX-FileCopyrightText: 2013 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef __INPLACE_TRANSFORM_STROKE_STRATEGY_H
0008 #define __INPLACE_TRANSFORM_STROKE_STRATEGY_H
0009 
0010 #include <QObject>
0011 #include <QMutex>
0012 #include <QElapsedTimer>
0013 #include <KoUpdater.h>
0014 #include <kis_stroke_strategy_undo_command_based.h>
0015 #include <kis_types.h>
0016 #include "tool_transform_args.h"
0017 #include <kritatooltransform_export.h>
0018 
0019 #include <transform_transaction_properties.h>
0020 
0021 #include "KisAsynchronousStrokeUpdateHelper.h"
0022 #include <commands_new/KisUpdateCommandEx.h>
0023 
0024 class KisPostExecutionUndoAdapter;
0025 class TransformTransactionProperties;
0026 class KisUpdatesFacade;
0027 class KisDecoratedNodeInterface;
0028 
0029 
0030 class InplaceTransformStrokeStrategy : public QObject, public KisStrokeStrategyUndoCommandBased
0031 {
0032     Q_OBJECT
0033 public:
0034     class UpdateTransformData : public KisStrokeJobData {
0035     public:
0036         enum Destination {
0037             PAINT_DEVICE,
0038             SELECTION,
0039         };
0040 
0041     public:
0042         UpdateTransformData(ToolTransformArgs _args, Destination _dest)
0043             : KisStrokeJobData(SEQUENTIAL, NORMAL),
0044               args(_args),
0045               destination(_dest)
0046         {}
0047 
0048         KisStrokeJobData* createLodClone(int levelOfDetail) override {
0049             return new UpdateTransformData(*this, levelOfDetail);
0050         }
0051 
0052     private:
0053         UpdateTransformData(const UpdateTransformData &rhs, int levelOfDetail)
0054             : KisStrokeJobData(rhs),
0055               args(rhs.args),
0056               destination(rhs.destination)
0057         {
0058             Q_UNUSED(levelOfDetail);
0059         }
0060 
0061     public:
0062         ToolTransformArgs args;
0063         Destination destination;
0064     };
0065 
0066 private:
0067 
0068     /**
0069      * A special barrier update data that triggers regeneration of
0070      * all the processed nodes.
0071      */
0072     struct BarrierUpdateData : public KisAsynchronousStrokeUpdateHelper::UpdateData
0073     {
0074         BarrierUpdateData(bool forceUpdate);
0075         KisStrokeJobData* createLodClone(int levelOfDetail) override;
0076     private:
0077         BarrierUpdateData(const BarrierUpdateData &rhs, int levelOfDetail);
0078     };
0079 
0080 public:
0081 
0082     /**
0083      * The transformation pipeline usually looks like that:
0084      *
0085      * 1) Apply Clear commands for all the layers. Some clear commands might
0086      * be "temporary", that is, they do not go to the final history, e.g. when
0087      * clearing a shape layer's projection.
0088      *
0089      * 2) Apply TransformLod commands to generate preview of the
0090      * transformation. Some commands may be declared as "temporary", that is,
0091      * they do not go to the final history, e.g. for the shape layer, for
0092      * which we just write to the projection device explicitly.
0093      *
0094      * 3) When transformation is changed we undo all TransformLod and
0095      * TransformTemporary commands to recover the old state. The temporary
0096      * command recovers the state of shape layers' projection device.
0097      *
0098      * 4) Repeat steps 2) and 3) until the user is satisfied.
0099      *
0100      * 5) When "Apply" button is pressed, all transform commands are undone
0101      * like in step 2).
0102      *
0103      * 6) All Transform commands are applied at Lod0-level. TransformTemporary
0104      * is not used atm.
0105      *
0106      * 7) All non-temporary commands go to the undo history.
0107      */
0108 
0109     enum CommandGroup {
0110         Clear = 0,
0111         ClearTemporary,
0112         Transform,
0113         TransformTemporary,
0114         TransformLod,
0115         TransformLodTemporary
0116     };
0117     Q_ENUM(CommandGroup);
0118 
0119 public:
0120     InplaceTransformStrokeStrategy(ToolTransformArgs::TransformMode mode,
0121                                    const QString &filterId,
0122                                    bool forceReset,
0123                                    KisNodeList rootNodes,
0124                                    KisSelectionSP selection,
0125                                    KisPaintDeviceSP externalSource,
0126                                    KisStrokeUndoFacade *undoFacade,
0127                                    KisUpdatesFacade *updatesFacade, KisNodeSP imageRoot, bool forceLodMode);
0128 
0129     ~InplaceTransformStrokeStrategy() override;
0130 
0131     void initStrokeCallback() override;
0132     void finishStrokeCallback() override;
0133     void cancelStrokeCallback() override;
0134     void doStrokeCallback(KisStrokeJobData *data) override;
0135 
0136 Q_SIGNALS:
0137     void sigTransactionGenerated(TransformTransactionProperties transaction, ToolTransformArgs args, void *cookie);
0138 
0139 protected:
0140     void postProcessToplevelCommand(KUndo2Command *command) override;
0141 
0142 private:
0143     friend class InitializeTransformModeStrokeStrategy;
0144 
0145     InplaceTransformStrokeStrategy(const InplaceTransformStrokeStrategy &rhs, int levelOfDetail);
0146 
0147     void tryPostUpdateJob(bool forceUpdate);
0148     void doCanvasUpdate(bool forceUpdate);
0149 
0150     int calculatePreferredLevelOfDetail(const QRect &srcRect);
0151 
0152     void executeAndAddCommand(KUndo2Command *cmd, CommandGroup group, KisStrokeJobData::Sequentiality seq);
0153 
0154     void notifyAllCommandsDone();
0155     void undoAllCommands();
0156     void undoTransformCommands(int levelOfDetail);
0157 
0158     void fetchAllUpdateRequests(int levelOfDetail, KisBatchNodeUpdateSP updateData);
0159 
0160     void transformNode(KisNodeSP node, const ToolTransformArgs &config, int levelOfDetail);
0161     void createCacheAndClearNode(KisNodeSP node);
0162     void reapplyTransform(ToolTransformArgs args, QVector<KisStrokeJobData *> &mutatedJobs, int levelOfDetail, bool useHoldUI);
0163     void finalizeStrokeImpl(QVector<KisStrokeJobData *> &mutatedJobs, bool saveCommands);
0164 
0165     void finishAction(QVector<KisStrokeJobData *> &mutatedJobs);
0166     void cancelAction(QVector<KisStrokeJobData *> &mutatedJobs);
0167     void addDirtyRect(KisNodeSP node, const QRect &rect, int levelOfDetail);
0168 
0169 private:
0170     struct Private;
0171     const QScopedPointer<Private> m_d;
0172 };
0173 
0174 #endif /* __INPLACE_TRANSFORM_STROKE_STRATEGY_H */