[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [krita/kazakov/svg-loading] /: Implement centralized painting of handles
From:       Dmitry Kazakov <null () kde ! org>
Date:       2017-02-17 11:16:43
Message-ID: E1cegWp-0004BY-Fa () code ! kde ! org
[Download RAW message or body]

Git commit 7a35b3b21fd4bc313445ee95b654d4518b9ea778 by Dmitry Kazakov.
Committed on 17/02/2017 at 11:05.
Pushed by dkazakov into branch 'kazakov/svg-loading'.

Implement centralized painting of handles

Now every (vector) tool in Krita uses KisHandlePainterHelper to
paint the handles. The helper supports styling, that is you
can set any predefined object of type KisHandleStyle to get
needed effect.

M  +16   -32   libs/basicflakes/tools/KoCreatePathTool.cpp
M  +5    -8    libs/basicflakes/tools/KoPencilTool.cpp
M  +6    -26   libs/flake/KoParameterShape.cpp
M  +3    -2    libs/flake/KoParameterShape.h
M  +21   -29   libs/flake/KoPathPoint.cpp
M  +2    -1    libs/flake/KoPathPoint.h
M  +2    -4    libs/flake/KoPathShape.cpp
M  +2    -1    libs/flake/KoPathShape.h
M  +12   -0    libs/flake/KoShape.cpp
M  +8    -1    libs/flake/KoShape.h
M  +8    -18   libs/flake/tools/KoPathTool.cpp
M  +13   -14   libs/flake/tools/KoPathToolHandle.cpp
M  +6    -4    libs/flake/tools/KoPathToolHandle.h
M  +8    -11   libs/flake/tools/KoPathToolSelection.cpp
M  +1    -1    libs/flake/tools/KoPathToolSelection.h
M  +1    -0    libs/global/CMakeLists.txt
M  +144  -11   libs/global/KisHandlePainterHelper.cpp
M  +59   -1    libs/global/KisHandlePainterHelper.h
A  +127  -0    libs/global/KisHandleStyle.cpp     [License: GPL (v2+)]
A  +93   -0    libs/global/KisHandleStyle.h     [License: GPL (v2+)]
M  +60   -0    libs/global/kis_painting_tweaks.cpp
M  +51   -0    libs/global/kis_painting_tweaks.h
M  +0    -16   libs/image/krita_utils.cpp
M  +0    -3    libs/image/krita_utils.h
M  +3    -3    libs/ui/kis_selection_decoration.cc
M  +4    -6    plugins/tools/defaulttool/connectionTool/ConnectionTool.cpp
M  +22   -38   plugins/tools/defaulttool/defaulttool/SelectionDecorator.cpp
M  +1    -1    plugins/tools/defaulttool/defaulttool/SelectionDecorator.h
M  +2    -2    plugins/tools/tool_transform2/kis_cage_transform_strategy.cpp
M  +2    -2    plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp

https://commits.kde.org/krita/7a35b3b21fd4bc313445ee95b654d4518b9ea778

diff --git a/libs/basicflakes/tools/KoCreatePathTool.cpp \
b/libs/basicflakes/tools/KoCreatePathTool.cpp index d55f220c0a7..c61864e8d85 100644
--- a/libs/basicflakes/tools/KoCreatePathTool.cpp
+++ b/libs/basicflakes/tools/KoCreatePathTool.cpp
@@ -33,6 +33,7 @@
 #include "kis_int_parse_spin_box.h"
 #include <KoColor.h>
 #include "kis_canvas_resource_provider.h"
+#include <KisHandlePainterHelper.h>
 
 #include <klocalizedstring.h>
 
@@ -62,52 +63,35 @@ void KoCreatePathTool::paint(QPainter &painter, const \
KoViewConverter &converter  paintPath(*(d->shape), painter, converter);
         painter.restore();
 
-        painter.save();
-
-        painter.setTransform(d->shape->absoluteTransformation(&converter) * \
                painter.transform());
-
-        KoShape::applyConversion(painter, converter);
+        KisHandlePainterHelper helper =
+            KoShape::createHandlePainterHelper(&painter, d->shape, converter, \
d->handleRadius);  
-        QPen pen(QBrush(Qt::blue), 1);
-        pen.setCosmetic(true);
-        painter.setPen(pen);
-        painter.setBrush(Qt::white);
+        const bool firstPointActive = d->firstPoint == d->activePoint;
 
-        const bool firstPoint = (d->firstPoint == d->activePoint);
-
-        if (d->pointIsDragged || firstPoint) {
+        if (d->pointIsDragged || firstPointActive) {
             const bool onlyPaintActivePoints = false;
             KoPathPoint::PointTypes paintFlags = KoPathPoint::ControlPoint2;
 
             if (d->activePoint->activeControlPoint1()) {
                 paintFlags |= KoPathPoint::ControlPoint1;
             }
-            d->activePoint->paint(painter, d->handleRadius, paintFlags, \
                onlyPaintActivePoints);
-        }
-
 
-        // check if we have to color the first point
-        if (d->mouseOverFirstPoint) {
-            painter.setBrush(Qt::red);
-        } else {
-            painter.setBrush(Qt::white);
+            helper.setHandleStyle(KisHandleStyle::highlightedPrimaryHandles());
+            d->activePoint->paint(helper, paintFlags, onlyPaintActivePoints);
         }
 
-        d->firstPoint->paint(painter, d->handleRadius, KoPathPoint::Node);
-
-        painter.restore();
+        if (!firstPointActive) {
+            helper.setHandleStyle(d->mouseOverFirstPoint ?
+                                      KisHandleStyle::highlightedPrimaryHandles() :
+                                      KisHandleStyle::primarySelection());
+            d->firstPoint->paint(helper, KoPathPoint::Node);
+        }
     }
 
     if (d->hoveredPoint) {
-        painter.save();
-        painter.setTransform(d->hoveredPoint->parent()->absoluteTransformation(&converter), \
                true);
-        KoShape::applyConversion(painter, converter);
-        QPen pen(QBrush(Qt::blue), 1);
-        pen.setCosmetic(true);
-        painter.setPen(pen);
-        painter.setBrush(Qt::white);
-        d->hoveredPoint->paint(painter, d->handleRadius, KoPathPoint::Node);
-        painter.restore();
+        KisHandlePainterHelper helper = KoShape::createHandlePainterHelper(&painter, \
d->hoveredPoint->parent(), converter, d->handleRadius); +        \
helper.setHandleStyle(KisHandleStyle::highlightedPrimaryHandles()); +        \
d->hoveredPoint->paint(helper, KoPathPoint::Node);  }
 
     painter.save();
diff --git a/libs/basicflakes/tools/KoPencilTool.cpp \
b/libs/basicflakes/tools/KoPencilTool.cpp index 3eaece98bd6..7a39c5f105b 100644
--- a/libs/basicflakes/tools/KoPencilTool.cpp
+++ b/libs/basicflakes/tools/KoPencilTool.cpp
@@ -35,6 +35,7 @@
 #include <KoPathPointMergeCommand.h>
 #include <KoShapePaintingContext.h>
 #include <widgets/KoStrokeConfigWidget.h>
+#include <KisHandlePainterHelper.h>
 
 #include <klocalizedstring.h>
 
@@ -93,15 +94,11 @@ void KoPencilTool::paint(QPainter &painter, const KoViewConverter \
&converter)  }
 
     if (m_hoveredPoint) {
-        painter.save();
-        painter.setTransform(m_hoveredPoint->parent()->absoluteTransformation(&converter), \
                true);
-        KoShape::applyConversion(painter, converter);
-
-        painter.setPen(QPen(Qt::blue, 0));      //TODO make configurable
-        painter.setBrush(Qt::white);   //TODO make configurable
-        m_hoveredPoint->paint(painter, handleRadius(), KoPathPoint::Node);
+        KisHandlePainterHelper helper =
+            KoShape::createHandlePainterHelper(&painter, m_hoveredPoint->parent(), \
converter, handleRadius());  
-        painter.restore();
+        helper.setHandleStyle(KisHandleStyle::primarySelection());
+        m_hoveredPoint->paint(helper, KoPathPoint::Node);
     }
 }
 
diff --git a/libs/flake/KoParameterShape.cpp b/libs/flake/KoParameterShape.cpp
index 843a5b41a09..6842c40bbd2 100644
--- a/libs/flake/KoParameterShape.cpp
+++ b/libs/flake/KoParameterShape.cpp
@@ -21,6 +21,8 @@
 #include "KoParameterShape.h"
 #include "KoParameterShape_p.h"
 
+#include <KisHandlePainterHelper.h>
+
 #include <QPainter>
 #include <FlakeDebug.h>
 
@@ -88,42 +90,20 @@ QPointF KoParameterShape::handlePosition(int handleId) const
     return d->handles.value(handleId);
 }
 
