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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Andrei Rudenko + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Andrei Rudenko + + + + + + + + + + + + + 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 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + +