Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_node_property_list_command.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2009 Cyrille Berger <cberger@cberger.net>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include <klocalizedstring.h>
8#include "kis_node.h"
9#include "kis_layer.h"
10#include "kis_image.h"
11#include "kis_selection_mask.h"
12#include "kis_paint_layer.h"
14#include "kis_undo_adapter.h"
16#include "kis_command_ids.h"
17
18#include <memory>
19
20// HACK! please refactor out!
23
24namespace {
25
26QSet<QString> changedProperties(const KisBaseNode::PropertyList &before,
27 const KisBaseNode::PropertyList &after)
28{
29 QSet<QString> changedIds;
30
31 auto valueForId = [] (const QString &id, const KisBaseNode::PropertyList &list) {
32 QVariant value;
33 Q_FOREACH (const KisBaseNode::Property &prop, list) {
34 if (prop.id == id) {
35 value = prop.state;
36 break;
37 }
38
39 }
40 return value;
41 };
42
45 const KisBaseNode::PropertyList &list1 = before.size() >= after.size() ? before : after;
46 const KisBaseNode::PropertyList &list2 = before.size() >= after.size() ? after : before;
47
48 Q_FOREACH (const KisBaseNode::Property &prop, list1) {
49 if (prop.state != valueForId(prop.id, list2)) {
50 changedIds.insert(prop.id);
51 }
52 }
53
54 return changedIds;
55}
56
57}
58
59
61 : KisNodeCommand(kundo2_i18n("Property Changes"), node),
62 m_newPropertyList(newPropertyList),
63 m_oldPropertyList(node->sectionModelProperties())
69{
70}
71
73{
75 const QSet<QString> changed = changedProperties(propsBefore, m_newPropertyList);
76 if (changed.isEmpty()) return;
77
78 const QRect oldExtent = m_node->projectionPlane()->tightUserVisibleBounds();
80
81 if (!propsWithNoUpdates().contains(changed)) {
82 doUpdate(propsBefore, m_node->sectionModelProperties(), oldExtent | m_node->projectionPlane()->tightUserVisibleBounds());
83 }
84}
85
87{
89 const QSet<QString> changed = changedProperties(propsBefore, m_oldPropertyList);
90 if (changed.isEmpty()) return;
91
92 const QRect oldExtent = m_node->projectionPlane()->tightUserVisibleBounds();
94
95 if (!propsWithNoUpdates().contains(changed)) {
96 doUpdate(propsBefore, m_node->sectionModelProperties(), oldExtent | m_node->projectionPlane()->tightUserVisibleBounds());
97 }
98}
99
104
106{
107 const KisNodePropertyListCommand *other =
108 dynamic_cast<const KisNodePropertyListCommand*>(command);
109
110 if (other && other->m_node == m_node &&
111 (changedProperties(m_oldPropertyList, m_newPropertyList).isEmpty() ||
112 changedProperties(m_oldPropertyList, m_newPropertyList) ==
113 changedProperties(other->m_oldPropertyList, other->m_newPropertyList))) {
114
115 const QSet<QString> changedInTheMeantime =
116 changedProperties(m_newPropertyList, other->m_oldPropertyList);
117
118 KIS_SAFE_ASSERT_RECOVER_NOOP(changedInTheMeantime.isEmpty() ||
119 (changedInTheMeantime.size() == 1 &&
120 *changedInTheMeantime.begin() == KisLayerPropertiesIcons::colorOverlay.id()));
121
123 return true;
124 }
125
126 return false;
127}
128
130{
131 const KisNodePropertyListCommand *other =
132 dynamic_cast<const KisNodePropertyListCommand*>(command);
133
134 return other && other->m_node == m_node &&
135 (changedProperties(m_oldPropertyList, m_newPropertyList).isEmpty() ||
136 changedProperties(m_oldPropertyList, m_newPropertyList) ==
137 changedProperties(other->m_oldPropertyList, other->m_newPropertyList));
138}
139
141{
142 const KisNodePropertyListCommand *other =
143 dynamic_cast<const KisNodePropertyListCommand*>(command);
144
145 return other && other->m_node == m_node &&
146 changedProperties(m_oldPropertyList, other->m_newPropertyList).isEmpty();
147}
148
150 const KisBaseNode::PropertyList &newPropertyList)
151{
152 return changedProperties(oldPropertyList, newPropertyList).contains(KisLayerPropertiesIcons::onionSkins.id());
153}
154
155
157 const KisBaseNode::PropertyList &newPropertyList,
158 const QRect &totalUpdateExtent)
159{
164 if (oldPropertyList == newPropertyList) {
165 return;
166 }
167
168 bool oldPassThroughValue = false;
169 bool newPassThroughValue = false;
170
171 bool oldVisibilityValue = false;
172 bool newVisibilityValue = false;
173
174 Q_FOREACH (const KisBaseNode::Property &prop, oldPropertyList) {
176 oldPassThroughValue = prop.state.toBool();
177 }
178 if (prop.id == KisLayerPropertiesIcons::visible.id()) {
179 oldVisibilityValue = prop.state.toBool();
180 }
181 }
182
183 Q_FOREACH (const KisBaseNode::Property &prop, newPropertyList) {
185 newPassThroughValue = prop.state.toBool();
186 }
187 if (prop.id == KisLayerPropertiesIcons::visible.id()) {
188 newVisibilityValue = prop.state.toBool();
189 }
190 }
191
192 if (oldPassThroughValue && !newPassThroughValue) {
193 KisLayerSP layer(qobject_cast<KisLayer*>(m_node.data()));
194 KisImageSP image = layer->image().toStrongRef();
195 if (image) {
196 image->refreshGraphAsync(layer);
197 }
198 } else if ((m_node->parent() && !oldPassThroughValue && newPassThroughValue) ||
199 (oldPassThroughValue && newPassThroughValue &&
200 !oldVisibilityValue && newVisibilityValue)) {
201
202 KisLayerSP layer(qobject_cast<KisLayer*>(m_node->parent().data()));
203 KisImageSP image = layer->image().toStrongRef();
204 if (image) {
205 image->refreshGraphAsync(layer);
206 }
207 } else if (checkOnionSkinChanged(oldPropertyList, newPropertyList)) {
208 m_node->setDirtyDontResetAnimationCache(totalUpdateExtent);
209 } else {
210 m_node->setDirty(totalUpdateExtent); // TODO check if visibility was actually changed or not
211 }
212}
213
227
229{
230 const QSet<QString> properties = changedProperties(node->sectionModelProperties(), proplist);
231
232 const bool undo = !properties.isEmpty() &&
233 (properties.size() != 1 ||
235
236 std::unique_ptr<KUndo2Command> cmd(new KisNodePropertyListCommand(node, proplist));
237
238 if (undo) {
239 image->undoAdapter()->addCommand(cmd.release());
240 }
241 else {
253 struct SimpleLodResettingStroke : public KisSimpleStrokeStrategy {
254 SimpleLodResettingStroke(KUndo2Command *cmd)
255 : KisSimpleStrokeStrategy(QLatin1String("SimpleLodResettingStroke")),
256 m_cmd(cmd)
257 {
258 setClearsRedoOnStart(false);
259 this->enableJob(JOB_INIT, true);
260 }
261
262 void initStrokeCallback() override {
263 m_cmd->redo();
264 // NOTE: we don't Q_EMIT imageModified signal here because this
265 // branch is only taken for the stasis changes, that do not
266 // change actual image representation.
267 }
268
269 private:
270 QScopedPointer<KUndo2Command> m_cmd;
271 };
272
273 KisStrokeId strokeId = image->startStroke(new SimpleLodResettingStroke(cmd.release()));
274 image->endStroke(strokeId);
275 }
276
277}
float value(const T *src, size_t ch)
KisUndoAdapter * undoAdapter() const
void refreshGraphAsync(KisNodeSP root, const QVector< QRect > &rects, const QRect &cropRect, KisProjectionUpdateFlags flags=KisProjectionUpdateFlag::None) override
KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy) override
void endStroke(KisStrokeId id) override
static bool isStatelessProperty(const QString &id)
the base command for commands altering a node
The command for changing the property list of a layer.
bool mergeWith(const KUndo2Command *command) override
KisBaseNode::PropertyList m_newPropertyList
KisBaseNode::PropertyList m_oldPropertyList
static void setNodePropertiesAutoUndo(KisNodeSP node, KisImageSP image, PropertyList proplist)
KisNodePropertyListCommand(KisNodeSP node, KisBaseNode::PropertyList newPropertyList)
bool canAnnihilateWith(const KUndo2Command *other) const override
bool canMergeWith(const KUndo2Command *command) const override
void doUpdate(const KisBaseNode::PropertyList &oldPropertyList, const KisBaseNode::PropertyList &newPropertyList, const QRect &totalUpdateExtent)
static const QSet< QString > & propsWithNoUpdates()
virtual void addCommand(KUndo2Command *cmd)=0
KisSharedPtr< T > toStrongRef() const
toStrongRef returns a KisSharedPtr which may be dereferenced.
QString id() const
Definition KoID.cpp:63
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
bool checkOnionSkinChanged(const KisBaseNode::PropertyList &oldPropertyList, const KisBaseNode::PropertyList &newPropertyList)
KUndo2MagicString kundo2_i18n(const char *text)
KisImageWSP image
virtual PropertyList sectionModelProperties() const
virtual void setSectionModelProperties(const PropertyList &properties)
void setDirtyDontResetAnimationCache()
Definition kis_node.cpp:599
virtual KisAbstractProjectionPlaneSP projectionPlane() const
Definition kis_node.cpp:240
KisNodeWSP parent
Definition kis_node.cpp:86
virtual void setDirty()
Definition kis_node.cpp:577