Krita Source Code Documentation
Loading...
Searching...
No Matches
KisGridDecoration Class Reference

#include <kis_grid_decoration.h>

+ Inheritance diagram for KisGridDecoration:

Classes

struct  Private
 

Public Member Functions

 KisGridDecoration (KisView *parent)
 
void setGridConfig (const KisGridConfig &config)
 
 ~KisGridDecoration () override
 
- Public Member Functions inherited from KisCanvasDecoration
const QString & id () const
 
 KisCanvasDecoration (const QString &id, QPointer< KisView >parent)
 
virtual void notifyWindowMinimized (bool minimized)
 
void paint (QPainter &gc, const QRectF &updateRect, const KisCoordinatesConverter *converter, KisCanvas2 *canvas)
 
int priority () const
 
virtual void setCanvasWidget (KisCanvasWidgetBase *canvas)
 
void setView (QPointer< KisView > imageView)
 
bool visible () const
 
 ~KisCanvasDecoration () override
 
- Public Member Functions inherited from KisShared
bool deref ()
 
bool ref ()
 
int refCount ()
 
QAtomicInt * sharedWeakReference ()
 

Protected Member Functions

void drawDecoration (QPainter &gc, const QRectF &updateArea, const KisCoordinatesConverter *converter, KisCanvas2 *canvas) override
 
- Protected Member Functions inherited from KisCanvasDecoration
int decorationThickness () const
 
void setPriority (int value)
 
QPointer< KisViewview () const
 
- Protected Member Functions inherited from KisShared
 KisShared ()
 
 ~KisShared ()
 

Private Attributes

const QScopedPointer< Privatem_d
 

Additional Inherited Members

- Public Slots inherited from KisCanvasDecoration
virtual void setVisible (bool v)
 
void toggleVisibility ()
 
- Static Public Member Functions inherited from KisCanvasDecoration
static bool comparePriority (KisCanvasDecorationSP decoration1, KisCanvasDecorationSP decoration2)
 

Detailed Description

Definition at line 19 of file kis_grid_decoration.h.

Constructor & Destructor Documentation

◆ KisGridDecoration()

KisGridDecoration::KisGridDecoration ( KisView * parent)

Definition at line 29 of file kis_grid_decoration.cpp.

30 : KisCanvasDecoration("grid", parent),
31 m_d(new Private)
32{
33 setPriority(0);
34}
KisCanvasDecoration(const QString &id, QPointer< KisView >parent)
const QScopedPointer< Private > m_d

References KisCanvasDecoration::setPriority().

◆ ~KisGridDecoration()

KisGridDecoration::~KisGridDecoration ( )
override

Definition at line 36 of file kis_grid_decoration.cpp.

37{
38
39}

Member Function Documentation

◆ drawDecoration()

void KisGridDecoration::drawDecoration ( QPainter & gc,
const QRectF & updateArea,
const KisCoordinatesConverter * converter,
KisCanvas2 * canvas )
overrideprotectedvirtual

Implements KisCanvasDecoration.

Definition at line 46 of file kis_grid_decoration.cpp.

