diff --git a/plugins/tools/selectiontools/CMakeLists.txt b/plugins/tools/selectiontools/CMakeLists.txt index c81049076c..9a2601c2b9 100644 --- a/plugins/tools/selectiontools/CMakeLists.txt +++ b/plugins/tools/selectiontools/CMakeLists.txt @@ -1,30 +1,32 @@ 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_tool_select_magnetic.cc kis_selection_modifier_mapper.cc ) qt5_add_resources(kritaselectiontools_SOURCES selectiontools.qrc) add_library(kritaselectiontools MODULE ${kritaselectiontools_SOURCES}) target_link_libraries(kritaselectiontools kritaui kritabasicflakes) 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/kis_tool_select_magnetic.cc b/plugins/tools/selectiontools/kis_tool_select_magnetic.cc new file mode 100644 index 0000000000..6c5910ff45 --- /dev/null +++ b/plugins/tools/selectiontools/kis_tool_select_magnetic.cc @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2007 Sven Langkamp + * + * 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 "kis_tool_select_magnetic.h" + +#include + +#include "kis_cursor.h" +#include "kis_image.h" +#include "kis_painter.h" +#include "kis_selection_options.h" +#include "kis_canvas_resource_provider.h" +#include "kis_canvas2.h" +#include "kis_pixel_selection.h" +#include "kis_selection_tool_helper.h" +#include + + +KisToolSelectMagnetic::KisToolSelectMagnetic(KoCanvasBase * canvas) + : KisToolSelectBase(canvas, + KisCursor::load("tool_polygonal_selection_cursor.png", 6, 6), + i18n("Select path"), + dynamic_cast (new __KisToolSelectMagneticLocalTool(canvas, this))) +{ +} + +void KisToolSelectMagnetic::requestStrokeEnd() +{ + localTool()->endPathWithoutLastPoint(); +} + +void KisToolSelectMagnetic::requestStrokeCancellation() +{ + localTool()->cancelPath(); +} + +void KisToolSelectMagnetic::mousePressEvent(KoPointerEvent* event) +{ + if (!selectionEditable()) return; + DelegatedSelectMagneticTool::mousePressEvent(event); +} + +// Install an event filter to catch right-click events. +// This code is duplicated in kis_tool_path.cc +bool KisToolSelectMagnetic::eventFilter(QObject *obj, QEvent *event) +{ + Q_UNUSED(obj); + if (event->type() == QEvent::MouseButtonPress || + event->type() == QEvent::MouseButtonDblClick) { + QMouseEvent *mouseEvent = static_cast(event); + if (mouseEvent->button() == Qt::RightButton) { + localTool()->removeLastPoint(); + return true; + } + } else if (event->type() == QEvent::TabletPress) { + QTabletEvent *tabletEvent = static_cast(event); + if (tabletEvent->button() == Qt::RightButton) { + localTool()->removeLastPoint(); + return true; + } + } + return false; +} + +QList > KisToolSelectMagnetic::createOptionWidgets() +{ + QList > widgetsList = + DelegatedSelectMagneticTool::createOptionWidgets(); + QList > filteredWidgets; + Q_FOREACH (QWidget* widget, widgetsList) { + if (widget->objectName() != "Stroke widget") { + filteredWidgets.push_back(widget); + } + } + return filteredWidgets; +} + +void KisDelegatedSelectMagneticWrapper::beginPrimaryAction(KoPointerEvent *event) { + mousePressEvent(event); +} + +void KisDelegatedSelectMagneticWrapper::continuePrimaryAction(KoPointerEvent *event){ + mouseMoveEvent(event); +} + +void KisDelegatedSelectMagneticWrapper::endPrimaryAction(KoPointerEvent *event) { + mouseReleaseEvent(event); +} + +bool KisDelegatedSelectMagneticWrapper::hasUserInteractionRunning() const +{ + /** + * KoCreatePathTool doesn't support moving interventions from KisToolselectBase, + * because it doesn't use begin/continue/endPrimaryAction and uses direct event + * handling instead. + * + * TODO: refactor KoCreatePathTool and port it to action infrastructure + */ + return true; +} + + +__KisToolSelectMagneticLocalTool::__KisToolSelectMagneticLocalTool(KoCanvasBase * canvas, KisToolSelectMagnetic* parentTool) + : KoCreatePathTool(canvas), m_selectionTool(parentTool) +{ + setEnableClosePathShortcut(false); +} + +void __KisToolSelectMagneticLocalTool::paintPath(KoPathShape &pathShape, QPainter &painter, const KoViewConverter &converter) +{ + Q_UNUSED(converter); + KisCanvas2 * kisCanvas = dynamic_cast(canvas()); + if (!kisCanvas) + return; + + QTransform matrix; + matrix.scale(kisCanvas->image()->xRes(), kisCanvas->image()->yRes()); + matrix.translate(pathShape.position().x(), pathShape.position().y()); + + qreal zoomX, zoomY; + kisCanvas->viewConverter()->zoom(&zoomX, &zoomY); + Q_ASSERT(qFuzzyCompare(zoomX, zoomY)); + + qreal width = 25*2; + width *= zoomX/(kisCanvas->image()->xRes()); + + paintOutline(&painter, m_selectionTool->pixelToView(matrix.map(pathShape.outline())), width); +} + +void __KisToolSelectMagneticLocalTool::addPathShape(KoPathShape* pathShape) +{ + pathShape->normalize(); + pathShape->close(); + + KisCanvas2 * kisCanvas = dynamic_cast(canvas()); + if (!kisCanvas) + return; + + KisImageWSP image = kisCanvas->image(); + + KisSelectionToolHelper helper(kisCanvas, kundo2_i18n("Select by Bezier Curve")); + + const SelectionMode mode = + helper.tryOverrideSelectionMode(kisCanvas->viewManager()->selection(), + m_selectionTool->selectionMode(), + m_selectionTool->selectionAction()); + + if (mode == PIXEL_SELECTION) { + + KisPixelSelectionSP tmpSel = KisPixelSelectionSP(new KisPixelSelection()); + + KisPainter painter(tmpSel); + painter.setPaintColor(KoColor(Qt::black, tmpSel->colorSpace())); + painter.setFillStyle(KisPainter::FillStyleForegroundColor); + painter.setAntiAliasPolygonFill(m_selectionTool->antiAliasSelection()); + painter.setStrokeStyle(KisPainter::StrokeStyleNone); + + QTransform matrix; + matrix.scale(image->xRes(), image->yRes()); + matrix.translate(pathShape->position().x(), pathShape->position().y()); + + QPainterPath path = matrix.map(pathShape->outline()); + painter.fillPainterPath(path); + tmpSel->setOutlineCache(path); + + helper.selectPixelSelection(tmpSel, m_selectionTool->selectionAction()); + + delete pathShape; + } else { + helper.addSelectionShape(pathShape, m_selectionTool->selectionAction()); + } +} + +void __KisToolSelectMagneticLocalTool::paintOutline(QPainter *painter, const QPainterPath &path, qreal width) +{ + painter->save(); + painter->setOpacity(.3); + painter->setPen(QPen(QColor(128, 128, 128), width)); + painter->drawPath(path); + m_selectionTool->updateCanvasViewRect(path.controlPointRect().adjusted(-width, -width, width, width)); + painter->restore(); +} + +void KisToolSelectMagnetic::resetCursorStyle() +{ + if (selectionAction() == SELECTION_ADD) { + useCursor(KisCursor::load("tool_polygonal_selection_cursor_add.png", 6, 6)); + } else if (selectionAction() == SELECTION_SUBTRACT) { + useCursor(KisCursor::load("tool_polygonal_selection_cursor_sub.png", 6, 6)); + } else { + KisToolSelectBase::resetCursorStyle(); + } +} diff --git a/plugins/tools/selectiontools/kis_tool_select_magnetic.h b/plugins/tools/selectiontools/kis_tool_select_magnetic.h new file mode 100644 index 0000000000..78ecc603c1 --- /dev/null +++ b/plugins/tools/selectiontools/kis_tool_select_magnetic.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2007 Sven Langkamp + * Copyright (c) 2015 Michael Abrahams + * + * 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 +#include "kis_tool_select_base.h" +#include "kis_delegated_tool.h" + +#include + +class KoCanvasBase; +class KisToolSelectMagnetic; + + +class __KisToolSelectMagneticLocalTool : public KoCreatePathTool { +public: + __KisToolSelectMagneticLocalTool(KoCanvasBase * canvas, KisToolSelectMagnetic* parentTool); + void paintPath(KoPathShape &path, QPainter &painter, const KoViewConverter &converter) override; + void addPathShape(KoPathShape* pathShape) override; + + using KoCreatePathTool::createOptionWidgets; + using KoCreatePathTool::endPathWithoutLastPoint; + using KoCreatePathTool::endPath; + using KoCreatePathTool::cancelPath; + using KoCreatePathTool::removeLastPoint; + +protected: + void paintOutline(QPainter *painter, const QPainterPath &path, qreal width); + +private: + KisToolSelectMagnetic* const m_selectionTool; +}; + +typedef KisDelegatedTool DelegatedSelectMagneticTool; + +struct KisDelegatedSelectMagneticWrapper : public DelegatedSelectMagneticTool { + KisDelegatedSelectMagneticWrapper(KoCanvasBase *canvas, + const QCursor &cursor, + KisTool* delegateTool) + : DelegatedSelectMagneticTool(canvas, cursor, dynamic_cast<__KisToolSelectMagneticLocalTool*>(delegateTool)) + { + } + + // If an event is explicitly forwarded only as an action (e.g. shift-click is captured by "change size") + // we will receive a primary action but no mousePressEvent. Thus these events must be explicitly forwarded. + void beginPrimaryAction(KoPointerEvent *event) override; + void continuePrimaryAction(KoPointerEvent *event) override; + void endPrimaryAction(KoPointerEvent *event) override; + + bool hasUserInteractionRunning() const; +}; + + +class KisToolSelectMagnetic : public KisToolSelectBase +{ + Q_OBJECT +public: + KisToolSelectMagnetic(KoCanvasBase * canvas); + void mousePressEvent(KoPointerEvent* event) override; + bool eventFilter(QObject *obj, QEvent *event) override; + void resetCursorStyle() override; + +protected: + void requestStrokeCancellation() override; + void requestStrokeEnd() override; + friend class __KisToolSelectMagneticLocalTool; + QList > createOptionWidgets() override; +}; + +class KisToolSelectMagneticFactory : public KisSelectionToolFactoryBase +{ +public: + KisToolSelectMagneticFactory() + : KisSelectionToolFactoryBase("KisToolSelectMagnetic") { + setToolTip(i18n("Magnetic Selection Tool")); + setSection(TOOL_TYPE_SELECTION); + setActivationShapeId(KRITA_TOOL_ACTIVATION_ID); + setIconName(koIconNameCStr("tool_path_selection")); + setPriority(6); + } + + ~KisToolSelectMagneticFactory() override {} + + KoToolBase * createTool(KoCanvasBase *canvas) override { + return new KisToolSelectMagnetic(canvas); + } + + +}; + + + +#endif // KIS_TOOL_SELECT_MAGNETIC_H_ diff --git a/plugins/tools/selectiontools/selection_tools.cc b/plugins/tools/selectiontools/selection_tools.cc index e0e44fbe60..2411b8f045 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 "kis_tool_select_magnetic.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"