Krita Source Code Documentation
Loading...
Searching...
No Matches
SelectionDecorator.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: 2006-2007 Thomas Zander <zander@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
10
11#include <QPainterPath>
12
13#include <KoShape.h>
14#include <KoSelection.h>
15#include <KoResourcePaths.h>
16#include "kis_algebra_2d.h"
17
18#include "kis_debug.h"
23#include <KoCanvasBase.h>
24#include <KoSvgTextShape.h>
26
27#include "kis_painting_tweaks.h"
29#include "kis_icon_utils.h"
30
31
32
33#define HANDLE_DISTANCE 10
34
36 : m_hotPosition(KoFlake::Center)
37 , m_rendererInterface(displayInterface)
38 , m_handleRadius(7)
39 , m_decorationThickness(1)
40 , m_showFillGradientHandles(false)
41 , m_showStrokeFillGradientHandles(false)
42 , m_forceShapeOutlines(false)
43{
46 resourceManager->resource(KoFlake::HotPosition).toInt());
47}
48
50{
51 m_selection = selection;
52}
53
55{
56 m_handleRadius = radius;
57}
58
60{
61 m_decorationThickness = thickness;
62}
63
68
73
78
85
86void SelectionDecorator::paint(QPainter &painter, const KoViewConverter &converter)
87{
89 if (selectedShapes.isEmpty()) return;
90
92
93 const bool haveOnlyOneEditableShape =
94 m_selection->selectedEditableShapes().size() == 1 &&
95 selectedShapes.size() == 1;
96
97 bool editable = false;
98 bool forceBoundingRubberLine = false;
99
100 Q_FOREACH (KoShape *shape, KoShape::linearizeSubtree(selectedShapes)) {
101 if (!haveOnlyOneEditableShape || !m_showStrokeFillGradientHandles) {
104
106
108 helper.drawRubberLine(shape->outlineRect());
109 } else {
110 QList<QPolygonF> polys = shape->outline().toSubpathPolygons();
111
112 if (polys.size() == 1) {
113 const QPolygonF poly1 = polys[0];
114 const QPolygonF poly2 = QPolygonF(polys[0].boundingRect());
115 const QPolygonF nonoverlap = poly2.subtracted(poly1);
116
117 forceBoundingRubberLine |= !nonoverlap.isEmpty();
118 }
119
120 Q_FOREACH (const QPolygonF &poly, polys) {
121 helper.drawRubberLine(poly);
122 }
123 }
124 }
125
126 if (shape->isShapeEditable()) {
127 editable = true;
128 }
129 }
130
131 const QRectF handleArea = m_selection->outlineRect();
132
133 // draw extra rubber line around all the shapes
134 if (selectedShapes.size() > 1 || forceBoundingRubberLine) {
137
139 helper.drawRubberLine(handleArea);
140 }
141
142 // if we have no editable shape selected there
143 // is no need drawing the selection handles
144 if (editable) {
148
149 QPolygonF outline = handleArea;
150
151 {
152 helper.drawHandleRect(outline.value(0));
153 helper.drawHandleRect(outline.value(1));
154 helper.drawHandleRect(outline.value(2));
155 helper.drawHandleRect(outline.value(3));
156 helper.drawHandleRect(0.5 * (outline.value(0) + outline.value(1)));
157 helper.drawHandleRect(0.5 * (outline.value(1) + outline.value(2)));
158 helper.drawHandleRect(0.5 * (outline.value(2) + outline.value(3)));
159 helper.drawHandleRect(0.5 * (outline.value(3) + outline.value(0)));
160
161 QPointF hotPos = KoFlake::anchorToPoint(m_hotPosition, handleArea);
163 helper.drawHandleRect(hotPos);
164 }
165 }
166
167 if (haveOnlyOneEditableShape) {
168 KoShape *shape = selectedShapes.first();
169
171 paintGradientHandles(shape, KoFlake::Fill, painter, converter);
173 paintGradientHandles(shape, KoFlake::StrokeFill, painter, converter);
174 }
175
176 // paint meshgradient handles
178 paintMeshGradientHandles(shape, KoFlake::Fill, painter, converter);
179 }
180 }
181
182}
183
184void SelectionDecorator::paintGradientHandles(KoShape *shape, KoFlake::FillVariant fillVariant, QPainter &painter, const KoViewConverter &converter)
185{
186 KoShapeGradientHandles gradientHandles(fillVariant, shape);
187 QVector<KoShapeGradientHandles::Handle> handles = gradientHandles.handles();
189
192
193 const QTransform t = shape->absoluteTransformation().inverted();
194
195 if (gradientHandles.type() == QGradient::LinearGradient) {
196 KIS_SAFE_ASSERT_RECOVER_NOOP(handles.size() == 2);
197
198 if (handles.size() == 2) {
200 helper.drawGradientArrow(t.map(handles[0].pos), t.map(handles[1].pos), 1.5 * m_handleRadius);
201 }
202 }
203
205
206 Q_FOREACH (const KoShapeGradientHandles::Handle &h, handles) {
208 helper.drawGradientCrossHandle(t.map(h.pos), 1.2 * m_handleRadius);
209 } else {
210 helper.drawGradientHandle(t.map(h.pos), 1.2 * m_handleRadius);
211 }
212 }
213}
214
216 KoFlake::FillVariant fillVariant,
217 QPainter &painter,
218 const KoViewConverter &converter)
219{
220 KoShapeMeshGradientHandles gradientHandles(fillVariant, shape);
222
226
227 helper.drawPath(gradientHandles.path());
228
229 // invert them, because we draw in logical coordinates.
230 const QTransform t = shape->absoluteTransformation().inverted();
231 const QVector<KoShapeMeshGradientHandles::Handle> cornerHandles = gradientHandles.handles();
232 for (const auto& corner: cornerHandles) {
233 const QPointF point = t.map(corner.pos);
235 helper.drawConnectionLine(gradientHandles.getAttachedCorner(corner), point);
236 helper.drawHandleSmallCircle(point);
237 } else if (corner.type == KoShapeMeshGradientHandles::Handle::Corner) {
238 helper.drawHandleCircle(point);
239 }
240 }
241
243
244 // highlight the selected handle (only corner)
246 helper.drawHandleRect(t.map(gradientHandles.getHandle(m_selectedMeshHandle.getPosition()).pos));
247 }
248
249 // highlight the path which is being hovered/moved
252 for (const auto &path: paths) {
253 helper.drawPath(path);
254 }
255 }
256}
257
float value(const T *src, size_t ch)
The KisHandlePainterHelper class is a special helper for painting handles around objects....
void drawHandleSmallCircle(const QPointF &center)
void drawPath(const QPainterPath &path)
void drawGradientCrossHandle(const QPointF &center, qreal radius)
void drawHandleRect(const QPointF &center, qreal radius)
void drawConnectionLine(const QLineF &line)
void setHandleStyle(const KisHandleStyle &style)
void drawGradientHandle(const QPointF &center, qreal radius)
void drawGradientArrow(const QPointF &start, const QPointF &end, qreal radius)
void drawRubberLine(const QPolygonF &poly)
void drawHandleCircle(const QPointF &center, qreal radius)
static KisHandleStyle & gradientArrows(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & highlightedPrimaryHandlesWithSolidOutline(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & gradientHandles(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & secondarySelection(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & primarySelection(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & highlightedPrimaryHandles(KisHandlePalette palette=KisHandlePalette())
virtual KisHandlePalette handlePaletteForDisplayColorSpace() const =0
handlePaletteForDisplayColorSpace
const QList< KoShape * > selectedVisibleShapes() const
QRectF outlineRect() const override
const QList< KoShape * > selectedEditableShapes() const
QGradient::Type type() const
QVector< Handle > handles() const
QVector< QPainterPath > getConnectedPath(const Handle &handle) const
Handle getHandle(SvgMeshPosition position) const
convenience method to get a handle by its position in the mesharray
QPointF getAttachedCorner(const Handle &bezierHandle) const
get the attached corner node of the bezierHandle
QVector< Handle > handles() const
get all nodes in the mesh, don't use this for drawing the path but use path()
virtual QRectF outlineRect() const
Definition KoShape.cpp:561
virtual QPainterPath outline() const
Definition KoShape.cpp:554
virtual bool isShapeEditable(bool recursive=true) const
checks recursively if the shape or one of its parents is not visible or locked
Definition KoShape.cpp:965
QTransform absoluteTransformation() const
Definition KoShape.cpp:330
static KisHandlePainterHelper createHandlePainterHelperView(QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius=0.0, int decorationThickness=1)
Definition KoShape.cpp:977
static QList< KoShape * > linearizeSubtree(const QList< KoShape * > &shapes)
Definition KoShape.cpp:1173
void setDecorationThickness(int thickness)
void paintGradientHandles(KoShape *shape, KoFlake::FillVariant fillVariant, QPainter &painter, const KoViewConverter &converter)
void setCurrentMeshGradientHandles(const KoShapeMeshGradientHandles::Handle &selectedHandle, const KoShapeMeshGradientHandles::Handle &hoveredHandle)
KoColorDisplayRendererInterface * m_rendererInterface
void paint(QPainter &painter, const KoViewConverter &converter)
void setSelection(KoSelection *selection)
KoFlake::AnchorPosition m_hotPosition
void paintMeshGradientHandles(KoShape *shape, KoFlake::FillVariant fillVariant, QPainter &painter, const KoViewConverter &converter)
void setShowFillMeshGradientHandles(bool value)
void setForceShapeOutlines(bool value)
KoSelection * m_selection
void setShowStrokeFillGradientHandles(bool value)
void setHandleRadius(int radius)
SelectionDecorator(KoCanvasResourceProvider *resourceManager, KoColorDisplayRendererInterface *displayInterface)
KoShapeMeshGradientHandles::Handle m_selectedMeshHandle
KoShapeMeshGradientHandles::Handle m_currentHoveredMeshHandle
void setShowFillGradientHandles(bool value)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
AnchorPosition
Definition KoFlake.h:85
@ HotPosition
Definition KoFlake.h:102
KRITAFLAKE_EXPORT QPointF anchorToPoint(AnchorPosition anchor, const QRectF rect, bool *valid=0)
Definition KoFlake.cpp:329
FillVariant
Definition KoFlake.h:28
@ StrokeFill
Definition KoFlake.h:30
@ Fill
Definition KoFlake.h:29
rgba palette[MAX_PALETTE]
Definition palette.c:35