[multimedia/kdenlive] src: timeremap: add keyframe type selector to remap dialog

Jean-Baptiste Mardelle <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 0dd7b3a9b542b9b2f350eaaf83f0c8aa3277ee0e by Jean-Baptiste Mardelle, on behalf of Yash Bavadiya.
Committed on 18/08/2026 at 08:31.
Pushed by mardelle into branch 'master'.

timeremap: add keyframe type selector to remap dialog

M  +30   -0    src/dialogs/timeremap.cpp
M  +2    -0    src/dialogs/timeremap.h
M  +14   -0    src/ui/timeremap_ui.ui

https://invent.kde.org/multimedia/kdenlive/-/commit/0dd7b3a9b542b9b2f350eaaf83f0c8aa3277ee0e

diff --git a/src/dialogs/timeremap.cpp b/src/dialogs/timeremap.cpp
index b24d5c9e8f..f0537efe19 100644
--- a/src/dialogs/timeremap.cpp
+++ b/src/dialogs/timeremap.cpp
@@ -6,6 +6,7 @@ SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
 
 #include "timeremap.h"
 
+#include "assets/keyframes/model/keyframemodel.hpp"
 #include "bin/projectclip.h"
 #include "core.h"
 #include "doc/kdenlivedoc.h"
@@ -1356,6 +1357,25 @@ std::pair<double, double> RemapView::getSpeed(std::pair<int, int> kf)
     return speeds;
 }
 
+void RemapView::slotSetKeyframeType(int type)
+{
+    if (m_currentKeyframe.first == -1 || !m_keyframes.contains(m_currentKeyframe.first)) {
+        return;
+    }
+    if (keyframeTypeAt(m_currentKeyframe.first) == type) {
+        return;
+    }
+    m_keyframesOrigin = m_keyframes;
+    m_keyframeTypesOrigin = m_keyframeTypes;
+    if (type == KeyframeType::Linear) {
+        m_keyframeTypes.remove(m_currentKeyframe.first);
+    } else {
+        m_keyframeTypes.insert(m_currentKeyframe.first, type);
+    }
+    Q_EMIT updateKeyframesWithUndo(m_keyframes, m_keyframesOrigin);
+    update();
+}
+
 void RemapView::addKeyframe()
 {
     // insert or remove keyframe at interpolated position
@@ -1692,7 +1712,17 @@ TimeRemap::TimeRemap(QWidget *parent)
         speedBefore->setValue(100. * speeds.first);
         speedAfter->setEnabled(!atEnd.second);
         speedAfter->setValue(100. * speeds.second);
+        QSignalBlocker bk5(kfr_type);
+        kfr_type->setCurrentIndex(qMax(0, kfr_type->findData(m_view->keyframeTypeAt(selection.first))));
     });
+    // TODO: the list is restricted to non overshooting interpolation types for
+    // now, pending a decision on how to handle types like bounce and elastic
+    // whose overshoot makes the source time briefly play backwards
+    const QMap<KeyframeType::KeyframeEnum, QString> kfrTypes = KeyframeModel::getKeyframeTypes();
+    for (auto type : {KeyframeType::Linear, KeyframeType::CurveSmooth, KeyframeType::CubicIn, KeyframeType::CubicOut}) {
+        kfr_type->addItem(kfrTypes.value(type), int(type));
+    }
+    connect(kfr_type, &QComboBox::activated, this, [this](int ix) { m_view->slotSetKeyframeType(kfr_type->itemData(ix).toInt()); });
     connect(m_view, &RemapView::updateSpeeds, this, [this](std::pair<double, double> speeds) {
         QSignalBlocker bk3(speedBefore);
         QSignalBlocker bk4(speedAfter);
diff --git a/src/dialogs/timeremap.h b/src/dialogs/timeremap.h
index 71720fafc2..f5ad3b1929 100644
--- a/src/dialogs/timeremap.h
+++ b/src/dialogs/timeremap.h
@@ -74,6 +74,8 @@ public Q_SLOTS:
     void goPrev();
     void updateBeforeSpeed(double speed);
     void updateAfterSpeed(double speed);
+    /** @brief Set the interpolation type of the currently selected keyframe */
+    void slotSetKeyframeType(int type);
     void toggleMoveNext(bool moveNext);
     void reloadProducer();
     void centerCurrentKeyframe();
diff --git a/src/ui/timeremap_ui.ui b/src/ui/timeremap_ui.ui
index 545afda8e9..a9271f75bb 100644
--- a/src/ui/timeremap_ui.ui
+++ b/src/ui/timeremap_ui.ui
@@ -286,6 +286,20 @@ SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
                </item>
               </layout>
              </item>
+             <item>
+              <layout class="QHBoxLayout" name="horizontalLayout_15">
+               <item>
+                <widget class="QLabel" name="label_type">
+                 <property name="text">
+                  <string>Type</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QComboBox" name="kfr_type"/>
+               </item>
+              </layout>
+             </item>
             </layout>
            </widget>
           </item>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.