]> git.sesse.net Git - kdenlive/commitdiff
Add animation feature to Slideshow Clip.
authorDan Dennedy <dan@dennedy.org>
Tue, 31 Aug 2010 07:44:51 +0000 (07:44 +0000)
committerDan Dennedy <dan@dennedy.org>
Tue, 31 Aug 2010 07:44:51 +0000 (07:44 +0000)
svn path=/trunk/kdenlive/; revision=4791

12 files changed:
src/clipmanager.cpp
src/clipmanager.h
src/clipproperties.cpp
src/docclipbase.cpp
src/kdenlivedoc.cpp
src/kdenlivedoc.h
src/projectlist.cpp
src/renderer.cpp
src/slideshowclip.cpp
src/slideshowclip.h
src/widgets/clipproperties_ui.ui
src/widgets/slideshowclip_ui.ui

index fc48734fd9e760017628d5cd54d84c1d23010733..dd9ffb7d14e0dfbb0b5c0fbb216c5064099ea5e8 100644 (file)
@@ -372,7 +372,10 @@ void ClipManager::slotAddColorClipFile(const QString name, const QString color,
     m_doc->commandStack()->push(command);
 }
 
-void ClipManager::slotAddSlideshowClipFile(const QString name, const QString path, int count, const QString duration, const bool loop, const bool crop, const bool fade, const QString &luma_duration, const QString &luma_file, const int softness, QString group, const QString &groupId)
+void ClipManager::slotAddSlideshowClipFile(const QString name, const QString path, int count, const QString duration,
+                                           const bool loop, const bool crop, const bool fade,
+                                           const QString &luma_duration, const QString &luma_file, const int softness,
+                                           const QString &animation, QString group, const QString &groupId)
 {
     QDomDocument doc;
     QDomElement prod = doc.createElement("producer");
@@ -391,6 +394,7 @@ void ClipManager::slotAddSlideshowClipFile(const QString name, const QString pat
     prod.setAttribute("fade", fade);
     prod.setAttribute("softness", QString::number(softness));
     prod.setAttribute("luma_file", luma_file);
+    prod.setAttribute("animation", animation);
     if (!group.isEmpty()) {
         prod.setAttribute("groupname", group);
         prod.setAttribute("groupid", groupId);
index 8ea9b4a8673aa5bfedc36009a5f9beefffa68032..2e83e7c546a9a2a4923c42e7a925d47e7e2cea22 100644 (file)
@@ -76,7 +76,10 @@ Q_OBJECT public:
     void slotAddTextTemplateClip(QString titleName, const KUrl path, const QString group, const QString &groupId);
     void slotAddXmlClipFile(const QString name, const QDomElement xml, const QString group, const QString &groupId);
     void slotAddColorClipFile(const QString name, const QString color, QString duration, const QString group, const QString &groupId);
-    void slotAddSlideshowClipFile(const QString name, const QString path, int count, const QString duration, const bool loop, const bool crop, const bool fade, const QString &luma_duration, const QString &luma_file, const int softness, const QString group, const QString &groupId);
+    void slotAddSlideshowClipFile(const QString name, const QString path, int count, const QString duration,
+                                  const bool loop, const bool crop,const bool fade,
+                                  const QString &luma_duration, const QString &luma_file, const int softness,
+                                  const QString &animation, const QString group, const QString &groupId);
     DocClipBase *getClipById(QString clipId);
     const QList <DocClipBase *> getClipByResource(QString resource);
     void slotDeleteClips(QStringList ids);
index 4ff65f02550b139de7a2e216473f53fc2c07c5a6..4c8332235e7f97bb3ed0dfd967aaac9b2c86b3d2 100644 (file)
@@ -183,11 +183,22 @@ ClipProperties::ClipProperties(DocClipBase *clip, Timecode tc, double fps, QWidg
         m_view.image_type->addItem("TGA (*.tga)", "tga");
         m_view.image_type->addItem("TIFF (*.tiff)", "tiff");
         m_view.image_type->addItem("Open EXR (*.exr)", "exr");
+        m_view.animation->addItem(i18n("None"), QString());
+        m_view.animation->addItem(i18n("Pan"), "Pan");
+        m_view.animation->addItem(i18n("Pan, low-pass"), "Pan, low-pass");
+        m_view.animation->addItem(i18n("Pan and zoom"), "Pan and zoom");
+        m_view.animation->addItem(i18n("Pan and zoom, low-pass"), "Pan and zoom, low-pass");
+        m_view.animation->addItem(i18n("Zoom"), "Zoom");
+        m_view.animation->addItem(i18n("Zoom, low-pass"), "Zoom, low-pass");
 
         m_view.slide_loop->setChecked(props.value("loop").toInt());
         m_view.slide_crop->setChecked(props.value("crop").toInt());
         m_view.slide_fade->setChecked(props.value("fade").toInt());
         m_view.luma_softness->setValue(props.value("softness").toInt());
+        if (!props.value("animation").isEmpty())
+            m_view.animation->setCurrentItem(props.value("animation"));
+        else
+            m_view.animation->setCurrentIndex(0);
         QString path = props.value("resource");
         QString ext = path.section('.', -1);
         for (int i = 0; i < m_view.image_type->count(); i++) {
@@ -631,6 +642,15 @@ QMap <QString, QString> ClipProperties::properties()
             }
         }
 
+        QString animation = m_view.animation->itemData(m_view.animation->currentIndex()).toString();
+        if (animation != m_old_props.value("animation")) {
+            if (animation.isEmpty()) {
+                props["animation"].clear();
+            } else {
+                props["animation"] = animation;
+            }
+            m_clipNeedsRefresh = true;
+        }
     }
     return props;
 }
index fc74fbf14a29dd36343dd1bb0fd80d2b275d6d09..87194e0f33ce4cc904329b78a17e44e50bfc5fac 100644 (file)
@@ -28,6 +28,7 @@
 #include "kdenlivesettings.h"
 #include "kthumb.h"
 #include "clipmanager.h"
+#include "slideshowclip.h"
 
 #include <KIO/NetAccess>
 #include <KDebug>
@@ -650,6 +651,49 @@ void DocClipBase::slotRefreshProducer()
         if (!getProperty("out").isEmpty()) m_clipProducer->set_in_and_out(getProperty("in").toInt(), getProperty("out").toInt());*/
         setProducerProperty("ttl", getProperty("ttl").toInt());
         //m_clipProducer->set("id", getProperty("id"));
+        if (!getProperty("animation").isEmpty()) {
+            Mlt::Service clipService(m_baseTrackProducers.at(0)->get_service());
+            int ct = 0;
+            Mlt::Filter *filter = clipService.filter(ct);
+            while (filter) {
+                if (strcmp(filter->get("mlt_service"), "affine") == 0) {
+                    break;
+                }
+                else if (strcmp(filter->get("mlt_service"), "boxblur") == 0) {
+                    clipService.detach(*filter);
+                } else ct++;
+                filter = clipService.filter(ct);
+            }
+
+            if (!filter || strcmp(filter->get("mlt_service"), "affine")) {
+                // filter does not exist, create it.
+                Mlt::Filter *filter = new Mlt::Filter(*(m_baseTrackProducers.at(0)->profile()), "affine");
+                if (filter && filter->is_valid()) {
+                    int cycle = getProperty("ttl").toInt();
+                    QString geometry = SlideshowClip::animationToGeometry(getProperty("animation"), cycle);
+                    if (!geometry.isEmpty()) {
+                        if (getProperty("animation").contains("low-pass")) {
+                            Mlt::Filter *blur = new Mlt::Filter(*(m_baseTrackProducers.at(0)->profile()), "boxblur");
+                            if (blur && blur->is_valid())
+                                clipService.attach(*blur);
+                        }
+                        filter->set("transition.geometry", geometry.toUtf8().data());
+                        filter->set("transition.cycle", cycle);
+                        clipService.attach(*filter);
+                    }
+                }
+            }
+        } else {
+            Mlt::Service clipService(m_baseTrackProducers.at(0)->get_service());
+            int ct = 0;
+            Mlt::Filter *filter = clipService.filter(0);
+            while (filter) {
+                if (strcmp(filter->get("mlt_service"), "affine") == 0 || strcmp(filter->get("mlt_service"), "boxblur") == 0) {
+                    clipService.detach(*filter);
+                } else ct++;
+                filter = clipService.filter(ct);
+            }
+        }
         if (getProperty("fade") == "1") {
             // we want a fade filter effect
             kDebug() << "////////////   FADE WANTED";
@@ -665,8 +709,8 @@ void DocClipBase::slotRefreshProducer()
             }
 
             if (filter && strcmp(filter->get("mlt_service"), "luma") == 0) {
-                filter->set("period", getProperty("ttl").toInt() - 1);
-                filter->set("luma.out", getProperty("luma_duration").toInt());
+                filter->set("cycle", getProperty("ttl").toInt());
+                filter->set("duration", getProperty("luma_duration").toInt());
                 QString resource = getProperty("luma_file");
                 char *tmp = (char *) qstrdup(resource.toUtf8().data());
                 filter->set("luma.resource", tmp);
@@ -678,8 +722,8 @@ void DocClipBase::slotRefreshProducer()
             } else {
                 // filter does not exist, create it...
                 Mlt::Filter *filter = new Mlt::Filter(*(m_baseTrackProducers.at(0)->profile()), "luma");
-                filter->set("period", getProperty("ttl").toInt() - 1);
-                filter->set("luma.out", getProperty("luma_duration").toInt());
+                filter->set("cycle", getProperty("ttl").toInt());
+                filter->set("duration", getProperty("luma_duration").toInt());
                 QString resource = getProperty("luma_file");
                 char *tmp = (char *) qstrdup(resource.toUtf8().data());
                 filter->set("luma.resource", tmp);
index 3af911e5c961a1a62de642b1b479b75da60eab75..7ea9272a11a01febe267adc656dd95fa6675577a 100644 (file)
@@ -1074,9 +1074,15 @@ void KdenliveDoc::slotCreateColorClip(const QString &name, const QString &color,
     emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
 }
 
-void KdenliveDoc::slotCreateSlideshowClipFile(const QString name, const QString path, int count, const QString duration, const bool loop, const bool crop, const bool fade, const QString &luma_duration, const QString &luma_file, const int softness, QString group, const QString &groupId)
-{
-    m_clipManager->slotAddSlideshowClipFile(name, path, count, duration, loop, crop, fade, luma_duration, luma_file, softness, group, groupId);
+void KdenliveDoc::slotCreateSlideshowClipFile(const QString name, const QString path, int count, const QString duration,
+                                              const bool loop, const bool crop, const bool fade,
+                                              const QString &luma_duration, const QString &luma_file, const int softness,
+                                              const QString &animation, QString group, const QString &groupId)
+{
+    m_clipManager->slotAddSlideshowClipFile(name, path, count, duration, loop,
+                                            crop, fade, luma_duration,
+                                            luma_file, softness,
+                                            animation, group, groupId);
     setModified(true);
     emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
 }
index f34dbabf7222dea98e3ef882db19c6c667c1e5b8..d8d2fc22d1aa4b952a21e612fcf6db357214ea40 100644 (file)
@@ -154,7 +154,10 @@ private:
 public slots:
     void slotCreateXmlClip(const QString &name, const QDomElement xml, QString group, const QString &groupId);
     void slotCreateColorClip(const QString &name, const QString &color, const QString &duration, QString group, const QString &groupId);
-    void slotCreateSlideshowClipFile(const QString name, const QString path, int count, const QString duration, const bool loop, const bool crop, const bool fade, const QString &luma_duration, const QString &luma_file, const int softness, QString group, const QString &groupId);
+    void slotCreateSlideshowClipFile(const QString name, const QString path, int count, const QString duration,
+                                     const bool loop, const bool crop, const bool fade,
+                                     const QString &luma_duration, const QString &luma_file, const int softness,
+                                     const QString &animation, QString group, const QString &groupId);
     void slotCreateTextClip(QString group, const QString &groupId, const QString &templatePath = QString());
     void slotCreateTextTemplateClip(QString group, const QString &groupId, KUrl path);
     /** Set to true if document needs saving, false otherwise */
index 8b2d0aa5d1dc7a9f69f083a0f1cc690abc469833..9899268e50b9a3b8a55f38ea5d620d49ed3b65f8 100644 (file)
@@ -1103,7 +1103,10 @@ void ProjectList::slotAddClip(const QList <QUrl> givenList, const QString &group
                             fileName.chop(1);
                         }
 
-                        m_doc->slotCreateSlideshowClipFile(fileName, pattern, count, m_timecode.reformatSeparators(KdenliveSettings::sequence_duration()), false, false, false, m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))), QString(), 0, groupInfo.at(0), groupInfo.at(1));
+                        m_doc->slotCreateSlideshowClipFile(fileName, pattern, count, m_timecode.reformatSeparators(KdenliveSettings::sequence_duration()),
+                                                           false, false, false,
+                                                           m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))), QString(), 0,
+                                                           QString(), groupInfo.at(0), groupInfo.at(1));
                         return;
                     }
                 }
