]> git.sesse.net Git - kdenlive/blobdiff - src/stopmotion/stopmotion.cpp
correctly enable capture button
[kdenlive] / src / stopmotion / stopmotion.cpp
index e4c12267ec37e40a6e786759f06aad22f5299139..87af29ee1748092c1dbb9464a6cd3e96ef2da0fa 100644 (file)
@@ -57,10 +57,16 @@ void MyLabel::setImage(QImage img)
 //virtual
 void MyLabel::wheelEvent(QWheelEvent * event)
 {
-    if(event->delta() > 0) emit seek(true);
+    if (event->delta() > 0) emit seek(true);
     else emit seek(false);
 }
 
+//virtual
+void MyLabel::mousePressEvent(QMouseEvent *)
+{
+    emit switchToLive();
+}
+
 //virtual
 void MyLabel::paintEvent(QPaintEvent * event)
 {
@@ -73,17 +79,17 @@ void MyLabel::paintEvent(QPaintEvent * event)
     int pictureHeight = height();
     int pictureWidth = width();
     int calculatedWidth = aspect_ratio * height();
-    if(calculatedWidth > width()) pictureHeight = width() / aspect_ratio;
+    if (calculatedWidth > width()) pictureHeight = width() / aspect_ratio;
     else {
         int calculatedHeight = width() / aspect_ratio;
-        if(calculatedHeight > height()) pictureWidth = height() * aspect_ratio;
+        if (calculatedHeight > height()) pictureWidth = height() * aspect_ratio;
     }
     p.drawImage(QRect((width() - pictureWidth) / 2, (height() - pictureHeight) / 2, pictureWidth, pictureHeight), m_img, QRect(0, 0, m_img.width(), m_img.height()));
     p.end();
 }
 
 
-StopmotionWidget::StopmotionWidget(KUrl projectFolder, QWidget *parent) :
+StopmotionWidget::StopmotionWidget(KUrl projectFolder, const QList< QAction * > actions, QWidget *parent) :
     QDialog(parent)
     , Ui::Stopmotion_UI()
     , m_projectFolder(projectFolder)
@@ -91,24 +97,26 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, QWidget *parent) :
     , m_sequenceFrame(0)
     , m_animatedIndex(-1)
 {
+    //setAttribute(Qt::WA_DeleteOnClose);
+    addActions(actions);
     setupUi(this);
     setWindowTitle(i18n("Stop Motion Capture"));
     setFont(KGlobalSettings::toolBarFont());
 
     live_button->setIcon(KIcon("camera-photo"));
-    m_captureAction = new QAction(KIcon("media-record"), i18n("Capture frame"), this);
-    m_captureAction->setShortcut(QKeySequence(Qt::Key_Space));
+
+    m_captureAction = actions.at(0);
     connect(m_captureAction, SIGNAL(triggered()), this, SLOT(slotCaptureFrame()));
     capture_button->setDefaultAction(m_captureAction);
 
+    connect(actions.at(1), SIGNAL(triggered()), this, SLOT(slotSwitchLive()));
+
     preview_button->setIcon(KIcon("media-playback-start"));
     capture_button->setEnabled(false);
 
     // Build config menu
     QMenu *confMenu = new QMenu;
-    m_showOverlay = new QAction(KIcon("edit-paste"), i18n("Show last frame over video"), this);
-    m_showOverlay->setCheckable(true);
-    m_showOverlay->setChecked(false);
+    m_showOverlay = actions.at(2);
     connect(m_showOverlay, SIGNAL(triggered(bool)), this, SLOT(slotShowOverlay(bool)));
     confMenu->addAction(m_showOverlay);
 
@@ -136,9 +144,9 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, QWidget *parent) :
     effectsMenu->addAction(invertEffect);
     effectsMenu->addAction(thresEffect);
     QList <QAction *> list = effectsMenu->actions();
