[calligra/krita-animation-pentikainen] krita: Implemented a "Drop Frames" mode for Krita and made it default option

Dmitry Kazakov dimula73 at gmail.com
Fri Jan 1 20:19:33 UTC 2016


Git commit bd79d3ca3fa17c4a9e5f0a80c6265d96ca19a0a0 by Dmitry Kazakov.
Committed on 01/01/2016 at 17:47.
Pushed by dkazakov into branch 'krita-animation-pentikainen'.

Implemented a "Drop Frames" mode for Krita and made it default option

Now you can switch on the "Drop Frames" mode in the Animation Docker
to ensure your animation is playing with the requested frame rate,
even when the GPU cannot handle this amount of data to be shown.

TODO: we still need an icon for this feature! Atm it uses "Auto Frame" icon!

BUG:356245
CC:kimageshop at kde.org

# Conflicts:
#	krita/ui/canvas/kis_animation_player.cpp
#	krita/ui/canvas/kis_animation_player.h
#	krita/ui/kis_config_notifier.cpp

M  +57   -6    krita/plugins/extensions/dockers/animation/animation_docker.cpp
M  +3    -0    krita/plugins/extensions/dockers/animation/animation_docker.h
M  +1    -0    krita/plugins/extensions/dockers/animation/kis_animation_utils.cpp
M  +1    -0    krita/plugins/extensions/dockers/animation/kis_animation_utils.h
M  +10   -0    krita/plugins/extensions/dockers/animation/wdg_animation.ui
M  +122  -29   krita/ui/canvas/kis_animation_player.cpp
M  +2    -2    krita/ui/canvas/kis_animation_player.h
M  +16   -1    krita/ui/kis_config.cc
M  +4    -1    krita/ui/kis_config.h
M  +15   -1    krita/ui/kis_config_notifier.cpp
M  +8    -1    krita/ui/kis_config_notifier.h

http://commits.kde.org/calligra/bd79d3ca3fa17c4a9e5f0a80c6265d96ca19a0a0

diff --git a/krita/plugins/extensions/dockers/animation/animation_docker.cpp b/krita/plugins/extensions/dockers/animation/animation_docker.cpp
index cff740b..f825c2a 100644
--- a/krita/plugins/extensions/dockers/animation/animation_docker.cpp
+++ b/krita/plugins/extensions/dockers/animation/animation_docker.cpp
@@ -33,11 +33,26 @@
 #include "kis_animation_utils.h"
 #include "krita_utils.h"
 #include "kis_image_config.h"
+#include "kis_config.h"
 #include "kis_signals_blocker.h"
+#include "kis_icon_utils.h"
 
 
 #include "ui_wdg_animation.h"
 
+void setupActionButton(const QString &text,
+                       KisAction::ActivationFlags flags,
+                       bool defaultValue,
+                       QToolButton *button,
+                       KisAction **action)
+{
+    *action = new KisAction(text, button);
+    (*action)->setActivationFlags(flags);
+    (*action)->setCheckable(true);
+    (*action)->setChecked(defaultValue);
+    button->setDefaultAction(*action);
+}
+
 AnimationDocker::AnimationDocker()
     : QDockWidget(i18n("Animation"))
     , m_canvas(0)
@@ -90,16 +105,23 @@ AnimationDocker::AnimationDocker()
     m_deleteKeyframeAction->setActivationFlags(KisAction::ACTIVE_LAYER);
     m_animationWidget->btnDeleteKeyframe->setDefaultAction(m_deleteKeyframeAction);
 
-    m_lazyFrameAction = new KisAction(KisAnimationUtils::lazyFrameCreationActionName, m_animationWidget->btnLazyFrame);
-    m_lazyFrameAction->setActivationFlags(KisAction::ACTIVE_IMAGE);
-    m_lazyFrameAction->setCheckable(true);
-
     {
         KisImageConfig cfg;
-        m_lazyFrameAction->setChecked(cfg.lazyFrameCreationEnabled());
+        setupActionButton(KisAnimationUtils::lazyFrameCreationActionName,
+                          KisAction::ACTIVE_IMAGE,
+                          cfg.lazyFrameCreationEnabled(),
+                          m_animationWidget->btnLazyFrame,
+                          &m_lazyFrameAction);
     }
 
