86 QMap<int, KisKeyframeSP>
keys;
132 if (
m_d->keys.contains(time)) {
144 m_d->keys.insert(time, keyframe);
157 m_d->keys.remove(time);
172 if (!sourceKeyframe)
return;
177 if (sourceChannel != targetChannel) {
179 targetKeyframe = sourceKeyframe->duplicate(targetChannel);
183 targetChannel->
insertKeyframe(targetTime, targetKeyframe, parentUndoCmd);
191 if (!sourceKeyframe)
return;
193 KisKeyframeSP copiedKeyframe = sourceKeyframe->duplicate(targetChannel);
196 targetChannel->
insertKeyframe(targetTime, copiedKeyframe, parentUndoCmd);
205 if (!keyframeB)
return;
208 moveKeyframe(channelA, timeA, channelB, timeB, parentUndoCmd);
211 if (channelA != channelB) {
212 keyframeB = keyframeB->duplicate(channelA);
220 QMap<int, KisKeyframeSP>::const_iterator iter =
m_d->keys.constFind(time);
221 if (iter !=
m_d->keys.constEnd()) {
230 return m_d->keys.count();
235 QMap<int, KisKeyframeSP>::const_iterator iter =
const_cast<const QMap<int, KisKeyframeSP>*
>(&
m_d->keys)->upperBound(time);
238 if (iter ==
m_d->keys.constBegin()) {
244 if (iter ==
m_d->keys.constEnd()) {
253 int time =
m_d->keys.key(toLookup, -1);
260 if (
m_d->keys.isEmpty()) {
263 return m_d->keys.firstKey();
273 QMap<int, KisKeyframeSP>::const_iterator iter =
m_d->keys.constFind(time);
275 if (iter ==
m_d->keys.constBegin() || iter ==
m_d->keys.constEnd()) {
285 QMap<int, KisKeyframeSP>::const_iterator iter =
const_cast<const QMap<int, KisKeyframeSP>*
>(&
m_d->keys)->upperBound(time);
287 if (iter ==
m_d->keys.constEnd()) {
296 if (
m_d->keys.isEmpty()) {
300 return m_d->keys.lastKey();
307 TimeKeyframeMap::const_iterator it =
m_d->keys.constBegin();
308 TimeKeyframeMap::const_iterator end =
m_d->keys.constEnd();
311 frames.insert(it.key());
325 return m_d->id.name();
330 if (
m_d->parentNode.isValid()) {
340 if (
m_d->parentNode) {
350 return m_d->parentNode;
359 TimeKeyframeMap::const_iterator it =
m_d->keys.constBegin();
360 TimeKeyframeMap::const_iterator end =
m_d->keys.constEnd();
399 QDomElement channelElement = doc.createElement(
"channel");
401 channelElement.setAttribute(
"name",
id());
403 Q_FOREACH (
int time,
m_d->keys.keys()) {
404 QDomElement keyframeElement = doc.createElement(
"keyframe");
407 keyframeElement.setAttribute(
"time", time);
408 keyframeElement.setAttribute(
"color-label", keyframe->colorLabel());
412 channelElement.appendChild(keyframeElement);
415 return channelElement;
420 for (QDomElement keyframeNode = channelNode.firstChildElement(); !keyframeNode.isNull(); keyframeNode = keyframeNode.nextSiblingElement()) {
421 if (keyframeNode.nodeName().toUpper() !=
"KEYFRAME")
continue;
423 QPair<int, KisKeyframeSP> timeKeyPair =
loadKeyframe(keyframeNode);
426 if (keyframeNode.hasAttribute(
"color-label")) {
427 timeKeyPair.second->setColorLabel(keyframeNode.attribute(
"color-label").toUInt());
446 return m_d->bounds->currentTime();
452 qWarning() <<
"WARNING: Loading a file with negative animation frames!";
453 qWarning() <<
" The file has been saved with a buggy version of Krita.";
454 qWarning() <<
" All the frames with negative ids will be dropped!";
455 qWarning() <<
" " <<
ppVar(this->
id()) <<
ppVar(*time);
457 m_d->haveBrokenFrameTimeBug =
true;
461 if (
m_d->haveBrokenFrameTimeBug) {
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
QSet< int > allKeyframeTimes() const
Get a set of all integer times that map to a keyframe.
void setDefaultBounds(KisDefaultBoundsBaseSP bounds)
virtual KisTimeSpan identicalFrames(int time) const
Get a span of times for which the channel gives identical results compared to frame at a given time....
static const KoID RotationY
virtual KisKeyframeSP createKeyframe()=0
Virtual keyframe creation function. Derived classes implement this function based on the needs of the...
int previousKeyframeTime(const int time) const
virtual void insertKeyframe(int time, KisKeyframeSP keyframe, KUndo2Command *parentUndoCmd=nullptr)
Insert an existing keyframe into the channel at the specified time.
virtual void removeKeyframe(int time, KUndo2Command *parentUndoCmd=nullptr)
Remove a keyframe from the channel at the specified time.
static void swapKeyframes(KisKeyframeChannel *channelA, int timeA, KisKeyframeChannel *channelB, int timeB, KUndo2Command *parentUndoCmd=nullptr)
Swap two keyframes across channel(s) at the specified times.
void sigAnyKeyframeChange()
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.
static void copyKeyframe(const KisKeyframeChannel *sourceChannel, int sourceTime, KisKeyframeChannel *targetChannel, int targetTime, KUndo2Command *parentUndoCmd=nullptr)
Copy a keyframe across channel(s) at the specified times.
virtual QPair< int, KisKeyframeSP > loadKeyframe(const QDomElement &keyframeNode)=0
static const KoID RotationZ
virtual void loadXML(const QDomElement &channelNode)
QMap< int, KisKeyframeSP > TimeKeyframeMap
static const KoID Opacity
static KoID channelIdToKoId(const QString &id)
virtual QDomElement toXML(QDomDocument doc, const QString &layerFilename)
const TimeKeyframeMap & constKeys() const
QScopedPointer< Private > m_d
int channelHash() const
Calculates a pseudo-unique hash based on the relevant internal state of the channel.
void addKeyframe(int time, KUndo2Command *parentUndoCmd=nullptr)
Add a new keyframe to the channel at the specified time.
virtual void saveKeyframe(KisKeyframeSP keyframe, QDomElement keyframeElement, const QString &layerFilename)=0
virtual void removeKeyframeImpl(int time, KUndo2Command *parentUndoCmd)
static const KoID RotationX
~KisKeyframeChannel() override
void sigKeyframeHasBeenRemoved(const KisKeyframeChannel *channel, int time)
This signal is emitted just AFTER a keyframe is removed from the channel.
virtual KisTimeSpan affectedFrames(int time) const
Get the set of frames affected by any changes to the value or content of the active keyframe at the g...
void setNode(KisNodeWSP node)
int activeKeyframeTime() const
void sigKeyframeAboutToBeRemoved(const KisKeyframeChannel *channel, int time)
This signal is emitted just BEFORE a keyframe is removed from the channel.
static const KoID PositionX
int keyframeCount() const
int lastKeyframeTime() const
Q_DECL_DEPRECATED void workaroundBrokenFrameTimeBug(int *time)
Between Krita 4.1 and 4.4 Krita had a bug which resulted in creating frames with negative time stamp....
static const KoID PositionY
KisKeyframeChannel(const KoID &id, KisDefaultBoundsBaseSP bounds)
void sigKeyframeChanged(const KisKeyframeChannel *channel, int time)
This signal is emitted just AFTER a non-raster keyframe was changed its value.
int nextKeyframeTime(const int time) const
static void moveKeyframe(KisKeyframeChannel *sourceChannel, int sourceTime, KisKeyframeChannel *targetChannel, int targetTime, KUndo2Command *parentUndoCmd=nullptr)
Move a keyframe across channel(s) at the specified times.
int lookupKeyframeTime(KisKeyframeSP toLookup)
Search for the time for a given keyframe. (Reverse map lookup, so use sparingly.)
void sigAddedKeyframe(const KisKeyframeChannel *channel, int time)
This signal is emitted just AFTER a keyframe was added to the channel.
static KisTimeSpan infinite(int start)
static KisTimeSpan fromTimeToTime(int start, int end)
#define KIS_SAFE_ASSERT_RECOVER(cond)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
KisSharedPtr< KisDefaultBoundsNodeWrapper > KisDefaultBoundsNodeWrapperSP
QSharedPointer< KisKeyframe > KisKeyframeSP
QMap< int, KisKeyframeSP > keys
Private(const Private &rhs)
KisDefaultBoundsBaseSP bounds
Private(const KoID &temp_id, KisDefaultBoundsBaseSP tmp_bounds)
bool haveBrokenFrameTimeBug
virtual void handleKeyframeChannelFrameAdded(const KisKeyframeChannel *channel, int time)
void handleKeyframeChannelFrameHasBeenRemoved(const KisKeyframeChannel *channel, int time)
void handleKeyframeChannelFrameAboutToBeRemoved(const KisKeyframeChannel *channel, int time)
virtual void handleKeyframeChannelFrameChange(const KisKeyframeChannel *channel, int time)