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 */