[krita] libs/ui: Implement color picking in Instant Preview mode

Dmitry Kazakov dimula73 at gmail.com
Thu Mar 24 19:43:02 UTC 2016


Git commit ed75e1efb6a879f67d174940acbb130f98750fbe by Dmitry Kazakov.
Committed on 24/03/2016 at 19:41.
Pushed by dkazakov into branch 'master'.

Implement color picking in Instant Preview mode

Please test color picking! Now it is done in asynchromous way, so the
results may go wild if something goes wrong.

CC:kimageshop at kde.org
Fixes T940
Bug:360760

M  +1    -0    libs/ui/CMakeLists.txt
M  +63   -41   libs/ui/tool/kis_tool_paint.cc
M  +23   -0    libs/ui/tool/kis_tool_paint.h
M  +1    -14   libs/ui/tool/kis_tool_utils.cpp
M  +0    -6    libs/ui/tool/kis_tool_utils.h
A  +71   -0    libs/ui/tool/strokes/kis_color_picker_stroke_strategy.cpp     [License: GPL (v2+)]
A  +65   -0    libs/ui/tool/strokes/kis_color_picker_stroke_strategy.h     [License: GPL (v2+)]

http://commits.kde.org/krita/ed75e1efb6a879f67d174940acbb130f98750fbe

diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt
index 1d3aa53..060fbef 100644
--- a/libs/ui/CMakeLists.txt
+++ b/libs/ui/CMakeLists.txt
@@ -193,6 +193,7 @@ set(kritaui_LIB_SRCS
     tool/strokes/freehand_stroke.cpp
     tool/strokes/kis_painter_based_stroke_strategy.cpp
     tool/strokes/kis_filter_stroke_strategy.cpp
+    tool/strokes/kis_color_picker_stroke_strategy.cpp
     widgets/kis_cmb_composite.cc
     widgets/kis_cmb_contour.cpp
     widgets/kis_cmb_gradient.cpp
diff --git a/libs/ui/tool/kis_tool_paint.cc b/libs/ui/tool/kis_tool_paint.cc
index a4dafbe..0ff83b8 100644
--- a/libs/ui/tool/kis_tool_paint.cc
+++ b/libs/ui/tool/kis_tool_paint.cc
@@ -74,6 +74,8 @@
 #include <brushengine/kis_paintop_preset.h>
 #include <kis_action_manager.h>
 #include <kis_action.h>
+#include "strokes/kis_color_picker_stroke_strategy.h"
+
 
 KisToolPaint::KisToolPaint(KoCanvasBase * canvas, const QCursor & cursor)
     : KisTool(canvas, cursor),
@@ -129,6 +131,12 @@ KisToolPaint::KisToolPaint(KoCanvasBase * canvas, const QCursor & cursor)
 
     m_colorPickerDelayTimer.setSingleShot(true);
     connect(&m_colorPickerDelayTimer, SIGNAL(timeout()), this, SLOT(activatePickColorDelayed()));
+
+    using namespace std::placeholders; // For _1 placeholder
+    std::function<void(PickingJob)> callback =
+        std::bind(&KisToolPaint::addPickerJob, this, _1);
+    m_colorPickingCompressor.reset(
+        new PickingCompressor(100, callback, KisSignalCompressor::FIRST_ACTIVE));
 }
 
 
@@ -319,13 +327,16 @@ void KisToolPaint::activatePickColorDelayed()
 
 }
 
