1 /*
2 * Copyright (c) 2008 Cyrille Berger <cberger@cberger.net>
3 * Copyright (c) 2010 Geoffry Song <goffrie@gmail.com>
4 * Copyright (c) 2014 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
5 * Copyright (c) 2017 Scott Petrovic <scottpetrovic@gmail.com>
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include "ParallelRulerAssistant.h"
23
24 #include "kis_debug.h"
25 #include <klocalizedstring.h>
26
27 #include <QPainter>
28 #include <QPainterPath>
29 #include <QLinearGradient>
30 #include <QTransform>
31
32 #include <kis_canvas2.h>
33 #include <kis_coordinates_converter.h>
34 #include <kis_algebra_2d.h>
35
36 #include <math.h>
37
ParallelRulerAssistant()38 ParallelRulerAssistant::ParallelRulerAssistant()
39 : KisPaintingAssistant("parallel ruler", i18n("Parallel Ruler assistant"))
40 , m_followBrushPosition(false)
41 , m_adjustedPositionValid(false)
42 {
43 }
44
clone(QMap<KisPaintingAssistantHandleSP,KisPaintingAssistantHandleSP> & handleMap) const45 KisPaintingAssistantSP ParallelRulerAssistant::clone(QMap<KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP> &handleMap) const
46 {
47 return KisPaintingAssistantSP(new ParallelRulerAssistant(*this, handleMap));
48 }
49
ParallelRulerAssistant(const ParallelRulerAssistant & rhs,QMap<KisPaintingAssistantHandleSP,KisPaintingAssistantHandleSP> & handleMap)50 ParallelRulerAssistant::ParallelRulerAssistant(const ParallelRulerAssistant &rhs, QMap<KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP> &handleMap)
51 : KisPaintingAssistant(rhs, handleMap)
52 , m_followBrushPosition(rhs.m_followBrushPosition)
53 , m_adjustedPositionValid(rhs.m_adjustedPositionValid)
54 , m_adjustedBrushPosition(rhs.m_adjustedBrushPosition)
55 {
56 }
57
setAdjustedBrushPosition(const QPointF position)58 void ParallelRulerAssistant::setAdjustedBrushPosition(const QPointF position)
59 {
60 m_adjustedBrushPosition = position;
61 m_adjustedPositionValid = true;
62 }
63
endStroke()64 void ParallelRulerAssistant::endStroke()
65 {
66 // Brush stroke ended, guides should follow the brush position again.
67 m_followBrushPosition = false;
68 m_adjustedPositionValid = false;
69 }
70
71
setFollowBrushPosition(bool follow)72 void ParallelRulerAssistant::setFollowBrushPosition(bool follow)
73 {
74 m_followBrushPosition = follow;
75 }
76
project(const QPointF & pt,const QPointF & strokeBegin)77 QPointF ParallelRulerAssistant::project(const QPointF& pt, const QPointF& strokeBegin)
78 {
79 Q_ASSERT(isAssistantComplete());
80
81 //code nicked from the perspective ruler.
82 qreal dx = pt.x() - strokeBegin.x();
83 qreal dy = pt.y() - strokeBegin.y();
84
85 if (dx * dx + dy * dy < 4.0) {
86 return strokeBegin; // allow some movement before snapping
87 }
88
89 //dbgKrita<<strokeBegin<< ", " <<*handles()[0];
90 QLineF snapLine = QLineF(*handles()[0], *handles()[1]);
91 QPointF translation = (*handles()[0]-strokeBegin)*-1.0;
92 snapLine = snapLine.translated(translation);
93
94 dx = snapLine.dx();
95 dy = snapLine.dy();
96
97 const qreal
98 dx2 = dx * dx,
99 dy2 = dy * dy,
100 invsqrlen = 1.0 / (dx2 + dy2);
101 QPointF r(dx2 * pt.x() + dy2 * snapLine.x1() + dx * dy * (pt.y() - snapLine.y1()),
102 dx2 * snapLine.y1() + dy2 * pt.y() + dx * dy * (pt.x() - snapLine.x1()));
103 r *= invsqrlen;
104 return r;
105 //return pt;
106 }
107
adjustPosition(const QPointF & pt,const QPointF & strokeBegin)108 QPointF ParallelRulerAssistant::adjustPosition(const QPointF& pt, const QPointF& strokeBegin)
109 {
110 return project(pt, strokeBegin);
111 }
112
drawAssistant(QPainter & gc,const QRectF & updateRect,const KisCoordinatesConverter * converter,bool cached,KisCanvas2 * canvas,bool assistantVisible,bool previewVisible)113 void ParallelRulerAssistant::drawAssistant(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter* converter, bool cached, KisCanvas2* canvas, bool assistantVisible, bool previewVisible)
114 {
115 gc.save();
116 gc.resetTransform();
117 QPointF mousePos(0,0);
118
119 if (canvas){
120 //simplest, cheapest way to get the mouse-position//
121 mousePos= canvas->canvasWidget()->mapFromGlobal(QCursor::pos());
122 }
123 else {
124 //...of course, you need to have access to a canvas-widget for that.//
125 mousePos = QCursor::pos();//this'll give an offset//
126 dbgFile<<"canvas does not exist in ruler, you may have passed arguments incorrectly:"<<canvas;
127 }
128
129 if (isAssistantComplete() && isSnappingActive() && previewVisible==true) {
130 //don't draw if invalid.
131 QTransform initialTransform = converter->documentToWidgetTransform();
132 QLineF snapLine= QLineF(initialTransform.map(*handles()[0]), initialTransform.map(*handles()[1]));
133
134 if (m_followBrushPosition && m_adjustedPositionValid) {
135 mousePos = initialTransform.map(m_adjustedBrushPosition);
136 }
137
138 QPointF translation = (initialTransform.map(*handles()[0])-mousePos)*-1.0;
139 snapLine= snapLine.translated(translation);
140
141 QRect viewport= gc.viewport();
142 KisAlgebra2D::intersectLineRect(snapLine, viewport);
143
144
145 QPainterPath path;
146 path.moveTo(snapLine.p1());
147 path.lineTo(snapLine.p2());
148
149 drawPreview(gc, path);//and we draw the preview.
150 }
151 gc.restore();
152
153 KisPaintingAssistant::drawAssistant(gc, updateRect, converter, cached, canvas, assistantVisible, previewVisible);
154
155 }
156
drawCache(QPainter & gc,const KisCoordinatesConverter * converter,bool assistantVisible)157 void ParallelRulerAssistant::drawCache(QPainter& gc, const KisCoordinatesConverter *converter, bool assistantVisible)
158 {
159 if (assistantVisible == false || !isAssistantComplete()){
160 return;
161 }
162
163 QTransform initialTransform = converter->documentToWidgetTransform();
164
165 // Draw the line
166 QPointF p1 = *handles()[0];
167 QPointF p2 = *handles()[1];
168
169 gc.setTransform(initialTransform);
170 QPainterPath path;
171 path.moveTo(p1);
172 path.lineTo(p2);
173 drawPath(gc, path, isSnappingActive());
174
175 }
176
getEditorPosition() const177 QPointF ParallelRulerAssistant::getEditorPosition() const
178 {
179 return (*handles()[0] + *handles()[1]) * 0.5;
180 }
181
isAssistantComplete() const182 bool ParallelRulerAssistant::isAssistantComplete() const
183 {
184 return handles().size() >= 2;
185 }
186
ParallelRulerAssistantFactory()187 ParallelRulerAssistantFactory::ParallelRulerAssistantFactory()
188 {
189 }
190
~ParallelRulerAssistantFactory()191 ParallelRulerAssistantFactory::~ParallelRulerAssistantFactory()
192 {
193 }
194
id() const195 QString ParallelRulerAssistantFactory::id() const
196 {
197 return "parallel ruler";
198 }
199
name() const200 QString ParallelRulerAssistantFactory::name() const
201 {
202 return i18n("Parallel Ruler");
203 }
204
createPaintingAssistant() const205 KisPaintingAssistant* ParallelRulerAssistantFactory::createPaintingAssistant() const
206 {
207 return new ParallelRulerAssistant;
208 }
209