From b5a324e639d6559118fabd4beab623a2a078c8ba Mon Sep 17 00:00:00 2001
From: Dmitry Kazakov <dima@laptop.(none)>
Date: Sat, 18 Sep 2010 22:45:38 +0400
Subject: [PATCH] Refactored KisToolFreehand to move gestures and panning to KisTool

---
 krita/ui/canvas/kis_canvas2.cpp    |    9 +-
 krita/ui/canvas/kis_canvas2.h      |    2 +-
 krita/ui/kis_config.cc             |    9 +
 krita/ui/kis_config.h              |    3 +
 krita/ui/tool/kis_tool.cc          |  182 +++++++++++++++-
 krita/ui/tool/kis_tool.h           |   37 +++-
 krita/ui/tool/kis_tool_freehand.cc |  416 ++++++++++++------------------------
 krita/ui/tool/kis_tool_freehand.h  |   51 ++---
 krita/ui/tool/kis_tool_paint.cc    |   87 +++++++--
 krita/ui/tool/kis_tool_paint.h     |   22 ++-
 10 files changed, 465 insertions(+), 353 deletions(-)

diff --git a/krita/ui/canvas/kis_canvas2.cpp b/krita/ui/canvas/kis_canvas2.cpp
index a9522c4..24afa03 100644
--- a/krita/ui/canvas/kis_canvas2.cpp
+++ b/krita/ui/canvas/kis_canvas2.cpp
@@ -674,14 +674,11 @@ KoFavoriteResourceManager* KisCanvas2::favoriteResourceManager()
 }
 
 
-bool KisCanvas2::handlePopupPaletteIsVisible(KoPointerEvent* e)
+bool KisCanvas2::handlePopupPaletteIsVisible()
 {
-    e->accept();
-
-    //TODO: port favoriteResourceManager to KisCanvas2, then enable this function.
-    if (e->button() && (Qt::LeftButton || Qt::MidButton || Qt::RightButton)
-        && favoriteResourceManager()
+    if (favoriteResourceManager()
         && favoriteResourceManager()->isPopupPaletteVisible()) {
+
         favoriteResourceManager()->slotShowPopupPalette();
         return true;
     }
diff --git a/krita/ui/canvas/kis_canvas2.h b/krita/ui/canvas/kis_canvas2.h
index 077a45f..6b94091 100644
--- a/krita/ui/canvas/kis_canvas2.h
+++ b/krita/ui/canvas/kis_canvas2.h
@@ -212,7 +212,7 @@ public:
 
     void createFavoriteResourceManager(KisPaintopBox*);
     KoFavoriteResourceManager* favoriteResourceManager();
-    bool handlePopupPaletteIsVisible(KoPointerEvent *);
+    bool handlePopupPaletteIsVisible();
 
 private:
     Q_DISABLE_COPY(KisCanvas2);
diff --git a/krita/ui/kis_config.cc b/krita/ui/kis_config.cc
index 3ad9911..9de7463 100644
--- a/krita/ui/kis_config.cc
+++ b/krita/ui/kis_config.cc
@@ -754,3 +754,12 @@ void KisConfig::setPresetChooserViewMode(const int mode)
     m_cfg.writeEntry("presetChooserViewMode", mode);
 }
 
+bool KisConfig::clicklessSpacePan() const
+{
+    return m_cfg.readEntry("clicklessSpacePan", true);
+}
+
+void KisConfig::setClicklessSpacePan(const bool toggle) const
+{
+    m_cfg.writeEntry("clicklessSpacePan", toggle);
+}
diff --git a/krita/ui/kis_config.h b/krita/ui/kis_config.h
index dd9a88e..74d6673 100644
--- a/krita/ui/kis_config.h
+++ b/krita/ui/kis_config.h
@@ -266,6 +266,9 @@ public:
     int presetChooserViewMode() const;
     void setPresetChooserViewMode(const int mode);
 
+    bool clicklessSpacePan() const;
+    void setClicklessSpacePan(const bool toggle) const;
+
 private:
     KisConfig(const KisConfig&);
     KisConfig& operator=(const KisConfig&);
diff --git a/krita/ui/tool/kis_tool.cc b/krita/ui/tool/kis_tool.cc
index 6d47685..b85c0aa 100644
--- a/krita/ui/tool/kis_tool.cc
+++ b/krita/ui/tool/kis_tool.cc
@@ -71,11 +71,13 @@
 #include <recorder/kis_recorded_paint_action.h>
 
 struct KisTool::Private {
-    Private() : currentPattern(0),
-            currentGradient(0),
-            currentPaintOpPreset(0),
-            currentGenerator(0),
-            optionWidget(0) { }
+    Private()
+        : currentPattern(0),
+          currentGradient(0),
+          currentPaintOpPreset(0),
+          currentGenerator(0),
+          optionWidget(0),
+          spacePressed(0) { }
     QCursor cursor; // the cursor that should be shown on tool activation.
 
     // From the canvas resources
@@ -93,6 +95,10 @@ struct KisTool::Private {
     KAction* toggleFgBg;
     KAction* resetFgBg;
 
+    bool spacePressed;
+    QPointF lastDocumentPoint;
+    QPointF initialGestureDocPoint;
+    QPoint initialGestureGlobalPoint;
 };
 
 KisTool::KisTool(KoCanvasBase * canvas, const QCursor & cursor)
@@ -114,6 +120,7 @@ KisTool::KisTool(KoCanvasBase * canvas, const QCursor & cursor)
     connect(d->resetFgBg, SIGNAL(triggered()), this, SLOT(slotResetFgBg()));
     addAction("reset_fg_bg", d->resetFgBg);
 
+    setMode(HOVER_MODE);
 }
 
 KisTool::~KisTool()
@@ -373,21 +380,182 @@ KisFilterConfiguration * KisTool::currentGenerator()
     return d->currentGenerator;
 }
 
