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>
25
26#include "kis_painting_tweaks.h"
28#include "kis_icon_utils.h"
29
30
31
32#define HANDLE_DISTANCE 10
33
35 : m_hotPosition(KoFlake::Center)
36 , m_handleRadius(7)
37 , m_decorationThickness(1)
38 , m_showFillGradientHandles(false)
39 , m_showStrokeFillGradientHandles(false)
40 , m_forceShapeOutlines(false)
41{
44 resourceManager->resource(KoFlake::HotPosition).toInt());
45}
46
48{
49 m_selection = selection;
50}
51
53{
54 m_handleRadius = radius;
55}
56
58{
59 m_decorationThickness = thickness;
60}
61
66
71
76
83
84void SelectionDecorator::paint(QPainter &painter, const KoViewConverter &converter)
85{
87 if (selectedShapes.isEmpty()) return;
88
89 const bool haveOnlyOneEditableShape =
90 m_selection->selectedEditableShapes().size() == 1 &&
91 selectedShapes.size() == 1;
92
93 bool editable = false;
94 bool forceBoundingRubberLine = false;
95
96 Q_FOREACH (KoShape *shape, KoShape::linearizeSubtree(selectedShapes)) {
97 if (!haveOnlyOneEditableShape || !m_showStrokeFillGradientHandles) {
100
102
104 helper.drawRubberLine(shape->outlineRect());
105 } else {
106 QList<QPolygonF> polys = shape->outline().toSubpathPolygons();
107
108 if (polys.size() == 1) {
109 const QPolygonF poly1 = polys[0];
110 const QPolygonF poly2 = QPolygonF(polys[0].boundingRect());
111 const QPolygonF nonoverlap = poly2.subtracted(poly1);
112
113 forceBoundingRubberLine |= !nonoverlap.isEmpty();
114 }
115
116 Q_FOREACH (const QPolygonF &poly, polys) {
117 helper.drawRubberLine(poly);
118 }
119 }
120 }
121
122 if (shape->isShapeEditable()) {
123 editable = true;
124 }
125 }
126
127 const QRectF handleArea = m_selection->outlineRect();
128
129 // draw extra rubber line around all the shapes
130 if (selectedShapes.size() > 1 || forceBoundingRubberLine) {
133
135 helper.drawRubberLine(handleArea);
136 }
137
138 // if we have no editable shape selected there
139 // is no need drawing the selection handles
140 if (editable) {
144
145 QPolygonF outline = handleArea;
146
147 {
148 helper.drawHandleRect(outline.value(0));
149 helper.drawHandleRect(outline.value(1));
150 helper.drawHandleRect(outline.value(2));
151 helper.drawHandleRect(outline.value(3));
152 helper.drawHandleRect(0.5 * (outline.value(0) + outline.value(1)));
153 helper.drawHandleRect(0.5 * (outline.value(1) + outline.value(2)));
154 helper.drawHandleRect(0.5 * (outline.value(2) + outline.value(3)));
155 helper.drawHandleRect(0.5 * (outline.value(3) + outline.value(0)));
156
157 QPointF hotPos = KoFlake::anchorToPoint(m_hotPosition, handleArea);
159 helper.drawHandleRect(hotPos);
160 }
161 }
162
163 if (haveOnlyOneEditableShape) {
164 KoShape *shape = selectedShapes.first();
165
167 paintGradientHandles(shape, KoFlake::Fill, painter, converter);
169 paintGradientHandles(shape, KoFlake::StrokeFill, painter, converter);
170 }
171
172 // paint meshgradient handles
174 paintMeshGradientHandles(shape, KoFlake::Fill, painter, converter);
175 }
176 }
177
178}
179
180void SelectionDecorator::paintGradientHandles(KoShape *shape, KoFlake::FillVariant fillVariant, QPainter &painter, const KoViewConverter &converter)
181{
182 KoShapeGradientHandles gradientHandles(fillVariant, shape);
183 QVector<KoShapeGradientHandles::Handle> handles = gradientHandles.handles();
184
187
188 const QTransform t = shape->absoluteTransformation().inverted();
189
190 if (gradientHandles.type() == QGradient::LinearGradient) {
191 KIS_SAFE_ASSERT_RECOVER_NOOP(handles.size() == 2);
192
193 if (handles.size() == 2) {
195 helper.drawGradientArrow(t.map(handles[0].pos), t.map(handles[1].pos), 1.5 * m_handleRadius);
196 }
197 }
198
200
201 Q_FOREACH (const KoShapeGradientHandles::Handle &h, handles) {
203 helper.drawGradientCrossHandle(t.map(h.pos), 1.2 * m_handleRadius);
204 } else {
205 helper.drawGradientHandle(t.map(h.pos), 1.2 * m_handleRadius);
206 }
207 }
208}
209
211 KoFlake::FillVariant fillVariant,
212 QPainter &painter,
213 const KoViewConverter &converter)
214{
215 KoShapeMeshGradientHandles gradientHandles(fillVariant, shape);
216
220
221 helper.drawPath(gradientHandles.path());
222
223 // invert them, because we draw in logical coordinates.
224 const QTransform t = shape->absoluteTransformation().inverted();
225 const QVector<KoShapeMeshGradientHandles::Handle> cornerHandles = gradientHandles.handles();
226 for (const auto& corner: cornerHandles) {
227 const QPointF point = t.map(corner.pos);
229 helper.drawConnectionLine(gradientHandles.getAttachedCorner(corner), point);
230 helper.drawHandleSmallCircle(point);
231 } else if (corner.type == KoShapeMeshGradientHandles::Handle::Corner) {
232 helper.drawHandleCircle(point);
233 }
234 }
235
237
238 // highlight the selected handle (only corner)
240 helper.drawHandleRect(t.map(gradientHandles.getHandle(m_selectedMeshHandle.getPosition()).pos));
241 }
242
243 // highlight the path which is being hovered/moved
246 for (const auto &path: paths) {
247 helper.drawPath(path);
248 }
249 }
250}
251
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 & gradientHandles()
static KisHandleStyle & highlightedPrimaryHandlesWithSolidOutline()
static KisHandleStyle & highlightedPrimaryHandles()
static KisHandleStyle & gradientArrows()
static KisHandleStyle & secondarySelection()
static KisHandleStyle & primarySelection()
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:637
virtual QPainterPath outline() const
Definition KoShape.cpp:630
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:1165
QTransform absoluteTransformation() const
Definition KoShape.cpp:382
static KisHandlePainterHelper createHandlePainterHelperView(QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius=0.0, int decorationThickness=1)
Definition KoShape.cpp:1177
static QList< KoShape * > linearizeSubtree(const QList< KoShape * > &shapes)
Definition KoShape.cpp:1381
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)
SelectionDecorator(KoCanvasResourceProvider *resourceManager)
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)
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