File indexing completed on 2024-12-22 04:14:40

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Jouni Pentikäinen <joupent@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "KisAnimCurvesChannelsModel.h"
0008 
0009 #include "KisAnimCurvesModel.h"
0010 #include "kis_dummies_facade_base.h"
0011 #include "kis_node_dummies_graph.h"
0012 #include "kis_node.h"
0013 #include "kis_node_view_color_scheme.h"
0014 #include "kis_scalar_keyframe_channel.h"
0015 #include "kis_signal_auto_connection.h"
0016 #include <kis_painting_tweaks.h>
0017 #include "kis_image.h"
0018 #include "KisAnimUtils.h"
0019 
0020 #include <QApplication>
0021 
0022 const quintptr ID_NODE = 0xffffffff;
0023 
0024 struct NodeListItem
0025 {
0026     NodeListItem(KisNodeDummy *dummy)
0027         : dummy(dummy)
0028     {}
0029 
0030     KisNodeDummy *dummy;
0031     QList<KisAnimationCurve*> curves;
0032 };
0033 
0034 struct KisAnimCurvesChannelsModel::Private
0035 {
0036     KisAnimCurvesModel *curvesModel;
0037     KisDummiesFacadeBase *dummiesFacade = 0;
0038     KisSignalAutoConnectionsStore dummiesFacadeConnections;
0039 
0040     QList<NodeListItem*> items;
0041 
0042     Private(KisAnimCurvesModel *curvesModel)
0043         : curvesModel(curvesModel)
0044     {}
0045 
0046     NodeListItem * itemForRow(int row) {
0047         if (row < 0 || row >= items.count())
0048             return nullptr;
0049         return items.at(row);
0050     }
0051 
0052     int rowForDummy(KisNodeDummy *dummy) {
0053         for (int row=0; row < items.count(); row++) {
0054             if (items.at(row)->dummy == dummy) return row;
0055         }
0056 
0057         return -1;
0058     }
0059 
0060     void addCurveForChannel(NodeListItem *nodeItem, KisKeyframeChannel *channel) {
0061         KisScalarKeyframeChannel *scalarChannel = dynamic_cast<KisScalarKeyframeChannel*>(channel);
0062 
0063         if (scalarChannel) {
0064             KisAnimationCurve *curve = curvesModel->addCurve(scalarChannel);
0065             nodeItem->curves.append(curve);
0066         }
0067     }
0068 };
0069 
0070 KisAnimCurvesChannelsModel::KisAnimCurvesChannelsModel(KisAnimCurvesModel *curvesModel, QObject *parent)
0071     : QAbstractItemModel(parent)
0072     , m_d(new Private(curvesModel))
0073 {}
0074 
0075 KisAnimCurvesChannelsModel::~KisAnimCurvesChannelsModel()
0076 {
0077     qDeleteAll(m_d->items);
0078     m_d->items.clear();
0079 }
0080 
0081 void KisAnimCurvesChannelsModel::setDummiesFacade(KisDummiesFacadeBase *facade)
0082 {
0083     m_d->dummiesFacadeConnections.clear();
0084     m_d->dummiesFacade = facade;
0085     m_d->dummiesFacadeConnections.addConnection(m_d->dummiesFacade, SIGNAL(sigBeginRemoveDummy(KisNodeDummy*)),
0086                                                 this, SLOT(slotNotifyDummyRemoved(KisNodeDummy*)));
0087 }
0088 
0089 void KisAnimCurvesChannelsModel::selectedNodesChanged(const KisNodeList &nodes)
0090 {
0091     // Remove unselected nodes
0092     for (int i = m_d->items.count()-1; i >= 0; i--) {
0093         NodeListItem *item = m_d->items.at(i);
0094         if (item && item->dummy) {
0095             if (!nodes.contains(item->dummy->node())) {
0096                 beginRemoveRows(QModelIndex(), i, i);
0097                 m_d->items.removeAt(i);
0098                 endRemoveRows();
0099 
0100                 Q_FOREACH(KisAnimationCurve *curve, item->curves) {
0101                     m_d->curvesModel->removeCurve(curve);
0102 
0103                 }
0104 
0105                 if (!item->dummy->node().isNull()) {
0106                     item->dummy->node()->disconnect(this);
0107                 }
0108 
0109                 delete item;
0110             }
0111         }
0112     }
0113 
0114     // Add newly selected nodes
0115     Q_FOREACH(KisNodeSP node, nodes) {
0116         KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(node);
0117         if (!dummy) continue;
0118 
0119         if (m_d->rowForDummy(dummy) == -1) {
0120             beginInsertRows(QModelIndex(), m_d->items.count(), m_d->items.count());
0121 
0122             NodeListItem *item = new NodeListItem(dummy);
0123             m_d->items.append(item);
0124 
0125             Q_FOREACH(KisKeyframeChannel *channel, dummy->node()->keyframeChannels()) {
0126                 m_d->addCurveForChannel(item, channel);
0127             }
0128 
0129             connect(node.data(), &KisNode::keyframeChannelAdded,
0130                     this, &KisAnimCurvesChannelsModel::keyframeChannelAddedToNode);
0131 
0132             endInsertRows();
0133         }
0134     }
0135 }
0136 
0137 void KisAnimCurvesChannelsModel::reset(const QModelIndex &index)
0138 {
0139     const quintptr parentRow = index.internalId();
0140     const bool indexIsNode = (parentRow == ID_NODE);
0141 
0142     if (indexIsNode) {
0143         NodeListItem *item = m_d->itemForRow(index.row());
0144 
0145         KisNodeSP node = item->dummy->node();
0146         if (!node || !node->image())
0147             return;
0148 
0149         KisImageSP image = node->image().toStrongRef();
0150 
0151         QList<KisAnimationCurve*> curves = item->curves;
0152         QList<QString> ids;
0153         Q_FOREACH( const KisAnimationCurve* curve, curves ) {
0154             ids << curve->channel()->id();
0155         }
0156 
0157         KisAnimUtils::resetChannels(image, node, ids);
0158 
0159     } else {
0160         NodeListItem *item = m_d->itemForRow(parentRow);
0161 
0162         KisAnimationCurve* curve = item->curves.at(index.row());
0163 
0164         if (!curve)
0165             return;
0166 
0167         KisNodeSP node = item->dummy->node();
0168 
0169         if (!node || !node->image())
0170             return;
0171 
0172         KisImageSP image = node->image().toStrongRef();
0173         KisAnimUtils::resetChannel(image, node, curve->channel()->id());
0174     }
0175 }
0176 
0177 void KisAnimCurvesChannelsModel::keyframeChannelAddedToNode(KisKeyframeChannel *channel)
0178 {
0179     KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(KisNodeSP(channel->node()));
0180     int row = m_d->rowForDummy(dummy);
0181     KIS_ASSERT_RECOVER_RETURN(row >= 0);
0182 
0183     NodeListItem *item = m_d->itemForRow(row);
0184 
0185     int newCurveRow = item->curves.count();
0186     beginInsertRows(index(row, 0, QModelIndex()), newCurveRow, newCurveRow);
0187 
0188     m_d->addCurveForChannel(item, channel);
0189 
0190     endInsertRows();
0191 }
0192 
0193 void KisAnimCurvesChannelsModel::slotNotifyDummyRemoved(KisNodeDummy *dummy)
0194 {
0195     bool shouldChangeSelection = false;
0196     KisNodeList newSelectedNodes;
0197 
0198     Q_FOREACH (NodeListItem *item, m_d->items) {
0199         if (item->dummy == dummy) {
0200             shouldChangeSelection = true;
0201             break;
0202         }
0203 
0204         newSelectedNodes << item->dummy->node();
0205     }
0206 
0207     if (shouldChangeSelection) {
0208         selectedNodesChanged(newSelectedNodes);
0209     }
0210 }
0211 
0212 QModelIndex KisAnimCurvesChannelsModel::index(int row, int column, const QModelIndex &parent) const
0213 {
0214     Q_UNUSED(column);
0215 
0216     if (!parent.isValid()) {
0217         // Node
0218 
0219         NodeListItem *item = m_d->itemForRow(row);
0220         if (!item) return QModelIndex();
0221 
0222         return createIndex(row, column, ID_NODE);
0223     } else {
0224         // Channel
0225         if (parent.parent().isValid()) return QModelIndex();
0226 
0227         NodeListItem *parentItem = m_d->itemForRow(parent.row());
0228         if (!parentItem) return QModelIndex();
0229 
0230         if (row >= parentItem->curves.count()) return QModelIndex();
0231 
0232         return createIndex(row, column, parent.row());
0233     }
0234 }
0235 
0236 QModelIndex KisAnimCurvesChannelsModel::parent(const QModelIndex &child) const
0237 {
0238     quintptr parentIndex = child.internalId();
0239     if (parentIndex == ID_NODE) return QModelIndex();
0240     return createIndex(parentIndex, 0, ID_NODE);
0241 }
0242 
0243 int KisAnimCurvesChannelsModel::rowCount(const QModelIndex &parent) const
0244 {
0245     if (!parent.isValid()) {
0246         // Root
0247         return m_d->items.count();
0248     } else if (parent.internalId() == ID_NODE) {
0249         // Node
0250         NodeListItem *item = m_d->itemForRow(parent.row());
0251         return item->curves.count();
0252     } else {
0253         // Channel
0254         return 0;
0255     }
0256 }
0257 
0258 int KisAnimCurvesChannelsModel::columnCount(const QModelIndex &parent) const
0259 {
0260     Q_UNUSED(parent);
0261     return 1;
0262 }
0263 
0264 QVariant KisAnimCurvesChannelsModel::data(const QModelIndex &index, int role) const
0265 {
0266     const quintptr parentRow = index.internalId();
0267     const bool indexIsNode = (parentRow == ID_NODE);
0268     NodeListItem *item = m_d->itemForRow(indexIsNode ? index.row() : parentRow);
0269 
0270     switch (role) {
0271     case Qt::DisplayRole: {
0272         if (indexIsNode) {
0273             return item->dummy->node()->name();
0274         } else {
0275             KisKeyframeChannel *channel = item->curves.at(index.row())->channel();
0276             return channel->name();
0277         }
0278     } break;
0279 
0280     case CurveRole:
0281         return !indexIsNode;
0282 
0283     case CurveColorRole:
0284         return indexIsNode ? QVariant() : item->curves.at(index.row())->color();
0285 
0286     case CurveVisibilityRole:
0287         return indexIsNode ? QVariant() : item->curves.at(index.row())->visible();
0288 
0289     case CurveIsIsolatedRole: {
0290         const bool isVisible = item->curves.at(index.row())->visible();
0291         if (!isVisible)
0292             return false;
0293 
0294         int numVisible = 0;
0295         for (int i = 0; i < item->curves.size(); i++) {
0296             if ( numVisible > 1)
0297                 return false;
0298 
0299             if (item->curves.at(i)->visible())
0300                 numVisible++;
0301         }
0302 
0303         return (numVisible == 1);
0304     }
0305     case NodeColorRole: {
0306 
0307         if (!indexIsNode)
0308             return QVariant();
0309 
0310         KisNodeViewColorScheme nodeColorScheme;
0311         const QColor backgroundColor = qApp->palette().color(QPalette::Button);
0312         const int colorLabelIndex = item->dummy->node()->colorLabelIndex();
0313         const QColor nodeColor = nodeColorScheme.colorFromLabelIndex(colorLabelIndex);
0314         return colorLabelIndex > 0 ? KisPaintingTweaks::blendColors(nodeColor, backgroundColor, 0.3) : backgroundColor;
0315     }
0316     default:
0317         break;
0318     }
0319 
0320     return QVariant();
0321 }
0322 
0323 bool KisAnimCurvesChannelsModel::setData(const QModelIndex &index, const QVariant &value, int role)
0324 {
0325     quintptr parentRow = index.internalId();
0326     bool indexIsNode = (parentRow == ID_NODE);
0327     NodeListItem *item = m_d->itemForRow(indexIsNode ? index.row() : parentRow);
0328 
0329     switch (role) {
0330     case CurveVisibilityRole:
0331         KIS_ASSERT_RECOVER_BREAK(!indexIsNode);
0332         m_d->curvesModel->setCurveVisible(item->curves.at(index.row()), value.toBool());
0333         this->dataChanged(index, index);
0334         return true;
0335     }
0336 
0337     return false;
0338 }
0339 
0340 
0341 void KisAnimCurvesChannelsModel::clear()
0342 {
0343     qDeleteAll(m_d->items);
0344     m_d->items.clear();
0345 }