diff --git a/krita/pics/tools/SVG/16/dark_tool_magnetic_selection.svg b/krita/pics/tools/SVG/16/dark_tool_magnetic_selection.svg
new file mode 100644
index 0000000000..cb6ebd8897
--- /dev/null
+++ b/krita/pics/tools/SVG/16/dark_tool_magnetic_selection.svg
@@ -0,0 +1,232 @@
+
+
+
+
diff --git a/krita/pics/tools/SVG/16/light_tool_magnetic_selection.svg b/krita/pics/tools/SVG/16/light_tool_magnetic_selection.svg
new file mode 100644
index 0000000000..426c2647d5
--- /dev/null
+++ b/krita/pics/tools/SVG/16/light_tool_magnetic_selection.svg
@@ -0,0 +1,150 @@
+
+
+
+
diff --git a/krita/pics/tools/SVG/16/tools-svg-16-icons.qrc b/krita/pics/tools/SVG/16/tools-svg-16-icons.qrc
index d760fb0128..e831473360 100644
--- a/krita/pics/tools/SVG/16/tools-svg-16-icons.qrc
+++ b/krita/pics/tools/SVG/16/tools-svg-16-icons.qrc
@@ -1,82 +1,84 @@
dark_calligraphy.svg
dark_draw-text.svg
dark_format-fill-color.svg
dark_krita_draw_path.svg
dark_krita_tool_color_fill.svg
dark_krita_tool_color_picker.svg
dark_krita_tool_dyna.svg
dark_krita_tool_ellipse.svg
dark_krita_tool_freehand.svg
dark_krita_tool_freehandvector.svg
dark_krita_tool_gradient.svg
dark_krita_tool_grid.svg
dark_krita_tool_line.svg
dark_krita_tool_measure.svg
dark_krita_tool_move.svg
dark_krita_tool_multihand.svg
dark_krita_tool_polygon.svg
dark_krita_tool_rectangle.svg
dark_krita_tool_transform.svg
dark_pattern.svg
dark_polyline.svg
dark_select.svg
dark_tool_contiguous_selection.svg
dark_tool_crop.svg
dark_tool_elliptical_selection.svg
+ dark_tool_magnetic_selection.svg
dark_tool_outline_selection.svg
dark_tool_pan.svg
dark_tool_path_selection.svg
dark_tool_perspectivegrid.svg
dark_tool_polygonal_selection.svg
dark_tool_rect_selection.svg
dark_tool_similar_selection.svg
dark_tool_zoom.svg
light_calligraphy.svg
light_draw-text.svg
light_format-fill-color.svg
light_krita_draw_path.svg
light_krita_tool_color_fill.svg
light_krita_tool_color_picker.svg
light_krita_tool_dyna.svg
light_krita_tool_ellipse.svg
light_krita_tool_freehand.svg
light_krita_tool_freehandvector.svg
light_krita_tool_gradient.svg
light_krita_tool_grid.svg
light_krita_tool_line.svg
light_krita_tool_measure.svg
light_krita_tool_move.svg
light_krita_tool_multihand.svg
light_krita_tool_polygon.svg
light_krita_tool_rectangle.svg
light_krita_tool_transform.svg
light_pattern.svg
light_polyline.svg
light_select.svg
light_tool_contiguous_selection.svg
light_tool_crop.svg
light_tool_elliptical_selection.svg
light_tool_outline_selection.svg
+ light_tool_magnetic_selection.svg
light_tool_pan.svg
light_tool_path_selection.svg
light_tool_perspectivegrid.svg
light_tool_polygonal_selection.svg
light_tool_rect_selection.svg
light_tool_similar_selection.svg
light_tool_zoom.svg
dark_shape_handling.svg
dark_artistic_text.svg
light_artistic_text.svg
light_shape_handling.svg
dark_krita_tool_lazybrush.svg
light_krita_tool_lazybrush.svg
dark_krita_tool_smart_patch.svg
light_krita_tool_smart_patch.svg
light_krita_tool_assistant.svg
dark_krita_tool_assistant.svg
dark_krita_tool_reference_images.svg
light_krita_tool_reference_images.svg
diff --git a/plugins/tools/selectiontools/CMakeLists.txt b/plugins/tools/selectiontools/CMakeLists.txt
index 2b8af08572..756cab5959 100644
--- a/plugins/tools/selectiontools/CMakeLists.txt
+++ b/plugins/tools/selectiontools/CMakeLists.txt
@@ -1,35 +1,37 @@
add_subdirectory(tests)
set(kritaselectiontools_SOURCES
selection_tools.cc
kis_tool_select_rectangular.cc
kis_tool_select_polygonal.cc
kis_tool_select_elliptical.cc
kis_tool_select_contiguous.cc
kis_tool_select_outline.cc
kis_tool_select_path.cc
kis_tool_select_similar.cc
kis_selection_modifier_mapper.cc
KisMagneticWorker.cc
+ KisToolSelectMagnetic.cc
)
qt5_add_resources(kritaselectiontools_SOURCES selectiontools.qrc)
add_library(kritaselectiontools MODULE ${kritaselectiontools_SOURCES})
generate_export_header(kritaselectiontools BASE_NAME kritaselectiontools)
target_link_libraries(kritaselectiontools kritaui kritabasicflakes kritaimage)
install(TARGETS kritaselectiontools DESTINATION ${KRITA_PLUGIN_INSTALL_DIR})
install( FILES
KisToolSelectPolygonal.action
KisToolSelectElliptical.action
KisToolSelectSimilar.action
KisToolSelectContiguous.action
KisToolSelectRectangular.action
KisToolSelectOutline.action
KisToolSelectPath.action
+ KisToolSelectMagnetic.action
DESTINATION ${DATA_INSTALL_DIR}/krita/actions
)
diff --git a/plugins/tools/selectiontools/KisToolSelectMagnetic.action b/plugins/tools/selectiontools/KisToolSelectMagnetic.action
new file mode 100644
index 0000000000..fe0fbb9f7c
--- /dev/null
+++ b/plugins/tools/selectiontools/KisToolSelectMagnetic.action
@@ -0,0 +1,6 @@
+
+
+
+ Magnetic Selection Tool
+
+
diff --git a/plugins/tools/selectiontools/KisToolSelectMagnetic.cc b/plugins/tools/selectiontools/KisToolSelectMagnetic.cc
new file mode 100644
index 0000000000..8d4421d30d
--- /dev/null
+++ b/plugins/tools/selectiontools/KisToolSelectMagnetic.cc
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2019 Kuntal Majumder
+ *
+ * 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 "KisToolSelectMagnetic.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "kis_painter.h"
+#include
+#include "canvas/kis_canvas2.h"
+#include "kis_pixel_selection.h"
+#include "kis_selection_tool_helper.h"
+
+#include "kis_algebra_2d.h"
+
+
+#define FEEDBACK_LINE_WIDTH 2
+
+
+KisToolSelectMagnetic::KisToolSelectMagnetic(KoCanvasBase *canvas)
+ : KisToolSelect(canvas,
+ KisCursor::load("tool_magnetic_selection_cursor.svg", 16, 16),
+ i18n("Magnetic Selection")),
+ m_continuedMode(false)
+{
+}
+
+KisToolSelectMagnetic::~KisToolSelectMagnetic()
+{
+}
+
+void KisToolSelectMagnetic::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_Control) {
+ m_continuedMode = true;
+ }
+
+ KisToolSelect::keyPressEvent(event);
+}
+
+void KisToolSelectMagnetic::keyReleaseEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_Control ||
+ !(event->modifiers() & Qt::ControlModifier)) {
+
+ m_continuedMode = false;
+ if (mode() != PAINT_MODE && !m_points.isEmpty()) {
+ finishSelectionAction();
+ }
+ }
+
+ KisToolSelect::keyReleaseEvent(event);
+}
+
+void KisToolSelectMagnetic::mouseMoveEvent(KoPointerEvent *event)
+{
+ KisToolSelect::mouseMoveEvent(event);
+ if (selectionDragInProgress()) return;
+
+ m_lastCursorPos = convertToPixelCoord(event);
+ if (m_continuedMode && mode() != PAINT_MODE) {
+ updateContinuedMode();
+ }
+}
+
+void KisToolSelectMagnetic::beginPrimaryAction(KoPointerEvent *event)
+{
+ KisToolSelectBase::beginPrimaryAction(event);
+ if (selectionDragInProgress()) return;
+
+ if (!selectionEditable()) {
+ event->ignore();
+ return;
+ }
+
+ setMode(KisTool::PAINT_MODE);
+
+ if (m_continuedMode && !m_points.isEmpty()) {
+ m_paintPath.lineTo(pixelToView(convertToPixelCoord(event)));
+ } else {
+ m_paintPath.moveTo(pixelToView(convertToPixelCoord(event)));
+ }
+
+ m_points.append(convertToPixelCoord(event));
+}
+
+void KisToolSelectMagnetic::continuePrimaryAction(KoPointerEvent *event)
+{
+ KisToolSelectBase::continuePrimaryAction(event);
+ if (selectionDragInProgress()) return;
+
+ CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE);
+
+ QPointF point = convertToPixelCoord(event);
+ m_paintPath.lineTo(pixelToView(point));
+ m_points.append(point);
+ updateFeedback();
+
+
+}
+
+void KisToolSelectMagnetic::endPrimaryAction(KoPointerEvent *event)
+{
+ const bool hadMoveInProgress = selectionDragInProgress();
+ KisToolSelectBase::endPrimaryAction(event);
+ if (hadMoveInProgress) return;
+
+ CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE);
+ setMode(KisTool::HOVER_MODE);
+
+ if (!m_continuedMode) {
+ finishSelectionAction();
+ }
+}
+
+void KisToolSelectMagnetic::finishSelectionAction()
+{
+ KisCanvas2 * kisCanvas = dynamic_cast(canvas());
+ KIS_ASSERT_RECOVER_RETURN(kisCanvas);
+ kisCanvas->updateCanvas();
+
+ QRectF boundingViewRect =
+ pixelToView(KisAlgebra2D::accumulateBounds(m_points));
+
+ KisSelectionToolHelper helper(kisCanvas, kundo2_i18n("Select by Outline"));
+
+ if (m_points.count() > 2 &&
+ !helper.tryDeselectCurrentSelection(boundingViewRect, selectionAction())) {
+ QApplication::setOverrideCursor(KisCursor::waitCursor());
+
+ const SelectionMode mode =
+ helper.tryOverrideSelectionMode(kisCanvas->viewManager()->selection(),
+ selectionMode(),
+ selectionAction());
+
+ if (mode == PIXEL_SELECTION) {
+
+ KisPixelSelectionSP tmpSel = KisPixelSelectionSP(new KisPixelSelection());
+
+ KisPainter painter(tmpSel);
+ painter.setPaintColor(KoColor(Qt::black, tmpSel->colorSpace()));
+ painter.setAntiAliasPolygonFill(antiAliasSelection());
+ painter.setFillStyle(KisPainter::FillStyleForegroundColor);
+ painter.setStrokeStyle(KisPainter::StrokeStyleNone);
+
+ painter.paintPolygon(m_points);
+
+ QPainterPath cache;
+ cache.addPolygon(m_points);
+ cache.closeSubpath();
+ tmpSel->setOutlineCache(cache);
+
+ helper.selectPixelSelection(tmpSel, selectionAction());
+ } else {
+
+ KoPathShape* path = new KoPathShape();
+ path->setShapeId(KoPathShapeId);
+
+ QTransform resolutionMatrix;
+ resolutionMatrix.scale(1 / currentImage()->xRes(), 1 / currentImage()->yRes());
+ path->moveTo(resolutionMatrix.map(m_points[0]));
+ for (int i = 1; i < m_points.count(); i++)
+ path->lineTo(resolutionMatrix.map(m_points[i]));
+ path->close();
+ path->normalize();
+
+ helper.addSelectionShape(path, selectionAction());
+ }
+ QApplication::restoreOverrideCursor();
+ }
+
+ m_points.clear();
+ m_paintPath = QPainterPath();
+}
+
+void KisToolSelectMagnetic::paint(QPainter& gc, const KoViewConverter &converter)
+{
+ Q_UNUSED(converter);
+
+ if ((mode() == KisTool::PAINT_MODE || m_continuedMode) &&
+ !m_points.isEmpty()) {
+
+ QPainterPath outline = m_paintPath;
+ if (m_continuedMode && mode() != KisTool::PAINT_MODE) {
+ outline.lineTo(pixelToView(m_lastCursorPos));
+ }
+ paintToolOutline(&gc, outline);
+ }
+}
+
+
+
+void KisToolSelectMagnetic::updateFeedback()
+{
+ if (m_points.count() > 1) {
+ qint32 lastPointIndex = m_points.count() - 1;
+
+ QRectF updateRect = QRectF(m_points[lastPointIndex - 1], m_points[lastPointIndex]).normalized();
+ updateRect = kisGrowRect(updateRect, FEEDBACK_LINE_WIDTH);
+
+ updateCanvasPixelRect(updateRect);
+ }
+}
+
+void KisToolSelectMagnetic::updateContinuedMode()
+{
+ if (!m_points.isEmpty()) {
+ qint32 lastPointIndex = m_points.count() - 1;
+
+ QRectF updateRect = QRectF(m_points[lastPointIndex - 1], m_lastCursorPos).normalized();
+ updateRect = kisGrowRect(updateRect, FEEDBACK_LINE_WIDTH);
+
+ updateCanvasPixelRect(updateRect);
+ }
+}
+
+void KisToolSelectMagnetic::deactivate()
+{
+ KisCanvas2 * kisCanvas = dynamic_cast(canvas());
+ KIS_ASSERT_RECOVER_RETURN(kisCanvas);
+ kisCanvas->updateCanvas();
+
+ m_continuedMode = false;
+
+ KisTool::deactivate();
+}
+
+void KisToolSelectMagnetic::resetCursorStyle()
+{
+ if (selectionAction() == SELECTION_ADD) {
+ useCursor(KisCursor::load("tool_outline_selection_cursor_add.png", 6, 6));
+ } else if (selectionAction() == SELECTION_SUBTRACT) {
+ useCursor(KisCursor::load("tool_outline_selection_cursor_sub.png", 6, 6));
+ } else {
+ KisToolSelect::resetCursorStyle();
+ }
+}
+
diff --git a/plugins/tools/selectiontools/KisToolSelectMagnetic.h b/plugins/tools/selectiontools/KisToolSelectMagnetic.h
new file mode 100644
index 0000000000..a2505d5a3b
--- /dev/null
+++ b/plugins/tools/selectiontools/KisToolSelectMagnetic.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2019 Kuntal Majumder
+ *
+ * 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.
+ */
+
+#ifndef KIS_TOOL_SELECT_MAGNETIC_H_
+#define KIS_TOOL_SELECT_MAGNETIC_H_
+
+#include
+#include "KisSelectionToolFactoryBase.h"
+#include
+#include
+
+class QPainterPath;
+
+class KisToolSelectMagnetic : public KisToolSelect
+{
+ Q_OBJECT
+
+public:
+ KisToolSelectMagnetic(KoCanvasBase *canvas);
+ ~KisToolSelectMagnetic() override;
+ void beginPrimaryAction(KoPointerEvent *event) override;
+ void continuePrimaryAction(KoPointerEvent *event) override;
+ void endPrimaryAction(KoPointerEvent *event) override;
+ void paint(QPainter& gc, const KoViewConverter &converter) override;
+
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+
+ void mouseMoveEvent(KoPointerEvent *event) override;
+
+ void resetCursorStyle();
+
+public Q_SLOTS:
+ void deactivate() override;
+
+protected:
+ using KisToolSelectBase::m_widgetHelper;
+
+private:
+ void finishSelectionAction();
+ void updateFeedback();
+ void updateContinuedMode();
+ void updateCanvas();
+
+ QPainterPath m_paintPath;
+ vQPointF m_points;
+ bool m_continuedMode;
+ QPointF m_lastCursorPos;
+};
+
+class KisToolSelectMagneticFactory : public KisSelectionToolFactoryBase
+{
+public:
+ KisToolSelectMagneticFactory()
+ : KisSelectionToolFactoryBase("KisToolSelectMagnetic")
+ {
+ setToolTip(i18n("Magnetic Selection Tool"));
+ setSection(TOOL_TYPE_SELECTION);
+ setIconName(koIconNameCStr("tool_magnetic_selection"));
+ setPriority(8);
+ setActivationShapeId(KRITA_TOOL_ACTIVATION_ID);
+ }
+
+ ~KisToolSelectMagneticFactory() override {}
+
+ KoToolBase * createTool(KoCanvasBase *canvas) override {
+ return new KisToolSelectMagnetic(canvas);
+ }
+};
+
+
+#endif //__selecttoolmagnetic_h__
+
diff --git a/plugins/tools/selectiontools/selection_tools.cc b/plugins/tools/selectiontools/selection_tools.cc
index e0e44fbe60..fb0af54745 100644
--- a/plugins/tools/selectiontools/selection_tools.cc
+++ b/plugins/tools/selectiontools/selection_tools.cc
@@ -1,59 +1,61 @@
/*
* selection_tools.cc -- Part of Krita
*
* Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org)
*
* 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 "selection_tools.h"
#include
#include
#include
#include "KoToolRegistry.h"
#include "kis_global.h"
#include "kis_types.h"
#include "kis_tool_select_outline.h"
#include "kis_tool_select_polygonal.h"
#include "kis_tool_select_rectangular.h"
#include "kis_tool_select_contiguous.h"
#include "kis_tool_select_elliptical.h"
#include "kis_tool_select_path.h"
#include "kis_tool_select_similar.h"
+#include "KisToolSelectMagnetic.h"
K_PLUGIN_FACTORY_WITH_JSON(SelectionToolsFactory, "kritaselectiontools.json", registerPlugin();)
SelectionTools::SelectionTools(QObject *parent, const QVariantList &)
: QObject(parent)
{
KoToolRegistry::instance()->add(new KisToolSelectOutlineFactory());
KoToolRegistry::instance()->add(new KisToolSelectPolygonalFactory());
KoToolRegistry::instance()->add(new KisToolSelectRectangularFactory());
KoToolRegistry::instance()->add(new KisToolSelectEllipticalFactory());
KoToolRegistry::instance()->add(new KisToolSelectContiguousFactory());
KoToolRegistry::instance()->add(new KisToolSelectPathFactory());
KoToolRegistry::instance()->add(new KisToolSelectSimilarFactory());
+ KoToolRegistry::instance()->add(new KisToolSelectMagneticFactory());
}
SelectionTools::~SelectionTools()
{
}
#include "selection_tools.moc"
diff --git a/plugins/tools/selectiontools/selectiontools.qrc b/plugins/tools/selectiontools/selectiontools.qrc
index cd3646a389..1950cec996 100644
--- a/plugins/tools/selectiontools/selectiontools.qrc
+++ b/plugins/tools/selectiontools/selectiontools.qrc
@@ -1,24 +1,25 @@
tool_contiguous_selection_cursor_add.png
tool_contiguous_selection_cursor.png
tool_contiguous_selection_cursor_sub.png
tool_elliptical_selection_cursor_add.png
tool_elliptical_selection_cursor.png
tool_elliptical_selection_cursor_sub.png
tool_eraser_selection_cursor.png
+ tool_magnetic_selection_cursor.svg
tool_outline_selection_cursor_add.png
tool_outline_selection_cursor.png
tool_outline_selection_cursor_sub.png
tool_polygonal_selection_cursor_add.png
tool_polygonal_selection_cursor.png
tool_polygonal_selection_cursor_sub.png
tool_rectangular_selection_cursor_add.png
tool_rectangular_selection_cursor.png
tool_rectangular_selection_cursor_sub.png
tool_similar_selection_cursor_add.png
tool_similar_selection_cursor.png
tool_similar_selection_cursor_sub.png
diff --git a/plugins/tools/selectiontools/tool_magnetic_selection_cursor.svg b/plugins/tools/selectiontools/tool_magnetic_selection_cursor.svg
new file mode 100644
index 0000000000..1fdccafb38
--- /dev/null
+++ b/plugins/tools/selectiontools/tool_magnetic_selection_cursor.svg
@@ -0,0 +1,79 @@
+
+
+
+