-    for(int i = 0; i < list.count(); i++) {
+    for (int i = 0; i < list.count(); i++) {
         list.at(i)->setCheckable(true);
-        if(list.at(i)->data().toInt() == m_effectIndex) {
+        if (list.at(i)->data().toInt() == m_effectIndex) {
             list.at(i)->setChecked(true);
         }
     }
@@ -152,8 +160,8 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, QWidget *parent) :
     connect(showThumbs, SIGNAL(triggered(bool)), this, SLOT(slotShowThumbs(bool)));
 
     QAction *removeCurrent = new QAction(KIcon("edit-delete"), i18n("Delete current frame"), this);
-    //TODO: implement frame deletion
-    //connect(removeCurrent, SIGNAL(triggered()), this, SLOT(slotRemoveFrame()));
+    removeCurrent->setShortcut(Qt::Key_Delete);
+    connect(removeCurrent, SIGNAL(triggered()), this, SLOT(slotRemoveFrame()));
 
     QAction *capInterval = new QAction(KIcon(), i18n("Set capture interval"), this);
     connect(capInterval, SIGNAL(triggered()), this, SLOT(slotSetCaptureInterval()));
@@ -174,21 +182,49 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, QWidget *parent) :
     capture_button->setMenu(capMenu);
 
     connect(sequence_name, SIGNAL(textChanged(const QString &)), this, SLOT(sequenceNameChanged(const QString &)));
+    connect(sequence_name, SIGNAL(currentIndexChanged(int)), live_button, SLOT(setFocus()));
+
     m_layout = new QVBoxLayout;
-    if(BMInterface::getBlackMagicDeviceList(capture_device, NULL)) {
+    if (BMInterface::getBlackMagicDeviceList(capture_device, NULL)) {
         // Found a BlackMagic device
         m_bmCapture = new BmdCaptureHandler(m_layout);
         connect(m_bmCapture, SIGNAL(gotMessage(const QString &)), this, SLOT(slotGotHDMIMessage(const QString &)));
     }
-    if(QFile::exists(KdenliveSettings::video4vdevice())) {
-        if(m_bmCapture == NULL) m_bmCapture = new V4lCaptureHandler(m_layout);
-        capture_device->addItem(KdenliveSettings::video4vdevice(), "v4l");
+    if (QFile::exists(KdenliveSettings::video4vdevice())) {
+#ifndef Q_WS_MAC
+        V4lCaptureHandler v4l(NULL);
+        // Video 4 Linux device detection
+        for (int i = 0; i < 10; i++) {
+            QString path = "/dev/video" + QString::number(i);
+            if (QFile::exists(path)) {
+                QStringList deviceInfo = v4l.getDeviceName(path);
+                if (!deviceInfo.isEmpty()) {
+                    capture_device->addItem(deviceInfo.at(0), "v4l");
+                    capture_device->setItemData(capture_device->count() - 1, path, Qt::UserRole + 1);
+                    capture_device->setItemData(capture_device->count() - 1, deviceInfo.at(1), Qt::UserRole + 2);
+                    if (path == KdenliveSettings::video4vdevice()) capture_device->setCurrentIndex(capture_device->count() - 1);
+                }
+            }
+        }
+
+        /*V4lCaptureHandler v4lhandler(NULL);
+        QStringList deviceInfo = v4lhandler.getDeviceName(KdenliveSettings::video4vdevice());
+            capture_device->addItem(deviceInfo.at(0), "v4l");
+        capture_device->setItemData(capture_device->count() - 1, deviceInfo.at(3), Qt::UserRole + 1);*/
+        if (m_bmCapture == NULL) {
+            m_bmCapture = new V4lCaptureHandler(m_layout);
+            m_bmCapture->setDevice(capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 1).toString(), capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 2).toString());
+        }
+#endif
     }
 
-    connect(m_bmCapture, SIGNAL(frameSaved(const QString)), this, SLOT(slotNewThumb(const QString)));
     connect(capture_device, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateHandler()));
