diff --git a/krita/krita.qrc b/krita/krita.qrc --- a/krita/krita.qrc +++ b/krita/krita.qrc @@ -53,7 +53,7 @@ pics/select_pixel.png pics/select_shape.png pics/selection_add.png - pics/selection_exclude.png + pics/selection_symmetric_difference.png pics/selection_intersect.png pics/selection_replace.png pics/selection_subtract.png diff --git a/krita/pics/selection_exclude.png b/krita/pics/selection_exclude.png deleted file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@invalidateThumbnailImage(); } +void KisPixelSelection::symmetricdifferenceSelection(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 { + 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); + /** + * Intersect with the inverse of the given selection with this selection. + */ + void symmetricdifference(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::symmetricdifference(Selection *selection) +{ + if (!d->selection) return; + d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_SYMMETRICDIFFERENCE); +} + 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: selectSymmetricDifference; + anchors.left: selectExclude.right; + image: Settings.theme.icon("select-symmetric-difference"); + width: Constants.ToolbarButtonSize * 0.8; + height: width; + checked: (toolManager.currentTool && toolManager.currentTool.selectionAction === 4) ? true : false; + onClicked: if (toolManager.currentTool && toolManager.currentTool.selectionAction !== undefined) toolManager.currentTool.selectionAction = 4; + } } 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) + Symmetric Difference ... @@ -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 @@ -715,6 +715,9 @@ case SELECTION_INTERSECT: actionName = kundo2_i18n("Select Opaque (Intersect)"); break; + case SELECTION_SYMMETRICDIFFERENCE: + actionName = kundo2_i18n("Select Opaque (Symmetric Difference)"); + 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 @@ -124,6 +124,9 @@ case Qt::Key_T: slotWidgetActionChanged(SELECTION_INTERSECT); break; + case Qt::Key_E: + slotWidgetActionChanged(SELECTION_SYMMETRICDIFFERENCE); + 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,14 +105,14 @@ KisSelectionTransaction transaction(pixelSelection); - if (!hasSelection && m_action == SELECTION_SUBTRACT) { + if (!hasSelection && m_action == SELECTION_SYMMETRICDIFFERENCE) { pixelSelection->invert(); } pixelSelection->applySelection(m_selection, m_action); QRect dirtyRect = m_view->image()->bounds(); - if (hasSelection && m_action != SELECTION_REPLACE && m_action != SELECTION_INTERSECT) { + if (hasSelection && m_action != SELECTION_REPLACE && m_action != SELECTION_SYMMETRICDIFFERENCE) { dirtyRect = m_selection->selectedRect(); } m_view->selection()->updateProjection(dirtyRect); @@ -226,6 +226,9 @@ case SELECTION_SUBTRACT: path = path1 - path2; break; + case SELECTION_SYMMETRICDIFFERENCE: + path = (path1 | path2) - (path1 & path2); + break; } KoShape *newShape = KoPathShape::createShapeFromPainterPath(path); @@ -266,7 +269,7 @@ bool KisSelectionToolHelper::canShortcutToDeselect(const QRect &rect, SelectionAction action) { - return rect.isEmpty() && (action == SELECTION_INTERSECT || action == SELECTION_REPLACE); + return rect.isEmpty() && (action == SELECTION_SYMMETRICDIFFERENCE || action == SELECTION_REPLACE); } bool KisSelectionToolHelper::canShortcutToNoop(const QRect &rect, SelectionAction action) @@ -279,7 +282,7 @@ bool result = false; if (KisAlgebra2D::maxDimension(selectionViewRect) < KisConfig(true).selectionViewSizeMinimum() && - (action == SELECTION_INTERSECT || action == SELECTION_REPLACE)) { + (action == SELECTION_SYMMETRICDIFFERENCE || action == SELECTION_REPLACE)) { // Queueing this action to ensure we avoid a race condition when unlocking the node system QTimer::singleShot(0, m_canvas->viewManager()->selectionManager(), SLOT(deselect())); 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->symmetricdifference, SELECTION_SYMMETRICDIFFERENCE); 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->symmetricdifference->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->symmetricdifference->setIcon(KisIconUtils::loadIcon("selection_symmetric_difference")); connect(m_mode, SIGNAL(buttonClicked(int)), this, SIGNAL(modeChanged(int))); connect(m_action, SIGNAL(buttonClicked(int)), this, SIGNAL(actionChanged(int))); 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 symmetricdifference(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 symmetricdifferenceModifiers; }; @@ -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; + symmetricdifferenceModifiers = (Qt::KeyboardModifiers)(Qt::AltModifier | Qt::ShiftModifier); } else { replaceModifiers = Qt::AltModifier; intersectModifiers = (Qt::KeyboardModifiers)(Qt::ControlModifier | Qt::ShiftModifier); - subtractModifiers = Qt::ControlModifier; + subtractModifiers = Qt::AltModifier; + symmetricdifferenceModifiers = (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 == symmetricdifferenceModifiers) { + newAction = SELECTION_SYMMETRICDIFFERENCE; } + return newAction; }