@@ -1191,8 +1194,10 @@ void ProjectList::slotAddSlideshowClip()
 
     if (dia->exec() == QDialog::Accepted) {
         QStringList groupInfo = getGroup();
-        m_doc->slotCreateSlideshowClipFile(dia->clipName(), dia->selectedPath(), dia->imageCount(), dia->clipDuration(), dia->loop(), dia->crop(), dia->fade(),
-                                           dia->lumaDuration(), dia->lumaFile(), dia->softness(), groupInfo.at(0), groupInfo.at(1));
+        m_doc->slotCreateSlideshowClipFile(dia->clipName(), dia->selectedPath(), dia->imageCount(), dia->clipDuration(),
+                                           dia->loop(), dia->crop(), dia->fade(),
+                                           dia->lumaDuration(), dia->lumaFile(), dia->softness(),
+                                           dia->animation(), groupInfo.at(0), groupInfo.at(1));
     }
     delete dia;
 }
index 4d6d315383fc2403927407b3cbde0d1317a9ef0b..c60864502164bbdfb5f92886d3aaeb46f670c3cd 100644 (file)
@@ -27,6 +27,7 @@
 #include "kdenlivesettings.h"
 #include "kthumb.h"
 #include "definitions.h"
+#include "slideshowclip.h"
 
 #include <mlt++/Mlt.h>
 
