kis_keyframe_channel.cpp 32.9 KB
Newer Older
1
/*
2
 *  Copyright (c) 2015 Jouni Pentikäinen <joupent@gmail.com>
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 *  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.
 */

19
#include "kis_keyframe_channel.h"
20
#include "KoID.h"
Dmitry Kazakov's avatar
Dmitry Kazakov committed
21
#include "kis_global.h"
22
#include "kis_node.h"
23
#include "KisCollectionUtils.h"
24
#include "kis_time_range.h"
25
#include "kundo2command.h"
26
#include "kis_keyframe_commands.h"
27
#include "kis_animation_cycle.h"
28

29 30
#include <QMap>

31
const KoID KisKeyframeChannel::Content = KoID("content", ki18n("Content"));
32
const KoID KisKeyframeChannel::Opacity = KoID("opacity", ki18n("Opacity"));
33
const KoID KisKeyframeChannel::TransformArguments = KoID("transform_arguments", ki18n("Transform"));
34 35 36 37 38 39 40 41 42
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)"));
43

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/**
 * Finds the last item the in the map with a key less than the given one.
 * Returns map.constEnd() if no such key exists.
 */
template<class T>
typename QMap<int, T>::const_iterator findActive(const QMap<int, T> &map, int maximumKey)
{
    typename QMap<int, T>::const_iterator i = map.upperBound(maximumKey);
    if (i == map.constBegin()) return map.constEnd();
    return i - 1;
}

/**
 * Finds the last item the in the map before the "active" item (see findActive) for the given key.
 * Returns map.constEnd() if no such key exists.
 */
template<class T>
typename QMap<int, T>::const_iterator findPrevious(const QMap<int, T> &map, int currentKey)
{
63
    typename QMap<int, T>::const_iterator active = lastBeforeOrAt(map, currentKey);
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
    if (active == map.constEnd()) return map.constEnd();

    if (currentKey > active.key()) return active;

    if (active == map.constBegin()) return map.constEnd();
    return active - 1;
}

/**
 * Finds the first item the in the map with a key greater than the given one.
 * Returns map.constEnd() if no such key exists.
 */
template<class T>
typename QMap<int, T>::const_iterator findNext(const QMap<int, T> &map, int currentKey)
{
    return map.upperBound(currentKey);
}

82 83
struct KisKeyframeChannel::Private
{
84 85 86 87
    Private() {}
    Private(const Private &rhs, KisNodeWSP newParentNode) {
        node = newParentNode;
        id = rhs.id;
88
        defaultBounds = rhs.defaultBounds;
89
        haveBrokenFrameTimeBug = rhs.haveBrokenFrameTimeBug;
90 91
    }

92
    KeyframesMap keys;
93
    QMap<int, QSharedPointer<KisAnimationCycle>> cycles;
94
    QMap<int, QSharedPointer<KisRepeatFrame>> repeats;
95 96
    KisNodeWSP node;
    KoID id;
97
    KisDefaultBoundsBaseSP defaultBounds;
98
    bool haveBrokenFrameTimeBug = false;
99

100 101
    void add(KisKeyframeBaseSP item) {
        auto repeat = item.dynamicCast<KisRepeatFrame>();
102
        if (repeat) {
103 104 105 106 107 108
            repeat->cycle()->addRepeat(repeat);
            repeats.insert(repeat->time(), repeat);
        } else {
            auto keyframe = item.dynamicCast<KisKeyframe>();
            KIS_ASSERT_RECOVER_RETURN(keyframe);
            keys.insert(item->time(), keyframe);
109 110 111
        }
    }

112 113
    void remove(KisKeyframeBaseSP item) {
        auto repeat = item.dynamicCast<KisRepeatFrame>();
114 115
        if (repeat) {
            repeat->cycle()->removeRepeat(repeat);
116 117 118
            repeats.remove(repeat->time());
        } else {
            keys.remove(item->time());
119 120 121
        }
    }

122 123 124
    void moveKeyframe(KisKeyframeBaseSP keyframe, int newTime) {
        const QSharedPointer<KisAnimationCycle> cycle = cycles.value(keyframe->time());

125
        remove(keyframe);
126
        keyframe->setTime(newTime);
127
        add(keyframe);
128 129 130 131 132 133 134 135

        if (cycle) {
            KIS_SAFE_ASSERT_RECOVER_NOOP(newTime < cycle->lastSourceKeyframe()->time()); // TODO: make sure this is the case

            cycles.remove(cycle->time());
            cycle->setTime(newTime);
            cycles.insert(newTime, cycle);
        }
136 137 138 139
    }