-    m_animationWidget->btnLazyFrame->setDefaultAction(m_lazyFrameAction);
+    {
+        KisConfig cfg;
+        setupActionButton(KisAnimationUtils::dropFramesActionName,
+                          KisAction::ACTIVE_IMAGE,
+                          cfg.animationDropFrames(),
+                          m_animationWidget->btnDropFrames,
+                          &m_dropFramesAction);
+    }
 
     QFont font;
     font.setPointSize(1.7 * font.pointSize());
@@ -121,6 +143,7 @@ AnimationDocker::AnimationDocker()
     connect(m_addDuplicateFrameAction, SIGNAL(triggered()), this, SLOT(slotAddDuplicateFrame()));
     connect(m_deleteKeyframeAction, SIGNAL(triggered()), this, SLOT(slotDeleteKeyframe()));
     connect(m_lazyFrameAction, SIGNAL(toggled(bool)), this, SLOT(slotLazyFrameChanged(bool)));
+    connect(m_dropFramesAction, SIGNAL(toggled(bool)), this, SLOT(slotDropFramesChanged(bool)));
 
     m_animationWidget->btnOnionSkinOptions->setToolTip(i18n("Onion Skins"));
     connect(m_animationWidget->btnOnionSkinOptions, SIGNAL(clicked()), this, SLOT(slotOnionSkinOptions()));
@@ -192,6 +215,7 @@ void AnimationDocker::setMainWindow(KisViewManager *view)
     actionManager->addAction("last_frame", m_lastFrameAction);
 
     actionManager->addAction("lazy_frame", m_lazyFrameAction);
+    actionManager->addAction("drop_frames", m_dropFramesAction);
 
     actionManager->addAction("toggle_playback", m_playPauseAction);
     actionManager->addAction("add_blank_frame", m_addBlankFrameAction);
@@ -428,6 +452,21 @@ void AnimationDocker::updateLazyFrameIcon()
                                .arg(KritaUtils::toLocalizedOnOff(value)));
 }
 
+void AnimationDocker::updateDropFramesIcon()
+{
+    KisConfig cfg;
+
+    const bool value = cfg.animationDropFrames();
+
+    m_dropFramesAction->setIcon(value ?
+                               KisIconUtils::loadIcon("lazyframeOn") :
+                               KisIconUtils::loadIcon("lazyframeOff"));
+
+    m_dropFramesAction->setText(QString("%1 (%2)")
+                               .arg(KisAnimationUtils::dropFramesActionName)
+                               .arg(KritaUtils::toLocalizedOnOff(value)));
+}
+
 void AnimationDocker::slotUpdateIcons()
 {
     m_previousFrameAction->setIcon(themedIcon("prevframe"));
@@ -445,6 +484,7 @@ void AnimationDocker::slotUpdateIcons()
     m_deleteKeyframeAction->setIcon(themedIcon("deletekeyframe"));
 
     updateLazyFrameIcon();
+    updateDropFramesIcon();
 
     m_animationWidget->btnOnionSkinOptions->setIcon(themedIcon("onion_skin_options"));
     m_animationWidget->btnOnionSkinOptions->setIconSize(QSize(22, 22));
@@ -462,6 +502,7 @@ void AnimationDocker::slotUpdateIcons()
     m_animationWidget->btnAddDuplicateFrame->setIconSize(QSize(22, 22));
     m_animationWidget->btnDeleteKeyframe->setIconSize(QSize(22, 22));
     m_animationWidget->btnLazyFrame->setIconSize(QSize(22, 22));
+    m_animationWidget->btnDropFrames->setIconSize(QSize(22, 22));
 }
 
 void AnimationDocker::slotLazyFrameChanged(bool value)
@@ -474,4 +515,14 @@ void AnimationDocker::slotLazyFrameChanged(bool value)
     }
 }
 
+void AnimationDocker::slotDropFramesChanged(bool value)
+{
+    KisConfig cfg;
+
+    if (value != cfg.animationDropFrames()) {
+        cfg.setAnimationDropFrames(value);
+        updateDropFramesIcon();
+    }
+}
+
 #include "animation_docker.moc"
diff --git a/krita/plugins/extensions/dockers/animation/animation_docker.h b/krita/plugins/extensions/dockers/animation/animation_docker.h
index 717c1b9..9fc9f26 100644
--- a/krita/plugins/extensions/dockers/animation/animation_docker.h
+++ b/krita/plugins/extensions/dockers/animation/animation_docker.h
@@ -67,8 +67,10 @@ private slots:
 
     void updatePlayPauseIcon();
     void updateLazyFrameIcon();
+    void updateDropFramesIcon();
 
     void slotLazyFrameChanged(bool value);
+    void slotDropFramesChanged(bool value);
 
 private:
 
