Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tool_paint.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2003-2009 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2015 Moritz Molch <kde@moritzmolch.de>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#include "kis_tool_paint.h"
9
10#include <algorithm>
11
12#include <QWidget>
13#include <QRect>
14#include <QLayout>
15#include <QPushButton>
16#include <QWhatsThis>
17#include <QCheckBox>
18#include <QVBoxLayout>
19#include <QHBoxLayout>
20#include <QGridLayout>
21#include <QEvent>
22#include <QVariant>
23#include <QAction>
24#include <kis_debug.h>
25#include <QPoint>
26
27#include <klocalizedstring.h>
28#include <kactioncollection.h>
29
30#include <kis_algebra_2d.h>
31#include <kis_icon.h>
32#include <KoShape.h>
34#include <KoColorSpace.h>
35#include <KoPointerEvent.h>
36#include <KoColor.h>
37#include <KoCanvasBase.h>
38#include <KoCanvasController.h>
39
40#include <kis_types.h>
41#include <kis_global.h>
42#include <kis_image.h>
43#include <kis_paint_device.h>
44#include <kis_layer.h>
45#include <KisViewManager.h>
46#include <kis_canvas2.h>
47#include <kis_cubic_curve.h>
49#include <KisDocument.h>
51
52#include "kis_config.h"
53#include "kis_config_notifier.h"
54#include "kis_cursor.h"
55#include "kis_image_config.h"
57#include "kis_slider_spin_box.h"
59#include "kis_tool_utils.h"
63#include <kis_action_manager.h>
64#include <kis_action.h>
66#include "kis_popup_palette.h"
67#include "kis_paintop_utils.h"
68
69
71{
72 // Keeps track of past cursor positions. This is used to determine the drawing angle when
73 // drawing the brush outline or starting a stroke.
75};
76
77
78KisToolPaint::KisToolPaint(KoCanvasBase *canvas, const QCursor &cursor)
79 : KisTool(canvas, cursor),
80 m_isOutlineEnabled(true),
81 m_isOutlineVisible(true),
82 m_colorSamplerHelper(dynamic_cast<KisCanvas2*>(canvas)),
83 m_d(new Private())
84{
85
86 {
87 const int maxSize = KisImageConfig(true).maxBrushSize();
88
89 int brushSize = 1;
90 do {
91 m_standardBrushSizes.push_back(brushSize);
92 int increment = qMax(1, int(std::ceil(qreal(brushSize) / 15)));
93 brushSize += increment;
94 } while (brushSize < maxSize);
95
96 m_standardBrushSizes.push_back(maxSize);
97 }
98
99 KisCanvas2 *kiscanvas = dynamic_cast<KisCanvas2*>(canvas);
100 KIS_ASSERT(kiscanvas);
101 connect(this, SIGNAL(sigPaintingFinished()), kiscanvas->viewManager()->canvasResourceProvider(), SLOT(slotPainting()));
102
103 connect(&m_colorSamplerHelper, SIGNAL(sigRequestCursor(QCursor)), this, SLOT(slotColorPickerRequestedCursor(QCursor)));
104 connect(&m_colorSamplerHelper, SIGNAL(sigRequestCursorReset()), this, SLOT(slotColorPickerRequestedCursorReset()));
105 connect(&m_colorSamplerHelper, SIGNAL(sigRequestUpdateOutline()), this, SLOT(slotColorPickerRequestedOutlineUpdate()));
106}
107
108
112
117
118void KisToolPaint::canvasResourceChanged(int key, const QVariant& v)
119{
121
122 switch(key) {
124 break;
126 if (isActive()) {
128 }
129 break;
130 }
132 if (isActive()) {
133 const QString formattedBrushName = v.toString().replace("_", " ");
134 Q_EMIT statusTextChanged(formattedBrushName);
135 }
136 break;
137 }
138 default: //nothing
139 break;
140 }
141
142 connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(resetCursorStyle()), Qt::UniqueConnection);
143
144}
145
147{
159 KisCanvasResourceProvider *provider = qobject_cast<KisCanvas2*>(canvas())->viewManager()->canvasResourceProvider();
160
161 KisPaintOpPresetSP newPreset = provider->currentPreset();
162
163 if (newPreset) {
164 m_oldPreset = newPreset;
165 m_oldPresetIsDirty = newPreset->isDirty();
166 m_oldPresetVersion = newPreset->version();
167 }
168}
169
170
171void KisToolPaint::activate(const QSet<KoShape*> &shapes)
172{
173 if (currentPaintOpPreset()) {
174 const QString formattedBrushName = currentPaintOpPreset() ? currentPaintOpPreset()->name().replace("_", " ") : QString();
175 Q_EMIT statusTextChanged(formattedBrushName);
176 }
177
178 KisTool::activate(shapes);
180 connect(action("increase_brush_size"), SIGNAL(triggered()), SLOT(increaseBrushSize()), Qt::UniqueConnection);
181 connect(action("decrease_brush_size"), SIGNAL(triggered()), SLOT(decreaseBrushSize()), Qt::UniqueConnection);
182 connect(action("increase_brush_size"), SIGNAL(triggered()), this, SLOT(showBrushSize()));
183 connect(action("decrease_brush_size"), SIGNAL(triggered()), this, SLOT(showBrushSize()));
184
185 }
186
187 connect(action("rotate_brush_tip_clockwise"), SIGNAL(triggered()), SLOT(rotateBrushTipClockwise()), Qt::UniqueConnection);
188 connect(action("rotate_brush_tip_clockwise_precise"), SIGNAL(triggered()), SLOT(rotateBrushTipClockwisePrecise()), Qt::UniqueConnection);
189 connect(action("rotate_brush_tip_counter_clockwise"), SIGNAL(triggered()), SLOT(rotateBrushTipCounterClockwise()), Qt::UniqueConnection);
190 connect(action("rotate_brush_tip_counter_clockwise_precise"), SIGNAL(triggered()), SLOT(rotateBrushTipCounterClockwisePrecise()), Qt::UniqueConnection);
191
193}
194
196{
198 disconnect(action("increase_brush_size"), 0, this, 0);
199 disconnect(action("decrease_brush_size"), 0, this, 0);
200 }
201
202 disconnect(action("rotate_brush_tip_clockwise"), 0, this, 0);
203 disconnect(action("rotate_brush_tip_clockwise_precise"), 0, this, 0);
204 disconnect(action("rotate_brush_tip_counter_clockwise"), 0, this, 0);
205 disconnect(action("rotate_brush_tip_counter_clockwise_precise"), 0, this, 0);
206
208 Q_EMIT statusTextChanged(QString());
209
211}
212
214{
216}
217
222
227
229{
230 KisConfig cfg(true);
231
232 bool useSeparateEraserCursor = cfg.separateEraserCursor() && isEraser();
233
234 const OutlineStyle currentOutlineStyle = !useSeparateEraserCursor ? cfg.newOutlineStyle() : cfg.eraserOutlineStyle();
235 if (currentOutlineStyle == OUTLINE_NONE) return originalOutline;
236
237 const qreal minThresholdSize = cfg.outlineSizeMinimum();
238
245 QSize widgetSize = canvas()->canvasWidget()->size();
246 const int maxThresholdSum = widgetSize.width() + widgetSize.height();
247
248 KisOptimizedBrushOutline outline = originalOutline;
249 QRectF boundingRect = outline.boundingRect();
250 const qreal sum = boundingRect.width() + boundingRect.height();
251
252 QPointF center = boundingRect.center();
253
254 if (sum > maxThresholdSum) {
255 const int hairOffset = 7;
256
257 QPainterPath crossIcon;
258
259 crossIcon.moveTo(center.x(), center.y() - hairOffset);
260 crossIcon.lineTo(center.x(), center.y() + hairOffset);
261
262 crossIcon.moveTo(center.x() - hairOffset, center.y());
263 crossIcon.lineTo(center.x() + hairOffset, center.y());
264
265 outline.addPath(crossIcon);
266
267 } else if (sum < minThresholdSize && !outline.isEmpty()) {
268 outline = QPainterPath();
269 outline.addEllipse(center, 0.5 * minThresholdSize, 0.5 * minThresholdSize);
270 }
271
272 return outline;
273}
274
275void KisToolPaint::paint(QPainter &gc, const KoViewConverter &converter)
276{
277 Q_UNUSED(converter);
278
280 paintToolOutline(&gc, path);
281
282 m_colorSamplerHelper.paint(gc, converter);
283}
284
286{
287 if(this->mode() == KisTool::PAINT_MODE &&
288 mode != KisTool::PAINT_MODE) {
289
290 // Let's add history information about recently used colors
291 Q_EMIT sigPaintingFinished();
292 }
293
295}
296
298{
299 if (!isSamplingAction(action)) {
301 return;
302 }
303
304 const bool sampleCurrentLayer = action == SampleFgNode || action == SampleBgNode;
305 const bool sampleFgColor = action == SampleFgNode || action == SampleFgImage;
306 m_colorSamplerHelper.activate(sampleCurrentLayer, sampleFgColor);
307}
308
318
325
327{
330
332 config.load();
333
334 m_colorSamplerHelper.startAction(event->point, config.radius, config.blend);
335 requestUpdateOutline(event->point, event);
336 } else {
338 }
339}
340
350
361
363{
365 if (mode() == KisTool::HOVER_MODE) {
366 requestUpdateOutline(event->point, event);
367 }
368}
369
371{
373 if (mode() == KisTool::HOVER_MODE) {
374 requestUpdateOutline(event->point, event);
375 }
376}
377
379{
380 KisCanvas2 *kisCanvas = dynamic_cast<KisCanvas2*>(canvas());
381
382 if (!kisCanvas) {
383 return nullptr;
384 }
385
387 return popupWidget;
388}
389
391{
393 if (mode() == KisTool::HOVER_MODE) {
394 requestUpdateOutline(event->point, event);
395 }
396}
397
399{
400 QWidget *optionWidget = new QWidget();
401 optionWidget->setObjectName(toolId());
402
403 QVBoxLayout *verticalLayout = new QVBoxLayout(optionWidget);
404 verticalLayout->setObjectName("KisToolPaint::OptionWidget::VerticalLayout");
405 verticalLayout->setContentsMargins(0,0,0,0);
406 verticalLayout->setSpacing(5);
407
408 // See https://bugs.kde.org/show_bug.cgi?id=316896
409 QWidget *specialSpacer = new QWidget(optionWidget);
410 specialSpacer->setObjectName("SpecialSpacer");
411 specialSpacer->setFixedSize(0, 0);
412 verticalLayout->addWidget(specialSpacer);
413 verticalLayout->addWidget(specialSpacer);
414
415 m_optionsWidgetLayout = new QGridLayout();
416 m_optionsWidgetLayout->setColumnStretch(1, 1);
417 verticalLayout->addLayout(m_optionsWidgetLayout);
418 m_optionsWidgetLayout->setContentsMargins(0,0,0,0);
419 m_optionsWidgetLayout->setSpacing(5);
420
421 if (!quickHelp().isEmpty()) {
422 QPushButton *push = new QPushButton(KisIconUtils::loadIcon("help-contents"), QString(), optionWidget);
423 connect(push, SIGNAL(clicked()), this, SLOT(slotPopupQuickHelp()));
424 QHBoxLayout *hLayout = new QHBoxLayout();
425 hLayout->addWidget(push);
426 hLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed));
427 verticalLayout->addLayout(hLayout);
428 }
429
430 return optionWidget;
431}
432
433QWidget* findLabelWidget(QGridLayout *layout, QWidget *control)
434{
435 QWidget *result = 0;
436
437 int index = layout->indexOf(control);
438
439 int row, col, rowSpan, colSpan;
440 layout->getItemPosition(index, &row, &col, &rowSpan, &colSpan);
441
442 if (col > 0) {
443 QLayoutItem *item = layout->itemAtPosition(row, col - 1);
444
445 if (item) {
446 result = item->widget();
447 }
448 } else {
449 QLayoutItem *item = layout->itemAtPosition(row, col + 1);
450 if (item) {
451 result = item->widget();
452 }
453 }
454
455 return result;
456}
457
458void KisToolPaint::showControl(QWidget *control, bool value)
459{
460 control->setVisible(value);
461 QWidget *label = findLabelWidget(m_optionsWidgetLayout, control);
462 if (label) {
463 label->setVisible(value);
464 }
465}
466
467void KisToolPaint::enableControl(QWidget *control, bool value)
468{
469 control->setEnabled(value);
470 QWidget *label = findLabelWidget(m_optionsWidgetLayout, control);
471 if (label) {
472 label->setEnabled(value);
473 }
474}
475
477{
478 Q_ASSERT(m_optionsWidgetLayout != 0);
479 int rowCount = m_optionsWidgetLayout->rowCount();
480 m_optionsWidgetLayout->addLayout(layout, rowCount, 0, 1, 2);
481}
482
483
484void KisToolPaint::addOptionWidgetOption(QWidget *control, QWidget *label)
485{
486 Q_ASSERT(m_optionsWidgetLayout != 0);
487 if (label) {
488 m_optionsWidgetLayout->addWidget(label, m_optionsWidgetLayout->rowCount(), 0);
489 m_optionsWidgetLayout->addWidget(control, m_optionsWidgetLayout->rowCount() - 1, 1);
490 }
491 else {
492 m_optionsWidgetLayout->addWidget(control, m_optionsWidgetLayout->rowCount(), 0, 1, 2);
493 }
494}
495
496
498{
499 QWhatsThis::showText(QCursor::pos(), quickHelp());
500}
501
507
513
515{
516 return m_isOutlineEnabled;
517}
518
524
526{
527 return m_isOutlineVisible;
528}
529
535
537{
538 qreal paintopSize = currentPaintOpPreset()->settings()->paintOpSize();
539
540 std::vector<int>::iterator result =
541 std::upper_bound(m_standardBrushSizes.begin(),
543 qRound(paintopSize));
544
545 int newValue = result != m_standardBrushSizes.end() ? *result : m_standardBrushSizes.back();
546
547 currentPaintOpPreset()->settings()->setPaintOpSize(newValue);
549}
550
552{
553 qreal paintopSize = currentPaintOpPreset()->settings()->paintOpSize();
554
555 std::vector<int>::reverse_iterator result =
556 std::upper_bound(m_standardBrushSizes.rbegin(),
558 qRound(paintopSize),
559 std::greater<int>());
560
561 int newValue = result != m_standardBrushSizes.rend() ? *result : m_standardBrushSizes.front();
562
563 currentPaintOpPreset()->settings()->setPaintOpSize(newValue);
565}
566
568{
569 KisCanvas2 *kisCanvas =dynamic_cast<KisCanvas2*>(canvas());
571 kisCanvas->viewManager()->showFloatingMessage(i18n("Brush Size: %1 px", currentPaintOpPreset()->settings()->paintOpSize())
572 , QIcon(), 1000, KisFloatingMessage::High, Qt::AlignLeft | Qt::TextWordWrap | Qt::AlignVCenter);
573}
574
576{
577 const qreal angle = currentPaintOpPreset()->settings()->paintOpAngle();
578 currentPaintOpPreset()->settings()->setPaintOpAngle(angle - 15);
580}
581
583{
584 const qreal angle = currentPaintOpPreset()->settings()->paintOpAngle();
585 currentPaintOpPreset()->settings()->setPaintOpAngle(angle - 1);
587}
588
590{
591 const qreal angle = currentPaintOpPreset()->settings()->paintOpAngle();
592 currentPaintOpPreset()->settings()->setPaintOpAngle(angle + 15);
594}
595
597{
598 const qreal angle = currentPaintOpPreset()->settings()->paintOpAngle();
599 currentPaintOpPreset()->settings()->setPaintOpAngle(angle + 1);
601}
602
603void KisToolPaint::requestUpdateOutline(const QPointF &outlineDocPoint, const KoPointerEvent *event)
604{
605 QRectF outlinePixelRect;
606 QRectF outlineDocRect;
607
608 QRectF colorPreviewDocUpdateRect;
609
610 QPointF outlineMoveVector;
611
612 if (m_supportOutline) {
613 KisConfig cfg(true);
615
616 bool useSeparateEraserCursor = cfg.separateEraserCursor() && isEraser();
617
618 const OutlineStyle currentOutlineStyle = !useSeparateEraserCursor ? cfg.newOutlineStyle() : cfg.eraserOutlineStyle();
619 const auto outlineStyleIsVisible = [&]() {
620 return currentOutlineStyle == OUTLINE_FULL ||
621 currentOutlineStyle == OUTLINE_CIRCLE ||
622 currentOutlineStyle == OUTLINE_TILT;
623 };
624 const auto shouldShowOutlineWhilePainting = [&]() {
625 return !useSeparateEraserCursor ? cfg.showOutlineWhilePainting() : cfg.showEraserOutlineWhilePainting();
626 };
629 (outlineStyleIsVisible() &&
630 (mode() == HOVER_MODE ||
631 (mode() == PAINT_MODE && shouldShowOutlineWhilePainting()))))) { // lisp forever!
632
633 outlineMode.isVisible = true;
634
635 switch (!useSeparateEraserCursor ? cfg.newOutlineStyle() : cfg.eraserOutlineStyle()) {
636 case OUTLINE_CIRCLE:
637 outlineMode.forceCircle = true;
638 break;
639 case OUTLINE_TILT:
640 outlineMode.forceCircle = true;
641 outlineMode.showTiltDecoration = true;
642 break;
643 default:
644 break;
645 }
646 }
647
648 outlineMode.forceFullSize = !useSeparateEraserCursor ? cfg.forceAlwaysFullSizedOutline() : cfg.forceAlwaysFullSizedEraserOutline();
649
650 outlineMoveVector = outlineDocPoint - m_outlineDocPoint;
651
652 m_outlineDocPoint = outlineDocPoint;
654
656 outlineDocRect = currentImage()->pixelToDocument(outlinePixelRect);
657
658 // This adjusted call is needed as we paint with a 3 pixel wide brush and the pen is outside the bounds of the path
659 // Pen uses view coordinates so we have to zoom the document value to match 2 pixel in view coordinates
660 // See BUG 275829
661 qreal zoomX;
662 qreal zoomY;
663 canvas()->viewConverter()->zoom(&zoomX, &zoomY);
664 qreal xoffset = 2.0/zoomX;
665 qreal yoffset = 2.0/zoomY;
666
667 if (!outlineDocRect.isEmpty()) {
668 outlineDocRect.adjust(-xoffset,-yoffset,xoffset,yoffset);
669 }
670
672
673 if (!colorPreviewDocUpdateRect.isEmpty()) {
674 colorPreviewDocUpdateRect = colorPreviewDocUpdateRect.adjusted(-xoffset,-yoffset,xoffset,yoffset);
675 }
676
677 }
678
679 // DIRTY HACK ALERT: we should fetch the assistant's dirty rect when requesting
680 // the update, instead of just dumbly update the entire canvas!
681
682 // WARNING: assistants code is also duplicated in KisDelegatedSelectPathWrapper::mouseMoveEvent
683
684 KisCanvas2 *kiscanvas = qobject_cast<KisCanvas2*>(canvas());
686 if (decoration && decoration->visible() && decoration->hasPaintableAssistants()) {
687 kiscanvas->updateCanvasDecorations();
688 }
689
690 if (!m_oldColorPreviewUpdateRect.isEmpty()) {
692 }
693
694 if (!m_oldOutlineRect.isEmpty()) {
696 }
697
698 if (!outlineDocRect.isEmpty()) {
722 const qreal maxUpdateAheadOutlinePortion = 0.5;
723
725 const qreal offsetFuzzyExtension = 0.1;
726
727 const qreal moveDistance = KisAlgebra2D::norm(outlineMoveVector);
728
729 QRectF offsetRect;
730
731 if (moveDistance < maxUpdateAheadOutlinePortion * KisAlgebra2D::maxDimension(outlineDocRect)) {
732 offsetRect = outlineDocRect.translated((1.0 + offsetFuzzyExtension) * outlineMoveVector);
733 }
734
735 kiscanvas->updateCanvasToolOutlineDoc(outlineDocRect | offsetRect);
736 }
737
738 if (!colorPreviewDocUpdateRect.isEmpty()) {
739 kiscanvas->updateCanvasToolOutlineDoc(colorPreviewDocUpdateRect);
740 }
741
742 m_oldOutlineRect = outlineDocRect;
743 m_oldColorPreviewUpdateRect = colorPreviewDocUpdateRect;
744}
745
749
751 const KoPointerEvent *event,
753{
754 KisCanvas2 *canvas2 = dynamic_cast<KisCanvas2 *>(canvas());
755 KIS_ASSERT(canvas2);
756 const KisCoordinatesConverter *converter = canvas2->coordinatesConverter();
757
758 const QPointF pixelPos = convertToPixelCoord(documentPos);
759 // When touch drawing, a "hover" event means the finger was just pressed
760 // down. The last cursor position is invalid with regards to distance and
761 // speed, since it isn't updated while the finger isn't down, so reset it.
762 if (event && event->isTouchEvent() && mode() == HOVER_MODE) {
763 m_d->lastCursorPos.reset(pixelPos);
764 }
765
766 KisPaintInformation info(pixelPos);
772
773 const qreal currentZoom = canvas2->resourceManager() ? canvas2->resourceManager()->resource(KoCanvasResource::EffectiveZoom).toReal() : 1.0;
774
775 QPointF prevPoint = m_d->lastCursorPos.pushThroughHistory(pixelPos, currentZoom);
776 qreal startAngle = KisAlgebra2D::directionBetweenPoints(prevPoint, pixelPos, 0);
777 KisDistanceInformation distanceInfo(prevPoint, startAngle);
778
780 info.registerDistanceInformation(&distanceInfo);
781
783 brushOutline(info,
784 outlineMode, converter->effectivePhysicalZoom());
785
786 return path;
787}
788
float value(const T *src, size_t ch)
qreal v
const QString COMPOSITE_ERASE
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void activate(bool sampleCurrentLayer, bool pickFgColor)
void paint(QPainter &gc, const KoViewConverter &converter)
void continueAction(const QPointF &docPoint)
void startAction(const QPointF &docPoint, int radius, int blend)
QRectF colorPreviewDocRect(const QPointF &docPoint)
KisPopupPalette * popupPalette
void updateCanvasToolOutlineDoc(const QRectF &docRect)
KisCoordinatesConverter * coordinatesConverter
KisViewManager * viewManager() const
KisAbstractCanvasWidget * canvasWidget
KisPaintingAssistantsDecorationSP paintingAssistantsDecoration() const
void updateCanvasDecorations()
const KoViewConverter * viewConverter() const override
KisPaintOpPresetSP currentPreset() const
static KisConfigNotifier * instance()
qreal outlineSizeMinimum(bool defaultValue=false) const
OutlineStyle newOutlineStyle(bool defaultValue=false) const
bool forceAlwaysFullSizedOutline(bool defaultValue=false) const
OutlineStyle eraserOutlineStyle(bool defaultValue=false) const
bool forceAlwaysFullSizedEraserOutline(bool defaultValue=false) const
bool showOutlineWhilePainting(bool defaultValue=false) const
bool separateEraserCursor(bool defaultValue=false) const
bool showEraserOutlineWhilePainting(bool defaultValue=false) const
int maxBrushSize(bool defaultValue=false) const
QPointF pixelToDocument(const QPointF &pixelCoord) const
void addPath(const QPainterPath &path)
void addEllipse(const QPointF &center, qreal rx, qreal ry)
void setRandomSource(KisRandomSourceSP value)
void setCanvasMirroredV(bool value)
void setCanvasMirroredH(bool value)
DistanceInformationRegistrar registerDistanceInformation(KisDistanceInformation *distance)
void setCanvasRotation(qreal rotation)
void setPerStrokeRandomSource(KisPerStrokeRandomSourceSP value)
The PopupWidgetInterface abstract class defines the basic interface that will be used by all popup wi...
QRectF m_oldColorPreviewUpdateRect
void enableControl(QWidget *control, bool value)
std::vector< int > m_standardBrushSizes
void slotColorPickerRequestedOutlineUpdate()
virtual KisOptimizedBrushOutline getOutlinePath(const QPointF &documentPos, const KoPointerEvent *event, KisPaintOpSettings::OutlineMode outlineMode)
QPointF m_outlineDocPoint
virtual void requestUpdateOutline(const QPointF &outlineDocPoint, const KoPointerEvent *event)
void deactivate() override
int flags() const override
void mouseReleaseEvent(KoPointerEvent *event) override
QWidget * createOptionWidget() override
QRectF m_oldOutlineRect
void activate(const QSet< KoShape * > &shapes) override
void deactivateAlternateAction(AlternateAction action) override
void setOutlineVisible(bool visible)
void addOptionWidgetLayout(QLayout *layout)
Add the tool-specific layout to the default option widget layout.
void increaseBrushSize()
void paint(QPainter &gc, const KoViewConverter &converter) override
KisPaintOpPresetSP m_oldPreset
void deactivatePrimaryAction() override
void sigPaintingFinished()
void setMode(ToolMode mode) override
bool isSamplingAction(AlternateAction action)
void rotateBrushTipCounterClockwisePrecise()
void mousePressEvent(KoPointerEvent *event) override
void rotateBrushTipClockwise()
bool isOutlineEnabled() const
bool isOutlineVisible() const
virtual void addOptionWidgetOption(QWidget *control, QWidget *label=nullptr)
Add a widget and a label to the current option widget layout.
bool isEraser() const
void rotateBrushTipClockwisePrecise()
KisToolPaint(KoCanvasBase *canvas, const QCursor &cursor)
QScopedPointer< Private > m_d
void slotColorPickerRequestedCursor(const QCursor &cursor)
void decreaseBrushSize()
KisOptimizedBrushOutline m_currentOutline
void showControl(QWidget *control, bool value)
void slotPopupQuickHelp()
void canvasResourceChanged(int key, const QVariant &v) override
KisPopupWidgetInterface * popupWidget() override
void endAlternateAction(KoPointerEvent *event, AlternateAction action) override
void activatePrimaryAction() override
QGridLayout * m_optionsWidgetLayout
void continueAlternateAction(KoPointerEvent *event, AlternateAction action) override
void rotateBrushTipCounterClockwise()
void activateAlternateAction(AlternateAction action) override
void mouseMoveEvent(KoPointerEvent *event) override
KisAsyncColorSamplerHelper m_colorSamplerHelper
virtual QString quickHelp() const
void beginAlternateAction(KoPointerEvent *event, AlternateAction action) override
~KisToolPaint() override
void slotColorPickerRequestedCursorReset()
KisOptimizedBrushOutline tryFixBrushOutline(const KisOptimizedBrushOutline &originalOutline)
void setOutlineEnabled(bool enabled)
void tryRestoreOpacitySnapshot()
KisCanvasResourceProvider * canvasResourceProvider()
void showFloatingMessage(const QString &message, const QIcon &icon, int timeout=4500, KisFloatingMessage::Priority priority=KisFloatingMessage::Medium, int alignment=Qt::AlignCenter|Qt::TextWordWrap)
shows a floating message in the top right corner of the canvas
QPointer< KoCanvasResourceProvider > resourceManager
bool isTouchEvent() const
QPointF point
The point in document coordinates.
Q_INVOKABLE QString toolId() const
void statusTextChanged(const QString &statusText)
void useCursor(const QCursor &cursor)
QAction * action(const QString &name) const
KoPointerEvent * lastDeliveredPointerEvent() const
virtual void zoom(qreal *zoomX, qreal *zoomY) const
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
OutlineStyle
Definition kis_global.h:53
@ OUTLINE_CIRCLE
Definition kis_global.h:55
@ OUTLINE_FULL
Definition kis_global.h:56
@ OUTLINE_TILT
Definition kis_global.h:57
@ OUTLINE_NONE
Definition kis_global.h:54
QWidget * findLabelWidget(QGridLayout *layout, QWidget *control)
auto maxDimension(Size size) -> decltype(size.width())
qreal directionBetweenPoints(const QPointF &p1, const QPointF &p2, qreal defaultAngle)
qreal norm(const T &a)
QIcon loadIcon(const QString &name)
@ EffectiveZoom
-Used only by painting tools for non-displaying purposes
KisPaintOpUtils::PositionHistory lastCursorPos
QPointF convertToPixelCoord(KoPointerEvent *e)
Definition kis_tool.cc:189
virtual ToolMode mode() const
Definition kis_tool.cc:407
virtual void activatePrimaryAction()
Definition kis_tool.cc:421
KisImageWSP currentImage()
Definition kis_tool.cc:393
void mouseReleaseEvent(KoPointerEvent *event) override
Definition kis_tool.cc:515
virtual void resetCursorStyle()
Definition kis_tool.cc:613
virtual void continueAlternateAction(KoPointerEvent *event, AlternateAction action)
Definition kis_tool.cc:477
QWidget * optionWidget
Definition kis_tool.cc:73
KisPaintOpPresetSP currentPaintOpPreset()
Definition kis_tool.cc:359
QPointF pixelToView(const QPoint &pixelCoord) const
Definition kis_tool.cc:269
virtual void activateAlternateAction(AlternateAction action)
Definition kis_tool.cc:456
virtual void deactivateAlternateAction(AlternateAction action)
Definition kis_tool.cc:461
bool isActive
Definition kis_tool.h:44
virtual void endAlternateAction(KoPointerEvent *event, AlternateAction action)
Definition kis_tool.cc:483
void mousePressEvent(KoPointerEvent *event) override
Definition kis_tool.cc:510
void canvasResourceChanged(int key, const QVariant &res) override
Definition kis_tool.cc:139
@ FLAG_USES_CUSTOM_SIZE
Definition kis_tool.h:47
@ FLAG_USES_CUSTOM_COMPOSITEOP
Definition kis_tool.h:47
void mouseMoveEvent(KoPointerEvent *event) override
Definition kis_tool.cc:520
void activate(const QSet< KoShape * > &shapes) override
Definition kis_tool.cc:93
void paintToolOutline(QPainter *painter, const KisOptimizedBrushOutline &path)
Definition kis_tool.cc:589
void deactivate() override
Definition kis_tool.cc:131
@ SECONDARY_PAINT_MODE
Definition kis_tool.h:301
@ GESTURE_MODE
Definition kis_tool.h:303
@ PAINT_MODE
Definition kis_tool.h:300
@ HOVER_MODE
Definition kis_tool.h:299
QCursor cursor
Definition kis_tool.cc:64
virtual void beginAlternateAction(KoPointerEvent *event, AlternateAction action)
Definition kis_tool.cc:466
virtual void deactivatePrimaryAction()
Definition kis_tool.cc:426
AlternateAction
Definition kis_tool.h:134
@ SampleFgImage
Definition kis_tool.h:139
@ SampleFgNode
Definition kis_tool.h:137
@ SampleBgImage
Definition kis_tool.h:140
@ SampleBgNode
Definition kis_tool.h:138
virtual void setMode(ToolMode mode)
Definition kis_tool.cc:403
KisCanvas2 * canvas