    void addCycle(QSharedPointer<KisAnimationCycle> cycle) {
        cycles.insert(cycle->time(), cycle);
140 141 142 143 144

        Q_FOREACH(QWeakPointer<KisRepeatFrame> repeatWP, cycle->repeats()) {
            KisKeyframeBaseSP repeat = repeatWP.toStrongRef();
            if (repeat) add(repeat);
        }
145 146 147 148 149
    }

    void removeCycle(QSharedPointer<KisAnimationCycle> cycle) {
        KIS_SAFE_ASSERT_RECOVER_NOOP(cycle->repeats().isEmpty());
        cycles.remove(cycle->time());
150
    }
151 152
};

153
KisKeyframeChannel::KisKeyframeChannel(const KoID &id, KisDefaultBoundsBaseSP defaultBounds)
154
    : m_d(new Private)
155
{
156
    m_d->id = id;
157
    m_d->node = 0;
158
    m_d->defaultBounds = defaultBounds;
159 160
}

161
KisKeyframeChannel::KisKeyframeChannel(const KisKeyframeChannel &rhs, KisNode *newParentNode)
162 163 164
    : m_d(new Private(*rhs.m_d, newParentNode))
{
    KIS_ASSERT_RECOVER_NOOP(&rhs != this);
165 166

    Q_FOREACH(KisKeyframeSP keyframe, rhs.m_d->keys) {
167
        const KisKeyframeSP clone = keyframe->cloneFor(this);
168
            m_d->add(clone);
169 170 171
    }

    Q_FOREACH(const QSharedPointer<KisAnimationCycle> rhsCycle, rhs.m_d->cycles) {
172 173 174 175 176 177 178 179 180 181 182 183 184
        KisKeyframeSP firstFrame = keyframeAt(rhsCycle->firstSourceKeyframe()->time());
        KisKeyframeSP lastFrame = keyframeAt(rhsCycle->lastSourceKeyframe()->time());

        QSharedPointer<KisAnimationCycle> cycle = toQShared(new KisAnimationCycle(this, firstFrame, lastFrame));
        m_d->addCycle(cycle);

        Q_FOREACH(auto rhsRepeatWP, rhsCycle->repeats()) {
            const QSharedPointer<KisRepeatFrame> rhsRepeat = rhsRepeatWP.toStrongRef();
            if (rhsRepeat) {
                m_d->add(toQShared(new KisRepeatFrame(this, rhsRepeat->time(), cycle)));
            }
        }

185
    }
186 187
}

Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
188
KisKeyframeChannel::~KisKeyframeChannel()
189
{}
Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
190

191 192 193 194 195
QString KisKeyframeChannel::id() const
{
    return m_d->id.id();
}

Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
196 197
QString KisKeyframeChannel::name() const
{
198
    return m_d->id.name();
Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
199 200
}

201 202 203 204 205
void KisKeyframeChannel::setNode(KisNodeWSP node)
{
    m_d->node = node;
}

206
KisNodeWSP KisKeyframeChannel::node() const
Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
207
{
208
    return m_d->node;
Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
209 210
}

211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
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;
}

226 227 228 229 230 231 232
#define LAZY_INITIALIZE_PARENT_COMMAND(cmd)       \
    QScopedPointer<KUndo2Command> __tempCommand;  \
    if (!parentCommand) {                         \
        __tempCommand.reset(new KUndo2Command()); \
        cmd = __tempCommand.data();               \
    }

233
KisKeyframeSP KisKeyframeChannel::addKeyframe(int time, KUndo2Command *parentCommand)
Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
234
{
235
    LAZY_INITIALIZE_PARENT_COMMAND(parentCommand);
236
    return insertKeyframe(time, KisKeyframeSP(), parentCommand);
237 238
}

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
KisKeyframeBaseSP KisKeyframeChannel::copyItem(const KisKeyframeBaseSP item, int newTime, KUndo2Command *parentCommand)
{
    LAZY_INITIALIZE_PARENT_COMMAND(parentCommand);
    return insertKeyframe(newTime, item, parentCommand);
}