@@ -90,6 +92,7 @@ private:
     KisAction *m_addDuplicateFrameAction;
     KisAction *m_deleteKeyframeAction;
     KisAction *m_lazyFrameAction;
+    KisAction *m_dropFramesAction;
 
     KisMainWindow *m_mainWindow;
 };
diff --git a/krita/plugins/extensions/dockers/animation/kis_animation_utils.cpp b/krita/plugins/extensions/dockers/animation/kis_animation_utils.cpp
index 66ed519..34b7a15 100644
--- a/krita/plugins/extensions/dockers/animation/kis_animation_utils.cpp
+++ b/krita/plugins/extensions/dockers/animation/kis_animation_utils.cpp
@@ -32,6 +32,7 @@ namespace KisAnimationUtils {
     const QString removeFrameActionName = i18n("Remove Frame");
     const QString removeFramesActionName = i18n("Remove Frames");
     const QString lazyFrameCreationActionName = i18n("Auto Frame Mode");
+    const QString dropFramesActionName = i18n("Drop Frames");
     const QString showLayerActionName = i18n("Show in Timeline");
 
 
diff --git a/krita/plugins/extensions/dockers/animation/kis_animation_utils.h b/krita/plugins/extensions/dockers/animation/kis_animation_utils.h
index 4a42bd8..63e3fb6 100644
--- a/krita/plugins/extensions/dockers/animation/kis_animation_utils.h
+++ b/krita/plugins/extensions/dockers/animation/kis_animation_utils.h
@@ -52,6 +52,7 @@ namespace KisAnimationUtils
     extern const QString removeFrameActionName;
     extern const QString removeFramesActionName;
     extern const QString lazyFrameCreationActionName;
+    extern const QString dropFramesActionName;
     extern const QString showLayerActionName;
 };
 
diff --git a/krita/plugins/extensions/dockers/animation/wdg_animation.ui b/krita/plugins/extensions/dockers/animation/wdg_animation.ui
index 83f0590..fced8f1 100644
--- a/krita/plugins/extensions/dockers/animation/wdg_animation.ui
+++ b/krita/plugins/extensions/dockers/animation/wdg_animation.ui
@@ -442,6 +442,16 @@
            </property>
           </widget>
          </item>
+         <item>
+          <widget class="QToolButton" name="btnDropFrames">
+           <property name="text">
+            <string>...</string>
+           </property>
+           <property name="autoRaise">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
         </layout>
        </item>
       </layout>
diff --git a/krita/ui/canvas/kis_animation_player.cpp b/krita/ui/canvas/kis_animation_player.cpp
index 3b26819..ffc9c25 100644
--- a/krita/ui/canvas/kis_animation_player.cpp
+++ b/krita/ui/canvas/kis_animation_player.cpp
@@ -18,14 +18,15 @@
 
 #include "kis_animation_player.h"
 
+#include <QElapsedTimer>
 #include <QTimer>
 
-//#define DEBUG_FRAMERATE
+//#define PLAYER_DEBUG_FRAMERATE
 
-#ifdef DEBUG_FRAMERATE
-#include <QTime>
-#endif /* DEBUG_FRAMERATE */
+#include "kis_global.h"
 
+#include "kis_config.h"
+#include "kis_config_notifier.h"
 #include "kis_image.h"
 #include "kis_canvas2.h"
 #include "kis_animation_frame_cache.h"
@@ -33,19 +34,38 @@
 #include "kis_image_animation_interface.h"
 #include "kis_time_range.h"
 
