1 /*
2 
3 Pencil2D - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2012-2020 Matthew Chiawen Chang
6 
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2 of the License.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 */
17 
18 #include "eyedroppertool.h"
19 
20 #include <QPainter>
21 #include <QPixmap>
22 #include <QBitmap>
23 #include <QtMath>
24 #include "pointerevent.h"
25 
26 #include "vectorimage.h"
27 #include "layervector.h"
28 #include "layerbitmap.h"
29 #include "colormanager.h"
30 #include "object.h"
31 #include "editor.h"
32 #include "layermanager.h"
33 #include "scribblearea.h"
34 #include "util.h"
35 
EyedropperTool(QObject * parent)36 EyedropperTool::EyedropperTool(QObject* parent) : BaseTool(parent)
37 {
38 }
39 
loadSettings()40 void EyedropperTool::loadSettings()
41 {
42     properties.width = -1;
43     properties.feather = -1;
44     properties.useFeather = false;
45     properties.useAA = -1;
46 }
47 
cursor()48 QCursor EyedropperTool::cursor()
49 {
50     if (mEditor->preference()->isOn(SETTING::TOOL_CURSOR))
51     {
52         return QCursor(QPixmap(":icons/eyedropper.png"), 0, 15);
53     }
54     else
55     {
56         return QCursor(QPixmap(":icons/cross.png"), 10, 10);
57     }
58 }
59 
cursor(const QColor color)60 QCursor EyedropperTool::cursor(const QColor color)
61 {
62     QPixmap icon(":icons/eyedropper.png");
63 
64     QPixmap pixmap(32, 32);
65     pixmap.fill(Qt::transparent);
66 
67     QPainter painter(&pixmap);
68     painter.drawPixmap(0, 0, icon);
69 
70     painter.setBrush(Qt::white);
71     painter.drawRect(17, 17, 13, 13);
72     painter.setPen(QPen(Qt::white, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
73     painter.setBrush(color);
74     painter.drawRect(16, 16, 15, 15);
75     painter.end();
76 
77     return QCursor(pixmap, 0, 15);
78 }
79 
pointerPressEvent(PointerEvent *)80 void EyedropperTool::pointerPressEvent(PointerEvent*)
81 {}
82 
pointerMoveEvent(PointerEvent *)83 void EyedropperTool::pointerMoveEvent(PointerEvent*)
84 {
85     Layer* layer = mEditor->layers()->currentLayer();
86     if (layer == nullptr) { return; }
87 
88     if (layer->type() == Layer::BITMAP)
89     {
90         QColor pickedColor = getBitmapColor(static_cast<LayerBitmap*>(layer));
91         if (pickedColor.isValid())
92         {
93             mScribbleArea->setCursor(cursor(pickedColor));
94         }
95         else
96         {
97             mScribbleArea->setCursor(cursor());
98         }
99     }
100     if (layer->type() == Layer::VECTOR)
101     {
102         int pickedColor = getVectorColor(static_cast<LayerVector*>(layer));
103         if (pickedColor >= 0)
104         {
105             mScribbleArea->setCursor(cursor(mEditor->object()->getColor(pickedColor).color));
106         }
107         else
108         {
109             mScribbleArea->setCursor(cursor());
110         }
111     }
112 }
113 
pointerReleaseEvent(PointerEvent * event)114 void EyedropperTool::pointerReleaseEvent(PointerEvent* event)
115 {
116     if (event->button() == Qt::LeftButton)
117     {
118         updateFrontColor();
119 
120         // reset cursor
121         mScribbleArea->setCursor(cursor());
122     }
123 }
124 
updateFrontColor()125 void EyedropperTool::updateFrontColor()
126 {
127     Layer* layer = mEditor->layers()->currentLayer();
128     if (layer == nullptr) { return; }
129     if (layer->type() == Layer::BITMAP)
130     {
131         QColor pickedColor = getBitmapColor(static_cast<LayerBitmap*>(layer));
132         if (pickedColor.isValid())
133         {
134             mEditor->color()->setColor(pickedColor);
135         }
136     }
137     else if (layer->type() == Layer::VECTOR)
138     {
139         int pickedColor = getVectorColor(static_cast<LayerVector*>(layer));
140         if (pickedColor >= 0)
141         {
142             mEditor->color()->setColorNumber(pickedColor);
143         }
144     }
145 }
146 
getBitmapColor(LayerBitmap * layer)147 QColor EyedropperTool::getBitmapColor(LayerBitmap* layer)
148 {
149     BitmapImage* targetImage = layer->getLastBitmapImageAtFrame(mEditor->currentFrame(), 0);
150     if (targetImage == nullptr || !targetImage->contains(getCurrentPoint())) return QColor();
151 
152     QColor pickedColour;
153     const QRgb pixelColor = targetImage->constScanLine(qFloor(getCurrentPoint().x()),
154                                                        qFloor(getCurrentPoint().y()));
155     pickedColour.setRgba(pixelColor);
156 
157     if (pickedColour.alpha() <= 0) pickedColour = QColor();
158     return pickedColour;
159 }
160 
getVectorColor(LayerVector * layer)161 int EyedropperTool::getVectorColor(LayerVector* layer)
162 {
163     auto vectorImage = static_cast<VectorImage*>(layer->getLastKeyFrameAtPosition(mEditor->currentFrame()));
164     if (vectorImage == nullptr) return -1;
165 
166     // Check curves
167     const qreal toleranceDistance = 10.0;
168     const QList<int> closestCurves = vectorImage->getCurvesCloseTo(getCurrentPoint(), toleranceDistance);
169     const QList<int> visibleClosestCurves = filter(closestCurves, [vectorImage](int i) { return vectorImage->isCurveVisible(i); });
170 
171     if (!visibleClosestCurves.isEmpty())
172     {
173         return vectorImage->getCurvesColor(visibleClosestCurves.last());
174     }
175 
176     // Check fills
177     int colorNumber = vectorImage->getColorNumber(getCurrentPoint());
178     return colorNumber;
179 }
180