-void KoParameterShape::paintHandles(QPainter & painter, const KoViewConverter & \
converter, int handleRadius) +void \
KoParameterShape::paintHandles(KisHandlePainterHelper &handlesHelper)  {
     Q_D(KoParameterShape);
-    applyConversion(painter, converter);
-
-    QTransform worldMatrix = painter.worldTransform();
-    painter.setTransform(QTransform());
-
-    QTransform matrix;
-    matrix.rotate(45.0);
-    QPolygonF poly(d->handleRect(QPointF(0, 0), handleRadius));
-    poly = matrix.map(poly);
 
     QList<QPointF>::const_iterator it(d->handles.constBegin());
     for (; it != d->handles.constEnd(); ++it) {
-        QPointF moveVector = worldMatrix.map(*it);
-        poly.translate(moveVector.x(), moveVector.y());
-        painter.drawPolygon(poly);
-        poly.translate(-moveVector.x(), -moveVector.y());
+        handlesHelper.drawGradientHandle(*it);
     }
 }
 
-void KoParameterShape::paintHandle(QPainter & painter, const KoViewConverter & \
converter, int handleId, int handleRadius) +void \
KoParameterShape::paintHandle(KisHandlePainterHelper &handlesHelper, int handleId)  {
     Q_D(KoParameterShape);
-    applyConversion(painter, converter);
-
-    QTransform worldMatrix = painter.worldTransform();
-    painter.setTransform(QTransform());
-
-    QTransform matrix;
-    matrix.rotate(45.0);
-    QPolygonF poly(d->handleRect(QPointF(0, 0), handleRadius));
-    poly = matrix.map(poly);
-    poly.translate(worldMatrix.map(d->handles[handleId]));
-    painter.drawPolygon(poly);
+    handlesHelper.drawGradientHandle(d->handles[handleId]);
 }
 
 void KoParameterShape::setSize(const QSizeF &newSize)
diff --git a/libs/flake/KoParameterShape.h b/libs/flake/KoParameterShape.h
index 6f01533b950..05ce7ce9a1e 100644
--- a/libs/flake/KoParameterShape.h
+++ b/libs/flake/KoParameterShape.h
@@ -25,6 +25,7 @@
 #include "kritaflake_export.h"
 
 class KoParameterShapePrivate;
+class KisHandlePainterHelper;
 
 /**
  * KoParameterShape is the base class for all parametric shapes
@@ -83,7 +84,7 @@ public:
      * @param converter the view converter for applying the actual zoom
      * @param handleRadius the radius of the handles used for painting
      */
-    void paintHandles(QPainter &painter, const KoViewConverter &converter, int \
handleRadius); +    void paintHandles(KisHandlePainterHelper &handlesHelper);
 
     /**
      * @brief Paint the given handles
@@ -93,7 +94,7 @@ public:
      * @param handleId of the handle which should be repainted
      * @param handleRadius the radius of the handle used for painting
      */
-    void paintHandle(QPainter &painter, const KoViewConverter &converter, int \
handleId, int handleRadius); +    void paintHandle(KisHandlePainterHelper \
&handlesHelper, int handleId);  
     /// reimplemented from KoShape
     virtual void setSize(const QSizeF &size);
diff --git a/libs/flake/KoPathPoint.cpp b/libs/flake/KoPathPoint.cpp
index 7002e6d25d3..e59b78ae390 100644
--- a/libs/flake/KoPathPoint.cpp
+++ b/libs/flake/KoPathPoint.cpp
@@ -25,6 +25,7 @@
 #include <FlakeDebug.h>
 #include <QPainter>
 #include <QPointF>
+#include <KisHandlePainterHelper.h>
 
 #include <math.h>
 
@@ -261,49 +262,40 @@ void KoPathPoint::map(const QTransform &matrix)
         d->shape->notifyChanged();
 }
 
-void KoPathPoint::paint(QPainter &painter, int handleRadius, PointTypes types, bool \
active) +void KoPathPoint::paint(KisHandlePainterHelper &handlesHelper, PointTypes \
types, bool active)  {
-    QRectF handle(-handleRadius, -handleRadius, 2*handleRadius, 2*handleRadius);
-
     bool drawControlPoint1 = types & ControlPoint1 && (!active || \
                activeControlPoint1());
     bool drawControlPoint2 = types & ControlPoint2 && (!active || \
activeControlPoint2());  
     // draw lines at the bottom
-    if (drawControlPoint2)
-        painter.drawLine(point(), controlPoint2());
-
-    if (drawControlPoint1)
-        painter.drawLine(point(), controlPoint1());
-
-
-    QTransform worldMatrix = painter.worldTransform();
+    if (drawControlPoint2) {
+        handlesHelper.drawConnectionLine(point(), controlPoint2());
+    }
 
-    painter.setWorldTransform(QTransform());
+    if (drawControlPoint1) {
+        handlesHelper.drawConnectionLine(point(), controlPoint1());
+    }
 
     // the point is lowest
     if (types & Node) {
-        if (properties() & IsSmooth)
-            painter.drawRect(handle.translated(worldMatrix.map(point())));
-        else if (properties() & IsSymmetric) {
-            QTransform matrix;
-            matrix.rotate(45.0);
-            QPolygonF poly(handle);
-            poly = matrix.map(poly);
-            poly.translate(worldMatrix.map(point()));
-            painter.drawPolygon(poly);
-        } else
-            painter.drawEllipse(handle.translated(worldMatrix.map(point())));
+        if (properties() & IsSmooth) {
+            handlesHelper.drawHandleRect(point());
+        } else if (properties() & IsSymmetric) {
+            handlesHelper.drawGradientHandle(point());
+        } else {
+            handlesHelper.drawHandleCircle(point());
+        }
     }
 
     // then comes control point 2
-    if (drawControlPoint2)
-        painter.drawEllipse(handle.translated(worldMatrix.map(controlPoint2())));
+    if (drawControlPoint2) {
+        handlesHelper.drawHandleCircle(controlPoint2());
+    }
 
     // then comes control point 1
-    if (drawControlPoint1)
-        painter.drawEllipse(handle.translated(worldMatrix.map(controlPoint1())));
-
-    painter.setWorldTransform(worldMatrix);
+    if (drawControlPoint1) {
+        handlesHelper.drawHandleCircle(controlPoint1());
+    }
 }
 
 void KoPathPoint::setParent(KoPathShape* parent)
diff --git a/libs/flake/KoPathPoint.h b/libs/flake/KoPathPoint.h
index 35dd393d208..778310315de 100644
--- a/libs/flake/KoPathPoint.h
+++ b/libs/flake/KoPathPoint.h
@@ -31,6 +31,7 @@ class QPointF;
 class QTransform;
 class QRectF;
 class QPainter;
+class KisHandlePainterHelper;
 
 /**
  * @brief A KoPathPoint represents a point in a path.
@@ -213,7 +214,7 @@ public:
      * @param active If true only the given active points are painted
      *               If false all given points are used.
      */
