diff --git a/libs/image/KisSelectionTags.h b/libs/image/KisSelectionTags.h --- a/libs/image/KisSelectionTags.h +++ b/libs/image/KisSelectionTags.h @@ -30,6 +30,7 @@ SELECTION_ADD, SELECTION_SUBTRACT, SELECTION_INTERSECT, + SELECTION_EXCLUDE, SELECTION_DEFAULT }; diff --git a/libs/image/kis_pixel_selection.h b/libs/image/kis_pixel_selection.h --- a/libs/image/kis_pixel_selection.h +++ b/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; diff --git a/libs/image/kis_pixel_selection.cpp b/libs/image/kis_pixel_selection.cpp --- a/libs/image/kis_pixel_selection.cpp +++ b/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) { diff --git a/libs/libkis/Selection.h b/libs/libkis/Selection.h --- a/libs/libkis/Selection.h +++ b/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. diff --git a/libs/libkis/Selection.cpp b/libs/libkis/Selection.cpp --- a/libs/libkis/Selection.cpp +++ b/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 { diff --git a/libs/libqml/qml/panels/SelectPanel.qml b/libs/libqml/qml/panels/SelectPanel.qml --- a/libs/libqml/qml/panels/SelectPanel.qml +++ b/libs/libqml/qml/panels/SelectPanel.qml @@ -124,8 +124,8 @@ image: Settings.theme.icon("select-intersect"); width: Constants.ToolbarButtonSize * 0.8; height: width; - checked: (toolManager.currentTool && toolManager.currentTool.selectionAction === 3) ? true : false; - onClicked: if (toolManager.currentTool && toolManager.currentTool.selectionAction !== undefined) toolManager.currentTool.selectionAction = 3; + checked: (toolManager.currentTool && toolManager.currentTool.selectionAction === 4) ? true : false; + onClicked: if (toolManager.currentTool && toolManager.currentTool.selectionAction !== undefined) toolManager.currentTool.selectionAction = 4; } Button { id: selectAdd; @@ -145,6 +145,15 @@ checked: (toolManager.currentTool && toolManager.currentTool.selectionAction === 2) ? true : false; onClicked: if (toolManager.currentTool && toolManager.currentTool.selectionAction !== undefined) toolManager.currentTool.selectionAction = 2; } + Button { + id: selectExclude; + anchors.left: selectExclude.right; + image: Settings.theme.icon("select-exclude"); + width: Constants.ToolbarButtonSize * 0.8; + height: width; + checked: (toolManager.currentTool && toolManager.currentTool.selectionAction === 3) ? true : false; + onClicked: if (toolManager.currentTool && toolManager.currentTool.selectionAction !== undefined) toolManager.currentTool.selectionAction = 3; + } } Item { width: childrenRect.width; diff --git a/libs/ui/forms/wdgselectionoptions.ui b/libs/ui/forms/wdgselectionoptions.ui --- a/libs/ui/forms/wdgselectionoptions.ui +++ b/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,10 +131,20 @@ - - + + + + Action: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + - Subtract (Shortcut S) + Exclude ... @@ -158,7 +159,7 @@ - + Qt::Horizontal diff --git a/libs/ui/kis_selection_manager.cc b/libs/ui/kis_selection_manager.cc --- a/libs/ui/kis_selection_manager.cc +++ b/libs/ui/kis_selection_manager.cc @@ -650,6 +650,9 @@ case SELECTION_INTERSECT: actionName = kundo2_i18n("Select Opaque (Intersect)"); break; + case SELECTION_EXCLUDE: + actionName = kundo2_i18n("Select Opaque (Exclude)"); + break; default: actionName = kundo2_i18n("Select Opaque"); break; diff --git a/libs/ui/tool/kis_selection_tool_config_widget_helper.cpp b/libs/ui/tool/kis_selection_tool_config_widget_helper.cpp --- a/libs/ui/tool/kis_selection_tool_config_widget_helper.cpp +++ b/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(); @@ -81,7 +83,7 @@ void KisSelectionToolConfigWidgetHelper::slotWidgetActionChanged(int action) { - if (action >= SELECTION_REPLACE && action <= SELECTION_INTERSECT) { + if (action >= SELECTION_REPLACE && action <= SELECTION_EXCLUDE) { m_optionsWidget->setAction(action); m_resourceProvider->setSelectionAction(action); emit selectionActionChanged(action); @@ -124,6 +126,9 @@ case Qt::Key_T: slotWidgetActionChanged(SELECTION_INTERSECT); break; + case Qt::Key_E: + slotWidgetActionChanged(SELECTION_EXCLUDE); + break; default: event->ignore(); } diff --git a/libs/ui/tool/kis_selection_tool_helper.cpp b/libs/ui/tool/kis_selection_tool_helper.cpp --- a/libs/ui/tool/kis_selection_tool_helper.cpp +++ b/libs/ui/tool/kis_selection_tool_helper.cpp @@ -105,7 +105,7 @@ KisSelectionTransaction transaction(pixelSelection); - if (!hasSelection && m_action == SELECTION_SUBTRACT) { + if (!hasSelection && m_action == SELECTION_EXCLUDE) { pixelSelection->invert(); } diff --git a/libs/ui/widgets/kis_selection_options.cc b/libs/ui/widgets/kis_selection_options.cc --- a/libs/ui/widgets/kis_selection_options.cc +++ b/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); } diff --git a/plugins/extensions/pykrita/sip/krita/Selection.sip b/plugins/extensions/pykrita/sip/krita/Selection.sip --- a/plugins/extensions/pykrita/sip/krita/Selection.sip +++ b/plugins/extensions/pykrita/sip/krita/Selection.sip @@ -35,6 +35,7 @@ void add(Selection *selection); void subtract(Selection *selection); void intersect(Selection *selection); + void exclude(Selection *selection); QByteArray pixelData(int x, int y, int w, int h) const; void setPixelData(QByteArray value, int x, int y, int w, int h); private: diff --git a/plugins/tools/selectiontools/kis_selection_modifier_mapper.cc b/plugins/tools/selectiontools/kis_selection_modifier_mapper.cc --- a/plugins/tools/selectiontools/kis_selection_modifier_mapper.cc +++ b/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; }