Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAnimCurvesChannelsModel.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2016 Jouni Pentikäinen <joupent@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QApplication>
10#include <QPalette>
11
12#include "KisAnimCurvesModel.h"
15#include "kis_node.h"
19#include <kis_painting_tweaks.h>
20#include "KisAnimUtils.h"
21#include <kis_image.h>
22
23const quintptr ID_NODE = 0xffffffff;
24
34
36{
40
42
46
48 if (row < 0 || row >= items.count())
49 return nullptr;
50 return items.at(row);
51 }
52
54 for (int row=0; row < items.count(); row++) {
55 if (items.at(row)->dummy == dummy) return row;
56 }
57
58 return -1;
59 }
60
62 KisScalarKeyframeChannel *scalarChannel = dynamic_cast<KisScalarKeyframeChannel*>(channel);
63
64 if (scalarChannel) {
65 KisAnimationCurve *curve = curvesModel->addCurve(scalarChannel);
66 nodeItem->curves.append(curve);
67 }
68 }
69};
70
72 : QAbstractItemModel(parent)
73 , m_d(new Private(curvesModel))
74{}
75
77{
78 qDeleteAll(m_d->items);
79 m_d->items.clear();
80}
81
83{
84 m_d->dummiesFacadeConnections.clear();
85 m_d->dummiesFacade = facade;
86 m_d->dummiesFacadeConnections.addConnection(m_d->dummiesFacade, SIGNAL(sigBeginRemoveDummy(KisNodeDummy*)),
88}
89
91{
92 // Remove unselected nodes
93 for (int i = m_d->items.count()-1; i >= 0; i--) {
94 NodeListItem *item = m_d->items.at(i);
95 if (item && item->dummy) {
96 if (!nodes.contains(item->dummy->node())) {
97 beginRemoveRows(QModelIndex(), i, i);
98 m_d->items.removeAt(i);
99 endRemoveRows();
100
101 Q_FOREACH(KisAnimationCurve *curve, item->curves) {
102 m_d->curvesModel->removeCurve(curve);
103
104 }
105
106 if (!item->dummy->node().isNull()) {
107 item->dummy->node()->disconnect(this);
108 }
109
110 delete item;
111 }
112 }
113 }
114
115 // Add newly selected nodes
116 Q_FOREACH(KisNodeSP node, nodes) {
117 KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(node);
118 if (!dummy) continue;
119
120 if (m_d->rowForDummy(dummy) == -1) {
121 beginInsertRows(QModelIndex(), m_d->items.count(), m_d->items.count());
122
123 NodeListItem *item = new NodeListItem(dummy);
124 m_d->items.append(item);
125
126 Q_FOREACH(KisKeyframeChannel *channel, dummy->node()->keyframeChannels()) {
127 m_d->addCurveForChannel(item, channel);
128 }
129
132
133 endInsertRows();
134 }
135 }
136}
137
138void KisAnimCurvesChannelsModel::reset(const QModelIndex &index)
139{
140 const quintptr parentRow = index.internalId();
141 const bool indexIsNode = (parentRow == ID_NODE);
142
143 if (indexIsNode) {
144 NodeListItem *item = m_d->itemForRow(index.row());
145
146 KisNodeSP node = item->dummy->node();
147 if (!node || !node->image())
148 return;
149
150 KisImageSP image = node->image().toStrongRef();
151
152 QList<KisAnimationCurve*> curves = item->curves;
153 QList<QString> ids;
154 Q_FOREACH( const KisAnimationCurve* curve, curves ) {
155 ids << curve->channel()->id();
156 }
157
158 KisAnimUtils::resetChannels(image, node, ids);
159
160 } else {
161 NodeListItem *item = m_d->itemForRow(parentRow);
162
163 KisAnimationCurve* curve = item->curves.at(index.row());
164
165 if (!curve)
166 return;
167
168 KisNodeSP node = item->dummy->node();
169
170 if (!node || !node->image())
171 return;
172
173 KisImageSP image = node->image().toStrongRef();
174 KisAnimUtils::resetChannel(image, node, curve->channel()->id());
175 }
176}
177
179{
180 KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(KisNodeSP(channel->node()));
181 int row = m_d->rowForDummy(dummy);
183
184 NodeListItem *item = m_d->itemForRow(row);
185
186 int newCurveRow = item->curves.count();
187 beginInsertRows(index(row, 0, QModelIndex()), newCurveRow, newCurveRow);
188
189 m_d->addCurveForChannel(item, channel);
190
191 endInsertRows();
192}
193
195{
196 bool shouldChangeSelection = false;
197 KisNodeList newSelectedNodes;
198
199 Q_FOREACH (NodeListItem *item, m_d->items) {
200 if (item->dummy == dummy) {
201 shouldChangeSelection = true;
202 break;
203 }
204
205 newSelectedNodes << item->dummy->node();
206 }
207
208 if (shouldChangeSelection) {
209 selectedNodesChanged(newSelectedNodes);
210 }
211}
212
213QModelIndex KisAnimCurvesChannelsModel::index(int row, int column, const QModelIndex &parent) const
214{
215 Q_UNUSED(column);
216
217 if (!parent.isValid()) {
218 // Node
219
220 NodeListItem *item = m_d->itemForRow(row);
221 if (!item) return QModelIndex();
222
223 return createIndex(row, column, ID_NODE);
224 } else {
225 // Channel
226 if (parent.parent().isValid()) return QModelIndex();
227
228 NodeListItem *parentItem = m_d->itemForRow(parent.row());
229 if (!parentItem) return QModelIndex();
230
231 if (row >= parentItem->curves.count()) return QModelIndex();
232
233 return createIndex(row, column, parent.row());
234 }
235}
236
237QModelIndex KisAnimCurvesChannelsModel::parent(const QModelIndex &child) const
238{
239 quintptr parentIndex = child.internalId();
240 if (parentIndex == ID_NODE) return QModelIndex();
241 return createIndex(parentIndex, 0, ID_NODE);
242}
243
244int KisAnimCurvesChannelsModel::rowCount(const QModelIndex &parent) const
245{
246 if (!parent.isValid()) {
247 // Root
248 return m_d->items.count();
249 } else if (parent.internalId() == ID_NODE) {
250 // Node
251 NodeListItem *item = m_d->itemForRow(parent.row());
252 return item->curves.count();
253 } else {
254 // Channel
255 return 0;
256 }
257}
258
259int KisAnimCurvesChannelsModel::columnCount(const QModelIndex &parent) const
260{
261 Q_UNUSED(parent);
262 return 1;
263}
264
265QVariant KisAnimCurvesChannelsModel::data(const QModelIndex &index, int role) const
266{
267 const quintptr parentRow = index.internalId();
268 const bool indexIsNode = (parentRow == ID_NODE);
269 NodeListItem *item = m_d->itemForRow(indexIsNode ? index.row() : parentRow);
270
271 switch (role) {
272 case Qt::DisplayRole: {
273 if (indexIsNode) {
274 return item->dummy->node()->name();
275 } else {
276 KisKeyframeChannel *channel = item->curves.at(index.row())->channel();
277 return channel->name();
278 }
279 } break;
280
281 case CurveRole:
282 return !indexIsNode;
283
284 case CurveColorRole:
285 return indexIsNode ? QVariant() : item->curves.at(index.row())->color();
286
288 return indexIsNode ? QVariant() : item->curves.at(index.row())->visible();
289
290 case CurveIsIsolatedRole: {
291 const bool isVisible = item->curves.at(index.row())->visible();
292 if (!isVisible)
293 return false;
294
295 int numVisible = 0;
296 for (int i = 0; i < item->curves.size(); i++) {
297 if ( numVisible > 1)
298 return false;
299
300 if (item->curves.at(i)->visible())
301 numVisible++;
302 }
303
304 return (numVisible == 1);
305 }
306 case NodeColorRole: {
307
308 if (!indexIsNode)
309 return QVariant();
310
311 KisNodeViewColorScheme nodeColorScheme;
312 const QColor backgroundColor = qApp->palette().color(QPalette::Button);
313 const int colorLabelIndex = item->dummy->node()->colorLabelIndex();
314 const QColor nodeColor = nodeColorScheme.colorFromLabelIndex(colorLabelIndex);
315 return colorLabelIndex > 0 ? KisPaintingTweaks::blendColors(nodeColor, backgroundColor, 0.3) : backgroundColor;
316 }
317 default:
318 break;
319 }
320
321 return QVariant();
322}
323
324bool KisAnimCurvesChannelsModel::setData(const QModelIndex &index, const QVariant &value, int role)
325{
326 quintptr parentRow = index.internalId();
327 bool indexIsNode = (parentRow == ID_NODE);
328 NodeListItem *item = m_d->itemForRow(indexIsNode ? index.row() : parentRow);
329
330 switch (role) {
332 KIS_ASSERT_RECOVER_BREAK(!indexIsNode);
333 m_d->curvesModel->setCurveVisible(item->curves.at(index.row()), value.toBool());
334 this->dataChanged(index, index);
335 return true;
336 }
337
338 return false;
339}
340
341
343{
344 qDeleteAll(m_d->items);
345 m_d->items.clear();
346}
float value(const T *src, size_t ch)
const quintptr ID_NODE
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
KisAnimCurvesChannelsModel(KisAnimCurvesModel *curvesModel, QObject *parent)
int columnCount(const QModelIndex &parent) const override
void reset(const QModelIndex &index)
QModelIndex parent(const QModelIndex &child) const override
void setDummiesFacade(KisDummiesFacadeBase *facade)
void keyframeChannelAddedToNode(KisKeyframeChannel *channel)
void selectedNodesChanged(const QList< KisNodeSP > &nodes)
const QScopedPointer< Private > m_d
int rowCount(const QModelIndex &parent) const override
bool setData(const QModelIndex &index, const QVariant &value, int role) override
QVariant data(const QModelIndex &index, int role) const override
QModelIndex index(int row, int column, const QModelIndex &parent) const override
void slotNotifyDummyRemoved(KisNodeDummy *dummy)
KisAnimationCurve * addCurve(KisScalarKeyframeChannel *channel)
KisScalarKeyframeChannel * channel() const
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
KisNodeSP node() const
QColor colorFromLabelIndex(int index) const
The KisScalarKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisSca...
bool isNull() const
KisSharedPtr< T > toStrongRef() const
toStrongRef returns a KisSharedPtr which may be dereferenced.
#define KIS_ASSERT_RECOVER_BREAK(cond)
Definition kis_assert.h:65
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
void resetChannels(KisImageSP image, KisNodeSP node, const QList< QString > &channelIDs)
void resetChannel(KisImageSP image, KisNodeSP node, const QString &channelID)
QColor blendColors(const QColor &c1, const QColor &c2, qreal r1)
void addCurveForChannel(NodeListItem *nodeItem, KisKeyframeChannel *channel)
KisSignalAutoConnectionsStore dummiesFacadeConnections
QMap< QString, KisKeyframeChannel * > keyframeChannels
void keyframeChannelAdded(KisKeyframeChannel *channel)
KisImageWSP image
int colorLabelIndex() const
QString name() const
QList< KisAnimationCurve * > curves
NodeListItem(KisNodeDummy *dummy)