+#ifdef PLAYER_DEBUG_FRAMERATE
+#include <boost/accumulators/accumulators.hpp>
+#include <boost/accumulators/statistics/stats.hpp>
+#include <boost/accumulators/statistics/rolling_mean.hpp>
+
+using namespace boost::accumulators;
+typedef accumulator_set<qreal, stats<tag::rolling_mean> > FpsAccumulator;
+#endif /* PLAYER_DEBUG_FRAMERATE */
+
 struct KisAnimationPlayer::Private
 {
 public:
-    Private(KisAnimationPlayer *_q) : q(_q) {}
+    Private(KisAnimationPlayer *_q)
+        : q(_q),
+#ifdef PLAYER_DEBUG_FRAMERATE
+          realFpsAccumulator(tag::rolling_window::window_size = 12),
+          droppedFpsAccumulator(tag::rolling_window::window_size = 12),
+#endif /* PLAYER_DEBUG_FRAMERATE */
+          dropFramesMode(true),
+          nextFrameExpectedTime(0),
+          expectedInterval(0),
+          expectedFrame(0),
+          lastTimerInterval(0),
+          lastPaintedFrame(0)
+          {}
 
     KisAnimationPlayer *q;
 
     bool useFastFrameUpload;
     bool playing;
-    int currentFrame;
 
     QTimer *timer;
-    QImage frame;
 
     int firstFrame;
     int lastFrame;
@@ -56,11 +76,30 @@ public:
 
     KisSignalAutoConnectionsStore cancelStrokeConnections;
 
-#ifdef DEBUG_FRAMERATE
-    QTime frameRateTimer;
-#endif /* DEBUG_FRAMERATE */
+#ifdef PLAYER_DEBUG_FRAMERATE
+    QElapsedTimer realFpsTimer;
+    FpsAccumulator realFpsAccumulator;
+    FpsAccumulator droppedFpsAccumulator;
+#endif /* PLAYER_DEBUG_FRAMERATE */
+
+    bool dropFramesMode;
+
+    QElapsedTimer playbackTime;
+    int nextFrameExpectedTime;
+    int expectedInterval;
+    int expectedFrame;
+    int lastTimerInterval;
+    int lastPaintedFrame;
 
     void stopImpl(bool doUpdates);
+
+    int incFrame(int frame, int inc) {
+        frame += inc;
+        if (frame > lastFrame) {
+            frame = firstFrame + frame - lastFrame - 1;
+        }
+        return frame;
+    }
 };
 
 KisAnimationPlayer::KisAnimationPlayer(KisCanvas2 *canvas)
@@ -74,11 +113,23 @@ KisAnimationPlayer::KisAnimationPlayer(KisCanvas2 *canvas)
 
     m_d->timer = new QTimer(this);
     connect(m_d->timer, SIGNAL(timeout()), this, SLOT(slotUpdate()));
+    m_d->timer->setSingleShot(true);
+
+    connect(KisConfigNotifier::instance(),
+            SIGNAL(dropFramesModeChanged()),
+            SLOT(slotUpdateDropFramesMode()));
+    slotUpdateDropFramesMode();
 }
 
 KisAnimationPlayer::~KisAnimationPlayer()
 {}
 
+void KisAnimationPlayer::slotUpdateDropFramesMode()
+{
+    KisConfig cfg;
+    m_d->dropFramesMode = cfg.animationDropFrames();
+}
+
 void KisAnimationPlayer::connectCancelSignals()
 {
     m_d->cancelStrokeConnections.addConnection(
@@ -122,9 +173,19 @@ void KisAnimationPlayer::slotUpdatePlaybackTimer()
     m_d->fps = animation->framerate();
     m_d->firstFrame = range.start();
     m_d->lastFrame = range.end();
-    m_d->currentFrame = qBound(m_d->firstFrame, m_d->currentFrame, m_d->lastFrame);
+    m_d->expectedFrame = qBound(m_d->firstFrame, m_d->expectedFrame, m_d->lastFrame);
+
+    m_d->expectedInterval = qreal(1000) / m_d->fps / m_d->playbackSpeed;
+    m_d->lastTimerInterval = m_d->expectedInterval;
+    m_d->timer->start(m_d->expectedInterval);
+
+    if (m_d->playbackTime.isValid()) {
+        m_d->playbackTime.restart();
+    } else {
+        m_d->playbackTime.start();
+    }
 
-    m_d->timer->start(qreal(1000) / m_d->fps / m_d->playbackSpeed);
+    m_d->nextFrameExpectedTime = m_d->playbackTime.elapsed() + m_d->expectedInterval;
 }
 
 void KisAnimationPlayer::play()
@@ -132,7 +193,8 @@ void KisAnimationPlayer::play()
     m_d->playing = true;
 
     slotUpdatePlaybackTimer();
-    m_d->currentFrame = m_d->firstFrame;
+    m_d->expectedFrame = m_d->firstFrame;
+    m_d->lastPaintedFrame = m_d->firstFrame;
 
     connectCancelSignals();
 }
@@ -168,7 +230,7 @@ bool KisAnimationPlayer::isPlaying()
 
 int KisAnimationPlayer::currentTime()
 {
-    return m_d->currentFrame;
+    return m_d->lastPaintedFrame;
 }
 
 void KisAnimationPlayer::displayFrame(int time)