-    void paint(QPainter &painter, int handleRadius, PointTypes types, bool active = \
true); +    void paint(KisHandlePainterHelper &handlesHelper, PointTypes types, bool \
active = true);  
     /**
      * @brief Sets the parent path shape.
diff --git a/libs/flake/KoPathShape.cpp b/libs/flake/KoPathShape.cpp
index e568fb0cb31..5f633238591 100644
--- a/libs/flake/KoPathShape.cpp
+++ b/libs/flake/KoPathShape.cpp
@@ -461,18 +461,16 @@ void KoPathShapePrivate::debugPath() const
 }
 #endif
 
-void KoPathShape::paintPoints(QPainter &painter, const KoViewConverter &converter, \
int handleRadius) +void KoPathShape::paintPoints(KisHandlePainterHelper \
&handlesHelper)  {
     Q_D(KoPathShape);
 
-    applyConversion(painter, converter);
-
     KoSubpathList::const_iterator pathIt(d->subpaths.constBegin());
 
     for (; pathIt != d->subpaths.constEnd(); ++pathIt) {
         KoSubpath::const_iterator it((*pathIt)->constBegin());
         for (; it != (*pathIt)->constEnd(); ++it)
-            (*it)->paint(painter, handleRadius, KoPathPoint::Node);
+            (*it)->paint(handlesHelper, KoPathPoint::Node);
     }
 }
 
diff --git a/libs/flake/KoPathShape.h b/libs/flake/KoPathShape.h
index c0b5c6ace74..d917381f3c1 100644
--- a/libs/flake/KoPathShape.h
+++ b/libs/flake/KoPathShape.h
@@ -37,6 +37,7 @@ class KoPathSegment;
 class KoPathPoint;
 class KoPathShapePrivate;
 class KoMarker;
+class KisHandlePainterHelper;
 
 typedef QPair<int, int> KoPathPointIndex;
 
@@ -89,7 +90,7 @@ public:
 
     /// reimplemented
     virtual void paint(QPainter &painter, const KoViewConverter &converter, \
                KoShapePaintingContext &paintContext);
-    virtual void paintPoints(QPainter &painter, const KoViewConverter &converter, \
int handleRadius); +    virtual void paintPoints(KisHandlePainterHelper \
&handlesHelper);  
     /// reimplemented
     QRectF outlineRect() const override;
diff --git a/libs/flake/KoShape.cpp b/libs/flake/KoShape.cpp
index 45e4b2335ae..02d471a9492 100644
--- a/libs/flake/KoShape.cpp
+++ b/libs/flake/KoShape.cpp
@@ -74,6 +74,7 @@
 
 #include <limits>
 #include "KoOdfGradientBackground.h"
+#include <KisHandlePainterHelper.h>
 
 // KoShapePrivate
 
@@ -2171,6 +2172,17 @@ void KoShape::applyConversion(QPainter &painter, const \
KoViewConverter &converte  painter.scale(zoomX, zoomY);
 }
 
+KisHandlePainterHelper KoShape::createHandlePainterHelper(QPainter *painter, KoShape \
*shape, const KoViewConverter &converter, qreal handleRadius) +{
+    const QTransform originalPainterTransform = painter->transform();
+
+    painter->setTransform(shape->absoluteTransformation(&converter) * \
painter->transform()); +    KoShape::applyConversion(*painter, converter);
+
+    // move c-tor
+    return KisHandlePainterHelper(painter, originalPainterTransform, handleRadius);
+}
+
 QPointF KoShape::shapeToDocument(const QPointF &point) const
 {
     return absoluteTransformation(0).map(point);
diff --git a/libs/flake/KoShape.h b/libs/flake/KoShape.h
index 9edd016bbf2..4e2699fbcbd 100644
--- a/libs/flake/KoShape.h
+++ b/libs/flake/KoShape.h
@@ -59,7 +59,7 @@ class KoShapeAnchor;
 class KoBorder;
 struct KoInsets;
 class KoShapeBackground;
-
+class KisHandlePainterHelper;
 
 
 /**
@@ -905,6 +905,13 @@ public:
     static void applyConversion(QPainter &painter, const KoViewConverter \
&converter);  
     /**
+     * A convenience method that creates a handles helper with applying \
transformations at +     * the same time. Please note that you shouldn't save/restore \
additionally. All the work +     * on restoring original painter's transformations is \
done by the helper. +     */
+    static KisHandlePainterHelper createHandlePainterHelper(QPainter *painter, \
KoShape *shape, const KoViewConverter &converter, qreal handleRadius = 0.0); +
+    /**
      * @brief Transforms point from shape coordinates to document coordinates
      * @param point in shape coordinates
      * @return point in document coordinates
diff --git a/libs/flake/tools/KoPathTool.cpp b/libs/flake/tools/KoPathTool.cpp
index ac5113fb920..e3a6b14a797 100644
--- a/libs/flake/tools/KoPathTool.cpp
+++ b/libs/flake/tools/KoPathTool.cpp
@@ -50,6 +50,7 @@
 #include "KoSnapGuide.h"
 #include "KoShapeController.h"
 #include "kis_action_registry.h"
+#include <KisHandlePainterHelper.h>
 
 #include <KoIcon.h>
 
@@ -416,23 +417,18 @@ void KoPathTool::breakAtSegment()
 void KoPathTool::paint(QPainter &painter, const KoViewConverter &converter)
 {
     Q_D(KoToolBase);
-    painter.setRenderHint(QPainter::Antialiasing, true);
-    // use different colors so that it is also visible on a background of the same \
                color
-    painter.setBrush(Qt::white);
-    painter.setPen(Qt::blue);
 
     Q_FOREACH (KoPathShape *shape, m_pointSelection.selectedShapes()) {
-        painter.save();
-        painter.setTransform(shape->absoluteTransformation(&converter) * \
painter.transform()); +        KisHandlePainterHelper helper =
+            KoShape::createHandlePainterHelper(&painter, shape, converter, \
m_handleRadius); +        helper.setHandleStyle(KisHandleStyle::primarySelection());
 
         KoParameterShape * parameterShape = dynamic_cast<KoParameterShape*>(shape);
         if (parameterShape && parameterShape->isParametricShape()) {
-            parameterShape->paintHandles(painter, converter, m_handleRadius);
+            parameterShape->paintHandles(helper);
         } else {
-            shape->paintPoints(painter, converter, m_handleRadius);
+            shape->paintPoints(helper);
         }
-
-        painter.restore();
     }
 
     if (m_currentStrategy) {
@@ -441,17 +437,11 @@ void KoPathTool::paint(QPainter &painter, const KoViewConverter \
&converter)  painter.restore();
     }
 
-    painter.setBrush(Qt::green);
-    painter.setPen(Qt::blue);
-
-    m_pointSelection.paint(painter, converter);
-
-    painter.setBrush(Qt::red);
-    painter.setPen(Qt::blue);
+    m_pointSelection.paint(painter, converter, m_handleRadius);
 
     if (m_activeHandle) {
         if (m_activeHandle->check(m_pointSelection.selectedShapes())) {
-            m_activeHandle->paint(painter, converter);
+            m_activeHandle->paint(painter, converter, m_handleRadius);
         } else {
             delete m_activeHandle;
             m_activeHandle = 0;
diff --git a/libs/flake/tools/KoPathToolHandle.cpp \
b/libs/flake/tools/KoPathToolHandle.cpp index eb2c50b61b5..3c0fe0fdd77 100644
--- a/libs/flake/tools/KoPathToolHandle.cpp
+++ b/libs/flake/tools/KoPathToolHandle.cpp
@@ -36,6 +36,8 @@
 #include "KoPointerEvent.h"
 #include "KoShapeController.h"
 #include <QPainter>
+#include <KisHandlePainterHelper.h>
+
 
 KoPathToolHandle::KoPathToolHandle(KoPathTool *tool)
         : m_tool(tool)
@@ -58,19 +60,18 @@ PointHandle::PointHandle(KoPathTool *tool, KoPathPoint \
*activePoint, KoPathPoint  {
 }
 
-void PointHandle::paint(QPainter &painter, const KoViewConverter &converter)
+void PointHandle::paint(QPainter &painter, const KoViewConverter &converter, qreal \
handleRadius)  {
-    painter.save();
-    painter.setTransform(m_activePoint->parent()->absoluteTransformation(&converter) \
                * painter.transform());
-    KoShape::applyConversion(painter, converter);
-
     KoPathToolSelection * selection = \
dynamic_cast<KoPathToolSelection*>(m_tool->selection());  
     KoPathPoint::PointType type = KoPathPoint::Node;
-    if (selection && selection->contains(m_activePoint))
+    if (selection && selection->contains(m_activePoint)) {
         type = KoPathPoint::All;
-    m_activePoint->paint(painter, handleRadius(), type);
-    painter.restore();
+    }
+
+    KisHandlePainterHelper helper = KoShape::createHandlePainterHelper(&painter, \
m_activePoint->parent(), converter, handleRadius); +    \
helper.setHandleStyle(KisHandleStyle::highlightedPrimaryHandles()); +    \
m_activePoint->paint(helper, type);  }
 
 void PointHandle::repaint() const
@@ -159,13 +160,11 @@ ParameterHandle::ParameterHandle(KoPathTool *tool, \
KoParameterShape *parameterSh  {
 }
 
-void ParameterHandle::paint(QPainter &painter, const KoViewConverter &converter)
+void ParameterHandle::paint(QPainter &painter, const KoViewConverter &converter, \
qreal handleRadius)  {
-    painter.save();
-    painter.setTransform(m_parameterShape->absoluteTransformation(&converter) * \
                painter.transform());
-
-    m_parameterShape->paintHandle(painter, converter, m_handleId, handleRadius());
-    painter.restore();
+    KisHandlePainterHelper helper = KoShape::createHandlePainterHelper(&painter, \
m_parameterShape, converter, handleRadius); +    \
helper.setHandleStyle(KisHandleStyle::highlightedPrimaryHandles()); +    \
m_parameterShape->paintHandle(helper, m_handleId);  }
 
 void ParameterHandle::repaint() const
diff --git a/libs/flake/tools/KoPathToolHandle.h \
b/libs/flake/tools/KoPathToolHandle.h index f1e44b82252..d2c5b624856 100644
--- a/libs/flake/tools/KoPathToolHandle.h
+++ b/libs/flake/tools/KoPathToolHandle.h
@@ -35,13 +35,15 @@ class KoViewConverter;
 class KoPointerEvent;
 class QPainter;
 class KoPathShape;
+class KisHandlePainterHelper;
+
 
 class KoPathToolHandle
 {
 public:
     explicit KoPathToolHandle(KoPathTool *tool);
     virtual ~KoPathToolHandle();
-    virtual void paint(QPainter &painter, const KoViewConverter &converter) = 0;
+    virtual void paint(QPainter &painter, const KoViewConverter &converter, qreal \
handleRadius) = 0;  virtual void repaint() const = 0;
     virtual KoInteractionStrategy * handleMousePress(KoPointerEvent *event) = 0;
     // test if handle is still valid
@@ -56,7 +58,7 @@ class PointHandle : public KoPathToolHandle
 {
 public:
     PointHandle(KoPathTool *tool, KoPathPoint *activePoint, KoPathPoint::PointType \
                activePointType);
-    void paint(QPainter &painter, const KoViewConverter &converter);
+    void paint(QPainter &painter, const KoViewConverter &converter, qreal \
handleRadius);  void repaint() const;
     KoInteractionStrategy *handleMousePress(KoPointerEvent *event);
     virtual bool check(const QList<KoPathShape*> &selectedShapes);
@@ -72,10 +74,10 @@ class ParameterHandle : public KoPathToolHandle
 {
 public:
     ParameterHandle(KoPathTool *tool, KoParameterShape *parameterShape, int \
                handleId);
-    void paint(QPainter &painter, const KoViewConverter &converter);
+    void paint(QPainter &painter, const KoViewConverter &converter, qreal \
handleRadius);  void repaint() const;
     KoInteractionStrategy *handleMousePress(KoPointerEvent *event);
-    virtual bool check(const QList<KoPathShape*> &selectedShapes);
+    bool check(const QList<KoPathShape*> &selectedShapes);
 protected:
     KoParameterShape *m_parameterShape;
     int m_handleId;
diff --git a/libs/flake/tools/KoPathToolSelection.cpp \
b/libs/flake/tools/KoPathToolSelection.cpp index 10a86146169..45dea7a1811 100644
--- a/libs/flake/tools/KoPathToolSelection.cpp
+++ b/libs/flake/tools/KoPathToolSelection.cpp
@@ -30,6 +30,7 @@
 #include <KoDocumentResourceManager.h>
 #include <KoShapeController.h>
 #include <QPainter>
+#include <KisHandlePainterHelper.h>
 
 KoPathToolSelection::KoPathToolSelection(KoPathTool * tool)
         : m_tool(tool)
@@ -40,21 +41,17 @@ KoPathToolSelection::~KoPathToolSelection()
 {
 }
 
-void KoPathToolSelection::paint(QPainter &painter, const KoViewConverter &converter)
+void KoPathToolSelection::paint(QPainter &painter, const KoViewConverter &converter, \
qreal handleRadius)  {
-    int handleRadius = \
                m_tool->canvas()->shapeController()->resourceManager()->handleRadius();
                
-
     PathShapePointMap::iterator it(m_shapePointMap.begin());
     for (; it != m_shapePointMap.end(); ++it) {
-        painter.save();
-
-        painter.setTransform(it.key()->absoluteTransformation(&converter) * \
                painter.transform());
-        KoShape::applyConversion(painter, converter);
+        KisHandlePainterHelper helper =
+            KoShape::createHandlePainterHelper(&painter, it.key(), converter, \
handleRadius); +        \
helper.setHandleStyle(KisHandleStyle::selectedPrimaryHandles());  
-        Q_FOREACH (KoPathPoint *p, it.value())
-            p->paint(painter, handleRadius, KoPathPoint::All);
-
-        painter.restore();
+        Q_FOREACH (KoPathPoint *p, it.value()) {
+            p->paint(helper, KoPathPoint::All);
+        }
     }
 }
 
diff --git a/libs/flake/tools/KoPathToolSelection.h \
b/libs/flake/tools/KoPathToolSelection.h index c0d1471f991..85abe777e3b 100644
--- a/libs/flake/tools/KoPathToolSelection.h
+++ b/libs/flake/tools/KoPathToolSelection.h
@@ -48,7 +48,7 @@ public:
     ~KoPathToolSelection();
 
     /// @brief Draw the selected points
-    void paint(QPainter &painter, const KoViewConverter &converter);
+    void paint(QPainter &painter, const KoViewConverter &converter, qreal \
handleRadius);  
     /**
     * @brief Add a point to the selection
diff --git a/libs/global/CMakeLists.txt b/libs/global/CMakeLists.txt
index 2c71e4ed420..9b20290f3b1 100644
--- a/libs/global/CMakeLists.txt
+++ b/libs/global/CMakeLists.txt
@@ -15,6 +15,7 @@ set(kritaglobal_LIB_SRCS
     kis_dom_utils.cpp
     kis_painting_tweaks.cpp
     KisHandlePainterHelper.cpp
+    KisHandleStyle.cpp
     kis_signal_compressor.cpp
     kis_signal_compressor_with_param.cpp
     kis_acyclic_signal_connector.cpp
diff --git a/libs/global/KisHandlePainterHelper.cpp \
b/libs/global/KisHandlePainterHelper.cpp index e434087ac0f..9149a1b8c9a 100644
--- a/libs/global/KisHandlePainterHelper.cpp
+++ b/libs/global/KisHandlePainterHelper.cpp
@@ -20,38 +20,111 @@
 
 #include <QPainter>
 #include "kis_algebra_2d.h"
+#include "kis_painting_tweaks.h"
 
+using KisPaintingTweaks::PenBrushSaver;
 
 KisHandlePainterHelper::KisHandlePainterHelper(QPainter *_painter, qreal \
handleRadius)  : m_painter(_painter),
+      m_originalPainterTransform(m_painter->transform()),
       m_painterTransform(m_painter->transform()),
+      m_handleRadius(handleRadius),
       m_decomposedMatrix(m_painterTransform)
 {
+    init();
+}
+
+KisHandlePainterHelper::KisHandlePainterHelper(QPainter *_painter, const QTransform \
&originalPainterTransform, qreal handleRadius) +    : m_painter(_painter),
+      m_originalPainterTransform(originalPainterTransform),
+      m_painterTransform(m_painter->transform()),
+      m_handleRadius(handleRadius),
+      m_decomposedMatrix(m_painterTransform)
+{
+    init();
+}
+
+KisHandlePainterHelper::KisHandlePainterHelper(KisHandlePainterHelper &&rhs)
+    : m_painter(rhs.m_painter),
+      m_originalPainterTransform(rhs.m_originalPainterTransform),
+      m_painterTransform(rhs.m_painterTransform),
+      m_handleRadius(rhs.m_handleRadius),
+      m_decomposedMatrix(rhs.m_decomposedMatrix),
+      m_handleTransform(rhs.m_handleTransform),
+      m_handlePolygon(rhs.m_handlePolygon),
+      m_handleStyle(rhs.m_handleStyle)
+{
+    // disable the source helper
+    rhs.m_painter = 0;
+}
+
+void KisHandlePainterHelper::init()
+{
+    m_handleStyle = KisHandleStyle::inheritStyle();
+
     m_painter->setTransform(QTransform());
     m_handleTransform = m_decomposedMatrix.shearTransform() * \
m_decomposedMatrix.rotateTransform();  
-    if (handleRadius > 0.0) {
-        const QRectF handleRect(-handleRadius, -handleRadius, 2 * handleRadius, 2 * \
handleRadius); +    if (m_handleRadius > 0.0) {
+        const QRectF handleRect(-m_handleRadius, -m_handleRadius, 2 * \
m_handleRadius, 2 * m_handleRadius);  m_handlePolygon = \
m_handleTransform.map(QPolygonF(handleRect));  }
 }
 
 KisHandlePainterHelper::~KisHandlePainterHelper() {
-    m_painter->setTransform(m_painterTransform);
+    if (m_painter) {
+        m_painter->setTransform(m_originalPainterTransform);
+    }
+}
+
+void KisHandlePainterHelper::setHandleStyle(const KisHandleStyle &style)
+{
+    m_handleStyle = style;
 }
 
 void KisHandlePainterHelper::drawHandleRect(const QPointF &center, qreal radius) {
+    KIS_SAFE_ASSERT_RECOVER_RETURN(m_painter);
+
     QRectF handleRect(-radius, -radius, 2 * radius, 2 * radius);
     QPolygonF handlePolygon = m_handleTransform.map(QPolygonF(handleRect));
     handlePolygon.translate(m_painterTransform.map(center));
-    m_painter->drawPolygon(handlePolygon);
+
+    Q_FOREACH (KisHandleStyle::IterationStyle it, m_handleStyle.handleIterations) {
+        PenBrushSaver saver(it.isValid ? m_painter : 0, it.stylePair, \
PenBrushSaver::allow_noop); +        m_painter->drawPolygon(handlePolygon);
+    }
+}
+
+void KisHandlePainterHelper::drawHandleCircle(const QPointF &center, qreal radius) {
+    KIS_SAFE_ASSERT_RECOVER_RETURN(m_painter);
+
+    QRectF handleRect(-radius, -radius, 2 * radius, 2 * radius);
+    handleRect.translate(m_painterTransform.map(center));
+
+    Q_FOREACH (KisHandleStyle::IterationStyle it, m_handleStyle.handleIterations) {
+        PenBrushSaver saver(it.isValid ? m_painter : 0, it.stylePair, \
PenBrushSaver::allow_noop); +        m_painter->drawEllipse(handleRect);
+    }
+}
+
+void KisHandlePainterHelper::drawHandleCircle(const QPointF &center)
+{
+    drawHandleCircle(center, m_handleRadius);
 }
 
 void KisHandlePainterHelper::drawHandleRect(const QPointF &center) {
-    m_painter->drawPolygon(m_handlePolygon.translated(m_painterTransform.map(center)));
 +    KIS_SAFE_ASSERT_RECOVER_RETURN(m_painter);
+    QPolygonF paintingPolygon = \
m_handlePolygon.translated(m_painterTransform.map(center)); +
+    Q_FOREACH (KisHandleStyle::IterationStyle it, m_handleStyle.handleIterations) {
+        PenBrushSaver saver(it.isValid ? m_painter : 0, it.stylePair, \
PenBrushSaver::allow_noop); +        m_painter->drawPolygon(paintingPolygon);
+    }
 }
 
 void KisHandlePainterHelper::drawGradientHandle(const QPointF &center, qreal radius) \
{ +    KIS_SAFE_ASSERT_RECOVER_RETURN(m_painter);
+
     QPolygonF handlePolygon;
 
     handlePolygon << QPointF(-radius, 0);
@@ -60,10 +133,21 @@ void KisHandlePainterHelper::drawGradientHandle(const QPointF \
&center, qreal rad  handlePolygon << QPointF(0, -radius);
 
     handlePolygon = m_handleTransform.map(handlePolygon);
-    m_painter->drawPolygon(handlePolygon.translated(m_painterTransform.map(center)));
 +    handlePolygon.translate(m_painterTransform.map(center));
+
+    Q_FOREACH (KisHandleStyle::IterationStyle it, m_handleStyle.handleIterations) {
+        PenBrushSaver saver(it.isValid ? m_painter : 0, it.stylePair, \
PenBrushSaver::allow_noop); +        m_painter->drawPolygon(handlePolygon);
+    }
+}
+
+void KisHandlePainterHelper::drawGradientHandle(const QPointF &center)
+{
+    drawGradientHandle(center, 1.41 * m_handleRadius);
 }
 
 void KisHandlePainterHelper::drawGradientCrossHandle(const QPointF &center, qreal \
radius) { +    KIS_SAFE_ASSERT_RECOVER_RETURN(m_painter);
 
     { // Draw a cross
         QPainterPath p;
@@ -73,7 +157,12 @@ void KisHandlePainterHelper::drawGradientCrossHandle(const \
QPointF &center, qrea  p.lineTo(-radius, radius);
 
         p = m_handleTransform.map(p);
-        m_painter->drawPath(p.translated(m_painterTransform.map(center)));
+        p.translate(m_painterTransform.map(center));
+
+        Q_FOREACH (KisHandleStyle::IterationStyle it, \
m_handleStyle.handleIterations) { +            PenBrushSaver saver(it.isValid ? \
m_painter : 0, it.stylePair, PenBrushSaver::allow_noop); +            \
m_painter->drawPath(p); +        }
     }
 
     { // Draw a square
@@ -86,12 +175,19 @@ void KisHandlePainterHelper::drawGradientCrossHandle(const \
QPointF &center, qrea  handlePolygon << QPointF(0, -halfRadius);
 
         handlePolygon = m_handleTransform.map(handlePolygon);
-        m_painter->drawPolygon(handlePolygon.translated(m_painterTransform.map(center)));
 +        handlePolygon.translate(m_painterTransform.map(center));
+
+        Q_FOREACH (KisHandleStyle::IterationStyle it, \
m_handleStyle.handleIterations) { +            PenBrushSaver saver(it.isValid ? \
m_painter : 0, it.stylePair, PenBrushSaver::allow_noop); +            \
m_painter->drawPolygon(handlePolygon); +        }
     }
 }
 
 void KisHandlePainterHelper::drawArrow(const QPointF &pos, const QPointF &from, \
qreal radius)  {
+    KIS_SAFE_ASSERT_RECOVER_RETURN(m_painter);
+
     QPainterPath p;
 
     QLineF line(pos, from);
@@ -106,15 +202,27 @@ void KisHandlePainterHelper::drawArrow(const QPointF &pos, \
const QPointF &from,  
     p.translate(-pos);
 
-    m_painter->drawPath(m_handleTransform.map(p).translated(m_painterTransform.map(pos)));
 +    p = m_handleTransform.map(p).translated(m_painterTransform.map(pos));
+
+    Q_FOREACH (KisHandleStyle::IterationStyle it, m_handleStyle.handleIterations) {
+        PenBrushSaver saver(it.isValid ? m_painter : 0, it.stylePair, \
PenBrushSaver::allow_noop); +        m_painter->drawPath(p);
+    }
 }
 
 void KisHandlePainterHelper::drawGradientArrow(const QPointF &start, const QPointF \
&end, qreal radius)  {
+    KIS_SAFE_ASSERT_RECOVER_RETURN(m_painter);
+
     QPainterPath p;
     p.moveTo(start);
     p.lineTo(end);
-    m_painter->drawPath(m_painterTransform.map(p));
+    p = m_painterTransform.map(p);
+
+    Q_FOREACH (KisHandleStyle::IterationStyle it, m_handleStyle.lineIterations) {
+        PenBrushSaver saver(it.isValid ? m_painter : 0, it.stylePair, \
PenBrushSaver::allow_noop); +        m_painter->drawPath(p);
+    }
 
     const qreal length = kisDistance(start, end);
     const QPointF diff = end - start;
@@ -128,5 +236,30 @@ void KisHandlePainterHelper::drawGradientArrow(const QPointF \
&start, const QPoin  }
 
 void KisHandlePainterHelper::drawRubberLine(const QPolygonF &poly) {
-    m_painter->drawPolygon(m_painterTransform.map(poly));
+    KIS_SAFE_ASSERT_RECOVER_RETURN(m_painter);
+
+    QPolygonF paintingPolygon = m_painterTransform.map(poly);
+
+    Q_FOREACH (KisHandleStyle::IterationStyle it, m_handleStyle.lineIterations) {
+        PenBrushSaver saver(it.isValid ? m_painter : 0, it.stylePair, \
PenBrushSaver::allow_noop); +        m_painter->drawPolygon(paintingPolygon);
+    }
+}
+
+void KisHandlePainterHelper::drawConnectionLine(const QLineF &line)
+{
+    drawConnectionLine(line.p1(), line.p2());
+}
+
+void KisHandlePainterHelper::drawConnectionLine(const QPointF &p1, const QPointF \
&p2) +{
+    KIS_SAFE_ASSERT_RECOVER_RETURN(m_painter);
+
+    QPointF realP1 = m_painterTransform.map(p1);
+    QPointF realP2 = m_painterTransform.map(p2);
+
+    Q_FOREACH (KisHandleStyle::IterationStyle it, m_handleStyle.lineIterations) {
+        PenBrushSaver saver(it.isValid ? m_painter : 0, it.stylePair, \
PenBrushSaver::allow_noop); +        m_painter->drawLine(realP1, realP2);
+    }
 }
diff --git a/libs/global/KisHandlePainterHelper.h \
b/libs/global/KisHandlePainterHelper.h index 84e01be2530..d163a02530c 100644
--- a/libs/global/KisHandlePainterHelper.h
+++ b/libs/global/KisHandlePainterHelper.h
@@ -22,7 +22,11 @@
 #include "kritaglobal_export.h"
 #include "kis_algebra_2d.h"
 
+#include <QPainter>
+#include <KisHandleStyle.h>
 class QPainter;
+class KoShape;
+class KoViewConverter;
 
 /**
  * @brief The KisHandlePainterHelper class is a special helper for
@@ -33,6 +37,10 @@ class QPainter;
  *
  *        On construction it resets QPainter transformation and on destruction
  *        recovers it back.
+ *
+ * Please consider using KoShape::createHandlePainterHelper instead of direct
+ * construction of the helper. This factory method will also apply the
+ * transformations needed for a shape.
  */
 
 class KRITAGLOBAL_EXPORT KisHandlePainterHelper
