9#include <QAbstractItemModel>
36 : m_d(new
Private(channel, color))
72 if (!index.isValid())
return 0;
74 int row = index.row();
76 if (row < 0 || row >=
curves.size()) {
84 return curves.indexOf(curve);
88 for (
int row = 0; row <
curves.count(); row++) {
89 if (
curves.at(row)->channel() == channel)
return row;
112 qDeleteAll(
m_d->curves);
118 return m_d->curves.size();
129 const int time = index.column();
134 return !keyframe.isNull();
138 if (keyframe.isNull())
145 if (!previousKeyframe)
152 return keyframe->leftTangent();
155 if (keyframe.isNull())
161 return keyframe->rightTangent();
164 return (keyframe.isNull()) ? QVariant() : keyframe->interpolationMode();
166 return (keyframe.isNull()) ? QVariant() : keyframe->tangentsMode();
168 return curve->
color();
174 if (!channel->
keyframeAt(activeKeyframeIndex))
return QVariant();
175 if (activeKeyframeIndex < time) {
176 return activeKeyframeIndex;
180 if (!channel->
keyframeAt(previousKeyframeIndex))
return QVariant();
181 return previousKeyframeIndex;
186 if (!channel->
keyframeAt(activeKeyframeIndex)) {
188 if (firstKeyIndex != -1 && firstKeyIndex > time) {
189 return firstKeyIndex;
195 if (!channel->
keyframeAt(nextKeyframeIndex))
return QVariant();
196 return nextKeyframeIndex;
199 return channel->
id();
207 return QVariant::fromValue<ChannelLimitsMetatype>(
ChannelLimitsMetatype(limits->lower, limits->upper) );
219 if (!index.isValid())
237 dataChanged(index,index);
244 if (!keyframe)
return false;
250 keyframe->setInterpolationTangents(leftTangent, rightTangent, command);
251 dataChanged(index, index);
260 dataChanged(index, index);
266 if (!keyframe)
return false;
271 keyframe->setTangentsMode( mode, command );
272 dataChanged(index,index);
279 if (command && !
m_d->undoCommand) {
307 m_d->undoCommand = 0;
313 QScopedPointer<KUndo2Command> command(
316 "Adjust %1 Keyframes",
320 KisImageBarrierLock lock(
image());
322 if (timeOffset != 0) {
324 if (!ok)
return false;
329 FrameItemList frameItems;
331 Q_FOREACH(QModelIndex index, indexes) {
335 frameItems << FrameItem(channel->
node(),
337 index.column() + timeOffset);
344 QScopedPointer<KUndo2Command> cmd(new KUndo2Command());
348 Q_FOREACH (const FrameItem &item, frameItems) {
349 const int time = item.time;
350 KisNodeSP node = item.node;
352 KisKeyframeChannel *channel = node->getKeyframeChannel(item.channel);
354 if (!channel) continue;
356 KisScalarKeyframeSP scalarKeyframe = channel->keyframeAt(time).dynamicCast<KisScalarKeyframe>();
358 if (!scalarKeyframe) continue;
360 const qreal currentValue = scalarKeyframe->value();
362 scalarKeyframe->setValue(currentValue + valueOffset, cmd.data());
379 beginInsertRows(QModelIndex(),
m_d->curves.size(),
m_d->curves.size());
382 m_d->curves.append(curve);
405 int index =
m_d->curves.indexOf(curve);
406 if (index < 0)
return;
408 curve->
channel()->disconnect(
this);
410 beginRemoveRows(QModelIndex(), index, index);
412 m_d->curves.removeAt(index);
422 int row =
m_d->rowForCurve(curve);
423 Q_EMIT dataChanged(index(row, 0), index(row,
columnCount()));
438 QMap<QString, KisKeyframeChannel*> list;
450 int row =
m_d->rowForChannel(channel);
451 QModelIndex changedIndex = index(row, time);
452 Q_EMIT dataChanged(changedIndex, changedIndex);
457 Q_EMIT
dataAdded(index(
m_d->rowForChannel(channel), time));
float value(const T *src, size_t ch)
QPair< qreal, qreal > ChannelLimitsMetatype
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
~KisAnimCurvesModel() override
KisKeyframeChannel * channelByID(QModelIndex index, const QString &id) const override
KisAnimationCurve * addCurve(KisScalarKeyframeChannel *channel)
const QScopedPointer< Private > m_d
QMap< QString, KisKeyframeChannel * > channelsAt(QModelIndex index) const override
void beginCommand(const KUndo2MagicString &text)
void slotKeyframeAdded(const KisKeyframeChannel *channel, int time)
QVariant data(const QModelIndex &index, int role) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void setCurveVisible(KisAnimationCurve *curve, bool visible)
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) override
bool setData(const QModelIndex &index, const QVariant &value, int role) override
void removeCurve(KisAnimationCurve *curve)
KisNodeSP nodeAt(QModelIndex index) const override
bool adjustKeyframes(const QModelIndexList &indexes, int timeOffset, qreal valueOffset)
KisAnimCurvesModel(QObject *parent)
void dataAdded(const QModelIndex &index)
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
void slotKeyframeChanged(const KisKeyframeChannel *channel, int time)
void setVisible(bool visible)
const QScopedPointer< Private > m_d
KisAnimationCurve(KisScalarKeyframeChannel *channel, QColor color)
KisScalarKeyframeChannel * channel() const
KisPostExecutionUndoAdapter * postExecutionUndoAdapter() const override
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
int previousKeyframeTime(const int time) const
int firstKeyframeTime() const
KisKeyframeSP keyframeAt(int time) const
Get a keyframe at specified time. Used primarily when the value of a given keyframe is needed.
void sigKeyframeHasBeenRemoved(const KisKeyframeChannel *channel, int time)
This signal is emitted just AFTER a keyframe is removed from the channel.
int activeKeyframeTime(int time) const
Get the time of the active keyframe. Useful for snapping any time to that of the most recent keyframe...
int nextKeyframeTime(const int time) const
void sigAddedKeyframe(const KisKeyframeChannel *channel, int time)
This signal is emitted just AFTER a keyframe was added to the channel.
void addCommand(KUndo2CommandSP command)
static void runSingleCommandStroke(KisImageSP image, KUndo2Command *cmd, KisStrokeJobData::Sequentiality sequentiality=KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::Exclusivity exclusivity=KisStrokeJobData::NORMAL)
runSingleCommandStroke creates a stroke and runs cmd in it. The text() field of cmd is used as a titl...
The KisScalarKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisSca...
qreal valueAt(int time) const
Quickly get the interpolated value at the given time.
void addScalarKeyframe(int time, qreal value, KUndo2Command *parentUndoCmd=nullptr)
QSharedPointer< ScalarKeyframeLimits > limits() const
The KisScalarKeyframe class is a concrete subclass of KisKeyframe that wraps a scalar value and inter...
InterpolationMode
Controls the type of interpolation between this KisScalarKeyframe and the next.
TangentsMode
Controls the behavior of the left and right tangents on a given keyframe for different curve shapes.
KUndo2Command * createOffsetFramesCommand(QModelIndexList srcIndexes, const QPoint &offset, bool copyFrames, bool moveEmptyFrames, KUndo2Command *parentCommand=0)
bool setData(const QModelIndex &index, const QVariant &value, int role) override
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
QVariant data(const QModelIndex &index, int role) const override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
KisImageWSP image() const
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) override
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
#define KIS_ASSERT_RECOVER_RETURN(cond)
QSharedPointer< T > toQShared(T *ptr)
KisSharedPtr< KisNode > KisNodeSP
KUndo2MagicString kundo2_i18n(const char *text)
KUndo2MagicString kundo2_i18np(const char *sing, const char *plur, const A1 &a1)
KUndo2Command * undoCommand
int rowForChannel(const KisKeyframeChannel *channel)
QList< KisAnimationCurve * > curves
int rowForCurve(KisAnimationCurve *curve)
KisAnimationCurve * getCurveAt(const QModelIndex &index)
Private(KisScalarKeyframeChannel *channel, QColor color)
KisScalarKeyframeChannel * channel
KisKeyframeChannel * getKeyframeChannel(const QString &id, bool create)
The LambdaCommand struct is a shorthand for creation of AggregateCommand commands using C++ lambda fe...