diff --git a/libs/ui/processing/fill_processing_visitor.cpp b/libs/ui/processing/fill_processing_visitor.cpp index 036848bdfe..5e100d8fdc 100644 --- a/libs/ui/processing/fill_processing_visitor.cpp +++ b/libs/ui/processing/fill_processing_visitor.cpp @@ -1,151 +1,151 @@ /* * Copyright (c) 2013 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fill_processing_visitor.h" #include #include #include #include #include "lazybrush/kis_colorize_mask.h" FillProcessingVisitor::FillProcessingVisitor(KisPaintDeviceSP refPaintDevice, const QPoint &startPoint, KisSelectionSP selection, KisResourcesSnapshotSP resources, bool useFastMode, bool usePattern, bool selectionOnly, bool useSelectionAsBoundary, int feather, int sizemod, int fillThreshold, bool unmerged, bool useBgColor) : m_refPaintDevice(refPaintDevice), m_startPoint(startPoint), m_selection(selection), m_useFastMode(useFastMode), m_selectionOnly(selectionOnly), m_useSelectionAsBoundary(useSelectionAsBoundary), m_usePattern(usePattern), m_resources(resources), m_feather(feather), m_sizemod(sizemod), m_fillThreshold(fillThreshold), m_unmerged(unmerged), m_useBgColor(useBgColor) { } void FillProcessingVisitor::visitExternalLayer(KisExternalLayer *layer, KisUndoAdapter *undoAdapter) { Q_UNUSED(layer); Q_UNUSED(undoAdapter); } void FillProcessingVisitor::visitNodeWithPaintDevice(KisNode *node, KisUndoAdapter *undoAdapter) { KisPaintDeviceSP device = node->paintDevice(); Q_ASSERT(device); ProgressHelper helper(node); fillPaintDevice(device, undoAdapter, helper); } void FillProcessingVisitor::fillPaintDevice(KisPaintDeviceSP device, KisUndoAdapter *undoAdapter, ProgressHelper &helper) { QRect fillRect = m_resources->image()->bounds(); if (!device->defaultBounds()->wrapAroundMode() && !fillRect.contains(m_startPoint)) { return; } if (m_selectionOnly) { KisPaintDeviceSP filledDevice = device->createCompositionSourceDevice(); KisFillPainter fillPainter(filledDevice); fillPainter.setProgress(helper.updater()); if (m_usePattern) { fillPainter.fillRect(fillRect, m_resources->currentPattern(), m_resources->fillTransform()); } else if (m_useBgColor) { fillPainter.fillRect(fillRect, m_resources->currentBgColor(), m_resources->opacity()); } else { fillPainter.fillRect(fillRect, m_resources->currentFgColor(), m_resources->opacity()); } QVector dirtyRect = fillPainter.takeDirtyRegion(); KisPainter painter(device, m_selection); painter.beginTransaction(); m_resources->setupPainter(&painter); Q_FOREACH (const QRect &rc, dirtyRect) { painter.bitBlt(rc.topLeft(), filledDevice, rc); } painter.endTransaction(undoAdapter); } else { QPoint startPoint = m_startPoint; if (device->defaultBounds()->wrapAroundMode()) { startPoint = KisWrappedRect::ptToWrappedPt(startPoint, device->defaultBounds()->imageBorderRect()); } KisFillPainter fillPainter(device, m_selection); fillPainter.beginTransaction(); m_resources->setupPainter(&fillPainter); fillPainter.setProgress(helper.updater()); fillPainter.setSizemod(m_sizemod); fillPainter.setFeather(m_feather); fillPainter.setFillThreshold(m_fillThreshold); fillPainter.setCareForSelection(true); - fillPainter.setUseSelectionAsBoundary(m_useSelectionAsBoundary); + fillPainter.setUseSelectionAsBoundary((m_selection.isNull() || m_selection->hasNonEmptyPixelSelection()) ? m_useSelectionAsBoundary : false); fillPainter.setWidth(fillRect.width()); fillPainter.setHeight(fillRect.height()); fillPainter.setUseCompositioning(!m_useFastMode); KisPaintDeviceSP sourceDevice = m_unmerged ? device : m_refPaintDevice; if (m_usePattern) { fillPainter.fillPattern(startPoint.x(), startPoint.y(), sourceDevice, m_resources->fillTransform()); } else { fillPainter.fillColor(startPoint.x(), startPoint.y(), sourceDevice); } fillPainter.endTransaction(undoAdapter); } } void FillProcessingVisitor::visitColorizeMask(KisColorizeMask *mask, KisUndoAdapter *undoAdapter) { // we fill only the coloring project so the user can work // with the mask like with a usual paint layer ProgressHelper helper(mask); fillPaintDevice(mask->coloringProjection(), undoAdapter, helper); } diff --git a/plugins/tools/selectiontools/kis_tool_select_contiguous.cc b/plugins/tools/selectiontools/kis_tool_select_contiguous.cc index 0f19ad0437..42267b858c 100644 --- a/plugins/tools/selectiontools/kis_tool_select_contiguous.cc +++ b/plugins/tools/selectiontools/kis_tool_select_contiguous.cc @@ -1,303 +1,307 @@ /* * kis_tool_select_contiguous - part of Krayon^WKrita * * Copyright (c) 1999 Michael Koch * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2012 José Luis Vergara * Copyright (c) 2015 Michael Abrahams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_select_contiguous.h" #include #include #include #include #include #include #include #include #include #include "KoPointerEvent.h" #include "KoViewConverter.h" #include "kis_cursor.h" #include "kis_selection_manager.h" #include "kis_image.h" #include "canvas/kis_canvas2.h" #include "kis_layer.h" #include "kis_selection_options.h" #include "kis_paint_device.h" #include "kis_fill_painter.h" #include "kis_pixel_selection.h" #include "kis_selection_tool_helper.h" #include "kis_slider_spin_box.h" #include "tiles3/kis_hline_iterator.h" #include "commands_new/KisMergeLabeledLayersCommand.h" #include "kis_image.h" #include "kis_undo_stores.h" #include "kis_resources_snapshot.h" #include "kis_processing_applicator.h" #include #include "kis_command_utils.h" KisToolSelectContiguous::KisToolSelectContiguous(KoCanvasBase *canvas) : KisToolSelect(canvas, KisCursor::load("tool_contiguous_selection_cursor.png", 6, 6), i18n("Contiguous Area Selection")), m_fuzziness(20), m_sizemod(0), m_feather(0) { setObjectName("tool_select_contiguous"); } KisToolSelectContiguous::~KisToolSelectContiguous() { } void KisToolSelectContiguous::activate(ToolActivation toolActivation, const QSet &shapes) { KisToolSelect::activate(toolActivation, shapes); m_configGroup = KSharedConfig::openConfig()->group(toolId()); } void KisToolSelectContiguous::beginPrimaryAction(KoPointerEvent *event) { KisToolSelectBase::beginPrimaryAction(event); KisPaintDeviceSP dev; if (!currentNode() || !(dev = currentNode()->paintDevice()) || !currentNode()->visible() || !selectionEditable()) { event->ignore(); return; } if (KisToolSelect::selectionDidMove()) { return; } QApplication::setOverrideCursor(KisCursor::waitCursor()); // ------------------------------- KisProcessingApplicator applicator(currentImage(), currentNode(), KisProcessingApplicator::NONE, KisImageSignalVector() << ModifiedSignal, kundo2_i18n("Select Contiguous Area")); QPoint pos = convertToImagePixelCoordFloored(event); QRect rc = currentImage()->bounds(); KisImageSP image = currentImage(); KisPaintDeviceSP sourceDevice; if (sampleLayersMode() == SampleAllLayers) { sourceDevice = image->projection(); } else if (sampleLayersMode() == SampleColorLabeledLayers) { KisImageSP refImage = KisMergeLabeledLayersCommand::createRefImage(image, "Contiguous Selection Tool Reference Image"); sourceDevice = KisMergeLabeledLayersCommand::createRefPaintDevice( image, "Contiguous Selection Tool Reference Result Paint Device"); KisMergeLabeledLayersCommand* command = new KisMergeLabeledLayersCommand(refImage, sourceDevice, image->root(), colorLabelsSelected()); applicator.applyCommand(command, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); } else { // Sample Current Layer sourceDevice = dev; } KisPixelSelectionSP selection = KisPixelSelectionSP(new KisPixelSelection(new KisSelectionDefaultBounds(dev))); bool antiAlias = antiAliasSelection(); int fuzziness = m_fuzziness; int feather = m_feather; int sizemod = m_sizemod; bool useSelectionAsBoundary = m_useSelectionAsBoundary; KisCanvas2 * kisCanvas = dynamic_cast(canvas()); KIS_SAFE_ASSERT_RECOVER(kisCanvas) { applicator.cancel(); QApplication::restoreOverrideCursor(); return; }; - KisPixelSelectionSP existingSelection = kisCanvas->imageView()->selection()->pixelSelection(); + KisPixelSelectionSP existingSelection; + if (kisCanvas->imageView() && kisCanvas->imageView()->selection()) + { + existingSelection = kisCanvas->imageView()->selection()->pixelSelection(); + } KUndo2Command* cmd = new KisCommandUtils::LambdaCommand( [dev, rc, fuzziness, feather, sizemod, useSelectionAsBoundary, selection, pos, sourceDevice, antiAlias, existingSelection] () mutable -> KUndo2Command* { KisFillPainter fillpainter(dev); fillpainter.setHeight(rc.height()); fillpainter.setWidth(rc.width()); fillpainter.setFillThreshold(fuzziness); fillpainter.setFeather(feather); fillpainter.setSizemod(sizemod); - fillpainter.setUseSelectionAsBoundary(useSelectionAsBoundary); + fillpainter.setUseSelectionAsBoundary((existingSelection.isNull() || existingSelection->isEmpty()) ? false : useSelectionAsBoundary); fillpainter.createFloodSelection(selection, pos.x(), pos.y(), sourceDevice, existingSelection); // If we're not antialiasing, threshold the entire selection if (!antiAlias) { const QRect r = selection->selectedExactRect(); KisSequentialIterator it (selection, r); while(it.nextPixel()) { if (*it.rawData() > 0) { *it.rawData() = OPACITY_OPAQUE_U8; } } } selection->invalidateOutlineCache(); return 0; }); applicator.applyCommand(cmd, KisStrokeJobData::SEQUENTIAL); KisSelectionToolHelper helper(kisCanvas, kundo2_i18n("Select Contiguous Area")); helper.selectPixelSelection(applicator, selection, selectionAction()); applicator.end(); QApplication::restoreOverrideCursor(); } void KisToolSelectContiguous::paint(QPainter &painter, const KoViewConverter &converter) { Q_UNUSED(painter); Q_UNUSED(converter); } void KisToolSelectContiguous::slotSetFuzziness(int fuzziness) { m_fuzziness = fuzziness; m_configGroup.writeEntry("fuzziness", fuzziness); } void KisToolSelectContiguous::slotSetSizemod(int sizemod) { m_sizemod = sizemod; m_configGroup.writeEntry("sizemod", sizemod); } void KisToolSelectContiguous::slotSetFeather(int feather) { m_feather = feather; m_configGroup.writeEntry("feather", feather); } void KisToolSelectContiguous::slotSetUseSelectionAsBoundary(bool useSelectionAsBoundary) { m_useSelectionAsBoundary = useSelectionAsBoundary; m_configGroup.writeEntry("useSelectionAsBoundary", useSelectionAsBoundary); } QWidget* KisToolSelectContiguous::createOptionWidget() { KisToolSelectBase::createOptionWidget(); KisSelectionOptions *selectionWidget = selectionOptionWidget(); QVBoxLayout * l = dynamic_cast(selectionWidget->layout()); Q_ASSERT(l); if (l) { QGridLayout * gridLayout = new QGridLayout(); l->insertLayout(1, gridLayout); QLabel * lbl = new QLabel(i18n("Fuzziness: "), selectionWidget); gridLayout->addWidget(lbl, 0, 0, 1, 1); KisSliderSpinBox *input = new KisSliderSpinBox(selectionWidget); Q_CHECK_PTR(input); input->setObjectName("fuzziness"); input->setRange(1, 100); input->setSingleStep(1); input->setExponentRatio(2); gridLayout->addWidget(input, 0, 1, 1, 1); lbl = new QLabel(i18n("Grow/shrink selection: "), selectionWidget); gridLayout->addWidget(lbl, 1, 0, 1, 1); KisSliderSpinBox *sizemod = new KisSliderSpinBox(selectionWidget); Q_CHECK_PTR(sizemod); sizemod->setObjectName("sizemod"); //grow/shrink selection sizemod->setRange(-40, 40); sizemod->setSingleStep(1); gridLayout->addWidget(sizemod, 1, 1, 1, 1); lbl = new QLabel(i18n("Feathering radius: "), selectionWidget); gridLayout->addWidget(lbl, 2, 0, 1, 1); KisSliderSpinBox *feather = new KisSliderSpinBox(selectionWidget); Q_CHECK_PTR(feather); feather->setObjectName("feathering"); feather->setRange(0, 40); feather->setSingleStep(1); gridLayout->addWidget(feather, 2, 1, 1, 1); lbl = new QLabel(i18n("Use selection as boundary: "), selectionWidget); gridLayout->addWidget(lbl, 3, 0, 1, 1); QCheckBox *useSelectionAsBoundary = new QCheckBox(selectionWidget); Q_CHECK_PTR(useSelectionAsBoundary); gridLayout->addWidget(useSelectionAsBoundary, 3, 1, 1, 1); connect (input , SIGNAL(valueChanged(int)), this, SLOT(slotSetFuzziness(int))); connect (sizemod, SIGNAL(valueChanged(int)), this, SLOT(slotSetSizemod(int))); connect (feather, SIGNAL(valueChanged(int)), this, SLOT(slotSetFeather(int))); connect (useSelectionAsBoundary, SIGNAL(toggled(bool)), this, SLOT(slotSetUseSelectionAsBoundary(bool))); selectionWidget->attachToImage(image(), dynamic_cast(canvas())); m_widgetHelper.setConfigGroupForExactTool(toolId()); // load configuration settings into tool options input->setValue(m_configGroup.readEntry("fuzziness", 20)); // fuzziness sizemod->setValue( m_configGroup.readEntry("sizemod", 0)); //grow/shrink sizemod->setSuffix(i18n(" px")); feather->setValue(m_configGroup.readEntry("feather", 0)); feather->setSuffix(i18n(" px")); useSelectionAsBoundary->setChecked(m_configGroup.readEntry("useSelectionAsBoundary", false)); } return selectionWidget; } void KisToolSelectContiguous::resetCursorStyle() { if (selectionAction() == SELECTION_ADD) { useCursor(KisCursor::load("tool_contiguous_selection_cursor_add.png", 6, 6)); } else if (selectionAction() == SELECTION_SUBTRACT) { useCursor(KisCursor::load("tool_contiguous_selection_cursor_sub.png", 6, 6)); } else { KisToolSelect::resetCursorStyle(); } }