18#include "stroketool.h"
21#include "scribblearea.h"
22#include "viewmanager.h"
23#include "preferencemanager.h"
25#include "toolmanager.h"
28#include "canvascursorpainter.h"
32 void detectWhichOSX();
33 void disableCoalescing();
34 void enableCoalescing();
38 void detectWhichOSX() {}
39 void disableCoalescing() {}
40 void enableCoalescing() {}
44const qreal StrokeTool::FEATHER_MIN = 1.;
45const qreal StrokeTool::FEATHER_MAX = 99.;
46const qreal StrokeTool::WIDTH_MIN = 1.;
47const qreal StrokeTool::WIDTH_MAX = 200.;
50bool StrokeTool::msIsAdjusting =
false;
51bool StrokeTool::mQuickSizingEnabled =
false;
60 mQuickSizingEnabled = mEditor->preference()->isOn(SETTING::QUICK_SIZING);
61 mCanvasCursorEnabled = mEditor->preference()->isOn(SETTING::CANVAS_CURSOR);
65 connect(mEditor->preference(), &PreferenceManager::optionChanged,
this, &StrokeTool::onPreferenceChanged);
70 mActiveConnections.
append(
connect(mEditor->view(), &ViewManager::viewChanged,
this, &StrokeTool::onViewUpdated));
79void StrokeTool::onPreferenceChanged(SETTING setting)
81 if (setting == SETTING::QUICK_SIZING) {
82 mQuickSizingEnabled = mEditor->preference()->isOn(setting);
83 }
else if (setting == SETTING::CANVAS_CURSOR) {
84 mCanvasCursorEnabled = mEditor->preference()->isOn(setting);
88void StrokeTool::onViewUpdated()
93QPointF StrokeTool::getCurrentPressPixel()
const
95 return mInterpolator.getCurrentPressPixel();
98QPointF StrokeTool::getCurrentPressPoint()
const
100 return mEditor->view()->mapScreenToCanvas(mInterpolator.getCurrentPressPixel());
103QPointF StrokeTool::getCurrentPixel()
const
105 return mInterpolator.getCurrentPixel();
108QPointF StrokeTool::getCurrentPoint()
const
110 return mEditor->view()->mapScreenToCanvas(getCurrentPixel());
113QPointF StrokeTool::getLastPixel()
const
115 return mInterpolator.getLastPixel();
118QPointF StrokeTool::getLastPoint()
const
120 return mEditor->view()->mapScreenToCanvas(getLastPixel());
123void StrokeTool::startStroke(PointerEvent::InputType inputType)
131 mLastPixel = getCurrentPixel();
133 mStrokePoints.
clear();
136 QPointF startStrokes = mInterpolator.interpolateStart(mLastPixel);
137 mStrokePoints << mEditor->view()->mapScreenToCanvas(startStrokes);
139 mStrokePressures.
clear();
140 mStrokePressures << mInterpolator.getPressure();
142 mCurrentInputType = inputType;
147bool StrokeTool::keyPressEvent(
QKeyEvent *event)
149 switch (event->
key()) {
151 if (mEditor->tools()->setTemporaryTool(EYEDROPPER, {},
Qt::AltModifier))
163 return BaseTool::keyPressEvent(event);
171void StrokeTool::endStroke()
173 mInterpolator.interpolateEnd();
174 mStrokePressures << mInterpolator.getPressure();
175 mStrokePoints.
clear();
176 mStrokePressures.
clear();
180 mEditor->setModified(mEditor->currentLayerIndex(), mEditor->currentFrame());
181 mScribbleArea->endStroke();
184void StrokeTool::drawStroke()
186 QPointF pixel = getCurrentPixel();
187 if (pixel != mLastPixel || !mFirstDraw)
190 QPointF startStrokes = mInterpolator.interpolateStart(getLastPixel());
191 mStrokePoints << mEditor->view()->mapScreenToCanvas(startStrokes);
192 mStrokePressures << mInterpolator.getPressure();
202 if (event->eventType() == PointerEvent::Press) {
203 if (mQuickSizingEnabled) {
204 return startAdjusting(event->
modifiers());
206 }
else if (event->eventType() == PointerEvent::Move) {
211 }
else if (event->eventType() == PointerEvent::Release) {
222 updateCanvasCursor();
227 updateCanvasCursor();
232 updateCanvasCursor();
235bool StrokeTool::event(
QEvent *event)
238 mCanvasCursorEnabled =
false;
239 updateCanvasCursor();
243 mCanvasCursorEnabled = mEditor->preference()->isOn(SETTING::CANVAS_CURSOR);
250void StrokeTool::updateCanvasCursor()
252 const qreal brushWidth = properties.width;
253 const qreal brushFeather = properties.feather;
255 const QPointF& cursorPos = msIsAdjusting ? mAdjustPosition : getCurrentPoint();
256 const qreal cursorRad = brushWidth * 0.5;
257 const QPointF& cursorOffset =
QPointF(cursorPos.
x() - cursorRad, cursorPos.
y() - cursorRad);
260 options.widthRect =
QRectF(cursorOffset,
QSizeF(brushWidth, brushWidth));
262 const qreal featherWidthFactor = MathUtils::normalize(brushFeather, 0.0, FEATHER_MAX);
263 options.featherRect =
QRectF(options.widthRect.
center().
x() - (cursorRad * featherWidthFactor),
264 options.widthRect.
center().
y() - (cursorRad * featherWidthFactor),
265 brushWidth * featherWidthFactor,
266 brushWidth * featherWidthFactor);
267 options.showCursor = mCanvasCursorEnabled;
268 options.isAdjusting = msIsAdjusting && mQuickSizingEnabled;
269 options.useFeather = mPropertyEnabled[FEATHER];
271 mCanvasCursorPainter.preparePainter(options, mEditor->view()->getView());
273 const QRect& dirtyRect = mCanvasCursorPainter.dirtyRect();
274 const QRect& updateRect = mEditor->view()->getView().
mapRect(
QRectF(cursorOffset,
QSizeF(brushWidth, brushWidth))).toAlignedRect();
276 if (!msIsAdjusting && !mCanvasCursorEnabled) {
277 if (mCanvasCursorPainter.isDirty()) {
279 mScribbleArea->
update(mCanvasCursorPainter.dirtyRect().
adjusted(-2, -2, 2, 2));
280 mCanvasCursorPainter.clearDirty();
291 if (!mQuickSizingProperties.
contains(modifiers))
296 const QPointF& currentPressPoint = getCurrentPressPoint();
297 const QPointF& currentPoint = getCurrentPoint();
298 auto propertyType = mQuickSizingProperties.
value(modifiers);
299 switch (propertyType) {
301 const qreal factor = 0.5;
302 const qreal rad = properties.width * factor;
303 const qreal distance =
QLineF(currentPressPoint -
QPointF(rad, rad), currentPoint).
length();
304 mAdjustPosition = currentPressPoint -
QPointF(distance * factor, distance * factor);
308 const qreal factor = 0.5;
309 const qreal cursorRad = properties.width * factor;
310 const qreal featherWidthFactor = MathUtils::normalize(properties.feather, 0.0, FEATHER_MAX);
311 const qreal offset = (cursorRad * featherWidthFactor) * factor;
312 const qreal distance =
QLineF(currentPressPoint -
QPointF(offset, offset), currentPoint).
length();
313 mAdjustPosition = currentPressPoint -
QPointF(distance, distance);
318 qWarning() <<
"Unhandled quick sizing property for tool" << typeName();
322 msIsAdjusting =
true;
323 updateCanvasCursor();
327void StrokeTool::stopAdjusting()
329 msIsAdjusting =
false;
331 updateCanvasCursor();
336 switch (mQuickSizingProperties.
value(modifiers))
341 const qreal newValue =
QLineF(mAdjustPosition, getCurrentPoint()).
length() * 2.0;
343 mEditor->tools()->setWidth(qBound(WIDTH_MIN, newValue, WIDTH_MAX));
348 const qreal inputMin = 0.0;
349 const qreal inputMax = properties.width * 0.5;
350 const qreal distance =
QLineF(mAdjustPosition, getCurrentPoint()).
length();
351 const qreal outputMax = FEATHER_MAX;
352 const qreal outputMin = 0.0;
355 const qreal mappedValue = MathUtils::map(distance, inputMin, inputMax, outputMax, outputMin);
357 mEditor->tools()->setFeather(qBound(FEATHER_MIN, mappedValue, FEATHER_MAX));
362 qWarning() <<
"Unhandled quick sizing property for tool" << typeName();
364 updateCanvasCursor();
367void StrokeTool::paint(
QPainter& painter,
const QRect& blitRect)
369 mCanvasCursorPainter.paint(painter, blitRect);
Qt::KeyboardModifiers modifiers() const
Returns the modifier created by keyboard while a device was in use.
Qt::MouseButtons buttons() const
Returns Qt::MouseButtons()
void handleDrawingOnEmptyFrame()
Call this when starting to use a paint tool.
QEvent::Type type() const const
bool contains(const Key &key) const const
const T value(const Key &key) const const
qreal length() const const
void append(const T &value)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual bool event(QEvent *e)
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
QRect united(const QRect &rectangle) const const
QPointF center() const const