@@ -41,32 +49,67 @@ public:
 
     /**
      * Creates the helper, initializes all the internal transformations and
-     * *resets* the transformation of teh painter.
+     * *resets* the transformation of the painter.
      */
     KisHandlePainterHelper(QPainter *_painter, qreal handleRadius = 0.0);
 
     /**
+     * Creates the helper, initializes all the internal transformations and
+     * *resets* the transformation of the painter. This override also adjusts the
+     * transformation of the painter into the coordinate system of the shape
+     */
+    KisHandlePainterHelper(QPainter *_painter, const QTransform \
&originalPainterTransform, qreal handleRadius); +
+    /**
+     * Move c-tor. Used to create and return the helper from functions by-value.
+     */
+    KisHandlePainterHelper(KisHandlePainterHelper &&rhs);
+    KisHandlePainterHelper(KisHandlePainterHelper &rhs) = delete;
+
+    /**
      * Restores the transformation of the painter
      */
     ~KisHandlePainterHelper();
 
     /**
+     * Sets style used for painting the handles. Please use static methods of
+     * KisHandleStyle to select predefined styles.
+     */
+    void setHandleStyle(const KisHandleStyle &style);
+
+    /**
      * Draws a handle rect with a custom \p radius at position \p center
      */
     void drawHandleRect(const QPointF &center, qreal radius);
 
     /**
+     * Draws a handle circle with a custom \p radius at position \p center
+     */
+    void drawHandleCircle(const QPointF &center, qreal radius);
+
+    /**
      * Optimized version of the drawing method for drawing handles of
      * predefined size
      */
     void drawHandleRect(const QPointF &center);
 
     /**
+     * Optimized version of the drawing method for drawing handles of
+     * predefined size
+     */
+    void drawHandleCircle(const QPointF &center);
+
+    /**
      * Draw a rotated handle representing the gradient handle
      */
     void drawGradientHandle(const QPointF &center, qreal radius);
 
     /**
+     * Draw a rotated handle representing the gradient handle
+     */
+    void drawGradientHandle(const QPointF &center);
+
+    /**
      * Draw a special handle representing the center of the gradient
      */
     void drawGradientCrossHandle(const QPointF &center, qreal radius);