+bool KisTool::specialModifierActive()
+{
+    KisCanvas2 *canvas2 = dynamic_cast<KisCanvas2 *>(canvas());
+    bool popupPalletActive = canvas2->handlePopupPaletteIsVisible();
+
+    KisConfig cfg;
+    return popupPalletActive || (d->spacePressed && !cfg.clicklessSpacePan());
+}
+
+void KisTool::setMode(ToolMode mode) {
+    m_mode = mode;
+}
+
+KisTool::ToolMode KisTool::mode() {
+    return m_mode;
+}
+
 void KisTool::mousePressEvent(KoPointerEvent *event)
 {
-    event->ignore();
+    KisConfig cfg;
+
+    if (mode() == KisTool::HOVER_MODE &&
+        ((event->button() == Qt::MidButton &&
+          event->modifiers() == Qt::NoModifier) ||
+         (d->spacePressed && !cfg.clicklessSpacePan()))) {
+
+        initPan(event->point);
+        event->accept();
+    }
+    else if (mode() == KisTool::HOVER_MODE &&
+             (event->button() == Qt::LeftButton &&
+              event->modifiers() == Qt::ShiftModifier)) {
+
+        initGesture(event->point);
+        event->accept();
+    }
+
+
+    d->lastDocumentPoint = event->point;
 }
 
 void KisTool::mouseMoveEvent(KoPointerEvent *event)
 {
-    event->ignore();
+    if(mode() == PAN_MODE) {
+        pan(event->point);
+        event->accept();
+    }
+    else if (mode() == GESTURE_MODE) {
+        processGesture(event->point);
+        event->accept();
+    }
+
+    d->lastDocumentPoint = event->point;
 }
 
 void KisTool::mouseReleaseEvent(KoPointerEvent *event)
 {
+    KisConfig cfg;
+
+    if(mode() == PAN_MODE) {
+        if (event->button() == Qt::MidButton ||
+            (event->button() == Qt::LeftButton && !cfg.clicklessSpacePan())) {
+
+            endPan();
+            event->accept();
+        }
+    }
+    else if (mode() == GESTURE_MODE) {
+        if (event->button() == Qt::LeftButton) {
+            endGesture();
+            event->accept();
+        }
+    }
+
+    d->lastDocumentPoint = event->point;
+}
+
+void KisTool::keyPressEvent(QKeyEvent *event)
+{
+    if (event->key() == Qt::Key_Space) {
+
+        KisConfig cfg;
+        if(cfg.clicklessSpacePan()) {
+            initPan(d->lastDocumentPoint);
+        }
+        else {
+            d->spacePressed = true;
+        }
+
+        event->accept();
+        return;
+    }
+
+    event->ignore();
+}
+
+void KisTool::keyReleaseEvent(QKeyEvent* event)
+{
+    if (event->key() == Qt::Key_Space) {
+
+        KisConfig cfg;
+        if(cfg.clicklessSpacePan()) {
+            endPan();
+        }
+        else {
+            d->spacePressed = false;
+        }
+
+        event->accept();
+        return;
+    }
+
     event->ignore();
 }
 