47{
48 if (!m_d->config.showGrid()) return;
49
50 Q_UNUSED(canvas);
51
52 QTransform transform = converter->imageToWidgetTransform();
53
54 const qreal scale = KoUnit::approxTransformScale(transform);
55 const int minWidgetSize = 3;
56 const int effectiveSize = qMin(m_d->config.spacing().x(), m_d->config.spacing().y());
57
58 int scaleCoeff = 1;
59 quint32 subdivision = m_d->config.subdivision();
60
61 while (qFloor(scale * scaleCoeff * effectiveSize) <= minWidgetSize) {
62 if (subdivision > 1) {
63 scaleCoeff = subdivision;
64 subdivision = 1;
65 } else {
66 scaleCoeff *= 2;
67 }
68
69 if (scaleCoeff > 32768) {
70 qWarning() << "WARNING: Grid Scale Coeff is too high! That is surely a bug!";
71 return;
72 }
73 }
74
75 QPen mainPen = m_d->config.penMain();
76 QPen subdivisionPen = m_d->config.penSubdivision();
77
79 subdivisionPen.setColor(canvas->displayRendererInterface()->convertColorToDisplayColorSpace(KoColor(subdivisionPen.color(), KoColorSpaceRegistry::instance()->rgb8())));
80
81 gc.save();
82 gc.setTransform(transform);
83
84 const QRect imageRectInImagePixels = converter->imageRectInImagePixels();
85 const QRectF updateRectInImagePixels =
86 converter->documentToImage(updateArea) &
87 imageRectInImagePixels;
88
89 // for angles. This will later be a combobox to select different types of options
90 // also add options to hide specific lines (vertical, horizontal, angle 1, etc
91 KisGridConfig::GridType gridType = m_d->config.gridType();
92
93 if (gridType == KisGridConfig::GRID_RECTANGULAR) {
94 gc.setRenderHints(QPainter::Antialiasing, false);
95 qreal x1, y1, x2, y2;
96 updateRectInImagePixels.getCoords(&x1, &y1, &x2, &y2);
97
98 // compensate the fact the getCoordt returns off-by-one pixel
99 // at the bottom right of the rect.
100 x2++;
101 y2++;
102
103 if (m_d->config.xSpacingActive()) {
104 // vertical lines
105 int offset = 0;
106 if (m_d->config.offsetActive()) {
107 offset = m_d->config.offset().x();
108 }
109 const int step = scaleCoeff * m_d->config.spacing().x();
110 const int lineIndexFirst = qCeil((x1 - offset) / step);
111 const int lineIndexLast = qFloor((x2 - offset) / step);
112
113 if (mainPen.style() != Qt::SolidLine) {
114 mainPen.setDashOffset(y1 * scale);
115 }
116 if (subdivisionPen.style() != Qt::SolidLine) {
117 subdivisionPen.setDashOffset(y1 * scale);
118 }
119
120 for (int i = lineIndexFirst; i <= lineIndexLast; i++) {
121 int w = offset + i * step;
122
123 gc.setPen(i % subdivision == 0 ? mainPen : subdivisionPen);
124 // we adjusted y2 to draw the grid correctly, clip it now...
125 gc.drawLine(QPointF(w, y1),QPointF(w, qMin(y2, qreal(imageRectInImagePixels.bottom() + 1))));
126 }
127 }
128
129 if (m_d->config.ySpacingActive()) {
130 // horizontal lines
131 int offset = 0;
132 if (m_d->config.offsetActive()) {
133 offset = m_d->config.offset().y();
134 }
135 const int step = scaleCoeff * m_d->config.spacing().y();
136 const int lineIndexFirst = qCeil((y1 - offset) / step);
137 const int lineIndexLast = qFloor((y2 - offset) / step);
138
139 if (mainPen.style() != Qt::SolidLine) {
140 mainPen.setDashOffset(x1 * scale);
141 }
142 if (subdivisionPen.style() != Qt::SolidLine) {
143 subdivisionPen.setDashOffset(x1 * scale);
144 }
145
146 for (int i = lineIndexFirst; i <= lineIndexLast; i++) {
147 int w = offset + i * step;
148
149 gc.setPen(i % subdivision == 0 ? mainPen : subdivisionPen);
150 // we adjusted x2 to draw the grid correctly, clip it now...
151 gc.drawLine(QPointF(x1, w),QPointF(qMin(x2, qreal(imageRectInImagePixels.right() + 1)), w));
152 }
153 }
154 } else if (gridType == KisGridConfig::GRID_ISOMETRIC_LEGACY) {
155 qreal x1, y1, x2, y2;
156
157 // get true coordinates, not just the updateArea
158 QRectF trueImageRect = converter->imageRectInImagePixels();
159 trueImageRect.getCoords(&x1, &y1, &x2, &y2);
160
161 // compensate the fact the getCoordt returns off-by-one pixel
162 // at the bottom right of the rect.
163 x2++;
164 y2++;
165
166 int offset = 0;
167 int offsetY = 0;
168 if (m_d->config.offsetActive()) {
169 offset = m_d->config.offset().x();
170 offsetY = m_d->config.offset().y();
171 }
172 const int cellSpacing = m_d->config.cellSpacing();
173
174 gc.setClipping(true);
175 gc.setClipRect(updateRectInImagePixels, Qt::IntersectClip);
176
177 // left angle
178 if (m_d->config.angleLeftActive()) {
179 const qreal gridXAngle = m_d->config.angleLeft();
180 const qreal bottomRightOfImageY = y2; // this should be the height of the image
181 qreal finalY = 0.0;
182
183 // figure out the spacing based off the angle. The spacing needs to be perpendicular to the angle,
184 // so we need to do a bit of trig to get the correct spacing.
185 qreal correctedAngleSpacing = cellSpacing;
186 if (gridXAngle > 0.0) {
187 correctedAngleSpacing = cellSpacing / qCos(qDegreesToRadians(gridXAngle));
188 gc.setRenderHints(QPainter::Antialiasing, true);
189 } else {
190 // horizontal line: don't want to be antialiased
191 gc.setRenderHints(QPainter::Antialiasing, false);
192 }
193
194 qreal counter = qFloor((-(offset + offsetY)) / correctedAngleSpacing);
195
196 while (finalY < bottomRightOfImageY) {
197
198 const qreal w = (counter * correctedAngleSpacing) + offsetY + offset;
199 gc.setPen(mainPen);
200
201 // calculate where the ending point will be based off the angle
202 const qreal startingY = w;
203 const qreal horizontalDistance = x2;
204
205 // qTan takes radians, so convert first before sending it
206 const qreal length2 = qTan(qDegreesToRadians(gridXAngle)) * x2;
207
208 finalY = startingY - length2;
209
210 gc.drawLine(QPointF(x1, w), QPointF(horizontalDistance, finalY));
211
212 counter = counter + 1.0;
213 }
214 }
215
216 // right angle (almost the same thing, except starting the lines on the right side)
217 if (m_d->config.angleRightActive()) {
218 const qreal gridXAngle = m_d->config.angleRight(); // TODO: add another angle property
219 const qreal bottomLeftOfImageY = y2;
220
221 // figure out the spacing based off the angle
222 qreal correctedAngleSpacing = cellSpacing;
223 if (gridXAngle > 0.0) {
224 correctedAngleSpacing = cellSpacing / qCos(qDegreesToRadians(gridXAngle));
225 gc.setRenderHints(QPainter::Antialiasing, true);
226 } else {
227 // horizontal line: don't want to be antialiased
228 gc.setRenderHints(QPainter::Antialiasing, false);
229 }
230
231 // distance is the same (width of the image)
232 const qreal horizontalDistance = x2;
233 // qTan takes radians, so convert first before sending it
234 const qreal length2 = qTan(qDegreesToRadians(gridXAngle)) * horizontalDistance;
235
236 // let's get x, y of the line that starts in the top right corder
237 const qreal yLower = 0.0;
238 const qreal yHigher = yLower - length2;
239
240 const qreal yLeftFirst = qCeil(yHigher / correctedAngleSpacing) * correctedAngleSpacing;
241 const qreal additionalOffset = yLeftFirst - yHigher;
242 qreal finalY = 0.0;
243 qreal counter = qFloor((-(offsetY - offset)) / correctedAngleSpacing);
244
245 while (finalY < bottomLeftOfImageY) {
246
247 const qreal w = (counter * correctedAngleSpacing) + offsetY - offset + additionalOffset;
248 gc.setPen(mainPen);
249
250 // calculate where the ending point will be based off the angle
251 const qreal startingY = w;
252
253 finalY = startingY - length2;
254
255 gc.drawLine(QPointF(x2, w), QPointF(0.0, finalY));
256
257 counter = counter + 1.0;
258 }
259 }
260 } else if (gridType == KisGridConfig::GRID_ISOMETRIC) {
261 qreal x1, y1, xRight, yBottom;
262
263 // get true coordinates, not just the updateArea
264 QRectF trueImageRect = converter->imageRectInImagePixels();
265 trueImageRect.getCoords(&x1, &y1, &xRight, &yBottom);
266
267 // compensate the fact the getCoordt returns off-by-one pixel
268 // at the bottom right of the rect.
269 xRight++;
270 yBottom++;
271
272 const KisGridConfig::TrigoCache trigoCache = m_d->config.trigoCache();
273
274 int offsetX = 0;
275 int offsetY = 0;
276 if (m_d->config.offsetActive()) {
277 offsetX = trigoCache.correctedAngleRightOffsetX;
278 offsetY = m_d->config.offset().y();
279 }
280
281 gc.setClipping(true);
282 gc.setClipRect(updateRectInImagePixels, Qt::IntersectClip);
283
284 // left angle
285 if (trigoCache.correctedAngleLeftCellSize > 0 && m_d->config.angleLeftActive()) {
286 if (m_d->config.angleLeft() > 0.0) {
287 gc.setRenderHints(QPainter::Antialiasing, true);
288 } else {
289 // horizontal line: don't want to be antialiased
290 gc.setRenderHints(QPainter::Antialiasing, false);
291 }
292
293 const qreal length2 = trigoCache.tanAngleLeft * xRight;
294
295 // let's get x, y of the line that starts in the top right corner
296 const qreal yLower = 0.0;
297 const qreal yHigher = yLower - length2;
298
299 const qreal yLeftFirst = qCeil(yHigher / trigoCache.correctedAngleLeftCellSize) * trigoCache.correctedAngleLeftCellSize;
300 const qreal additionalOffset = yLeftFirst - yHigher;
301
302 qreal finalY = 0.0;
303
304 // define line number used to determinate if is a subdivision or not
305 int subdivisionIndex = qCeil(yHigher / trigoCache.correctedAngleLeftCellSize);
306
307 qreal startingY = yLeftFirst + offsetY + offsetX + additionalOffset;
308
309 while (finalY < yBottom) {
310 // calculate where the ending point will be based off the angle
311 finalY = startingY - length2;
312
313 gc.setPen(qAbs(subdivisionIndex) % subdivision == 0 ? mainPen : subdivisionPen);
314 gc.drawLine(QPointF(0.0, startingY), QPointF(xRight, finalY));
315
316 subdivisionIndex++;
317 startingY += trigoCache.correctedAngleLeftCellSize;
318 }
319 }
320
321 // right angle (almost the same thing, except starting the lines on the right side)
322 if (trigoCache.correctedAngleRightCellSize > 0 && m_d->config.angleRightActive()) {
323 if (m_d->config.angleRight() > 0.0) {
324 gc.setRenderHints(QPainter::Antialiasing, true);
325 } else {
326 // horizontal line: don't want to be antialiased
327 gc.setRenderHints(QPainter::Antialiasing, false);
328 }
329
330 const qreal length2 = trigoCache.tanAngleRight * xRight;
331
332 // let's get x, y of the line that starts in the top right corner
333 const qreal yLower = 0.0;
334 const qreal yHigher = yLower - length2;
335
336 const qreal yLeftFirst = qCeil(yHigher / trigoCache.correctedAngleRightCellSize) * trigoCache.correctedAngleRightCellSize;
337 const qreal additionalOffset = yLeftFirst - yHigher;
338
339 qreal finalY = 0.0;
340
341 // define line number used to determinate if is a subdivision or not
342 int subdivisionIndex = qCeil(yHigher / trigoCache.correctedAngleRightCellSize);
343
344 qreal startingY = yLeftFirst + offsetY - offsetX + additionalOffset;
345
346 while (finalY < yBottom) {
347 // calculate where the ending point will be based off the angle
348 finalY = startingY - length2;
349
350 gc.setPen(qAbs(subdivisionIndex) % subdivision == 0 ? mainPen : subdivisionPen);
351 gc.drawLine(QPointF(xRight, startingY), QPointF(0.0, finalY));
352
353 subdivisionIndex++;
354 startingY += trigoCache.correctedAngleRightCellSize;
355 }
356 }
357
358 // vertical
359 if (trigoCache.verticalSpace > 0) {
360 QPen verticalPen = m_d->config.penVertical();
361 if (verticalPen.style() != Qt::SolidLine) {
362 verticalPen.setDashOffset(updateRectInImagePixels.top() * scale);
363 }
364 gc.setPen(verticalPen);
365 gc.setRenderHints(QPainter::Antialiasing, false);
366
367 int offset = 0;
368 if (m_d->config.offsetActive()) {
369 offset = m_d->config.offset().x();
370 }
371
372 qreal pX = (xRight - x1)/(2*trigoCache.verticalSpace);
373 pX = offset + (pX - qFloor(pX)) * trigoCache.verticalSpace;
374 pX = pX - trigoCache.verticalSpace * qFloor(pX/trigoCache.verticalSpace);
375
376 while(pX <= updateRectInImagePixels.right()) {
377 if (pX > updateRectInImagePixels.left()) {
378 gc.drawLine(QPointF(pX, updateRectInImagePixels.top()),QPointF(pX, qMin(yBottom, qreal(updateRectInImagePixels.bottom() + 1))));
379 }
380 pX += trigoCache.verticalSpace;
381 }
382 }
383 }
384
385 gc.restore();
386}
KoColorDisplayRendererInterface * displayRendererInterface() const override
displayRendererInterface The display renderer interface has a number of color conversion functions wh...
_Private::Traits< T >::Result documentToImage(const T &obj) const
virtual QColor convertColorToDisplayColorSpace(const KoColor color) const =0
convertColorToDisplayColorSpace
static qreal approxTransformScale(const QTransform &t)
Definition KoUnit.cpp:387
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())