@@ -712,13 +713,31 @@ void Render::getFileProperties(const QDomElement xml, const QString &clipId, int
     Mlt::Frame *frame = producer->get_frame();
 
     if (xml.attribute("type").toInt() == SLIDESHOW) {
-        if (xml.hasAttribute("ttl")) producer->set("ttl", xml.attribute("ttl").toInt());
+        int ttl = xml.hasAttribute("ttl") ? xml.attribute("ttl").toInt() : 0;
+        if (ttl) producer->set("ttl", ttl);
+        if (!xml.attribute("animation").isEmpty()) {
+            Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, "affine");
+            if (filter && filter->is_valid()) {
+                int cycle = ttl;
+                QString geometry = SlideshowClip::animationToGeometry(xml.attribute("animation"), cycle);
+                if (!geometry.isEmpty()) {
+                    if (xml.attribute("animation").contains("low-pass")) {
+                        Mlt::Filter *blur = new Mlt::Filter(*m_mltProfile, "boxblur");
+                        if (blur && blur->is_valid())
+                            producer->attach(*blur);
+                    }
+                    filter->set("transition.geometry", geometry.toUtf8().data());
+                    filter->set("transition.cycle", cycle);
+                    producer->attach(*filter);
+                }
+            }
+        }
         if (xml.attribute("fade") == "1") {
             // user wants a fade effect to slideshow
             Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, "luma");
             if (filter && filter->is_valid()) {
-                if (xml.hasAttribute("ttl")) filter->set("period", xml.attribute("ttl").toInt() - 1);
-                if (xml.hasAttribute("luma_duration") && !xml.attribute("luma_duration").isEmpty()) filter->set("luma.out", xml.attribute("luma_duration").toInt());
+                if (ttl) filter->set("cycle", ttl);
+                if (xml.hasAttribute("luma_duration") && !xml.attribute("luma_duration").isEmpty()) filter->set("duration", xml.attribute("luma_duration").toInt());
                 if (xml.hasAttribute("luma_file") && !xml.attribute("luma_file").isEmpty()) {
                     char *tmp = decodedString(xml.attribute("luma_file"));
                     filter->set("luma.resource", tmp);
@@ -728,8 +747,7 @@ void Render::getFileProperties(const QDomElement xml, const QString &clipId, int
                         filter->set("luma.softness", (double) soft / 100.0);
                     }
                 }
-                Mlt::Service clipService(producer->get_service());
-                clipService.attach(*filter);
+                producer->attach(*filter);
             }
         }
         if (xml.attribute("crop") == "1") {
index aa8e67ba633f89557f464302c841f52d7abab7a0..3938b029fe8147ed0fc13ffb1f7aa6144b96356a 100644 (file)
@@ -58,6 +58,13 @@ SlideshowClip::SlideshowClip(Timecode tc, QWidget * parent) :
     m_view.image_type->addItem("TGA (*.tga)", "tga");
     m_view.image_type->addItem("TIFF (*.tiff)", "tiff");
     m_view.image_type->addItem("Open EXR (*.exr)", "exr");
+    m_view.animation->addItem(i18n("None"), QString());
+    m_view.animation->addItem(i18n("Pan"), "Pan");
+    m_view.animation->addItem(i18n("Pan, low-pass"), "Pan, low-pass");
+    m_view.animation->addItem(i18n("Pan and zoom"), "Pan and zoom");
+    m_view.animation->addItem(i18n("Pan and zoom, low-pass"), "Pan and zoom, low-pass");
+    m_view.animation->addItem(i18n("Zoom"), "Zoom");
+    m_view.animation->addItem(i18n("Zoom, low-pass"), "Zoom, low-pass");
 
     m_view.clip_duration->setInputMask("");
     m_view.clip_duration->setValidator(m_timecode.validator());
@@ -378,6 +385,12 @@ QString SlideshowClip::lumaFile() const
     return m_view.luma_file->itemData(m_view.luma_file->currentIndex()).toString();
 }
 
+QString SlideshowClip::animation() const
+{
+    if (m_view.animation->itemData(m_view.animation->currentIndex()).isNull()) return QString();
+    return m_view.animation->itemData(m_view.animation->currentIndex()).toString();
+}
+
 void SlideshowClip::slotUpdateDurationFormat(int ix)
 {
     bool framesFormat = ix == 1;
@@ -414,7 +427,24 @@ void SlideshowClip::slotMethodChanged(bool active)
     parseFolder();
 }
 
-
+// static
+QString SlideshowClip::animationToGeometry(const QString &animation, int &ttl)
+{
+    QString geometry;
+    if (animation.startsWith("Pan and zoom")) {
+        geometry = QString().sprintf("0=0,0:100%%x100%%;%d=-14%%,-14%%:120%%x120%%;%d=-5%%,-5%%:110%%x110%%;%d=0,0:110%%x110%%;%d=0,-5%%:110%%x110%%;%d=-5%%,0:110%%x110%%",
+                                     ttl-1, ttl, ttl*2 - 1, ttl*2, ttl*3 - 1 );
+        ttl *= 3;
+    } else if (animation.startsWith("Pan")) {
+        geometry = QString().sprintf("0=-5%%,-5%%:110%%x110%%;%d=0,0:110%%x110%%;%d=0,0:110%%x110%%;%d=0,-5%%:110%%x110%%;%d=0,-5%%:110%%x110%%;%d=-5%%,-5%%:110%%x110%%;%d=0,-5%%:110%%x110%%;%d=-5%%,0:110%%x110%%",
+                                     ttl-1, ttl, ttl*2 - 1, ttl*2, ttl*3 - 1, ttl*3, ttl*4 - 1 );
+        ttl *= 4;
+    } else if (animation.startsWith("Zoom")) {
+        geometry = QString().sprintf("0=0,0:100%%x100%%;%d=-14%%,-14%%:120%%x120%%",
+                                     ttl-1, ttl );
+    }
+    return geometry;
+}
 
 #include "slideshowclip.moc"
 