KisKeyframeSP KisKeyframeChannel::copyAsKeyframe(const KisKeyframeBaseSP item, int originalTime, int newTime, KUndo2Command *parentCommand)
{
    LAZY_INITIALIZE_PARENT_COMMAND(parentCommand);

    KisKeyframeSP keyframe = item->getOriginalKeyframeFor(originalTime);
    return insertKeyframe(newTime, keyframe, parentCommand);
}

KisKeyframeSP KisKeyframeChannel::linkKeyframe(const KisKeyframeBaseSP, int, KUndo2Command*) {
254 255 256
    return KisKeyframeSP();
}

257
KisKeyframeSP KisKeyframeChannel::insertKeyframe(int time, const KisKeyframeBaseSP copySrc, KUndo2Command *parentCommand)
258
{
259 260 261
    KisKeyframeBaseSP oldItem = itemAt(time);
    if (oldItem) {
        deleteKeyframeImpl(oldItem, parentCommand, false);
262
    }
263

264
    Q_ASSERT(parentCommand);
265 266
    KisKeyframeSP sourceKeyframe = copySrc ? copySrc->getOriginalKeyframeFor(copySrc->time()) : KisKeyframeSP();
    KisKeyframeSP keyframe = createKeyframe(time, sourceKeyframe, parentCommand);
267 268 269 270 271

    KUndo2Command *cmd = new KisReplaceKeyframeCommand(this, keyframe->time(), keyframe, parentCommand);
    cmd->redo();

    return keyframe;
272
}
Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
273

274
bool KisKeyframeChannel::deleteKeyframe(KisKeyframeBaseSP keyframe, KUndo2Command *parentCommand)
275 276 277 278
{
    return deleteKeyframeImpl(keyframe, parentCommand, true);
}

279
bool KisKeyframeChannel::moveKeyframe(KisKeyframeBaseSP keyframe, int newTime, KUndo2Command *parentCommand)
280 281 282 283 284
{
    LAZY_INITIALIZE_PARENT_COMMAND(parentCommand);

    if (newTime == keyframe->time()) return false;

285
    KisKeyframeBaseSP other = itemAt(newTime);
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
    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;
}
301

302 303 304 305 306 307
bool KisKeyframeChannel::swapFrames(int lhsTime, int rhsTime, KUndo2Command *parentCommand)
{
    LAZY_INITIALIZE_PARENT_COMMAND(parentCommand);

    if (lhsTime == rhsTime) return false;

308 309
    KisKeyframeBaseSP lhsFrame = itemAt(lhsTime);
    KisKeyframeBaseSP rhsFrame = itemAt(rhsTime);
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324

    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;
}

325
bool KisKeyframeChannel::deleteKeyframeImpl(KisKeyframeBaseSP item, KUndo2Command *parentCommand, bool recreate)
326
{
327 328
    LAZY_INITIALIZE_PARENT_COMMAND(parentCommand);

329
    Q_ASSERT(parentCommand);
330

331
    KUndo2Command *cmd = new KisReplaceKeyframeCommand(this, item->time(), KisKeyframeSP(), parentCommand);
332
    cmd->redo();
333

334 335 336 337 338 339 340
    KisKeyframeSP keyframe = item.dynamicCast<KisKeyframe>();
    if (keyframe) {
        destroyKeyframe(keyframe, parentCommand);

        if (recreate && keyframe->time() == 0) {
            addKeyframe(0, parentCommand);
        }
341 342
    }

343
    return true;
344 345
}

346
void KisKeyframeChannel::moveKeyframeImpl(KisKeyframeBaseSP keyframe, int newTime)
347
{
348
    KIS_ASSERT_RECOVER_RETURN(keyframe);
349
    KIS_ASSERT_RECOVER_RETURN(!itemAt(newTime));
350

351
    KisFrameSet rangeSrc = affectedFrames(keyframe->time());
352
    QRect rectSrc = keyframe->affectedRect();
353

354
    emit sigKeyframeAboutToBeMoved(keyframe, newTime);
355

356
    int oldTime = keyframe->time();
357
    m_d->moveKeyframe(keyframe, newTime);
358
    keyframe->setTime(newTime);
Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
359

360
    emit sigKeyframeMoved(keyframe, oldTime);
361

362
    KisFrameSet rangeDst = affectedFrames(keyframe->time());
363
    QRect rectDst = keyframe->affectedRect();
364 365 366

    requestUpdate(rangeSrc, rectSrc);
    requestUpdate(rangeDst, rectDst);
367 368
}

