File indexing completed on 2024-05-26 04:32:24
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "KisAnimTimelineFrameDelegate.h" 0008 0009 #include <QPen> 0010 #include <QPainter> 0011 #include <QApplication> 0012 #include <QSvgRenderer> 0013 #include <kis_painting_tweaks.h> 0014 #include "KisAnimTimelineFramesModel.h" 0015 #include "KisAnimTimelineColors.h" 0016 0017 #include "kis_node_view_color_scheme.h" 0018 0019 KisAnimTimelineFrameDelegate::KisAnimTimelineFrameDelegate(QObject *parent) 0020 : QItemDelegate(parent), 0021 stripes(64, 64) 0022 { 0023 KisNodeViewColorScheme scm; 0024 labelColors = scm.allColorLabels(); 0025 0026 // Clone frame stripes SVG -> Pixmap.. 0027 QImage stripesImage(":diagonal-stripe.svg", "svg"); 0028 stripesImage.save("/tmp/krita_stripes.svg", "svg"); 0029 stripes = QPixmap::fromImage(stripesImage); 0030 } 0031 0032 KisAnimTimelineFrameDelegate::~KisAnimTimelineFrameDelegate() 0033 { 0034 } 0035 0036 void KisAnimTimelineFrameDelegate::paintActiveFrameSelector(QPainter *painter, const QRect &rc, bool isCurrentFrame) 0037 { 0038 painter->save(); 0039 0040 QColor lineColor = KisAnimTimelineColors::instance()->selectorColor(); 0041 const int lineWidth = rc.width() > 20 ? 4 : 2; 0042 0043 const int x0 = rc.x(); 0044 const int y0 = rc.y(); 0045 const int x1 = rc.right(); 0046 const int y1 = rc.bottom(); 0047 0048 QVector<QLine> linesDark; 0049 linesDark << QLine(x0 + lineWidth / 2, y0, x0 + lineWidth / 2, y1); 0050 linesDark << QLine(x1 - lineWidth / 2 + 1, y0, x1 - lineWidth / 2 + 1, y1); 0051 0052 QPen oldPen = painter->pen(); 0053 painter->setPen(QPen(lineColor, lineWidth)); 0054 painter->drawLines(linesDark); 0055 painter->setPen(oldPen); 0056 0057 if (isCurrentFrame) { 0058 QPen oldPen = painter->pen(); 0059 QBrush oldBrush(painter->brush()); 0060 0061 painter->setPen(QPen(lineColor, 0)); 0062 painter->setBrush(lineColor); 0063 0064 painter->drawEllipse(rc.center(), 2,2); 0065 0066 painter->setBrush(oldBrush); 0067 painter->setPen(oldPen); 0068 } 0069 0070 painter->restore(); 0071 } 0072 0073 void KisAnimTimelineFrameDelegate::paintSpecialKeyframeIndicator(QPainter *painter, const QModelIndex &index, const QRect &rc) const 0074 { 0075 painter->save(); 0076 0077 bool doesFrameExist = index.data(KisAnimTimelineFramesModel::FrameExistsRole).toBool(); /// does normal keyframe exist 0078 bool isEditable = index.data(KisAnimTimelineFramesModel::FrameEditableRole).toBool(); 0079 bool hasContent = index.data(KisAnimTimelineFramesModel::FrameHasContent).toBool(); /// find out if frame is empty 0080 0081 QColor color = qApp->palette().color(QPalette::Highlight); 0082 QColor baseColor = qApp->palette().color(QPalette::Base); 0083 QColor noLabelSetColor = qApp->palette().color(QPalette::Highlight); // if no color label is used 0084 0085 // use color label if it exists. coloring follows very similar logic to the drawBackground() function except this is a bit simpler 0086 QVariant colorLabel = index.data(KisAnimTimelineFramesModel::FrameColorLabelIndexRole); 0087 if (colorLabel.isValid()) { 0088 color = labelColors.at(colorLabel.toInt()); 0089 } else { 0090 color = noLabelSetColor; 0091 } 0092 0093 if (!isEditable) { 0094 color = KisPaintingTweaks::blendColors(baseColor, color, 0.5); 0095 } 0096 0097 if (doesFrameExist && hasContent) { 0098 color = baseColor; // special keyframe will be over filled in frame, so switch color so it is shown 0099 } 0100 0101 QPen oldPen = painter->pen(); 0102 QBrush oldBrush(painter->brush()); 0103 0104 painter->setPen(QPen(color, 0)); 0105 painter->setBrush(color); 0106 0107 QPointF center = rc.center(); 0108 QPointF points[4] = { 0109 QPointF(center.x() + 4, center.y() ), 0110 QPointF(center.x() , center.y() - 4), 0111 QPointF(center.x() - 4, center.y() ), 0112 QPointF(center.x() , center.y() + 4) 0113 }; 0114 painter->drawConvexPolygon(points, 4); 0115 0116 painter->setBrush(oldBrush); 0117 painter->setPen(oldPen); 0118 0119 painter->restore(); 0120 } 0121 0122 void KisAnimTimelineFrameDelegate::drawBackground(QPainter *painter, const QModelIndex &index, const QRect &rc) const 0123 { 0124 painter->save(); 0125 0126 /// is the current layer actively selected (this is not the same as visibility) 0127 bool hasActiveLayerRole = index.data(KisAnimTimelineFramesModel::ActiveLayerRole).toBool(); 0128 bool doesFrameExist = index.data(KisAnimTimelineFramesModel::FrameExistsRole).toBool(); /// does keyframe exist 0129 bool isEditable = index.data(KisAnimTimelineFramesModel::FrameEditableRole).toBool(); /// is layer editable 0130 bool hasContent = index.data(KisAnimTimelineFramesModel::FrameHasContent).toBool(); /// find out if frame is empty 0131 0132 QColor color; // will get re-used for determining color 0133 QColor noLabelSetColor = qApp->palette().color(QPalette::Highlight); // if no color label is used 0134 QColor highlightColor = qApp->palette().color(QPalette::Highlight); 0135 QColor baseColor = qApp->palette().color(QPalette::Base); 0136 0137 0138 // pass for filling in the active row with slightly color difference 0139 if (hasActiveLayerRole) { 0140 color = KisPaintingTweaks::blendColors(baseColor, highlightColor, 0.8); 0141 painter->fillRect(rc, color); 0142 } else { 0143 color = KisPaintingTweaks::blendColors(baseColor, highlightColor, 0.95); 0144 painter->fillRect(rc, color); 0145 } 0146 0147 // assign background color for frame depending on if the frame has a color label or not 0148 QVariant colorLabel = index.data(KisAnimTimelineFramesModel::FrameColorLabelIndexRole); 0149 if (colorLabel.isValid()) { 0150 color = labelColors.at(colorLabel.toInt()); 0151 } else { 0152 color = noLabelSetColor; 0153 } 0154 0155 0156 // if layer is hidden, make the entire color more subtle. 0157 // this should be in effect for both fill color and empty outline color 0158 if (!isEditable) { 0159 color = KisPaintingTweaks::blendColors(baseColor, color, 0.7); 0160 } 0161 0162 0163 // how do we fill in a frame that has content 0164 // a keyframe will be totally filled in. A hold frame will have a line running through it 0165 if (hasContent && doesFrameExist) { 0166 painter->fillRect(rc, color); 0167 } 0168 0169 // pass of outline for empty keyframes 0170 if (doesFrameExist && !hasContent) { 0171 0172 QPen oldPen = painter->pen(); 0173 QBrush oldBrush(painter->brush()); 0174 0175 painter->setPen(QPen(color, 2)); 0176 painter->setBrush(Qt::NoBrush); 0177 painter->drawRect(rc); 0178 0179 painter->setBrush(oldBrush); 0180 painter->setPen(oldPen); 0181 } 0182 0183 // pass of hold frame line 0184 if (!doesFrameExist && hasContent) { 0185 0186 // pretty much the same check as "isValid" above, but that isn't working with hold frames 0187 if (colorLabel.toInt() == 0) { 0188 color = noLabelSetColor; 0189 0190 if (!isEditable) { 0191 color = KisPaintingTweaks::blendColors(baseColor, color, 0.7); 0192 } 0193 } 0194 0195 0196 QPoint lineStart(rc.x(), (rc.y() + rc.height()/2)); 0197 QPoint lineEnd(rc.x() + rc.width(), (rc.y() + rc.height()/2)); 0198 0199 QPen holdFramePen(color); 0200 holdFramePen.setWidth(1); 0201 0202 painter->setPen(holdFramePen); 0203 painter->drawLine(QLine(lineStart, lineEnd)); 0204 } 0205 0206 painter->restore(); 0207 } 0208 0209 void KisAnimTimelineFrameDelegate::drawFocus(QPainter *painter, 0210 const QStyleOptionViewItem &option, 0211 const QRect &rect) const 0212 { 0213 // copied from Qt 4.8! 0214 if ((option.state & QStyle::State_HasFocus) == 0 || !rect.isValid()) 0215 return; 0216 0217 painter->save(); 0218 0219 0220 QStyleOptionFocusRect o; 0221 o.QStyleOption::operator=(option); 0222 o.rect = rect; 0223 o.state |= QStyle::State_KeyboardFocusChange; 0224 o.state |= QStyle::State_Item; 0225 QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) 0226 ? QPalette::Normal : QPalette::Disabled; 0227 o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected) 0228 ? QPalette::Highlight : QPalette::Window); 0229 const QWidget *widget = qobject_cast<QWidget*>(parent()); 0230 QStyle *style = widget ? widget->style() : QApplication::style(); 0231 style->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter, widget); 0232 0233 painter->restore(); 0234 } 0235 0236 void KisAnimTimelineFrameDelegate::drawCloneGraphics(QPainter *painter, const QRect &rect) const 0237 { 0238 painter->save(); 0239 0240 QBrush brush(stripes); 0241 brush.setStyle(Qt::TexturePattern); 0242 0243 painter->setPen(Qt::NoPen); 0244 painter->setBrush(brush); 0245 painter->setOpacity(0.25f); 0246 painter->drawRect(rect); 0247 0248 painter->restore(); 0249 } 0250 0251 void KisAnimTimelineFrameDelegate::paint(QPainter *painter, 0252 const QStyleOptionViewItem &option, 0253 const QModelIndex &index) const 0254 { 0255 // draws background as well as fills normal keyframes 0256 drawBackground(painter, index, option.rect); 0257 0258 // Clone graphics.. 0259 if (index.data(KisAnimTimelineFramesModel::CloneOfActiveFrame).toBool() && index.data(KisAnimTimelineFramesModel::ActiveLayerRole).toBool()) { 0260 drawCloneGraphics(painter, option.rect); 0261 } 0262 0263 // creates a semi transparent orange rectangle in the frame that is actively selected on the active row 0264 if (option.showDecorationSelected && 0265 (option.state & QStyle::State_Selected)) { 0266 painter->save(); 0267 0268 const QVariant data = index.data(KisAnimTimelineFramesModel::FrameEditableRole); 0269 bool isEditable = data.isValid() ? data.toBool() : true; 0270 0271 QColor highlightColor = KisAnimTimelineColors::instance()->selectionColor(); 0272 highlightColor.setAlpha(isEditable ? 128 : 64); 0273 QBrush brush = highlightColor; 0274 painter->fillRect(option.rect, brush); 0275 0276 painter->restore(); 0277 } 0278 0279 // not sure what this is drawing 0280 drawFocus(painter, option, option.rect); 0281 0282 // opacity keyframe, but NOT normal keyframes 0283 bool specialKeys = index.data(KisAnimTimelineFramesModel::SpecialKeyframeExists).toBool(); 0284 if (specialKeys) { 0285 paintSpecialKeyframeIndicator(painter, index, option.rect); 0286 } 0287 0288 // creates a border and dot on the selected frame on the active row 0289 bool active = index.data(KisAnimTimelineFramesModel::ActiveFrameRole).toBool(); 0290 bool layerIsCurrent = index.data(KisAnimTimelineFramesModel::ActiveLayerRole).toBool(); 0291 if (active) { 0292 paintActiveFrameSelector(painter, option.rect, layerIsCurrent); 0293 } 0294 0295 { // Shade over anything that's outside of the animation range... 0296 if (index.data(KisAnimTimelineFramesModel::WithinClipRange).toBool() == false) { 0297 painter->save(); 0298 0299 painter->setOpacity(0.50f); 0300 painter->fillRect(option.rect, qApp->palette().color(QPalette::Base).darker(110)); 0301 0302 painter->restore(); 0303 } 0304 } 0305 }