From f9394be680a8ac3c2ff8e39c9d8439eae5b55acc Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Tue, 19 Oct 2010 22:37:59 +0000 Subject: [PATCH] Progress on stopmotion widget (make it possible to switch between HDMI and V4L) svn path=/trunk/kdenlive/; revision=5024 --- src/kdenlivesettings.kcfg | 4 +- src/kdenlivesettingsdialog.cpp | 19 +- src/kdenlivesettingsdialog.h | 1 - src/mainwindow.cpp | 12 ++ src/projectlist.cpp | 44 ++--- src/recmonitor.cpp | 2 +- src/renderwidget.cpp | 1 - src/slideshowclip.cpp | 148 ++++++++------- src/slideshowclip.h | 4 +- src/stopmotion/stopmotion.cpp | 320 +++++++++++++++++--------------- src/stopmotion/stopmotion.h | 10 + src/widgets/configcapture_ui.ui | 4 +- 12 files changed, 307 insertions(+), 262 deletions(-) diff --git a/src/kdenlivesettings.kcfg b/src/kdenlivesettings.kcfg index 6c2d17e9..2f9444ce 100644 --- a/src/kdenlivesettings.kcfg +++ b/src/kdenlivesettings.kcfg @@ -614,12 +614,12 @@ false - + 0 - + 0 diff --git a/src/kdenlivesettingsdialog.cpp b/src/kdenlivesettingsdialog.cpp index 90c3d816..e4959223 100644 --- a/src/kdenlivesettingsdialog.cpp +++ b/src/kdenlivesettingsdialog.cpp @@ -168,11 +168,8 @@ KdenliveSettingsDialog::KdenliveSettingsDialog(QWidget * parent) : } - BMInterface::getBlackMagicDeviceList(m_configCapture.hdmi_list, m_configCapture.hdmi_capturemode); - connect(m_configCapture.hdmi_list, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateHDMIModes())); - connect(m_configCapture.hdmi_capturemode, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateHDMICaptureMode())); - m_configCapture.hdmi_list->setCurrentIndex(KdenliveSettings::hdmicapturedevice()); - m_configCapture.hdmi_capturemode->setCurrentIndex(KdenliveSettings::hdmicapturemode()); + BMInterface::getBlackMagicDeviceList(m_configCapture.kcfg_hdmi_capturedevice, m_configCapture.kcfg_hdmi_capturemode); + connect(m_configCapture.kcfg_hdmi_capturedevice, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateHDMIModes())); double dvgrabVersion = 0; if (!KdenliveSettings::dvgrab_path().isEmpty()) { @@ -208,15 +205,9 @@ KdenliveSettingsDialog::~KdenliveSettingsDialog() {} void KdenliveSettingsDialog::slotUpdateHDMIModes() { - QStringList modes = m_configCapture.hdmi_list->itemData(m_configCapture.hdmi_list->currentIndex()).toStringList(); - m_configCapture.hdmi_capturemode->clear(); - m_configCapture.hdmi_capturemode->insertItems(0, modes); - KdenliveSettings::setHdmicapturedevice(m_configCapture.hdmi_list->currentIndex()); -} - -void KdenliveSettingsDialog::slotUpdateHDMICaptureMode() -{ - KdenliveSettings::setHdmicapturemode(m_configCapture.hdmi_capturemode->currentIndex()); + QStringList modes = m_configCapture.kcfg_hdmi_capturedevice->itemData(m_configCapture.kcfg_hdmi_capturedevice->currentIndex()).toStringList(); + m_configCapture.kcfg_hdmi_capturemode->clear(); + m_configCapture.kcfg_hdmi_capturemode->insertItems(0, modes); } void KdenliveSettingsDialog::slotUpdateRmdRegionStatus() diff --git a/src/kdenlivesettingsdialog.h b/src/kdenlivesettingsdialog.h index 871dd905..2e265e47 100644 --- a/src/kdenlivesettingsdialog.h +++ b/src/kdenlivesettingsdialog.h @@ -67,7 +67,6 @@ private slots: void slotDialogModified(); void slotEnableCaptureFolder(); void slotUpdateHDMIModes(); - void slotUpdateHDMICaptureMode(); private: KPageWidgetItem *m_page1; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6da2caca..25942b19 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1967,6 +1967,12 @@ void MainWindow::doOpenFile(const KUrl &url, KAutoSaveFile *stale) if (!m_timelineArea->isEnabled()) return; m_fileRevert->setEnabled(true); + // Recreate stopmotion widget on document change + if (m_stopmotion) { + delete m_stopmotion; + m_stopmotion = NULL; + } + KProgressDialog progressDialog(this, i18n("Loading project"), i18n("Loading project")); progressDialog.setAllowCancel(false); progressDialog.progressBar()->setMaximum(4); @@ -2163,6 +2169,12 @@ void MainWindow::slotUpdateProjectProfile(const QString &profile) { double dar = m_activeDocument->dar(); + // Recreate the stopmotion widget if profile changes + if (m_stopmotion) { + delete m_stopmotion; + m_stopmotion = NULL; + } + // Deselect current effect / transition m_effectStack->slotClipItemSelected(NULL, 0); m_transitionConfig->slotTransitionItemSelected(NULL, 0, QPoint(), false); diff --git a/src/projectlist.cpp b/src/projectlist.cpp index b41fc50e..66cf7d75 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -1104,9 +1104,10 @@ void ProjectList::slotAddClip(const QList givenList, const QString &group if (fileName.at(fileName.size() - 1).isDigit()) { KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url); if (item.mimetype().startsWith("image")) { - int count = 0; // import as sequence if we found more than one image in the sequence - QString pattern = SlideshowClip::selectedPath(url.path(), false, QString(), &count); + QStringList list; + QString pattern = SlideshowClip::selectedPath(url.path(), false, QString(), &list); + int count = list.count(); if (count > 1) { delete d; QStringList groupInfo = getGroup(); @@ -1841,33 +1842,32 @@ void ProjectList::slotForceProcessing(const QString &id) void ProjectList::slotAddOrUpdateSequence(const QString frameName) { QString fileName = KUrl(frameName).fileName().section('_', 0, -2); - int count; - QString pattern = SlideshowClip::selectedPath(frameName, false, QString(), &count); + QStringList list; + QString pattern = SlideshowClip::selectedPath(frameName, false, QString(), &list); + int count = list.count(); if (count > 1) { - const QList existing = m_doc->clipManager()->getClipByResource(pattern); - if (!existing.isEmpty()) { - // Sequence already exists, update - QString id = existing.at(0)->getId(); - //ProjectItem *item = getItemById(id); + const QList existing = m_doc->clipManager()->getClipByResource(pattern); + if (!existing.isEmpty()) { + // Sequence already exists, update + QString id = existing.at(0)->getId(); + //ProjectItem *item = getItemById(id); QMap oldprops; QMap newprops; - int ttl = existing.at(0)->getProperty("ttl").toInt(); + int ttl = existing.at(0)->getProperty("ttl").toInt(); oldprops["out"] = existing.at(0)->getProperty("out"); newprops["out"] = QString::number(ttl * count - 1); - slotUpdateClipProperties(id, newprops); + slotUpdateClipProperties(id, newprops); EditClipCommand *command = new EditClipCommand(this, id, oldprops, newprops, false); m_commandStack->push(command); - } - else { - // Create sequence - QStringList groupInfo = getGroup(); - 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)); - } - } - else emit displayMessage(i18n("Sequence not found"), -2); + } else { + // Create sequence + QStringList groupInfo = getGroup(); + 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)); + } + } else emit displayMessage(i18n("Sequence not found"), -2); } #include "projectlist.moc" diff --git a/src/recmonitor.cpp b/src/recmonitor.cpp index bb1115ec..d917731d 100644 --- a/src/recmonitor.cpp +++ b/src/recmonitor.cpp @@ -456,7 +456,7 @@ void RecMonitor::slotStartCapture(bool play) case HDMI: video_capture->setVisible(true); video_frame->setHidden(true); - m_bmCapture->startPreview(KdenliveSettings::hdmicapturedevice(), KdenliveSettings::hdmicapturemode()); + m_bmCapture->startPreview(KdenliveSettings::hdmi_capturedevice(), KdenliveSettings::hdmi_capturemode()); m_playAction->setEnabled(false); m_stopAction->setEnabled(true); m_recAction->setEnabled(true); diff --git a/src/renderwidget.cpp b/src/renderwidget.cpp index 61e49c53..1b85df4e 100644 --- a/src/renderwidget.cpp +++ b/src/renderwidget.cpp @@ -176,7 +176,6 @@ RenderWidget::RenderWidget(const QString &projectfolder, QWidget * parent) : m_view.running_jobs->setItemDelegate(m_jobsDelegate); QHeaderView *header = m_view.running_jobs->header(); - QFontMetrics fm = fontMetrics(); header->setResizeMode(0, QHeaderView::Fixed); header->resizeSection(0, 30); header->setResizeMode(1, QHeaderView::Interactive); diff --git a/src/slideshowclip.cpp b/src/slideshowclip.cpp index dcdbd845..60c090c5 100644 --- a/src/slideshowclip.cpp +++ b/src/slideshowclip.cpp @@ -28,10 +28,10 @@ SlideshowClip::SlideshowClip(Timecode tc, QWidget * parent) : - QDialog(parent), - m_count(0), - m_timecode(tc), - m_thumbJob(NULL) + QDialog(parent), + m_count(0), + m_timecode(tc), + m_thumbJob(NULL) { setFont(KGlobalSettings::toolBarFont()); setWindowTitle(i18n("Add Slideshow Clip")); @@ -88,9 +88,9 @@ SlideshowClip::SlideshowClip(Timecode tc, QWidget * parent) : filters << "*.pgm" << "*.png"; QStringList customLumas = KGlobal::dirs()->findDirs("appdata", "lumas"); - foreach(const QString &folder, customLumas) { + foreach(const QString & folder, customLumas) { QStringList filesnames = QDir(folder).entryList(filters, QDir::Files); - foreach(const QString &fname, filesnames) { + foreach(const QString & fname, filesnames) { QString filePath = KUrl(folder).path(KUrl::AddTrailingSlash) + fname; m_view.luma_file->addItem(KIcon(filePath), fname, filePath); } @@ -102,7 +102,7 @@ SlideshowClip::SlideshowClip(Timecode tc, QWidget * parent) : folder.append("/lumas/PAL"); // TODO: cleanup the PAL / NTSC mess in luma files QDir lumafolder(folder); QStringList filesnames = lumafolder.entryList(filters, QDir::Files); - foreach(const QString &fname, filesnames) { + foreach(const QString & fname, filesnames) { QString filePath = KUrl(folder).path(KUrl::AddTrailingSlash) + fname; m_view.luma_file->addItem(KIcon(filePath), fname, filePath); } @@ -160,9 +160,11 @@ void SlideshowClip::slotEnableLumaFile(int state) int SlideshowClip::sequenceCount(KUrl file) { // find pattern + int count = 0; QString filter = file.fileName(); QString ext = filter.section('.', -1); filter = filter.section('.', 0, -2); + int fullSize = filter.size(); bool hasDigit = false; while (filter.at(filter.size() - 1).isDigit()) { hasDigit = true; @@ -170,15 +172,22 @@ int SlideshowClip::sequenceCount(KUrl file) } if (!hasDigit) return 0; - QString regexp = "^" + filter + "\\d+\\." + ext + "$"; - QRegExp rx(regexp); - - QDir dir(file.directory()); - QStringList result = dir.entryList(QDir::Files); - int count = 0; - foreach(const QString &path, result) { - if (rx.exactMatch(path)) count ++; + // Find number of digits in sequence + int precision = fullSize - filter.size(); + QString folder = file.directory(KUrl::AppendTrailingSlash); + // Check how many files we have + QDir dir(folder); + QString path; + int gap = 0; + for (int i = 0; gap < 100; i++) { + path = filter + QString::number(i).rightJustified(precision, '0', false) + ext; + if (dir.exists(path)) { + count ++; + gap = 0; + } else { + gap++; + } } return count; } @@ -191,6 +200,8 @@ void SlideshowClip::parseFolder() QDir dir(path); if (path.isEmpty() || !dir.exists()) return; + KIcon unknownicon("unknown"); + QStringList result; QStringList filters; QString filter; if (isMime) { @@ -198,41 +209,39 @@ void SlideshowClip::parseFolder() filter = m_view.image_type->itemData(m_view.image_type->currentIndex()).toString(); filters << "*." + filter; dir.setNameFilters(filters); - } - - QStringList result = dir.entryList(QDir::Files); - - if (!isMime) { + result = dir.entryList(QDir::Files); + } else { // find pattern filter = m_view.pattern_url->url().fileName(); QString ext = filter.section('.', -1); filter = filter.section('.', 0, -2); - + int fullSize = filter.size(); while (filter.at(filter.size() - 1).isDigit()) { filter.remove(filter.size() - 1, 1); } - QString regexp = "^" + filter + "\\d+\\." + ext + "$"; - QRegExp rx(regexp); - QStringList entries; - foreach(const QString &path, result) { - if (rx.exactMatch(path)) entries << path; + int precision = fullSize - filter.size(); + QString path; + int gap = 0; + for (int i = 0; gap < 100; i++) { + path = filter + QString::number(i).rightJustified(precision, '0', false) + ext; + if (dir.exists(path)) { + result.append(path); + gap = 0; + } else { + gap++; + } } - result = entries; } - - m_count = result.count(); - if (m_count == 0) m_view.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - else m_view.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); - m_view.label_info->setText(i18np("1 image found", "%1 images found", m_count)); QListWidgetItem *item; - int i = 0; - KIcon unknownicon("unknown"); - foreach(const QString &path, result) { - i++; + foreach(const QString & path, result) { item = new QListWidgetItem(unknownicon, KUrl(path).fileName()); item->setData(Qt::UserRole, dir.filePath(path)); m_view.icon_list->addItem(item); } + m_count = result.count(); + if (m_count == 0) m_view.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + else m_view.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + m_view.label_info->setText(i18np("1 image found", "%1 images found", m_count)); if (m_view.show_thumbs->isChecked()) slotGenerateThumbs(); m_view.icon_list->setCurrentRow(0); } @@ -276,15 +285,30 @@ void SlideshowClip::slotSetPixmap(const KFileItem &fileItem, const QPixmap &pix) QString SlideshowClip::selectedPath() { - return selectedPath(m_view.folder_url->url(), m_view.method_mime->isChecked(), ".all." + m_view.image_type->itemData(m_view.image_type->currentIndex()).toString(), &m_count); + QStringList list; + QString path = selectedPath(m_view.folder_url->url(), m_view.method_mime->isChecked(), ".all." + m_view.image_type->itemData(m_view.image_type->currentIndex()).toString(), &list); + m_count = list.count(); + return path; } + // static -QString SlideshowClip::selectedPath(KUrl url, bool isMime, QString extension, int *count) +int SlideshowClip::getFrameNumberFromPath(KUrl path) { - QString folder; + QString filter = path.fileName(); + filter = filter.section('.', 0, -2); + int ix = filter.size() - 1; + while (filter.at(ix).isDigit()) { + ix--; + } + return filter.remove(0, ix + 1).toInt(); +} +// static +QString SlideshowClip::selectedPath(KUrl url, bool isMime, QString extension, QStringList *list) +{ + QString folder; if (isMime) { folder = url.path(KUrl::AddTrailingSlash); } else { @@ -292,41 +316,31 @@ QString SlideshowClip::selectedPath(KUrl url, bool isMime, QString extension, in QString filter = url.fileName(); QString ext = '.' + filter.section('.', -1); filter = filter.section('.', 0, -2); + int fullSize = filter.size(); while (filter.at(filter.size() - 1).isDigit()) { filter.chop(1); } - // Check that the first image exists and which format it has (image1.jpg or image001.jpg, ...) - // Find first image in sequence - QString regexp = "^" + filter + "\\d+" + ext + "$"; - QRegExp rx(regexp); - QStringList entries; + // Find number of digits in sequence + int precision = fullSize - filter.size(); + // Check how many files we have QDir dir(folder); - QStringList result = dir.entryList(QDir::Files); - int precision = 1; - QString pathValue; - QMap sortedList; - foreach(const QString &path, result) { - if (rx.exactMatch(path)) { - pathValue = path.section('.', 0, -2); - pathValue.remove(0, filter.size()); - sortedList.insert(pathValue.toInt(), path); + QString path; + int gap = 0; + for (int i = 0; gap < 100; i++) { + path = filter + QString::number(i).rightJustified(precision, '0', false) + ext; + if (dir.exists(path)) { + (*list).append(folder + path); + gap = 0; + } else { + gap++; } } - *count = sortedList.size(); - if (*count == 0) kDebug() << "No IMAGE FOUND!!!!!!!"; - else { - QMapIterator i(sortedList); - i.next(); - QString result = i.value(); - result.remove(0, filter.size()); - result = result.section('.', 0, -2); - precision = result.size(); - } extension = filter + "%." + QString::number(precision) + "d" + ext; } + kDebug() << "// FOUND " << (*list).count() << " items for " << url.path(); return folder + extension; } @@ -418,15 +432,15 @@ void SlideshowClip::slotMethodChanged(bool active) if (active) { // User wants mimetype image sequence if (m_view.clip_duration->text().isEmpty()) { - m_view.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::image_duration())); - } + m_view.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::image_duration())); + } m_view.stackedWidget->setCurrentIndex(0); KdenliveSettings::setSlideshowbymime(true); } else { // User wants pattern image sequence if (m_view.clip_duration->text().isEmpty()) { - m_view.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::sequence_duration())); - } + m_view.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::sequence_duration())); + } m_view.stackedWidget->setCurrentIndex(1); KdenliveSettings::setSlideshowbymime(false); } diff --git a/src/slideshowclip.h b/src/slideshowclip.h index 36ba0a2a..69fc496f 100644 --- a/src/slideshowclip.h +++ b/src/slideshowclip.h @@ -51,8 +51,10 @@ public: /** @brief Check if there are several files with filename pattern, like: image_001.jpg, image_002.jpg,... */ static int sequenceCount(KUrl file); + /** @brief Get the image frame number from a file path, for example image_047.jpg will return 47. */ + static int getFrameNumberFromPath(KUrl path); /** @brief return the url pattern for selected slideshow. */ - static QString selectedPath(KUrl url, bool isMime, QString extension, int *count); + static QString selectedPath(KUrl url, bool isMime, QString extension, QStringList *list); /** @brief Convert the selection animation style into an affine geometry string. */ static QString animationToGeometry(const QString &animation, int &ttl); diff --git a/src/stopmotion/stopmotion.cpp b/src/stopmotion/stopmotion.cpp index db1244c5..c11ddc56 100644 --- a/src/stopmotion/stopmotion.cpp +++ b/src/stopmotion/stopmotion.cpp @@ -40,7 +40,7 @@ #include MyLabel::MyLabel(QWidget *parent) : - QLabel(parent) + QLabel(parent) { } @@ -57,7 +57,7 @@ void MyLabel::wheelEvent(QWheelEvent * event) } //virtual -void MyLabel::paintEvent( QPaintEvent * event) +void MyLabel::paintEvent(QPaintEvent * event) { Q_UNUSED(event); @@ -70,8 +70,8 @@ void MyLabel::paintEvent( QPaintEvent * event) int calculatedWidth = aspect_ratio * height(); if (calculatedWidth > width()) pictureHeight = width() / aspect_ratio; else { - int calculatedHeight = width() / aspect_ratio; - if (calculatedHeight > height()) pictureWidth = height() * aspect_ratio; + int calculatedHeight = width() / 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(); @@ -79,12 +79,12 @@ void MyLabel::paintEvent( QPaintEvent * event) StopmotionWidget::StopmotionWidget(KUrl projectFolder, QWidget *parent) : - QDialog(parent) - , Ui::Stopmotion_UI() - , m_projectFolder(projectFolder) - , m_bmCapture(NULL) - , m_sequenceFrame(0) - , m_animatedIndex(-1) + QDialog(parent) + , Ui::Stopmotion_UI() + , m_projectFolder(projectFolder) + , m_bmCapture(NULL) + , m_sequenceFrame(0) + , m_animatedIndex(-1) { setupUi(this); setWindowTitle(i18n("Stop Motion Capture")); @@ -96,7 +96,7 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, QWidget *parent) : m_captureAction->setShortcut(QKeySequence(Qt::Key_Space)); connect(m_captureAction, SIGNAL(triggered()), this, SLOT(slotCaptureFrame())); capture_button->setDefaultAction(m_captureAction); - + preview_button->setIcon(KIcon("media-playback-start")); removelast_button->setIcon(KIcon("edit-delete")); frameoverlay_button->setEnabled(false); @@ -104,23 +104,22 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, QWidget *parent) : capture_button->setEnabled(false); connect(sequence_name, SIGNAL(textChanged(const QString &)), this, SLOT(sequenceNameChanged(const QString &))); - QVBoxLayout *lay = new QVBoxLayout; + m_layout = new QVBoxLayout; if (BMInterface::getBlackMagicDeviceList(capture_device, NULL)) { - // Found a BlackMagic device - kDebug()<<"CREATE BM DEVICE"; - m_bmCapture = new BmdCaptureHandler(lay); - connect(m_bmCapture, SIGNAL(gotMessage(const QString &)), this, SLOT(slotGotHDMIMessage(const QString &))); + // Found a BlackMagic device + m_bmCapture = new BmdCaptureHandler(m_layout); + connect(m_bmCapture, SIGNAL(gotMessage(const QString &)), this, SLOT(slotGotHDMIMessage(const QString &))); } - else { - kDebug()<<"CREATE V4L DEVICE"; - m_bmCapture = new V4lCaptureHandler(lay); - capture_device->addItem(KdenliveSettings::video4vdevice()); + if (QFile::exists(KdenliveSettings::video4vdevice())) { + if (m_bmCapture == NULL) m_bmCapture = new V4lCaptureHandler(m_layout); + capture_device->addItem(KdenliveSettings::video4vdevice(), "v4l"); } + connect(capture_device, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateHandler())); m_frame_preview = new MyLabel(this); connect(m_frame_preview, SIGNAL(seek(bool)), this, SLOT(slotSeekFrame(bool))); - lay->addWidget(m_frame_preview); + m_layout->addWidget(m_frame_preview); m_frame_preview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - video_preview->setLayout(lay); + video_preview->setLayout(m_layout); live_button->setChecked(false); frameoverlay_button->setChecked(false); button_addsequence->setEnabled(false); @@ -130,8 +129,8 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, QWidget *parent) : connect(button_addsequence, SIGNAL(clicked(bool)), this, SLOT(slotAddSequence())); connect(preview_button, SIGNAL(clicked(bool)), this, SLOT(slotPlayPreview())); connect(frame_list, SIGNAL(currentRowChanged(int)), this, SLOT(slotShowSelectedFrame())); - connect(this, SIGNAL(doCreateThumbs(QImage, int)), this, SLOT(slotCreateThumbs(QImage,int))); - + connect(this, SIGNAL(doCreateThumbs(QImage, int)), this, SLOT(slotCreateThumbs(QImage, int))); + parseExistingSequences(); } @@ -140,6 +139,21 @@ StopmotionWidget::~StopmotionWidget() m_bmCapture->stopPreview(); } +void StopmotionWidget::slotUpdateHandler() +{ + QString data = capture_device->itemData(capture_device->currentIndex()).toString(); + m_bmCapture->stopPreview(); + delete m_bmCapture; + m_layout->removeWidget(m_frame_preview); + if (data == "v4l") { + m_bmCapture = new V4lCaptureHandler(m_layout); + } else { + m_bmCapture = new BmdCaptureHandler(m_layout); + connect(m_bmCapture, SIGNAL(gotMessage(const QString &)), this, SLOT(slotGotHDMIMessage(const QString &))); + } + m_layout->addWidget(m_frame_preview); +} + void StopmotionWidget::slotGotHDMIMessage(const QString &message) { log_box->insertItem(0, message); @@ -156,33 +170,31 @@ void StopmotionWidget::parseExistingSequences() QStringList sequences = dir.entryList(filters, QDir::Files, QDir::Name); //kDebug()<<"PF: "<<<<", sm: "<addItem(sequencename.section("_", 0, -2)); + sequence_name->addItem(sequencename.section("_", 0, -2)); } } void StopmotionWidget::slotLive(bool isOn) { if (isOn) { - m_frame_preview->setImage(QImage()); - m_frame_preview->setHidden(true); - m_bmCapture->startPreview(KdenliveSettings::hdmicapturedevice(), KdenliveSettings::hdmicapturemode()); - capture_button->setEnabled(true); - } - else { - m_bmCapture->stopPreview(); - capture_button->setEnabled(false); + m_frame_preview->setImage(QImage()); + m_frame_preview->setHidden(true); + m_bmCapture->startPreview(KdenliveSettings::hdmi_capturedevice(), KdenliveSettings::hdmi_capturemode()); + capture_button->setEnabled(true); + } else { + m_bmCapture->stopPreview(); + capture_button->setEnabled(false); } } void StopmotionWidget::slotShowOverlay(bool isOn) { if (isOn) { - if (live_button->isChecked() && m_sequenceFrame > 0) { - slotUpdateOverlay(); - } - } - else { - m_bmCapture->hideOverlay(); + if (live_button->isChecked() && m_sequenceFrame > 0) { + slotUpdateOverlay(); + } + } else { + m_bmCapture->hideOverlay(); } } @@ -192,8 +204,8 @@ void StopmotionWidget::slotUpdateOverlay() if (!QFile::exists(path)) return; QImage img(path); if (img.isNull()) { - QTimer::singleShot(1000, this, SLOT(slotUpdateOverlay())); - return; + QTimer::singleShot(1000, this, SLOT(slotUpdateOverlay())); + return; } m_bmCapture->showOverlay(img); } @@ -201,60 +213,52 @@ void StopmotionWidget::slotUpdateOverlay() void StopmotionWidget::sequenceNameChanged(const QString &name) { // Get rid of frames from previous sequence - disconnect(this, SIGNAL(doCreateThumbs(QImage, int)), this, SLOT(slotCreateThumbs(QImage,int))); + disconnect(this, SIGNAL(doCreateThumbs(QImage, int)), this, SLOT(slotCreateThumbs(QImage, int))); m_filesList.clear(); m_future.waitForFinished(); frame_list->clear(); if (name.isEmpty()) { - button_addsequence->setEnabled(false); - frame_number->blockSignals(true); - frame_number->setValue(m_sequenceFrame); - frame_number->blockSignals(false); - frameoverlay_button->setEnabled(false); - removelast_button->setEnabled(false); - } - else { - // Check if we are editing an existing sequence - int count = 0; - QString pattern = SlideshowClip::selectedPath(getPathForFrame(0, sequence_name->currentText()), false, QString(), &count); - m_sequenceFrame = count; - frame_number->blockSignals(true); - frame_number->setValue(0); - frame_number->blockSignals(false); - m_currentIndex = 0; - if (count > 0) { - m_sequenceName = sequence_name->currentText(); - //TODO: Do the thumbnail stuff in a thread - for (int i = 0; i < count; i++) { - //slotUpdateFrameList(i); - m_filesList.append(getPathForFrame(i)); - } - connect(this, SIGNAL(doCreateThumbs(QImage, int)), this, SLOT(slotCreateThumbs(QImage,int))); - m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs); - button_addsequence->setEnabled(true); - frameoverlay_button->setEnabled(true); - } - else { - button_addsequence->setEnabled(false); - frameoverlay_button->setEnabled(false); - } - frame_number->setRange(0, m_sequenceFrame); - capture_button->setEnabled(true); + button_addsequence->setEnabled(false); + frame_number->blockSignals(true); + frame_number->setValue(m_sequenceFrame); + frame_number->blockSignals(false); + frameoverlay_button->setEnabled(false); + removelast_button->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.size(); + frame_number->blockSignals(true); + frame_number->setValue(0); + frame_number->blockSignals(false); + m_currentIndex = 0; + 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); + button_addsequence->setEnabled(true); + frameoverlay_button->setEnabled(true); + } else { + button_addsequence->setEnabled(false); + frameoverlay_button->setEnabled(false); + } + frame_number->setRange(0, m_sequenceFrame); + capture_button->setEnabled(true); } } void StopmotionWidget::slotCaptureFrame() { if (sequence_name->currentText().isEmpty()) { - QString seqName = QInputDialog::getText(this, i18n("Create New Sequence"), i18n("Enter sequence name")); - if (seqName.isEmpty()) return; - sequence_name->blockSignals(true); - sequence_name->setItemText(sequence_name->currentIndex(), seqName); - sequence_name->blockSignals(false); + QString seqName = QInputDialog::getText(this, i18n("Create New Sequence"), i18n("Enter sequence name")); + 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()) { - m_sequenceName = sequence_name->currentText(); - m_sequenceFrame = 0; + m_sequenceName = sequence_name->currentText(); + m_sequenceFrame = 0; } capture_button->setEnabled(false); m_bmCapture->captureFrame(getPathForFrame(m_sequenceFrame)); @@ -274,15 +278,15 @@ void StopmotionWidget::slotPrepareThumbs() { if (m_filesList.isEmpty()) return; QString path = m_filesList.takeFirst(); - emit doCreateThumbs(QImage(path), m_currentIndex++); - + emit doCreateThumbs(QImage(path), SlideshowClip::getFrameNumberFromPath(path)); + } void StopmotionWidget::slotCreateThumbs(QImage img, int ix) { if (img.isNull()) { - m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs); - return; + m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs); + return; } int height = 90; int width = height * img.width() / img.height(); @@ -297,23 +301,24 @@ void StopmotionWidget::slotCreateThumbs(QImage img, int ix) p.end(); QIcon icon(pix); QListWidgetItem *item = new QListWidgetItem(icon, QString(), frame_list); + item->setToolTip(getPathForFrame(ix, sequence_name->currentText())); item->setData(Qt::UserRole, ix); m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs); } void StopmotionWidget::slotUpdateFrameList(int ix) { - kDebug()<< "// GET FRAME: "<setEnabled(true); - return; + capture_button->setEnabled(true); + return; } QImage img(path); if (img.isNull()) { - if (ix == m_sequenceFrame - 1) QTimer::singleShot(1000, this, SLOT(slotUpdateFrameList())); - return; + if (ix == m_sequenceFrame - 1) QTimer::singleShot(1000, this, SLOT(slotUpdateFrameList())); + return; } int height = 90; int width = height * img.width() / img.height(); @@ -329,6 +334,9 @@ void StopmotionWidget::slotUpdateFrameList(int ix) QIcon icon(pix); QListWidgetItem *item = new QListWidgetItem(icon, QString(), frame_list); item->setData(Qt::UserRole, ix); + frame_list->blockSignals(true); + frame_list->setCurrentItem(item); + frame_list->blockSignals(true); capture_button->setEnabled(true); } @@ -341,46 +349,46 @@ QString StopmotionWidget::getPathForFrame(int ix, QString seqName) void StopmotionWidget::slotShowFrame(int ix) { if (m_sequenceFrame == 0) { - //there are no images in sequence - return; + //there are no images in sequence + return; } frameoverlay_button->blockSignals(true); frameoverlay_button->setChecked(false); frameoverlay_button->blockSignals(false); 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); - } + // 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); + } } /*else { - slotLive(true); - m_frame_preview->setImage(QImage()); - m_frame_preview->setHidden(true); - m_bmCapture->hideOverlay(); - m_bmCapture->hidePreview(false); - capture_button->setEnabled(true); - }*/ + 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(); - //frame_number->blockSignals(true); - frame_number->setValue(ix); - //frame_number->blockSignals(false); - //slotShowFrame(ix); + int ix = item->data(Qt::UserRole).toInt(); + //frame_number->blockSignals(true); + frame_number->setValue(ix); + //frame_number->blockSignals(false); + //slotShowFrame(ix); } } @@ -392,13 +400,13 @@ void StopmotionWidget::slotAddSequence() void StopmotionWidget::slotPlayPreview() { if (m_animatedIndex != -1) { - // stop animation - m_animatedIndex = -1; - return; + // stop animation + m_animatedIndex = -1; + return; } QListWidgetItem *item = frame_list->currentItem(); if (item) { - m_animatedIndex = item->data(Qt::UserRole).toInt(); + m_animatedIndex = item->data(Qt::UserRole).toInt(); } QTimer::singleShot(200, this, SLOT(slotAnimate())); } @@ -411,34 +419,45 @@ void StopmotionWidget::slotAnimate() else m_animatedIndex = -1; } -void StopmotionWidget::selectFrame(int ix) +QListWidgetItem *StopmotionWidget::getFrameFromIndex(int ix) { - frame_list->blockSignals(true); - QListWidgetItem *item = frame_list->item(ix); - int current = item->data(Qt::UserRole).toInt(); - if (current == ix) { - frame_list->setCurrentItem(item); - } - else if (current < ix) { - for (int i = ix; i < frame_list->count(); i++) { - item = frame_list->item(i); - current = item->data(Qt::UserRole).toInt(); - if (current == ix) { - frame_list->setCurrentItem(item); - break; - } - } + QListWidgetItem *item = NULL; + int pos = ix; + if (ix >= frame_list->count()) { + pos = frame_list->count() - 1; } - else { - for (int i = ix; i >= 0; i--) { - item = frame_list->item(i); - current = item->data(Qt::UserRole).toInt(); - if (current == ix) { - frame_list->setCurrentItem(item); - break; - } - } + 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) { + pos++; + while (pos < frame_list->count()) { + item = frame_list->item(pos); + value = item->data(Qt::UserRole).toInt(); + if (value == ix) return item; + pos++; + } + } else { + pos --; + while (pos >= 0) { + item = frame_list->item(pos); + value = item->data(Qt::UserRole).toInt(); + if (value == ix) return item; + pos --; + } } + return NULL; +} + + +void StopmotionWidget::selectFrame(int ix) +{ + frame_list->blockSignals(true); + QListWidgetItem *item = getFrameFromIndex(ix); + if (!item) return; + frame_list->setCurrentItem(item); frame_list->blockSignals(false); } @@ -446,9 +465,8 @@ 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 (ix < frame_list->count() - 1) frame_list->setCurrentRow(ix + 1); + } else if (ix > 0) frame_list->setCurrentRow(ix - 1); } diff --git a/src/stopmotion/stopmotion.h b/src/stopmotion/stopmotion.h index eab6c9d1..2976a3bd 100644 --- a/src/stopmotion/stopmotion.h +++ b/src/stopmotion/stopmotion.h @@ -24,6 +24,7 @@ #include #include #include +#include class MyLabel : public QLabel { @@ -62,6 +63,9 @@ protected: private: + /** @brief Widget layout holding video and frame preview. */ + QVBoxLayout *m_layout; + /** @brief Current project folder (where the captured frames will be saved). */ KUrl m_projectFolder; @@ -97,6 +101,9 @@ private: /** @brief Holds the state of the threaded thumbnail generation. */ QFuture m_future; + + /** @brief Get the frame number ix. */ + QListWidgetItem *getFrameFromIndex(int ix); private slots: /** @brief Display the live feed from capture device. @@ -152,6 +159,9 @@ private slots: /** @brief Prepare thumbnails creation. */ void slotPrepareThumbs(); + /** @brief Called when user switches the video capture backend. */ + void slotUpdateHandler(); + signals: /** @brief Ask to add sequence to current project. */ void addOrUpdateSequence(const QString); diff --git a/src/widgets/configcapture_ui.ui b/src/widgets/configcapture_ui.ui index 9f4f97e3..66bc1530 100644 --- a/src/widgets/configcapture_ui.ui +++ b/src/widgets/configcapture_ui.ui @@ -798,7 +798,7 @@ - + 0 @@ -815,7 +815,7 @@ - + -- 2.39.2