Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_liquify_transform_strategy.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <algorithm>
10
11#include <QPointF>
12#include <QPainter>
13#include <QPainterPath>
14
15#include "KoPointerEvent.h"
16
18#include "tool_transform_args.h"
20#include "krita_utils.h"
21#include "kis_cursor.h"
22#include "kis_transform_utils.h"
23#include "kis_algebra_2d.h"
27#include "kis_tool_utils.h"
28
29
31{
33 const KisCoordinatesConverter *_converter,
34 ToolTransformArgs &_currentArgs,
36 const KoCanvasResourceProvider *_manager)
37 : manager(_manager),
38 q(_q),
39 converter(_converter),
40 currentArgs(_currentArgs),
41 transaction(_transaction),
42 helper(_converter),
44 {
45 }
46
48
50
52
54
59
62
63 QTransform handlesTransform;
64
66
68
69 // size-gesture-related
73
74 // for increase/decrease brush size
75 QPointF lastDocPos;
78
80
82
84 inline QPointF imageToThumb(const QPointF &pt, bool useFlakeOptimization);
85};
86
88 ToolTransformArgs &currentArgs,
90 const KoCanvasResourceProvider *manager)
91
92 : m_d(new Private(this, converter, currentArgs, transaction, manager))
93{
94}
95
99
101{
102 return m_d->helper.brushOutline(*m_d->currentArgs.liquifyProperties());
103}
104
105void KisLiquifyTransformStrategy::setTransformFunction(const QPointF &mousePos, bool perspectiveModifierActive, bool shiftModifierActive)
106{
107 Q_UNUSED(mousePos);
108 Q_UNUSED(perspectiveModifierActive);
109 Q_UNUSED(shiftModifierActive);
110}
111
113{
114 return Qt::BlankCursor;
115}
116
118{
119 // Draw preview image
120
121 if (m_d->recalculateOnNextRedraw) {
122 m_d->recalculateTransformations();
123 m_d->recalculateOnNextRedraw = false;
124 }
125
126 gc.save();
127
128 gc.setOpacity(m_d->transaction.basePreviewOpacity());
129 gc.setTransform(m_d->paintingTransform, true);
130 gc.drawImage(m_d->paintingOffset, m_d->transformedImage);
131
132 gc.restore();
133}
134
136{
137 if (!m_d->currentArgs.liquifyWorker()) return;
138 m_d->recalculateTransformations();
139}
140
142{
143 return true;
144}
145
147{
148 m_d->lastDocPos = event->point;
149 m_d->helper.configurePaintOp(*m_d->currentArgs.liquifyProperties(), m_d->currentArgs.liquifyWorker());
150 m_d->helper.startPaint(event, m_d->manager);
151
152 m_d->recalculateTransformations();
153
154 return true;
155}
156
158{
159 m_d->lastDocPos = event->point;
160 m_d->helper.continuePaint(event);
161
162 // the updates should be compressed
163 m_d->recalculateOnNextRedraw = true;
164 Q_EMIT requestCanvasUpdate();
165}
166
168{
169 m_d->lastDocPos = event->point;
170 if (m_d->helper.endPaint(event)) {
171 m_d->recalculateTransformations();
172 Q_EMIT requestCanvasUpdate();
173 }
174
175 return true;
176}
177
179{
180 m_d->lastDocPos = event->point;
181 m_d->helper.hoverPaint(event);
182}
183
185{
186 if (action == KisTool::SampleFgNode || action == KisTool::SampleBgNode ||
187 action == KisTool::SampleFgImage || action == KisTool::SampleBgImage) {
188
189 KisLiquifyProperties *props = m_d->currentArgs.liquifyProperties();
190 props->setReverseDirection(!props->reverseDirection());
192 }
193}
194
196{
197 if (action == KisTool::SampleFgNode || action == KisTool::SampleBgNode ||
198 action == KisTool::SampleFgImage || action == KisTool::SampleBgImage) {
199
200 KisLiquifyProperties *props = m_d->currentArgs.liquifyProperties();
201 props->setReverseDirection(!props->reverseDirection());
203 }
204}
205
207{
208 m_d->lastDocPos = event->point;
209 if (action == KisTool::ChangeSize || action == KisTool::ChangeSizeSnap) {
210 QPointF widgetPoint = m_d->converter->documentToWidget(event->point);
211 m_d->lastMouseWidgetPos = widgetPoint;
212 m_d->startResizeImagePos = m_d->converter->documentToImage(event->point);
213 m_d->startResizeGlobalCursorPos = event->globalPos();
214 return true;
215 } else if (action == KisTool::SampleFgNode || action == KisTool::SampleBgNode ||
216 action == KisTool::SampleFgImage || action == KisTool::SampleBgImage) {
217
218 return beginPrimaryAction(event);
219 }
220
221 return false;
222}
223
225{
226 m_d->lastDocPos = event->point;
227 if (action == KisTool::ChangeSize || action == KisTool::ChangeSizeSnap) {
228 QPointF widgetPoint = m_d->converter->documentToWidget(event->point);
229
230 QPointF diff = widgetPoint - m_d->lastMouseWidgetPos;
231
232 KisLiquifyProperties *props = m_d->currentArgs.liquifyProperties();
233 const qreal linearizedOffset = diff.x() / KisTransformUtils::scaleFromAffineMatrix(m_d->converter->imageToWidgetTransform());
234 const qreal newSize = qBound(props->minSize(), props->size() + linearizedOffset, props->maxSize());
235 if (action == KisTool::ChangeSizeSnap) {
236 props->setSize(floor(newSize));
237 } else {
238 props->setSize(newSize);
239 }
240 m_d->currentArgs.saveLiquifyTransformMode();
241
242 m_d->lastMouseWidgetPos = widgetPoint;
243
244 Q_EMIT requestCursorOutlineUpdate(m_d->startResizeImagePos);
245 } else if (action == KisTool::SampleFgNode || action == KisTool::SampleBgNode ||
246 action == KisTool::SampleFgImage || action == KisTool::SampleBgImage) {
247
248 return continuePrimaryAction(event);
249 }
250}
251
253{
254 m_d->lastDocPos = event->point;
255
256 if (action == KisTool::ChangeSize || action == KisTool::ChangeSizeSnap) {
257 KisToolUtils::setCursorPos(m_d->startResizeGlobalCursorPos);
258 return true;
259 } else if (action == KisTool::SampleFgNode || action == KisTool::SampleBgNode ||
260 action == KisTool::SampleFgImage || action == KisTool::SampleBgImage) {
261 return endPrimaryAction(event);
262 }
263
264 return false;
265}
266
271
276
278{
279 KisLiquifyProperties *props = m_d->currentArgs.liquifyProperties();
280 qreal oldSize = props->size();
281
282 int newSize;
283 if (increase) {
284 newSize = m_d->standardBrushSizes.increaseBrushSize(oldSize);
285 } else {
286 newSize = m_d->standardBrushSizes.decreaseBrushSize(oldSize);
287 }
288
289 props->setSize(newSize);
291 Q_EMIT requestCursorOutlineUpdate( m_d->converter->documentToImage(m_d->lastDocPos));
293}
294
295inline QPointF KisLiquifyTransformStrategy::Private::imageToThumb(const QPointF &pt, bool useFlakeOptimization)
296{
297 return useFlakeOptimization ? converter->imageToDocument(converter->documentToFlake((pt))) : q->thumbToImageTransform().inverted().map(pt);
298}
299
301{
302 KIS_ASSERT_RECOVER_RETURN(currentArgs.liquifyWorker());
303
304 QTransform scaleTransform = KisTransformUtils::imageToFlakeTransform(converter);
305
306 QTransform resultThumbTransform = q->thumbToImageTransform() * scaleTransform;
307 qreal scale = KisTransformUtils::scaleFromAffineMatrix(resultThumbTransform);
308 bool useFlakeOptimization = scale < 1.0 &&
309 !KisTransformUtils::thumbnailTooSmall(resultThumbTransform, q->originalImage().rect());
310
311 paintingOffset = transaction.originalTopLeft();
312 if (!q->originalImage().isNull()) {
313 if (useFlakeOptimization) {
314 transformedImage = q->originalImage().transformed(resultThumbTransform);
315 paintingTransform = QTransform();
316 } else {
317 transformedImage = q->originalImage();
318 paintingTransform = resultThumbTransform;
319 }
320
321 QTransform imageToRealThumbTransform =
322 useFlakeOptimization ?
323 scaleTransform :
324 q->thumbToImageTransform().inverted();
325
326 QPointF origTLInFlake =
327 imageToRealThumbTransform.map(transaction.originalTopLeft());
328
329 transformedImage =
330 currentArgs.liquifyWorker()->runOnQImage(transformedImage,
331 origTLInFlake,
332 imageToRealThumbTransform,
333 &paintingOffset);
334 } else {
335 transformedImage = q->originalImage();
336 paintingOffset = imageToThumb(transaction.originalTopLeft(), false);
337 paintingTransform = resultThumbTransform;
338 }
339
340 handlesTransform = scaleTransform;
341 Q_EMIT q->requestImageRecalculation();
342}
343
_Private::Traits< T >::Result documentToFlake(const T &obj) const
_Private::Traits< T >::Result imageToDocument(const T &obj) const
void setReverseDirection(bool value)
void changeBrushSize(KoCanvasBase *canvas, bool increase)
void activateAlternateAction(KisTool::AlternateAction action) override
void deactivateAlternateAction(KisTool::AlternateAction action) override
void hoverActionCommon(KoPointerEvent *event) override
void increaseBrushSize(KoCanvasBase *canvas) override
void continueAlternateAction(KoPointerEvent *event, KisTool::AlternateAction action) override
bool beginAlternateAction(KoPointerEvent *event, KisTool::AlternateAction action) override
bool endAlternateAction(KoPointerEvent *event, KisTool::AlternateAction action) override
const QScopedPointer< Private > m_d
void setTransformFunction(const QPointF &mousePos, bool perspectiveModifierActive, bool shiftModifierActive)
void continuePrimaryAction(KoPointerEvent *event) override
KisLiquifyTransformStrategy(const KisCoordinatesConverter *converter, ToolTransformArgs &currentArgs, TransformTransactionProperties &transaction, const KoCanvasResourceProvider *manager)
void requestCursorOutlineUpdate(const QPointF &imagePoint)
QPainterPath getCursorOutline() const override
bool endPrimaryAction(KoPointerEvent *event) override
bool beginPrimaryAction(KoPointerEvent *event) override
void decreaseBrushSize(KoCanvasBase *canvas) override
static qreal scaleFromAffineMatrix(const QTransform &t)
static QTransform imageToFlakeTransform(const KisCoordinatesConverter *converter)
static bool thumbnailTooSmall(const QTransform &resultThumbTransform, const QRect &originalImageRect)
QPointF point
The point in document coordinates.
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
void KRITAUI_EXPORT showBrushSizeFloatingMessage(KoCanvasBase *canvas, qreal size)
void KRITAUI_EXPORT setCursorPos(const QPoint &point)
const KisCoordinatesConverter * converter
standard members ///
QPointF imageToThumb(const QPointF &pt, bool useFlakeOptimization)
KisToolUtils::StandardBrushSizes standardBrushSizes
Private(KisLiquifyTransformStrategy *_q, const KisCoordinatesConverter *_converter, ToolTransformArgs &_currentArgs, TransformTransactionProperties &_transaction, const KoCanvasResourceProvider *_manager)
AlternateAction
Definition kis_tool.h:134
@ SampleFgImage
Definition kis_tool.h:139
@ SampleFgNode
Definition kis_tool.h:137
@ ChangeSizeSnap
Definition kis_tool.h:136
@ SampleBgImage
Definition kis_tool.h:140
@ SampleBgNode
Definition kis_tool.h:138
@ ChangeSize
Definition kis_tool.h:135