Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tool_fill.cc
Go to the documentation of this file.
1/*
2* kis_tool_fill.cc - part of Krayon
3*
4* SPDX-FileCopyrightText: 2000 John Califf <jcaliff@compuzone.net>
5* SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org>
6* SPDX-FileCopyrightText: 2004 Bart Coppens <kde@bartcoppens.be>
7*
8* SPDX-License-Identifier: GPL-2.0-or-later
9*/
10
11#include "kis_tool_fill.h"
12
13#include <kis_debug.h>
14#include <klocalizedstring.h>
15
16#include <QSlider>
17#include <QSpinBox>
18#include <QCheckBox>
19#include <QPushButton>
20
23#include <KoGroupButton.h>
24
25#include <ksharedconfig.h>
26
27#include <KoCanvasBase.h>
28#include <KoPointerEvent.h>
29
30#include <kis_layer.h>
31#include <resources/KoPattern.h>
32#include <kis_selection.h>
33
34#include <KisViewManager.h>
35#include <canvas/kis_canvas2.h>
37#include <kis_slider_spin_box.h>
39#include <kis_cursor.h>
41#include <KisAngleSelector.h>
43#include <kis_color_button.h>
44#include <kis_cmb_composite.h>
45
47#include <kis_command_utils.h>
48#include <kis_layer_utils.h>
49#include <krita_utils.h>
53#include <kis_fill_painter.h>
55
56#include <KisPart.h>
57#include <KisDocument.h>
58#include <kis_dummies_facade.h>
64
65#include "kis_icon_utils.h"
66
68 : KisToolPaint(canvas, KisCursor::load("tool_fill_cursor.png", 6, 6))
69 , m_fillMask(nullptr)
70 , m_referencePaintDevice(nullptr)
71 , m_referenceNodeList(nullptr)
72 , m_previousTime(0)
73 , m_compressorFillUpdate(150, KisSignalCompressor::FIRST_ACTIVE)
74 , m_dirtyRect(nullptr)
75 , m_fillStrokeId(nullptr)
76{
77 setObjectName("tool_fill");
78 connect(&m_compressorFillUpdate, SIGNAL(timeout()), SLOT(slotUpdateFill()));
79
80 KisCanvas2 *kritaCanvas = dynamic_cast<KisCanvas2*>(canvas);
81
82 connect(kritaCanvas->viewManager()->canvasResourceProvider(), SIGNAL(sigEffectiveCompositeOpChanged()), SLOT(resetCursorStyle()));
83}
84
88
90{
92 useCursor(KisCursor::load("tool_fill_eraser_cursor.png", 6, 6));
93 } else {
95 }
96
98}
99
100void KisToolFill::activate(const QSet<KoShape*> &shapes)
101{
103 m_configGroup = KSharedConfig::openConfig()->group(toolId());
104 KisCanvas2 *kisCanvas = static_cast<KisCanvas2*>(canvas());
105 KisCanvasResourceProvider *resourceProvider = kisCanvas->viewManager()->canvasResourceProvider();
106 if (resourceProvider) {
107 connect(resourceProvider,
108 SIGNAL(sigNodeChanged(const KisNodeSP)),
109 this,
112 }
113}
114
116{
117 m_referencePaintDevice = nullptr;
118 m_referenceNodeList = nullptr;
119 KisCanvas2 *kisCanvas = static_cast<KisCanvas2*>(canvas());
120 KisCanvasResourceProvider *resourceProvider = kisCanvas->viewManager()->canvasResourceProvider();
121 if (resourceProvider) {
122 disconnect(resourceProvider,
123 SIGNAL(sigNodeChanged(const KisNodeSP)),
124 this,
126 }
129}
130
132{
133 // cannot use fill tool on non-painting layers.
134 // this logic triggers with multiple layer types like vector layer, clone layer, file layer, group layer
135 if (currentNode().isNull() || currentNode()->inherits("KisShapeLayer") || nodePaintAbility()!=NodePaintAbility::PAINT ) {
136 KisCanvas2 * kiscanvas = static_cast<KisCanvas2*>(canvas());
137 kiscanvas->viewManager()->
138 showFloatingMessage(
139 i18n("You cannot use this tool with the selected layer type"),
140 QIcon(), 2000, KisFloatingMessage::Medium, Qt::AlignCenter);
141 event->ignore();
142 return;
143 }
144
145 if (!nodeEditable()) {
146 event->ignore();
147 return;
148 }
149
150 m_fillStartWidgetPosition = event->pos();
151 const QPoint lastImagePosition = convertToImagePixelCoordFloored(event);
152
153 if (!currentNode() ||
154 (!image()->wrapAroundModePermitted() &&
155 !image()->bounds().contains(lastImagePosition))) {
156 return;
157 }
158
159 // Switch the fill mode if shift or alt modifiers are pressed
160 if (event->modifiers() == Qt::ShiftModifier) {
163 } else {
165 }
166 } else if (event->modifiers() == Qt::AltModifier) {
169 } else {
171 }
172 } else {
174 }
175
176 m_seedPoints.append(lastImagePosition);
177 beginFilling(lastImagePosition);
178 m_isFilling = true;
179
181}
182
184{
187 return;
188 }
189
190 if (!m_isDragging) {
191 const int dragDistanceSquared =
192 pow2(event->pos().x() - m_fillStartWidgetPosition.x()) +
193 pow2(event->pos().y() - m_fillStartWidgetPosition.y());
194
195 if (dragDistanceSquared < minimumDragDistanceSquared) {
196 return;
197 }
198
199 m_isDragging = true;
200 }
201
202 const QPoint newImagePosition = convertToImagePixelCoordFloored(event);
203 m_seedPoints.append(newImagePosition);
204
206}
207
209{
210 if (m_isFilling) {
212 endFilling();
213 }
214
215 m_isFilling = false;
216 m_isDragging = false;
217 m_seedPoints.clear();
218}
219
221{
222 if (action == ChangeSize) {
223 beginPrimaryAction(event);
224 return;
225 }
227}
228
237
239{
240 if (action == ChangeSize) {
241 endPrimaryAction(event);
242 return;
243 }
245}
246
247void KisToolFill::beginFilling(const QPoint &seedPoint)
248{
250
252 new KisStrokeStrategyUndoCommandBased(kundo2_i18n("Flood Fill"), false, image().data());
253 strategy->setSupportsWrapAroundMode(true);
254 m_fillStrokeId = image()->startStroke(strategy);
256
257 m_resourcesSnapshot = new KisResourcesSnapshot(image(), currentNode(), this->canvas()->resourceManager());
258
259 KisPaintDeviceSP referencePaintDevice = nullptr;
262 referencePaintDevice = currentNode()->paintDevice();
263 } else if (m_reference == Reference_AllLayers) {
264 referencePaintDevice = currentImage()->projection();
266 if (!m_referenceNodeList) {
267 referencePaintDevice = KisMergeLabeledLayersCommand::createRefPaintDevice(image(), "Fill Tool Reference Result Paint Device");
269 } else {
270 referencePaintDevice = m_referencePaintDevice;
271 }
272 KisPaintDeviceSP newReferencePaintDevice = KisMergeLabeledLayersCommand::createRefPaintDevice(image(), "Fill Tool Reference Result Paint Device");
274 const int currentTime = image()->animationInterface()->currentTime();
275 image()->addJob(
279 image(),
281 newReferenceNodeList,
282 referencePaintDevice,
283 newReferencePaintDevice,
286 m_previousTime != currentTime,
287 m_useActiveLayer ? currentNode() : nullptr
288 )),
289 false,
292 )
293 );
294 referencePaintDevice = newReferencePaintDevice;
295 m_referenceNodeList = newReferenceNodeList;
296 m_previousTime = currentTime;
297 }
298
299 QSharedPointer<KoColor> referenceColor(new KoColor);
301 // We need to obtain the reference color from the reference paint
302 // device, but it is produced in a stroke, so we must get the color
303 // after the device is ready. So we get it in the stroke
304 image()->addJob(
308 [referencePaintDevice, referenceColor, seedPoint]() -> KUndo2Command*
309 {
310 *referenceColor = referencePaintDevice->pixel(seedPoint);
311 return 0;
312 }
313 )),
314 false,
317 )
318 );
319 } else {
320 // Here the reference device is already ready, so we obtain the
321 // reference color directly
322 *referenceColor = referencePaintDevice->pixel(seedPoint);
323 // Reset this so that the device from color labeled layers gets
324 // regenerated when that mode is selected again
325 m_referenceNodeList.reset();
326 }
327
328 m_referencePaintDevice = referencePaintDevice;
329 m_referenceColor = referenceColor;
330
332 }
333
334 m_dirtyRect.reset(new QRect);
335 m_transform.reset();
337 const qreal normalizedScale = m_patternScale * 0.01;
338 m_transform.scale(normalizedScale, normalizedScale);
340}
341
342void KisToolFill::addFillingOperation(const QPoint &seedPoint)
343{
344 const QVector<QPoint> seedPoints({seedPoint});
345 addFillingOperation(seedPoints);
346}
347
349{
351
352 const qreal customOpacity = m_customOpacity / 100.0;
353
358
359 const bool blendingOptionsAreNoOp = m_useCustomBlendingOptions
360 ? (qFuzzyCompare(customOpacity, OPACITY_OPAQUE_F) &&
364
365 const bool useFastMode = !m_resourcesSnapshot->activeSelection() &&
366 blendingOptionsAreNoOp &&
368 m_opacitySpread == 100 &&
369 m_useSelectionAsBoundary == false &&
370 !m_antiAlias && m_sizemod == 0 && m_feather == 0 &&
371 m_closeGap == 0 &&
373
374 visitor->setSeedPoints(seedPoints);
375 visitor->setUseFastMode(useFastMode);
381 visitor->setCustomOpacity(customOpacity);
383 }
384 visitor->setRegionFillingMode(
388 );
391 }
394 visitor->setCloseGap(m_closeGap);
396 visitor->setAntiAlias(m_antiAlias);
397 visitor->setSizeMod(m_sizemod);
399 visitor->setFeather(m_feather);
400 if (m_isDragging) {
401 visitor->setContinuousFillMode(
405 );
408 }
410
411 image()->addJob(
415 false,
418 )
419 );
420 } else {
421 KisSelectionSP fillMask = m_fillMask;
424
425 {
427 KisFillPainter painter;
428 QRect bounds = currentImage()->bounds();
429 if (selection) {
430 bounds = bounds.intersected(selection->projection()->selectedRect());
431 }
432
435 painter.setAntiAlias(m_antiAlias);
436 painter.setSizemod(m_sizemod);
438 painter.setFeather(m_feather);
439
443 bounds, selection ? selection->projection() : nullptr, progressHelper
444 );
445
446 for (KisStrokeJobData *job : jobs) {
447 image()->addJob(m_fillStrokeId, job);
448 }
449 }
450
451 {
452 FillProcessingVisitor *visitor = new FillProcessingVisitor(nullptr,
453 fillMask,
455
456 visitor->setSeedPoints(seedPoints);
457 visitor->setSelectionOnly(true);
462 visitor->setCustomOpacity(customOpacity);
464 }
466 visitor->setProgressHelper(progressHelper);
467
468 image()->addJob(
472 false,
475 )
476 );
477 }
478 }
479}
480
495
507
509{
511
514 // clear to not re-add the segments, but retain the last point to maintain continuity
515 m_seedPoints = {m_seedPoints.last()};
516 } else {
518 }
520}
521
523{
525
526 // Create widgets
527 KisOptionButtonStrip *optionButtonStripWhatToFill =
529 m_buttonWhatToFillSelection = optionButtonStripWhatToFill->addButton(
530 KisIconUtils::loadIcon("tool_outline_selection"));
531 m_buttonWhatToFillContiguous = optionButtonStripWhatToFill->addButton(
532 KisIconUtils::loadIcon("contiguous-selection"));
533 m_buttonWhatToFillSimilar = optionButtonStripWhatToFill->addButton(
534 KisIconUtils::loadIcon("similar-selection"));
535 m_buttonWhatToFillContiguous->setChecked(true);
536
537 KisOptionButtonStrip *optionButtonStripFillWith = new KisOptionButtonStrip;
538 m_buttonFillWithFG = optionButtonStripFillWith->addButton(
539 KisIconUtils::loadIcon("object-order-lower-calligra"));
540 m_buttonFillWithBG = optionButtonStripFillWith->addButton(
541 KisIconUtils::loadIcon("object-order-raise-calligra"));
543 optionButtonStripFillWith->addButton(KisIconUtils::loadIcon("pattern"));
544 m_buttonFillWithFG->setChecked(true);
546 m_sliderPatternScale->setRange(0, 10000, 2);
550 i18nc("The pattern 'scale' spinbox in fill tool options; {n} is the number value, % is the percent sign",
551 "Scale: {n}%"));
555 m_checkBoxCustomBlendingOptions = new QCheckBox(i18n("Use custom blending options"));
559 i18nc("{n} is the number value, % is the percent sign", "Opacity: {n}%"));
561
562 KisOptionButtonStrip *optionButtonStripContiguousFillMode = new KisOptionButtonStrip;
563 m_buttonContiguousFillModeFloodFill = optionButtonStripContiguousFillMode->addButton(
564 KisIconUtils::loadIcon("region-filling-flood-fill"));
565 m_buttonContiguousFillModeBoundaryFill = optionButtonStripContiguousFillMode->addButton(
566 KisIconUtils::loadIcon("region-filling-boundary-fill"));
567 m_buttonContiguousFillModeFloodFill->setChecked(true);
570 m_sliderThreshold->setPrefix(i18nc("The 'threshold' spinbox prefix in fill tool options", "Threshold: "));
573 m_sliderSpread->setRange(0, 100);
576 i18nc("The 'spread' spinbox in fill tool options; {n} is the number value, % is the percent sign",
577 "Spread: {n}%"));
578
580 m_sliderCloseGap->setPrefix(i18nc("The 'close gap' spinbox prefix in fill tool options", "Close Gap: "));
582 m_sliderCloseGap->setSuffix(i18n(" px"));
583
585 new QCheckBox(
586 i18nc("The 'use selection as boundary' checkbox in fill tool to use selection borders as boundary when filling",
587 "Use selection as boundary")
588 );
589 m_checkBoxSelectionAsBoundary->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);
590
591 m_checkBoxAntiAlias = new QCheckBox(i18nc("The anti-alias checkbox in fill tool options", "Anti-aliasing"));
592
595 m_sliderGrow->setPrefix(i18nc("The 'grow/shrink' spinbox prefix in fill tool options", "Grow: "));
596 m_sliderGrow->setRange(-400, 400);
597 m_sliderGrow->setSoftRange(-40, 40);
598 m_sliderGrow->setSuffix(i18n(" px"));
599 m_buttonStopGrowingAtDarkestPixel = new QToolButton;
600 m_buttonStopGrowingAtDarkestPixel->setAutoRaise(true);
601 m_buttonStopGrowingAtDarkestPixel->setCheckable(true);
602 m_buttonStopGrowingAtDarkestPixel->setIcon(KisIconUtils::loadIcon("stop-at-boundary"));
603 containerGrow->appendWidget("sliderGrow", m_sliderGrow);
604 containerGrow->appendWidget("buttonStopGrowingAtDarkestPixel", m_buttonStopGrowingAtDarkestPixel);
605 containerGrow->setOrientation(Qt::Horizontal);
607 m_sliderFeather->setPrefix(i18nc("The 'feather' spinbox prefix in fill tool options", "Feather: "));
608 m_sliderFeather->setRange(0, 400);
610 m_sliderFeather->setSuffix(i18n(" px"));
611
612 KisOptionButtonStrip *optionButtonStripReference = new KisOptionButtonStrip;
613 m_buttonReferenceCurrent = optionButtonStripReference->addButton(
614 KisIconUtils::loadIcon("current-layer"));
615 m_buttonReferenceAll = optionButtonStripReference->addButton(
616 KisIconUtils::loadIcon("all-layers"));
618 optionButtonStripReference->addButton(KisIconUtils::loadIcon("tag"));
619 m_buttonReferenceCurrent->setChecked(true);
625 m_checkBoxUseActiveLayer = new QCheckBox(i18n("Use active layer"));
626
627 KisOptionButtonStrip *optionButtonStripDragFill =
629 m_buttonDragFillDoNotUse = optionButtonStripDragFill->addButton(
630 KisIconUtils::loadIcon("dialog-cancel"));
631 m_buttonDragFillAny = optionButtonStripDragFill->addButton(
632 KisIconUtils::loadIcon("different-regions"));
633 m_buttonDragFillSimilar = optionButtonStripDragFill->addButton(
634 KisIconUtils::loadIcon("similar-regions"));
635 m_buttonDragFillAny->setChecked(true);
636
637 QPushButton *buttonReset = new QPushButton(i18nc("The 'reset' button in fill tool options", "Reset"));
638
639 // Set the tooltips
640 m_buttonWhatToFillSelection->setToolTip(i18n("Fill the active selection, or the entire canvas"));
641 m_buttonWhatToFillContiguous->setToolTip(i18n("Fill a contiguous region"));
642 m_buttonWhatToFillSimilar->setToolTip(i18n("Fill all regions of a similar color"));
643
644 m_buttonFillWithFG->setToolTip(i18n("Foreground color"));
645 m_buttonFillWithBG->setToolTip(i18n("Background color"));
646 m_buttonFillWithPattern->setToolTip(i18n("Pattern"));
647 m_sliderPatternScale->setToolTip(i18n("Set the scale of the pattern"));
648 m_angleSelectorPatternRotation->setToolTip(i18n("Set the rotation of the pattern"));
649 m_checkBoxCustomBlendingOptions->setToolTip(i18n("Set custom blending options instead of using the brush ones"));
650 m_sliderCustomOpacity->setToolTip(i18n("Set a custom opacity for the fill"));
651 m_comboBoxCustomCompositeOp->setToolTip(i18n("Set a custom blend mode for the fill"));
652
653 m_buttonContiguousFillModeFloodFill->setToolTip(i18n("Fill regions similar in color to the clicked region"));
654 m_buttonContiguousFillModeBoundaryFill->setToolTip(i18n("Fill all regions until a specific boundary color"));
655 m_buttonContiguousFillBoundaryColor->setToolTip(i18n("Boundary color"));
656 m_sliderThreshold->setToolTip(i18n("Set the color similarity tolerance of the fill. Increasing threshold increases the range of similar colors to be filled."));
657 m_sliderSpread->setToolTip(i18n("Set the extent of the opaque portion of the fill. Decreasing spread decreases opacity of fill areas depending on color similarity."));
658 m_sliderCloseGap->setToolTip(i18n("Close gaps in lines up to the set amount"));
659 m_checkBoxSelectionAsBoundary->setToolTip(i18n("Set if the contour of the active selection should be treated as a boundary when filling the region"));
660
661 m_checkBoxAntiAlias->setToolTip(i18n("Smooths the edges of the fill"));
662 m_sliderGrow->setToolTip(i18n("Grow or shrink the fill by the set amount"));
663 m_buttonStopGrowingAtDarkestPixel->setToolTip(i18n("Stop growing at the darkest and/or most opaque pixels"));
664 m_sliderFeather->setToolTip(i18n("Blur the fill by the set amount"));
665
666 m_buttonReferenceCurrent->setToolTip(i18n("Fill regions found from the active layer"));
667 m_buttonReferenceAll->setToolTip(i18n("Fill regions found from the merging of all layers"));
668 m_buttonReferenceLabeled->setToolTip(i18n("Fill regions found from the merging of layers with specific color labels"));
669 m_checkBoxUseActiveLayer->setToolTip(i18n("Includes the active layer in regions found from merging of layers with specific color labels"));
670
671 m_buttonDragFillDoNotUse->setToolTip(i18n("Dragging will not fill different regions"));
672 m_buttonDragFillAny->setToolTip(i18n("Dragging will fill regions of any color"));
673 m_buttonDragFillSimilar->setToolTip(i18n("Dragging will fill only regions similar in color to the initial region (useful for filling line-art)"));
674
675 buttonReset->setToolTip(i18n("Reset the options to their default values"));
676
677 // Construct the option widget
679 m_optionWidget->setContentsMargins(0, 10, 0, 10);
681
682 KisOptionCollectionWidgetWithHeader *sectionWhatToFill =
684 i18nc("The 'fill mode' section label in fill tool options", "Fill mode")
685 );
686 sectionWhatToFill->setPrimaryWidget(optionButtonStripWhatToFill);
687 m_optionWidget->appendWidget("sectionWhatToFill", sectionWhatToFill);
688
689 KisOptionCollectionWidgetWithHeader *sectionFillWith =
691 i18nc("The 'fill source' section label in fill tool options", "Fill source")
692 );
693 sectionFillWith->setPrimaryWidget(optionButtonStripFillWith);
694 sectionFillWith->appendWidget("sliderPatternScale", m_sliderPatternScale);
695 sectionFillWith->appendWidget("angleSelectorPatternRotation", m_angleSelectorPatternRotation);
696 sectionFillWith->appendWidget("checkBoxCustomBlendingOptions", m_checkBoxCustomBlendingOptions);
697 sectionFillWith->appendWidget("sliderCustomOpacity", m_sliderCustomOpacity);
698 sectionFillWith->appendWidget("comboBoxCustomCompositeOp", m_comboBoxCustomCompositeOp);
699 sectionFillWith->setWidgetVisible("sliderPatternScale", false);
700 sectionFillWith->setWidgetVisible("angleSelectorPatternRotation", false);
701 m_optionWidget->appendWidget("sectionFillWith", sectionFillWith);
702
704 widgetLabelsGroup->appendWidget("labelWidget", m_widgetLabels);
705 widgetLabelsGroup->appendWidget("checkBoxUseActiveLayer", m_checkBoxUseActiveLayer);
706 widgetLabelsGroup->setWidgetsMargin(0);
707
708 KisOptionCollectionWidgetWithHeader *sectionReference =
710 i18nc("The 'reference' section label in fill tool options", "Reference")
711 );
712 sectionReference->setPrimaryWidget(optionButtonStripReference);
713 sectionReference->appendWidget("widgetLabels", widgetLabelsGroup);
714 sectionReference->setWidgetVisible("widgetLabels", false);
715 m_optionWidget->appendWidget("sectionReference", sectionReference);
716
717 KisOptionCollectionWidgetWithHeader *sectionRegionExtent =
719 i18nc("The 'fill extent' section label in fill tool options", "Fill extent")
720 );
721 sectionRegionExtent->setPrimaryWidget(optionButtonStripContiguousFillMode);
722 sectionRegionExtent->appendWidget("buttonContiguousFillBoundaryColor", m_buttonContiguousFillBoundaryColor);
723 sectionRegionExtent->setWidgetVisible("buttonContiguousFillBoundaryColor", false);
724 sectionRegionExtent->appendWidget("sliderThreshold", m_sliderThreshold);
725 sectionRegionExtent->appendWidget("sliderSpread", m_sliderSpread);
726 sectionRegionExtent->appendWidget("sliderCloseGap", m_sliderCloseGap);
727 sectionRegionExtent->appendWidget("checkBoxSelectionAsBoundary", m_checkBoxSelectionAsBoundary);
728 m_optionWidget->appendWidget("sectionRegionExtent", sectionRegionExtent);
729
730 KisOptionCollectionWidgetWithHeader *sectionAdjustments =
732 i18nc("The 'adjustments' section label in fill tool options", "Adjustments")
733 );
734 sectionAdjustments->appendWidget("checkBoxAntiAlias", m_checkBoxAntiAlias);
735 sectionAdjustments->appendWidget("containerGrow", containerGrow);
736 sectionAdjustments->appendWidget("sliderFeather", m_sliderFeather);
737 m_optionWidget->appendWidget("sectionAdjustments", sectionAdjustments);
738
739 KisOptionCollectionWidgetWithHeader *sectionDragFill =
741 i18nc("The 'drag-fill mode' section label in fill tool options", "Drag-fill mode")
742 );
743 sectionDragFill->setPrimaryWidget(optionButtonStripDragFill);
744 m_optionWidget->appendWidget("sectionDragFill", sectionDragFill);
745
746 m_optionWidget->appendWidget("buttonReset", buttonReset);
747
748 // Initialize widgets
750 m_buttonWhatToFillSelection->setChecked(true);
751 m_optionWidget->setWidgetVisible("sectionRegionExtent", false);
752 m_optionWidget->setWidgetVisible("sectionAdjustments", false);
753 m_optionWidget->setWidgetVisible("sectionReference", false);
754 m_optionWidget->setWidgetVisible("sectionDragFill", false);
756 m_buttonWhatToFillSimilar->setChecked(true);
757 m_optionWidget->setWidgetVisible("sectionDragFill", false);
758 sectionRegionExtent->setWidgetVisible("checkBoxSelectionAsBoundary", false);
759 sectionRegionExtent->setWidgetVisible("sliderCloseGap", false);
760 }
763 m_buttonFillWithBG->setChecked(true);
764 } else if (m_fillType == FillType_FillWithPattern) {
765 m_buttonFillWithPattern->setChecked(true);
766 sectionFillWith->setWidgetVisible("sliderPatternScale", true);
767 sectionFillWith->setWidgetVisible("angleSelectorPatternRotation", true);
768 }
774 ? currentNode()->paintDevice()->colorSpace()
775 : nullptr);
778 sectionFillWith->setWidgetVisible("sliderCustomOpacity", false);
779 sectionFillWith->setWidgetVisible("comboBoxCustomCompositeOp", false);
780 }
783 sectionRegionExtent->setWidgetVisible("buttonContiguousFillBoundaryColor",
785 }
791 m_checkBoxAntiAlias->setChecked(m_antiAlias);
796 m_buttonReferenceAll->setChecked(true);
798 m_buttonReferenceLabeled->setChecked(true);
799 sectionReference->setWidgetVisible("widgetLabels", true);
800 }
802 m_buttonDragFillDoNotUse->setChecked(true);
804 m_buttonDragFillSimilar->setChecked(true);
805 }
808
809 // Make connections
810 connect(optionButtonStripWhatToFill,
811 SIGNAL(buttonToggled(KoGroupButton *, bool)),
813 connect(optionButtonStripFillWith,
814 SIGNAL(buttonToggled(KoGroupButton *, bool)),
817 SIGNAL(valueChanged(double)),
820 SIGNAL(angleChanged(double)),
823 SIGNAL(toggled(bool)),
826 SIGNAL(valueChanged(int)),
829 SIGNAL(currentIndexChanged(int)),
831 connect(optionButtonStripContiguousFillMode,
832 SIGNAL(buttonToggled(KoGroupButton *, bool)),
835 SIGNAL(changed(const KoColor&)),
837 connect(m_sliderThreshold, SIGNAL(valueChanged(int)), SLOT(slot_sliderThreshold_valueChanged(int)));
838 connect(m_sliderSpread, SIGNAL(valueChanged(int)), SLOT(slot_sliderSpread_valueChanged(int)));
839 connect(m_sliderCloseGap, SIGNAL(valueChanged(int)), SLOT(slot_sliderCloseGap_valueChanged(int)));
841 SIGNAL(toggled(bool)),
843 connect(m_checkBoxAntiAlias, SIGNAL(toggled(bool)), SLOT(slot_checkBoxAntiAlias_toggled(bool)));
844 connect(m_sliderGrow, SIGNAL(valueChanged(int)), SLOT(slot_sliderGrow_valueChanged(int)));
846 SIGNAL(toggled(bool)),
848 connect(m_sliderFeather, SIGNAL(valueChanged(int)), SLOT(slot_sliderFeather_valueChanged(int)));
849 connect(optionButtonStripReference,
850 SIGNAL(buttonToggled(KoGroupButton *, bool)),
853 connect(m_checkBoxUseActiveLayer, SIGNAL(toggled(bool)), SLOT(slot_checkBoxUseActiveLayer_toggled(bool)));
854 connect(
855 optionButtonStripDragFill,
856 SIGNAL(buttonToggled(KoGroupButton *, bool)),
858 connect(buttonReset, SIGNAL(clicked()), SLOT(slot_buttonReset_clicked()));
859
860 return m_optionWidget;
861}
862
864{
865 {
866 const QString whatToFillStr = m_configGroup.readEntry<QString>("whatToFill", "");
867 if (whatToFillStr == "fillSelection") {
869 } else if (whatToFillStr == "fillContiguousRegion") {
871 } else if (whatToFillStr == "fillSimilarRegions") {
873 } else {
874 if (m_configGroup.readEntry<bool>("fillSelection", false)) {
876 } else {
878 }
879 }
880 }
881 {
882 const QString fillTypeStr = m_configGroup.readEntry<QString>("fillWith", "");
883 if (fillTypeStr == "foregroundColor") {
885 } else if (fillTypeStr == "backgroundColor") {
887 } else if (fillTypeStr == "pattern") {
889 } else {
890 if (m_configGroup.readEntry<bool>("usePattern", false)) {
892 } else {
894 }
895 }
896 }
897 m_patternScale = m_configGroup.readEntry<qreal>("patternScale", 100.0);
898 m_patternRotation = m_configGroup.readEntry<qreal>("patternRotate", 0.0);
899 m_useCustomBlendingOptions = m_configGroup.readEntry<bool>("useCustomBlendingOptions", false);
900 m_customOpacity = qBound(0, m_configGroup.readEntry<int>("customOpacity", 100), 100);
901 m_customCompositeOp = m_configGroup.readEntry<QString>("customCompositeOp", COMPOSITE_OVER);
904 }
905 {
906 const QString contiguousFillModeStr = m_configGroup.readEntry<QString>("contiguousFillMode", "");
907 m_contiguousFillMode = contiguousFillModeStr == "boundaryFill"
910 }
912 m_threshold = m_configGroup.readEntry<int>("thresholdAmount", 8);
913 m_opacitySpread = m_configGroup.readEntry<int>("opacitySpread", 100);
914 m_closeGap = m_configGroup.readEntry<int>("closeGapAmount", 0);
915 m_useSelectionAsBoundary = m_configGroup.readEntry<bool>("useSelectionAsBoundary", true);
916 m_antiAlias = m_configGroup.readEntry<bool>("antiAlias", false);
917 m_sizemod = m_configGroup.readEntry<int>("growSelection", 0);
918 m_stopGrowingAtDarkestPixel = m_configGroup.readEntry<bool>("stopGrowingAtDarkestPixel", false);
919 m_feather = m_configGroup.readEntry<int>("featherAmount", 0);
920 {
921 const QString sampleLayersModeStr = m_configGroup.readEntry<QString>("sampleLayersMode", "");
922 if (sampleLayersModeStr == "currentLayer") {
924 } else if (sampleLayersModeStr == "allLayers") {
926 } else if (sampleLayersModeStr == "colorLabeledLayers") {
928 } else {
929 if (m_configGroup.readEntry<bool>("sampleMerged", false)) {
931 } else {
933 }
934 }
935 }
936 {
937 const QStringList colorLabelsStr = m_configGroup.readEntry<QString>("colorLabels", "").split(',', Qt::SkipEmptyParts);
938 m_selectedColorLabels.clear();
939 for (const QString &colorLabelStr : colorLabelsStr) {
940 bool ok;
941 const int colorLabel = colorLabelStr.toInt(&ok);
942 if (ok) {
943 m_selectedColorLabels << colorLabel;
944 }
945 }
946 m_useActiveLayer = m_configGroup.readEntry<bool>("useActiveLayer", false);
947 }
948 {
949 const QString continuousFillModeStr = m_configGroup.readEntry<QString>("continuousFillMode", "fillAnyRegion");
950 if (continuousFillModeStr == "doNotUse") {
952 } else if (continuousFillModeStr == "fillSimilarRegions") {
954 } else {
956 }
957 }
958}
959
961{
962 const QString xmlColor = m_configGroup.readEntry("contiguousFillBoundaryColor", QString());
963 QDomDocument doc;
964 if (doc.setContent(xmlColor)) {
965 QDomElement e = doc.documentElement().firstChild().toElement();
966 QString channelDepthID = doc.documentElement().attribute("channeldepth", Integer16BitsColorDepthID.id());
967 bool ok;
968 if (e.hasAttribute("space") || e.tagName().toLower() == "srgb") {
969 return KoColor::fromXML(e, channelDepthID, &ok);
970 } else if (doc.documentElement().hasAttribute("space") || doc.documentElement().tagName().toLower() == "srgb"){
971 return KoColor::fromXML(doc.documentElement(), channelDepthID, &ok);
972 }
973 }
974 return KoColor();
975}
976
979 bool checked)
980{
981 if (!checked) {
982 return;
983 }
984
986 m_optionWidget->setWidgetVisible("sectionRegionExtent", false);
987 m_optionWidget->setWidgetVisible("sectionAdjustments", false);
988 m_optionWidget->setWidgetVisible("sectionReference", false);
989 m_optionWidget->setWidgetVisible("sectionDragFill", false);
991 m_configGroup.writeEntry("whatToFill", "fillSelection");
992 } else if (button == m_buttonWhatToFillContiguous) {
993 m_optionWidget->setWidgetVisible("sectionRegionExtent", true);
994 m_optionWidget->setWidgetVisible("sectionAdjustments", true);
995 m_optionWidget->setWidgetVisible("sectionReference", true);
996 m_optionWidget->setWidgetVisible("sectionDragFill", true);
998 ->setPrimaryWidgetVisible(true);
1000 ->setWidgetVisible("buttonContiguousFillBoundaryColor", m_contiguousFillMode == ContiguousFillMode_BoundaryFill);
1002 ->setWidgetVisible("sliderCloseGap", true);
1004 ->setWidgetVisible("checkBoxSelectionAsBoundary", true);
1006 m_configGroup.writeEntry("whatToFill", "fillContiguousRegion");
1007 } else {
1008 m_optionWidget->setWidgetVisible("sectionRegionExtent", true);
1009 m_optionWidget->setWidgetVisible("sectionAdjustments", true);
1010 m_optionWidget->setWidgetVisible("sectionReference", true);
1011 m_optionWidget->setWidgetVisible("sectionDragFill", false);
1013 ->setPrimaryWidgetVisible(false);
1015 ->setWidgetVisible("buttonContiguousFillBoundaryColor", false);
1017 ->setWidgetVisible("sliderCloseGap", false);
1019 ->setWidgetVisible("checkBoxSelectionAsBoundary", false);
1021 m_configGroup.writeEntry("whatToFill", "fillSimilarRegions");
1022 }
1023}
1024
1027 bool checked)
1028{
1029 if (!checked) {
1030 return;
1031 }
1032 const bool visible = button == m_buttonFillWithPattern;
1033 KisOptionCollectionWidgetWithHeader *sectionFillWith =
1035 sectionFillWith->setWidgetVisible("sliderPatternScale", visible);
1036 sectionFillWith->setWidgetVisible("angleSelectorPatternRotation", visible);
1037
1042
1043 m_configGroup.writeEntry(
1044 "fillWith",
1046 ? "foregroundColor"
1047 : (button == m_buttonFillWithBG ? "backgroundColor" : "pattern")
1048 );
1049}
1050
1052{
1053 if (value == m_patternScale) {
1054 return;
1055 }
1057 m_configGroup.writeEntry("patternScale", value);
1058}
1059
1061{
1062 if (value == m_patternRotation) {
1063 return;
1064 }
1066 m_configGroup.writeEntry("patternRotate", value);
1067}
1068
1070{
1071 KisOptionCollectionWidgetWithHeader *sectionFillWith =
1073 sectionFillWith->setWidgetVisible("sliderCustomOpacity", checked);
1074 sectionFillWith->setWidgetVisible("comboBoxCustomCompositeOp", checked);
1076 m_configGroup.writeEntry("useCustomBlendingOptions", checked);
1077}
1078
1080{
1081 if (value == m_customOpacity) {
1082 return;
1083 }
1085 m_configGroup.writeEntry("customOpacity", value);
1086}
1087
1089{
1090 Q_UNUSED(index);
1091 const QString compositeOpId = m_comboBoxCustomCompositeOp->selectedCompositeOp().id();
1092 if (compositeOpId == m_customCompositeOp) {
1093 return;
1094 }
1095 m_customCompositeOp = compositeOpId;
1096 m_configGroup.writeEntry("customCompositeOp", compositeOpId);
1097}
1098
1101 bool checked)
1102{
1103 if (!checked) {
1104 return;
1105 }
1106
1107 const bool visible = button == m_buttonContiguousFillModeBoundaryFill;
1108 KisOptionCollectionWidgetWithHeader *sectionRegionExtent =
1110 sectionRegionExtent->setWidgetVisible("buttonContiguousFillBoundaryColor", visible);
1111
1115
1116 m_configGroup.writeEntry(
1117 "contiguousFillMode",
1119 ? "floodFill"
1120 : "boundaryFill"
1121 );
1122}
1123
1125{
1126 if (color == m_contiguousFillBoundaryColor) {
1127 return;
1128 }
1130 m_configGroup.writeEntry("contiguousFillBoundaryColor", color.toXML());
1131}
1132
1134{
1135 if (value == m_threshold) {
1136 return;
1137 }
1139 m_configGroup.writeEntry("thresholdAmount", value);
1140}
1141
1143{
1144 if (value == m_opacitySpread) {
1145 return;
1146 }
1148 m_configGroup.writeEntry("opacitySpread", value);
1149}
1150
1152{
1153 if (value == m_closeGap) {
1154 return;
1155 }
1156 m_closeGap = value;
1157 m_configGroup.writeEntry("closeGapAmount", value);
1158}
1159
1161{
1162 if (checked == m_useSelectionAsBoundary) {
1163 return;
1164 }
1165 m_useSelectionAsBoundary = checked;
1166 m_configGroup.writeEntry("useSelectionAsBoundary", checked);
1167}
1168
1170{
1171 if (checked == m_antiAlias) {
1172 return;
1173 }
1174 m_antiAlias = checked;
1175 m_configGroup.writeEntry("antiAlias", checked);
1176}
1177
1179{
1180 if (value == m_sizemod) {
1181 return;
1182 }
1183 m_sizemod = value;
1184 m_configGroup.writeEntry("growSelection", value);
1185}
1186
1188{
1189 if (enabled == m_stopGrowingAtDarkestPixel) {
1190 return;
1191 }
1193 m_configGroup.writeEntry("stopGrowingAtDarkestPixel", enabled);
1194}
1195
1197{
1198 if (value == m_feather) {
1199 return;
1200 }
1201 m_feather = value;
1202 m_configGroup.writeEntry("featherAmount", value);
1203}
1204
1207 bool checked)
1208{
1209 if (!checked) {
1210 return;
1211 }
1212 KisOptionCollectionWidgetWithHeader *sectionReference =
1214 sectionReference->setWidgetVisible("widgetLabels", button == m_buttonReferenceLabeled);
1215
1220
1221 m_configGroup.writeEntry(
1222 "sampleLayersMode",
1224 ? "currentLayer"
1225 : (button == m_buttonReferenceAll ? "allLayers" : "colorLabeledLayers")
1226 );
1227}
1228
1230{
1232 if (labels == m_selectedColorLabels) {
1233 return;
1234 }
1235 m_selectedColorLabels = labels;
1236 if (labels.isEmpty()) {
1237 return;
1238 }
1239 QString colorLabels = QString::number(labels.first());
1240 for (int i = 1; i < labels.size(); ++i) {
1241 colorLabels += "," + QString::number(labels[i]);
1242 }
1243 m_configGroup.writeEntry("colorLabels", colorLabels);
1244}
1245
1248 bool checked)
1249{
1250 if (!checked) {
1251 return;
1252 }
1258 m_configGroup.writeEntry(
1259 "continuousFillMode",
1261 ? "fillAnyRegion"
1263 ? "doNotUse"
1264 : "fillSimilarRegions"
1265 );
1266}
1267
1289
1291{
1293 disconnect(m_previousNode->paintDevice().data(),
1294 SIGNAL(colorSpaceChanged(const KoColorSpace*)),
1295 this,
1296 SLOT(slot_colorSpaceChanged(const KoColorSpace*)));
1297 }
1298 if (node && node->paintDevice()) {
1299 connect(node->paintDevice().data(),
1300 SIGNAL(colorSpaceChanged(const KoColorSpace*)),
1301 this,
1302 SLOT(slot_colorSpaceChanged(const KoColorSpace*)));
1304 }
1305 m_previousNode = node;
1306}
1307
1309{
1311 return;
1312 }
1313 const KoColorSpace *compositionSpace = colorSpace;
1314 if (currentNode() && currentNode()->paintDevice()) {
1315 // Currently, composition source is enough to determine the available blending mode,
1316 // because either destination is the same (paint layers), or composition happens
1317 // in source space (masks).
1318 compositionSpace = currentNode()->paintDevice()->compositionSourceColorSpace();
1319 }
1320 m_comboBoxCustomCompositeOp->validate(compositionSpace);
1321}
1322
1324{
1325 if (checked == m_useActiveLayer) {
1326 return;
1327 }
1328 m_useActiveLayer = checked;
1329 m_configGroup.writeEntry("useActiveLayer", checked);
1330}
float value(const T *src, size_t ch)
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const qreal OPACITY_OPAQUE_F
const QString COMPOSITE_OVER
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void setOutDirtyRect(QSharedPointer< QRect > outDirtyRect)
void setSeedPoints(const QVector< QPoint > &seedPoints)
void setStopGrowingAtDarkestPixel(bool stopGrowingAtDarkestPixel)
void setUseFastMode(bool useFastMode)
void setUseCustomBlendingOptions(bool useCustomBlendingOptions)
void setCustomCompositeOp(const QString &customCompositeOp)
void setProgressHelper(QSharedPointer< ProgressHelper > progressHelper)
void setOpacitySpread(int opacitySpread)
void setAntiAlias(bool antiAlias)
void setSelectionOnly(bool selectionOnly)
void setUseBgColor(bool useBgColor)
void setContinuousFillMask(KisSelectionSP continuousFillMask)
void setFillThreshold(int fillThreshold)
void setRegionFillingBoundaryColor(const KoColor &regionFillingBoundaryColor)
void setUsePattern(bool usePattern)
void setCustomOpacity(qreal customOpacity)
void setContinuousFillReferenceColor(const QSharedPointer< KoColor > continuousFillReferenceColor)
void setRegionFillingMode(KisFillPainter::RegionFillingMode regionFillingMode)
void setContinuousFillMode(ContinuousFillMode continuousFillMode)
void setUseSelectionAsBoundary(bool useSelectionAsBoundary)
@ IncreasingDirection_Clockwise
A widget with several options to select an angle.
@ FlipOptionsMode_ContextMenu
The flip options are shown only as a context menu when right-clicking the gauge widget.
void setFlipOptionsMode(FlipOptionsMode newMode)
Sets the mode in which the flip options should be shown.
void setIncreasingDirection(KisAngleGauge::IncreasingDirection newIncreasingDirection)
Sets the increasing direction in the angle gauge.
void setAngle(qreal newAngle)
Sets the current angle.
KisViewManager * viewManager() const
A pushbutton to display or allow user selection of a color.
void setColor(const KoColor &c)
void setButtonSize(int size)
Set the size of the buttons.
void setSelection(const QList< int > &indices)
Set the list of checked button indices.
void setExclusive(bool exclusive)
Set if the button selection is mutually exclusive. This allows switching between single or multiple s...
void setButtonWrapEnabled(bool enabled)
Set if the buttons should wrap in multiple lines if there is no enough space horizontally.
void setMouseDragEnabled(bool enabled)
Set if the user can drag to check/uncheck multiple buttons.
QList< int > selection() const
Get the list of checked button indices.
void validate(const KoColorSpace *cs)
void selectCompositeOp(const KoID &op)
static QCursor load(const QString &cursorName, int hotspotX=-1, int hotspotY=-1)
This class is a spinbox in which you can click and drag to set the value. A slider like bar is displa...
void setValue(qreal newValue)
void setRange(qreal newMinimum, qreal newMaximum, int newNumberOfDecimals=0, bool computeNewFastSliderStep=true)
Set the minimum and the maximum values of the range.
void setSoftMaximum(qreal newSoftMaximum)
void setSizemod(int sizemod)
void setFillThreshold(int threshold)
void setFeather(int feather)
QVector< KisStrokeJobData * > createSimilarColorsSelectionJobs(KisPixelSelectionSP outSelection, const QSharedPointer< KoColor > referenceColor, KisPaintDeviceSP referenceDevice, const QRect &rect, KisPixelSelectionSP mask, QSharedPointer< KisProcessingVisitor::ProgressHelper > progressHelper=nullptr)
void setAntiAlias(bool antiAlias)
void setStopGrowingAtDarkestPixel(bool stopGrowingAtDarkestPixel)
void setOpacitySpread(int opacitySpread)
KisImageAnimationInterface * animationInterface() const
KisPaintDeviceSP projection() const
void addJob(KisStrokeId id, KisStrokeJobData *data) override
KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy) override
QRect bounds() const override
void endStroke(KisStrokeId id) override
static KisPaintDeviceSP createRefPaintDevice(KisImageSP originalImage, QString name="Merge Labeled Layers Reference Paint Device")
@ GroupSelectionPolicy_SelectIfColorLabeled
Groups will be taken into account only if they have set an explicit color label. This ignores groups ...
Provides a list of consecutive tool buttons.
KoGroupButton * addButton(const QIcon &icon, const QString &text=QString())
Wrapper class around a KisOptionCollectionWidget that also provide a header with a title label and an...
void setPrimaryWidget(QWidget *widget)
Set the primary widget. The list widget takes ownership of it.
void appendWidget(const QString &id, QWidget *widget)
Insert the given widget with the given id at the end of the list. The list widget takes ownership of ...
void setPrimaryWidgetVisible(bool visible)
Set the visibility of the primary widget. Use this function instead of the widget one directly to get...
void setWidgetVisible(int index, bool visible)
Set the visibility of the widget that is at the given position.
Class providing a list of widgets with some addons such as separators, orientation or individual widg...
void setWidgetsMargin(int margin)
Set the margins of the widgets. This allows to indent the widgets with respect to the separators....
T widgetAs(int index) const
Get the widget that is at the given position casted to some other class.
void setOrientation(Qt::Orientation orientation, bool recursive=false)
Set the orientation of the list of widgets.
void setWidgetVisible(int index, bool visible)
Set the visibility of the widget that is at the given position. Use this function instead of the widg...
void appendWidget(const QString &id, QWidget *widget)
Insert the given widget with the given id at the end of the list. The list widget takes ownership of ...
void setSeparatorsVisible(bool visible)
Set the visibility of the separators.
virtual const KoColorSpace * compositionSourceColorSpace() const
const KoColorSpace * colorSpace() const
bool pixel(qint32 x, qint32 y, QColor *c) const
The KisResourcesSnapshot class takes a snapshot of the various resources like colors and settings use...
KisSelectionSP activeSelection() const
void setFillTransform(QTransform transform)
This class is a spinbox in which you can click and drag to set the value. A slider like bar is displa...
void setSoftRange(int newSoftMinimum, int newSoftMaximum)
Set the minimum and the maximum values of the soft range.
void setValue(int newValue)
void setRange(int newMinimum, int newMaximum, bool computeNewFastSliderStep=true)
Set the minimum and the maximum values of the range, computing a new "fast slider step" based on the ...
KisSignalCompressor m_compressorFillUpdate
qreal m_patternRotation
void resetCursorStyle() override
void slot_sliderGrow_valueChanged(int value)
KoGroupButton * m_buttonFillWithBG
@ Reference_ColorLabeledLayers
void slot_colorSpaceChanged(const KoColorSpace *colorSpace)
void slot_optionButtonStripReference_buttonToggled(KoGroupButton *button, bool checked)
KisCompositeOpComboBox * m_comboBoxCustomCompositeOp
KConfigGroup m_configGroup
void slot_optionButtonStripDragFill_buttonToggled(KoGroupButton *button, bool checked)
KoGroupButton * m_buttonWhatToFillContiguous
void slot_checkBoxUseCustomBlendingOptions_toggled(bool checked)
KisSliderSpinBox * m_sliderCloseGap
~KisToolFill() override
void addFillingOperation(const QPoint &seedPoint)
void slot_optionButtonStripFillWith_buttonToggled(KoGroupButton *button, bool checked)
void slot_optionButtonStripContiguousFillMode_buttonToggled(KoGroupButton *button, bool checked)
@ FillMode_FillContiguousRegion
@ FillMode_FillSimilarRegions
@ ContiguousFillMode_BoundaryFill
@ ContiguousFillMode_FloodFill
void slot_comboBoxCustomCompositeOp_currentIndexChanged(int index)
KisToolFill(KoCanvasBase *canvas)
KoGroupButton * m_buttonReferenceAll
void addUpdateOperation()
KisSliderSpinBox * m_sliderCustomOpacity
int m_stopGrowingAtDarkestPixel
@ FillType_FillWithForegroundColor
@ FillType_FillWithBackgroundColor
@ FillType_FillWithPattern
void slot_angleSelectorPatternRotation_angleChanged(double value)
QString m_customCompositeOp
KisColorButton * m_buttonContiguousFillBoundaryColor
KisSliderSpinBox * m_sliderGrow
KisAngleSelector * m_angleSelectorPatternRotation
void slot_optionButtonStripWhatToFill_buttonToggled(KoGroupButton *button, bool checked)
void slot_sliderThreshold_valueChanged(int value)
void slot_checkBoxSelectionAsBoundary_toggled(bool checked)
void slot_sliderPatternScale_valueChanged(double value)
QSharedPointer< KoColor > m_referenceColor
void slot_sliderCustomOpacity_valueChanged(int value)
QPoint m_fillStartWidgetPosition
FillType m_fillType
KoColor loadContiguousFillBoundaryColorFromConfig()
KisSliderSpinBox * m_sliderFeather
KoGroupButton * m_buttonFillWithFG
void slot_sliderCloseGap_valueChanged(int value)
void deactivate() override
void slot_checkBoxUseActiveLayer_toggled(bool checked)
KisStrokeId m_fillStrokeId
KisNodeSP m_previousNode
KoColor m_contiguousFillBoundaryColor
KoGroupButton * m_buttonDragFillAny
void endAlternateAction(KoPointerEvent *event, AlternateAction action) override
void loadConfiguration()
void endPrimaryAction(KoPointerEvent *event) override
KoGroupButton * m_buttonFillWithPattern
void slot_widgetLabels_selectionChanged()
KoGroupButton * m_buttonDragFillDoNotUse
Reference m_reference
KisResourcesSnapshotSP m_resourcesSnapshot
KisSelectionSP m_fillMask
FillMode m_effectiveFillMode
KisSliderSpinBox * m_sliderThreshold
KoGroupButton * m_buttonContiguousFillModeBoundaryFill
KoGroupButton * m_buttonReferenceCurrent
bool m_useActiveLayer
void continueAlternateAction(KoPointerEvent *event, AlternateAction action) override
void slot_buttonStopGrowingAtDarkestPixel_toggled(bool enabled)
void slot_sliderSpread_valueChanged(int value)
QVector< QPoint > m_seedPoints
QToolButton * m_buttonStopGrowingAtDarkestPixel
KoGroupButton * m_buttonDragFillSimilar
QCheckBox * m_checkBoxSelectionAsBoundary
void beginAlternateAction(KoPointerEvent *event, AlternateAction action) override
void slot_checkBoxAntiAlias_toggled(bool checked)
KisSliderSpinBox * m_sliderSpread
KisDoubleSliderSpinBox * m_sliderPatternScale
void activate(const QSet< KoShape * > &shapes) override
KoGroupButton * m_buttonWhatToFillSimilar
void beginFilling(const QPoint &seedPoint)
void slotUpdateFill()
QList< int > m_selectedColorLabels
QTransform m_transform
ContiguousFillMode m_contiguousFillMode
QCheckBox * m_checkBoxAntiAlias
bool m_useSelectionAsBoundary
KisPaintDeviceSP m_referencePaintDevice
QSharedPointer< QRect > m_dirtyRect
QCheckBox * m_checkBoxCustomBlendingOptions
KisOptionCollectionWidget * m_optionWidget
QWidget * createOptionWidget() override
void slot_buttonContiguousFillBoundaryColor_changed(const KoColor &color)
KoGroupButton * m_buttonWhatToFillSelection
bool m_useCustomBlendingOptions
static constexpr int minimumDragDistanceSquared
void continuePrimaryAction(KoPointerEvent *event) override
KoGroupButton * m_buttonReferenceLabeled
void slot_currentNodeChanged(const KisNodeSP node)
@ ContinuousFillMode_FillSimilarRegions
@ ContinuousFillMode_FillAnyRegion
@ ContinuousFillMode_DoNotUse
void slot_buttonReset_clicked()
FillMode m_fillMode
KisMergeLabeledLayersCommand::ReferenceNodeInfoListSP m_referenceNodeList
QCheckBox * m_checkBoxUseActiveLayer
void beginPrimaryAction(KoPointerEvent *event) override
ContinuousFillMode m_continuousFillMode
KoGroupButton * m_buttonContiguousFillModeFloodFill
KisColorLabelSelectorWidget * m_widgetLabels
void slot_sliderFeather_valueChanged(int value)
qreal m_patternScale
void deactivate() override
void activate(const QSet< KoShape * > &shapes) override
void setMode(ToolMode mode) override
bool isEraser() const
void endAlternateAction(KoPointerEvent *event, AlternateAction action) override
void continueAlternateAction(KoPointerEvent *event, AlternateAction action) override
void beginAlternateAction(KoPointerEvent *event, AlternateAction action) override
KisCanvasResourceProvider * canvasResourceProvider()
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
Definition KoColor.cpp:350
void toXML(QDomDocument &doc, QDomElement &colorElt) const
Definition KoColor.cpp:304
static const KoCompositeOpRegistry & instance()
KoID getKoID(const QString &compositeOpID) const
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
Qt::KeyboardModifiers modifiers() const
QPoint pos() const
return the position in widget coordinates
void selectionChanged(bool hasSelection)
Q_INVOKABLE QString toolId() const
virtual KoToolSelection * selection()
void useCursor(const QCursor &cursor)
QAction * action(const QString &name) const
static bool qFuzzyCompare(half p1, half p2)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define bounds(x, a, b)
T pow2(const T &x)
Definition kis_global.h:166
QString button(const QWheelEvent &ev)
#define CHECK_MODE_SANITY_OR_RETURN(_mode)
Definition kis_tool.h:27
QSharedPointer< KUndo2Command > KUndo2CommandSP
Definition kis_types.h:262
KUndo2MagicString kundo2_i18n(const char *text)
QIcon loadIcon(const QString &name)
void setText(QSpinBox *spinBox, const QStringView textTemplate)
QVector< QPoint > rasterizePolylineDDA(const QVector< QPoint > &polylinePoints)
virtual KisPaintDeviceSP paintDevice() const =0
The LambdaCommand struct is a shorthand for creation of AggregateCommand commands using C++ lambda fe...
KisPixelSelectionSP pixelSelection
KisImageWSP currentImage()
Definition kis_tool.cc:393
KisTool::NodePaintAbility nodePaintAbility()
Definition kis_tool.cc:539
virtual void resetCursorStyle()
Definition kis_tool.cc:613
bool nodeEditable()
Checks checks if the current node is editable.
Definition kis_tool.cc:651
QPoint convertToImagePixelCoordFloored(KoPointerEvent *e)
Definition kis_tool.cc:236
KisNodeSP currentNode() const
Definition kis_tool.cc:370
bool overrideCursorIfNotEditable()
Override the cursor appropriately if current node is not editable.
Definition kis_tool.cc:618
KisImageWSP image() const
Definition kis_tool.cc:332
@ PAINT_MODE
Definition kis_tool.h:300
@ HOVER_MODE
Definition kis_tool.h:299
AlternateAction
Definition kis_tool.h:134
@ ChangeSize
Definition kis_tool.h:135
KisCanvas2 * canvas