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;
}