keyframemodellist.cpp 14.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/***************************************************************************
 *   Copyright (C) 2017 by Nicolas Carion                                  *
 *   This file is part of Kdenlive. See www.kdenlive.org.                  *
 *                                                                         *
 *   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) version 3 or any later version accepted by the       *
 *   membership of KDE e.V. (or its successor approved  by the membership  *
 *   of KDE e.V.), which shall act as a proxy defined in Section 14 of     *
 *   version 3 of the license.                                             *
 *                                                                         *
 *   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, see <http://www.gnu.org/licenses/>. *
 ***************************************************************************/

#include "keyframemodellist.hpp"
23
#include "assets/model/assetcommand.hpp"
24
#include "assets/model/assetparametermodel.hpp"
25
#include "core.h"
Nicolas Carion's avatar
Nicolas Carion committed
26
#include "doc/docundostack.hpp"
27
#include "keyframemodel.hpp"
Nicolas Carion's avatar
Nicolas Carion committed
28 29
#include "klocalizedstring.h"
#include "macros.hpp"
30
#include <kdenlivesettings.h>
31 32 33

#include <QDebug>

34
KeyframeModelList::KeyframeModelList(std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack)
35 36 37 38
    : m_model(model)
    , m_undoStack(undo_stack)
    , m_lock(QReadWriteLock::Recursive)
{
Nicolas Carion's avatar
Nicolas Carion committed
39
    qDebug() << "Construct keyframemodellist. Checking model:" << m_model.expired();
40
    addParameter(index);
41 42 43
    connect(m_parameters.begin()->second.get(), &KeyframeModel::modelChanged, this, &KeyframeModelList::modelChanged);
}

44 45 46 47 48 49 50 51
ObjectId KeyframeModelList::getOwnerId() const
{
    if (auto ptr = m_model.lock()) {
        return ptr->getOwnerId();
    }
    return ObjectId();
}

52
void KeyframeModelList::addParameter(const QModelIndex &index)
53
{
Nicolas Carion's avatar
Nicolas Carion committed
54
    std::shared_ptr<KeyframeModel> parameter(new KeyframeModel(m_model, index, m_undoStack));
55 56 57
    m_parameters.insert({index, std::move(parameter)});
}

Nicolas Carion's avatar
Nicolas Carion committed
58
bool KeyframeModelList::applyOperation(const std::function<bool(std::shared_ptr<KeyframeModel>, Fun &, Fun &)> &op, const QString &undoString)
59 60 61 62 63 64 65
{
    QWriteLocker locker(&m_lock);
    Q_ASSERT(m_parameters.size() > 0);
    Fun undo = []() { return true; };
    Fun redo = []() { return true; };

    bool res = true;
Nicolas Carion's avatar
Nicolas Carion committed
66
    for (const auto &param : m_parameters) {
67 68 69 70 71 72 73 74 75 76 77 78
        res = op(param.second, undo, redo);
        if (!res) {
            bool undone = undo();
            Q_ASSERT(undone);
            return res;
        }
    }
    if (res && !undoString.isEmpty()) {
        PUSH_UNDO(undo, redo, undoString);
    }
    return res;
}
79

80 81 82 83 84
bool KeyframeModelList::addKeyframe(GenTime pos, KeyframeType type)
{
    QWriteLocker locker(&m_lock);
    Q_ASSERT(m_parameters.size() > 0);
    bool update = (m_parameters.begin()->second->hasKeyframe(pos) > 0);
Nicolas Carion's avatar
Nicolas Carion committed
85
    auto op = [pos, type](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) {
86
        QVariant value = param->getInterpolatedValue(pos);
87
        return param->addKeyframe(pos, type, value, true, undo, redo);
88 89 90 91
    };
    return applyOperation(op, update ? i18n("Change keyframe type") : i18n("Add keyframe"));
}

