File indexing completed on 2025-02-23 04:05:46
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "KoShapeResizeCommand.h" 0008 0009 #include <KoShape.h> 0010 #include "kis_command_ids.h" 0011 #include "kis_assert.h" 0012 0013 0014 struct Q_DECL_HIDDEN KoShapeResizeCommand::Private 0015 { 0016 QList<KoShape *> shapes; 0017 qreal scaleX; 0018 qreal scaleY; 0019 QPointF absoluteStillPoint; 0020 bool useGlobalMode; 0021 bool usePostScaling; 0022 QTransform postScalingCoveringTransform; 0023 0024 QList<QSizeF> oldSizes; 0025 QList<QTransform> oldTransforms; 0026 }; 0027 0028 0029 KoShapeResizeCommand::KoShapeResizeCommand(const QList<KoShape*> &shapes, 0030 qreal scaleX, qreal scaleY, 0031 const QPointF &absoluteStillPoint, 0032 bool useGLobalMode, 0033 bool usePostScaling, 0034 const QTransform &postScalingCoveringTransform, 0035 KUndo2Command *parent) 0036 : SkipFirstRedoBase(false, kundo2_i18n("Resize"), parent), 0037 m_d(new Private) 0038 { 0039 m_d->shapes = shapes; 0040 m_d->scaleX = scaleX; 0041 m_d->scaleY = scaleY; 0042 m_d->absoluteStillPoint = absoluteStillPoint; 0043 m_d->useGlobalMode = useGLobalMode; 0044 m_d->usePostScaling = usePostScaling; 0045 m_d->postScalingCoveringTransform = postScalingCoveringTransform; 0046 0047 Q_FOREACH (KoShape *shape, m_d->shapes) { 0048 m_d->oldSizes << shape->size(); 0049 m_d->oldTransforms << shape->transformation(); 0050 } 0051 } 0052 0053 KoShapeResizeCommand::~KoShapeResizeCommand() 0054 { 0055 } 0056 0057 void KoShapeResizeCommand::redoImpl() 0058 { 0059 QMap<KoShape*, QRectF> updates = redoNoUpdate(); 0060 0061 for (auto it = updates.begin(); it != updates.end(); ++it) { 0062 it.key()->updateAbsolute(it.value()); 0063 } 0064 } 0065 0066 void KoShapeResizeCommand::undoImpl() 0067 { 0068 QMap<KoShape*, QRectF> updates = undoNoUpdate(); 0069 0070 for (auto it = updates.begin(); it != updates.end(); ++it) { 0071 it.key()->updateAbsolute(it.value()); 0072 } 0073 } 0074 0075 QMap<KoShape*, QRectF> KoShapeResizeCommand::redoNoUpdate() 0076 { 0077 QMap<KoShape*,QRectF> updates; 0078 0079 Q_FOREACH (KoShape *shape, m_d->shapes) { 0080 const QRectF oldDirtyRect = shape->boundingRect(); 0081 0082 KoFlake::resizeShapeCommon(shape, 0083 m_d->scaleX, m_d->scaleY, 0084 m_d->absoluteStillPoint, 0085 m_d->useGlobalMode, 0086 m_d->usePostScaling, 0087 m_d->postScalingCoveringTransform); 0088 0089 updates[shape] = oldDirtyRect | shape->boundingRect(); 0090 } 0091 0092 return updates; 0093 } 0094 0095 QMap<KoShape*, QRectF> KoShapeResizeCommand::undoNoUpdate() 0096 { 0097 QMap<KoShape*,QRectF> updates; 0098 0099 for (int i = 0; i < m_d->shapes.size(); i++) { 0100 KoShape *shape = m_d->shapes[i]; 0101 0102 const QRectF oldDirtyRect = shape->boundingRect(); 0103 shape->setSize(m_d->oldSizes[i]); 0104 shape->setTransformation(m_d->oldTransforms[i]); 0105 0106 updates[shape] = oldDirtyRect | shape->boundingRect(); 0107 } 0108 0109 return updates; 0110 } 0111 0112 int KoShapeResizeCommand::id() const 0113 { 0114 return KisCommandUtils::ResizeShapeId; 0115 } 0116 0117 bool KoShapeResizeCommand::mergeWith(const KUndo2Command *command) 0118 { 0119 const KoShapeResizeCommand *other = dynamic_cast<const KoShapeResizeCommand*>(command); 0120 0121 if (!other || 0122 other->m_d->absoluteStillPoint != m_d->absoluteStillPoint || 0123 other->m_d->shapes != m_d->shapes || 0124 other->m_d->useGlobalMode != m_d->useGlobalMode || 0125 other->m_d->usePostScaling != m_d->usePostScaling) { 0126 0127 return false; 0128 } 0129 0130 // check if the significant orientations coincide 0131 if (m_d->useGlobalMode && !m_d->usePostScaling) { 0132 Qt::Orientation our = KoFlake::significantScaleOrientation(m_d->scaleX, m_d->scaleY); 0133 Qt::Orientation their = KoFlake::significantScaleOrientation(other->m_d->scaleX, other->m_d->scaleY); 0134 0135 if (our != their) { 0136 return false; 0137 } 0138 } 0139 0140 m_d->scaleX *= other->m_d->scaleX; 0141 m_d->scaleY *= other->m_d->scaleY; 0142 return true; 0143 } 0144 0145 void KoShapeResizeCommand::replaceResizeAction(qreal scaleX, qreal scaleY, const QPointF &absoluteStillPoint) 0146 { 0147 const QMap<KoShape*, QRectF> undoUpdates = undoNoUpdate(); 0148 0149 m_d->scaleX = scaleX; 0150 m_d->scaleY = scaleY; 0151 m_d->absoluteStillPoint = absoluteStillPoint; 0152 0153 const QMap<KoShape*, QRectF> redoUpdates = redoNoUpdate(); 0154 0155 KIS_SAFE_ASSERT_RECOVER_NOOP(undoUpdates.size() == redoUpdates.size()); 0156 0157 for (auto it = undoUpdates.begin(); it != undoUpdates.end(); ++it) { 0158 KIS_SAFE_ASSERT_RECOVER_NOOP(redoUpdates.contains(it.key())); 0159 it.key()->updateAbsolute(it.value() | redoUpdates[it.key()]); 0160 } 0161 }