369
void KisKeyframeChannel::swapKeyframesImpl(KisKeyframeBaseSP lhsKeyframe, KisKeyframeBaseSP rhsKeyframe)
370 371 372 373
{
    KIS_ASSERT_RECOVER_RETURN(lhsKeyframe);
    KIS_ASSERT_RECOVER_RETURN(rhsKeyframe);

374 375
    KisFrameSet rangeLhs = affectedFrames(lhsKeyframe->time());
    KisFrameSet rangeRhs = affectedFrames(rhsKeyframe->time());
376

377 378
    const QRect rectLhsSrc = lhsKeyframe->affectedRect();
    const QRect rectRhsSrc = rhsKeyframe->affectedRect();
379 380 381 382 383 384 385

    const int lhsTime = lhsKeyframe->time();
    const int rhsTime = rhsKeyframe->time();

    emit sigKeyframeAboutToBeMoved(lhsKeyframe, rhsTime);
    emit sigKeyframeAboutToBeMoved(rhsKeyframe, lhsTime);

386 387
    m_d->remove(lhsKeyframe);
    m_d->remove(rhsKeyframe);
388 389 390 391

    rhsKeyframe->setTime(lhsTime);
    lhsKeyframe->setTime(rhsTime);

392 393
    m_d->add(lhsKeyframe);
    m_d->add(rhsKeyframe);
394 395 396 397

    emit sigKeyframeMoved(lhsKeyframe, lhsTime);
    emit sigKeyframeMoved(rhsKeyframe, rhsTime);

398 399
    const QRect rectLhsDst = lhsKeyframe->affectedRect();
    const QRect rectRhsDst = rhsKeyframe->affectedRect();
400 401 402 403 404

    requestUpdate(rangeLhs, rectLhsSrc | rectRhsDst);
    requestUpdate(rangeRhs, rectRhsSrc | rectLhsDst);
}

405
KisKeyframeBaseSP KisKeyframeChannel::replaceKeyframeAt(int time, KisKeyframeBaseSP newKeyframe)
406
{
407
    Q_ASSERT(newKeyframe.isNull() || time == newKeyframe->time());
408

409
    KisKeyframeBaseSP existingKeyframe = itemAt(time);
410 411 412
    if (!existingKeyframe.isNull()) {
        removeKeyframeLogical(existingKeyframe);
    }
413

414 415
    if (!newKeyframe.isNull()) {
        insertKeyframeLogical(newKeyframe);
416
    }
417

418 419
    return existingKeyframe;
}
420

421
void KisKeyframeChannel::insertKeyframeLogical(KisKeyframeBaseSP keyframe)
422 423
{
    const int time = keyframe->time();
424

425
    emit sigKeyframeAboutToBeAdded(keyframe);
426
    m_d->add(keyframe);
427
    emit sigKeyframeAdded(keyframe);
428

429
    QRect rect = keyframe->affectedRect();
430
    KisFrameSet range = affectedFrames(time);
431
    requestUpdate(range, rect);
432 433
}

434
void KisKeyframeChannel::removeKeyframeLogical(KisKeyframeBaseSP keyframe)
435
{
436
    QRect rect = keyframe->affectedRect();
437
    KisFrameSet range = affectedFrames(keyframe->time());
438

439
    emit sigKeyframeAboutToBeRemoved(keyframe);
440
    m_d->remove(keyframe);
441
    emit sigKeyframeRemoved(keyframe);
442 443

    requestUpdate(range, rect);
444 445
}

446
KisKeyframeSP KisKeyframeChannel::keyframeAt(int time) const
Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
447
{
448
    return m_d->keys.value(time);
449
}
450

451
KisKeyframeSP KisKeyframeChannel::activeKeyframeAt(int time) const
452
{
453
    KeyframesMap::const_iterator i = KisCollectionUtils::lastBeforeOrAt(m_d->keys, time);
454 455 456 457 458
    if (i != m_d->keys.constEnd()) {
        return i.value();
    }

    return KisKeyframeSP();
459 460
}

461 462
KisKeyframeSP KisKeyframeChannel::visibleKeyframeAt(int time) const
{
463 464
    const QSharedPointer<KisRepeatFrame> repeat = activeRepeatAt(time);
    return repeat ? repeat->getOriginalKeyframeFor(time) : activeKeyframeAt(time);
465 466
}