92 93 94 95 96 97
bool KeyframeModelList::addKeyframe(int frame, double val)
{
    QWriteLocker locker(&m_lock);
    GenTime pos(frame, pCore->getCurrentFps());
    Q_ASSERT(m_parameters.size() > 0);
    bool update = (m_parameters.begin()->second->hasKeyframe(pos) > 0);
98 99 100 101 102 103 104 105 106 107
    bool isRectParam = false;
    if (m_inTimelineIndex.isValid()) {
        if (auto ptr = m_model.lock()) {
            ParamType tp = ptr->data(m_inTimelineIndex, AssetParameterModel::TypeRole).value<ParamType>();
            if (tp == ParamType::AnimatedRect) {
                isRectParam = true;
            }
        }
    }
    auto op = [this, pos, frame, val, isRectParam](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) {
108
        QVariant value;
109 110 111 112 113 114 115 116 117 118 119 120
        if (m_inTimelineIndex.isValid()) {
            if (m_parameters.at(m_inTimelineIndex) == param) {
                if (isRectParam) {
                    value = param->getInterpolatedValue(pos);
                    value = param->updateInterpolated(value, val);
                } else {
                    value = param->getNormalizedValue(val);
                }
            } else {
                value = param->getInterpolatedValue(pos);
            }
        } else if (m_parameters.begin()->second == param) {
121 122 123 124
            value = param->getNormalizedValue(val);
        } else {
            value = param->getInterpolatedValue(pos);
        }
125
        return param->addKeyframe(pos, (KeyframeType)KdenliveSettings::defaultkeyframeinterp(), value, true, undo, redo);
126 127 128 129
    };
    return applyOperation(op, update ? i18n("Change keyframe type") : i18n("Add keyframe"));
}

130 131 132 133
bool KeyframeModelList::removeKeyframe(GenTime pos)
{
    QWriteLocker locker(&m_lock);
    Q_ASSERT(m_parameters.size() > 0);
Nicolas Carion's avatar
Nicolas Carion committed
134
    auto op = [pos](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) { return param->removeKeyframe(pos, undo, redo); };
135 136 137 138 139 140 141
    return applyOperation(op, i18n("Delete keyframe"));
}

bool KeyframeModelList::removeAllKeyframes()
{
    QWriteLocker locker(&m_lock);
    Q_ASSERT(m_parameters.size() > 0);
Nicolas Carion's avatar
Nicolas Carion committed
142
    auto op = [](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) { return param->removeAllKeyframes(undo, redo); };
143 144 145
    return applyOperation(op, i18n("Delete all keyframes"));
}

146 147 148 149 150 151 152 153
bool KeyframeModelList::removeNextKeyframes(GenTime pos)
{
    QWriteLocker locker(&m_lock);
    Q_ASSERT(m_parameters.size() > 0);
    auto op = [pos](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) { return param->removeNextKeyframes(pos, undo, redo); };
    return applyOperation(op, i18n("Delete keyframes"));
}

154 155 156 157
bool KeyframeModelList::moveKeyframe(GenTime oldPos, GenTime pos, bool logUndo)
{
    QWriteLocker locker(&m_lock);
    Q_ASSERT(m_parameters.size() > 0);
158
    auto op = [oldPos, pos](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) { return param->moveKeyframe(oldPos, pos, QVariant(), undo, redo); };
159 160 161
    return applyOperation(op, logUndo ? i18n("Move keyframe") : QString());
}

162
bool KeyframeModelList::updateKeyframe(GenTime oldPos, GenTime pos, QVariant normalizedVal, bool logUndo)
163 164 165
{
    QWriteLocker locker(&m_lock);
    Q_ASSERT(m_parameters.size() > 0);
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    bool isRectParam = false;
    if (m_inTimelineIndex.isValid()) {
        if (auto ptr = m_model.lock()) {
            ParamType tp = ptr->data(m_inTimelineIndex, AssetParameterModel::TypeRole).value<ParamType>();
            if (tp == ParamType::AnimatedRect) {
                isRectParam = true;
            }
        }
    }
    auto op = [this, oldPos, pos, normalizedVal, isRectParam](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) {
        QVariant value;
        if (m_inTimelineIndex.isValid()) {
            if (m_parameters.at(m_inTimelineIndex) == param) {
                if (isRectParam) {
                    if (normalizedVal.isValid()) {
                        value = param->getInterpolatedValue(oldPos);
                        value = param->updateInterpolated(value, normalizedVal.toDouble());
                    }
                } else {
                    value = normalizedVal;
                }
            }
        } else if (m_parameters.begin()->second == param) {
189 190 191 192 193 194 195
            value = normalizedVal;
        }
        return param->moveKeyframe(oldPos, pos, value, undo, redo);
    };
    return applyOperation(op, logUndo ? i18n("Move keyframe") : QString());
}

