Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAnimCurvesKeyDelegate.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 <QPainter>
10#include <QApplication>
11#include <QVector2D>
12
13#include "KisAnimCurvesModel.h"
15#include "kis_keyframe.h"
16
17const int NODE_RENDER_RADIUS = 4;
18const int NODE_UI_RADIUS = 8;
19
35
37 : QAbstractItemDelegate(parent)
38 , m_d(new Private(horizontalRuler, verticalRuler))
39{
40}
41
44
45
46void KisAnimCurvesKeyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
47{
48 bool selected = option.state & QStyle::State_Selected;
49 bool active = option.state & QStyle::State_HasFocus;
50 QPointF center = nodeCenter(index, selected);
51
52 QColor color;
53 QColor bgColor = qApp->palette().color(QPalette::Window);
54 if (selected) {
55 color = (bgColor.value() > 128) ? Qt::black : Qt::white;
56 } else {
57 color = index.data(KisAnimCurvesModel::CurveColorRole).value<QColor>();
58 }
59
60 painter->setPen(QPen(color, 0));
61 painter->setBrush(color);
62 painter->drawEllipse(center, NODE_RENDER_RADIUS, NODE_RENDER_RADIUS);
63
64 if (selected) {
65 painter->setPen(QPen(color, 1));
66 painter->setBrush(bgColor);
67
68 if (hasHandle(index, 0)) {
69 QPointF leftTangent = leftHandle(index, active);
70 paintHandle(painter, center, leftTangent);
71 }
72
73 if (hasHandle(index, 1)) {
74 QPointF rightTangent = rightHandle(index, active);
75 paintHandle(painter, center, rightTangent);
76 }
77 }
78}
79
80QSize KisAnimCurvesKeyDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
81{
82 Q_UNUSED(option);
83 Q_UNUSED(index);
84 return QSize(2*NODE_UI_RADIUS, 2*NODE_UI_RADIUS);
85}
86
87QPointF KisAnimCurvesKeyDelegate::nodeCenter(const QModelIndex index, bool selected) const
88{
89 int section = m_d->horizontalRuler->logicalIndex(index.column());
90 int x = m_d->horizontalRuler->sectionViewportPosition(section)
91 + (m_d->horizontalRuler->sectionSize(section) / 2);
92
93 float value = index.data(KisAnimCurvesModel::ScalarValueRole).toReal();
94 float y = m_d->verticalRuler->valueToWidget(value);
95
96 QPointF center = QPointF(x, y);
97 if (selected) center += m_d->selectionOffset;
98 return center;
99}
100
101bool KisAnimCurvesKeyDelegate::hasHandle(const QModelIndex index, int handle) const
102{
103 QModelIndex interpolatedIndex;
104
105 if (handle == 0) {
106 // Left handle: use previous keyframe's interpolation mode
107
108 QVariant previous = index.data(KisAnimCurvesModel::PreviousKeyframeTime);
109 if (!previous.isValid()) return false;
110
111 interpolatedIndex = index.model()->index(index.row(), previous.toInt());
112 } else {
113 interpolatedIndex = index;
114 }
115
116 return (interpolatedIndex.data(KisAnimCurvesModel::InterpolationModeRole).toInt() == KisScalarKeyframe::Bezier);
117}
118
119QPointF KisAnimCurvesKeyDelegate::leftHandle(const QModelIndex index, bool active) const
120{
121 return handlePosition(index, active, 0);
122}
123
124QPointF KisAnimCurvesKeyDelegate::rightHandle(const QModelIndex index, bool active) const
125{
126 return handlePosition(index, active, 1);
127}
128
129QPointF KisAnimCurvesKeyDelegate::handlePosition(const QModelIndex index, bool active, int handle) const
130{
132 QPointF tangent = index.data(role).toPointF();
133
134 float x = tangent.x() * m_d->horizontalRuler->defaultSectionSize();
135 float y = m_d->verticalRuler->valueToPixelOffset(tangent.y());
136 QPointF handlePos = QPointF(x, y);
137
138 if (active && !m_d->handleAdjustment.isNull()) {
139 if (handle == m_d->adjustedHandle) {
140 handlePos += m_d->handleAdjustment;
141 if ((handle == 0 && handlePos.x() > 0) ||
142 (handle == 1 && handlePos.x() < 0)) {
143 handlePos.setX(0);
144 }
145 } else if (index.data(KisAnimCurvesModel::TangentsModeRole).toInt() == KisScalarKeyframe::Smooth) {
146 qreal length = QVector2D(handlePos).length();
147 QVector2D opposite(handlePosition(index, active, 1-handle));
148 handlePos = (-length * opposite.normalized()).toPointF();
149 }
150 }
151
152 return handlePos;
153}
154
156{
157 if (axisSnap) {
158 offset = qAbs(offset.y()) >= qAbs(offset.x()) ? QPointF(0.0f, offset.y()) : QPointF(offset.x(), 0.0f);
159 }
160 m_d->selectionOffset = offset;
161}
162
163void KisAnimCurvesKeyDelegate::setHandleAdjustment(QPointF offset, int handle)
164{
165 m_d->adjustedHandle = handle;
166 m_d->handleAdjustment = offset;
167}
168
169QPointF KisAnimCurvesKeyDelegate::unscaledTangent(QPointF handlePosition) const
170{
171 qreal x = handlePosition.x() / m_d->horizontalRuler->defaultSectionSize();
172 qreal y = m_d->verticalRuler->pixelsToValueOffset(handlePosition.y());
173
174 return QPointF(x, y);
175}
176
177void KisAnimCurvesKeyDelegate::paintHandle(QPainter *painter, QPointF nodePos, QPointF tangent) const
178{
179 QPointF handlePos = nodePos + tangent;
180
181 painter->drawLine(nodePos, handlePos);
182 painter->drawEllipse(handlePos, NODE_RENDER_RADIUS, NODE_RENDER_RADIUS);
183}
184
185QRect KisAnimCurvesKeyDelegate::itemRect(const QModelIndex index) const
186{
187 QPointF center = nodeCenter(index, false);
188
189 return QRect(center.x() - NODE_UI_RADIUS, center.y() - NODE_UI_RADIUS, 2*NODE_UI_RADIUS, 2*NODE_UI_RADIUS);
190}
191
192QRect KisAnimCurvesKeyDelegate::frameRect(const QModelIndex index) const
193{
194 int section = m_d->horizontalRuler->logicalIndex(index.column());
195 int x = m_d->horizontalRuler->sectionViewportPosition(section);
196 int xSize = m_d->horizontalRuler->sectionSize(section);
197
198 float value = index.data(KisAnimCurvesModel::ScalarValueRole).toReal();
199 float y = m_d->verticalRuler->valueToWidget(value);
200 int ySize = m_d->verticalRuler->height();
201
202 return QRect(x, y, xSize, ySize);
203}
204
205QRect KisAnimCurvesKeyDelegate::visualRect(const QModelIndex index) const
206{
207 QPointF center = nodeCenter(index, false);
208 QPointF leftHandlePos = center + leftHandle(index, false);
209 QPointF rightHandlePos = center + rightHandle(index, false);
210
211 int minX = qMin(center.x(), leftHandlePos.x()) - NODE_RENDER_RADIUS;
212 int maxX = qMax(center.x(), rightHandlePos.x()) + NODE_RENDER_RADIUS;
213
214 int minY = qMin(center.y(), qMin(leftHandlePos.y(), rightHandlePos.y())) - NODE_RENDER_RADIUS;
215 int maxY = qMax(center.y(), qMax(leftHandlePos.y(), rightHandlePos.y())) + NODE_RENDER_RADIUS;
216
217 return QRect(QPoint(minX, minY), QPoint(maxX, maxY));
218}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
float value(const T *src, size_t ch)
const int NODE_UI_RADIUS
const int NODE_RENDER_RADIUS
QPointF unscaledTangent(QPointF handlePosition) const
QPointF handlePosition(const QModelIndex index, bool active, int handle) const
QPointF leftHandle(const QModelIndex index, bool active) const
bool hasHandle(const QModelIndex index, int handle) const
QRect itemRect(const QModelIndex index) const
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
void setSelectedItemVisualOffset(QPointF offset, bool axisSnap=false)
QPointF nodeCenter(const QModelIndex index, bool selected) const
QRect frameRect(const QModelIndex index) const
void setHandleAdjustment(QPointF offset, int handle)
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
KisAnimCurvesKeyDelegate(const KisAnimTimelineTimeHeader *horizontalRuler, const KisAnimCurvesValuesHeader *verticalRuler, QObject *parent)
QRect visualRect(const QModelIndex index) const
QPointF rightHandle(const QModelIndex index, bool active) const
void paintHandle(QPainter *painter, QPointF nodePos, QPointF tangent) const
const QScopedPointer< Private > m_d
const KisAnimCurvesValuesHeader * verticalRuler
Private(const KisAnimTimelineTimeHeader *horizontalRuler, const KisAnimCurvesValuesHeader *verticalRuler)
const KisAnimTimelineTimeHeader * horizontalRuler