467 468 469 470 471
KisKeyframeSP KisKeyframeChannel::currentlyActiveKeyframe() const
{
    return activeKeyframeAt(currentTime());
}

472 473
KisKeyframeSP KisKeyframeChannel::firstKeyframe() const
{
474
    if (m_d->keys.isEmpty()) return KisKeyframeSP();
475
    return m_d->keys.first();
476 477
}

478
KisKeyframeSP KisKeyframeChannel::nextKeyframe(KisKeyframeSP keyframe) const
479
{
480
    return nextKeyframe(keyframe->time());
481 482
}

483
KisKeyframeSP KisKeyframeChannel::nextKeyframe(int time) const
484
{
485
    KeyframesMap::const_iterator i = KisCollectionUtils::firstAfter(m_d->keys, time);
486
    if (i == m_d->keys.constEnd()) return KisKeyframeSP(0);
487 488 489
    return i.value();
}

490
KisKeyframeSP KisKeyframeChannel::previousKeyframe(KisKeyframeSP keyframe) const
491
{
492
    return previousKeyframe(keyframe->time());
493 494
}

495
KisKeyframeSP KisKeyframeChannel::previousKeyframe(int time) const
496
{
497
    KeyframesMap::const_iterator i = KisCollectionUtils::lastBefore(m_d->keys, time);
498
    if (i == m_d->keys.constEnd()) return KisKeyframeSP(0);
499
    return i.value();
Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
500 501
}

502 503 504 505 506 507 508
KisKeyframeSP KisKeyframeChannel::lastKeyframe() const
{
    if (m_d->keys.isEmpty()) return KisKeyframeSP(0);

    return (m_d->keys.end()-1).value();
}

509
KisKeyframeBaseSP KisKeyframeChannel::itemAt(int time) const
510
{
511 512 513 514 515 516 517
    const KisKeyframeSP keyframe = keyframeAt(time);
    if (keyframe) return keyframe;

    const QSharedPointer<KisRepeatFrame> repeat = activeRepeatAt(time);
    if (repeat && time == repeat->time()) return repeat;

    return KisKeyframeBaseSP();
518 519
}

520
KisKeyframeBaseSP KisKeyframeChannel::activeItemAt(int time) const
521
{
522 523
    const KisKeyframeSP keyframe = activeKeyframeAt(time);
    if (keyframe) return keyframe;
524

525 526
    return activeRepeatAt(time);
}
527

528 529
KisKeyframeBaseSP KisKeyframeChannel::nextItem(const KisKeyframeBase &item) const
{
530
    const KisKeyframeSP keyframe = nextKeyframe(item.time());
531

532
    auto repeatIter = KisCollectionUtils::firstAfter(m_d->repeats, item.time());
533
    const auto repeat = (repeatIter != m_d->repeats.constEnd()) ? repeatIter.value() : QSharedPointer<KisRepeatFrame>();
534

535 536 537 538 539 540 541
    if (keyframe && (!repeat || repeat->time() > keyframe->time())) return keyframe;

    return repeat;
}

KisKeyframeBaseSP KisKeyframeChannel::previousItem(const KisKeyframeBase &item) const
{
542
    const KisKeyframeSP keyframe = previousKeyframe(item.time());
543

544
    auto repeatIter = KisCollectionUtils::lastBefore(m_d->repeats, item.time());
545 546 547 548 549 550 551 552 553 554 555
    const auto repeat = (repeatIter != m_d->repeats.constEnd()) ? repeatIter.value() : QSharedPointer<KisRepeatFrame>();
    if (keyframe && (!repeat || repeat->time() > keyframe->time())) return keyframe;

    return repeat;
}

KisVisibleKeyframeIterator KisKeyframeChannel::visibleKeyframesFrom(int time) const
{
    return KisVisibleKeyframeIterator(visibleKeyframeAt(time));
}

556 557 558 559 560
QList<QSharedPointer<KisAnimationCycle>> KisKeyframeChannel::cycles() const
{
    return m_d->cycles.values();
}

561 562 563 564 565 566 567
KisTimeSpan KisKeyframeChannel::cycledRangeAt(int time) const
{
    QSharedPointer<KisRepeatFrame> repeat = activeRepeatAt(time);
    if (repeat) return repeat->cycle()->originalRange();

    QSharedPointer<KisAnimationCycle> cycle = cycleAt(time);
    if (cycle) return cycle->originalRange();
568 569 570 571 572 573

    return KisTimeSpan();
}