@@ -81,6 +124,16 @@ public:
      */
     void drawRubberLine(const QPolygonF &poly);
 
+    /**
+     * Draw a line connecting two points
+     */
+    void drawConnectionLine(const QLineF &line);
+
+    /**
+     * Draw a line connecting two points
+     */
+    void drawConnectionLine(const QPointF &p1, const QPointF &p2);
+
 private:
 
     /**
@@ -89,12 +142,17 @@ private:
      */
     void drawArrow(const QPointF &pos, const QPointF &from, qreal radius);
 
+    void init();
+
 private:
     QPainter *m_painter;
+    QTransform m_originalPainterTransform;
     QTransform m_painterTransform;
+    qreal m_handleRadius;
     KisAlgebra2D::DecomposedMatix m_decomposedMatrix;
     QTransform m_handleTransform;
     QPolygonF m_handlePolygon;
+    KisHandleStyle m_handleStyle;
 };
 
 #endif // KISHANDLEPAINTERHELPER_H
diff --git a/libs/global/KisHandleStyle.cpp b/libs/global/KisHandleStyle.cpp
new file mode 100644
index 00000000000..5821481a8d6
--- /dev/null
+++ b/libs/global/KisHandleStyle.cpp
@@ -0,0 +1,127 @@
+/*
+ *  Copyright (c) 2017 Dmitry Kazakov <dimula73@gmail.com>
+ *
+ *  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 "KisHandleStyle.h"
+#include "kis_painting_tweaks.h"
+
+namespace {
+void initDashedStyle(const QColor &baseColor, const QColor &handleFill, \
KisHandleStyle *style) { +    QPen ants;
+    QPen outline;
+    KisPaintingTweaks::initAntsPen(&ants, &outline);
+
+    ants.setColor(baseColor);
+
+    style->lineIterations << KisHandleStyle::IterationStyle(outline, Qt::NoBrush);
+    style->lineIterations << KisHandleStyle::IterationStyle(ants, Qt::NoBrush);
+
+    QPen handlePen(baseColor);
+    handlePen.setWidth(2);
+    handlePen.setJoinStyle(Qt::RoundJoin);
+
+    style->handleIterations << KisHandleStyle::IterationStyle(handlePen, \
handleFill); +}
+
+static const QColor primaryColor(0, 0, 90, 180);
+static const QColor secondaryColor(0, 0, 255, 127);
+static const QColor gradientFillColor(255, 197, 39);
+static const QColor highlightColor(255, 100, 100);
+static const QColor selectionColor(66, 255, 0);
+
+}
+
+
+KisHandleStyle &KisHandleStyle::inheritStyle()
+{
+    static QScopedPointer<KisHandleStyle> style;
+
+    if (!style) {
+        style.reset(new KisHandleStyle());
+        style->lineIterations << KisHandleStyle::IterationStyle();
+        style->handleIterations << KisHandleStyle::IterationStyle();
+    }
+
+    return *style;
+}
+
+KisHandleStyle &KisHandleStyle::primarySelection()
+{
+    static QScopedPointer<KisHandleStyle> style;
+
+    if (!style) {
+        style.reset(new KisHandleStyle());
+        initDashedStyle(primaryColor, Qt::white, style.data());
+    }
+
+    return *style;
+}
+
+KisHandleStyle &KisHandleStyle::secondarySelection()
+{
+    static QScopedPointer<KisHandleStyle> style;
+
+    if (!style) {
+        style.reset(new KisHandleStyle());
+        initDashedStyle(secondaryColor, Qt::white, style.data());
+    }
+
+    return *style;
+}
+
+KisHandleStyle &KisHandleStyle::gradientHandles()
+{
+    static QScopedPointer<KisHandleStyle> style;
+
+    if (!style) {
+        style.reset(new KisHandleStyle());
+        initDashedStyle(primaryColor, gradientFillColor, style.data());
+    }
+
+    return *style;
+}
+
+KisHandleStyle &KisHandleStyle::gradientArrows()
+{
+    return primarySelection();
+}
+
+
+KisHandleStyle &KisHandleStyle::highlightedPrimaryHandles()
+{
+    static QScopedPointer<KisHandleStyle> style;
+
+    if (!style) {
+        style.reset(new KisHandleStyle());
+        initDashedStyle(primaryColor, highlightColor, style.data());
+    }
+
+    return *style;
+}
+
+KisHandleStyle &KisHandleStyle::selectedPrimaryHandles()
+{
+    static QScopedPointer<KisHandleStyle> style;
+
+    if (!style) {
+        style.reset(new KisHandleStyle());
+        initDashedStyle(primaryColor, selectionColor, style.data());
+    }
+
+    return *style;
+}
+
diff --git a/libs/global/KisHandleStyle.h b/libs/global/KisHandleStyle.h
new file mode 100644
index 00000000000..4e7bf8610ef
--- /dev/null
+++ b/libs/global/KisHandleStyle.h
@@ -0,0 +1,93 @@
+/*
+ *  Copyright (c) 2017 Dmitry Kazakov <dimula73@gmail.com>
+ *
+ *  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 KISHANDLESTYLE_H
+#define KISHANDLESTYLE_H
+
+#include <QVector>
+#include <QPen>
+#include <QBrush>
+
+#include "kritaglobal_export.h"
+
+
+/**
+ * A special class that defines a set of predefined styles for painting handles.
+ * Please use static methods for requesting standard krita styles.
+ */
+class KRITAGLOBAL_EXPORT KisHandleStyle
+{
+public:
+
+    /**
+     * Default style that does *no* change to the painter. That is, the painter
+     * will paint with its current pen and brush.
+     */
+    static KisHandleStyle& inheritStyle();
+
+    /**
+     * Main style. Used for showing a single selection or a boundary box of
+     * multiple selected objects.
+     */
+    static KisHandleStyle& primarySelection();
+
+    /**
+     * Secondary style. Used for highlighting objects inside a mupltiple
+     * selection.
+     */
+    static KisHandleStyle& secondarySelection();
+
+    /**
+     * Style for painting gradient handles
+     */
+    static KisHandleStyle& gradientHandles();
+
+    /**
+     * Style for painting linear gradient arrows
+     */
+    static KisHandleStyle& gradientArrows();
+
+    /**
+     * Same as primary style, but the handles are filled with red color to show
+     * that the user is hovering them.
+     */
+    static KisHandleStyle& highlightedPrimaryHandles();
+
+    /**
+     * Same as primary style, but the handles are filled with green color to show
+     * that they are selected.
+     */
+    static KisHandleStyle& selectedPrimaryHandles();
+
+    struct IterationStyle {
+        IterationStyle() : isValid(false) {}
+        IterationStyle(const QPen &pen, const QBrush &brush)
+            : isValid(true),
+              stylePair(pen, brush)
+        {
+        }
+
+        bool isValid;
+        QPair<QPen, QBrush> stylePair;
+    };
+
+    QVector<IterationStyle> handleIterations;
+    QVector<IterationStyle> lineIterations;
+};
+
+#endif // KISHANDLESTYLE_H
diff --git a/libs/global/kis_painting_tweaks.cpp \
b/libs/global/kis_painting_tweaks.cpp index 1c59e1a7827..56a29d03f2d 100644
--- a/libs/global/kis_painting_tweaks.cpp
+++ b/libs/global/kis_painting_tweaks.cpp
@@ -18,6 +18,9 @@
 
 #include "kis_painting_tweaks.h"
 
