Index: libs/image/KisSelectionTags.h =================================================================== --- libs/image/KisSelectionTags.h +++ libs/image/KisSelectionTags.h @@ -30,6 +30,7 @@ SELECTION_ADD, SELECTION_SUBTRACT, SELECTION_INTERSECT, + SELECTION_EXCLUDE, SELECTION_DEFAULT }; Index: libs/image/kis_pixel_selection.h =================================================================== --- libs/image/kis_pixel_selection.h +++ libs/image/kis_pixel_selection.h @@ -153,6 +153,11 @@ */ void intersectSelection(KisPixelSelectionSP selection); + /** + * Exclude a selection + */ + void excludeSelection(KisPixelSelectionSP selection); + private: // We don't want these methods to be used on selections: using KisPaintDevice::extent; Index: libs/image/kis_pixel_selection.cpp =================================================================== --- libs/image/kis_pixel_selection.cpp +++ libs/image/kis_pixel_selection.cpp @@ -150,6 +150,9 @@ case SELECTION_INTERSECT: intersectSelection(selection); break; + case SELECTION_EXCLUDE: + excludeSelection(selection); + break; default: break; } @@ -255,6 +258,35 @@ m_d->invalidateThumbnailImage(); } +void KisPixelSelection::excludeSelection(KisPixelSelectionSP selection) +{ + QRect r = selection->selectedRect(); + if (r.isEmpty()) return; + + + KisHLineIteratorSP dst = createHLineIteratorNG(r.x(), r.y(), r.width()); + KisHLineConstIteratorSP src = selection->createHLineConstIteratorNG(r.x(), r.y(), r.width()); + for (int i = 0; i < r.height(); ++i) { + do { + if (*dst->rawData() - *src->oldRawData() > MIN_SELECTED) + *dst->rawData() = *dst->rawData() - *src->oldRawData(); + else + *dst->rawData() = abs(*dst->rawData() - *src->oldRawData()); + + } while (src->nextPixel() && dst->nextPixel()); + dst->nextRow(); + src->nextRow(); + } + + m_d->outlineCacheValid &= selection->outlineCacheValid(); + + if (m_d->outlineCacheValid) { + m_d->outlineCache += selection->outlineCache() - (m_d->outlineCache &= selection->outlineCache()); + } + + m_d->invalidateThumbnailImage(); +} + void KisPixelSelection::clear(const QRect & r) { if (*defaultPixel().data() != MIN_SELECTED) { Index: libs/libkis/Selection.h =================================================================== --- libs/libkis/Selection.h +++ libs/libkis/Selection.h @@ -196,6 +196,11 @@ */ void intersect(Selection *selection); + /** + * Exclude the given selection with this selection. + */ + void exclude(Selection *selection); + /** * @brief pixelData reads the given rectangle from the Selection's mask and returns it as a * byte array. The pixel data starts top-left, and is ordered row-first. Index: libs/libkis/Selection.cpp =================================================================== --- libs/libkis/Selection.cpp +++ libs/libkis/Selection.cpp @@ -293,6 +293,12 @@ d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_INTERSECT); } +void Selection::exclude(Selection *selection) +{ + if (!d->selection) return; + d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_EXCLUDE); +} + QByteArray Selection::pixelData(int x, int y, int w, int h) const { Index: libs/ui/forms/wdgselectionoptions.ui =================================================================== --- libs/ui/forms/wdgselectionoptions.ui +++ libs/ui/forms/wdgselectionoptions.ui @@ -6,35 +6,33 @@ 0 0 - 271 - 106 + 652 + 257 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - + 0 - - + + + + CrossCursor + + + Mode: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + - Intersect + Subtract (Shortcut S) ... @@ -63,10 +61,10 @@ - - + + - Replace (Shortcut R) + Add (Shortcut A) ... @@ -74,18 +72,15 @@ true - - true - false - - + + - Add (Shortcut A) + Pixel Selection ... @@ -93,38 +88,34 @@ true + + true + false - - - - CrossCursor + + + + Intersect - Mode: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + ... - - - - - - Action: + + true - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + false - - + + - Pixel Selection + Replace (Shortcut R) ... @@ -140,8 +131,18 @@ - - + + + + Action: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + Subtract (Shortcut S) @@ -158,7 +159,7 @@ - + Qt::Horizontal Index: libs/ui/tool/kis_selection_tool_config_widget_helper.cpp =================================================================== --- libs/ui/tool/kis_selection_tool_config_widget_helper.cpp +++ libs/ui/tool/kis_selection_tool_config_widget_helper.cpp @@ -59,6 +59,8 @@ this, &KisSelectionToolConfigWidgetHelper::slotGlobalActionChanged); connect(m_resourceProvider, &KisCanvasResourceProvider::sigSelectionModeChanged, this, &KisSelectionToolConfigWidgetHelper::slotGlobalModeChanged); + connect(m_resourceProvider, &KisCanvasResourceProvider::sigSelectionModeChanged, + this, &KisSelectionToolConfigWidgetHelper::slotGlobalModeChanged); m_optionsWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); m_optionsWidget->adjustSize(); @@ -124,6 +126,9 @@ case Qt::Key_T: slotWidgetActionChanged(SELECTION_INTERSECT); break; + case Qt::Key_E: + slotWidgetActionChanged(SELECTION_EXCLUDE); + break; default: event->ignore(); } Index: libs/ui/widgets/kis_selection_options.cc =================================================================== --- libs/ui/widgets/kis_selection_options.cc +++ libs/ui/widgets/kis_selection_options.cc @@ -53,6 +53,7 @@ m_action->addButton(m_page->subtract, SELECTION_SUBTRACT); m_action->addButton(m_page->replace, SELECTION_REPLACE); m_action->addButton(m_page->intersect, SELECTION_INTERSECT); + m_action->addButton(m_page->exclude, SELECTION_EXCLUDE); m_page->pixel->setGroupPosition(KoGroupButton::GroupLeft); m_page->shape->setGroupPosition(KoGroupButton::GroupRight); @@ -63,10 +64,12 @@ m_page->subtract->setGroupPosition(KoGroupButton::GroupRight); m_page->replace->setGroupPosition(KoGroupButton::GroupLeft); m_page->intersect->setGroupPosition(KoGroupButton::GroupCenter); + m_page->exclude->setGroupPosition(KoGroupButton::GroupRight); m_page->add->setIcon(KisIconUtils::loadIcon("selection_add")); m_page->subtract->setIcon(KisIconUtils::loadIcon("selection_subtract")); m_page->replace->setIcon(KisIconUtils::loadIcon("selection_replace")); m_page->intersect->setIcon(KisIconUtils::loadIcon("selection_intersect")); + m_page->exclude->setIcon(KisIconUtils::loadIcon("selection_exclude")); connect(m_mode, SIGNAL(buttonClicked(int)), this, SIGNAL(modeChanged(int))); connect(m_action, SIGNAL(buttonClicked(int)), this, SIGNAL(actionChanged(int))); @@ -105,6 +108,7 @@ m_page->subtract->setVisible(isPixelSelection); m_page->replace->setVisible(isPixelSelection); m_page->intersect->setVisible(isPixelSelection); + m_page->exclude->setVisible(isPixelSelection); m_page->chkAntiAliasing->setVisible(isPixelSelection); } Index: plugins/tools/selectiontools/kis_selection_modifier_mapper.cc =================================================================== --- plugins/tools/selectiontools/kis_selection_modifier_mapper.cc +++ plugins/tools/selectiontools/kis_selection_modifier_mapper.cc @@ -59,6 +59,7 @@ Qt::KeyboardModifiers intersectModifiers; Qt::KeyboardModifiers addModifiers; Qt::KeyboardModifiers subtractModifiers; + Qt::KeyboardModifiers excludeModifiers; }; @@ -91,13 +92,15 @@ { KisConfig cfg(true); if (!cfg.switchSelectionCtrlAlt()) { - replaceModifiers = Qt::ControlModifier; - intersectModifiers = (Qt::KeyboardModifiers)(Qt::AltModifier | Qt::ShiftModifier); - subtractModifiers = Qt::AltModifier; + replaceModifiers = Qt::AltModifier; + intersectModifiers = (Qt::KeyboardModifiers)(Qt::AltModifier | Qt::ControlModifier); + subtractModifiers = Qt::ControlModifier; + excludeModifiers = (Qt::KeyboardModifiers)(Qt::AltModifier | Qt::ShiftModifier); } else { replaceModifiers = Qt::AltModifier; intersectModifiers = (Qt::KeyboardModifiers)(Qt::ControlModifier | Qt::ShiftModifier); - subtractModifiers = Qt::ControlModifier; + subtractModifiers = Qt::AltModifier; + excludeModifiers = (Qt::KeyboardModifiers)((Qt::ControlModifier | Qt::ShiftModifier)|Qt::AltModifier); } addModifiers = Qt::ShiftModifier; @@ -119,6 +122,9 @@ newAction = SELECTION_ADD; } else if (m == subtractModifiers) { newAction = SELECTION_SUBTRACT; + } else if (m == excludeModifiers) { + newAction = SELECTION_EXCLUDE; } + return newAction; }