QSharedPointer<KisAnimationCycle> KisKeyframeChannel::cycleAt(int time) const
{
574 575
    if (m_d->cycles.isEmpty()) return QSharedPointer<KisAnimationCycle>();

576
    const auto it = KisCollectionUtils::lastBeforeOrAt(m_d->cycles, time);
577 578 579 580
    if (it == m_d->cycles.constEnd()) return QSharedPointer<KisAnimationCycle>();

    const KisKeyframeBaseSP next = nextItem(*it.value()->lastSourceKeyframe());
    if (next && next->time() <= time) return QSharedPointer<KisAnimationCycle>();
581

582
    return it.value();
583 584
};

585 586
QSharedPointer<KisRepeatFrame> KisKeyframeChannel::activeRepeatAt(int time) const
{
587
    const auto repeat = KisCollectionUtils::lastBeforeOrAt(m_d->repeats, time);
588 589 590 591 592 593 594 595
    if (repeat == m_d->repeats.constEnd()) return QSharedPointer<KisRepeatFrame>();

    const KisKeyframeSP lastKeyframe = activeKeyframeAt(time);
    if (lastKeyframe && lastKeyframe->time() > repeat.value()->time()) return QSharedPointer<KisRepeatFrame>();

    return repeat.value();
}

596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
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;
    }
}

611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
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;
}

626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
QSet<int> KisKeyframeChannel::allKeyframeIds() const
{
    QSet<int> 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;
}

641
KisFrameSet KisKeyframeChannel::affectedFrames(int time) const
642
{
643
    if (m_d->keys.isEmpty()) return KisFrameSet::infiniteFrom(0);
644

645
    KeyframesMap::const_iterator active = KisCollectionUtils::lastBeforeOrAt(m_d->keys, time);
646
    KeyframesMap::const_iterator next;
647 648 649

    int from;

650 651
    if (active == m_d->keys.constEnd()) {
        // No active keyframe, ie. time is before the first keyframe
652
        from = 0;
653
        next = m_d->keys.constBegin();
654 655
    } else {
        from = active.key();
656
        next = active + 1;
657 658
    }

659 660
    KisFrameSet frames;

661 662 663 664 665 666 667
    QSharedPointer<KisRepeatFrame> repeat = activeRepeatAt(time);

    if (repeat) {
        const KisKeyframeSP original = repeat->getOriginalKeyframeFor(time);
        return affectedFrames(original->time());
    }

668
    QSharedPointer<KisAnimationCycle> cycle = cycleAt(time);
669
    if (cycle) {
670
        KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(active != m_d->keys.constEnd() && active.value(), KisFrameSet());
671
        frames = cycle->instancesWithin(active.value(), KisTimeSpan());
672 673
    }

674
    if (next == m_d->keys.constEnd()) {
675
        frames |= KisFrameSet::infiniteFrom(from);
676
    } else {
677
        frames |= KisFrameSet::between(from, next.key() - 1);
678
    }
679 680

    return frames;
681 682
}

683
KisFrameSet KisKeyframeChannel::identicalFrames(int time, const KisTimeSpan range) const
684
{
685 686 687 688 689
    const QSharedPointer<KisRepeatFrame> repeat = activeRepeatAt(time);
    if (repeat) {
        const KisKeyframeSP original = repeat->getOriginalKeyframeFor(time);
        return identicalFrames(original->time(), range);
    }
690

691
    KeyframesMap::const_iterator active = KisCollectionUtils::lastBeforeOrAt(m_d->keys, time);
692 693 694 695

    const QSharedPointer<KisAnimationCycle> cycle = cycleAt(time);
    if (cycle) {
        return cycle->instancesWithin(active.value(), range);
696 697
    }

698 699
    if (active != m_d->keys.constEnd() && (active+1) != m_d->keys.constEnd()) {
        if (active->data()->interpolationMode() != KisKeyframe::Constant) {
700
            return KisFrameSet::between(time, time);
701 702 703 704 705 706
        }
    }

    return affectedFrames(time);
}

707 708 709 710 711 712 713 714 715 716 717 718
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);
}