+
+
+#include <QPen>
 #include <QRegion>
 #include <QPainter>
 #include <QTransform>
@@ -48,4 +51,61 @@ QRect safeClipBoundingRect(const QPainter &painter)
     return painter.clipBoundingRect().toAlignedRect();
 }
 
+void initAntsPen(QPen *antsPen, QPen *outlinePen,
+                 int antLength, int antSpace)
+{
+    QVector<qreal> antDashPattern;
+    antDashPattern << antLength << antSpace;
+
+    *antsPen = QPen(Qt::CustomDashLine);
+    antsPen->setDashPattern(antDashPattern);
+    antsPen->setCosmetic(true);
+    antsPen->setColor(Qt::black);
+
+    *outlinePen = QPen(Qt::SolidLine);
+    outlinePen->setCosmetic(true);
+    outlinePen->setColor(Qt::white);
+}
+
+PenBrushSaver::PenBrushSaver(QPainter *painter)
+    : m_painter(painter),
+      m_pen(painter->pen()),
+      m_brush(painter->brush())
+{
+}
+
+PenBrushSaver::PenBrushSaver(QPainter *painter, const QPen &pen, const QBrush \
&brush) +    : PenBrushSaver(painter)
+{
+    m_painter->setPen(pen);
+    m_painter->setBrush(brush);
+}
+
+PenBrushSaver::PenBrushSaver(QPainter *painter, const QPair<QPen, QBrush> &pair)
+    : PenBrushSaver(painter)
+{
+    m_painter->setPen(pair.first);
+    m_painter->setBrush(pair.second);
+}
+
+PenBrushSaver::PenBrushSaver(QPainter *painter, const QPair<QPen, QBrush> &pair, \
allow_noop_t) +    : m_painter(painter)
+{
+    if (m_painter) {
+        m_pen = m_painter->pen();
+        m_brush = m_painter->brush();
+        m_painter->setPen(pair.first);
+        m_painter->setBrush(pair.second);
+    }
+}
+
+PenBrushSaver::~PenBrushSaver()
+{
+    if (m_painter) {
+        m_painter->setPen(m_pen);
+        m_painter->setBrush(m_brush);
+    }
+}
+
+
 }
