diff --git a/libs/image/kis_animation_cycle.cpp b/libs/image/kis_animation_cycle.cpp index 5207c4cede..910a0f440a 100644 --- a/libs/image/kis_animation_cycle.cpp +++ b/libs/image/kis_animation_cycle.cpp @@ -1,221 +1,212 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_animation_cycle.h" #include #include "kis_time_range.h" #include "kis_keyframe_channel.h" -KisAnimationCycle::KisAnimationCycle(KisKeyframeSP firstKeyframe, KisKeyframeSP lastKeyframe) - : m_firstSourceKeyframe(firstKeyframe) +KisAnimationCycle::KisAnimationCycle(KisKeyframeChannel *channel, KisKeyframeSP firstKeyframe, KisKeyframeSP lastKeyframe) + : KisKeyframeBase(channel, firstKeyframe->time()) + , m_firstSourceKeyframe(firstKeyframe) , m_lastSourceKeyframe(lastKeyframe) {} -void KisAnimationCycle::setFirstKeyframe(KisKeyframeSP keyframe) -{ - m_firstSourceKeyframe = keyframe; -} - -void KisAnimationCycle::setLastKeyframe(KisKeyframeSP keyframe) -{ - m_lastSourceKeyframe = keyframe; -} - KisKeyframeSP KisAnimationCycle::firstSourceKeyframe() const { return m_firstSourceKeyframe; } KisKeyframeSP KisAnimationCycle::lastSourceKeyframe() const { return m_lastSourceKeyframe; } KisTimeSpan KisAnimationCycle::originalRange() const { const KisKeyframeSP firstAfterCycle = m_lastSourceKeyframe->channel()->nextKeyframe(m_lastSourceKeyframe); KisTimeSpan range; if (firstAfterCycle.isNull()) { // TODO: semantics of repeat definition without a terminating keyframe? range = KisTimeSpan(m_firstSourceKeyframe->time(), m_lastSourceKeyframe->time()); } else { range = KisTimeSpan(m_firstSourceKeyframe->time(), firstAfterCycle->time() - 1); } return range; } int KisAnimationCycle::duration() const { return originalRange().duration(); } void KisAnimationCycle::addRepeat(QSharedPointer repeat) { m_repeats.append(repeat); } void KisAnimationCycle::removeRepeat(QSharedPointer repeat) { m_repeats.removeAll(repeat); } const QVector>& KisAnimationCycle::repeats() const { return m_repeats; } KisFrameSet KisAnimationCycle::instancesWithin(KisKeyframeSP original, KisTimeSpan range) const { KisFrameSet frames; const int originalTime = original->time(); const KisKeyframeSP next = original->channel()->nextKeyframe(original); const int frameDuration = (next.isNull()) ? -1 : next->time() - originalTime; const int interval = duration(); int infiniteFrom = frameDuration == -1 ? originalTime : -1; QVector spans; Q_FOREACH(const QWeakPointer repeatFrame, m_repeats) { auto repeat = repeatFrame.toStrongRef(); if (!repeat) continue; - KisKeyframeSP terminatingKey = repeat->channel()->nextKeyframe(*repeat); + // FIXME! KisKeyframeSP terminatingKey = repeat->channel()->nextKeyframe(*repeat); + KisKeyframeSP terminatingKey = KisKeyframeSP(); if (range.isEmpty()) { if (terminatingKey) { range = KisTimeSpan(0, terminatingKey->time() -1); } else { infiniteFrom = repeat->firstInstanceOf(originalTime); continue; } } KisTimeSpan repeatRange = terminatingKey ? range.truncateLeft(terminatingKey->time() - 1) : range; int firstInstance = repeat->firstInstanceOf(originalTime); if (firstInstance < repeatRange.start()) firstInstance += (range.start() - firstInstance) / interval * interval; for (int repeatTime = firstInstance; repeatTime <= repeatRange.end(); repeatTime += interval) { const int repeatEndTime = (frameDuration != -1 && repeatTime + frameDuration - 1 <= repeatRange.end()) ? repeatTime + frameDuration - 1 : repeatRange.end(); spans.append(KisTimeSpan(repeatTime, repeatEndTime)); } } frames |= KisFrameSet(spans); if (infiniteFrom != -1) { frames |= KisFrameSet::infiniteFrom(infiniteFrom); } else { frames |= KisFrameSet::between(originalTime, originalTime + frameDuration - 1); } return frames; } - -KisKeyframeSP KisRepeatFrame::cloneFor(KisKeyframeChannel *channel) const +QRect KisAnimationCycle::affectedRect() const { - const int cycleBeginTime = m_cycle->firstSourceKeyframe()->time(); - QSharedPointer targetCycle = channel->cycleAt(cycleBeginTime); - return toQShared(new KisRepeatFrame(channel, time(), targetCycle)); + QRect rect; + + KisKeyframeSP keyframe = m_firstSourceKeyframe; + do { + rect |= keyframe->affectedRect(); + keyframe = channel()->nextKeyframe(keyframe); + } while (keyframe && keyframe != m_lastSourceKeyframe); + + return rect; } -bool KisRepeatFrame::isRepeat(KisKeyframeSP keyframe) +KisKeyframeSP KisAnimationCycle::getOriginalKeyframeFor(int time) const { - return dynamic_cast(keyframe.data()) != nullptr; + return channel()->activeKeyframeAt(time); } KisRepeatFrame::KisRepeatFrame(KisKeyframeChannel *channel, int time, QSharedPointer cycle) - : KisKeyframe(channel, time) + : KisKeyframeBase(channel, time) , m_cycle(cycle) {} QSharedPointer KisRepeatFrame::cycle() const { return m_cycle; } QRect KisRepeatFrame::affectedRect() const { - KisKeyframeSP keyframe = m_cycle->firstSourceKeyframe(); - - QRect rect; - while (!keyframe.isNull() && keyframe->time() <= m_cycle->lastSourceKeyframe()->time()) { - rect |= keyframe->affectedRect(); - keyframe = channel()->nextKeyframe(keyframe); - } - - return rect; + return m_cycle->affectedRect(); } int KisRepeatFrame::getOriginalTimeFor(int time) const { KisTimeSpan originalRange = m_cycle->originalRange(); int timeWithinCycle = (time - this->time()) % originalRange.duration(); return m_cycle->firstSourceKeyframe()->time() + timeWithinCycle; } KisKeyframeSP KisRepeatFrame::getOriginalKeyframeFor(int time) const { return channel()->activeKeyframeAt(getOriginalTimeFor(time)); } int KisRepeatFrame::firstInstanceOf(int originalTime) const { KisTimeSpan originalRange = m_cycle->originalRange(); const int timeWithinCycle = originalTime - originalRange.start(); - const int first = this->time() + timeWithinCycle; - - const KisKeyframeSP next = channel()->nextKeyframe(*this); - if (next && next->time() < first) return -1; + const int first = time() + timeWithinCycle; - return first; + const int endTime = end(); + return (endTime == -1 || first <= endTime) ? first : -1; } int KisRepeatFrame::previousVisibleFrame(int time) const { if (time <= this->time()) return -1; const int earlierOriginalTime = getOriginalTimeFor(time - 1); int originalStart, originalEnd; channel()->activeKeyframeRange(earlierOriginalTime, &originalStart, &originalEnd); if (originalEnd == -1) return -1; const int durationOfOriginalKeyframe = originalEnd + 1 - originalStart; return time - durationOfOriginalKeyframe; } int KisRepeatFrame::nextVisibleFrame(int time) const { const int originalTime = getOriginalTimeFor(time); int originalStart, originalEnd; channel()->activeKeyframeRange(originalTime, &originalStart, &originalEnd); if (originalEnd == -1) return -1; const int durationOfOriginalKeyframe = originalEnd + 1 - originalStart; const int nextFrameTime = time + durationOfOriginalKeyframe; - const KisKeyframeSP next = channel()->nextKeyframe(*this); - if (next && next->time() <= nextFrameTime) return -1; + const int endTime = end(); + return (endTime == -1 || nextFrameTime < endTime) ? nextFrameTime : -1; +} - return nextFrameTime; +int KisRepeatFrame::end() const +{ + // TODO: implement + return -1; } diff --git a/libs/image/kis_animation_cycle.h b/libs/image/kis_animation_cycle.h index 77191af60f..91d5169405 100644 --- a/libs/image/kis_animation_cycle.h +++ b/libs/image/kis_animation_cycle.h @@ -1,85 +1,91 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_ANIMATION_CYCLE_H #define KIS_ANIMATION_CYCLE_H #include "kis_keyframe.h" class KisTimeSpan; class KisFrameSet; class KisRepeatFrame; -class KRITAIMAGE_EXPORT KisAnimationCycle { +class KRITAIMAGE_EXPORT KisAnimationCycle : public KisKeyframeBase { public: - KisAnimationCycle(KisKeyframeSP firstKeyframe, KisKeyframeSP lastKeyframe); + KisAnimationCycle(KisKeyframeChannel *channel, KisKeyframeSP firstKeyframe, KisKeyframeSP lastKeyframe); KisKeyframeSP firstSourceKeyframe() const; KisKeyframeSP lastSourceKeyframe() const; KisTimeSpan originalRange() const; int duration() const; void addRepeat(QSharedPointer repeat); void removeRepeat(QSharedPointer repeat); const QVector>& repeats() const; + QRect affectedRect() const override; + KisKeyframeSP getOriginalKeyframeFor(int time) const override; + KisFrameSet instancesWithin(KisKeyframeSP original, KisTimeSpan range) const; private: friend class KisKeyframeChannel; - void setFirstKeyframe(KisKeyframeSP keyframe); - void setLastKeyframe(KisKeyframeSP keyframe); KisKeyframeSP m_firstSourceKeyframe, m_lastSourceKeyframe; QVector> m_repeats; }; -class KRITAIMAGE_EXPORT KisRepeatFrame : public KisKeyframe +class KRITAIMAGE_EXPORT KisRepeatFrame : public KisKeyframeBase { public: KisRepeatFrame(KisKeyframeChannel *channel, int time, QSharedPointer cycle); QSharedPointer cycle() const; + QRect affectedRect() const override; - KisKeyframeSP cloneFor(KisKeyframeChannel *channel) const override; + int getOriginalTimeFor(int time) const; - KisKeyframeSP getOriginalKeyframeFor(int time) const; + KisKeyframeSP getOriginalKeyframeFor(int time) const override; /// Returns the earliest time the original frame appears in this repeat, or -1 if it never does. int firstInstanceOf(int originalTime) const; /** Returns the time at which the previous frame within the repeat appears, * or -1 if time is at the first repeated frame. * NB: time should be at the start of a repeated frame */ int previousVisibleFrame(int time) const; /** Returns the time at which the next frame within the repeat appears, * or -1 if time is at the last repeated frame. * NB: time should be at the start of a repeated frame */ int nextVisibleFrame(int time) const; - static bool isRepeat(KisKeyframeSP keyframe); + /** + * Finds the time of the next keyframe if any. + * Returns -1 if the cycle continues indefinitely. + */ + int end() const; private: QSharedPointer m_cycle; }; #endif diff --git a/libs/image/kis_keyframe.cpp b/libs/image/kis_keyframe.cpp index cb230cc17c..5f0f655bcb 100644 --- a/libs/image/kis_keyframe.cpp +++ b/libs/image/kis_keyframe.cpp @@ -1,132 +1,148 @@ /* * Copyright (c) 2015 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "kis_image_config.h" #include "kis_keyframe.h" +#include "kis_image_config.h" #include "kis_keyframe_channel.h" #include "kis_types.h" #include struct KisKeyframeSPStaticRegistrar { KisKeyframeSPStaticRegistrar() { + qRegisterMetaType("KisKeyframeBaseSP"); qRegisterMetaType("KisKeyframeSP"); } }; static KisKeyframeSPStaticRegistrar __registrar; - -struct KisKeyframe::Private +struct KisKeyframeBase::Private { QPointer channel; int time; - InterpolationMode interpolationMode; - InterpolationTangentsMode tangentsMode; + Private(KisKeyframeChannel *channel, int time) + : channel(channel), time(time) + {} +}; + +KisKeyframeBase::KisKeyframeBase(KisKeyframeChannel *channel, int time) + : m_d(new Private(channel, time)) +{} + +KisKeyframeBase::~KisKeyframeBase() = default; + +KisKeyframeChannel *KisKeyframeBase::channel() const +{ + return m_d->channel; +} + +int KisKeyframeBase::time() const +{ + return m_d->time; +} + +void KisKeyframeBase::setTime(int time) +{ + m_d->time = time; +} + +struct KisKeyframe::Private +{ + InterpolationMode interpolationMode{Constant}; + InterpolationTangentsMode tangentsMode{Smooth}; QPointF leftTangent; QPointF rightTangent; int colorLabel{0}; - - Private(KisKeyframeChannel *channel, int time) - : channel(channel), time(time), interpolationMode(Constant) - {} }; KisKeyframe::KisKeyframe(KisKeyframeChannel *channel, int time) - : m_d(new Private(channel, time)) + : KisKeyframeBase(channel, time) + , m_d(new Private()) { m_d->colorLabel = KisImageConfig(true).defaultFrameColorLabel(); } KisKeyframe::KisKeyframe(const KisKeyframe *rhs, KisKeyframeChannel *channel) - : m_d(new Private(channel, rhs->time())) + : KisKeyframeBase(channel, rhs->time()) + , m_d(new Private()) { m_d->interpolationMode = rhs->m_d->interpolationMode; m_d->tangentsMode = rhs->m_d->tangentsMode; m_d->leftTangent = rhs->m_d->leftTangent; m_d->rightTangent = rhs->m_d->rightTangent; m_d->colorLabel = rhs->m_d->colorLabel; } KisKeyframe::~KisKeyframe() {} -int KisKeyframe::time() const -{ - return m_d->time; -} - -void KisKeyframe::setTime(int time) -{ - m_d->time = time; -} - void KisKeyframe::setInterpolationMode(KisKeyframe::InterpolationMode mode) { m_d->interpolationMode = mode; } KisKeyframe::InterpolationMode KisKeyframe::interpolationMode() const { return m_d->interpolationMode; } void KisKeyframe::setTangentsMode(KisKeyframe::InterpolationTangentsMode mode) { m_d->tangentsMode = mode; } KisKeyframe::InterpolationTangentsMode KisKeyframe::tangentsMode() const { return m_d->tangentsMode; } void KisKeyframe::setInterpolationTangents(QPointF leftTangent, QPointF rightTangent) { m_d->leftTangent = leftTangent; m_d->rightTangent = rightTangent; } QPointF KisKeyframe::leftTangent() const { return m_d->leftTangent; } QPointF KisKeyframe::rightTangent() const { return m_d->rightTangent; } int KisKeyframe::colorLabel() const { return m_d->colorLabel; } void KisKeyframe::setColorLabel(int label) { m_d->colorLabel = label; } bool KisKeyframe::hasContent() const { return true; } -KisKeyframeChannel *KisKeyframe::channel() const +KisKeyframeSP KisKeyframe::getOriginalKeyframeFor(int) const { - return m_d->channel; + return channel()->keyframeAt(this->time()); } diff --git a/libs/image/kis_keyframe.h b/libs/image/kis_keyframe.h index c71d4dfd7b..ad866ab14a 100644 --- a/libs/image/kis_keyframe.h +++ b/libs/image/kis_keyframe.h @@ -1,82 +1,100 @@ /* * Copyright (c) 2015 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_KEYFRAME_H #define KIS_KEYFRAME_H #include #include #include #include "kritaimage_export.h" #include "kis_types.h" class KisKeyframeChannel; -class KRITAIMAGE_EXPORT KisKeyframe +class KRITAIMAGE_EXPORT KisKeyframeBase +{ +public: + KisKeyframeBase(KisKeyframeChannel *channel, int time); + virtual ~KisKeyframeBase(); + + KisKeyframeChannel *channel() const; + + int time() const; + void setTime(int time); + + virtual QRect affectedRect() const = 0; + virtual KisKeyframeSP getOriginalKeyframeFor(int time) const = 0; + +private: + struct Private; + QScopedPointer m_d; + +}; +class KRITAIMAGE_EXPORT KisKeyframe : public KisKeyframeBase { public: enum InterpolationMode { Constant, Linear, Bezier }; enum InterpolationTangentsMode { Sharp, Smooth }; KisKeyframe(KisKeyframeChannel *channel, int time); - virtual ~KisKeyframe(); + ~KisKeyframe() override; /** * Create a copy of the keyframe for insertion into given channel. * Used when constructing a copy of a keyframe channel. */ virtual KisKeyframeSP cloneFor(KisKeyframeChannel *channel) const = 0; - int time() const; - void setTime(int time); - void setInterpolationMode(InterpolationMode mode); InterpolationMode interpolationMode() const; void setTangentsMode(InterpolationTangentsMode mode); InterpolationTangentsMode tangentsMode() const; void setInterpolationTangents(QPointF leftTangent, QPointF rightTangent); QPointF leftTangent() const; QPointF rightTangent() const; int colorLabel() const; void setColorLabel(int label); + virtual bool hasContent() const; // does any content exist in keyframe, or is it empty? - virtual QRect affectedRect() const = 0; - KisKeyframeChannel *channel() const; + KisKeyframeSP getOriginalKeyframeFor(int time) const override; protected: KisKeyframe(const KisKeyframe *rhs, KisKeyframeChannel *channel); private: struct Private; QScopedPointer m_d; }; +Q_DECLARE_METATYPE(KisKeyframeBase*) +Q_DECLARE_METATYPE(KisKeyframeBaseSP) Q_DECLARE_METATYPE(KisKeyframe*) Q_DECLARE_METATYPE(KisKeyframeSP) #endif diff --git a/libs/image/kis_keyframe_channel.cpp b/libs/image/kis_keyframe_channel.cpp index 516f1791e0..b8e4157aa6 100644 --- a/libs/image/kis_keyframe_channel.cpp +++ b/libs/image/kis_keyframe_channel.cpp @@ -1,956 +1,964 @@ /* * Copyright (c) 2015 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_keyframe_channel.h" #include "KoID.h" #include "kis_global.h" #include "kis_node.h" #include "kis_time_range.h" #include "kundo2command.h" #include "kis_keyframe_commands.h" #include "kis_animation_cycle.h" #include const KoID KisKeyframeChannel::Content = KoID("content", ki18n("Content")); const KoID KisKeyframeChannel::Opacity = KoID("opacity", ki18n("Opacity")); const KoID KisKeyframeChannel::TransformArguments = KoID("transform_arguments", ki18n("Transform")); const KoID KisKeyframeChannel::TransformPositionX = KoID("transform_pos_x", ki18n("Position (X)")); const KoID KisKeyframeChannel::TransformPositionY = KoID("transform_pos_y", ki18n("Position (Y)")); const KoID KisKeyframeChannel::TransformScaleX = KoID("transform_scale_x", ki18n("Scale (X)")); const KoID KisKeyframeChannel::TransformScaleY = KoID("transform_scale_y", ki18n("Scale (Y)")); const KoID KisKeyframeChannel::TransformShearX = KoID("transform_shear_x", ki18n("Shear (X)")); const KoID KisKeyframeChannel::TransformShearY = KoID("transform_shear_y", ki18n("Shear (Y)")); const KoID KisKeyframeChannel::TransformRotationX = KoID("transform_rotation_x", ki18n("Rotation (X)")); const KoID KisKeyframeChannel::TransformRotationY = KoID("transform_rotation_y", ki18n("Rotation (Y)")); const KoID KisKeyframeChannel::TransformRotationZ = KoID("transform_rotation_z", ki18n("Rotation (Z)")); struct KisKeyframeChannel::Private { Private() {} Private(const Private &rhs, KisNodeWSP newParentNode) { node = newParentNode; id = rhs.id; defaultBounds = rhs.defaultBounds; haveBrokenFrameTimeBug = rhs.haveBrokenFrameTimeBug; } KeyframesMap keys; QMap> cycles; + QMap> repeats; KisNodeWSP node; KoID id; KisDefaultBoundsBaseSP defaultBounds; bool haveBrokenFrameTimeBug = false; - void addKeyframe(KisKeyframeSP keyframe) { - keys.insert(keyframe->time(), keyframe); - - auto repeat = keyframe.dynamicCast(); + void add(KisKeyframeBaseSP item) { + auto repeat = item.dynamicCast(); if (repeat) { - QSharedPointer cycle = repeat->cycle(); - cycles.insert(keyframe->time(), cycle); - cycle->addRepeat(repeat); + repeat->cycle()->addRepeat(repeat); + repeats.insert(repeat->time(), repeat); + } else { + auto keyframe = item.dynamicCast(); + KIS_ASSERT_RECOVER_RETURN(keyframe); + keys.insert(item->time(), keyframe); } } - void removeKeyframe(KisKeyframeSP keyframe) { - keys.remove(keyframe->time()); - - auto repeat = keyframe.dynamicCast(); + void remove(KisKeyframeBaseSP item) { + auto repeat = item.dynamicCast(); if (repeat) { - cycles.remove(keyframe->time()); repeat->cycle()->removeRepeat(repeat); + repeats.remove(repeat->time()); + } else { + keys.remove(item->time()); } } void moveKeyframe(KisKeyframeSP keyframe, int newTime) { - removeKeyframe(keyframe); + remove(keyframe); keyframe->setTime(newTime); - addKeyframe(keyframe); + add(keyframe); + } + + void addCycle(QSharedPointer cycle) { + cycles.insert(cycle->time(), cycle); + } + + void removeCycle(QSharedPointer cycle) { + KIS_SAFE_ASSERT_RECOVER_NOOP(cycle->repeats().isEmpty()); + cycles.remove(cycle->time()); } }; KisKeyframeChannel::KisKeyframeChannel(const KoID &id, KisDefaultBoundsBaseSP defaultBounds) : m_d(new Private) { m_d->id = id; m_d->node = 0; m_d->defaultBounds = defaultBounds; } KisKeyframeChannel::KisKeyframeChannel(const KisKeyframeChannel &rhs, KisNode *newParentNode) : m_d(new Private(*rhs.m_d, newParentNode)) { KIS_ASSERT_RECOVER_NOOP(&rhs != this); - Q_FOREACH(const QSharedPointer rhsCycle, rhs.m_d->cycles) { - const int time = rhsCycle->firstSourceKeyframe()->time(); - QSharedPointer cycle = toQShared(new KisAnimationCycle(KisKeyframeSP(), KisKeyframeSP())); - m_d->cycles.insert(time, cycle); - } - Q_FOREACH(KisKeyframeSP keyframe, rhs.m_d->keys) { const KisKeyframeSP clone = keyframe->cloneFor(this); - m_d->addKeyframe(clone); + m_d->add(clone); } Q_FOREACH(const QSharedPointer rhsCycle, rhs.m_d->cycles) { - QSharedPointer cycle = cycleAt(rhsCycle->firstSourceKeyframe()->time()); - cycle->setFirstKeyframe(keyframeAt(rhsCycle->firstSourceKeyframe()->time())); - cycle->setLastKeyframe(keyframeAt(rhsCycle->lastSourceKeyframe()->time())); + KisKeyframeSP firstFrame = keyframeAt(rhsCycle->firstSourceKeyframe()->time()); + KisKeyframeSP lastFrame = keyframeAt(rhsCycle->lastSourceKeyframe()->time()); + + QSharedPointer cycle = toQShared(new KisAnimationCycle(this, firstFrame, lastFrame)); + m_d->addCycle(cycle); + + Q_FOREACH(auto rhsRepeatWP, rhsCycle->repeats()) { + const QSharedPointer rhsRepeat = rhsRepeatWP.toStrongRef(); + if (rhsRepeat) { + m_d->add(toQShared(new KisRepeatFrame(this, rhsRepeat->time(), cycle))); + } + } + } } KisKeyframeChannel::~KisKeyframeChannel() {} QString KisKeyframeChannel::id() const { return m_d->id.id(); } QString KisKeyframeChannel::name() const { return m_d->id.name(); } void KisKeyframeChannel::setNode(KisNodeWSP node) { m_d->node = node; } KisNodeWSP KisKeyframeChannel::node() const { return m_d->node; } int KisKeyframeChannel::keyframeCount() const { return m_d->keys.count(); } KisKeyframeChannel::KeyframesMap& KisKeyframeChannel::keys() { return m_d->keys; } const KisKeyframeChannel::KeyframesMap& KisKeyframeChannel::constKeys() const { return m_d->keys; } #define LAZY_INITIALIZE_PARENT_COMMAND(cmd) \ QScopedPointer __tempCommand; \ if (!parentCommand) { \ __tempCommand.reset(new KUndo2Command()); \ cmd = __tempCommand.data(); \ } KisKeyframeSP KisKeyframeChannel::addKeyframe(int time, KUndo2Command *parentCommand) { LAZY_INITIALIZE_PARENT_COMMAND(parentCommand); return insertKeyframe(time, KisKeyframeSP(), parentCommand); } KisKeyframeSP KisKeyframeChannel::copyKeyframe(const KisKeyframeSP keyframe, int newTime, KUndo2Command *parentCommand) { LAZY_INITIALIZE_PARENT_COMMAND(parentCommand); return insertKeyframe(newTime, keyframe, parentCommand); } KisKeyframeSP KisKeyframeChannel::linkKeyframe(const KisKeyframeSP, int, KUndo2Command*) { return KisKeyframeSP(); } KisKeyframeSP KisKeyframeChannel::insertKeyframe(int time, const KisKeyframeSP copySrc, KUndo2Command *parentCommand) { KisKeyframeSP keyframe = keyframeAt(time); if (keyframe) { deleteKeyframeImpl(keyframe, parentCommand, false); } Q_ASSERT(parentCommand); keyframe = createKeyframe(time, copySrc, parentCommand); KUndo2Command *cmd = new KisReplaceKeyframeCommand(this, keyframe->time(), keyframe, parentCommand); cmd->redo(); return keyframe; } bool KisKeyframeChannel::deleteKeyframe(KisKeyframeSP keyframe, KUndo2Command *parentCommand) { return deleteKeyframeImpl(keyframe, parentCommand, true); } bool KisKeyframeChannel::moveKeyframe(KisKeyframeSP keyframe, int newTime, KUndo2Command *parentCommand) { LAZY_INITIALIZE_PARENT_COMMAND(parentCommand); if (newTime == keyframe->time()) return false; KisKeyframeSP other = keyframeAt(newTime); if (other) { deleteKeyframeImpl(other, parentCommand, false); } const int srcTime = keyframe->time(); KUndo2Command *cmd = new KisMoveFrameCommand(this, keyframe, srcTime, newTime, parentCommand); cmd->redo(); if (srcTime == 0) { addKeyframe(srcTime, parentCommand); } return true; } bool KisKeyframeChannel::swapFrames(int lhsTime, int rhsTime, KUndo2Command *parentCommand) { LAZY_INITIALIZE_PARENT_COMMAND(parentCommand); if (lhsTime == rhsTime) return false; KisKeyframeSP lhsFrame = keyframeAt(lhsTime); KisKeyframeSP rhsFrame = keyframeAt(rhsTime); if (!lhsFrame && !rhsFrame) return false; if (lhsFrame && !rhsFrame) { moveKeyframe(lhsFrame, rhsTime, parentCommand); } else if (!lhsFrame && rhsFrame) { moveKeyframe(rhsFrame, lhsTime, parentCommand); } else { KUndo2Command *cmd = new KisSwapFramesCommand(this, lhsFrame, rhsFrame, parentCommand); cmd->redo(); } return true; } bool KisKeyframeChannel::deleteKeyframeImpl(KisKeyframeSP keyframe, KUndo2Command *parentCommand, bool recreate) { LAZY_INITIALIZE_PARENT_COMMAND(parentCommand); Q_ASSERT(parentCommand); KUndo2Command *cmd = new KisReplaceKeyframeCommand(this, keyframe->time(), KisKeyframeSP(), parentCommand); cmd->redo(); destroyKeyframe(keyframe, parentCommand); if (recreate && keyframe->time() == 0) { addKeyframe(0, parentCommand); } return true; } void KisKeyframeChannel::moveKeyframeImpl(KisKeyframeSP keyframe, int newTime) { KIS_ASSERT_RECOVER_RETURN(keyframe); KIS_ASSERT_RECOVER_RETURN(!keyframeAt(newTime)); KisFrameSet rangeSrc = affectedFrames(keyframe->time()); QRect rectSrc = keyframe->affectedRect(); emit sigKeyframeAboutToBeMoved(keyframe, newTime); int oldTime = keyframe->time(); m_d->moveKeyframe(keyframe, newTime); keyframe->setTime(newTime); emit sigKeyframeMoved(keyframe, oldTime); KisFrameSet rangeDst = affectedFrames(keyframe->time()); QRect rectDst = keyframe->affectedRect(); requestUpdate(rangeSrc, rectSrc); requestUpdate(rangeDst, rectDst); } void KisKeyframeChannel::swapKeyframesImpl(KisKeyframeSP lhsKeyframe, KisKeyframeSP rhsKeyframe) { KIS_ASSERT_RECOVER_RETURN(lhsKeyframe); KIS_ASSERT_RECOVER_RETURN(rhsKeyframe); KisFrameSet rangeLhs = affectedFrames(lhsKeyframe->time()); KisFrameSet rangeRhs = affectedFrames(rhsKeyframe->time()); const QRect rectLhsSrc = lhsKeyframe->affectedRect(); const QRect rectRhsSrc = rhsKeyframe->affectedRect(); const int lhsTime = lhsKeyframe->time(); const int rhsTime = rhsKeyframe->time(); emit sigKeyframeAboutToBeMoved(lhsKeyframe, rhsTime); emit sigKeyframeAboutToBeMoved(rhsKeyframe, lhsTime); - m_d->removeKeyframe(lhsKeyframe); - m_d->removeKeyframe(rhsKeyframe); + m_d->remove(lhsKeyframe); + m_d->remove(rhsKeyframe); rhsKeyframe->setTime(lhsTime); lhsKeyframe->setTime(rhsTime); - m_d->addKeyframe(lhsKeyframe); - m_d->addKeyframe(rhsKeyframe); + m_d->add(lhsKeyframe); + m_d->add(rhsKeyframe); emit sigKeyframeMoved(lhsKeyframe, lhsTime); emit sigKeyframeMoved(rhsKeyframe, rhsTime); const QRect rectLhsDst = lhsKeyframe->affectedRect(); const QRect rectRhsDst = rhsKeyframe->affectedRect(); requestUpdate(rangeLhs, rectLhsSrc | rectRhsDst); requestUpdate(rangeRhs, rectRhsSrc | rectLhsDst); } KisKeyframeSP KisKeyframeChannel::replaceKeyframeAt(int time, KisKeyframeSP newKeyframe) { Q_ASSERT(newKeyframe.isNull() || time == newKeyframe->time()); KisKeyframeSP existingKeyframe = keyframeAt(time); if (!existingKeyframe.isNull()) { removeKeyframeLogical(existingKeyframe); } if (!newKeyframe.isNull()) { insertKeyframeLogical(newKeyframe); } return existingKeyframe; } void KisKeyframeChannel::insertKeyframeLogical(KisKeyframeSP keyframe) { const int time = keyframe->time(); emit sigKeyframeAboutToBeAdded(keyframe); - m_d->addKeyframe(keyframe); + m_d->add(keyframe); emit sigKeyframeAdded(keyframe); QRect rect = keyframe->affectedRect(); KisFrameSet range = affectedFrames(time); requestUpdate(range, rect); } void KisKeyframeChannel::removeKeyframeLogical(KisKeyframeSP keyframe) { QRect rect = keyframe->affectedRect(); KisFrameSet range = affectedFrames(keyframe->time()); emit sigKeyframeAboutToBeRemoved(keyframe); - m_d->removeKeyframe(keyframe); + m_d->remove(keyframe); emit sigKeyframeRemoved(keyframe); requestUpdate(range, rect); } KisKeyframeSP KisKeyframeChannel::keyframeAt(int time) const { KeyframesMap::const_iterator i = m_d->keys.constFind(time); if (i != m_d->keys.constEnd()) { return i.value(); } return KisKeyframeSP(); } KisKeyframeSP KisKeyframeChannel::activeKeyframeAt(int time) const { KeyframesMap::const_iterator i = activeKeyIterator(time); if (i != m_d->keys.constEnd()) { return i.value(); } return KisKeyframeSP(); } KisKeyframeSP KisKeyframeChannel::visibleKeyframeAt(int time) const { KisKeyframeSP keyframe = activeKeyframeAt(time); const KisRepeatFrame *repeat = dynamic_cast(keyframe.data()); if (repeat) keyframe = repeat->getOriginalKeyframeFor(time); return keyframe; } KisKeyframeSP KisKeyframeChannel::currentlyActiveKeyframe() const { return activeKeyframeAt(currentTime()); } KisKeyframeSP KisKeyframeChannel::firstKeyframe() const { if (m_d->keys.isEmpty()) return KisKeyframeSP(); return m_d->keys.first(); } KisKeyframeSP KisKeyframeChannel::nextKeyframe(KisKeyframeSP keyframe) const { return nextKeyframe(*keyframe); } KisKeyframeSP KisKeyframeChannel::nextKeyframe(const KisKeyframe &keyframe) const { KeyframesMap::const_iterator i = m_d->keys.constFind(keyframe.time()); if (i == m_d->keys.constEnd()) return KisKeyframeSP(0); i++; if (i == m_d->keys.constEnd()) return KisKeyframeSP(0); return i.value(); } KisKeyframeSP KisKeyframeChannel::previousKeyframe(KisKeyframeSP keyframe) const { return previousKeyframe(*keyframe); } KisKeyframeSP KisKeyframeChannel::previousKeyframe(const KisKeyframe &keyframe) const { KeyframesMap::const_iterator i = m_d->keys.constFind(keyframe.time()); if (i == m_d->keys.constBegin() || i == m_d->keys.constEnd()) return KisKeyframeSP(0); i--; return i.value(); } KisKeyframeSP KisKeyframeChannel::lastKeyframe() const { if (m_d->keys.isEmpty()) return KisKeyframeSP(0); return (m_d->keys.end()-1).value(); } KisVisibleKeyframeIterator KisKeyframeChannel::visibleKeyframesFrom(int time) const { return KisVisibleKeyframeIterator(visibleKeyframeAt(time)); } KisTimeSpan KisKeyframeChannel::cycledRangeAt(int time) const { QSharedPointer cycle = cycleAt(time); if (cycle.isNull()) return KisTimeSpan(); const KisKeyframeSP firstAfterCycle = nextKeyframe(cycle->lastSourceKeyframe()); int start = cycle->firstSourceKeyframe()->time(); KisTimeSpan originalRange; if (firstAfterCycle.isNull()) { originalRange = KisTimeSpan(start, lastKeyframe()->time()); } else { originalRange = KisTimeSpan(start, firstAfterCycle->time() - 1); } - if (originalRange.contains(time) || KisRepeatFrame::isRepeat(activeKeyframeAt(time))) { + if (originalRange.contains(time)) { return originalRange; } return KisTimeSpan(); } QSharedPointer KisKeyframeChannel::cycleAt(int time) const { if (!m_d->cycles.isEmpty()) { auto it = m_d->cycles.upperBound(time); if (it != m_d->cycles.begin()) it--; return it.value(); } return QSharedPointer(); }; void KisKeyframeChannel::activeKeyframeRange(int time, int *first, int *last) const { *first = *last = -1; const KisKeyframeSP currentKeyframe = activeKeyframeAt(time); if (currentKeyframe.isNull()) return; *first = currentKeyframe->time(); const KisKeyframeSP next = nextKeyframe(currentKeyframe); if (!next.isNull()) { *last = next->time() - 1; } } int KisKeyframeChannel::framesHash() const { KeyframesMap::const_iterator it = m_d->keys.constBegin(); KeyframesMap::const_iterator end = m_d->keys.constEnd(); int hash = 0; while (it != end) { hash += it.key(); ++it; } return hash; } QSet KisKeyframeChannel::allKeyframeIds() const { QSet frames; KeyframesMap::const_iterator it = m_d->keys.constBegin(); KeyframesMap::const_iterator end = m_d->keys.constEnd(); while (it != end) { frames.insert(it.key()); ++it; } return frames; } KisFrameSet KisKeyframeChannel::affectedFrames(int time) const { if (m_d->keys.isEmpty()) return KisFrameSet::infiniteFrom(0); KeyframesMap::const_iterator active = activeKeyIterator(time); KeyframesMap::const_iterator next; int from; if (active == m_d->keys.constEnd()) { // No active keyframe, ie. time is before the first keyframe from = 0; next = m_d->keys.constBegin(); } else { from = active.key(); next = active + 1; } KisFrameSet frames; QSharedPointer cycle = cycleAt(time); if (!cycle.isNull()) { KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(active != m_d->keys.constEnd() && active.value(), KisFrameSet()); if (cycle->originalRange().contains(time)) { frames = cycle->instancesWithin(active.value(), KisTimeSpan()); } else { const KisRepeatFrame *repeat = dynamic_cast(active.value().data()); if (repeat) { const KisKeyframeSP original = repeat->getOriginalKeyframeFor(time); return affectedFrames(original->time()); } } } if (next == m_d->keys.constEnd()) { frames |= KisFrameSet::infiniteFrom(from); } else { frames |= KisFrameSet::between(from, next.key() - 1); } return frames; } KisFrameSet KisKeyframeChannel::identicalFrames(int time, const KisTimeSpan range) const { KeyframesMap::const_iterator active = activeKeyIterator(time); QSharedPointer cycle = cycleAt(time); if (!cycle.isNull()) { if (cycle->originalRange().contains(time)) { return cycle->instancesWithin(active.value(), range); } else { const KisRepeatFrame *repeat = dynamic_cast(active.value().data()); if (repeat) { const KisKeyframeSP original = repeat->getOriginalKeyframeFor(time); return identicalFrames(original->time(), range); } } } if (active != m_d->keys.constEnd() && (active+1) != m_d->keys.constEnd()) { if (active->data()->interpolationMode() != KisKeyframe::Constant) { return KisFrameSet::between(time, time); } } return affectedFrames(time); } bool KisKeyframeChannel::areFramesIdentical(int time1, int time2) const { const KisFrameSet identical = identicalFrames(time1, KisTimeSpan(time2, time2)); return identical.contains(time2); } bool KisKeyframeChannel::isFrameAffectedBy(int targetFrame, int changedFrame) const { const KisFrameSet affected = affectedFrames(changedFrame); return affected.contains(targetFrame); } QDomElement KisKeyframeChannel::toXML(QDomDocument doc, const QString &layerFilename) { QDomElement channelElement = doc.createElement("channel"); channelElement.setAttribute("name", id()); Q_FOREACH (const QSharedPointer cycle, m_d->cycles.values()) { QDomElement cycleElement = doc.createElement("cycle"); cycleElement.setAttribute("firstKeyframe", cycle->firstSourceKeyframe()->time()); cycleElement.setAttribute("lastKeyframe", cycle->lastSourceKeyframe()->time()); channelElement.appendChild(cycleElement); } Q_FOREACH (KisKeyframeSP keyframe, m_d->keys.values()) { QDomElement keyframeElement = doc.createElement("keyframe"); keyframeElement.setAttribute("time", keyframe->time()); keyframeElement.setAttribute("color-label", keyframe->colorLabel()); KisRepeatFrame *repeat = dynamic_cast(keyframe.data()); if (repeat) { keyframeElement.setAttribute("type", "repeat"); const int sourceTime = repeat->cycle()->firstSourceKeyframe()->time(); keyframeElement.setAttribute("cycle", sourceTime); } else { saveKeyframe(keyframe, keyframeElement, layerFilename); } channelElement.appendChild(keyframeElement); } return channelElement; } void KisKeyframeChannel::loadXML(const QDomElement &channelNode) { QMap> cyclesByFirstKeyframe; QMap> cyclesByLastKeyframe; for (QDomElement childNode = channelNode.firstChildElement(); !childNode.isNull(); childNode = childNode.nextSiblingElement()) { const QString nodeName = childNode.nodeName().toUpper(); if (nodeName == "CYCLE") { const int firstKeyframeTime = childNode.attribute("firstKeyframe", "-1").toInt(); const int lastKeyframeTime = childNode.attribute("lastKeyframe", "-1").toInt(); if (firstKeyframeTime >= 0 && lastKeyframeTime > firstKeyframeTime) { - QSharedPointer cycle = toQShared(new KisAnimationCycle(KisKeyframeSP(), KisKeyframeSP())); + QSharedPointer cycle = toQShared(new KisAnimationCycle(this, KisKeyframeSP(), KisKeyframeSP())); cyclesByFirstKeyframe.insert(firstKeyframeTime, cycle); cyclesByLastKeyframe.insert(lastKeyframeTime, cycle); } } } for (QDomElement childNode = channelNode.firstChildElement(); !childNode.isNull(); childNode = childNode.nextSiblingElement()) { const QString nodeName = childNode.nodeName().toUpper(); if (nodeName == "KEYFRAME") { const QString keyframeType = childNode.attribute("type", "").toUpper(); KisKeyframeSP keyframe; if (keyframeType == "REPEAT") { - keyframe = loadRepeatFrame(childNode, cyclesByFirstKeyframe); + // FIXME + //keyframe = loadRepeatFrame(childNode, cyclesByFirstKeyframe); } else { keyframe = loadKeyframe(childNode); } KIS_SAFE_ASSERT_RECOVER(keyframe) { continue; } if (childNode.hasAttribute("color-label")) { keyframe->setColorLabel(childNode.attribute("color-label").toUInt()); } - m_d->addKeyframe(keyframe); + m_d->add(keyframe); const int time = keyframe->time(); if (cyclesByFirstKeyframe.contains(time)) { - cyclesByFirstKeyframe[time]->setFirstKeyframe(keyframe); + //cyclesByFirstKeyframe[time]->setFirstKeyframe(keyframe); addCycle(cyclesByFirstKeyframe[time]); } if (cyclesByLastKeyframe.contains(time)) { - cyclesByLastKeyframe[time]->setLastKeyframe(keyframe); + //cyclesByLastKeyframe[time]->setLastKeyframe(keyframe); } } } } -KisKeyframeSP KisKeyframeChannel::loadRepeatFrame(const QDomElement &keyframeNode, const QMap> &cyclesByFirstKeyframe) -{ - const int original = keyframeNode.attribute("cycle", "-1").toInt(); - const QSharedPointer cycle = cyclesByFirstKeyframe.value(original); - const int time = keyframeNode.attribute("time").toInt(); - - if (cycle) { - return toQShared(new KisRepeatFrame(this, time, cycle)); - } - return KisKeyframeSP(); -} - bool KisKeyframeChannel::swapExternalKeyframe(KisKeyframeChannel *srcChannel, int srcTime, int dstTime, KUndo2Command *parentCommand) { if (srcChannel->id() != id()) { warnKrita << "Cannot copy frames from different ids:" << ppVar(srcChannel->id()) << ppVar(id()); return KisKeyframeSP(); } LAZY_INITIALIZE_PARENT_COMMAND(parentCommand); KisKeyframeSP srcFrame = srcChannel->keyframeAt(srcTime); KisKeyframeSP dstFrame = keyframeAt(dstTime); if (!dstFrame && srcFrame) { copyExternalKeyframe(srcChannel, srcTime, dstTime, parentCommand); srcChannel->deleteKeyframe(srcFrame, parentCommand); } else if (dstFrame && !srcFrame) { srcChannel->copyExternalKeyframe(this, dstTime, srcTime, parentCommand); deleteKeyframe(dstFrame, parentCommand); } else if (dstFrame && srcFrame) { const int fakeFrameTime = -1; KisKeyframeSP newKeyframe = createKeyframe(fakeFrameTime, KisKeyframeSP(), parentCommand); uploadExternalKeyframe(srcChannel, srcTime, newKeyframe); srcChannel->copyExternalKeyframe(this, dstTime, srcTime, parentCommand); // do not recreate frame! deleteKeyframeImpl(dstFrame, parentCommand, false); newKeyframe->setTime(dstTime); KUndo2Command *cmd = new KisReplaceKeyframeCommand(this, newKeyframe->time(), newKeyframe, parentCommand); cmd->redo(); } return true; } KisKeyframeSP KisKeyframeChannel::copyExternalKeyframe(KisKeyframeChannel *srcChannel, int srcTime, int dstTime, KUndo2Command *parentCommand) { if (srcChannel->id() != id()) { warnKrita << "Cannot copy frames from different ids:" << ppVar(srcChannel->id()) << ppVar(id()); return KisKeyframeSP(); } LAZY_INITIALIZE_PARENT_COMMAND(parentCommand); KisKeyframeSP dstFrame = keyframeAt(dstTime); if (dstFrame) { deleteKeyframeImpl(dstFrame, parentCommand, false); } KisKeyframeSP newKeyframe = createKeyframe(dstTime, KisKeyframeSP(), parentCommand); uploadExternalKeyframe(srcChannel, srcTime, newKeyframe); KUndo2Command *cmd = new KisReplaceKeyframeCommand(this, newKeyframe->time(), newKeyframe, parentCommand); cmd->redo(); return newKeyframe; } KUndo2Command * KisKeyframeChannel::createCycle(KisKeyframeSP firstKeyframe, KisKeyframeSP lastKeyframe, KUndo2Command *parentCommand) { - const QSharedPointer cycle = toQShared(new KisAnimationCycle(firstKeyframe, lastKeyframe)); + const QSharedPointer cycle = toQShared(new KisAnimationCycle(this, firstKeyframe, lastKeyframe)); return new KisDefineCycleCommand(this, cycle, false, parentCommand); } void KisKeyframeChannel::addCycle(QSharedPointer cycle) { m_d->cycles.insert(cycle->firstSourceKeyframe()->time(), cycle); } KUndo2Command* KisKeyframeChannel::deleteCycle(QSharedPointer cycle, KUndo2Command *parentCommand) { Q_FOREACH(QWeakPointer repeat, cycle->repeats()) { auto repeatSP = repeat.toStrongRef(); - deleteKeyframe(repeatSP, parentCommand); + // FIXME! deleteKeyframe(repeatSP, parentCommand); } return new KisDefineCycleCommand(this, cycle, true, parentCommand); } void KisKeyframeChannel::removeCycle(QSharedPointer cycle) { m_d->cycles.remove(cycle->firstSourceKeyframe()->time()); } KisKeyframeSP KisKeyframeChannel::addRepeat(int time, KisKeyframeSP source, KUndo2Command *parentCommand) { + return KisKeyframeSP(); + + /* FIXME const QSharedPointer cycle = m_d->cycles.value(source->time()); if (cycle.isNull()) return QSharedPointer(); const QSharedPointer repeatFrame = toQShared(new KisRepeatFrame(this, time, cycle)); KUndo2Command *cmd = new KisReplaceKeyframeCommand(this, time, repeatFrame, parentCommand); cmd->redo(); return repeatFrame; + */ } KisKeyframeChannel::KeyframesMap::const_iterator KisKeyframeChannel::activeKeyIterator(int time) const { KeyframesMap::const_iterator i = const_cast(&m_d->keys)->upperBound(time); if (i == m_d->keys.constBegin()) return m_d->keys.constEnd(); return --i; } void KisKeyframeChannel::requestUpdate(const KisFrameSet &range, const QRect &rect) { if (m_d->node) { m_d->node->invalidateFrames(range, rect); int currentTime = m_d->defaultBounds->currentTime(); if (range.contains(currentTime)) { m_d->node->setDirty(rect); } } } void KisKeyframeChannel::workaroundBrokenFrameTimeBug(int *time) { /** * Between Krita 4.1 and 4.4 Krita had a bug which resulted in creating frames * with negative time stamp. The bug has been fixed, but there might be some files * still in the wild. * * TODO: remove this workaround in Krita 5.0, when no such file are left :) */ if (*time < 0) { qWarning() << "WARNING: Loading a file with negative animation frames!"; qWarning() << " The file has been saved with a buggy version of Krita."; qWarning() << " All the frames with negative ids will be dropped!"; qWarning() << " " << ppVar(this->id()) << ppVar(*time); m_d->haveBrokenFrameTimeBug = true; *time = 0; } if (m_d->haveBrokenFrameTimeBug) { while (keyframeAt(*time)) { (*time)++; } } } int KisKeyframeChannel::currentTime() const { return m_d->defaultBounds->currentTime(); } qreal KisKeyframeChannel::minScalarValue() const { return 0; } qreal KisKeyframeChannel::maxScalarValue() const { return 0; } qreal KisKeyframeChannel::scalarValue(const KisKeyframeSP keyframe) const { Q_UNUSED(keyframe); return 0; } void KisKeyframeChannel::setScalarValue(KisKeyframeSP keyframe, qreal value, KUndo2Command *parentCommand) { Q_UNUSED(keyframe); Q_UNUSED(value); Q_UNUSED(parentCommand); } KisVisibleKeyframeIterator::KisVisibleKeyframeIterator() = default; KisVisibleKeyframeIterator::KisVisibleKeyframeIterator(KisKeyframeSP keyframe) : m_channel(keyframe->channel()) , m_keyframe(keyframe) , m_time(keyframe->time()) {} KisVisibleKeyframeIterator& KisVisibleKeyframeIterator::operator--() { const KisRepeatFrame *repeat = dynamic_cast(m_keyframe.data()); if (repeat) { const int time = repeat->previousVisibleFrame(m_time); if (time >= 0) { m_time = time; return *this; } } m_keyframe = m_channel->previousKeyframe(*m_keyframe); if (!m_keyframe) return invalidate(); m_time = m_keyframe->time(); return *this; } KisVisibleKeyframeIterator& KisVisibleKeyframeIterator::operator++() { const KisRepeatFrame *repeat = dynamic_cast(m_keyframe.data()); if (repeat) { const int time = repeat->nextVisibleFrame(m_time); if (time >= 0) { m_time = time; return *this; } } m_keyframe = m_channel->nextKeyframe(*m_keyframe); if (!m_keyframe) return invalidate(); m_time = m_keyframe->time(); return *this; }; KisKeyframeSP KisVisibleKeyframeIterator::operator*() const { const KisRepeatFrame *repeat = dynamic_cast(m_keyframe.data()); if (repeat) { return repeat->getOriginalKeyframeFor(m_time); } return m_keyframe; } KisKeyframeSP KisVisibleKeyframeIterator::operator->() const { return operator*(); } bool KisVisibleKeyframeIterator::isValid() const { return m_channel && m_time >= 0; } KisVisibleKeyframeIterator& KisVisibleKeyframeIterator::invalidate() { m_channel = nullptr; m_keyframe = KisKeyframeSP(); m_time = -1; return *this; } diff --git a/libs/image/kis_types.h b/libs/image/kis_types.h index 87793d8db0..42886efb71 100644 --- a/libs/image/kis_types.h +++ b/libs/image/kis_types.h @@ -1,310 +1,313 @@ /* * Copyright (c) 2002 Patrick Julien * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISTYPES_H_ #define KISTYPES_H_ #include #include #include #include "kritaimage_export.h" template class KisWeakSharedPtr; template class KisSharedPtr; template class QSharedPointer; template class QWeakPointer; template uint qHash(KisSharedPtr ptr) { return qHash(ptr.data()); } template uint qHash(KisWeakSharedPtr ptr) { return qHash(ptr.data()); } /** * Define lots of shared pointer versions of Krita classes. * Shared pointer classes have the advantage of near automatic * memory management (but beware of circular references) * These types should never be passed by reference, * because that will mess up their reference counter. * * An example of the naming pattern used: * * KisPaintDeviceSP is a KisSharedPtr of KisPaintDevice * KisPaintDeviceWSP is a KisWeakSharedPtr of KisPaintDevice * vKisPaintDeviceSP is a QVector of KisPaintDeviceSP * vKisPaintDeviceSP_it is an iterator of vKisPaintDeviceSP * */ class KisImage; typedef KisSharedPtr KisImageSP; typedef KisWeakSharedPtr KisImageWSP; class KisPaintDevice; typedef KisSharedPtr KisPaintDeviceSP; typedef KisWeakSharedPtr KisPaintDeviceWSP; typedef QVector vKisPaintDeviceSP; typedef vKisPaintDeviceSP::iterator vKisPaintDeviceSP_it; class KisFixedPaintDevice; typedef KisSharedPtr KisFixedPaintDeviceSP; class KisMask; typedef KisSharedPtr KisMaskSP; typedef KisWeakSharedPtr KisMaskWSP; class KisNode; typedef KisSharedPtr KisNodeSP; typedef KisWeakSharedPtr KisNodeWSP; typedef QVector vKisNodeSP; typedef vKisNodeSP::iterator vKisNodeSP_it; typedef vKisNodeSP::const_iterator vKisNodeSP_cit; class KisBaseNode; typedef KisSharedPtr KisBaseNodeSP; typedef KisWeakSharedPtr KisBaseNodeWSP; class KisEffectMask; typedef KisSharedPtr KisEffectMaskSP; typedef KisWeakSharedPtr KisEffectMaskWSP; class KisFilterMask; typedef KisSharedPtr KisFilterMaskSP; typedef KisWeakSharedPtr KisFilterMaskWSP; class KisTransformMask; typedef KisSharedPtr KisTransformMaskSP; typedef KisWeakSharedPtr KisTransformMaskWSP; class KisTransformMaskParamsInterface; typedef QSharedPointer KisTransformMaskParamsInterfaceSP; typedef QWeakPointer KisTransformMaskParamsInterfaceWSP; class KisTransparencyMask; typedef KisSharedPtr KisTransparencyMaskSP; typedef KisWeakSharedPtr KisTransparencyMaskWSP; class KisColorizeMask; typedef KisSharedPtr KisColorizeMaskSP; typedef KisWeakSharedPtr KisColorizeMaskWSP; class KisLayer; typedef KisSharedPtr KisLayerSP; typedef KisWeakSharedPtr KisLayerWSP; class KisShapeLayer; typedef KisSharedPtr KisShapeLayerSP; class KisPaintLayer; typedef KisSharedPtr KisPaintLayerSP; class KisAdjustmentLayer; typedef KisSharedPtr KisAdjustmentLayerSP; class KisGeneratorLayer; typedef KisSharedPtr KisGeneratorLayerSP; class KisCloneLayer; typedef KisSharedPtr KisCloneLayerSP; typedef KisWeakSharedPtr KisCloneLayerWSP; class KisGroupLayer; typedef KisSharedPtr KisGroupLayerSP; typedef KisWeakSharedPtr KisGroupLayerWSP; class KisFileLayer; typedef KisSharedPtr KisFileLayerSP; typedef KisWeakSharedPtr KisFileLayerWSP; class KisSelection; typedef KisSharedPtr KisSelectionSP; typedef KisWeakSharedPtr KisSelectionWSP; class KisSelectionComponent; typedef KisSharedPtr KisSelectionComponentSP; class KisSelectionMask; typedef KisSharedPtr KisSelectionMaskSP; class KisPixelSelection; typedef KisSharedPtr KisPixelSelectionSP; class KisHistogram; typedef KisSharedPtr KisHistogramSP; typedef QVector vKisSegments; class KisFilter; typedef KisSharedPtr KisFilterSP; class KisLayerStyleFilter; typedef KisSharedPtr KisLayerStyleFilterSP; class KisGenerator; typedef KisSharedPtr KisGeneratorSP; class KisConvolutionKernel; typedef KisSharedPtr KisConvolutionKernelSP; class KisAnnotation; typedef KisSharedPtr KisAnnotationSP; typedef QVector vKisAnnotationSP; typedef vKisAnnotationSP::iterator vKisAnnotationSP_it; typedef vKisAnnotationSP::const_iterator vKisAnnotationSP_cit; class KisAnimationFrameCache; typedef KisSharedPtr KisAnimationFrameCacheSP; typedef KisWeakSharedPtr KisAnimationFrameCacheWSP; class KisPaintingAssistant; typedef QSharedPointer KisPaintingAssistantSP; typedef QWeakPointer KisPaintingAssistantWSP; class KisReferenceImage; typedef QSharedPointer KisReferenceImageSP; typedef QWeakPointer KisReferenceImageWSP; // Repeat iterators class KisHLineIterator2; template class KisRepeatHLineIteratorPixelBase; typedef KisRepeatHLineIteratorPixelBase< KisHLineIterator2 > KisRepeatHLineConstIteratorNG; typedef KisSharedPtr KisRepeatHLineConstIteratorSP; class KisVLineIterator2; template class KisRepeatVLineIteratorPixelBase; typedef KisRepeatVLineIteratorPixelBase< KisVLineIterator2 > KisRepeatVLineConstIteratorNG; typedef KisSharedPtr KisRepeatVLineConstIteratorSP; // NG Iterators class KisHLineIteratorNG; typedef KisSharedPtr KisHLineIteratorSP; class KisHLineConstIteratorNG; typedef KisSharedPtr KisHLineConstIteratorSP; class KisVLineIteratorNG; typedef KisSharedPtr KisVLineIteratorSP; class KisVLineConstIteratorNG; typedef KisSharedPtr KisVLineConstIteratorSP; class KisRandomConstAccessorNG; typedef KisSharedPtr KisRandomConstAccessorSP; class KisRandomAccessorNG; typedef KisSharedPtr KisRandomAccessorSP; class KisRandomSubAccessor; typedef KisSharedPtr KisRandomSubAccessorSP; // Things typedef QVector vQPointF; class KisPaintOpPreset; typedef KisSharedPtr KisPaintOpPresetSP; typedef KisWeakSharedPtr KisPaintOpPresetWSP; template class KisPinnedSharedPtr; class KisPaintOpSettings; typedef KisPinnedSharedPtr KisPaintOpSettingsSP; template class KisRestrictedSharedPtr; typedef KisRestrictedSharedPtr KisPaintOpSettingsRestrictedSP; class KisPaintOp; typedef KisSharedPtr KisPaintOpSP; class KoID; typedef QList KoIDList; class KoUpdater; template class QPointer; typedef QPointer KoUpdaterPtr; class KisProcessingVisitor; typedef KisSharedPtr KisProcessingVisitorSP; class KUndo2Command; typedef QSharedPointer KUndo2CommandSP; typedef QList KisNodeList; typedef QSharedPointer KisNodeListSP; typedef QList KisPaintDeviceList; class KisStroke; typedef QSharedPointer KisStrokeSP; typedef QWeakPointer KisStrokeWSP; typedef KisStrokeWSP KisStrokeId; class KisFilterConfiguration; typedef KisPinnedSharedPtr KisFilterConfigurationSP; class KisPropertiesConfiguration; typedef KisPinnedSharedPtr KisPropertiesConfigurationSP; class KisLockedProperties; typedef KisSharedPtr KisLockedPropertiesSP; class KisProjectionUpdatesFilter; typedef QSharedPointer KisProjectionUpdatesFilterSP; class KisAbstractProjectionPlane; typedef QSharedPointer KisAbstractProjectionPlaneSP; typedef QWeakPointer KisAbstractProjectionPlaneWSP; class KisProjectionLeaf; typedef QSharedPointer KisProjectionLeafSP; typedef QWeakPointer KisProjectionLeafWSP; class KisKeyframe; typedef QSharedPointer KisKeyframeSP; typedef QWeakPointer KisKeyframeWSP; +class KisKeyframeBase; +typedef QSharedPointer KisKeyframeBaseSP; + class KisFilterChain; typedef KisSharedPtr KisFilterChainSP; class KisProofingConfiguration; typedef QSharedPointer KisProofingConfigurationSP; typedef QWeakPointer KisProofingConfigurationWSP; class KisLayerComposition; typedef QSharedPointer KisLayerCompositionSP; typedef QWeakPointer KisLayerCompositionWSP; #include #include #include #include #include #endif // KISTYPES_H_