Krita Source Code Documentation
Loading...
Searching...
No Matches
KoCreatePathTool.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 *
3 * SPDX-FileCopyrightText: 2006 Thorsten Zachmann <zachmann@kde.org>
4 * SPDX-FileCopyrightText: 2008-2010 Jan Hambrecht <jaham@gmx.net>
5 *
6 * SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8
9#include "KoCreatePathTool.h"
10#include "KoCreatePathTool_p.h"
11
12#include <KoUnit.h>
13#include "KoPointerEvent.h"
14#include "KoPathShape.h"
15#include "KoSelection.h"
17#include "KoShapeStroke.h"
18#include "KoCanvasBase.h"
20#include <KoColor.h>
25#include <KisAngleSelector.h>
26
27#include <klocalizedstring.h>
28
29#include <QCheckBox>
30#include <QHBoxLayout>
31#include <QPainter>
32#include <QSpinBox>
33#include <QVBoxLayout>
34
39
43
45{
46 Q_D(const KoCreatePathTool);
47
48 QRectF dirtyRect;
49
50 if (pathStarted()) {
51 dirtyRect |= kisGrowRect(d->shape->boundingRect(), handleDocRadius());
52 }
53
54 if (d->hoveredPoint) {
55 dirtyRect |= kisGrowRect(d->hoveredPoint->boundingRect(false), handleDocRadius());
56 }
57
58 if (d->activePoint) {
59 dirtyRect |= kisGrowRect(d->activePoint->boundingRect(false), handleDocRadius());
60
61 if (d->pointIsDragged) {
62 // the path is not closed, therefore the point is not marked as
63 // active inside the path itself
64 dirtyRect |= handlePaintRect(
65 d->activePoint->parent()->shapeToDocument(
66 d->activePoint->controlPoint2()));
67 }
68
69 }
70
71 if (canvas()->snapGuide()->isSnapping()) {
72 dirtyRect |= canvas()->snapGuide()->boundingRect();
73 }
74
75 return dirtyRect;
76}
77
78void KoCreatePathTool::paint(QPainter &painter, const KoViewConverter &converter)
79{
81
83
84 if (pathStarted()) {
85
86 painter.save();
87 paintPath(*(d->shape), painter, converter);
88 painter.restore();
89
91 KoShape::createHandlePainterHelperView(&painter, d->shape, converter, d->handleRadius, d->decorationThickness);
92
93 const bool firstPointActive = d->firstPoint == d->activePoint;
94
95 if (d->pointIsDragged || firstPointActive) {
96 const bool onlyPaintActivePoints = false;
97 KoPathPoint::PointTypes paintFlags = KoPathPoint::ControlPoint2;
99 if (d->activePoint->activeControlPoint1()) {
100 paintFlags |= KoPathPoint::ControlPoint1;
101 }
102
104 d->activePoint->paint(helper, paintFlags, onlyPaintActivePoints);
105 }
106
107 if (!firstPointActive) {
108 helper.setHandleStyle(d->mouseOverFirstPoint ?
111 d->firstPoint->paint(helper, KoPathPoint::Node);
112 }
113 }
114
115 if (d->hoveredPoint) {
116 KisHandlePainterHelper helper = KoShape::createHandlePainterHelperView(&painter, d->hoveredPoint->parent(), converter, d->handleRadius, d->decorationThickness);
118 d->hoveredPoint->paint(helper, KoPathPoint::Node);
119 }
120
121 painter.save();
122 painter.setTransform(converter.documentToView(), true);
123 canvas()->snapGuide()->paint(painter, converter, canvas()->displayRendererInterface());
124 painter.restore();
125}
126
127void KoCreatePathTool::paintPath(KoPathShape& pathShape, QPainter &painter, const KoViewConverter &converter)
128{
129 Q_D(KoCreatePathTool);
130 painter.setTransform(pathShape.absoluteTransformation() *
131 converter.documentToView() *
132 painter.transform());
133 painter.save();
134
135 pathShape.paint(painter);
136 painter.restore();
137
138 if (pathShape.stroke()) {
139 painter.save();
140 pathShape.stroke()->paint(d->shape, painter);
141 painter.restore();
142 }
143}
144
146{
147 Q_D(KoCreatePathTool);
148
149 // When using touch drawing, we only ever receive move events after the
150 // finger has pressed down. We have to issue an artificial move here so that
151 // the tool's state is updated properly to handle the press.
152 if (event->isTouchEvent()) {
153 handleMouseMove(event, false);
154 }
155
156 //Right click removes last point
157 if (event->button() == Qt::RightButton) {
159 return;
160 }
161
162 const bool isOverFirstPoint = d->shape &&
163 handleGrabRect(d->firstPoint->point()).contains(event->point);
164
165 const bool haveCloseModifier = d->enableClosePathShortcut
166 && d->shape
167 && d->shape->pointCount() > 2
168 && (event->modifiers() & Qt::ShiftModifier);
169
170 if ((event->button() == Qt::LeftButton) && haveCloseModifier && !isOverFirstPoint) {
172 return;
173 }
174
175 d->finishAfterThisPoint = false;
176
177 if (d->shape && pathStarted()) {
178 if (isOverFirstPoint) {
179 d->activePoint->setPoint(d->firstPoint->point());
180 canvas()->updateCanvas(d->shape->boundingRect());
181 canvas()->updateCanvas(canvas()->snapGuide()->boundingRect());
182
183 if (haveCloseModifier) {
184 d->shape->closeMerge();
185 // we are closing the path, so reset the existing start path point
186 d->existingStartPoint = 0;
187 // finish path
188 endPath();
189 } else {
190 // the path shape will get closed when the user releases
191 // the mouse button
192 d->finishAfterThisPoint = true;
194 }
195 } else {
196 QPointF point = canvas()->snapGuide()->snap(event->point, event->modifiers());
197
198 // check whether we hit an start/end node of an existing path
199 d->existingEndPoint = d->endPointAtPosition(point);
200 if (d->existingEndPoint.isValid() && d->existingEndPoint != d->existingStartPoint) {
201 point = d->existingEndPoint.path->shapeToDocument(d->existingEndPoint.point->point());
202 d->activePoint->setPoint(point);
203 // finish path
204 endPath();
205 } else {
206 d->activePoint->setPoint(point);
208 }
209 }
210 } else {
211 beginShape();
212
213 KoPathShape *pathShape = new KoPathShape();
214 d->shape = pathShape;
215 pathShape->setShapeId(KoPathShapeId);
216
217 KoShapeStrokeSP stroke(new KoShapeStroke());
218 const qreal size = canvas()->resourceManager()->resource(KoCanvasResource::Size).toReal();
219
220 stroke->setLineWidth(canvas()->unit().fromUserValue(size));
221 stroke->setColor(canvas()->resourceManager()->foregroundColor().toQColor());
222
223 pathShape->setStroke(stroke);
224 QPointF point = canvas()->snapGuide()->snap(event->point, event->modifiers());
225
226 // check whether we hit an start/end node of an existing path
227 d->existingStartPoint = d->endPointAtPosition(point);
228
229 if (d->existingStartPoint.isValid()) {
230 point = d->existingStartPoint.path->shapeToDocument(d->existingStartPoint.point->point());
231 }
232
233 d->activePoint = pathShape->moveTo(point);
234 d->firstPoint = d->activePoint;
235
237
238 d->angleSnapStrategy = new AngleSnapStrategy(d->angleSnappingDelta, d->angleSnapStatus);
239 canvas()->snapGuide()->addCustomSnapStrategy(d->angleSnapStrategy);
240
242 }
243
244 d->dragStartPoint = event->point;
245
246 if (d->angleSnapStrategy)
247 d->angleSnapStrategy->setStartPoint(d->activePoint->point());
248}
249
251{
252 Q_D(const KoCreatePathTool);
253 return ((bool) d->shape);
254}
255
257{
258 return addPathShapeImpl(pathShape, true);
259}
260
262{
263 Q_D(KoCreatePathTool);
264 d->enableClosePathShortcut = value;
265}
266
274
276{
277 handleMouseMove(event, true);
278}
279
280void KoCreatePathTool::handleMouseMove(const KoPointerEvent *event, bool considerDrag)
281{
282 Q_D(KoCreatePathTool);
283
284 d->hoveredPoint = d->endPointAtPosition(event->point);
285
286 if (!pathStarted()) {
287 canvas()->snapGuide()->snap(event->point, event->modifiers());
289
290 d->mouseOverFirstPoint = false;
291 return;
292 }
293
294 d->mouseOverFirstPoint = handleGrabRect(d->firstPoint->point()).contains(event->point);
295
296 QPointF snappedPosition = canvas()->snapGuide()->snap(event->point, event->modifiers());
297
298 if (considerDrag && (event->buttons() & Qt::LeftButton)) {
299 if (d->pointIsDragged ||
300 !handleGrabRect(d->dragStartPoint).contains(event->point)) {
301
302 d->pointIsDragged = true;
303 QPointF offset = snappedPosition - d->activePoint->point();
304 d->activePoint->setControlPoint2(d->activePoint->point() + offset);
305 // pressing <alt> stops controls points moving symmetrically
306 if ((event->modifiers() & Qt::AltModifier) == 0) {
307 d->activePoint->setControlPoint1(d->activePoint->point() - offset);
308 }
309 }
310 } else {
311 d->activePoint->setPoint(snappedPosition);
312
313 if (!d->prevPointWasDragged && d->autoSmoothCurves) {
314 KoPathPointIndex index = d->shape->pathPointIndex(d->activePoint);
315 if (index.second > 0) {
316
317 KoPathPointIndex prevIndex(index.first, index.second - 1);
318 KoPathPoint *prevPoint = d->shape->pointByIndex(prevIndex);
319
320 if (prevPoint) {
321 KoPathPoint *prevPrevPoint = 0;
322
323 if (index.second > 1) {
324 KoPathPointIndex prevPrevIndex(index.first, index.second - 2);
325 prevPrevPoint = d->shape->pointByIndex(prevPrevIndex);
326 }
327
328 if (prevPrevPoint) {
329 const QPointF control1 = prevPoint->point() + 0.3 * (prevPrevPoint->point() - prevPoint->point());
330 prevPoint->setControlPoint1(control1);
331 }
332
333 const QPointF control2 = prevPoint->point() + 0.3 * (d->activePoint->point() - prevPoint->point());
334 prevPoint->setControlPoint2(control2);
335
336 const QPointF activeControl = d->activePoint->point() + 0.3 * (prevPoint->point() - d->activePoint->point());
337 d->activePoint->setControlPoint1(activeControl);
338
340 }
341 }
342 }
343
344 }
345
347}
348
350{
351 Q_D(KoCreatePathTool);
352
353 if (! d->shape || (event->buttons() & Qt::RightButton)) return;
354
355 d->prevPointWasDragged = d->pointIsDragged;
356 d->pointIsDragged = false;
357 KoPathPoint *lastActivePoint = d->activePoint;
358
359 if (!d->finishAfterThisPoint) {
360 d->activePoint = d->shape->lineTo(event->point);
361 canvas()->snapGuide()->setIgnoredPathPoints((QList<KoPathPoint*>() << d->activePoint));
362 }
363
364 // apply symmetric point property if applicable
365 if (lastActivePoint->activeControlPoint1() && lastActivePoint->activeControlPoint2()) {
366 QPointF diff1 = lastActivePoint->point() - lastActivePoint->controlPoint1();
367 QPointF diff2 = lastActivePoint->controlPoint2() - lastActivePoint->point();
368 if (qFuzzyCompare(diff1.x(), diff2.x()) && qFuzzyCompare(diff1.y(), diff2.y()))
369 lastActivePoint->setProperty(KoPathPoint::IsSymmetric);
370 }
371
372 if (d->finishAfterThisPoint) {
373
374 d->firstPoint->setControlPoint1(d->activePoint->controlPoint1());
375 delete d->shape->removePoint(d->shape->pathPointIndex(d->activePoint));
376 d->activePoint = d->firstPoint;
377
378 if (!d->prevPointWasDragged && d->autoSmoothCurves) {
380 }
381
382 d->shape->closeMerge();
383
384 // we are closing the path, so reset the existing start path point
385 d->existingStartPoint = 0;
386 // finish path
387 endPath();
388 }
389
390 if (d->angleSnapStrategy && lastActivePoint->activeControlPoint2()) {
391 d->angleSnapStrategy->deactivate();
392 }
393
395}
396
398{
399 Q_D(KoCreatePathTool);
400
401 if (!d->shape) {
402 return;
403 }
404 d->addPathShape();
406 endShape();
407}
408
410{
411 Q_D(KoCreatePathTool);
412
413 if (!d->shape) {
414 return;
415 }
416 delete d->shape->removePoint(d->shape->pathPointIndex(d->activePoint));
417 d->addPathShape();
418
420 endShape();
421}
422
424{
425 Q_D(KoCreatePathTool);
426
427 if (!d->shape) {
428 return;
429 }
430 d->firstPoint = 0;
431 d->activePoint = 0;
432 d->cleanUp();
434 endShape();
435}
436
438{
439 Q_D(KoCreatePathTool);
440
441 if ((d->shape)) {
442 KoPathPointIndex lastPointIndex = d->shape->pathPointIndex(d->activePoint);
443
444 if (lastPointIndex.second > 1) {
445 lastPointIndex.second--;
446 delete d->shape->removePoint(lastPointIndex);
447
448 d->hoveredPoint = 0;
449
451 }
452 }
453}
454
455void KoCreatePathTool::activate(const QSet<KoShape*> &shapes)
456{
457 KoToolBase::activate(shapes);
458
459 Q_D(KoCreatePathTool);
460 useCursor(Qt::ArrowCursor);
461
462 // retrieve the actual global handle radius
463 d->handleRadius = handleRadius();
464 d->decorationThickness = decorationThickness();
465 d->loadAutoSmoothValueFromConfig();
466
467 // reset snap guide
468 canvas()->snapGuide()->reset();
470}
471
477
478void KoCreatePathTool::canvasResourceChanged(int key, const QVariant & res)
479{
480 Q_D(KoCreatePathTool);
481
482 switch (key) {
484 d->handleRadius = res.toUInt();
485 }
486 break;
488 d->decorationThickness = res.toUInt();
489 }
490 break;
491 default:
492 return;
493 }
494}
495
496bool KoCreatePathTool::addPathShapeImpl(KoPathShape *pathShape, bool tryMergeOnly)
497{
498 Q_D(KoCreatePathTool);
499
500 KoPathShape *startShape = 0;
502 pathShape->normalize();
503
504 // check if existing start/end points are still valid
505 d->existingStartPoint.validate(canvas());
506 d->existingEndPoint.validate(canvas());
507
508 if (d->connectPaths(pathShape, d->existingStartPoint, d->existingEndPoint)) {
509 if (d->existingStartPoint.isValid()) {
510 startShape = d->existingStartPoint.path;
511 }
512 if (d->existingEndPoint.isValid() && d->existingEndPoint != d->existingStartPoint) {
513 endShape = d->existingEndPoint.path;
514 }
515 }
516
517 if (tryMergeOnly && !startShape && !endShape) {
518 return false;
519 }
520
521 KUndo2Command *cmd = canvas()->shapeController()->addShape(pathShape, 0);
523 canvas()->updateCanvas(pathShape->boundingRect());
524 delete pathShape;
525 return true;
526 }
527
529 selection->deselectAll();
530 selection->select(pathShape);
531
532 if (startShape) {
533 pathShape->setBackground(startShape->background());
534 pathShape->setStroke(startShape->stroke());
535 } else if (endShape) {
536 pathShape->setBackground(endShape->background());
537 pathShape->setStroke(endShape->stroke());
538 }
539
540
541 if (startShape) {
542 canvas()->shapeController()->removeShape(startShape, cmd);
543 }
544 if (endShape && startShape != endShape) {
545 canvas()->shapeController()->removeShape(endShape, cmd);
546 }
547 canvas()->addCommand(cmd);
548
549 return true;
550}
551
552
554{
555 addPathShapeImpl(pathShape, false);
556}
557
559{
560 Q_D(KoCreatePathTool);
561
563
564 QWidget *widget = new QWidget();
565 widget->setObjectName("bezier-curve-tool-widget");
566 widget->setWindowTitle(i18n("Path options"));
567
568 QCheckBox *smoothCurves = new QCheckBox(i18n("Autosmooth curve"), widget);
569 smoothCurves->setObjectName("smooth-curves-widget");
570 smoothCurves->setChecked(d->autoSmoothCurves);
571
572 QCheckBox *angleSnap = new QCheckBox(i18n("Activate angle snap"), widget);
573 angleSnap->setObjectName("angle-snap-widget");
574 angleSnap->setChecked(false);
575 angleSnap->setCheckable(true);
576
577 KisAngleSelector *angleEdit = new KisAngleSelector(widget);
578 angleEdit->setObjectName("angle-edit-widget");
579 angleEdit->setAngle(d->angleSnappingDelta);
580 angleEdit->setRange(1, 360);
581 angleEdit->setDecimals(0);
583 angleEdit->setEnabled(angleSnap->isChecked());
584
585 QHBoxLayout *angleEditLayout = new QHBoxLayout;
586 angleEditLayout->setContentsMargins(10, 0, 0, 0);
587 angleEditLayout->setSpacing(0);
588 angleEditLayout->addWidget(angleEdit);
589
590 QVBoxLayout *mainLayout = new QVBoxLayout;
591 mainLayout->setContentsMargins(0, 0, 0, 0);
592 mainLayout->setSpacing(5);
593
594 mainLayout->addWidget(smoothCurves);
595 mainLayout->addWidget(angleSnap);
596 mainLayout->addLayout(angleEditLayout);
597
598 widget->setLayout(mainLayout);
599
600 list.append(widget);
601
602 connect(smoothCurves,
603 SIGNAL(toggled(bool)),
604 this,
605 SLOT(autoSmoothCurvesChanged(bool)));
606 connect(this,
607 SIGNAL(sigUpdateAutoSmoothCurvesGUI(bool)),
608 smoothCurves,
609 SLOT(setChecked(bool)));
610 connect(angleEdit, SIGNAL(angleChanged(qreal)), this, SLOT(angleDeltaChanged(qreal)));
611 connect(angleSnap, SIGNAL(stateChanged(int)), this, SLOT(angleSnapChanged(int)));
612 connect(angleSnap,
613 SIGNAL(toggled(bool)),
614 angleEdit,
615 SLOT(setEnabled(bool)));
616
617 return list;
618}
619
620//have to include this because of Q_PRIVATE_SLOT
621#include <moc_KoCreatePathTool.cpp>
float value(const T *src, size_t ch)
#define KoPathShapeId
Definition KoPathShape.h:20
QPair< int, int > KoPathPointIndex
Definition KoPathShape.h:28
A widget with several options to select an angle.
@ FlipOptionsMode_MenuButton
The flip options are shown as a menu accessible via a options button.
void setFlipOptionsMode(FlipOptionsMode newMode)
Sets the mode in which the flip options should be shown.
void setAngle(qreal newAngle)
Sets the current angle.
void setRange(qreal newMinimum, qreal newMaximum)
Sets the minimum and maximum values for the angle.
void setDecimals(int newNumberOfDecimals)
Sets the number of decimals (precision) used by the angle.
The KisHandlePainterHelper class is a special helper for painting handles around objects....
void setHandleStyle(const KisHandleStyle &style)
static KisHandleStyle & primarySelection(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & highlightedPrimaryHandles(KisHandlePalette palette=KisHandlePalette())
KoSnapGuide * snapGuide
QPointer< KoShapeController > shapeController
virtual KoShapeManager * shapeManager() const =0
virtual void updateCanvas(const QRectF &rc)=0
virtual KoColorDisplayRendererInterface * displayRendererInterface() const
displayRendererInterface The display renderer interface has a number of color conversion functions wh...
virtual void addCommand(KUndo2Command *command)=0
QPointer< KoCanvasResourceProvider > resourceManager
virtual KisHandlePalette handlePaletteForDisplayColorSpace() const =0
handlePaletteForDisplayColorSpace
void deactivate() override
reimplemented
void canvasResourceChanged(int key, const QVariant &res) override
reimplemented
KoCreatePathTool(KoCanvasBase *canvas)
void mousePressEvent(KoPointerEvent *event) override
reimplemented
void mouseDoubleClickEvent(KoPointerEvent *event) override
reimplemented
void mouseReleaseEvent(KoPointerEvent *event) override
reimplemented
void mouseMoveEvent(KoPointerEvent *event) override
reimplemented
virtual void paintPath(KoPathShape &pathShape, QPainter &painter, const KoViewConverter &converter)
void setEnableClosePathShortcut(bool value)
virtual void beginShape()
QList< QPointer< QWidget > > createOptionWidgets() override
reimplemented
bool tryMergeInPathShape(KoPathShape *pathShape)
void paint(QPainter &painter, const KoViewConverter &converter) override
reimplemented
void handleMouseMove(const KoPointerEvent *event, bool considerDrag)
QRectF decorationsRect() const override
virtual void addPathShape(KoPathShape *pathShape)
~KoCreatePathTool() override
bool addPathShapeImpl(KoPathShape *pathShape, bool tryMergeOnly)
void sigUpdateAutoSmoothCurvesGUI(bool value)
void angleSnapChanged(int)) Q_PRIVATE_SLOT(d_func()
virtual void endShape()
void activate(const QSet< KoShape * > &shapes) override
reimplemented
static void makeCubicPointSmooth(KoPathPoint *point)
A KoPathPoint represents a point in a path.
void setControlPoint1(const QPointF &point)
Set the control point 1.
QPointF point
void setProperty(PointProperty property)
Sets a single property of a point.
void setControlPoint2(const QPointF &point)
Set the control point 2.
QPointF controlPoint1
@ IsSymmetric
it is symmetric, like smooth but control points have same distance to point
Definition KoPathPoint.h:42
@ ControlPoint2
the second control point
Definition KoPathPoint.h:51
@ ControlPoint1
the first control point
Definition KoPathPoint.h:50
@ Node
the node point
Definition KoPathPoint.h:49
bool activeControlPoint1
bool activeControlPoint2
QPointF controlPoint2
The position of a path point within a path shape.
Definition KoPathShape.h:63
virtual QPointF normalize()
Normalizes the path data.
KoPathPoint * moveTo(const QPointF &p)
Starts a new Subpath.
void paint(QPainter &painter) const override
reimplemented
QRectF boundingRect() const override
reimplemented
Qt::MouseButton button() const
return button pressed (see QMouseEvent::button());
Qt::MouseButtons buttons() const
return buttons pressed (see QMouseEvent::buttons());
bool isTouchEvent() const
Qt::KeyboardModifiers modifiers() const
QPointF point
The point in document coordinates.
KoSelection * selection
virtual KoShapeStrokeModelSP stroke() const
Definition KoShape.cpp:885
virtual void setStroke(KoShapeStrokeModelSP stroke)
Definition KoShape.cpp:899
QTransform absoluteTransformation() const
Definition KoShape.cpp:330
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
Definition KoShape.cpp:746
static KisHandlePainterHelper createHandlePainterHelperView(QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius=0.0, int decorationThickness=1)
Definition KoShape.cpp:977
virtual QSharedPointer< KoShapeBackground > background() const
Definition KoShape.cpp:754
void setShapeId(const QString &id)
Definition KoShape.cpp:880
bool addCustomSnapStrategy(KoSnapStrategy *customStrategy)
void reset()
Resets the snap guide.
void paint(QPainter &painter, const KoViewConverter &converter, const KoColorDisplayRendererInterface *displayRenderer)
paints the guide
void setIgnoredPathPoints(const QList< KoPathPoint * > &ignoredPoints)
Sets a list of path points to ignore.
QPointF snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
snaps the mouse position, returns if mouse was snapped
void setAdditionalEditedShape(KoShape *shape)
Adds an additional shape to snap to (useful when creating a path)
QRectF boundingRect()
returns the bounding rect of the guide
qreal handleDocRadius() const
KoCanvasBase * canvas() const
Returns the canvas the tool is working on.
QRectF handlePaintRect(const QPointF &position) const
virtual KoToolSelection * selection()
virtual void repaintDecorations()
int handleRadius() const
Convenience function to get the current handle radius.
void useCursor(const QCursor &cursor)
virtual void activate(const QSet< KoShape * > &shapes)
QRectF handleGrabRect(const QPointF &position) const
virtual void deactivate()
int decorationThickness() const
decorationThickness The minimum thickness for tool decoration lines, this is derived from the screen ...
virtual QPointF documentToView(const QPointF &documentPoint) const
static bool qFuzzyCompare(half p1, half p2)
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
T kisGrowRect(const T &rect, U offset)
Definition kis_global.h:186
@ DecorationThickness
Integer, the thickness of single px decorations, will be adjusted by HiDPI settings....
@ HandleRadius
The handle radius used for drawing handles of any kind.
rgba palette[MAX_PALETTE]
Definition palette.c:35