+    if (m_bmCapture) {
+        connect(m_bmCapture, SIGNAL(frameSaved(const QString)), this, SLOT(slotNewThumb(const QString)));
+    } else live_button->setEnabled(false);
     m_frame_preview = new MyLabel(this);
     connect(m_frame_preview, SIGNAL(seek(bool)), this, SLOT(slotSeekFrame(bool)));
+    connect(m_frame_preview, SIGNAL(switchToLive()), this, SLOT(slotSwitchLive()));
     m_layout->addWidget(m_frame_preview);
     m_frame_preview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
     video_preview->setLayout(m_layout);
@@ -196,47 +232,49 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, QWidget *parent) :
     button_addsequence->setEnabled(false);
     connect(live_button, SIGNAL(clicked(bool)), this, SLOT(slotLive(bool)));
     connect(button_addsequence, SIGNAL(clicked(bool)), this, SLOT(slotAddSequence()));
-    connect(preview_button, SIGNAL(clicked(bool)), this, SLOT(slotPlayPreview()));
+    connect(preview_button, SIGNAL(clicked(bool)), this, SLOT(slotPlayPreview(bool)));
     connect(frame_list, SIGNAL(currentRowChanged(int)), this, SLOT(slotShowSelectedFrame()));
+    connect(frame_list, SIGNAL(itemClicked(QListWidgetItem *)), this, SLOT(slotShowSelectedFrame()));
     connect(this, SIGNAL(doCreateThumbs(QImage, int)), this, SLOT(slotCreateThumbs(QImage, int)));
 
+    frame_list->addAction(removeCurrent);
+    frame_list->setContextMenuPolicy(Qt::ActionsContextMenu);
     frame_list->setHidden(!KdenliveSettings::showstopmotionthumbs());
     parseExistingSequences();
 }
 
 StopmotionWidget::~StopmotionWidget()
 {
-    m_bmCapture->stopPreview();
+    if (m_bmCapture)
+        m_bmCapture->stopPreview();
 }
 
 void StopmotionWidget::slotUpdateOverlayEffect(QAction *act)
 {
 #ifdef QIMAGEBLITZ
-    if(act) m_effectIndex = act->data().toInt();
+    if (act) m_effectIndex = act->data().toInt();
     KdenliveSettings::setBlitzeffect(m_effectIndex);
-    if(m_showOverlay->isChecked()) slotUpdateOverlay();
+    if (m_showOverlay->isChecked()) slotUpdateOverlay();
 #endif
 }
 
 void StopmotionWidget::closeEvent(QCloseEvent *e)
 {
     slotLive(false);
-    live_button->setChecked(false);
     QDialog::closeEvent(e);
 }
 
 void StopmotionWidget::slotSetCaptureInterval()
 {
     int interval = QInputDialog::getInteger(this, i18n("Set Capture Interval"), i18n("Interval (in seconds)"), KdenliveSettings::captureinterval(), 1);
-    if(interval > 0 && interval != KdenliveSettings::captureinterval())
+    if (interval > 0 && interval != KdenliveSettings::captureinterval())
         KdenliveSettings::setCaptureinterval(interval);
 }
 
 void StopmotionWidget::slotShowThumbs(bool show)
 {
     KdenliveSettings::setShowstopmotionthumbs(show);
-    kDebug() << "SHOW THUMBS: " << show;
-    if(show) {
+    if (show) {
         frame_list->clear();
         sequenceNameChanged(sequence_name->currentText());
     } else {
@@ -248,22 +286,28 @@ void StopmotionWidget::slotShowThumbs(bool show)
 
 void StopmotionWidget::slotIntervalCapture(bool capture)
 {
-    if(capture) slotCaptureFrame();
+    if (capture) slotCaptureFrame();
 }
 
 
 void StopmotionWidget::slotUpdateHandler()
 {
     QString data = capture_device->itemData(capture_device->currentIndex()).toString();
-    m_bmCapture->stopPreview();
-    delete m_bmCapture;
+    slotLive(false);
+    if (m_bmCapture) {
+        delete m_bmCapture;
+    }
     m_layout->removeWidget(m_frame_preview);
-    if(data == "v4l") {
+    if (data == "v4l") {
+#ifndef Q_WS_MAC
         m_bmCapture = new V4lCaptureHandler(m_layout);
+        m_bmCapture->setDevice(capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 1).toString(), capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 2).toString());
+#endif
     } else {
         m_bmCapture = new BmdCaptureHandler(m_layout);
-        connect(m_bmCapture, SIGNAL(gotMessage(const QString &)), this, SLOT(slotGotHDMIMessage(const QString &)));
+        if (m_bmCapture) connect(m_bmCapture, SIGNAL(gotMessage(const QString &)), this, SLOT(slotGotHDMIMessage(const QString &)));
     }
+    live_button->setEnabled(m_bmCapture != NULL);
     m_layout->addWidget(m_frame_preview);
 }
 
@@ -287,45 +331,62 @@ void StopmotionWidget::parseExistingSequences()
     }
 }
 