diff --git a/libs/global/kis_painting_tweaks.h b/libs/global/kis_painting_tweaks.h
index 274cbad7632..5588b51d7f8 100644
--- a/libs/global/kis_painting_tweaks.h
+++ b/libs/global/kis_painting_tweaks.h
@@ -21,9 +21,13 @@
 
 #include "kritaglobal_export.h"
 
+#include <QPen>
+#include <QBrush>
+
 class QPainter;
 class QRegion;
 class QRect;
+class QPen;
 
 namespace KisPaintingTweaks {
 
@@ -40,6 +44,53 @@ namespace KisPaintingTweaks {
      * \see safeClipRegion()
      */
     KRITAGLOBAL_EXPORT QRect safeClipBoundingRect(const QPainter &painter);
+
+    KRITAGLOBAL_EXPORT void initAntsPen(QPen *antsPen, QPen *outlinePen,
+                                        int antLength = 4, int antSpace = 4);
+
+
+    /**
+     * A special class to save painter->pen() and painter->brush() using RAII
+     * principle.
+     */
+    class KRITAGLOBAL_EXPORT PenBrushSaver
+    {
+    public:
+        struct allow_noop_t { explicit allow_noop_t() = default; };
+        static constexpr allow_noop_t	allow_noop { };
+
+        /**
+         * Saves pen and brush state of the provided painter object. \p painter \
cannot be null. +         */
+        PenBrushSaver(QPainter *painter);
+
+        /**
+         * Overrides pen and brush of \p painter with the provided values. \p \
painter cannot be null. +         */
+        PenBrushSaver(QPainter *painter, const QPen &pen, const QBrush &brush);
+
+        /**
+         * Overrides pen and brush of \p painter with the provided values. \p \
painter cannot be null. +         */
+        PenBrushSaver(QPainter *painter, const QPair<QPen, QBrush> &pair);
+
+        /**
+         * A special contructor of PenBrushSaver that allows \p painter to be null. \
Passing null +         * pointer will basically mean that the whole saver existance \
will be a noop. +         */
+        PenBrushSaver(QPainter *painter, const QPair<QPen, QBrush> &pair, \
allow_noop_t); +
+        /**
+         * Restores the state of the painter that has been saved during the \
construction of the saver +         */
+        ~PenBrushSaver();
+
+    private:
+        PenBrushSaver(const PenBrushSaver &rhs) = delete;
+        QPainter *m_painter;
+        QPen m_pen;
+        QBrush m_brush;
+    };
 }
 
 #endif /* __KIS_PAINTING_TWEAKS_H */
diff --git a/libs/image/krita_utils.cpp b/libs/image/krita_utils.cpp
index 9ac80611b30..bd419d13676 100644
--- a/libs/image/krita_utils.cpp
+++ b/libs/image/krita_utils.cpp
@@ -174,22 +174,6 @@ namespace KritaUtils
         return dirtyRegion;
     }
 
-    void KRITAIMAGE_EXPORT initAntsPen(QPen *antsPen, QPen *outlinePen,
-                                       int antLength, int antSpace)
-    {
-        QVector<qreal> antDashPattern;
-        antDashPattern << antLength << antSpace;
-
-        *antsPen = QPen(Qt::CustomDashLine);
-        antsPen->setDashPattern(antDashPattern);
-        antsPen->setCosmetic(true);
-        antsPen->setColor(Qt::black);
-
-        *outlinePen = QPen(Qt::SolidLine);
-        outlinePen->setCosmetic(true);
-        outlinePen->setColor(Qt::white);
-    }
-
     QString KRITAIMAGE_EXPORT prettyFormatReal(qreal value)
     {
         return QString("%1").arg(value, 6, 'f', 1);
diff --git a/libs/image/krita_utils.h b/libs/image/krita_utils.h
index bc8520fc745..45e6fab3e0e 100644
--- a/libs/image/krita_utils.h
+++ b/libs/image/krita_utils.h
@@ -46,9 +46,6 @@ namespace KritaUtils
                                              const QVector<QPointF> &points);
     QRegion KRITAIMAGE_EXPORT splitPath(const QPainterPath &path);
 
-    void KRITAIMAGE_EXPORT initAntsPen(QPen *antsPen, QPen *outlinePen,
-                                       int antLength = 4, int antSpace = 4);
-
     QString KRITAIMAGE_EXPORT prettyFormatReal(qreal value);
 
     qreal KRITAIMAGE_EXPORT maxDimensionPortion(const QRectF &bounds, qreal portion, \
                qreal minValue);
diff --git a/libs/ui/kis_selection_decoration.cc \
b/libs/ui/kis_selection_decoration.cc index 40c186ef969..6f366237c24 100644
--- a/libs/ui/kis_selection_decoration.cc
+++ b/libs/ui/kis_selection_decoration.cc
@@ -35,7 +35,7 @@
 #include "kis_canvas_resource_provider.h"
 #include "kis_coordinates_converter.h"
 #include "kis_config.h"
-#include "krita_utils.h"
+#include "kis_painting_tweaks.h"
 #include "KisView.h"
 
 static const unsigned int ANT_LENGTH = 4;
@@ -48,8 +48,8 @@ KisSelectionDecoration::KisSelectionDecoration(QPointer<KisView>view)
  m_offset(0),
       m_mode(Ants)
 {
-    KritaUtils::initAntsPen(&m_antsPen, &m_outlinePen,
-                            ANT_LENGTH, ANT_SPACE);
+    KisPaintingTweaks::initAntsPen(&m_antsPen, &m_outlinePen,
+                                   ANT_LENGTH, ANT_SPACE);
 
     m_antsTimer = new QTimer(this);
     m_antsTimer->setInterval(150);
diff --git a/plugins/tools/defaulttool/connectionTool/ConnectionTool.cpp \
b/plugins/tools/defaulttool/connectionTool/ConnectionTool.cpp index \
                5260c439968..40c27585610 100644
--- a/plugins/tools/defaulttool/connectionTool/ConnectionTool.cpp
+++ b/plugins/tools/defaulttool/connectionTool/ConnectionTool.cpp
@@ -51,6 +51,7 @@
 #include <KoConnectionShapeConfigWidget.h>
 #include <KoPathConnectionPointStrategy.h>
 #include <KoStrokeConfigWidget.h>
+#include <KisHandlePainterHelper.h>
 
 #include <KoIcon.h>
 #include "kis_action_registry.h"
@@ -217,12 +218,9 @@ void ConnectionTool::paint(QPainter &painter, const \
KoViewConverter &converter)  int radius = handleRadius() + 1;
             int handleCount = connectionShape->handleCount();
             for (int i = 0; i < handleCount; ++i) {
-                painter.save();
-                painter.setPen(Qt::blue);
-                painter.setBrush(i == m_activeHandle ? Qt::red : Qt::white);
-                painter.setTransform(connectionShape->absoluteTransformation(&converter) \
                * painter.transform());
-                connectionShape->paintHandle(painter, converter, i, radius);
-                painter.restore();
+                KisHandlePainterHelper helper = \
KoShape::createHandlePainterHelper(&painter, connectionShape, converter, radius); +   \
helper.setHandleStyle(i == m_activeHandle ? \
KisHandleStyle::highlightedPrimaryHandles() : KisHandleStyle::primarySelection()); +  \
connectionShape->paintHandle(helper, i);  }
         }
     }
diff --git a/plugins/tools/defaulttool/defaulttool/SelectionDecorator.cpp \
b/plugins/tools/defaulttool/defaulttool/SelectionDecorator.cpp index \
                0919305c3ad..39f1925dd73 100644
--- a/plugins/tools/defaulttool/defaulttool/SelectionDecorator.cpp
+++ b/plugins/tools/defaulttool/defaulttool/SelectionDecorator.cpp
@@ -32,6 +32,8 @@
 #include <KisQPainterStateSaver.h>
 #include "KoShapeGradientHandles.h"
 