719
QDomElement KisKeyframeChannel::toXML(QDomDocument doc, const QString &layerFilename)
720 721 722 723 724
{
    QDomElement channelElement = doc.createElement("channel");

    channelElement.setAttribute("name", id());

725
    Q_FOREACH (KisKeyframeSP keyframe, m_d->keys.values()) {
726 727
        QDomElement keyframeElement = doc.createElement("keyframe");
        keyframeElement.setAttribute("time", keyframe->time());
728
        keyframeElement.setAttribute("color-label", keyframe->colorLabel());
729

730
        saveKeyframe(keyframe, keyframeElement, layerFilename);
731

732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
        channelElement.appendChild(keyframeElement);
    }

    Q_FOREACH (const QSharedPointer<KisAnimationCycle> cycle, m_d->cycles.values()) {
        QDomElement cycleElement = doc.createElement("cycle");
        cycleElement.setAttribute("firstKeyframe", cycle->firstSourceKeyframe()->time());
        cycleElement.setAttribute("lastKeyframe", cycle->lastSourceKeyframe()->time());

        Q_FOREACH (auto repeatWP, cycle->repeats()) {
            const QSharedPointer<KisRepeatFrame> repeat = repeatWP.toStrongRef();
            if (!repeat) continue;

            QDomElement repeatElement = doc.createElement("repeat");
            repeatElement.setAttribute("time", repeat->time());
            cycleElement.appendChild(repeatElement);
747
        }
748

749
        channelElement.appendChild(cycleElement);
750 751 752 753 754
    }

    return channelElement;
}

755
void KisKeyframeChannel::loadXML(const QDomElement &channelNode)
Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
756
{
757 758 759 760 761 762
    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;
763
            keyframe = loadKeyframe(childNode);
764 765 766 767 768 769

            KIS_SAFE_ASSERT_RECOVER(keyframe) { continue; }

            if (childNode.hasAttribute("color-label")) {
                keyframe->setColorLabel(childNode.attribute("color-label").toUInt());
            }
770

771
            m_d->add(keyframe);
772 773
        }
    }
774

775 776 777 778 779
    for (QDomElement childNode = channelNode.firstChildElement(); !childNode.isNull(); childNode = childNode.nextSiblingElement()) {
        if (childNode.nodeName().toUpper() == "CYCLE") {
            QSharedPointer<KisAnimationCycle> cycle = loadCycle(childNode);
            if (cycle) {
                m_d->addCycle(cycle);
780
            }
781
        }
782 783
    }
}
784

785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
QSharedPointer<KisAnimationCycle> KisKeyframeChannel::loadCycle(const QDomElement &cycleElement)
{
    const int firstKeyframeTime = cycleElement.attribute("firstKeyframe", "-1").toInt();
    const int lastKeyframeTime = cycleElement.attribute("lastKeyframe", "-1").toInt();

    if (firstKeyframeTime < 0 || lastKeyframeTime <= firstKeyframeTime) {
        qWarning() << "Invalid cycle range: " << firstKeyframeTime << "to" << lastKeyframeTime;
        return nullptr;
    }

    const KisKeyframeSP firstKeyframe = keyframeAt(firstKeyframeTime);
    const KisKeyframeSP lastKeyframe = keyframeAt(lastKeyframeTime);

    if (!firstKeyframe || !lastKeyframe) {
        qWarning() << "Could not find defining keyframes for cycle " << firstKeyframeTime << "to" << lastKeyframeTime;
        return nullptr;
    }

    QSharedPointer<KisAnimationCycle> cycle = toQShared(new KisAnimationCycle(this, firstKeyframe, lastKeyframe));

    for (QDomElement grandChildNode = cycleElement.firstChildElement(); !grandChildNode.isNull(); grandChildNode = grandChildNode.nextSiblingElement()) {
        if (grandChildNode.nodeName().toUpper() == "REPEAT") {
            const int time = grandChildNode.attribute("time").toInt();
            const QSharedPointer<KisRepeatFrame> repeat = toQShared(new KisRepeatFrame(this, time, cycle));
            m_d->add(repeat);
        }
    }

    return cycle;
}

816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
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;
}


855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
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);

872
    KUndo2Command *cmd = new KisReplaceKeyframeCommand(this, newKeyframe->time(), newKeyframe, parentCommand);
873 874 875 876 877
    cmd->redo();

    return newKeyframe;
}

878
KisDefineCycleCommand * KisKeyframeChannel::createCycle(KisKeyframeSP firstKeyframe, KisKeyframeSP lastKeyframe, KUndo2Command *parentCommand)
879
{
880
    const QSharedPointer<KisAnimationCycle> cycle = toQShared(new KisAnimationCycle(this, firstKeyframe, lastKeyframe));
881
    return new KisDefineCycleCommand(nullptr, cycle, parentCommand);
882 883 884 885
}