index 9aa3838745b8a4fc5d392df3512da572acac2805..36ba0a2a3343dcd5e6a95b2c30f46db3f20b01c3 100644 (file)
@@ -47,11 +47,14 @@ public:
     bool fade() const;
     QString lumaFile() const;
     int softness() const;
+    QString animation() const;
 
     /** @brief Check if there are several files with filename pattern, like: image_001.jpg, image_002.jpg,... */
     static int sequenceCount(KUrl file);
     /** @brief return the url pattern for selected slideshow. */
     static QString selectedPath(KUrl url, bool isMime, QString extension, int *count);
+    /** @brief Convert the selection animation style into an affine geometry string. */
+    static QString animationToGeometry(const QString &animation, int &ttl);
 
 private slots:
     void parseFolder();
index 309822c30eedc312bdd2fa57d957fb6cae09edd3..ed1698341bd4bdd5373e6dc15cb9eceff51628be 100644 (file)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>302</width>
-    <height>424</height>
+    <width>306</width>
+    <height>478</height>
    </rect>
   </property>
   <property name="windowTitle">
          </property>
         </widget>
        </item>
-       <item row="8" column="0" colspan="3">
+       <item row="9" column="0" colspan="3">
         <widget class="QLabel" name="slide_info">
          <property name="text">
           <string>No image found</string>
          </property>
         </widget>
        </item>
-       <item row="9" column="1">
+       <item row="10" column="1">
         <spacer name="verticalSpacer_6">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
          </property>
         </widget>
        </item>
+       <item row="8" column="0">
+        <widget class="QLabel" name="label_animation">
+         <property name="text">
+          <string>Animation</string>
+         </property>
+        </widget>
+       </item>
+       <item row="8" column="1" colspan="2">
+        <widget class="KComboBox" name="animation"/>
+       </item>
       </layout>
      </widget>
      <widget class="QWidget" name="tab_4">
index 97dbdafd2dd5e01fec094adf9fb37ccbf25d4fd4..c2b34e2ffc1b82bcc41c809fdb9c8809d0ae60c6 100644 (file)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>287</width>
-    <height>453</height>
+    <width>290</width>
+    <height>507</height>
    </rect>
   </property>
   <property name="windowTitle">
      </property>
     </widget>
    </item>
-   <item row="8" column="0" colspan="4">
+   <item row="9" column="0" colspan="4">
     <widget class="KListWidget" name="icon_list"/>
    </item>
-   <item row="9" column="0" colspan="4">
+   <item row="10" column="0" colspan="4">
     <layout class="QHBoxLayout" name="horizontalLayout_3">
      <item>
       <widget class="QCheckBox" name="show_thumbs">
      </item>
     </layout>
    </item>
-   <item row="10" column="2" colspan="2">
+   <item row="11" column="2" colspan="2">
     <widget class="QDialogButtonBox" name="buttonBox">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
     </widget>
    </item>
+   <item row="8" column="0">
+    <widget class="QLabel" name="label_6">
+     <property name="text">
+      <string>Animation</string>
+     </property>
+    </widget>
+   </item>
+   <item row="8" column="2" colspan="2">
+    <widget class="KComboBox" name="animation">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <customwidgets>