References KoUnit::approxTransformScale(), KoColorDisplayRendererInterface::convertColorToDisplayColorSpace(), KisGridConfig::TrigoCache::correctedAngleLeftCellSize, KisGridConfig::TrigoCache::correctedAngleRightCellSize, KisGridConfig::TrigoCache::correctedAngleRightOffsetX, KisCanvas2::displayRendererInterface(), KisCoordinatesConverter::documentToImage(), KisGridConfig::GRID_ISOMETRIC, KisGridConfig::GRID_ISOMETRIC_LEGACY, KisGridConfig::GRID_RECTANGULAR, KisCoordinatesConverter::imageRectInImagePixels(), KisCoordinatesConverter::imageToWidgetTransform(), KoColorSpaceRegistry::instance(), m_d, KoColorSpaceRegistry::rgb8(), KisGridConfig::TrigoCache::tanAngleLeft, KisGridConfig::TrigoCache::tanAngleRight, and KisGridConfig::TrigoCache::verticalSpace.

◆ setGridConfig()

void KisGridDecoration::setGridConfig ( const KisGridConfig & config)

Definition at line 41 of file kis_grid_decoration.cpp.

42{
43 m_d->config = config;
44}

References m_d.

Member Data Documentation

◆ m_d

const QScopedPointer<Private> KisGridDecoration::m_d
private

Definition at line 33 of file kis_grid_decoration.h.


The documentation for this class was generated from the following files: