Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_mask_manager.cc
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2006 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "kis_mask_manager.h"
8
9#include <kactioncollection.h>
10
11#include <KoProperties.h>
12
13#include <kis_transaction.h>
16#include <kis_undo_adapter.h>
17#include <kis_paint_layer.h>
18#include "KisDocument.h"
19#include "KisViewManager.h"
20#include <kis_layer.h>
21#include <kis_clone_layer.h>
22#include <kis_group_layer.h>
23#include <kis_filter_mask.h>
25#include <kis_transform_mask.h>
27#include <kis_selection_mask.h>
28#include <kis_effect_mask.h>
31#include <kis_selection.h>
33#include <kis_pixel_selection.h>
35#include <kis_image.h>
37#include <KoColorSpace.h>
38#include <KoColor.h>
42#include "kis_iterator_ng.h"
44#include "kis_node_manager.h"
45
46
48 : m_view(view)
49 , m_imageView(0)
50 , m_commandsAdapter(new KisNodeCommandsAdapter(m_view))
51{
52}
53
55{
56 m_imageView = imageView;
57}
58
59void KisMaskManager::setup(KisKActionCollection *actionCollection, KisActionManager *actionManager)
60{
61 Q_UNUSED(actionCollection);
62 Q_UNUSED(actionManager);
63}
64
66{
67 // XXX: enable/disable menu items according to whether there's a mask selected currently
68 // XXX: disable the selection mask item if there's already a selection mask
69 // YYY: doesn't KisAction do that already?
70}
71
73{
74 if (m_imageView) {
75 return m_imageView->currentMask();
76 }
77 return 0;
78}
79
81{
82 KisMaskSP mask = activeMask();
83 return mask ? mask->paintDevice() : 0;
84}
85
87{
88 Q_UNUSED(mask);
89}
90
95
96void KisMaskManager::adjustMaskPosition(KisNodeSP node, KisNodeSP activeNode, bool avoidActiveNode, KisNodeSP &parent, KisNodeSP &above)
97{
98 Q_ASSERT(node);
99 Q_ASSERT(activeNode);
100
101 if (!avoidActiveNode && activeNode->allowAsChild(node)) {
102 parent = activeNode;
103 above = activeNode->lastChild();
104 } else if (activeNode->parent() && activeNode->parent()->allowAsChild(node)
105 && activeNode->parent()->parent() /* we don't want to add masks to root */) {
106 parent = activeNode->parent();
107 above = activeNode;
108 } else {
109 KisNodeSP t = activeNode;
110 while ((t = t->nextSibling())) {
111 if (t->allowAsChild(node)) {
112 parent = t;
113 above = t->lastChild();
114 break;
115 }
116 }
117
118 if (!t) {
119 t = activeNode;
120 while ((t = t->prevSibling())) {
121 if (t->allowAsChild(node)) {
122 parent = t;
123 above = t->lastChild();
124 break;
125 }
126 }
127 }
128
129 if (!t && activeNode->parent()) {
130 adjustMaskPosition(node, activeNode->parent(), true, parent, above);
131 } else if (!t) {
132 KisImageWSP image = m_view->image();
133 KisLayerSP layer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, image->colorSpace());
134 m_commandsAdapter->addNode(layer, activeNode, 0);
135
136 parent = layer;
137 above = 0;
138 }
139 }
140}
141
143 KisNodeSP activeNode,
144 KisPaintDeviceSP copyFrom,
145 const KUndo2MagicString& macroName,
146 const QString &nodeType,
147 const QString &nodeName,
148 bool suppressSelection,
149 bool avoidActiveNode,
150 bool updateImage)
151{
152 m_commandsAdapter->beginMacro(macroName);
153
154 KisNodeSP parent;
155 KisNodeSP above;
156 adjustMaskPosition(mask, activeNode, avoidActiveNode, parent, above);
157
158 KisLayerSP parentLayer = qobject_cast<KisLayer*>(parent.data());
159 Q_ASSERT(parentLayer);
160
161 bool shouldDeselectGlobalSelection = false;
162
163 if (!suppressSelection) {
164 if (copyFrom) {
165 mask->initSelection(copyFrom, parentLayer);
166 } else {
167 mask->initSelection(m_view->selection(), parentLayer);
168 shouldDeselectGlobalSelection = m_view->selection();
169 }
170 }
171
172 mask->setName( createMaskNameCommon(parentLayer, nodeType, nodeName) );
173
174 KisImageLayerAddCommand::Flags flags =
175 updateImage ?
178
179 m_commandsAdapter->addNode(mask, parentLayer, above, flags);
180
181 if (shouldDeselectGlobalSelection) {
183 }
184
186
187 masksUpdated();
188}
189
190QString KisMaskManager::createMaskNameCommon(KisNodeSP targetNode, const QString &nodeType, const QString &desiredName)
191{
193 int number = masks.count() + 1;
194 return desiredName + QString(" ") + QString::number(number);
195}
196
197KisNodeSP KisMaskManager::createSelectionMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool convertActiveNode)
198{
199 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
200
202
203 createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Selection Mask"), "KisSelectionMask", i18n("Selection"), false, convertActiveNode, false);
204 mask->setActive(true);
205 if (convertActiveNode) {
206 m_commandsAdapter->removeNode(activeNode);
207 }
208 return mask;
209}
210
212{
213 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
214
215 KisMaskSP mask = new KisTransparencyMask(m_view->image(), "");
216 createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Transparency Mask"), "KisTransparencyMask", i18n("Transparency Mask"), false, convertActiveNode);
217 if (convertActiveNode) {
218 m_commandsAdapter->removeNode(activeNode);
219 }
220 return mask;
221}
222
223
224KisNodeSP KisMaskManager::createFilterMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool quiet, bool convertActiveNode)
225{
226 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
227
228 KisFilterMaskSP mask = new KisFilterMask(m_view->image(), "");
229 createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Filter Mask"), "KisFilterMask", i18n("Filter Mask"), false, convertActiveNode);
230
231 if (convertActiveNode) {
232 m_commandsAdapter->removeNode(activeNode);
233 }
234
240 KisPaintDeviceSP originalDevice = mask->parent()->original();
241
242
243 KisDlgAdjustmentLayer dialog(mask, mask.data(), originalDevice,
244 mask->name(), i18n("New Filter Mask"),
245 m_view, qApp->activeWindow());
246
247 // If we are supposed to not disturb the user, don't start asking them about things.
248 if(quiet) {
250 if (filter) {
251 mask->setFilter(filter->cloneWithResourcesSnapshot());
252 mask->setName(mask->name());
253 }
254 return mask;
255 }
256
257 if (dialog.exec() == QDialog::Accepted) {
258 KisFilterConfigurationSP filter = dialog.filterConfiguration();
259 if (filter) {
260 QString name = dialog.layerName();
261 mask->setFilter(filter->cloneWithResourcesSnapshot());
262 mask->setName(name);
263 }
264
265 return mask;
266
267 } else {
269 }
270
271 return 0;
272}
273
274
276{
277 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
278
280 createMaskCommon(mask, activeNode, 0, kundo2_i18n("Add Colorize Mask"), "KisColorizeMask", i18n("Colorize Mask"), true, false);
281 mask->initializeCompositeOp();
282 delete mask->setColorSpace(mask->parent()->colorSpace());
283 return mask;
284}
285
286
288{
289 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
290
292 createMaskCommon(mask, activeNode, 0, kundo2_i18n("Add Transform Mask"), "KisTransformMask", i18n("Transform Mask"), true, false);
293 return mask;
294}
295
297{
298 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
299
300 KisLayerSP activeLayer = qobject_cast<KisLayer*>(activeNode.data());
301 Q_ASSERT(activeLayer);
302
305 if (!filter) return nullptr;
306
307 m_commandsAdapter->beginMacro(kundo2_i18n("Add Fast Color Overlay"));
308
309 KisFilterMaskSP mask = new KisFilterMask(m_view->image(), "");
310 mask->initSelection(activeLayer);
311 mask->setName(createMaskNameCommon(activeLayer, "KisFilterMask", i18n("Color Overlay Mask")));
312 mask->setFilter(filter->cloneWithResourcesSnapshot());
313
314 KisImageLayerAddCommand::Flags flags =
317
318 if (activeLayer->childCount() == 0) {
321 activeNode, true));
322
324 };
325
326 m_commandsAdapter->addNode(mask, activeLayer, activeLayer->lastChild(), flags);
327
329
330 return mask;
331}
332
334{
335 if (!activeMask()) return;
336
337 if (!m_view->nodeManager()->canModifyLayer(activeMask())) return;
338
339 if (activeMask()->inherits("KisFilterMask")) {
340 KisFilterMask *mask = static_cast<KisFilterMask*>(activeMask().data());
341
342 KisLayerSP layer = qobject_cast<KisLayer*>(mask->parent().data());
343 if (! layer)
344 return;
345
346
347 KisPaintDeviceSP dev = layer->original();
348 if (!dev) {
349 return;
350 }
351
352 KisDlgAdjLayerProps dlg(layer, mask, dev, m_view, mask->filter().data(), mask->name(), i18n("Filter Mask Properties"), m_view->mainWindowAsQWidget(), "dlgeffectmaskprops");
353
354 KisFilterConfigurationSP configBefore(mask->filter());
355 Q_ASSERT(configBefore);
356 QString xmlBefore = configBefore->toXML();
357
358 if (dlg.exec() == QDialog::Accepted) {
359
361 Q_ASSERT(configAfter);
362 QString xmlAfter = configAfter->toXML();
363
364 mask->setName(dlg.layerName());
365
366 if(xmlBefore != xmlAfter) {
368 = new KisChangeFilterCmd(mask,
369 configBefore->cloneWithResourcesSnapshot(),
370 configAfter->cloneWithResourcesSnapshot());
371
372 // FIXME: check whether is needed
373 cmd->redo();
375 m_view->document()->setModified(true);
376 }
377 }
378 else {
380 Q_ASSERT(configAfter);
381 QString xmlAfter = configAfter->toXML();
382
383 if(xmlBefore != xmlAfter) {
384 mask->setFilter(configBefore->cloneWithResourcesSnapshot());
385 mask->setDirty();
386 }
387 }
388
389 } else {
390 // Not much to show for transparency or selection masks?
391 }
392}
QList< QString > QStringList
const quint8 OPACITY_OPAQUE_U8
char nodeType(const KoPathPoint *point)
A KisActionManager class keeps track of KisActions. These actions are always associated with the GUI....
KUndo2Command * setColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags(), KoUpdater *progressUpdater=nullptr)
The command for deselection the global selection of KisImage.
KisFilterConfigurationSP filterConfiguration() const
void setModified(bool _mod)
void setFilter(KisFilterConfigurationSP filterConfig, bool checkCompareConfig=true) override
static KisFilterRegistry * instance()
static KisResourcesInterfaceSP instance()
const KoColorSpace * colorSpace() const
QString nextLayerName(const QString &baseName="") const
Definition kis_image.cc:715
A container for a set of QAction objects.
KisNodeCommandsAdapter * m_commandsAdapter
KisViewManager * m_view
KisMaskManager(KisViewManager *view)
KisNodeSP createTransformMask(KisNodeSP activeNode)
void createMaskCommon(KisMaskSP mask, KisNodeSP activeNode, KisPaintDeviceSP copyFrom, const KUndo2MagicString &macroName, const QString &nodeType, const QString &nodeName, bool suppressSelection, bool avoidActiveNode, bool updateImage=true)
void setup(KisKActionCollection *actionCollection, KisActionManager *actionManager)
void activateMask(KisMaskSP mask)
KisNodeSP createSelectionMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool convertActiveNode)
KisPaintDeviceSP activeDevice()
KisNodeSP createColorizeMask(KisNodeSP activeNode)
KisMaskSP activeMask()
void setView(QPointer< KisView >view)
KisNodeSP createFastColorOverlayMask(KisNodeSP activeNode)
KisNodeSP createTransparencyMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool convertActiveNode)
QPointer< KisView > m_imageView
KisNodeSP createFilterMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool quiet, bool convertActiveNode)
QString createMaskNameCommon(KisNodeSP targetNode, const QString &nodeType, const QString &desiredName)
void adjustMaskPosition(KisNodeSP node, KisNodeSP activeNode, bool avoidActiveNode, KisNodeSP &parent, KisNodeSP &above)
void addNode(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis, KisImageLayerAddCommand::Flags flags=KisImageLayerAddCommand::DoRedoUpdates|KisImageLayerAddCommand::DoUndoUpdates)
void addExtraCommand(KUndo2Command *command)
void beginMacro(const KUndo2MagicString &macroName)
virtual KisFilterConfigurationSP filter() const
bool canModifyLayer(KisNodeSP node, bool showWarning=true)
virtual void addCommand(KUndo2Command *cmd)=0
KisDocument * document() const
KisUndoAdapter * undoAdapter()
The undo adapter is used to add commands to the undo stack.
KisSelectionSP selection()
KisNodeManager * nodeManager() const
The node manager handles everything about nodes.
QWidget * mainWindowAsQWidget() const
KisImageWSP image() const
Return the image this view is displaying.
const T value(const QString &id) const
QList< T > values() const
KUndo2MagicString kundo2_i18n(const char *text)
void setName(const QString &name)
virtual const KoColorSpace * colorSpace() const =0
QString name() const
virtual KisFilterConfigurationSP defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const
KisPaintDeviceSP original() const override=0
void initSelection(KisSelectionSP copyFrom, KisLayerSP parentLayer)
initSelection initializes the selection for the mask from the given selection's projection.
Definition kis_mask.cc:157
KisPaintDeviceSP paintDevice() const override
Definition kis_mask.cc:223
KisNodeSP prevSibling() const
Definition kis_node.cpp:402
QList< KisNodeSP > childNodes(const QStringList &nodeTypes, const KoProperties &properties) const
Definition kis_node.cpp:439
quint32 childCount() const
Definition kis_node.cpp:414
KisNodeWSP parent
Definition kis_node.cpp:86
KisNodeSP lastChild() const
Definition kis_node.cpp:367
KisNodeSP nextSibling() const
Definition kis_node.cpp:408
virtual void setDirty()
Definition kis_node.cpp:577
virtual bool allowAsChild(KisNodeSP) const =0
void setActive(bool active)