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
117void KisLiquifyTransformStrategy::paint(QPainter &gc, const KoColorDisplayRendererInterface *displayRendererInterface)
118{
119 Q_UNUSED(displayRendererInterface)
120 // Draw preview image
121
122 if (m_d->recalculateOnNextRedraw) {
123 m_d->recalculateTransformations();
124 m_d->recalculateOnNextRedraw = false;
125 }
126
127 gc.save();
128
129 gc.setOpacity(m_d->transaction.basePreviewOpacity());
130 gc.setTransform(m_d->paintingTransform, true);
131 gc.drawImage(m_d->paintingOffset, m_d->transformedImage);
132
133 gc.restore();
134}
135
137{
138 if (!m_d->currentArgs.liquifyWorker()) return;
139 m_d->recalculateTransformations();
140}
141
143{
144 return true;
145}
146
148{
149 m_d->lastDocPos = event->point;
150 m_d->helper.configurePaintOp(*m_d->currentArgs.liquifyProperties(), m_d->currentArgs.liquifyWorker());
151 m_d->helper.startPaint(event, m_d->manager);
152
153 m_d->recalculateTransformations();
154
155 return true;
156}
157
159{
160 m_d->lastDocPos = event->point;
161 m_d->helper.continuePaint(event);
162
163 // the updates should be compressed
164 m_d->recalculateOnNextRedraw = true;
165 Q_EMIT requestCanvasUpdate();
166}
167
169{
170 m_d->lastDocPos = event->point;
171 if (m_d->helper.endPaint(event)) {
172 m_d->recalculateTransformations();
173 Q_EMIT requestCanvasUpdate();
174 }
175
176 return true;
177}
178
180{
181 m_d->lastDocPos = event->point;
182 m_d->helper.hoverPaint(event);
183}
184
186{
187 if (action == KisTool::SampleFgNode || action == KisTool::SampleBgNode ||
188 action == KisTool::SampleFgImage || action == KisTool::SampleBgImage) {
189
190 KisLiquifyProperties *props = m_d->currentArgs.liquifyProperties();
191 props->setReverseDirection(!props->reverseDirection());
193 }
194}
195
197{
198 if (action == KisTool::SampleFgNode || action == KisTool::SampleBgNode ||
199 action == KisTool::SampleFgImage || action == KisTool::SampleBgImage) {
200
201 KisLiquifyProperties *props = m_d->currentArgs.liquifyProperties();
202 props->setReverseDirection(!props->reverseDirection());
204 }
205}
206
208{
209 m_d->lastDocPos = event->point;
210 if (action == KisTool::ChangeSize || action == KisTool::ChangeSizeSnap) {
211 QPointF widgetPoint = m_d->converter->documentToWidget(event->point);
212 m_d->lastMouseWidgetPos = widgetPoint;
213 m_d->startResizeImagePos = m_d->converter->documentToImage(event->point);
214 m_d->startResizeGlobalCursorPos = event->globalPos();
215 return true;
216 } else if (action == KisTool::SampleFgNode || action == KisTool::SampleBgNode ||
217 action == KisTool::SampleFgImage || action == KisTool::SampleBgImage) {
218
219 return beginPrimaryAction(event);
220 }
221
222 return false;
223}
224
226{
227 m_d->lastDocPos = event->point;
228 if (action == KisTool::ChangeSize || action == KisTool::ChangeSizeSnap) {
229 QPointF widgetPoint = m_d->converter->documentToWidget(event->point);
230
231 QPointF diff = widgetPoint - m_d->lastMouseWidgetPos;
232
233 KisLiquifyProperties *props = m_d->currentArgs.liquifyProperties();
234 const qreal linearizedOffset = diff.x() / KisTransformUtils::scaleFromAffineMatrix(m_d->converter->imageToWidgetTransform());
235 const qreal newSize = qBound(props->minSize(), props->size() + linearizedOffset, props->maxSize());
236 if (action == KisTool::ChangeSizeSnap) {
237 props->setSize(floor(newSize));
238 } else {
239 props->setSize(newSize);
240 }
241 m_d->currentArgs.saveLiquifyTransformMode();
242
243 m_d->lastMouseWidgetPos = widgetPoint;
244
245 Q_EMIT requestCursorOutlineUpdate(m_d->startResizeImagePos);
246 } else if (action == KisTool::SampleFgNode || action == KisTool::SampleBgNode ||
247 action == KisTool::SampleFgImage || action == KisTool::SampleBgImage) {
248
249 return continuePrimaryAction(event);
250 }
251}
252
254{
255 m_d->lastDocPos = event->point;
256
257 if (action == KisTool::ChangeSize || action == KisTool::ChangeSizeSnap) {
258 KisToolUtils::setCursorPos(m_d->startResizeGlobalCursorPos);
259 return true;
260 } else if (action == KisTool::SampleFgNode || action == KisTool::SampleBgNode ||
261 action == KisTool::SampleFgImage || action == KisTool::SampleBgImage) {
262 return endPrimaryAction(event);
263 }
264
265 return false;
266}
267
272
277
279{
280 KisLiquifyProperties *props = m_d->currentArgs.liquifyProperties();
281 qreal oldSize = props->size();
282
283 int newSize;
284 if (increase) {
285 newSize = m_d->standardBrushSizes.increaseBrushSize(oldSize);
286 } else {
287 newSize = m_d->standardBrushSizes.decreaseBrushSize(oldSize);
288 }
289
290 props->setSize(newSize);
292 Q_EMIT requestCursorOutlineUpdate( m_d->converter->documentToImage(m_d->lastDocPos));
294}
295
296inline QPointF KisLiquifyTransformStrategy::Private::imageToThumb(const QPointF &pt, bool useFlakeOptimization)
297{
298 return useFlakeOptimization ? converter->imageToDocument(converter->documentToFlake((pt))) : q->thumbToImageTransform().inverted().map(pt);
299}
300
302{
303 KIS_ASSERT_RECOVER_RETURN(currentArgs.liquifyWorker());
304
305 QTransform scaleTransform = KisTransformUtils::imageToFlakeTransform(converter);
306
307 QTransform resultThumbTransform = q->thumbToImageTransform() * scaleTransform;
308 qreal scale = KisTransformUtils::scaleFromAffineMatrix(resultThumbTransform);
309 bool useFlakeOptimization = scale < 1.0 &&
310 !KisTransformUtils::thumbnailTooSmall(resultThumbTransform, q->originalImage().rect());
311
312 paintingOffset = transaction.originalTopLeft();
313 if (!q->originalImage().isNull()) {
314 if (useFlakeOptimization) {
315 transformedImage = q->originalImage().transformed(resultThumbTransform);
316 paintingTransform = QTransform();
317 } else {
318 transformedImage = q->originalImage();
319 paintingTransform = resultThumbTransform;
320 }
321
322 QTransform imageToRealThumbTransform =
323 useFlakeOptimization ?
324 scaleTransform :
325 q->thumbToImageTransform().inverted();
326
327 QPointF origTLInFlake =
328 imageToRealThumbTransform.map(transaction.originalTopLeft());
329
330 transformedImage =
331 currentArgs.liquifyWorker()->runOnQImage(transformedImage,
332 origTLInFlake,
333 imageToRealThumbTransform,
334 &paintingOffset);
335 } else {
336 transformedImage = q->originalImage();
337 paintingOffset = imageToThumb(transaction.originalTopLeft(), false);
338 paintingTransform = resultThumbTransform;
339 }
340
341 handlesTransform = scaleTransform;
342 Q_EMIT q->requestImageRecalculation();
343}
344
_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 paint(QPainter &gc, const KoColorDisplayRendererInterface *displayRendererInterface) override
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