diff --git a/libs/ui/input/kis_tool_invocation_action.cpp b/libs/ui/input/kis_tool_invocation_action.cpp index 6eadd700da..1fbce7c7ea 100644 --- a/libs/ui/input/kis_tool_invocation_action.cpp +++ b/libs/ui/input/kis_tool_invocation_action.cpp @@ -1,200 +1,205 @@ /* This file is part of the KDE project * Copyright (C) 2012 Arjen Hiemstra * * 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_invocation_action.h" #include #include #include #include #include #include #include "kis_tool.h" #include "kis_input_manager.h" #include "kis_image.h" class KisToolInvocationAction::Private { public: Private() : active(false), lineToolActivated(false) { } bool active; bool lineToolActivated; QPointer activatedToolProxy; QPointer runningToolProxy; }; KisToolInvocationAction::KisToolInvocationAction() : KisAbstractInputAction("Tool Invocation") , d(new Private) { setName(i18n("Tool Invocation")); setDescription(i18n("The Tool Invocation action invokes the current tool, for example, using the brush tool, it will start painting.")); QHash indexes; indexes.insert(i18n("Activate"), ActivateShortcut); indexes.insert(i18n("Confirm"), ConfirmShortcut); indexes.insert(i18n("Cancel"), CancelShortcut); indexes.insert(i18n("Activate Line Tool"), LineToolShortcut); setShortcutIndexes(indexes); } KisToolInvocationAction::~KisToolInvocationAction() { delete d; } void KisToolInvocationAction::activate(int shortcut) { Q_UNUSED(shortcut); if (!inputManager()) return; if (shortcut == LineToolShortcut) { KoToolManager::instance()->switchToolTemporaryRequested("KritaShape/KisToolLine"); d->lineToolActivated = true; } d->activatedToolProxy = inputManager()->toolProxy(); d->activatedToolProxy->activateToolAction(KisTool::Primary); } void KisToolInvocationAction::deactivate(int shortcut) { Q_UNUSED(shortcut); if (!inputManager()) return; /** * Activate call might ave come before actual input manager or tool proxy * was attached. So we may end up wil null activatedToolProxy. */ if (d->activatedToolProxy) { d->activatedToolProxy->deactivateToolAction(KisTool::Primary); d->activatedToolProxy.clear(); } if (shortcut == LineToolShortcut && d->lineToolActivated) { d->lineToolActivated = false; KoToolManager::instance()->switchBackRequested(); } } int KisToolInvocationAction::priority() const { return 0; } bool KisToolInvocationAction::canIgnoreModifiers() const { return true; } void KisToolInvocationAction::begin(int shortcut, QEvent *event) { if (shortcut == ActivateShortcut || shortcut == LineToolShortcut) { d->runningToolProxy = inputManager()->toolProxy(); d->active = d->runningToolProxy->forwardEvent( KisToolProxy::BEGIN, KisTool::Primary, event, event); } else if (shortcut == ConfirmShortcut) { QKeyEvent pressEvent(QEvent::KeyPress, Qt::Key_Return, 0); inputManager()->toolProxy()->keyPressEvent(&pressEvent); QKeyEvent releaseEvent(QEvent::KeyRelease, Qt::Key_Return, 0); inputManager()->toolProxy()->keyReleaseEvent(&releaseEvent); /** * All the tools now have a KisTool::requestStrokeEnd() method, * so they should use this instead of direct filtering Enter key * press. Until all the tools support it, we just duplicate the * key event and the method call */ inputManager()->canvas()->image()->requestStrokeEnd(); /** * Some tools would like to distinguish automated requestStrokeEnd() * calls from explicit user actions. Just let them do it! * * Please note that this call should happen **after** * requestStrokeEnd(). Some of the tools will switch to another * tool on this request, and this (next) tool does not expect to * get requestStrokeEnd() right after switching in. */ inputManager()->toolProxy()->explicitUserStrokeEndRequest(); } else if (shortcut == CancelShortcut) { /** * The tools now have a KisTool::requestStrokeCancellation() method, * so just request it. */ inputManager()->canvas()->image()->requestStrokeCancellation(); } } void KisToolInvocationAction::end(QEvent *event) { if (d->active) { // It might happen that the action is still running, while the // canvas has been removed, which kills the toolProxy. KIS_SAFE_ASSERT_RECOVER_NOOP(d->runningToolProxy); if (d->runningToolProxy) { d->runningToolProxy-> forwardEvent(KisToolProxy::END, KisTool::Primary, event, event); d->runningToolProxy.clear(); } d->active = false; } KisAbstractInputAction::end(event); } void KisToolInvocationAction::inputEvent(QEvent* event) { if (!d->active) return; if (!d->runningToolProxy) return; d->runningToolProxy-> forwardEvent(KisToolProxy::CONTINUE, KisTool::Primary, event, event); } void KisToolInvocationAction::processUnhandledEvent(QEvent* event) { bool savedState = d->active; + KisToolProxy *savedToolProxy = d->runningToolProxy; + if (!d->runningToolProxy) { + d->runningToolProxy = inputManager()->toolProxy(); + } d->active = true; inputEvent(event); d->active = savedState; + d->runningToolProxy = savedToolProxy; } bool KisToolInvocationAction::supportsHiResInputEvents() const { return inputManager()->toolProxy()->primaryActionSupportsHiResEvents(); } bool KisToolInvocationAction::isShortcutRequired(int shortcut) const { //These really all are pretty important for basic user interaction. Q_UNUSED(shortcut) return true; } diff --git a/plugins/tools/selectiontools/kis_tool_select_outline.cc b/plugins/tools/selectiontools/kis_tool_select_outline.cc index 667b425177..87763bd16c 100644 --- a/plugins/tools/selectiontools/kis_tool_select_outline.cc +++ b/plugins/tools/selectiontools/kis_tool_select_outline.cc @@ -1,278 +1,280 @@ /* * kis_tool_select_freehand.h - part of Krayon^WKrita * * Copyright (c) 2000 John Califf * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Boudewijn Rempt * 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. */ #include "kis_tool_select_outline.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 KisToolSelectOutline::KisToolSelectOutline(KoCanvasBase * canvas) : KisToolSelect(canvas, KisCursor::load("tool_outline_selection_cursor.png", 5, 5), i18n("Outline Selection")), m_continuedMode(false) { } KisToolSelectOutline::~KisToolSelectOutline() { } void KisToolSelectOutline::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Control) { m_continuedMode = true; } KisToolSelect::keyPressEvent(event); } void KisToolSelectOutline::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 KisToolSelectOutline::mouseMoveEvent(KoPointerEvent *event) { if (selectionDragInProgress()) return; m_lastCursorPos = convertToPixelCoord(event); if (m_continuedMode && mode() != PAINT_MODE) { updateContinuedMode(); } + + KisToolSelect::mouseMoveEvent(event); } void KisToolSelectOutline::beginPrimaryAction(KoPointerEvent *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 KisToolSelectOutline::continuePrimaryAction(KoPointerEvent *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 KisToolSelectOutline::endPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); const bool hadMoveInProgress = selectionDragInProgress(); if (hadMoveInProgress) return; CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); setMode(KisTool::HOVER_MODE); if (!m_continuedMode) { finishSelectionAction(); m_points.clear(); // ensure points are always cleared } } void KisToolSelectOutline::finishSelectionAction() { KisCanvas2 * kisCanvas = dynamic_cast(canvas()); KIS_ASSERT_RECOVER_RETURN(kisCanvas); kisCanvas->updateCanvas(); const QRectF boundingRect = KisAlgebra2D::accumulateBounds(m_points); const QRectF boundingViewRect = pixelToView(boundingRect); KisSelectionToolHelper helper(kisCanvas, kundo2_i18n("Select by Outline")); if (helper.tryDeselectCurrentSelection(boundingViewRect, selectionAction())) { return; } if (m_points.count() > 2) { 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 KisToolSelectOutline::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 KisToolSelectOutline::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 KisToolSelectOutline::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 KisToolSelectOutline::deactivate() { KisCanvas2 * kisCanvas = dynamic_cast(canvas()); KIS_ASSERT_RECOVER_RETURN(kisCanvas); kisCanvas->updateCanvas(); m_continuedMode = false; KisTool::deactivate(); } void KisToolSelectOutline::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(); } }