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_command_utils.h>
36#include <kis_image.h>
38#include <KoColorSpace.h>
39#include <KoColor.h>
43#include "kis_iterator_ng.h"
45#include "kis_node_manager.h"
46
47
49 : m_view(view)
50 , m_imageView(0)
51 , m_commandsAdapter(new KisNodeCommandsAdapter(m_view))
52{
53}
54
56{
57 m_imageView = imageView;
58}
59
60void KisMaskManager::setup(KisKActionCollection *actionCollection, KisActionManager *actionManager)
61{
62 Q_UNUSED(actionCollection);
63 Q_UNUSED(actionManager);
64}
65
67{
68 // XXX: enable/disable menu items according to whether there's a mask selected currently
69 // XXX: disable the selection mask item if there's already a selection mask
70 // YYY: doesn't KisAction do that already?
71}
72
74{
75 if (m_imageView) {
76 return m_imageView->currentMask();
77 }
78 return 0;
79}
80
82{
83 KisMaskSP mask = activeMask();
84 return mask ? mask->paintDevice() : 0;
85}
86
88{
89 Q_UNUSED(mask);
90}
91
96
97void KisMaskManager::adjustMaskPosition(KisNodeSP node, KisNodeSP activeNode, bool avoidActiveNode, KisNodeSP &parent, KisNodeSP &above)
98{
99 Q_ASSERT(node);
100 Q_ASSERT(activeNode);
101
102 if (!avoidActiveNode && activeNode->allowAsChild(node)) {
103 parent = activeNode;
104 above = activeNode->lastChild();
105 } else if (activeNode->parent() && activeNode->parent()->allowAsChild(node)
106 && activeNode->parent()->parent() /* we don't want to add masks to root */) {
107 parent = activeNode->parent();
108 above = activeNode;
109 } else {
110 KisNodeSP t = activeNode;
111 while ((t = t->nextSibling())) {
112 if (t->allowAsChild(node)) {
113 parent = t;
114 above = t->lastChild();
115 break;
116 }
117 }
118
119 if (!t) {
120 t = activeNode;
121 while ((t = t->prevSibling())) {
122 if (t->allowAsChild(node)) {
123 parent = t;
124 above = t->lastChild();
125 break;
126 }
127 }
128 }
129
130 if (!t && activeNode->parent()) {
131 adjustMaskPosition(node, activeNode->parent(), true, parent, above);
132 } else if (!t) {
133 KisImageWSP image = m_view->image();
134 KisLayerSP layer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, image->colorSpace());
135 m_commandsAdapter->addNode(layer, activeNode, 0);
136
137 parent = layer;
138 above = 0;
139 }
140 }
141}
142
144 KisNodeSP activeNode,
145 KisPaintDeviceSP copyFrom,
146 const KUndo2MagicString& macroName,
147 const QString &nodeType,
148 const QString &nodeName,
149 bool suppressSelection,
150 bool avoidActiveNode,
151 bool updateImage)
152{
153 m_commandsAdapter->beginMacro(macroName);
154
155 KisNodeSP parent;
156 KisNodeSP above;
157 adjustMaskPosition(mask, activeNode, avoidActiveNode, parent, above);
158
159 KisLayerSP parentLayer = qobject_cast<KisLayer*>(parent.data());
160 Q_ASSERT(parentLayer);
161
162 bool shouldDeselectGlobalSelection = false;
163
164 if (!suppressSelection) {
165 if (copyFrom) {
166 mask->initSelection(copyFrom, parentLayer);
167 } else {
168 mask->initSelection(m_view->selection(), parentLayer);
169 shouldDeselectGlobalSelection = m_view->selection();
170 }
171 }
172
173 mask->setName( createMaskNameCommon(parentLayer, nodeType, nodeName) );
174
175 KisImageLayerAddCommand::Flags flags =
176 updateImage ?
179
180 m_commandsAdapter->addNode(mask, parentLayer, above, flags);
181
182 if (shouldDeselectGlobalSelection) {
184 }
185
187
188 masksUpdated();
189}
190
191QString KisMaskManager::createMaskNameCommon(KisNodeSP targetNode, const QString &nodeType, const QString &desiredName)
192{
194 int number = masks.count() + 1;
195 return desiredName + QString(" ") + QString::number(number);
196}
197
198KisNodeSP KisMaskManager::createSelectionMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool convertActiveNode)
199{
200 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
201
203
204 createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Selection Mask"), "KisSelectionMask", i18n("Selection"), false, convertActiveNode, false);
205 mask->setActive(true);
206 if (convertActiveNode) {
207 m_commandsAdapter->removeNode(activeNode);
208 }
209 return mask;
210}
211
213{
214 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
215
216 KisMaskSP mask = new KisTransparencyMask(m_view->image(), "");
217 createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Transparency Mask"), "KisTransparencyMask", i18n("Transparency Mask"), false, convertActiveNode);
218 if (convertActiveNode) {
219 m_commandsAdapter->removeNode(activeNode);
220 }
221 return mask;
222}
223
224
225KisNodeSP KisMaskManager::createFilterMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool quiet, bool convertActiveNode)
226{
227 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
228
229 KisFilterMaskSP mask = new KisFilterMask(m_view->image(), "");
230 createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Filter Mask"), "KisFilterMask", i18n("Filter Mask"), false, convertActiveNode);
231
232 if (convertActiveNode) {
233 m_commandsAdapter->removeNode(activeNode);
234 }
235
241 KisPaintDeviceSP originalDevice = mask->parent()->original();
242
243
244 KisDlgAdjustmentLayer dialog(mask, mask.data(), originalDevice,
245 mask->name(), i18n("New Filter Mask"),
246 m_view, qApp->activeWindow());
247
248 // If we are supposed to not disturb the user, don't start asking them about things.
249 if(quiet) {
251 if (filter) {
252 mask->setFilter(filter->cloneWithResourcesSnapshot());
253 mask->setName(mask->name());
254 }
255 return mask;
256 }
257
258 if (dialog.exec() == QDialog::Accepted) {
259 KisFilterConfigurationSP filter = dialog.filterConfiguration();
260 if (filter) {
261 QString name = dialog.layerName();
262 mask->setFilter(filter->cloneWithResourcesSnapshot());
263 mask->setName(name);
264 }
265
266 return mask;
267
268 } else {
270 }
271
272 return 0;
273}
274
275
277{
278 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
279
281 createMaskCommon(mask, activeNode, 0, kundo2_i18n("Add Colorize Mask"), "KisColorizeMask", i18n("Colorize Mask"), true, false);
282 mask->initializeCompositeOp();
283 delete mask->setColorSpace(mask->parent()->colorSpace());
284 return mask;
285}
286
287
289{
290 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
291
293 createMaskCommon(mask, activeNode, 0, kundo2_i18n("Add Transform Mask"), "KisTransformMask", i18n("Transform Mask"), true, false);
294 return mask;
295}
296
298{
299 if (!m_view->nodeManager()->canModifyLayer(activeNode)) return 0;
300
301 KisLayerSP activeLayer = qobject_cast<KisLayer*>(activeNode.data());
302 Q_ASSERT(activeLayer);
303
306 if (!filter) return nullptr;
307
308 m_commandsAdapter->beginMacro(kundo2_i18n("Add Fast Color Overlay"));
309
310 KisFilterMaskSP mask = new KisFilterMask(m_view->image(), "");
311 mask->initSelection(activeLayer);
312 mask->setName(createMaskNameCommon(activeLayer, "KisFilterMask", i18n("Color Overlay Mask")));
313 mask->setFilter(filter->cloneWithResourcesSnapshot());
314
315 KisImageLayerAddCommand::Flags flags =
318
319 if (activeLayer->childCount() == 0) {
322 activeNode, true));
323
325 };
326
327 m_commandsAdapter->addNode(mask, activeLayer, activeLayer->lastChild(), flags);
328
330
331 return mask;
332}
333
335{
336 if (!activeMask()) return;
337
338 if (!m_view->nodeManager()->canModifyLayer(activeMask())) return;
339
340 if (activeMask()->inherits("KisFilterMask")) {
341 KisFilterMask *mask = static_cast<KisFilterMask*>(activeMask().data());
342
343 KisLayerSP layer = qobject_cast<KisLayer*>(mask->parent().data());
344 if (! layer)
345 return;
346
347
348 KisPaintDeviceSP dev = layer->original();
349 if (!dev) {
350 return;
351 }
352
353 KisDlgAdjustmentLayer dlg(mask, mask, dev, mask->name(),
354 i18n("Filter Mask Properties"), m_view,
355 m_view->mainWindowAsQWidget(), mask->filter());
356
357 KisFilterConfigurationSP configBefore(mask->filter());
358 Q_ASSERT(configBefore);
359 QString xmlBefore = configBefore->toXML();
360
361 if (dlg.exec() == QDialog::Accepted) {
362
364 Q_ASSERT(configAfter);
365 QString xmlAfter = configAfter->toXML();
366
367 KUndo2Command *cmd = nullptr;
368
369 if(xmlBefore != xmlAfter) {
371 new KisChangeFilterCmd(mask,
372 configBefore->cloneWithResourcesSnapshot(),
373 configAfter->cloneWithResourcesSnapshot()));
374 }
375
376 if (mask->name() != dlg.layerName()) {
378 new KisNodeRenameCommand(mask, mask->name(), dlg.layerName()));
379 }
380
381 if (cmd) {
383 m_view->document()->setModified(true);
384 }
385 }
386 else {
388 Q_ASSERT(configAfter);
389 QString xmlAfter = configAfter->toXML();
390
391 if(xmlBefore != xmlAfter) {
392 mask->setFilter(configBefore->cloneWithResourcesSnapshot());
393 mask->setDirty();
394 }
395 }
396
397 } else {
398 // Not much to show for transparency or selection masks?
399 }
400}
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:741
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)
The command for setting the node's name.
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)
KUndo2Command * composeCommands(KUndo2Command *parent, KUndo2Command *cmd)
virtual const KoColorSpace * colorSpace() const =0
QString name() const
virtual KisFilterConfigurationSP defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const
KisPaintDeviceSP original() const override=0
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)