+bool KisToolPaint::isPickingAction(AlternateAction action) {
+    return action == PickFgNode ||
+        action == PickBgNode ||
+        action == PickFgImage ||
+        action == PickBgImage;
+}
+
 void KisToolPaint::deactivateAlternateAction(AlternateAction action)
 {
-    if (action != PickFgNode &&
-        action != PickBgNode &&
-        action != PickFgImage &&
-        action != PickBgImage) {
-
+    if (!isPickingAction(action)) {
         KisTool::deactivateAlternateAction(action);
         return;
     }
@@ -337,30 +348,62 @@ void KisToolPaint::deactivateAlternateAction(AlternateAction action)
     deactivatePickColor(action);
 }
 
+void KisToolPaint::addPickerJob(const PickingJob &pickingJob)
+{
+    /**
+     * The actual picking is delayed by a compressor, so we can get this
+     * event when the stroke is already closed
+     */
+    if (!m_pickerStrokeId) return;
+
+    KIS_ASSERT_RECOVER_RETURN(isPickingAction(pickingJob.action));
+
+    const QPoint imagePoint = image()->documentToIntPixel(pickingJob.documentPixel);
+    const bool fromCurrentNode = pickingJob.action == PickFgNode || pickingJob.action == PickBgNode;
+    m_pickingResource = colorPreviewResourceId(pickingJob.action);
+
+    KisPaintDeviceSP device = fromCurrentNode ?
+        currentNode()->projection() : image()->projection();
+
+    image()->addJob(m_pickerStrokeId,
+                    new KisColorPickerStrokeStrategy::Data(device, imagePoint));
+}
+
 void KisToolPaint::beginAlternateAction(KoPointerEvent *event, AlternateAction action)
 {
-    if (pickColor(event->point, action)) {
+    if (isPickingAction(action)) {
+        KIS_ASSERT_RECOVER_RETURN(!m_pickerStrokeId);
         setMode(SECONDARY_PAINT_MODE);
+
+        KisColorPickerStrokeStrategy *strategy = new KisColorPickerStrokeStrategy();
+        connect(strategy, &KisColorPickerStrokeStrategy::sigColorUpdated,
+                this, &KisToolPaint::slotColorPickingFinished);
+
+        m_pickerStrokeId = image()->startStroke(strategy);
+        m_colorPickingCompressor->start(PickingJob(event->point, action));
         requestUpdateOutline(event->point, event);
     } else {
         KisTool::beginAlternateAction(event, action);
     }
-
 }
 
 void KisToolPaint::continueAlternateAction(KoPointerEvent *event, AlternateAction action)
 {
-    if (!pickColor(event->point, action)) {
-        KisTool::continueAlternateAction(event, action);
-    } else {
+    if (isPickingAction(action)) {
+        KIS_ASSERT_RECOVER_RETURN(m_pickerStrokeId);
+        m_colorPickingCompressor->start(PickingJob(event->point, action));
         requestUpdateOutline(event->point, event);
+    } else {
+        KisTool::continueAlternateAction(event, action);
     }
 }
 
 void KisToolPaint::endAlternateAction(KoPointerEvent *event, AlternateAction action)
 {
-    if (pickColor(event->point, action)) {
-        setMode(KisTool::HOVER_MODE);
+    if (isPickingAction(action)) {
+        KIS_ASSERT_RECOVER_RETURN(m_pickerStrokeId);
+        image()->endStroke(m_pickerStrokeId);
+        m_pickerStrokeId.clear();
         requestUpdateOutline(event->point, event);
     } else {
         KisTool::endAlternateAction(event, action);
@@ -376,41 +419,20 @@ int KisToolPaint::colorPreviewResourceId(AlternateAction action)
     return resource;
 }
 
-bool KisToolPaint::pickColor(const QPointF &documentPixel,
-                             AlternateAction action)
+void KisToolPaint::slotColorPickingFinished(const KoColor &color)
 {
-    if (action != PickFgNode &&
-        action != PickBgNode &&
-        action != PickFgImage &&
-        action != PickBgImage) {
-
-        return false;
-    }
+    if (!m_pickerStrokeId) return;
 
-    bool fromCurrentNode = action == PickFgNode || action == PickBgNode;
-
-    int resource = colorPreviewResourceId(action);
-
-    KisPaintDeviceSP device = fromCurrentNode ?
-        currentNode()->projection() : image()->projection();
+    canvas()->resourceManager()->setResource(m_pickingResource, color);
 
-    QPoint imagePoint = image()->documentToIntPixel(documentPixel);
-
-    KoColor color;
-    QColor previewColor;
-
-    if (KisToolUtils::pickWrapped(device, imagePoint, &color, image())) {
-        canvas()->resourceManager()->setResource(resource, color);
-
-        KisCanvas2 * kisCanvas = dynamic_cast<KisCanvas2*>(canvas());
-        KIS_ASSERT_RECOVER(kisCanvas) { return true; }
-        previewColor = kisCanvas->displayColorConverter()->toQColor(color);
-    }
+    KisCanvas2 * kisCanvas = dynamic_cast<KisCanvas2*>(canvas());
+    KIS_ASSERT_RECOVER_RETURN(kisCanvas);
+    QColor previewColor = kisCanvas->displayColorConverter()->toQColor(color);
 
-    m_colorPreviewCurrentColor = previewColor;
     m_colorPreviewShowComparePlate = true;
+    m_colorPreviewCurrentColor = previewColor;
 
-    return true;
+    requestUpdateOutline(m_outlineDocPoint, 0);
 }
 
 void KisToolPaint::mousePressEvent(KoPointerEvent *event)
diff --git a/libs/ui/tool/kis_tool_paint.h b/libs/ui/tool/kis_tool_paint.h
index 51ba687..11bd769 100644
--- a/libs/ui/tool/kis_tool_paint.h
+++ b/libs/ui/tool/kis_tool_paint.h
@@ -35,6 +35,7 @@
 
 #include <kis_types.h>
 #include <kis_image.h>
+#include "kis_signal_compressor_with_param.h"
 #include <brushengine/kis_paintop_settings.h>
 
 #include <resources/KoPattern.h>
@@ -158,6 +159,8 @@ private Q_SLOTS:
 
     void activatePickColorDelayed();
 
+    void slotColorPickingFinished(const KoColor &color);
+
 protected Q_SLOTS:
     void updateTabletPressureSamples();
 
@@ -187,6 +190,21 @@ private:
     int colorPreviewResourceId(AlternateAction action);
     QRectF colorPreviewDocRect(const QPointF &outlineDocPoint);
 
+    bool isPickingAction(AlternateAction action);
+
+
+    struct PickingJob {
+        PickingJob() {}
+        PickingJob(QPointF _documentPixel,
+                   AlternateAction _action)
+            : documentPixel(_documentPixel),
+              action(_action) {}
+
+        QPointF documentPixel;
+        AlternateAction action;
+    };
+    void addPickerJob(const PickingJob &pickingJob);
+
 private:
 
     bool m_specialHoverModifier;
@@ -205,6 +223,11 @@ private:
     bool m_isOutlineEnabled;
     std::vector<int> m_standardBrushSizes;
 
+    KisStrokeId m_pickerStrokeId;
+    int m_pickingResource;
+    typedef KisSignalCompressorWithParam<PickingJob> PickingCompressor;
+    QScopedPointer<PickingCompressor> m_colorPickingCompressor;
+
 Q_SIGNALS:
     void sigPaintingFinished();
 };
diff --git a/libs/ui/tool/kis_tool_utils.cpp b/libs/ui/tool/kis_tool_utils.cpp
index 3dfe206..168fa96 100644
--- a/libs/ui/tool/kis_tool_utils.cpp
+++ b/libs/ui/tool/kis_tool_utils.cpp
@@ -27,24 +27,11 @@
 
 namespace KisToolUtils {
 
-    bool pickWrapped(KisPaintDeviceSP dev, QPoint pos, KoColor *color, KisImageSP image)
-    {
-        if (!image->tryBarrierLock()) return false;
-
-        if (image->wrapAroundModePermitted()) {
-            pos = KisWrappedRect::ptToWrappedPt(pos, image->bounds());
-        }
-
-        bool result = pick(dev, pos, color);
-
-        image->unlock();
-        return result;
-    }
-
     bool pick(KisPaintDeviceSP dev, const QPoint& pos, KoColor *color)
     {
         KIS_ASSERT(dev);
         KoColor pickedColor;
+
         dev->pixel(pos.x(), pos.y(), &pickedColor);
         pickedColor.convertTo(dev->compositionSourceColorSpace());
 
diff --git a/libs/ui/tool/kis_tool_utils.h b/libs/ui/tool/kis_tool_utils.h
index 57e5bbd..286181e 100644
--- a/libs/ui/tool/kis_tool_utils.h
+++ b/libs/ui/tool/kis_tool_utils.h
@@ -29,12 +29,6 @@ namespace KisToolUtils {
 
 /**
  * return the color at the given position on the given paint device.
- * NOTE: the function takes wraparound mode and image locking into account
- */
-bool pickWrapped(KisPaintDeviceSP dev, QPoint pos, KoColor *color, KisImageSP image);
-
-/**
- * return the color at the given position on the given paint device.
  */
 bool KRITAUI_EXPORT pick(KisPaintDeviceSP dev, const QPoint& pos, KoColor *color);
 
diff --git a/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.cpp b/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.cpp
new file mode 100644
index 0000000..81c0f48
--- /dev/null
+++ b/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.cpp
@@ -0,0 +1,71 @@
+/*
+ *  Copyright (c) 2016 Dmitry Kazakov <dimula73 at 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 "kis_color_picker_stroke_strategy.h"
+
+#include <KoColor.h>
+
+
+#include "kis_debug.h"
+#include "kis_tool_utils.h"
+#include <kis_wrapped_rect.h>
+#include "kis_default_bounds.h"
+#include "kis_paint_device.h"
+
+
+struct KisColorPickerStrokeStrategy::Private
+{
+    Private() : shouldSkipWork(false) {}
+
+    bool shouldSkipWork;
+};
+
+KisColorPickerStrokeStrategy::KisColorPickerStrokeStrategy()
+    : m_d(new Private)
+{
+    setSupportsWrapAroundMode(true);
+    enableJob(KisSimpleStrokeStrategy::JOB_DOSTROKE);
+}
+
+KisColorPickerStrokeStrategy::~KisColorPickerStrokeStrategy()
+{
+}
+
+void KisColorPickerStrokeStrategy::doStrokeCallback(KisStrokeJobData *data)
+{
+    if (m_d->shouldSkipWork) return;
+
+    Data *d = dynamic_cast<Data*>(data);
+    KIS_ASSERT_RECOVER_RETURN(d);
+
+    KoColor color;
+    bool result = KisToolUtils::pick(d->dev, d->pt, &color);
+
+    emit sigColorUpdated(color);
+}
+
+KisStrokeStrategy* KisColorPickerStrokeStrategy::createLodClone(int levelOfDetail)
+{
+    m_d->shouldSkipWork = true;
+
+    KisColorPickerStrokeStrategy *lodStrategy = new KisColorPickerStrokeStrategy();
+    connect(lodStrategy, &KisColorPickerStrokeStrategy::sigColorUpdated,
+            this, &KisColorPickerStrokeStrategy::sigColorUpdated);
+    return lodStrategy;
+}
+
diff --git a/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.h b/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.h
new file mode 100644
index 0000000..532b150
--- /dev/null
+++ b/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.h
@@ -0,0 +1,65 @@
+/*
+ *  Copyright (c) 2016 Dmitry Kazakov <dimula73 at 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 __KIS_COLOR_PICKER_STROKE_STRATEGY_H
+#define __KIS_COLOR_PICKER_STROKE_STRATEGY_H
+
+#include <QObject>
+#include <QScopedPointer>
+#include "kis_simple_stroke_strategy.h"
+#include "kis_lod_transform.h"
+
+class KoColor;
+
+
+class KisColorPickerStrokeStrategy : public QObject, public KisSimpleStrokeStrategy
+{
+    Q_OBJECT
+public:
+    class Data : public KisStrokeJobData {
+    public:
+        Data(KisPaintDeviceSP _dev, const QPoint _pt)
+            : dev(_dev), pt(_pt)
+        {}
+
+        KisStrokeJobData* createLodClone(int levelOfDetail) {
+            KisLodTransform t(levelOfDetail);
+            const QPoint realPoint = t.map(pt);
+
+            return new Data(dev, realPoint);
+        }
+
+        KisPaintDeviceSP dev;
+        QPoint pt;
+    };
+public:
+    KisColorPickerStrokeStrategy();
+    ~KisColorPickerStrokeStrategy();
+
+    void doStrokeCallback(KisStrokeJobData *data);
+    KisStrokeStrategy* createLodClone(int levelOfDetail);
+
+Q_SIGNALS:
+    void sigColorUpdated(const KoColor &color);
+
+private:
+    struct Private;
+    const QScopedPointer<Private> m_d;
+};
+
+#endif /* __KIS_COLOR_PICKER_STROKE_STRATEGY_H */



More information about the kimageshop mailing list