File indexing completed on 2024-06-16 04:16:03

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 "KisAnimCurvesChannelDelegate.h"
0008 #include "KisAnimCurvesChannelsModel.h"
0009 #include "krita_utils.h"
0010 #include "kis_icon_utils.h"
0011 
0012 #include <QApplication>
0013 #include <QMouseEvent>
0014 #include <QPainter>
0015 #include <QFontMetrics>
0016 
0017 const int CHANNEL_LEGEND_RADIUS = 6;
0018 const int CHANNEL_ICON_SIZE = 16;
0019 
0020 KisAnimCurvesChannelDelegate::KisAnimCurvesChannelDelegate(QObject *parent)
0021     : QStyledItemDelegate(parent)
0022 {}
0023 
0024 QSize KisAnimCurvesChannelDelegate::sizeHint(const QStyleOptionViewItem &styleOption, const QModelIndex &index) const
0025 {
0026     const bool isCurve = index.data(KisAnimCurvesChannelsModel::CurveRole).toBool();
0027     if (isCurve) {
0028         return QStyledItemDelegate::sizeHint(styleOption, index);
0029     } else {
0030         return QSize(24, 24);
0031     }
0032 }
0033 
0034 bool KisAnimCurvesChannelDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
0035 {
0036     if (event->type() == QEvent::MouseButtonPress) {
0037         QMouseEvent *me = static_cast<QMouseEvent*>(event);
0038 
0039         if (me->button() == Qt::LeftButton) {
0040             const bool isCurve = index.data(KisAnimCurvesChannelsModel::CurveRole).toBool();
0041             if (isCurve) {
0042                 const QRect visibilityIcon = option.rect.adjusted(option.rect.width() - CHANNEL_ICON_SIZE, 0, 0, 0);
0043 
0044                 if (visibilityIcon.contains(me->pos())) {
0045                     if (me->modifiers() & Qt::ShiftModifier) {
0046                         bool currentlyIsolated = index.data(KisAnimCurvesChannelsModel::CurveIsIsolatedRole).toBool();
0047                         if (currentlyIsolated) {
0048                             showAllChannels(model, index.parent());
0049                         } else {
0050                             soloChannelVisibility(model, index);
0051                         }
0052                     } else {
0053                         bool visible = index.data(KisAnimCurvesChannelsModel::CurveVisibilityRole).toBool();
0054                         model->setData(index, !visible, KisAnimCurvesChannelsModel::CurveVisibilityRole);
0055                     }
0056 
0057                     return true;
0058                 }
0059             }
0060         }
0061     }
0062 
0063     return false;
0064 }
0065 
0066 void KisAnimCurvesChannelDelegate::paint(QPainter *painter, const QStyleOptionViewItem &styleOption, const QModelIndex &index) const
0067 {
0068     painter->save();
0069 
0070     const bool isNode = !index.data(KisAnimCurvesChannelsModel::CurveRole).toBool();
0071     QPalette palette = QApplication::palette();
0072 
0073     // Draw background
0074     if (isNode) {
0075         QVariant colorData = index.data(KisAnimCurvesChannelsModel::NodeColorRole);
0076         KIS_ASSERT(colorData.isValid());
0077 
0078         QColor nodeBGColor = colorData.value<QColor>();
0079         paintNodeBackground(styleOption, painter, nodeBGColor);
0080     } else {
0081         styleOption.widget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem,
0082                                                    &styleOption, painter,
0083                                                    styleOption.widget);
0084     }
0085 
0086     // Draw layer name..
0087     QString text = index.data().toString();
0088     const int iconSpace = isNode ? 0 : CHANNEL_ICON_SIZE;
0089     QRect textArea = styleOption.rect.adjusted(CHANNEL_LEGEND_RADIUS + 4, 0, -iconSpace, 0);
0090     text = styleOption.fontMetrics.elidedText(text, styleOption.textElideMode, textArea.width());
0091     painter->setBrush(palette.buttonText());
0092     styleOption.widget->style()->drawItemText(painter, textArea, Qt::AlignLeft | Qt::AlignVCenter, styleOption.palette, true, text, QPalette::ButtonText);
0093 
0094     if (isNode) {
0095         // Draw Open / Close Arrow
0096         QRect arrow = QRect(styleOption.widget->rect().topLeft(), styleOption.rect.bottomLeft());
0097         painter->setPen(Qt::NoPen);
0098         QStyleOptionViewItem item = styleOption;
0099         item.rect = arrow;
0100         styleOption.widget->style()->drawPrimitive(QStyle::PE_IndicatorBranch,
0101                                                    &item, painter,
0102                                                    styleOption.widget);
0103     } else {
0104         QVariant colorData = index.data(KisAnimCurvesChannelsModel::CurveColorRole);
0105         QColor color = colorData.value<QColor>();
0106 
0107         QPen newPen = QPen(color, CHANNEL_LEGEND_RADIUS);
0108         newPen.setCapStyle(Qt::RoundCap);
0109         painter->setPen(newPen);
0110 
0111         if (index.data(KisAnimCurvesChannelsModel::CurveVisibilityRole).toBool()) {
0112             painter->setBrush(color);
0113         } else {
0114             painter->setBrush(QBrush());
0115         }
0116 
0117         const int y = styleOption.rect.top() + styleOption.rect.height() / 2;
0118         const QPoint left = QPoint(styleOption.rect.left() - CHANNEL_LEGEND_RADIUS, y);
0119         const QPoint right = QPoint(styleOption.rect.left(), y);
0120         painter->drawLine(left, right);
0121     }
0122 
0123     // Draw buttons..
0124     if (!isNode) {
0125         QRect iconArea = styleOption.rect.adjusted(styleOption.rect.width() - iconSpace, 0, 0, 0);
0126         const bool isVisible = index.data(KisAnimCurvesChannelsModel::CurveVisibilityRole).toBool();
0127         QIcon visibilityIcon = isVisible ? KisIconUtils::loadIcon("visible") : KisIconUtils::loadIcon("novisible");
0128         visibilityIcon.paint(painter, iconArea);
0129     }
0130 
0131     painter->restore();
0132 }
0133 
0134 void KisAnimCurvesChannelDelegate::paintNodeBackground(const QStyleOptionViewItem &styleOption, QPainter *painter, const QColor &nodeColor) const
0135 {
0136     const bool hasValidStyle = styleOption.widget ? styleOption.widget->isEnabled() : (styleOption.state & QStyle::State_Enabled);
0137     QPalette::ColorGroup cg = hasValidStyle ? QPalette::Normal : QPalette::Disabled;
0138 
0139     QRect viewArea = styleOption.rect;
0140     const QWidget* const widget = styleOption.widget;
0141     KIS_ASSERT(widget);
0142     viewArea.setLeft(widget->rect().left());
0143 
0144     { // Highlight, Shadow and Selection Color
0145         const QColor highlight = nodeColor.lighter(115);
0146         const QColor shadow = nodeColor.darker(105);
0147         painter->fillRect(viewArea, highlight);
0148         painter->fillRect(viewArea.adjusted(0,6,0,0), shadow);
0149 
0150         if ( (styleOption.state & QStyle::State_Selected)
0151               && widget->style()->proxy()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, &styleOption, widget)) {
0152             painter->fillRect(viewArea, styleOption.palette.brush(cg, QPalette::Highlight));
0153         }
0154     }
0155 
0156     { // Center "Neutral" Band
0157         viewArea -= QMargins(0, 2, 0, 2);
0158         painter->fillRect(viewArea, nodeColor);
0159     }
0160 }
0161 
0162 void KisAnimCurvesChannelDelegate::soloChannelVisibility(QAbstractItemModel *model, const QModelIndex &channelIndex)
0163 {
0164     KIS_SAFE_ASSERT_RECOVER_RETURN(channelIndex.parent().isValid()); //We need to have a parent "node" to isolate.
0165 
0166     const int numCurves = model->rowCount(channelIndex.parent());
0167     const int clickedCurve = channelIndex.row();
0168     const QModelIndex& nodeIndex = channelIndex.parent();
0169 
0170     for (int i = 0; i < numCurves; i++) {
0171         if (i == clickedCurve) {
0172             model->setData(channelIndex, true, KisAnimCurvesChannelsModel::CurveVisibilityRole);
0173         } else {
0174             QModelIndex indexToToggle = model->index(i, channelIndex.column(), nodeIndex);
0175             model->setData(indexToToggle, false, KisAnimCurvesChannelsModel::CurveVisibilityRole);
0176         }
0177     }
0178 }
0179 
0180 void KisAnimCurvesChannelDelegate::showAllChannels(QAbstractItemModel *model, const QModelIndex &nodeIndex )
0181 {
0182     KIS_SAFE_ASSERT_RECOVER_RETURN(nodeIndex.isValid() && !nodeIndex.parent().isValid()); //We should have no parent node here.
0183 
0184     const int numCurves = model->rowCount(nodeIndex);
0185 
0186     for (int i = 0; i < numCurves; i++) {
0187         QModelIndex curveIndex = model->index(i, 0, nodeIndex);
0188         model->setData(curveIndex, true, KisAnimCurvesChannelsModel::CurveVisibilityRole);
0189     }
0190 }