196
bool KeyframeModelList::updateKeyframe(GenTime pos, QVariant value, const QPersistentModelIndex &index)
197
{
198 199 200 201 202 203 204 205 206 207
    if (singleKeyframe()) {
        bool ok = false;
        Keyframe kf = m_parameters.begin()->second->getNextKeyframe(GenTime(-1), &ok);
        pos = kf.first;
    }
    if (auto ptr = m_model.lock()) {
        AssetKeyframeCommand *command = new AssetKeyframeCommand(ptr, index, value, pos);
        pCore->pushUndo(command);
    }
    return true;
208
    QWriteLocker locker(&m_lock);
209 210 211
    Q_ASSERT(m_parameters.count(index) > 0);
    Fun undo = []() { return true; };
    Fun redo = []() { return true; };
212 213 214 215 216
    if (singleKeyframe()) {
        bool ok = false;
        Keyframe kf = m_parameters.begin()->second->getNextKeyframe(GenTime(-1), &ok);
        pos = kf.first;
    }
217 218 219 220 221
    bool res = m_parameters.at(index)->updateKeyframe(pos, value, undo, redo);
    if (res) {
        PUSH_UNDO(undo, redo, i18n("Update keyframe"));
    }
    return res;
222 223
}

224 225 226 227 228 229 230 231 232 233 234
bool KeyframeModelList::updateKeyframeType(GenTime pos, int type, const QPersistentModelIndex &index)
{
    QWriteLocker locker(&m_lock);
    Q_ASSERT(m_parameters.count(index) > 0);
    Fun undo = []() { return true; };
    Fun redo = []() { return true; };
    if (singleKeyframe()) {
        bool ok = false;
        Keyframe kf = m_parameters.begin()->second->getNextKeyframe(GenTime(-1), &ok);
        pos = kf.first;
    }
235 236 237 238 239
    // Update kf type in all parameters
    bool res = true;
    for (const auto &param : m_parameters) {
        res = res && param.second->updateKeyframeType(pos, type, undo, redo);
    }
240 241 242 243 244
    if (res) {
        PUSH_UNDO(undo, redo, i18n("Update keyframe"));
    }
    return res;
}
245

246 247 248 249 250 251 252 253 254 255 256 257 258
KeyframeType KeyframeModelList::keyframeType(GenTime pos) const
{
    QWriteLocker locker(&m_lock);
    if (singleKeyframe()) {
        bool ok = false;
        Keyframe kf = m_parameters.begin()->second->getNextKeyframe(GenTime(-1), &ok);
        return kf.second;
    }
    bool ok = false;
    Keyframe kf = m_parameters.begin()->second->getKeyframe(pos, &ok);
    return kf.second;
}

259 260 261 262 263 264 265
Keyframe KeyframeModelList::getKeyframe(const GenTime &pos, bool *ok) const
{
    READ_LOCK();
    Q_ASSERT(m_parameters.size() > 0);
    return m_parameters.begin()->second->getKeyframe(pos, ok);
}

266 267 268 269 270 271 272
bool KeyframeModelList::singleKeyframe() const
{
    READ_LOCK();
    Q_ASSERT(m_parameters.size() > 0);
    return m_parameters.begin()->second->singleKeyframe();
}

273 274 275 276 277 278
bool KeyframeModelList::isEmpty() const
{
    READ_LOCK();
    return (m_parameters.size() == 0 || m_parameters.begin()->second->rowCount() == 0);
}

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
Keyframe KeyframeModelList::getNextKeyframe(const GenTime &pos, bool *ok) const
{
    READ_LOCK();
    Q_ASSERT(m_parameters.size() > 0);
    return m_parameters.begin()->second->getNextKeyframe(pos, ok);
}

Keyframe KeyframeModelList::getPrevKeyframe(const GenTime &pos, bool *ok) const
{
    READ_LOCK();
    Q_ASSERT(m_parameters.size() > 0);
    return m_parameters.begin()->second->getPrevKeyframe(pos, ok);
}

Keyframe KeyframeModelList::getClosestKeyframe(const GenTime &pos, bool *ok) const
{
    READ_LOCK();
    Q_ASSERT(m_parameters.size() > 0);
    return m_parameters.begin()->second->getClosestKeyframe(pos, ok);
}

bool KeyframeModelList::hasKeyframe(int frame) const
{
    READ_LOCK();
    Q_ASSERT(m_parameters.size() > 0);
    return m_parameters.begin()->second->hasKeyframe(frame);
}