+#include "kis_painting_tweaks.h"
+
 #define HANDLE_DISTANCE 10
 
 SelectionDecorator::SelectionDecorator(KoCanvasResourceManager *resourceManager)
@@ -69,19 +71,6 @@ void SelectionDecorator::setShowStrokeFillGradientHandles(bool \
value)  
 void SelectionDecorator::paint(QPainter &painter, const KoViewConverter &converter)
 {
-    QRectF handleArea;
-    KisQPainterStateSaver s(&painter);
-
-    // save the original painter transformation
-    QTransform painterMatrix = painter.worldTransform();
-
-    QPen pen;
-    //Use the #00adf5 color with 50% opacity
-    pen.setColor(QColor(0, 173, 245, 127));
-    pen.setWidth(m_lineWidth);
-    pen.setJoinStyle(Qt::RoundJoin);
-    painter.setPen(pen);
-
     const bool haveOnlyOneEditableShape = \
m_selection->selectedEditableShapes().size() == 1;  
     bool editable = false;
@@ -90,11 +79,11 @@ void SelectionDecorator::paint(QPainter &painter, const \
KoViewConverter &convert  if (selectedShapes.isEmpty()) return;
 
     foreach (KoShape *shape, KoShape::linearizeSubtree(selectedShapes)) {
-        painter.setWorldTransform(shape->absoluteTransformation(&converter) * \
                painterMatrix);
-        KoShape::applyConversion(painter, converter);
-
         if (!haveOnlyOneEditableShape || !m_showStrokeFillGradientHandles) {
-            KisHandlePainterHelper helper(&painter);
+            KisHandlePainterHelper helper =
+                KoShape::createHandlePainterHelper(&painter, shape, converter, \
m_handleRadius); +
+            helper.setHandleStyle(KisHandleStyle::secondarySelection());
             helper.drawRubberLine(shape->outlineRect());
         }
 
@@ -103,29 +92,27 @@ void SelectionDecorator::paint(QPainter &painter, const \
KoViewConverter &convert  }
     }
 
-    handleArea = m_selection->outlineRect();
-    painter.setTransform(m_selection->absoluteTransformation(&converter) * \
                painterMatrix);
-    KoShape::applyConversion(painter, converter);
+    const QRectF handleArea = m_selection->outlineRect();
 
     // draw extra rubber line around all the shapes
     if (selectedShapes.size() > 1) {
-        painter.setPen(Qt::blue);
+        KisHandlePainterHelper helper =
+            KoShape::createHandlePainterHelper(&painter, m_selection, converter, \
m_handleRadius);  
-        KisHandlePainterHelper helper(&painter);
+        helper.setHandleStyle(KisHandleStyle::primarySelection());
         helper.drawRubberLine(handleArea);
-
     }
 
     // if we have no editable shape selected there
     // is no need drawing the selection handles
     if (editable) {
-        painter.setPen(pen);
-        painter.setBrush(Qt::white);
+        KisHandlePainterHelper helper =
+            KoShape::createHandlePainterHelper(&painter, m_selection, converter, \
m_handleRadius); +        helper.setHandleStyle(KisHandleStyle::primarySelection());
 
         QPolygonF outline = handleArea;
 
         {
-            KisHandlePainterHelper helper(&painter, m_handleRadius);
             helper.drawHandleRect(outline.value(0));
             helper.drawHandleRect(outline.value(1));
             helper.drawHandleRect(outline.value(2));
@@ -135,9 +122,8 @@ void SelectionDecorator::paint(QPainter &painter, const \
                KoViewConverter &convert
             helper.drawHandleRect(0.5 * (outline.value(2) + outline.value(3)));
             helper.drawHandleRect(0.5 * (outline.value(3) + outline.value(0)));
 
-            // draw the hot position
-            painter.setBrush(Qt::red);
             QPointF hotPos = KoFlake::anchorToPoint(m_hotPosition, handleArea);
+            helper.setHandleStyle(KisHandleStyle::highlightedPrimaryHandles());
             helper.drawHandleRect(hotPos);
         }
     }
@@ -146,35 +132,33 @@ void SelectionDecorator::paint(QPainter &painter, const \
KoViewConverter &convert  KoShape *shape = selectedShapes.first();
 
         if (m_showFillGradientHandles) {
-            paintGradientHandles(shape, KoFlake::Fill, painter, pen);
+            paintGradientHandles(shape, KoFlake::Fill, painter, converter);
         } else if (m_showStrokeFillGradientHandles) {
-            paintGradientHandles(shape, KoFlake::StrokeFill, painter, pen);
+            paintGradientHandles(shape, KoFlake::StrokeFill, painter, converter);
         }
     }
 }
 
-void SelectionDecorator::paintGradientHandles(KoShape *shape, KoFlake::FillVariant \
fillVariant, QPainter &painter, QPen pen) +void \
SelectionDecorator::paintGradientHandles(KoShape *shape, KoFlake::FillVariant \
fillVariant, QPainter &painter, const KoViewConverter &converter)  {
     KoShapeGradientHandles gradientHandles(fillVariant, shape);
     QVector<KoShapeGradientHandles::Handle> handles = gradientHandles.handles();
 
-    KisHandlePainterHelper helper(&painter);
-    const QTransform t = shape->absoluteTransformation(0).inverted();
+    KisHandlePainterHelper helper =
+        KoShape::createHandlePainterHelper(&painter, shape, converter, \
m_handleRadius);  
-    painter.setPen(pen);
-    painter.setBrush(Qt::white);
+    const QTransform t = shape->absoluteTransformation(0).inverted();
 
     if (gradientHandles.type() == QGradient::LinearGradient) {
         KIS_SAFE_ASSERT_RECOVER_NOOP(handles.size() == 2);
 
         if (handles.size() == 2) {
+            helper.setHandleStyle(KisHandleStyle::gradientArrows());
             helper.drawGradientArrow(t.map(handles[0].pos), t.map(handles[1].pos), \
1.5 * m_handleRadius);  }
     }
 
-    pen.setColor(QColor(255, 197, 39));
-    painter.setPen(pen);
-    painter.setBrush(Qt::white);
+    helper.setHandleStyle(KisHandleStyle::gradientHandles());
 
     Q_FOREACH (const KoShapeGradientHandles::Handle &h, handles) {
         if (h.type == KoShapeGradientHandles::Handle::RadialCenter) {
diff --git a/plugins/tools/defaulttool/defaulttool/SelectionDecorator.h \
b/plugins/tools/defaulttool/defaulttool/SelectionDecorator.h index \
                eec334a9e4b..640043469b4 100644
--- a/plugins/tools/defaulttool/defaulttool/SelectionDecorator.h
+++ b/plugins/tools/defaulttool/defaulttool/SelectionDecorator.h
@@ -76,7 +76,7 @@ public:
     void setShowStrokeFillGradientHandles(bool value);
 
 private:
-    void paintGradientHandles(KoShape *shape, KoFlake::FillVariant fillVariant, \
QPainter &painter, QPen pen); +    void paintGradientHandles(KoShape *shape, \
KoFlake::FillVariant fillVariant, QPainter &painter, const KoViewConverter \
&converter);  
 private:
     KoFlake::AnchorPosition m_hotPosition;
diff --git a/plugins/tools/tool_transform2/kis_cage_transform_strategy.cpp \
b/plugins/tools/tool_transform2/kis_cage_transform_strategy.cpp index \
                a961b1c11ea..df39a447fb1 100644
--- a/plugins/tools/tool_transform2/kis_cage_transform_strategy.cpp
+++ b/plugins/tools/tool_transform2/kis_cage_transform_strategy.cpp
@@ -22,7 +22,7 @@
 #include <QPointF>
 #include <QPainter>
 
-#include "krita_utils.h"
+#include "kis_painting_tweaks.h"
 #include "kis_cursor.h"
 #include <kis_cage_transform_worker.h>
 
@@ -64,7 +64,7 @@ void KisCageTransformStrategy::drawConnectionLines(QPainter &gc,
     QPen antsPen;
     QPen outlinePen;
 
-    KritaUtils::initAntsPen(&antsPen, &outlinePen);
+    KisPaintingTweaks::initAntsPen(&antsPen, &outlinePen);
 
     const int iterateLimit = isEditingPoints ? numPoints : numPoints + 1;
 
diff --git a/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp \
b/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp index \
                26b70b422b6..ba5b4668d77 100644
--- a/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp
+++ b/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp
@@ -26,7 +26,7 @@
 #include "kis_coordinates_converter.h"
 #include "tool_transform_args.h"
 #include "transform_transaction_properties.h"
-#include "krita_utils.h"
+#include "kis_painting_tweaks.h"
 #include "kis_cursor.h"
 #include "kis_transform_utils.h"
 #include "kis_algebra_2d.h"
@@ -209,7 +209,7 @@ void KisWarpTransformStrategy::drawConnectionLines(QPainter &gc,
     QPen antsPen;
     QPen outlinePen;
 
-    KritaUtils::initAntsPen(&antsPen, &outlinePen);
+    KisPaintingTweaks::initAntsPen(&antsPen, &outlinePen);
 
     const int numPoints = origPoints.size();
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic