Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tool_shape.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005 Adrian Page <adrian@pagenet.plus.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "kis_tool_shape.h"
8
9#include <QWidget>
10#include <QLayout>
11#include <QGridLayout>
12
13#include <KoUnit.h>
14#include <KoShape.h>
16#include <KoCanvasBase.h>
17#include <KoShapeController.h>
18#include <KoColorBackground.h>
19#include <KoPatternBackground.h>
20#include <KoShapeStroke.h>
22#include <KoPathShape.h>
23
24#include <klocalizedstring.h>
25#include <ksharedconfig.h>
26
27#include <kis_debug.h>
30#include <kis_paint_layer.h>
31#include <kis_paint_device.h>
33#include <kis_node_query_path.h>
34
36#include <KoSelection.h>
38#include "kis_selection_mask.h"
39#include "kis_shape_selection.h"
41
42
43KisToolShape::KisToolShape(KoCanvasBase * canvas, const QCursor & cursor)
44 : KisToolPaint(canvas, cursor)
45{
47}
48
50{
51 // in case the widget hasn't been shown
54 }
55}
56
57void KisToolShape::activate(const QSet<KoShape*> &shapes)
58{
60 m_configGroup = KSharedConfig::openConfig()->group(toolId());
61}
62
63
69
71{
73
74 m_shapeOptionsWidget->cmbOutline->setCurrentIndex(KisPainter::StrokeStyleBrush);
75
76 m_shapeOptionsWidget->angleSelectorRotation->setIncreasingDirection(KisAngleGauge::IncreasingDirection_Clockwise);
77 m_shapeOptionsWidget->angleSelectorRotation->setFlipOptionsMode(KisAngleSelector::FlipOptionsMode_MenuButton);
78
79 m_shapeOptionsWidget->sldScale->setSuffix("%");
80 m_shapeOptionsWidget->sldScale->setRange(0.0, 10000.0, 2);
81 m_shapeOptionsWidget->sldScale->setSoftMaximum(500);
82 m_shapeOptionsWidget->sldScale->setSingleStep(1.0);
83
84 //connect two combo box event. Inherited classes can call the slots to make appropriate changes
85 connect(m_shapeOptionsWidget->cmbOutline, SIGNAL(currentIndexChanged(int)), this, SLOT(outlineSettingChanged(int)));
86 connect(m_shapeOptionsWidget->cmbFill, SIGNAL(currentIndexChanged(int)), this, SLOT(fillSettingChanged(int)));
87 connect(m_shapeOptionsWidget->angleSelectorRotation, SIGNAL(angleChanged(qreal)), this, SLOT(patternRotationSettingChanged(qreal)));
88 connect(m_shapeOptionsWidget->sldScale, SIGNAL(valueChanged(qreal)), this, SLOT(patternScaleSettingChanged(qreal)));
89
90 m_shapeOptionsWidget->cmbOutline->setCurrentIndex(m_configGroup.readEntry("outlineType", 0));
91 m_shapeOptionsWidget->cmbFill->setCurrentIndex(m_configGroup.readEntry("fillType", 0));
92 m_shapeOptionsWidget->sldScale->setValue(m_configGroup.readEntry("patternTransformScale", 100));
93 m_shapeOptionsWidget->angleSelectorRotation->setAngle(m_configGroup.readEntry("patternTransformRotation", 0));
94
95 //if both settings are empty, force the outline to brush so the tool will work when first activated
96 if ( m_shapeOptionsWidget->cmbFill->currentIndex() == 0 &&
97 m_shapeOptionsWidget->cmbOutline->currentIndex() == 0)
98 {
99 m_shapeOptionsWidget->cmbOutline->setCurrentIndex(1); // brush
100 }
101
102 bool enablePatternTransform = (m_shapeOptionsWidget->cmbFill->currentIndex() == int(KisToolShapeUtils::FillStylePattern));
103 m_shapeOptionsWidget->gbPatternTransform->setEnabled(enablePatternTransform);
104
106}
107
109{
110 m_configGroup.writeEntry("outlineType", value);
111}
112
114{
115 m_configGroup.writeEntry("fillType", value);
116 bool enable = (value == int(KisToolShapeUtils::FillStylePattern));
117 m_shapeOptionsWidget->gbPatternTransform->setEnabled(enable);
118}
119
121{
122 m_configGroup.writeEntry("patternTransformRotation", value);
123}
124
126{
127 m_configGroup.writeEntry("patternTransformScale", value);
128}
129
131{
133 return static_cast<KisToolShapeUtils::FillStyle>(m_shapeOptionsWidget->cmbFill->currentIndex());
134 } else {
136 }
137}
138
140{
142 return static_cast<KisToolShapeUtils::StrokeStyle>(m_shapeOptionsWidget->cmbOutline->currentIndex());
143 } else {
145 }
146}
147
149{
150 QTransform transform;
151
153 transform.rotate(m_shapeOptionsWidget->angleSelectorRotation->angle());
154 qreal scale = m_shapeOptionsWidget->sldScale->value()*0.01;
155 transform.scale(scale, scale);
156 }
157
158 return transform;
159}
160
162{
163 const qreal sizeInPx =
164 canvas()->resourceManager()->resource(KoCanvasResource::Size).toReal();
165
166 return canvas()->unit().fromUserValue(sizeInPx);
167}
168
170{
171 ShapeAddInfo info;
172
173 if (currentNode->inherits("KisShapeLayer")) {
174 info.shouldAddShape = true;
175 } else if (KisSelectionMask *mask = dynamic_cast<KisSelectionMask*>(currentNode.data())) {
176 if (mask->selection()->hasShapeSelection()) {
177 info.shouldAddShape = true;
178 info.shouldAddSelectionShape = true;
179 }
180 }
181
182 return info;
183}
184
191
193{
194 using namespace KisToolShapeUtils;
195
196 KisResourcesSnapshot resources(image(),
197 currentNode(),
198 canvas()->resourceManager());
199 switch(fillStyle()) {
200 case FillStyleForegroundColor:
202 break;
203 case FillStyleBackgroundColor:
205 break;
206 case FillStylePattern:
208 break;
209 case FillStyleNone:
211 break;
212 }
213
214 switch (strokeStyle()) {
217 break;
220 KoShapeStrokeSP stroke(new KoShapeStroke());
221 stroke->setLineWidth(currentStrokeWidth());
222 const QColor color = strokeStyle() == KisToolShapeUtils::StrokeStyleForeground ?
223 resources.currentFgColor().toQColor() :
224 resources.currentBgColor().toQColor();
225 stroke->setColor(color);
226 shape->setStroke(stroke);
227 break;
228 }
229 }
230
231 KUndo2Command *parentCommand = new KUndo2Command();
232
234 const QList<KoShape*> oldSelectedShapes = selection->selectedShapes();
235
236 // reset selection on the newly added shape :)
237 // TODO: think about moving this into controller->addShape?
238 new KoKeepShapesSelectedCommand(oldSelectedShapes, {shape}, canvas()->selectedShapesProxy(), false, parentCommand);
239 KUndo2Command *cmd = canvas()->shapeController()->addShape(shape, 0, parentCommand);
240 parentCommand->setText(cmd->text());
241 new KoKeepShapesSelectedCommand(oldSelectedShapes, {shape}, canvas()->selectedShapesProxy(), true, parentCommand);
242
244}
245
247{
248 KisNodeSP node = currentNode();
249 if (!node) {
250 return;
251 }
252
253 // Compute the outline
254 KisImageSP image = this->image();
255 QTransform matrix;
256 matrix.scale(image->xRes(), image->yRes());
257 matrix.translate(pathShape->position().x(), pathShape->position().y());
258 QPainterPath mappedOutline = matrix.map(pathShape->outline());
259
260 if (node->hasEditablePaintDevice()) {
261 KisFigurePaintingToolHelper helper(name,
262 image,
263 node,
264 canvas()->resourceManager(),
265 strokeStyle(),
266 fillStyle(),
267 fillTransform());
268 helper.paintPainterPath(mappedOutline);
269 } else if (node->inherits("KisShapeLayer")) {
270 pathShape->normalize();
271 addShape(pathShape);
272
273 }
274}
float value(const T *src, size_t ch)
QSharedPointer< KoShapeStrokeModel > KoShapeStrokeModelSP
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void setText(const KUndo2MagicString &text)
@ IncreasingDirection_Clockwise
@ FlipOptionsMode_MenuButton
The flip options are shown as a menu accessible via a options button.
KisSelectedShapesProxy selectedShapesProxy
KoUnit unit() const override
void paintPainterPath(const QPainterPath &path)
double xRes() const
double yRes() const
static void runSingleCommandStroke(KisImageSP image, KUndo2Command *cmd, KisStrokeJobData::Sequentiality sequentiality=KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::Exclusivity exclusivity=KisStrokeJobData::NORMAL)
runSingleCommandStroke creates a stroke and runs cmd in it. The text() field of cmd is used as a titl...
The KisResourcesSnapshot class takes a snapshot of the various resources like colors and settings use...
KoSelection * selection() override
void activate(const QSet< KoShape * > &shapes) override
KisToolShapeUtils::StrokeStyle strokeStyle()
WdgGeometryOptions * m_shapeOptionsWidget
KisToolShape(KoCanvasBase *canvas, const QCursor &cursor)
int flags() const override
~KisToolShape() override
QWidget * createOptionWidget() override
KConfigGroup m_configGroup
ShapeAddInfo shouldAddShape(KisNodeSP currentNode) const
qreal currentStrokeWidth() const
virtual void patternScaleSettingChanged(qreal value)
void activate(const QSet< KoShape * > &shapes) override
void addPathShape(KoPathShape *pathShape, const KUndo2MagicString &name)
QTransform fillTransform()
virtual void outlineSettingChanged(int value)
void addShape(KoShape *shape)
virtual void patternRotationSettingChanged(qreal value)
KisToolShapeUtils::FillStyle fillStyle()
virtual void fillSettingChanged(int value)
QPointer< KoShapeController > shapeController
QPointer< KoCanvasResourceProvider > resourceManager
A simple solid color shape background.
void toQColor(QColor *c) const
a convenience method for the above.
Definition KoColor.cpp:198
The position of a path point within a path shape.
Definition KoPathShape.h:63
virtual QPointF normalize()
Normalizes the path data.
QPainterPath outline() const override
reimplemented
virtual void setStroke(KoShapeStrokeModelSP stroke)
Definition KoShape.cpp:1081
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
Definition KoShape.cpp:918
void setUserData(KoShapeUserData *userData)
Definition KoShape.cpp:705
QPointF position() const
Get the position of the shape in pt.
Definition KoShape.cpp:825
Q_INVOKABLE QString toolId() const
virtual KoToolSelection * selection()
qreal fromUserValue(qreal value) const
Definition KoUnit.cpp:201
bool hasEditablePaintDevice() const
void markAsSelectionShapeIfNeeded(KoShape *shape) const
KisNodeSP currentNode() const
Definition kis_tool.cc:370
@ FLAG_USES_CUSTOM_SIZE
Definition kis_tool.h:47
@ FLAG_USES_CUSTOM_COMPOSITEOP
Definition kis_tool.h:47
@ FLAG_USES_CUSTOM_PRESET
Definition kis_tool.h:47
KisImageWSP image() const
Definition kis_tool.cc:332
KisCanvas2 * canvas