+void StopmotionWidget::slotSwitchLive()
+{
+    setUpdatesEnabled(false);
+    if (m_frame_preview->isHidden()) {
+        if (m_bmCapture) m_bmCapture->hidePreview(true);
+        m_frame_preview->setHidden(false);
+    } else {
+        m_frame_preview->setHidden(true);
+        if (m_bmCapture) m_bmCapture->hidePreview(false);
+        capture_button->setEnabled(true);
+    }
+    setUpdatesEnabled(true);
+}
+
 void StopmotionWidget::slotLive(bool isOn)
 {
-    if(isOn) {
-        m_frame_preview->setImage(QImage());
+    if (isOn && m_bmCapture) {
+        //m_frame_preview->setImage(QImage());
         m_frame_preview->setHidden(true);
-        m_bmCapture->startPreview(KdenliveSettings::hdmi_capturedevice(), KdenliveSettings::hdmi_capturemode());
+        m_bmCapture->startPreview(KdenliveSettings::hdmi_capturedevice(), KdenliveSettings::hdmi_capturemode(), false);
         capture_button->setEnabled(true);
     } else {
-        m_bmCapture->stopPreview();
+        if (m_bmCapture) m_bmCapture->stopPreview();
+        m_frame_preview->setHidden(false);
         capture_button->setEnabled(false);
+        live_button->setChecked(false);
     }
 }
 
 void StopmotionWidget::slotShowOverlay(bool isOn)
 {
-    if(isOn) {
-        if(live_button->isChecked() && m_sequenceFrame > 0) {
+    if (isOn) {
+        if (live_button->isChecked() && m_sequenceFrame > 0) {
             slotUpdateOverlay();
         }
-    } else {
+    } else if (m_bmCapture) {
         m_bmCapture->hideOverlay();
     }
 }
 
 void StopmotionWidget::slotUpdateOverlay()
 {
+    if (m_bmCapture == NULL) return;
     QString path = getPathForFrame(m_sequenceFrame - 1);
-    if(!QFile::exists(path)) return;
+    if (!QFile::exists(path)) return;
     QImage img(path);
-    if(img.isNull()) {
+    if (img.isNull()) {
         QTimer::singleShot(1000, this, SLOT(slotUpdateOverlay()));
         return;
     }
 
 #ifdef QIMAGEBLITZ
     //img = Blitz::convolveEdge(img, 0, Blitz::Low);
-    switch(m_effectIndex) {
+    switch (m_effectIndex) {
     case 2:
-        img = Blitz::contrast(img, true);
+        img = Blitz::contrast(img, true, 6);
         break;
     case 3:
         img = Blitz::edge(img);
@@ -337,7 +398,8 @@ void StopmotionWidget::slotUpdateOverlay()
         Blitz::invert(img);
         break;
     case 6:
-        img = Blitz::threshold(img, 200, Blitz::Grayscale, qRgba(255, 0, 0, 255), qRgba(0, 0, 0, 0));
+        img = Blitz::threshold(img, 120, Blitz::Grayscale, qRgba(0, 0, 0, 0), qRgba(255, 0, 0, 255));
+        //img = Blitz::flatten(img, QColor(255, 0, 0, 255), QColor(0, 0, 0, 0));
         break;
     default:
         break;
@@ -354,13 +416,13 @@ void StopmotionWidget::sequenceNameChanged(const QString &name)
     m_filesList.clear();
     m_future.waitForFinished();
     frame_list->clear();
-    if(name.isEmpty()) {
+    if (name.isEmpty()) {
         button_addsequence->setEnabled(false);
     } else {
         // Check if we are editing an existing sequence
         QString pattern = SlideshowClip::selectedPath(getPathForFrame(0, sequence_name->currentText()), false, QString(), &m_filesList);
         m_sequenceFrame = m_filesList.isEmpty() ? 0 : SlideshowClip::getFrameNumberFromPath(m_filesList.last()) + 1;
-        if(!m_filesList.isEmpty()) {
+        if (!m_filesList.isEmpty()) {
             m_sequenceName = sequence_name->currentText();
             connect(this, SIGNAL(doCreateThumbs(QImage, int)), this, SLOT(slotCreateThumbs(QImage, int)));
             m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs);
@@ -376,39 +438,39 @@ void StopmotionWidget::sequenceNameChanged(const QString &name)
 
 void StopmotionWidget::slotCaptureFrame()
 {
-    if(sequence_name->currentText().isEmpty()) {
+    if (m_bmCapture == NULL) return;
+    if (sequence_name->currentText().isEmpty()) {
         QString seqName = QInputDialog::getText(this, i18n("Create New Sequence"), i18n("Enter sequence name"));
-        if(seqName.isEmpty()) return;
+        if (seqName.isEmpty()) return;
         sequence_name->blockSignals(true);
         sequence_name->setItemText(sequence_name->currentIndex(), seqName);
         sequence_name->blockSignals(false);
     }
-    if(m_sequenceName != sequence_name->currentText()) {
+    if (m_sequenceName != sequence_name->currentText()) {
         m_sequenceName = sequence_name->currentText();
         m_sequenceFrame = 0;
     }
     //capture_button->setEnabled(false);
     QString currentPath = getPathForFrame(m_sequenceFrame);
-    kDebug() << "Capture FRame NB: " << m_sequenceFrame;
     m_bmCapture->captureFrame(currentPath);
     KNotification::event("FrameCaptured");
     m_sequenceFrame++;
     button_addsequence->setEnabled(true);
-    if(m_intervalCapture->isChecked()) QTimer::singleShot(KdenliveSettings::captureinterval() * 1000, this, SLOT(slotCaptureFrame()));
+    if (m_intervalCapture->isChecked()) QTimer::singleShot(KdenliveSettings::captureinterval() * 1000, this, SLOT(slotCaptureFrame()));
 }
 
 
 void StopmotionWidget::slotNewThumb(const QString path)
 {
-    if(!KdenliveSettings::showstopmotionthumbs()) return;
+    if (!KdenliveSettings::showstopmotionthumbs()) return;
     m_filesList.append(path);
-    if(m_showOverlay->isChecked()) slotUpdateOverlay();
-    if(!m_future.isRunning()) m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs);
+    if (m_showOverlay->isChecked()) slotUpdateOverlay();
+    if (!m_future.isRunning()) m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs);
 }
 
 void StopmotionWidget::slotPrepareThumbs()
 {
-    if(m_filesList.isEmpty()) return;
+    if (m_filesList.isEmpty()) return;
     QString path = m_filesList.takeFirst();
     emit doCreateThumbs(QImage(path), SlideshowClip::getFrameNumberFromPath(path));
 
@@ -416,7 +478,7 @@ void StopmotionWidget::slotPrepareThumbs()
 
 void StopmotionWidget::slotCreateThumbs(QImage img, int ix)
 {
-    if(img.isNull()) {
+    if (img.isNull()) {
         m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs);
         return;
     }
@@ -435,52 +497,37 @@ void StopmotionWidget::slotCreateThumbs(QImage img, int ix)
     QListWidgetItem *item = new QListWidgetItem(icon, QString(), frame_list);
     item->setToolTip(getPathForFrame(ix, sequence_name->currentText()));
     item->setData(Qt::UserRole, ix);
+    frame_list->blockSignals(true);
+    frame_list->setCurrentItem(item);
+    frame_list->blockSignals(false);
     m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs);
 }
 
 QString StopmotionWidget::getPathForFrame(int ix, QString seqName)
 {
-    if(seqName.isEmpty()) seqName = m_sequenceName;
+    if (seqName.isEmpty()) seqName = m_sequenceName;
     return m_projectFolder.path(KUrl::AddTrailingSlash) + seqName + "_" + QString::number(ix).rightJustified(4, '0', false) + ".png";
 }
 
-void StopmotionWidget::slotShowFrame(int ix)
+void StopmotionWidget::slotShowFrame(const QString &path)
 {
-    if(m_sequenceFrame == 0) {
-        //there are no images in sequence
-        return;
-    }
-    if(ix < m_sequenceFrame) {
-        // Show previous frame
-        slotLive(false);
-        live_button->setChecked(false);
-        QImage img(getPathForFrame(ix));
-        capture_button->setEnabled(false);
-        if(!img.isNull()) {
-            //m_bmCapture->showOverlay(img, false);
-            m_bmCapture->hidePreview(true);
-            m_frame_preview->setImage(img);
-            m_frame_preview->setHidden(false);
-            m_frame_preview->update();
-            selectFrame(ix);
-        }
+    //slotLive(false);
+    QImage img(path);
+    capture_button->setEnabled(false);
+    if (!img.isNull()) {
+        if (m_bmCapture) m_bmCapture->hidePreview(true);
+        m_frame_preview->setImage(img);
+        m_frame_preview->setHidden(false);
+        m_frame_preview->update();
     }
-    /*else {
-    slotLive(true);
-    m_frame_preview->setImage(QImage());
-    m_frame_preview->setHidden(true);
-    m_bmCapture->hideOverlay();
-    m_bmCapture->hidePreview(false);
-    capture_button->setEnabled(true);
-    }*/
 }
 
 void StopmotionWidget::slotShowSelectedFrame()
 {
     QListWidgetItem *item = frame_list->currentItem();
-    if(item) {
-        int ix = item->data(Qt::UserRole).toInt();;
-        //slotShowFrame(ix);
+    if (item) {
+        //int ix = item->data(Qt::UserRole).toInt();;
+        slotShowFrame(item->toolTip());
     }
 }
 
@@ -489,54 +536,64 @@ void StopmotionWidget::slotAddSequence()
     emit addOrUpdateSequence(getPathForFrame(0));
 }
 
-void StopmotionWidget::slotPlayPreview()
+void StopmotionWidget::slotPlayPreview(bool animate)
 {
-    if(m_animatedIndex != -1) {
+    if (!animate) {
         // stop animation
-        m_animatedIndex = -1;
+        m_animationList.clear();
         return;
     }
-    QListWidgetItem *item = frame_list->currentItem();
-    if(item) {
-        m_animatedIndex = item->data(Qt::UserRole).toInt();
+    if (KdenliveSettings::showstopmotionthumbs()) {
+        frame_list->setCurrentRow(0);
+        QTimer::singleShot(200, this, SLOT(slotAnimate()));
+    } else {
+        SlideshowClip::selectedPath(getPathForFrame(0, sequence_name->currentText()), false, QString(), &m_animationList);
+        slotAnimate();
     }
-    QTimer::singleShot(200, this, SLOT(slotAnimate()));
 }
 
 void StopmotionWidget::slotAnimate()
 {
-    slotShowFrame(m_animatedIndex);
-    m_animatedIndex++;
-    if(m_animatedIndex < m_sequenceFrame) QTimer::singleShot(200, this, SLOT(slotAnimate()));
-    else m_animatedIndex = -1;
+    //slotShowFrame(m_animatedIndex);
+    if (KdenliveSettings::showstopmotionthumbs()) {
+        //TODO: loop
+        if (frame_list->currentRow() < (frame_list->count() - 1)) {
+            frame_list->setCurrentRow(frame_list->currentRow() + 1);
+            QTimer::singleShot(100, this, SLOT(slotAnimate()));
+        } else preview_button->setChecked(false);
+    } else if (!m_animationList.isEmpty()) {
+        slotShowFrame(m_animationList.takeFirst());
+        QTimer::singleShot(100, this, SLOT(slotAnimate()));
+    } else preview_button->setChecked(false);
+
 }
 
 QListWidgetItem *StopmotionWidget::getFrameFromIndex(int ix)
 {
     QListWidgetItem *item = NULL;
     int pos = ix;
-    if(ix >= frame_list->count()) {
+    if (ix >= frame_list->count()) {
         pos = frame_list->count() - 1;
     }
-    if(ix < 0) pos = 0;
+    if (ix < 0) pos = 0;
     item = frame_list->item(pos);
 
     int value = item->data(Qt::UserRole).toInt();
-    if(value == ix) return item;
-    else if(value < ix) {
+    if (value == ix) return item;
+    else if (value < ix) {
         pos++;
-        while(pos < frame_list->count()) {
+        while (pos < frame_list->count()) {
             item = frame_list->item(pos);
             value = item->data(Qt::UserRole).toInt();
-            if(value == ix) return item;
+            if (value == ix) return item;
             pos++;
         }
     } else {
         pos --;
-        while(pos >= 0) {
+        while (pos >= 0) {
             item = frame_list->item(pos);
             value = item->data(Qt::UserRole).toInt();
-            if(value == ix) return item;
+            if (value == ix) return item;
             pos --;
         }
     }
@@ -548,7 +605,7 @@ void StopmotionWidget::selectFrame(int ix)
 {
     frame_list->blockSignals(true);
     QListWidgetItem *item = getFrameFromIndex(ix);
-    if(!item) return;
+    if (!item) return;
     frame_list->setCurrentItem(item);
     frame_list->blockSignals(false);
 }
@@ -556,9 +613,19 @@ void StopmotionWidget::selectFrame(int ix)
 void StopmotionWidget::slotSeekFrame(bool forward)
 {
     int ix = frame_list->currentRow();
-    if(forward) {
-        if(ix < frame_list->count() - 1) frame_list->setCurrentRow(ix + 1);
-    } else if(ix > 0) frame_list->setCurrentRow(ix - 1);
+    if (forward) {
+        if (ix < frame_list->count() - 1) frame_list->setCurrentRow(ix + 1);
+    } else if (ix > 0) frame_list->setCurrentRow(ix - 1);
 }
 
-
+void StopmotionWidget::slotRemoveFrame()
+{
+    if (frame_list->currentItem() == NULL) return;
+    QString path = frame_list->currentItem()->toolTip();
+    if (KMessageBox::questionYesNo(this, i18n("Delete frame %1 from disk?", path), i18n("Delete Frame")) != KMessageBox::Yes) return;
+    QFile f(path);
+    if (f.remove()) {
+        QListWidgetItem *item = frame_list->takeItem(frame_list->currentRow());
+        delete item;
+    }
+}