307 308
void KeyframeModelList::refresh()
{
309
    QWriteLocker locker(&m_lock);
Nicolas Carion's avatar
Nicolas Carion committed
310
    for (const auto &param : m_parameters) {
311 312 313
        param.second->refresh();
    }
}
314

315 316 317 318 319 320 321 322
void KeyframeModelList::reset()
{
    QWriteLocker locker(&m_lock);
    for (const auto &param : m_parameters) {
        param.second->reset();
    }
}

Nicolas Carion's avatar
Nicolas Carion committed
323
QVariant KeyframeModelList::getInterpolatedValue(int pos, const QPersistentModelIndex &index) const
324 325 326 327 328
{
    READ_LOCK();
    Q_ASSERT(m_parameters.count(index) > 0);
    return m_parameters.at(index)->getInterpolatedValue(pos);
}
329 330 331

KeyframeModel *KeyframeModelList::getKeyModel()
{
332 333 334 335 336 337 338 339 340 341
    if (m_inTimelineIndex.isValid()) {
        return m_parameters.at(m_inTimelineIndex).get();
    }
    if (auto ptr = m_model.lock()) {
        for (const auto &param : m_parameters) {
            if (ptr->data(param.first, AssetParameterModel::ShowInTimelineRole) == true) {
                m_inTimelineIndex = param.first;
                return param.second.get();
            }
        }
342 343 344
    }
    return nullptr;
}
345

346 347 348 349 350 351 352 353
KeyframeModel *KeyframeModelList::getKeyModel(const QPersistentModelIndex &index)
{
    if (m_parameters.size() > 0) {
        return m_parameters.at(index).get();
    }
    return nullptr;
}

354 355 356 357
void KeyframeModelList::resizeKeyframes(int oldIn, int oldOut, int in, int out, Fun &undo, Fun &redo)
{
    bool ok;
    bool ok2;
358 359 360 361 362 363 364
    if (oldIn != in) {
        GenTime old_in(oldIn, pCore->getCurrentFps());
        GenTime new_in(in, pCore->getCurrentFps());
        Keyframe kf = getKeyframe(old_in, &ok);
        KeyframeType type = kf.second;
        getKeyframe(new_in, &ok2);
        // Check keyframes after last position
365
        QList<GenTime> positions;
366
        if (ok && !ok2 && oldIn != 0) {
367
            positions << old_in;
368 369 370 371 372
        } else if (in == 0 && ok && ok2) {
            // We moved start to 0. As the 0 keyframe is always here, simply remove old position
            for (const auto &param : m_parameters) {
                param.second->removeKeyframe(old_in, undo, redo);
            }
373
        }
374
        // qDebug()<<"/// \n\nKEYS TO DELETE: "<<positions<<"\n------------------------";
375 376 377 378 379 380 381 382 383 384
        if (ok && !ok2) {
            for (const auto &param : m_parameters) {
                QVariant value = param.second->getInterpolatedValue(new_in);
                param.second->addKeyframe(new_in, type, value, true, undo, redo);
                for (auto frame : positions) {
                    param.second->removeKeyframe(frame, undo, redo);
                }
            }
        }
    }
385 386 387 388 389 390 391 392 393
    if (oldOut != out) {
        GenTime old_out(oldOut, pCore->getCurrentFps());
        GenTime new_out(out, pCore->getCurrentFps());
        Keyframe kf = getKeyframe(old_out, &ok);
        KeyframeType type = kf.second;
        getKeyframe(new_out, &ok2);
        // Check keyframes after last position
        bool ok3;
        Keyframe toDel = getNextKeyframe(new_out, &ok3);
394
        QList<GenTime> positions;
395 396 397 398
        if (ok && !ok2) {
            positions << old_out;
        }
        while (ok3) {
399
            if (!positions.contains(toDel.first)) {
400 401 402 403
                positions << toDel.first;
            }
            toDel = getNextKeyframe(toDel.first, &ok3);
        }
404
        // qDebug()<<"/// \n\nKEYS TO DELETE: "<<positions<<"\n------------------------";
405 406
        if (ok && !ok2) {
            for (const auto &param : m_parameters) {
407 408
                QVariant value = param.second->getInterpolatedValue(new_out);
                param.second->addKeyframe(new_out, type, value, true, undo, redo);
409 410 411
                for (auto frame : positions) {
                    param.second->removeKeyframe(frame, undo, redo);
                }
412 413 414 415
            }
        }
    }
}