+void KisTool::initPan(const QPointF &docPoint)
+{
+    setMode(PAN_MODE);
+    m_lastPosition = convertDocumentToWidget(docPoint);
+    useCursor(QCursor(Qt::ClosedHandCursor));
+}
+
+void KisTool::pan(const QPointF &docPoint)
+{
+    Q_ASSERT(canvas());
+    Q_ASSERT(canvas()->canvasController());
+
+    QPointF actualPosition = convertDocumentToWidget(docPoint);
+    QPointF distance(m_lastPosition - actualPosition);
+    canvas()->canvasController()->pan(distance.toPoint());
+
+    m_lastPosition = actualPosition;
+}
+
+void KisTool::endPan()
+{
+    setMode(HOVER_MODE);
+    resetCursorStyle();
+}
+
+void KisTool::initGesture(const QPointF &docPoint)
+{
+    setMode(GESTURE_MODE);
+    d->initialGestureDocPoint = docPoint;
+    d->initialGestureGlobalPoint = QCursor::pos();
+    useCursor(KisCursor::blankCursor());
+}
+
+void KisTool::processGesture(const QPointF &docPoint)
+{
+    QPointF lastWidgetPosition = convertDocumentToWidget(d->lastDocumentPoint);
+    QPointF actualWidgetPosition = convertDocumentToWidget(docPoint);
+
+    QPointF offset = actualWidgetPosition - lastWidgetPosition;
+
+    /**
+     * view pixels != widget pixels, but we do this anyway, we only
+     * need to scale the gesture down, not rotate or anything
+     */
+    QPointF scaledOffset = canvas()->viewConverter()->viewToDocument(offset);
+    gesture(scaledOffset, d->initialGestureDocPoint);
+}
+
+void KisTool::endGesture()
+{
+    gesture(QPointF(), d->initialGestureDocPoint);
+    setMode(HOVER_MODE);
+    resetCursorStyle();
+    QCursor::setPos(d->initialGestureGlobalPoint);
+}
+
+void KisTool::gesture(const QPointF &offsetInDocPixels, const QPointF &initialDocPoint)
+{
+    Q_UNUSED(offsetInDocPixels);
+}
+
 void KisTool::setupPainter(KisPainter* painter)
 {
     Q_ASSERT(currentImage());
diff --git a/krita/ui/tool/kis_tool.h b/krita/ui/tool/kis_tool.h
index 78d6bd7..08680a6 100644
--- a/krita/ui/tool/kis_tool.h
+++ b/krita/ui/tool/kis_tool.h
@@ -76,15 +76,13 @@ public slots:
 
 public:
 
-    /// reimplemented from superclass
     virtual void mousePressEvent(KoPointerEvent *event);
-
-    /// reimplemented from superclass
     virtual void mouseMoveEvent(KoPointerEvent *event);
-
-    /// reimplemented from superclass
     virtual void mouseReleaseEvent(KoPointerEvent *event);
 
+    virtual void keyPressEvent(QKeyEvent *event);
+    virtual void keyReleaseEvent(QKeyEvent* event);
+
     /// reimplemented from superclass
     virtual void mouseDoubleClickEvent(KoPointerEvent *) {}  // when a krita tool is enabled, don't push double click on
 
@@ -135,6 +133,10 @@ public:
 
 protected:
 
+    bool specialModifierActive();
+    virtual void gesture(const QPointF &offsetInDocPixels,
+                         const QPointF &initialDocPoint);
+
     KisImageWSP image() const;
     QCursor cursor() const;
 
@@ -173,6 +175,20 @@ protected:
     /// This is a convenience method that calls endOpenGL() on the OpenGL canvas object.
     void endOpenGL();
 
+protected:
+    enum ToolMode {
+        HOVER_MODE,
+        PAINT_MODE,
+        SECONDARY_PAINT_MODE,
+        GESTURE_MODE,
+        PAN_MODE,
+        OTHER // not used now
+    };
+
+    void setMode(ToolMode mode);
+    ToolMode mode();
+
+
 protected slots:
     /**
      * Called whenever the configuration settings change.
@@ -185,7 +201,18 @@ private slots:
     void slotResetFgBg();
 
 private:
+    void initPan(const QPointF &docPoint);
+    void pan(const QPointF &docPoint);
+    void endPan();
+
+    void initGesture(const QPointF &docPoint);
+    void processGesture(const QPointF &docPoint);
+    void endGesture();
+
+private:
     PaintMode m_outlinePaintMode;
+    ToolMode m_mode;
+    QPointF m_lastPosition;
 
     struct Private;
     Private* const d;
diff --git a/krita/ui/tool/kis_tool_freehand.cc b/krita/ui/tool/kis_tool_freehand.cc
index f5e383e..92f04df 100644
--- a/krita/ui/tool/kis_tool_freehand.cc
+++ b/krita/ui/tool/kis_tool_freehand.cc
@@ -78,10 +78,11 @@ static const int HIDE_OUTLINE_TIMEOUT = 800; // ms
 
 KisToolFreehand::KisToolFreehand(KoCanvasBase * canvas, const QCursor & cursor, const QString & transactionText)
     : KisToolPaint(canvas, cursor)
-    , m_dragDist(0)
     , m_transactionText(transactionText)
-    , m_mode(HOVER)
 {
+    m_explicitShowOutline = false;
+
+
     m_painter = 0;
     m_paintIncremental = false;
     m_executor = new QThreadPool(this);
@@ -115,9 +116,8 @@ KisToolFreehand::KisToolFreehand(KoCanvasBase * canvas, const QCursor & cursor,
     connect(this, SIGNAL(sigFavoritePaletteCalled(const QPoint&)), canvas2, SIGNAL(favoritePaletteCalled(const QPoint&)));
     connect(this, SIGNAL(sigPainting()), canvas2->view()->resourceProvider(), SLOT(slotPainting()));
 
-    m_showOutline = false;
-    m_timer.setSingleShot(true);
-    connect(&m_timer, SIGNAL(timeout()), this, SLOT( hideOutline() ));
+    m_outlineTimer.setSingleShot(true);
+    connect(&m_outlineTimer, SIGNAL(timeout()), this, SLOT(hideOutline()));
 
 }
 
@@ -134,72 +134,39 @@ void KisToolFreehand::deactivate()
 
 void KisToolFreehand::mousePressEvent(KoPointerEvent *e)
 {
-    if (currentPaintOpPreset() && currentPaintOpPreset()->settings()) {
-        m_paintIncremental = currentPaintOpPreset()->settings()->paintIncremental();
+    if(mode() == KisTool::PAINT_MODE)
+        return;
+
+    if(mode() == KisTool::HOVER_MODE &&
+       e->button() == Qt::LeftButton &&
+       e->modifiers() == Qt::NoModifier &&
+       !specialModifierActive()) {
+
         currentPaintOpPreset()->settings()->mousePressEvent(e);
         if (e->isAccepted()) {
             return;
         }
-    }
 
-    KisCanvas2 *canvas2 = dynamic_cast<KisCanvas2 *>(canvas());
-    if (canvas2->handlePopupPaletteIsVisible(e)) return;
-
-    m_strokeTimeMeasure.start();
-
-    //    dbgUI << "mousePressEvent" << m_mode;
-    //     if (!currentImage())
-    //    return;
-    if (m_mode == PAN) {
-        e->accept();
-        return;
-    }
-    if (e->button() == Qt::MidButton) {
-        initPan();
-        e->accept();
-        return;
-    }
+        setMode(KisTool::PAINT_MODE);
 
-    if (!currentNode())
-        return;
+        initPaint(e);
+        m_previousPaintInformation = KisPaintInformation(convertToPixelCoord(adjustPosition(e->point)),
+                                                         pressureToCurve(e->pressure()), e->xTilt(), e->yTilt(),
+                                                         KisVector2D::Zero(),
+                                                         e->rotation(), e->tangentialPressure(), m_strokeTimeMeasure.elapsed());
 
-    if (!currentNode()->paintDevice())
-        return;
+        m_outlineDocPoint = e->point;
 
-    // control-click gets the color at the current point. For now, only with a ratio of 1
-    // get the current color of the project, as per Deevad's suggestion.
-    // this shouldn't be changed back to the current node :-)
-    // CTRL+ALT picks color from current layer
-    // CTRL picks color from projection
-    if (e->modifiers() & Qt::ControlModifier) {
-
-        m_toForegroundColor = (e->button() == Qt::LeftButton);
-        pickColor(convertToIntPixelCoord(e),e->modifiers() & Qt::AltModifier);
-        m_mode = COLOR_PICKING;
-        useCursor(KisCursor::pickerCursor());
-        e->accept();
+        KisConfig cfg;
+        if(cfg.cursorStyle() == CURSOR_STYLE_OUTLINE) {
+            updateOutlineRect();
+        }
 
-   } else if (e->modifiers() == Qt::ShiftModifier) {
-        m_mode = EDIT_BRUSH;
-        m_prevMousePos = e->point;
-        m_originalPos = e->globalPos();
-        m_originalMousePos = e->point;
         e->accept();
-        return;
-    } else { // No modifiers
-
-        if (e->button() == Qt::LeftButton) {
-            initPaint(e);
-            m_previousPaintInformation = KisPaintInformation(convertToPixelCoord(adjustPosition(e->point)),
-                                                             pressureToCurve(e->pressure()), e->xTilt(), e->yTilt(),
-                                                             KisVector2D::Zero(),
-                                                             e->rotation(), e->tangentialPressure(), m_strokeTimeMeasure.elapsed());
-        } else if (m_mode == PAINT && (e->button() == Qt::RightButton || e->button() == Qt::MidButton)) {
-            // end painting, if calling the menu or the pop up palette. otherwise there is weird behaviour
-            endPaint();
-        }
     }
-    e->accept();
+    else {
+        KisToolPaint::mousePressEvent(e);
+    }
 }
 
 inline double norm(const QPointF& p)
@@ -214,172 +181,107 @@ inline double angle(const QPointF& p1, const QPointF& p2)
 
 void KisToolFreehand::mouseMoveEvent(KoPointerEvent *e)
 {
-    //    dbgUI << "mouseMoveEvent " << m_mode << " " << e->button() << " " << e->buttons();
-    switch (m_mode) {
-    case PAINT: {
-            QPointF pos = convertToPixelCoord(adjustPosition(e->point));
-            QPointF dragVec = pos - m_previousPaintInformation.pos();
-
-            KisPaintInformation info = KisPaintInformation(pos,
-                                                           pressureToCurve(e->pressure()), e->xTilt(), e->yTilt(),
-                                                           toKisVector2D(dragVec),
-                                                           e->rotation(), e->tangentialPressure(), m_strokeTimeMeasure.elapsed());
-
-            if (m_smooth) {
-                QPointF newTangent = dragVec;
-
-                if (norm(newTangent) != 0) {
-                    newTangent /= norm(newTangent) ;
-                }
-                double normVec = 0.5 * m_smoothness * norm(dragVec);
-                QPointF control1 = m_previousPaintInformation.pos() + m_previousTangent * normVec;
-                QPointF control2 = info.pos() - newTangent * normVec;
-                paintBezierCurve(m_previousPaintInformation,
-                                 control1,
-                                 control2,
-                                 info);
-                m_previousTangent = newTangent;
-                m_previousDrag = dragVec;
-            } else {
-                paintLine(m_previousPaintInformation, info);
-            }
+    if(mode() == KisTool::HOVER_MODE ||
+       mode() == KisTool::PAINT_MODE) {
+        m_outlineDocPoint = e->point;
 
-            m_previousPaintInformation = info;
+        KisConfig cfg;
+        if(cfg.cursorStyle() == CURSOR_STYLE_OUTLINE) {
+            updateOutlineRect();
         }
-        break;
-    case EDIT_BRUSH: {
-            useCursor(KisCursor::blankCursor());
-            qreal dx = m_prevMousePos.x() - e->point.x();
-            qreal dy = m_prevMousePos.y() - e->point.y();
-            currentPaintOpPreset()->settings()->changePaintOpSize(-dx, -dy);
-            m_prevMousePos = e->point;
-        }
-        break;
-    case PAN: {
-            pan(e);
-        }
-        break;
-    case COLOR_PICKING:{
-            useCursor(KisCursor::pickerCursor());
-            if (e->modifiers() & Qt::ControlModifier) {
-                pickColor(convertToIntPixelCoord(e), e->modifiers() & Qt::AltModifier);
-            }else {
-                // DO Nothing
-            }
 
+#if defined(HAVE_OPENGL)
+        else if (cfg.cursorStyle() == CURSOR_STYLE_3D_MODEL) {
+            if (isCanvasOpenGL()) {
+                m_xTilt = e->xTilt();
+                m_yTilt = e->yTilt();
+                // TODO : optimize? but you need to know the size of the 3d brush?
+                canvas()->updateCanvas(QRect(QPoint(0, 0), QSize(currentImage()->width(), currentImage()->height())));
+            }
         }
-        break;
-    default:
-        ;
-    }
-
-    KisConfig cfg;
-    KisPaintOpSettings::OutlineMode outlineMode;
-    if ((m_mode != PAINT  || cfg.showOutlineWhilePainting()) &&
-        (cfg.cursorStyle() == CURSOR_STYLE_OUTLINE || m_mode == EDIT_BRUSH || m_showOutline)) {
-        outlineMode = KisPaintOpSettings::CursorIsOutline;
-    } else {
-        outlineMode = KisPaintOpSettings::CursorIsNotOutline;
+#endif
     }
 
-    if (!m_oldOutlineRect.isEmpty()) {
-        canvas()->updateCanvas(m_oldOutlineRect.adjusted(-2,-2,2,2)); // erase the old guy
+    if(mode() != KisTool::PAINT_MODE) {
+        KisToolPaint::mouseMoveEvent(e);
+        return;
     }
 
-    m_mousePos = e->point;
+    QPointF pos = convertToPixelCoord(adjustPosition(e->point));
+    QPointF dragVec = pos - m_previousPaintInformation.pos();
 
-#if defined(HAVE_OPENGL)
-    if (cfg.cursorStyle() == CURSOR_STYLE_3D_MODEL) {
-        if (isCanvasOpenGL()) {
-            m_xTilt = e->xTilt();
-            m_yTilt = e->yTilt();
-            // TODO : optimize? but you need to know the size of the 3d brush?
-            canvas()->updateCanvas(QRect(QPoint(0, 0), QSize(currentImage()->width(), currentImage()->height())));
-        }
-    }
-#endif
+    KisPaintInformation info =
+        KisPaintInformation(pos, pressureToCurve(e->pressure()),
+                            e->xTilt(), e->yTilt(), toKisVector2D(dragVec),
+                            e->rotation(), e->tangentialPressure(),
+                            m_strokeTimeMeasure.elapsed());
 
+    if (m_smooth) {
+        QPointF newTangent = dragVec;
 
-    QPainterPath path;
-    if (m_painter && m_painter->paintOp()){
-        path = currentPaintOpPreset()->settings()->brushOutline(currentImage()->documentToPixel(outlinePos()), 
-                                                                         outlineMode,
-                                                                         m_painter->paintOp()->currentScale(),
-                                                                         m_painter->paintOp()->currentRotation());
-    }else{
-        path = currentPaintOpPreset()->settings()->brushOutline(currentImage()->documentToPixel(outlinePos()),outlineMode);
-    }
-    m_oldOutlineRect = currentImage()->pixelToDocument(path.boundingRect());
-    if (!m_oldOutlineRect.isEmpty()) {
-        canvas()->updateCanvas(m_oldOutlineRect.adjusted(-2,-2,2,2));
+        if (norm(newTangent) != 0) {
+            newTangent /= norm(newTangent) ;
+        }
+        double normVec = 0.5 * m_smoothness * norm(dragVec);
+        QPointF control1 = m_previousPaintInformation.pos() + m_previousTangent * normVec;
+        QPointF control2 = info.pos() - newTangent * normVec;
+        paintBezierCurve(m_previousPaintInformation,
+                         control1,
+                         control2,
+                         info);
+        m_previousTangent = newTangent;
+    } else {
+        paintLine(m_previousPaintInformation, info);
     }
 
+    m_previousPaintInformation = info;
 }
 
 void KisToolFreehand::mouseReleaseEvent(KoPointerEvent* e)
 {
-    KisCanvas2 *canvas2 = dynamic_cast<KisCanvas2 *>(canvas());
-    if (canvas2->handlePopupPaletteIsVisible(e)) {
+    if(mode() != KisTool::PAINT_MODE) {
+        KisToolPaint::mouseReleaseEvent(e);
         return;
     }
-    else if (e->button() == Qt::LeftButton) {
-        //TODO: There is a bug here. If pop up palette is visible and a new colour is selected,
-        //the new colour will be added when the user clicks on the canvas to hide the palette
-        //This is used to handle recently used colour (KoFavoriteResourceManager)
-        emit sigPainting();
-    }
 
-    switch (m_mode) {
-    case PAINT:
-        if (!m_hasPaintAtLeastOnce)
-        {
-            paintAt(m_previousPaintInformation);
-        }
-        endPaint();
-        break;
-    case PAN:
-        if (e->button() == Qt::MidButton) {
-            endPan();
-            e->accept();
-        }
-        return;
-    case EDIT_BRUSH:
-        QCursor::setPos(m_originalPos);
-        break;
-    default:
-        ;
-    };
-
-    if (m_mode != COLOR_PICKING){
-        KisToolPaint::mouseReleaseEvent(e);
+    if (!m_hasPaintAtLeastOnce) {
+        paintAt(m_previousPaintInformation);
+
+        // Let's add history information about recently used colors
+        emit sigPainting();
     }
 
-    m_mode = HOVER;
-    resetCursorStyle();
+    setMode(KisTool::HOVER_MODE);
+    endPaint();
 }
 
 void KisToolFreehand::keyPressEvent(QKeyEvent *event)
 {
-    if (m_mode != HOVER) {
-        event->accept(); // Make sure nothing disturb the painting
-    }
-    else if (event->key() == Qt::Key_Space) {
-        initPan();
-        event->accept();
-    }/* else if (event->key() == Qt::Key_Control){ // we need to reset the cursor back when the user does not hold any key so commented so far
-        useCursor(KisCursor::pickerCursor());
-    }*/else {
-        event->ignore();
+    if(mode() != KisTool::PAINT_MODE) {
+        KisToolPaint::keyPressEvent(event);
+        return;
     }
+
+    event->ignore();
 }
 
 void KisToolFreehand::keyReleaseEvent(QKeyEvent* event)
 {
-    if (m_mode == PAN && event->key() == Qt::Key_Space) {
-        endPan();
-        event->accept();
+    if(mode() != KisTool::PAINT_MODE) {
+        KisToolPaint::keyReleaseEvent(event);
+        return;
     }
-    KoToolBase::keyReleaseEvent(event);
+
+    event->ignore();
+}
+
+void KisToolFreehand::gesture(const QPointF &offsetInDocPixels, const QPointF &initialDocPoint)
+{
+    currentPaintOpPreset()->settings()->changePaintOpSize(offsetInDocPixels.x(), offsetInDocPixels.y());
+
+    m_outlineDocPoint = initialDocPoint;
+
+    updateOutlineRect();
 }
 
 void KisToolFreehand::initPaint(KoPointerEvent *)
@@ -388,13 +290,10 @@ void KisToolFreehand::initPaint(KoPointerEvent *)
     if(canvas2)
         canvas2->view()->disableControls();
 
-    //    dbgUI << "initPaint";
     if (!currentNode() || !currentNode()->paintDevice())
         return;
 
-    m_mode = PAINT;
     m_hasPaintAtLeastOnce = false;
-    m_dragDist = 0;
 
     KisPaintDeviceSP paintDevice = currentNode()->paintDevice();
     KisPaintDeviceSP targetDevice;
@@ -402,6 +301,8 @@ void KisToolFreehand::initPaint(KoPointerEvent *)
     if (!m_compositeOp)
         m_compositeOp = paintDevice->colorSpace()->compositeOp(COMPOSITE_OVER);
 
+    m_strokeTimeMeasure.start();
+    m_paintIncremental = currentPaintOpPreset()->settings()->paintIncremental();
 
     if (!m_paintIncremental) {
         KisIndirectPaintingSupport* indirect =
@@ -439,7 +340,6 @@ void KisToolFreehand::initPaint(KoPointerEvent *)
     }
 
     m_previousTangent = QPointF(0, 0);
-    m_previousDrag = QPointF(0, 0);
 
 
 #ifdef ENABLE_RECORDING // Temporary, to figure out what is going without being
@@ -455,13 +355,11 @@ void KisToolFreehand::initPaint(KoPointerEvent *)
 
 void KisToolFreehand::endPaint()
 {
-    //    dbgUI << "endPaint";
-
     KisCanvas2 *canvas2 = dynamic_cast<KisCanvas2 *>(canvas());
-    if(canvas2)
+    if(canvas2) {
         canvas2->view()->enableControls();
+    }
 
-    m_mode = HOVER;
     if (m_painter) {
 
         m_executor->waitForDone();
@@ -545,7 +443,7 @@ bool KisToolFreehand::wantsAutoScroll() const
 
 void KisToolFreehand::setDirty(const QRegion& region)
 {
-    if (region.numRects() < 1)
+    if (region.isEmpty())
         return;
 
     currentNode()->setDirty(region);
@@ -565,7 +463,6 @@ void KisToolFreehand::setAssistant(bool assistant)
     m_assistant = assistant;
 }
 
-#define ZET 7
 void KisToolFreehand::paint(QPainter& gc, const KoViewConverter &converter)
 {
     KisConfig cfg;
@@ -587,7 +484,7 @@ void KisToolFreehand::paint(QPainter& gc, const KoViewConverter &converter)
             }
 
             if (glIsList(m_displayList)) {
-                QPointF pos = converter.documentToView(m_mousePos);
+                QPointF pos = converter.documentToView(m_outlineDocPoint);
 
                 glColor3f(0.0, 1.0, 0.0);
                 glShadeModel(GL_SMOOTH);
@@ -642,32 +539,17 @@ void KisToolFreehand::paint(QPainter& gc, const KoViewConverter &converter)
 
     {
         KisPaintOpSettings::OutlineMode outlineMode;
-        if (m_mode == PAINT) {
-            m_showOutline = false;
-        }
-
-        if ((m_mode != PAINT || cfg.showOutlineWhilePainting()) &&
-            (cfg.cursorStyle() == CURSOR_STYLE_OUTLINE || m_mode == EDIT_BRUSH || m_showOutline)) {
-            outlineMode = KisPaintOpSettings::CursorIsOutline;
-        } else {
-            outlineMode = KisPaintOpSettings::CursorIsNotOutline;
-        }
-
-        qreal zoomX, zoomY;
-        converter.zoom(&zoomX, &zoomY);
+        outlineMode = KisPaintOpSettings::CursorIsNotOutline;
 
+        if(m_explicitShowOutline ||
+           mode() == KisTool::GESTURE_MODE ||
+           (cfg.cursorStyle() == CURSOR_STYLE_OUTLINE &&
+            (mode() != PAINT_MODE || cfg.showOutlineWhilePainting()))) {
 
-        QPainterPath path;
-        if (m_painter && m_painter->paintOp()){
-            path = currentPaintOpPreset()->settings()->brushOutline(currentImage()->documentToPixel(outlinePos()), 
-                                                                                outlineMode,
-                                                                                m_painter->paintOp()->currentScale(),
-                                                                                m_painter->paintOp()->currentRotation());
-        }else{
-            path = currentPaintOpPreset()->settings()->brushOutline(currentImage()->documentToPixel(outlinePos()),outlineMode);
+            outlineMode = KisPaintOpSettings::CursorIsOutline;
         }
-        m_oldOutlineRect = currentImage()->pixelToDocument(path.boundingRect());
 
+        QPainterPath path = getOutlinePath(m_outlineDocPoint, outlineMode);
         paintToolOutline(&gc,pixelToView(path));
     }
 }
@@ -681,46 +563,26 @@ QPointF KisToolFreehand::adjustPosition(const QPointF& point)
     return point;
 }
 
-void KisToolFreehand::initPan()
+QPainterPath KisToolFreehand::getOutlinePath(const QPointF &documentPos,
+                                             KisPaintOpSettings::OutlineMode outlineMode)
 {
-    m_mode = PAN;
-    m_lastPosition = convertDocumentToWidget(m_mousePos);
-    useCursor(QCursor(Qt::ClosedHandCursor));
-}
-
-void KisToolFreehand::pan(KoPointerEvent *event)
-{
-    Q_ASSERT(canvas());
-    Q_ASSERT(canvas()->canvasController());
-
-    event->accept();
-
-    QPointF actualPosition = convertDocumentToWidget(event->point);
-    QPointF distance(m_lastPosition - actualPosition);
-    canvas()->canvasController()->pan(distance.toPoint());
-
-    m_lastPosition = actualPosition;
-}
+    qreal scale = 1.0;
+    qreal rotation = 0;
+    if (m_painter && m_painter->paintOp()){
+        scale = m_painter->paintOp()->currentScale();
+        rotation = m_painter->paintOp()->currentRotation();
+    }
 
-void KisToolFreehand::endPan()
-{
-    m_mode = HOVER;
-    resetCursorStyle();
-}
+    QPointF imagePos = currentImage()->documentToPixel(documentPos);
+    QPainterPath path = currentPaintOpPreset()->settings()->
+        brushOutline(imagePos, outlineMode, scale, rotation);
 
-void KisToolFreehand::customMoveEvent(KoPointerEvent * event)
-{
-    if (m_mode == PAN) {
-        canvas()->canvasController()->pan(QPoint(-event->x(), -event->y()));
-        event->accept();
-    }
-    event->ignore();
+    return path;
 }
 
 void KisToolFreehand::increaseBrushSize()
 {
     currentPaintOpPreset()->settings()->changePaintOpSize(1, 0);
-    m_oldOutlineRect.adjust(-1, -1, 1, 1);
     showOutlineTemporary();
 }
 
@@ -730,41 +592,27 @@ void KisToolFreehand::decreaseBrushSize()
     showOutlineTemporary();
 }
 
-QPointF KisToolFreehand::outlinePos() const
+void KisToolFreehand::updateOutlineRect()
 {
-    if (m_mode == EDIT_BRUSH) {
-        return m_originalMousePos;
-    } else {
-        return m_mousePos;
-    }
+    QRectF outlinePixelRect = getOutlinePath(m_outlineDocPoint, KisPaintOpSettings::CursorIsOutline).boundingRect();
+    QRectF outlineDocRect = currentImage()->pixelToDocument(outlinePixelRect);
+
+#warning "Remove adjusted() call -- it smells hacky"
+    canvas()->updateCanvas(outlineDocRect.adjusted(-2,-2,2,2));
 }
 
 void KisToolFreehand::showOutlineTemporary()
 {
-    m_showOutline = true;
-    m_timer.start(HIDE_OUTLINE_TIMEOUT);
-    //canvas()->updateCanvas(m_oldOutlineRect);
-    canvas()->updateCanvas(QRect(QPoint(0, 0), QSize(currentImage()->width(), currentImage()->height())));
+    m_explicitShowOutline = true;
+    m_outlineTimer.start(HIDE_OUTLINE_TIMEOUT);
+    updateOutlineRect();
 }
 
 void KisToolFreehand::hideOutline()
 {
-    m_showOutline = false;
-    //canvas()->updateCanvas(m_oldOutlineRect);
-    canvas()->updateCanvas(QRect(QPoint(0, 0), QSize(currentImage()->width(), currentImage()->height())));
+    m_explicitShowOutline = false;
+    updateOutlineRect();
 }
 
-
-void KisToolFreehand::pickColor(const QPoint &pos, bool fromCurrentNode)
-{
-    int key = m_toForegroundColor ? KoCanvasResource::ForegroundColor : KoCanvasResource::BackgroundColor;
-    if (fromCurrentNode){
-            canvas()->resourceManager()->setResource(key,KisToolUtils::pick( currentNode()->paintDevice(),pos));
-    } else /* projection */{
-            canvas()->resourceManager()->setResource(key,KisToolUtils::pick( image()->projection(), pos));
-    }
-}
-
-
 #include "kis_tool_freehand.moc"
 
diff --git a/krita/ui/tool/kis_tool_freehand.h b/krita/ui/tool/kis_tool_freehand.h
index 9f3485a..c2cd990 100644
--- a/krita/ui/tool/kis_tool_freehand.h
+++ b/krita/ui/tool/kis_tool_freehand.h
@@ -40,6 +40,16 @@ class FreehandPaintJob;
 class KisRecordedPathPaintAction;
 class FreehandPaintJobExecutor;
 
+#include "kis_paintop_settings.h"
+
+enum KDE_DEPRECATED enumBrushMode {
+    PAINT,
+    HOVER,
+    EDIT_BRUSH,
+    PAN,
+    COLOR_PICKING
+};
+
 class KRITAUI_EXPORT KisToolFreehand : public KisToolPaint
 {
 
@@ -54,7 +64,6 @@ public:
     virtual void mousePressEvent(KoPointerEvent *e);
     virtual void mouseMoveEvent(KoPointerEvent *e);
     virtual void mouseReleaseEvent(KoPointerEvent *e);
-    virtual void customMoveEvent(KoPointerEvent * event); // only for panning
     virtual void keyPressEvent(QKeyEvent *event);
     virtual void keyReleaseEvent(QKeyEvent* event);
     virtual bool wantsAutoScroll() const;
@@ -66,6 +75,13 @@ signals:
 
 protected:
 
+    void gesture(const QPointF &offsetInDocPixels,
+                 const QPointF &initialDocPoint);
+
+    QPainterPath getOutlinePath(const QPointF &documentPos,
+                                KisPaintOpSettings::OutlineMode outlineMode);
+    void updateOutlineRect();
+
     /// Paint a single brush footprint on the current layer
     virtual void paintAt(const KisPaintInformation &pi);
 
@@ -82,10 +98,6 @@ protected:
     virtual void endPaint();
     virtual void paint(QPainter& gc, const KoViewConverter &converter);
 
-    virtual void initPan();
-    virtual void pan(KoPointerEvent *e);
-    virtual void endPan();
-
 protected slots:
 
     void setSmooth(bool smooth);
@@ -98,8 +110,12 @@ private:
     QPointF adjustPosition(const QPointF& point);
     void queuePaintJob(FreehandPaintJob* job, FreehandPaintJob* previousJob);
     void showOutlineTemporary();
-    void pickColor(const QPoint &pos, bool currentNode);
-    
+
+private:
+    QTimer m_outlineTimer;
+    bool m_explicitShowOutline;
+    QPointF m_outlineDocPoint;
+
 private slots:
 
     void increaseBrushSize();
@@ -109,7 +125,6 @@ protected:
 
     KisPaintInformation m_previousPaintInformation;
     QPointF m_previousTangent;
-    QPointF m_previousDrag;
     double m_dragDist;
 
     bool m_paintIncremental;
@@ -123,7 +138,6 @@ protected:
     double m_magnetism;
 
 private:
-    QPointF outlinePos() const;
 #if defined(HAVE_OPENGL)
     qreal m_xTilt;
     qreal m_yTilt;
@@ -135,34 +149,17 @@ private:
     QString m_brushModelName;
 #endif
 
-    QPointF m_mousePos;
-    QPointF m_prevMousePos;
-    QPointF m_originalMousePos;
-    QPoint  m_originalPos;
-
-    // for painting
-    QRectF m_oldOutlineRect;
-    QPointF m_oldOutlinePosition;
-    
-    
     QRegion m_incrementalDirtyRegion;
     QList<FreehandPaintJob*> m_paintJobs;
     KisRecordedPathPaintAction* m_pathPaintAction;
     QThreadPool* m_executor;
 
-    // for panning
-    QPointF m_lastPosition;
     QTime m_strokeTimeMeasure;
 
     KAction* m_increaseBrushSize;
     KAction* m_decreaseBrushSize;
-    
+
     bool m_hasPaintAtLeastOnce; ///< this indicates whether mouseReleaseEvent should call paintAt or not
-    
-    QTimer m_timer;
-    bool m_showOutline;
-    
-    bool m_toForegroundColor;
 };
 
 
diff --git a/krita/ui/tool/kis_tool_paint.cc b/krita/ui/tool/kis_tool_paint.cc
index 355d872..f829db9 100644
--- a/krita/ui/tool/kis_tool_paint.cc
+++ b/krita/ui/tool/kis_tool_paint.cc
@@ -66,6 +66,7 @@
 #include "kis_canvas_resource_provider.h"
 #include <recorder/kis_recorded_paint_action.h>
 #include <kis_cubic_curve.h>
+#include "kis_color_picker_utils.h"
 
 
 KisToolPaint::KisToolPaint(KoCanvasBase * canvas, const QCursor & cursor)
@@ -123,25 +124,83 @@ void KisToolPaint::paint(QPainter&, const KoViewConverter &)
 {
 }
 
+void KisToolPaint::pickColor(const QPointF &documentPixel,
+                             bool fromCurrentNode,
+                             bool toForegroundColor)
+{
+    int resource = toForegroundColor ?
+        KoCanvasResource::ForegroundColor : KoCanvasResource::BackgroundColor;
+
+    KisPaintDeviceSP device = fromCurrentNode ?
+        currentNode()->paintDevice() : image()->projection();
+
+    QPoint imagePoint = image()->documentToIntPixel(documentPixel);
 
-void KisToolPaint::mouseReleaseEvent(KoPointerEvent *e)
+    canvas()->resourceManager()->
+        setResource(resource, KisToolUtils::pick(device, imagePoint));
+}
+
+void KisToolPaint::mousePressEvent(KoPointerEvent *event)
 {
-    if (e->button() == Qt::RightButton) {
-        //CALLING POP UP PALETTE
-        emit sigFavoritePaletteCalled(e->pos());
-
-//        KoResourceManager * resourceProvider = 0;
-//        if (canvas() && (resourceProvider = canvas()->resourceProvider())) {
-//            QVariant fg = resourceProvider->resource(KoCanvasResource::ForegroundColor);
-//            if (!fg.isValid()) return;
-//            QVariant bg = resourceProvider->resource(KoCanvasResource::BackgroundColor);
-//            if (!bg.isValid()) return;
-//            resourceProvider->setResource(KoCanvasResource::ForegroundColor, bg);
-//            resourceProvider->setResource(KoCanvasResource::BackgroundColor, fg);
-//        }
+    if(mode() == KisTool::HOVER_MODE &&
+       (event->button() == Qt::LeftButton || event->button() == Qt::RightButton) &&
+       event->modifiers() & Qt::ControlModifier &&
+       !specialModifierActive()) {
+
+        setMode(SECONDARY_PAINT_MODE);
+        useCursor(KisCursor::pickerCursor());
+
+        m_toForegroundColor = event->button() == Qt::LeftButton;
+        pickColor(event->point, event->modifiers() & Qt::AltModifier,
+                  m_toForegroundColor);
+        event->accept();
+    }
+    else if(mode() == KisTool::HOVER_MODE &&
+            event->button() == Qt::RightButton &&
+            event->modifiers() == Qt::NoModifier &&
+            !specialModifierActive()) {
+
+        emit sigFavoritePaletteCalled(event->pos());
+        event->accept();
+    }
+    else {
+        KisTool::mousePressEvent(event);
     }
 }
 
+void KisToolPaint::mouseMoveEvent(KoPointerEvent *event)
+{
+    if(mode() == KisTool::SECONDARY_PAINT_MODE) {
+        pickColor(event->point, event->modifiers() & Qt::AltModifier,
+                  m_toForegroundColor);
+        event->accept();
+    }
+    else {
+        KisTool::mouseMoveEvent(event);
+    }
+}
+
+void KisToolPaint::mouseReleaseEvent(KoPointerEvent *event)
+{
+    if(mode() == KisTool::SECONDARY_PAINT_MODE) {
+        setMode(KisTool::HOVER_MODE);
+        resetCursorStyle();
+        event->accept();
+    }
+    else {
+        KisTool::mouseReleaseEvent(event);
+    }
+}
+
+void KisToolPaint::keyPressEvent(QKeyEvent *event)
+{
+    KisTool::keyPressEvent(event);
+}
+
+void KisToolPaint::keyReleaseEvent(QKeyEvent* event)
+{
+    KisTool::keyReleaseEvent(event);
+}
 
 QWidget * KisToolPaint::createOptionWidget()
 {
diff --git a/krita/ui/tool/kis_tool_paint.h b/krita/ui/tool/kis_tool_paint.h
index 33df739..2918e7c 100644
--- a/krita/ui/tool/kis_tool_paint.h
+++ b/krita/ui/tool/kis_tool_paint.h
@@ -54,14 +54,6 @@ class KoCanvasBase;
 
 class KisSliderSpinBox;
 
-enum enumBrushMode {
-    PAINT,
-    HOVER,
-    EDIT_BRUSH,
-    PAN,
-    COLOR_PICKING
-};
-
 // wacom 
 const static int LEVEL_OF_PRESSURE_RESOLUTION = 1024;
 
@@ -82,7 +74,13 @@ public:
 
     virtual void paint(QPainter& gc, const KoViewConverter &converter);
 
+    virtual void mousePressEvent(KoPointerEvent *event);
     virtual void mouseReleaseEvent(KoPointerEvent *event);
+    virtual void mouseMoveEvent(KoPointerEvent *event);
+
+    virtual void keyPressEvent(QKeyEvent *event);
+    virtual void keyReleaseEvent(QKeyEvent* event);
+
 
     /** If the paint tool support outline like brushes, set to true.
     *   If not (e.g. gradient tool), set to false. Default is false.
@@ -114,7 +112,13 @@ protected:
     qreal pressureToCurve(qreal pressure){
         return m_pressureSamples.at( qRound(pressure * LEVEL_OF_PRESSURE_RESOLUTION) );
     }
-    
+
+private:
+    void pickColor(const QPointF &documentPixel, bool fromCurrentNode,
+                   bool toForegroundColor);
+
+    bool m_toForegroundColor;
+
 public slots:
     virtual void activate(ToolActivation toolActivation, const QSet<KoShape*> &shapes);
 
-- 
1.6.4.2

