diff --git a/libs/ui/tool/kis_tool_select_base.h b/libs/ui/tool/kis_tool_select_base.h index 4449ba7154..d3dfcc812c 100644 --- a/libs/ui/tool/kis_tool_select_base.h +++ b/libs/ui/tool/kis_tool_select_base.h @@ -1,402 +1,407 @@ /* This file is part of the KDE project * Copyright (C) 2009 Boudewijn Rempt * Copyright (C) 2015 Michael Abrahams * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISTOOLSELECTBASE_H #define KISTOOLSELECTBASE_H #include "KoPointerEvent.h" #include "kis_tool.h" #include "kis_canvas2.h" #include "kis_selection.h" #include "kis_selection_options.h" #include "kis_selection_tool_config_widget_helper.h" #include "KisViewManager.h" #include "kis_selection_manager.h" #include "kis_selection_modifier_mapper.h" #include "strokes/move_stroke_strategy.h" #include "kis_image.h" #include "kis_cursor.h" #include "kis_action_manager.h" #include "kis_action.h" #include "kis_signal_auto_connection.h" #include "kis_selection_tool_helper.h" /** * This is a basic template to create selection tools from basic path based drawing tools. * The template overrides the ability to execute alternate actions correctly. * The default behavior for the modifier keys is as follows: * * Shift: add to selection * Alt: subtract from selection * Shift+Alt: intersect current selection * Ctrl: replace selection * * The mapping itself is done in KisSelectionModifierMapper. * * Certain tools also use modifier keys to alter their behavior, e.g. forcing square proportions with the rectangle tool. * The template enables the following rules for forwarding keys: * 1) Any modifier keys held *when the tool is first activated* will determine * the new selection method. This is recorded in m_selectionActionAlternate. A * value of m_selectionActionAlternate = SELECTION_DEFAULT means no modifier was * being pressed when the tool was activated. * * 2) If the underlying tool *does not take modifier keys*, pressing modifier * keys in the middle of a stroke will change the selection method. This is * recorded in m_selectionAction. A value of SELECTION_DEFAULT means no modifier * is being pressed. Applies to the lasso tool and polygon tool. * * 3) If the underlying tool *takes modifier keys,* they will always be * forwarded to the underlying tool, and it is not possible to change the * selection method in the middle of a stroke. */ template class KisToolSelectBase : public BaseClass { public: KisToolSelectBase(KoCanvasBase* canvas, const QString toolName) : BaseClass(canvas) , m_widgetHelper(toolName) , m_selectionActionAlternate(SELECTION_DEFAULT) { KisSelectionModifierMapper::instance(); } KisToolSelectBase(KoCanvasBase* canvas, const QCursor cursor, const QString toolName) : BaseClass(canvas, cursor) , m_widgetHelper(toolName) , m_selectionActionAlternate(SELECTION_DEFAULT) { KisSelectionModifierMapper::instance(); } KisToolSelectBase(KoCanvasBase* canvas, QCursor cursor, QString toolName, KoToolBase *delegateTool) : BaseClass(canvas, cursor, delegateTool) , m_widgetHelper(toolName) , m_selectionActionAlternate(SELECTION_DEFAULT) { KisSelectionModifierMapper::instance(); } void updateActionShortcutToolTips() { KisSelectionOptions *widget = m_widgetHelper.optionWidget(); if (widget) { widget->updateActionButtonToolTip( SELECTION_REPLACE, this->action("selection_tool_mode_replace")->shortcut()); widget->updateActionButtonToolTip( SELECTION_ADD, this->action("selection_tool_mode_add")->shortcut()); widget->updateActionButtonToolTip( SELECTION_SUBTRACT, this->action("selection_tool_mode_subtract")->shortcut()); widget->updateActionButtonToolTip( SELECTION_INTERSECT, this->action("selection_tool_mode_intersect")->shortcut()); } } void activate(KoToolBase::ToolActivation activation, const QSet &shapes) { BaseClass::activate(activation, shapes); m_modeConnections.addUniqueConnection( this->action("selection_tool_mode_replace"), SIGNAL(triggered()), &m_widgetHelper, SLOT(slotReplaceModeRequested())); m_modeConnections.addUniqueConnection( this->action("selection_tool_mode_add"), SIGNAL(triggered()), &m_widgetHelper, SLOT(slotAddModeRequested())); m_modeConnections.addUniqueConnection( this->action("selection_tool_mode_subtract"), SIGNAL(triggered()), &m_widgetHelper, SLOT(slotSubtractModeRequested())); m_modeConnections.addUniqueConnection( this->action("selection_tool_mode_intersect"), SIGNAL(triggered()), &m_widgetHelper, SLOT(slotIntersectModeRequested())); updateActionShortcutToolTips(); } void deactivate() { BaseClass::deactivate(); m_modeConnections.clear(); } QWidget* createOptionWidget() { KisCanvas2* canvas = dynamic_cast(this->canvas()); Q_ASSERT(canvas); m_widgetHelper.createOptionWidget(canvas, this->toolId()); this->connect(this, SIGNAL(isActiveChanged(bool)), &m_widgetHelper, SLOT(slotToolActivatedChanged(bool))); this->connect(&m_widgetHelper, SIGNAL(selectionActionChanged(int)), this, SLOT(resetCursorStyle())); updateActionShortcutToolTips(); return m_widgetHelper.optionWidget(); } SelectionMode selectionMode() const { return m_widgetHelper.selectionMode(); } SelectionAction selectionAction() const { if (alternateSelectionAction() == SELECTION_DEFAULT) { return m_widgetHelper.selectionAction(); } return alternateSelectionAction(); } bool antiAliasSelection() const { return m_widgetHelper.antiAliasSelection(); } SelectionAction alternateSelectionAction() const { return m_selectionActionAlternate; } KisSelectionOptions* selectionOptionWidget() { return m_widgetHelper.optionWidget(); } virtual void setAlternateSelectionAction(SelectionAction action) { m_selectionActionAlternate = action; dbgKrita << "Changing to selection action" << m_selectionActionAlternate; } void activateAlternateAction(KisTool::AlternateAction action) { Q_UNUSED(action); BaseClass::activatePrimaryAction(); } void deactivateAlternateAction(KisTool::AlternateAction action) { Q_UNUSED(action); BaseClass::deactivatePrimaryAction(); } void beginAlternateAction(KoPointerEvent *event, KisTool::AlternateAction action) { Q_UNUSED(action); beginPrimaryAction(event); } void continueAlternateAction(KoPointerEvent *event, KisTool::AlternateAction action) { Q_UNUSED(action); continuePrimaryAction(event); } void endAlternateAction(KoPointerEvent *event, KisTool::AlternateAction action) { Q_UNUSED(action); endPrimaryAction(event); } KisNodeSP locateSelectionMaskUnderCursor(const QPointF &pos, Qt::KeyboardModifiers modifiers) { if (modifiers != Qt::NoModifier) return 0; KisCanvas2* canvas = dynamic_cast(this->canvas()); KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(canvas, 0); KisSelectionSP selection = canvas->viewManager()->selection(); if (selection && selection->outlineCacheValid()) { const qreal handleRadius = qreal(this->handleRadius()) / canvas->coordinatesConverter()->effectiveZoom(); QPainterPath samplePath; samplePath.addEllipse(pos, handleRadius, handleRadius); const QPainterPath selectionPath = selection->outlineCache(); if (selectionPath.intersects(samplePath) && !selectionPath.contains(samplePath)) { KisNodeSP parent = selection->parentNode(); if (parent && parent->isEditable()) { return parent; } } } return 0; } void keyPressEvent(QKeyEvent *event) { if (this->mode() != KisTool::PAINT_MODE) { setAlternateSelectionAction(KisSelectionModifierMapper::map(event->modifiers())); this->resetCursorStyle(); } BaseClass::keyPressEvent(event); } void keyReleaseEvent(QKeyEvent *event) { if (this->mode() != KisTool::PAINT_MODE) { setAlternateSelectionAction(KisSelectionModifierMapper::map(event->modifiers())); this->resetCursorStyle(); } BaseClass::keyPressEvent(event); } void mouseMoveEvent(KoPointerEvent *event) { if (!this->hasUserInteractionRunning() && (m_moveStrokeId || this->mode() != KisTool::PAINT_MODE)) { const QPointF pos = this->convertToPixelCoord(event->point); KisNodeSP selectionMask = locateSelectionMaskUnderCursor(pos, event->modifiers()); if (selectionMask) { this->useCursor(KisCursor::moveSelectionCursor()); } else { setAlternateSelectionAction(KisSelectionModifierMapper::map(event->modifiers())); this->resetCursorStyle(); } } BaseClass::mouseMoveEvent(event); } virtual void beginPrimaryAction(KoPointerEvent *event) { if (!this->hasUserInteractionRunning()) { const QPointF pos = this->convertToPixelCoord(event->point); KisCanvas2* canvas = dynamic_cast(this->canvas()); KIS_SAFE_ASSERT_RECOVER_RETURN(canvas); KisNodeSP selectionMask = locateSelectionMaskUnderCursor(pos, event->modifiers()); if (selectionMask) { KisStrokeStrategy *strategy = new MoveStrokeStrategy({selectionMask}, this->image().data(), this->image().data()); m_moveStrokeId = this->image()->startStroke(strategy); m_dragStartPos = pos; - + m_didMove = true; return; } } - + m_didMove = false; keysAtStart = event->modifiers(); setAlternateSelectionAction(KisSelectionModifierMapper::map(keysAtStart)); if (alternateSelectionAction() != SELECTION_DEFAULT) { BaseClass::listenToModifiers(false); } BaseClass::beginPrimaryAction(event); } virtual void continuePrimaryAction(KoPointerEvent *event) { if (m_moveStrokeId) { const QPointF pos = this->convertToPixelCoord(event->point); const QPoint offset((pos - m_dragStartPos).toPoint()); this->image()->addJob(m_moveStrokeId, new MoveStrokeStrategy::Data(offset)); return; } //If modifier keys have changed, tell the base tool it can start capturing modifiers if ((keysAtStart != event->modifiers()) && !BaseClass::listeningToModifiers()) { BaseClass::listenToModifiers(true); } //Always defer to the base class if it signals it is capturing modifier keys if (!BaseClass::listeningToModifiers()) { setAlternateSelectionAction(KisSelectionModifierMapper::map(event->modifiers())); } BaseClass::continuePrimaryAction(event); } void endPrimaryAction(KoPointerEvent *event) { if (m_moveStrokeId) { this->image()->endStroke(m_moveStrokeId); m_moveStrokeId.clear(); return; } keysAtStart = Qt::NoModifier; //reset this with each action BaseClass::endPrimaryAction(event); } bool selectionDragInProgress() const { return m_moveStrokeId; } + bool selectionDidMove() const { + return m_didMove; + } + QMenu* popupActionsMenu() { KisCanvas2 * kisCanvas = dynamic_cast(canvas()); KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(kisCanvas, 0); return KisSelectionToolHelper::getSelectionContextMenu(kisCanvas); } protected: using BaseClass::canvas; KisSelectionToolConfigWidgetHelper m_widgetHelper; SelectionAction m_selectionActionAlternate; private: Qt::KeyboardModifiers keysAtStart; QPointF m_dragStartPos; KisStrokeId m_moveStrokeId; + bool m_didMove = false; KisSignalAutoConnectionsStore m_modeConnections; }; struct FakeBaseTool : KisTool { FakeBaseTool(KoCanvasBase* canvas) : KisTool(canvas, QCursor()) { } FakeBaseTool(KoCanvasBase* canvas, const QString &toolName) : KisTool(canvas, QCursor()) { Q_UNUSED(toolName); } FakeBaseTool(KoCanvasBase* canvas, const QCursor &cursor) : KisTool(canvas, cursor) { } bool hasUserInteractionRunning() const { return false; } }; typedef KisToolSelectBase KisToolSelect; #endif // KISTOOLSELECTBASE_H diff --git a/plugins/tools/selectiontools/kis_tool_select_contiguous.cc b/plugins/tools/selectiontools/kis_tool_select_contiguous.cc index 5a4c8daea9..59d7c81a89 100644 --- a/plugins/tools/selectiontools/kis_tool_select_contiguous.cc +++ b/plugins/tools/selectiontools/kis_tool_select_contiguous.cc @@ -1,247 +1,251 @@ /* * 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" 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), m_limitToCurrentLayer(false) { 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()->projection()) || !currentNode()->visible() || !selectionEditable()) { event->ignore(); return; } + if (KisToolSelect::selectionDidMove()) { + return; + } + QApplication::setOverrideCursor(KisCursor::waitCursor()); QPoint pos = convertToImagePixelCoordFloored(event); QRect rc = currentImage()->bounds(); KisFillPainter fillpainter(dev); fillpainter.setHeight(rc.height()); fillpainter.setWidth(rc.width()); fillpainter.setFillThreshold(m_fuzziness); fillpainter.setFeather(m_feather); fillpainter.setSizemod(m_sizemod); KisImageWSP image = currentImage(); KisPaintDeviceSP sourceDevice = m_limitToCurrentLayer ? dev : image->projection(); image->lock(); KisSelectionSP selection = fillpainter.createFloodSelection(pos.x(), pos.y(), sourceDevice); image->unlock(); // If we're not antialiasing, threshold the entire selection if (!antiAliasSelection()) { QRect r = selection->selectedExactRect(); if (r.isValid()) { KisHLineIteratorSP selectionIt = selection->pixelSelection()->createHLineIteratorNG(r.x(), r.y(), r.width()); for (qint32 y = 0; y < r.height(); y++) { do { if (selectionIt->rawData()[0] > 0) { selection->pixelSelection()->colorSpace()->setOpacity(selectionIt->rawData(), OPACITY_OPAQUE_U8, 1); } } while (selectionIt->nextPixel()); selectionIt->nextRow(); } } } KisCanvas2 * kisCanvas = dynamic_cast(canvas()); if (!kisCanvas || !selection->pixelSelection()) { QApplication::restoreOverrideCursor(); return; } selection->pixelSelection()->invalidateOutlineCache(); KisSelectionToolHelper helper(kisCanvas, kundo2_i18n("Select Contiguous Area")); helper.selectPixelSelection(selection->pixelSelection(), selectionAction()); 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); } QWidget* KisToolSelectContiguous::createOptionWidget() { KisToolSelectBase::createOptionWidget(); KisSelectionOptions *selectionWidget = selectionOptionWidget(); selectionWidget->disableSelectionModeOption(); 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); 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))); QCheckBox* limitToCurrentLayer = new QCheckBox(i18n("Limit to current layer"), selectionWidget); l->insertWidget(4, limitToCurrentLayer); connect (limitToCurrentLayer, SIGNAL(stateChanged(int)), this, SLOT(slotLimitToCurrentLayer(int))); // 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")); limitToCurrentLayer->setChecked(m_configGroup.readEntry("limitToCurrentLayer", false)); } return selectionWidget; } void KisToolSelectContiguous::slotLimitToCurrentLayer(int state) { if (state == Qt::PartiallyChecked) return; m_limitToCurrentLayer = (state == Qt::Checked); m_configGroup.writeEntry("limitToCurrentLayer", state); } 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(); } } diff --git a/plugins/tools/selectiontools/kis_tool_select_similar.cc b/plugins/tools/selectiontools/kis_tool_select_similar.cc index 72a01e55b5..67d3ebe748 100644 --- a/plugins/tools/selectiontools/kis_tool_select_similar.cc +++ b/plugins/tools/selectiontools/kis_tool_select_similar.cc @@ -1,184 +1,188 @@ /* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2005 Boudewijn Rempt * 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_similar.h" #include #include #include #include #include #include #include #include #include #include "kis_canvas2.h" #include #include "kis_selection_tool_helper.h" #include "kis_slider_spin_box.h" #include "kis_iterator_ng.h" #include "kis_image.h" void selectByColor(KisPaintDeviceSP dev, KisPixelSelectionSP selection, const quint8 *c, int fuzziness, const QRect & rc) { if (rc.isEmpty()) { return; } // XXX: Multithread this! qint32 x, y, w, h; x = rc.x(); y = rc.y(); w = rc.width(); h = rc.height(); const KoColorSpace * cs = dev->colorSpace(); KisHLineConstIteratorSP hiter = dev->createHLineConstIteratorNG(x, y, w); KisHLineIteratorSP selIter = selection->createHLineIteratorNG(x, y, w); for (int row = y; row < y + h; ++row) { do { //if (dev->colorSpace()->hasAlpha()) // opacity = dev->colorSpace()->alpha(hiter->rawData()); if (fuzziness == 1) { if (memcmp(c, hiter->oldRawData(), cs->pixelSize()) == 0) { *(selIter->rawData()) = MAX_SELECTED; } } else { quint8 match = cs->difference(c, hiter->oldRawData()); if (match <= fuzziness) { *(selIter->rawData()) = MAX_SELECTED; } } } while (hiter->nextPixel() && selIter->nextPixel()); hiter->nextRow(); selIter->nextRow(); } } KisToolSelectSimilar::KisToolSelectSimilar(KoCanvasBase * canvas) : KisToolSelect(canvas, KisCursor::load("tool_similar_selection_cursor.png", 6, 6), i18n("Similar Color Selection")), m_fuzziness(20) { } void KisToolSelectSimilar::activate(ToolActivation toolActivation, const QSet &shapes) { KisToolSelect::activate(toolActivation, shapes); m_configGroup = KSharedConfig::openConfig()->group(toolId()); } void KisToolSelectSimilar::beginPrimaryAction(KoPointerEvent *event) { KisToolSelectBase::beginPrimaryAction(event); KisPaintDeviceSP dev; if (!currentNode() || !(dev = currentNode()->projection()) || !currentNode()->visible() || !selectionEditable()) { event->ignore(); return; } + if (KisToolSelect::selectionDidMove()) { + return; + } + QPointF pos = convertToPixelCoord(event); KisCanvas2 * kisCanvas = dynamic_cast(canvas()); KIS_ASSERT_RECOVER_RETURN(kisCanvas); QApplication::setOverrideCursor(KisCursor::waitCursor()); KoColor c; dev->pixel(pos.x(), pos.y(), &c); // XXX we should make this configurable: "allow to select transparent" // if (opacity > OPACITY_TRANSPARENT) KisPixelSelectionSP tmpSel = KisPixelSelectionSP(new KisPixelSelection()); QRect rc; if (dev->colorSpace()->difference(c.data(), dev->defaultPixel().data()) <= m_fuzziness) { rc = image()->bounds(); } else { rc = dev->exactBounds(); } selectByColor(dev, tmpSel, c.data(), m_fuzziness, rc); tmpSel->invalidateOutlineCache(); KisSelectionToolHelper helper(kisCanvas, kundo2_i18n("Select Similar Color")); helper.selectPixelSelection(tmpSel, selectionAction()); QApplication::restoreOverrideCursor(); } void KisToolSelectSimilar::slotSetFuzziness(int fuzziness) { m_fuzziness = fuzziness; m_configGroup.writeEntry("fuzziness", fuzziness); } QWidget* KisToolSelectSimilar::createOptionWidget() { KisToolSelectBase::createOptionWidget(); KisSelectionOptions *selectionWidget = selectionOptionWidget(); selectionWidget->disableAntiAliasSelectionOption(); selectionWidget->disableSelectionModeOption(); QHBoxLayout* fl = new QHBoxLayout(); QLabel * lbl = new QLabel(i18n("Fuzziness: "), selectionWidget); fl->addWidget(lbl); KisSliderSpinBox* input = new KisSliderSpinBox(selectionWidget); input->setObjectName("fuzziness"); input->setRange(0, 200); input->setSingleStep(10); fl->addWidget(input); connect(input, SIGNAL(valueChanged(int)), this, SLOT(slotSetFuzziness(int))); QVBoxLayout* l = dynamic_cast(selectionWidget->layout()); Q_ASSERT(l); l->insertLayout(1, fl); // load setting from config input->setValue(m_configGroup.readEntry("fuzziness", 20)); return selectionWidget; } void KisToolSelectSimilar::resetCursorStyle() { if (selectionAction() == SELECTION_ADD) { useCursor(KisCursor::load("tool_similar_selection_cursor_add.png", 6, 6)); } else if (selectionAction() == SELECTION_SUBTRACT) { useCursor(KisCursor::load("tool_similar_selection_cursor_sub.png", 6, 6)); } else { KisToolSelect::resetCursorStyle(); } }