void KisKeyframeChannel::addCycle(QSharedPointer<KisAnimationCycle> cycle)
{
886
    m_d->addCycle(cycle);
887 888 889 890
}

KUndo2Command* KisKeyframeChannel::deleteCycle(QSharedPointer<KisAnimationCycle> cycle, KUndo2Command *parentCommand)
{
891
    KisDefineCycleCommand *defineCycleCommand = new KisDefineCycleCommand(cycle, nullptr, parentCommand);
892 893 894 895 896 897 898

    // Remove repeats of the cycle
    Q_FOREACH(QWeakPointer<KisRepeatFrame> repeatWP, cycle->repeats()) {
        auto repeat = repeatWP.toStrongRef();
        if (repeat) {
            deleteKeyframe(repeat);
        }
899 900
    }

901
    return defineCycleCommand;
902 903 904 905
}

void KisKeyframeChannel::removeCycle(QSharedPointer<KisAnimationCycle> cycle)
{
906
    m_d->removeCycle(cycle);
907 908
}

909
QSharedPointer<KisRepeatFrame> KisKeyframeChannel::addRepeat(QSharedPointer<KisAnimationCycle> cycle, int time, KUndo2Command *parentCommand)
910 911 912 913 914 915
{
    const QSharedPointer<KisRepeatFrame> repeatFrame = toQShared(new KisRepeatFrame(this, time, cycle));
    KUndo2Command *cmd = new KisReplaceKeyframeCommand(this, time, repeatFrame, parentCommand);
    cmd->redo();

    return repeatFrame;
916 917
}

918
void KisKeyframeChannel::requestUpdate(const KisFrameSet &range, const QRect &rect)
919
{
Dmitry Kazakov's avatar
Dmitry Kazakov committed
920 921
    if (m_d->node) {
        m_d->node->invalidateFrames(range, rect);
922 923 924 925 926

        int currentTime = m_d->defaultBounds->currentTime();
        if (range.contains(currentTime)) {
            m_d->node->setDirty(rect);
        }
Dmitry Kazakov's avatar
Dmitry Kazakov committed
927
    }
928
}
929

930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
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)++;
        }
    }
}

957 958 959 960
int KisKeyframeChannel::currentTime() const
{
    return m_d->defaultBounds->currentTime();
}
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984

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);
}
985 986 987 988 989 990 991 992 993 994 995

KisVisibleKeyframeIterator::KisVisibleKeyframeIterator() = default;

KisVisibleKeyframeIterator::KisVisibleKeyframeIterator(KisKeyframeSP keyframe)
    : m_channel(keyframe->channel())
    , m_keyframe(keyframe)
    , m_time(keyframe->time())
{}

KisVisibleKeyframeIterator& KisVisibleKeyframeIterator::operator--()
{
996
    const QSharedPointer<KisRepeatFrame> repeat = m_channel->activeRepeatAt(m_time);
997 998 999 1000 1001 1002 1003 1004 1005

    if (repeat) {
        const int time = repeat->previousVisibleFrame(m_time);
        if (time >= 0) {
            m_time = time;
            return *this;
        }
    }

1006
    m_keyframe = m_channel->previousKeyframe(m_keyframe->time());
1007 1008 1009 1010 1011 1012 1013 1014
    if (!m_keyframe) return invalidate();

    m_time = m_keyframe->time();
    return *this;
}

KisVisibleKeyframeIterator& KisVisibleKeyframeIterator::operator++()
{
1015
    const QSharedPointer<KisRepeatFrame> repeat = m_channel->activeRepeatAt(m_time);
1016 1017 1018 1019 1020 1021 1022 1023 1024

    if (repeat) {
        const int time = repeat->nextVisibleFrame(m_time);
        if (time >= 0) {
            m_time = time;
            return *this;
        }
    }

1025
    m_keyframe = m_channel->nextKeyframe(m_keyframe->time());
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
    if (!m_keyframe) return invalidate();

    m_time = m_keyframe->time();

    return *this;
};

KisKeyframeSP KisVisibleKeyframeIterator::operator*() const
{
    const KisRepeatFrame *repeat = dynamic_cast<KisRepeatFrame*>(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;
}