@@ -178,19 +240,35 @@ void KisAnimationPlayer::displayFrame(int time)
 
 void KisAnimationPlayer::slotUpdate()
 {
-    m_d->currentFrame++;
-    if (m_d->currentFrame > m_d->lastFrame) m_d->currentFrame = m_d->firstFrame;
-
-    uploadFrame(m_d->currentFrame);
+    uploadFrame(-1);
 }
 
-#ifdef DEBUG_FRAMERATE
-#include "../../sdk/tests/testutil.h"
-static TestUtil::MeasureAvgPortion C(25);
-#endif /* DEBUG_FRAMERATE */
-
 void KisAnimationPlayer::uploadFrame(int frame)
 {
+    if (frame < 0) {
+        const int currentTime = m_d->playbackTime.elapsed();
+        const int framesDiff = currentTime - m_d->nextFrameExpectedTime;
+        const qreal framesDiffNorm = qreal(framesDiff) / m_d->expectedInterval;
+
+        // qDebug() << ppVar(framesDiff)
+        //          << ppVar(m_d->expectedFrame)
+        //          << ppVar(framesDiffNorm)
+        //          << ppVar(m_d->lastTimerInterval);
+
+        if (m_d->dropFramesMode) {
+            frame = m_d->incFrame(m_d->expectedFrame, qMax(0, qRound(framesDiffNorm)));
+        } else {
+            frame = m_d->expectedFrame;
+        }
+
+        m_d->nextFrameExpectedTime = currentTime + m_d->expectedInterval;
+
+        m_d->lastTimerInterval = qMax(0.0, m_d->lastTimerInterval - 0.5 * framesDiff);
+        m_d->expectedFrame = m_d->incFrame(frame,  1);
+
+        m_d->timer->start(m_d->lastTimerInterval);
+    }
+
     if (m_d->canvas->frameCache()) {
         if (m_d->canvas->frameCache()->uploadFrame(frame)) {
             m_d->canvas->updateCanvas();
@@ -206,14 +284,29 @@ void KisAnimationPlayer::uploadFrame(int frame)
         emit sigFrameChanged();
     }
 
-#ifdef DEBUG_FRAMERATE
-    if (!m_d->frameRateTimer.isValid()) {
-        m_d->frameRateTimer.start();
+#ifdef PLAYER_DEBUG_FRAMERATE
+    if (!m_d->realFpsTimer.isValid()) {
+        m_d->realFpsTimer.start();
     } else {
-        const int elapsed = m_d->frameRateTimer.restart();
-        C.addTotal(1000 / elapsed);
+        const int elapsed = m_d->realFpsTimer.restart();
+        m_d->realFpsAccumulator(elapsed);
+
+        int numFrames = frame - m_d->lastPaintedFrame;
+        if (numFrames < 0) {
+            numFrames += m_d->lastFrame - m_d->firstFrame + 1;
+        }
+
+        if (numFrames > 0) {
+            m_d->droppedFpsAccumulator(qreal(elapsed) / numFrames);
+        }
+
+        qDebug() << "    RFPS:" << 1000.0 / rolling_mean(m_d->realFpsAccumulator)
+                 << "DFPS:" << 1000.0 / rolling_mean(m_d->droppedFpsAccumulator) << ppVar(numFrames);
     }
-#endif /* DEBUG_FRAMERATE */
+#endif /* PLAYER_DEBUG_FRAMERATE */
+
+    m_d->lastPaintedFrame = frame;
+
 }
 
 void KisAnimationPlayer::slotCancelPlayback()
diff --git a/krita/ui/canvas/kis_animation_player.h b/krita/ui/canvas/kis_animation_player.h
index dfa96f2..ef166ce 100644
--- a/krita/ui/canvas/kis_animation_player.h
+++ b/krita/ui/canvas/kis_animation_player.h
@@ -52,7 +52,7 @@ public slots:
     void slotCancelPlaybackSafe();
     void slotUpdatePlaybackSpeed(double value);
     void slotUpdatePlaybackTimer();
-
+    void slotUpdateDropFramesMode();
 signals:
     void sigFrameChanged();
     void sigPlaybackStopped();
@@ -60,7 +60,7 @@ signals:
 private:
     void connectCancelSignals();
     void disconnectCancelSignals();
-    void uploadFrame(int frame);
+    void uploadFrame(int time);
 
 private:
     struct Private;
diff --git a/krita/ui/kis_config.cc b/krita/ui/kis_config.cc
index 5b2e1ce..cc2b3fe 100644
--- a/krita/ui/kis_config.cc
+++ b/krita/ui/kis_config.cc
@@ -1630,7 +1630,7 @@ void KisConfig::setEnableOpenGLDebugging(bool value) const
     m_cfg.writeEntry("enableOpenGLDebugging", value);
 }
 
-void KisConfig::setEnableAmdVectorizationWorkaround(bool value) const
+void KisConfig::setEnableAmdVectorizationWorkaround(bool value)
 {
     m_cfg.writeEntry("amdDisableVectorWorkaround", value);
 }
@@ -1639,3 +1639,18 @@ bool KisConfig::enableAmdVectorizationWorkaround(bool defaultValue) const
 {
     return (defaultValue ? false : m_cfg.readEntry("amdDisableVectorWorkaround", false));
 }
+
+void KisConfig::setAnimationDropFrames(bool value)
+{
+    bool oldValue = animationDropFrames();
+
+    if (value == oldValue) return;
+
+    m_cfg.writeEntry("animationDropFrames", value);
+    KisConfigNotifier::instance()->notifyDropFramesModeChanged();
+}
+
+bool KisConfig::animationDropFrames(bool defaultValue) const
+{
+    return (defaultValue ? true : m_cfg.readEntry("animationDropFrames", true));
+}
diff --git a/krita/ui/kis_config.h b/krita/ui/kis_config.h
index d73ddfc..727e195 100644
--- a/krita/ui/kis_config.h
+++ b/krita/ui/kis_config.h
@@ -465,9 +465,12 @@ public:
     void setEnableOpenGLDebugging(bool value) const;
     bool enableOpenGLDebugging(bool defaultValue = false) const;
 
-    void setEnableAmdVectorizationWorkaround(bool value) const;
+    void setEnableAmdVectorizationWorkaround(bool value);
     bool enableAmdVectorizationWorkaround(bool defaultValue = false) const;
 
+    bool animationDropFrames(bool defaultValue = false) const;
+    void setAnimationDropFrames(bool value);
+
     template<class T>
     void writeEntry(const QString& name, const T& value) {
         m_cfg.writeEntry(name, value);
diff --git a/krita/ui/kis_config_notifier.cpp b/krita/ui/kis_config_notifier.cpp
index 2d78405..ce7bf3e 100644
--- a/krita/ui/kis_config_notifier.cpp
+++ b/krita/ui/kis_config_notifier.cpp
@@ -20,9 +20,19 @@
 #include <kglobal.h>
 
 #include <kis_debug.h>
+#include "kis_signal_compressor.h"
+
+struct KisConfigNotifier::Private
+{
+    Private() : dropFramesModeCompressor(300, KisSignalCompressor::FIRST_ACTIVE) {}
+
+    KisSignalCompressor dropFramesModeCompressor;
+};
 
 KisConfigNotifier::KisConfigNotifier()
+    : m_d(new Private)
 {
+    connect(&m_d->dropFramesModeCompressor, SIGNAL(timeout()), SIGNAL(dropFramesModeChanged()));
 }
 
 KisConfigNotifier::~KisConfigNotifier()
@@ -41,5 +51,9 @@ void KisConfigNotifier::notifyConfigChanged(void)
     emit configChanged();
 }
 
-#include "kis_config_notifier.moc"
+void KisConfigNotifier::notifyDropFramesModeChanged()
+{
+    m_d->dropFramesModeCompressor.start();
+}
 
+#include "kis_config_notifier.moc"
diff --git a/krita/ui/kis_config_notifier.h b/krita/ui/kis_config_notifier.h
index 9615108..86dcbe0 100644
--- a/krita/ui/kis_config_notifier.h
+++ b/krita/ui/kis_config_notifier.h
@@ -19,6 +19,7 @@
 #define KIS_CONFIG_NOTIFIER_H_
 
 #include <QObject>
+#include <QScopedPointer>
 
 #include "kritaui_export.h"
 
@@ -41,17 +42,23 @@ public:
      */
     void notifyConfigChanged(void);
 
+    void notifyDropFramesModeChanged();
+
 Q_SIGNALS:
     /**
      * This signal is emitted whenever notifyConfigChanged() is called.
      */
     void configChanged(void);
-
+    void dropFramesModeChanged();
 private:
     KisConfigNotifier();
     ~KisConfigNotifier();
     KisConfigNotifier(const KisConfigNotifier&);
     KisConfigNotifier operator=(const KisConfigNotifier&);
+
+private:
+    struct Private;
+    const QScopedPointer<Private> m_d;
 };
 
 #endif // KIS_CONFIG_NOTIFIER_H_



More information about the kimageshop mailing list