1 /***************************************************************************
2 * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
22 #include "smallruler.h"
23 #include "docclipbase.h"
24 #include "abstractclipitem.h"
25 #include "monitorscene.h"
26 #include "widgets/monitoreditwidget.h"
27 #include "kdenlivesettings.h"
30 #include <KLocalizedString>
31 #include <KFileDialog>
32 #include <KApplication>
33 #include <KMessageBox>
34 #include <KSelectAction>
36 #include <QMouseEvent>
37 #include <QStylePainter>
39 #include <QToolButton>
41 #include <QDesktopWidget>
43 #include <QIntValidator>
44 #include <QVBoxLayout>
48 #define SEEK_INACTIVE (-1)
51 Monitor::Monitor(Kdenlive::MonitorId id, MonitorManager *manager, QString profile, QWidget *parent) :
52 AbstractMonitor(id, manager, parent)
58 , m_dragStarted(false)
59 , m_loopClipAction(NULL)
61 , m_effectWidget(NULL)
62 , m_selectedClip(NULL)
63 , m_loopClipTransition(true)
67 QVBoxLayout *layout = new QVBoxLayout;
68 layout->setContentsMargins(0, 0, 0, 0);
69 layout->setSpacing(0);
71 // Video widget holder
72 layout->addWidget(videoBox, 10);
75 // Get base size for icons
76 int s = style()->pixelMetric(QStyle::PM_SmallIconSize);
80 m_toolbar = new QToolBar(this);
81 m_toolbar->setIconSize(QSize(s, s));
83 m_playIcon = KIcon("media-playback-start");
84 m_pauseIcon = KIcon("media-playback-pause");
87 if (id != Kdenlive::DvdMonitor) {
88 m_toolbar->addAction(KIcon("kdenlive-zone-start"), i18n("Set zone start"), this, SLOT(slotSetZoneStart()));
89 m_toolbar->addAction(KIcon("kdenlive-zone-end"), i18n("Set zone end"), this, SLOT(slotSetZoneEnd()));
92 m_toolbar->addAction(KIcon("media-seek-backward"), i18n("Rewind"), this, SLOT(slotRewind()));
93 //m_toolbar->addAction(KIcon("media-skip-backward"), i18n("Rewind 1 frame"), this, SLOT(slotRewindOneFrame()));
95 QToolButton *playButton = new QToolButton(m_toolbar);
96 m_playMenu = new QMenu(i18n("Play..."), this);
97 m_playAction = m_playMenu->addAction(m_playIcon, i18n("Play"));
98 //m_playAction->setCheckable(true);
99 connect(m_playAction, SIGNAL(triggered()), this, SLOT(slotPlay()));
101 playButton->setMenu(m_playMenu);
102 playButton->setPopupMode(QToolButton::MenuButtonPopup);
103 m_toolbar->addWidget(playButton);
105 //m_toolbar->addAction(KIcon("media-skip-forward"), i18n("Forward 1 frame"), this, SLOT(slotForwardOneFrame()));
106 m_toolbar->addAction(KIcon("media-seek-forward"), i18n("Forward"), this, SLOT(slotForward()));
108 playButton->setDefaultAction(m_playAction);
110 if (id != Kdenlive::DvdMonitor) {
111 QToolButton *configButton = new QToolButton(m_toolbar);
112 m_configMenu = new QMenu(i18n("Misc..."), this);
113 configButton->setIcon(KIcon("system-run"));
114 configButton->setMenu(m_configMenu);
115 configButton->setPopupMode(QToolButton::QToolButton::InstantPopup);
116 m_toolbar->addWidget(configButton);
118 if (id == Kdenlive::ClipMonitor) {
119 m_markerMenu = new QMenu(i18n("Go to marker..."), this);
120 m_markerMenu->setEnabled(false);
121 m_configMenu->addMenu(m_markerMenu);
122 connect(m_markerMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotGoToMarker(QAction*)));
124 m_configMenu->addAction(KIcon("transform-scale"), i18n("Resize (100%)"), this, SLOT(slotSetSizeOneToOne()));
125 m_configMenu->addAction(KIcon("transform-scale"), i18n("Resize (50%)"), this, SLOT(slotSetSizeOneToTwo()));
128 // Create Volume slider popup
129 m_volumePopup = new QFrame(this, Qt::Popup);
130 QVBoxLayout *poplayout = new QVBoxLayout;
131 poplayout->setContentsMargins(0, 0, 0, 0);
132 m_audioSlider = new QSlider(Qt::Vertical);
133 m_audioSlider->setRange(0, 100);
134 poplayout->addWidget(m_audioSlider);
135 m_volumePopup->setLayout(poplayout);
137 if (KdenliveSettings::volume() == 0) icon = KIcon("audio-volume-muted");
138 else icon = KIcon("audio-volume-medium");
140 m_volumeWidget = m_toolbar->widgetForAction(m_toolbar->addAction(icon, i18n("Audio volume"), this, SLOT(slotShowVolume())));
142 // we need to show / hide the popup once so that it's geometry can be calculated in slotShowVolume
143 m_volumePopup->show();
144 m_volumePopup->hide();
146 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
148 setMinimumHeight(200);
150 if (profile.isEmpty())
151 profile = KdenliveSettings::current_profile();
153 createOpenGlWidget(videoBox, profile);
154 QVBoxLayout *lay = new QVBoxLayout;
155 lay->setContentsMargins(0, 0, 0, 0);
156 lay->addWidget(m_glWidget);
157 videoBox->setLayout(lay);
160 m_ruler = new SmallRuler(this, render);
161 if (id == Kdenlive::DvdMonitor) m_ruler->setZone(-3, -2);
162 layout->addWidget(m_ruler);
164 connect(m_audioSlider, SIGNAL(valueChanged(int)), this, SLOT(slotSetVolume(int)));
165 connect(render, SIGNAL(durationChanged(int)), this, SLOT(adjustRulerSize(int)));
166 connect(render, SIGNAL(rendererStopped(int)), this, SLOT(rendererStopped(int)));
167 connect(render, SIGNAL(rendererPosition(int)), this, SLOT(seekCursor(int)));
169 if (id != Kdenlive::ClipMonitor) {
170 connect(render, SIGNAL(rendererPosition(int)), this, SIGNAL(renderPosition(int)));
171 connect(render, SIGNAL(durationChanged(int)), this, SIGNAL(durationChanged(int)));
172 connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SIGNAL(zoneUpdated(QPoint)));
174 connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SLOT(setClipZone(QPoint)));
177 if (id == Kdenlive::ProjectMonitor) {
178 m_effectWidget = new MonitorEditWidget(render, videoBox);
179 connect(m_effectWidget, SIGNAL(showEdit(bool,bool)), this, SLOT(slotShowEffectScene(bool,bool)));
180 m_toolbar->addAction(m_effectWidget->getVisibilityAction());
181 videoBox->layout()->addWidget(m_effectWidget);
182 m_effectWidget->hide();
185 QWidget *spacer = new QWidget(this);
186 spacer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
187 m_toolbar->addWidget(spacer);
188 m_timePos = new TimecodeDisplay(m_monitorManager->timecode(), this);
189 m_toolbar->addWidget(m_timePos);
190 connect(m_timePos, SIGNAL(timeCodeEditingFinished()), this, SLOT(slotSeek()));
191 m_toolbar->setMaximumHeight(m_timePos->height());
192 layout->addWidget(m_toolbar);
201 delete m_effectWidget;
205 QWidget *Monitor::container()
210 void Monitor::createOpenGlWidget(QWidget *parent, const QString &profile)
212 render = new Render(id(), 0, profile, this);
213 m_glWidget = new VideoGLWidget(parent);
214 if (m_glWidget == NULL) {
215 // Creation failed, we are in trouble...
216 QMessageBox::critical(this, i18n("Missing OpenGL support"),
217 i18n("You need working OpenGL support to run Kdenlive. Exiting."));
220 m_glWidget->setImageAspectRatio(render->dar());
221 m_glWidget->setBackgroundColor(KdenliveSettings::window_background());
222 connect(render, SIGNAL(showImageSignal(QImage)), m_glWidget, SLOT(showImage(QImage)));
225 void Monitor::setupMenu(QMenu *goMenu, QAction *playZone, QAction *loopZone, QMenu *markerMenu, QAction *loopClip)
227 m_contextMenu = new QMenu(this);
228 m_contextMenu->addMenu(m_playMenu);
230 m_contextMenu->addMenu(goMenu);
232 m_contextMenu->addMenu(markerMenu);
233 QList <QAction *>list = markerMenu->actions();
234 for (int i = 0; i < list.count(); ++i) {
235 if (list.at(i)->data().toString() == "edit_marker") {
236 m_editMarker = list.at(i);
242 m_playMenu->addAction(playZone);
243 m_playMenu->addAction(loopZone);
245 m_loopClipAction = loopClip;
246 m_playMenu->addAction(loopClip);
249 //TODO: add save zone to timeline monitor when fixed
250 if (m_id == Kdenlive::ClipMonitor) {
251 m_contextMenu->addMenu(m_markerMenu);
252 m_contextMenu->addAction(KIcon("document-save"), i18n("Save zone"), this, SLOT(slotSaveZone()));
253 QAction *extractZone = m_configMenu->addAction(KIcon("document-new"), i18n("Extract Zone"), this, SLOT(slotExtractCurrentZone()));
254 m_contextMenu->addAction(extractZone);
256 QAction *extractFrame = m_configMenu->addAction(KIcon("document-new"), i18n("Extract frame"), this, SLOT(slotExtractCurrentFrame()));
257 m_contextMenu->addAction(extractFrame);
259 if (m_id != Kdenlive::ClipMonitor) {
260 QAction *splitView = m_contextMenu->addAction(KIcon("view-split-left-right"), i18n("Split view"), render, SLOT(slotSplitView(bool)));
261 splitView->setCheckable(true);
262 m_configMenu->addAction(splitView);
264 QAction *setThumbFrame = m_contextMenu->addAction(KIcon("document-new"), i18n("Set current image as thumbnail"), this, SLOT(slotSetThumbFrame()));
265 m_configMenu->addAction(setThumbFrame);
268 QAction *showTips = m_contextMenu->addAction(KIcon("help-hint"), i18n("Monitor overlay infos"));
269 showTips->setCheckable(true);
270 connect(showTips, SIGNAL(toggled(bool)), this, SLOT(slotSwitchMonitorInfo(bool)));
271 showTips->setChecked(KdenliveSettings::displayMonitorInfo());
273 QAction *dropFrames = m_contextMenu->addAction(KIcon(), i18n("Real time (drop frames)"));
274 dropFrames->setCheckable(true);
275 dropFrames->setChecked(true);
276 connect(dropFrames, SIGNAL(toggled(bool)), this, SLOT(slotSwitchDropFrames(bool)));
278 m_configMenu->addAction(showTips);
279 m_configMenu->addAction(dropFrames);
282 void Monitor::slotGoToMarker(QAction *action)
284 int pos = action->data().toInt();
288 void Monitor::slotSetSizeOneToOne()
290 QRect r = QApplication::desktop()->screenGeometry();
291 const int maxWidth = r.width() - 20;
292 const int maxHeight = r.height() - 20;
293 int width = render->renderWidth();
294 int height = render->renderHeight();
295 kDebug() << "// render info: " << width << "x" << height;
296 while (width >= maxWidth || height >= maxHeight) {
298 height = height * 0.8;
300 kDebug() << "// MONITOR; set SIZE: " << width << ", " << height;
301 videoBox->setFixedSize(width, height);
304 //m_ui.video_frame->setMinimumSize(0, 0);
305 emit adjustMonitorSize();
308 void Monitor::slotSetSizeOneToTwo()
310 QRect r = QApplication::desktop()->screenGeometry();
311 const int maxWidth = r.width() - 20;
312 const int maxHeight = r.height() - 20;
313 int width = render->renderWidth() / 2;
314 int height = render->renderHeight() / 2;
315 kDebug() << "// render info: " << width << "x" << height;
316 while (width >= maxWidth || height >= maxHeight) {
318 height = height * 0.8;
320 kDebug() << "// MONITOR; set SIZE: " << width << ", " << height;
321 videoBox->setFixedSize(width, height);
324 //m_ui.video_frame->setMinimumSize(0, 0);
325 emit adjustMonitorSize();
328 void Monitor::resetSize()
330 videoBox->setMinimumSize(0, 0);
333 QString Monitor::getTimecodeFromFrames(int pos)
335 return m_monitorManager->timecode().getTimecodeFromFrames(pos);
338 double Monitor::fps() const
340 return m_monitorManager->timecode().fps();
343 DocClipBase *Monitor::activeClip()
345 return m_currentClip;
348 void Monitor::updateMarkers(DocClipBase *source)
350 if (source == m_currentClip && source != NULL) {
351 m_markerMenu->clear();
352 QList <CommentedTime> markers = m_currentClip->commentedSnapMarkers();
353 if (!markers.isEmpty()) {
355 for (int i = 0; i < markers.count(); ++i) {
356 int pos = (int) markers.at(i).time().frames(m_monitorManager->timecode().fps());
358 QString position = m_monitorManager->timecode().getTimecode(markers.at(i).time()) + ' ' + markers.at(i).comment();
359 QAction *go = m_markerMenu->addAction(position);
363 m_ruler->setMarkers(markers);
364 m_markerMenu->setEnabled(!m_markerMenu->isEmpty());
368 void Monitor::setMarkers(const QList<CommentedTime> &markers)
370 m_ruler->setMarkers(markers);
373 void Monitor::slotSeekToPreviousSnap()
375 if (m_currentClip) slotSeek(getSnapForPos(true).frames(m_monitorManager->timecode().fps()));
378 void Monitor::slotSeekToNextSnap()
380 if (m_currentClip) slotSeek(getSnapForPos(false).frames(m_monitorManager->timecode().fps()));
383 GenTime Monitor::position()
385 return render->seekPosition();
388 GenTime Monitor::getSnapForPos(bool previous)
390 QList <GenTime> snaps;
391 QList < GenTime > markers = m_currentClip->snapMarkers();
392 for (int i = 0; i < markers.size(); ++i) {
393 GenTime t = markers.at(i);
396 QPoint zone = m_ruler->zone();
397 snaps.append(GenTime(zone.x(), m_monitorManager->timecode().fps()));
398 snaps.append(GenTime(zone.y(), m_monitorManager->timecode().fps()));
399 snaps.append(GenTime());
400 snaps.append(m_currentClip->duration());
403 const GenTime pos = render->seekPosition();
404 for (int i = 0; i < snaps.size(); ++i) {
405 if (previous && snaps.at(i) >= pos) {
407 return snaps.at(i - 1);
408 } else if (!previous && snaps.at(i) > pos) {
415 void Monitor::slotZoneMoved(int start, int end)
417 m_ruler->setZone(start, end);
418 setClipZone(m_ruler->zone());
422 void Monitor::slotSetZoneStart()
424 m_ruler->setZoneStart();
425 emit zoneUpdated(m_ruler->zone());
426 setClipZone(m_ruler->zone());
430 void Monitor::slotSetZoneEnd()
432 m_ruler->setZoneEnd();
433 emit zoneUpdated(m_ruler->zone());
434 setClipZone(m_ruler->zone());
439 void Monitor::mousePressEvent(QMouseEvent * event)
441 if (render) render->setActiveMonitor();
442 if (event->button() != Qt::RightButton) {
443 if (videoBox->geometry().contains(event->pos()) && (!m_overlay || !m_overlay->underMouse())) {
444 m_dragStarted = true;
445 m_DragStartPosition = event->pos();
447 } else if (m_contextMenu && (!m_effectWidget || !m_effectWidget->isVisible())) {
448 m_contextMenu->popup(event->globalPos());
452 void Monitor::resizeEvent(QResizeEvent *event)
455 if (render && isVisible() && isActive()) render->doRefresh();
458 void Monitor::slotSwitchFullScreen()
460 videoBox->switchFullScreen();
464 void Monitor::mouseReleaseEvent(QMouseEvent * event)
466 if (m_dragStarted && event->button() != Qt::RightButton) {
467 if (videoBox->geometry().contains(event->pos()) && (!m_effectWidget || !m_effectWidget->isVisible())) {
468 if (isActive()) slotPlay();
469 else slotActivateMonitor();
470 } //else event->ignore(); //QWidget::mouseReleaseEvent(event);
472 m_dragStarted = false;
477 void Monitor::mouseMoveEvent(QMouseEvent *event)
479 if (!m_dragStarted || m_currentClip == NULL) return;
481 if ((event->pos() - m_DragStartPosition).manhattanLength()
482 < QApplication::startDragDistance())
486 QDrag *drag = new QDrag(this);
487 QMimeData *mimeData = new QMimeData;
490 list.append(m_currentClip->getId());
491 QPoint p = m_ruler->zone();
492 list.append(QString::number(p.x()));
493 list.append(QString::number(p.y()));
495 data.append(list.join(";").toUtf8());
496 mimeData->setData("kdenlive/clip", data);
497 drag->setMimeData(mimeData);
498 /*QPixmap pix = m_currentClip->thumbnail();
499 drag->setPixmap(pix);
500 drag->setHotSpot(QPoint(0, 50));*/
501 drag->start(Qt::MoveAction);
502 /*Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction);
503 Qt::DropAction dropAction;
504 dropAction = drag->start(Qt::CopyAction | Qt::MoveAction);*/
506 //Qt::DropAction dropAction = drag->exec();
513 /*void Monitor::dragMoveEvent(QDragMoveEvent * event) {
514 event->setDropAction(Qt::IgnoreAction);
515 event->setDropAction(Qt::MoveAction);
516 if (event->mimeData()->hasText()) {
517 event->acceptProposedAction();
521 Qt::DropActions Monitor::supportedDropActions() const {
522 // returns what actions are supported when dropping
523 return Qt::MoveAction;
526 QStringList Monitor::mimeTypes() const
528 QStringList qstrList;
529 // list of accepted mime types for drop
530 qstrList.append("kdenlive/clip");
535 void Monitor::wheelEvent(QWheelEvent * event)
537 slotMouseSeek(event->delta(), event->modifiers() == Qt::ControlModifier);
541 void Monitor::slotMouseSeek(int eventDelta, bool fast)
544 int delta = m_monitorManager->timecode().fps();
545 if (eventDelta > 0) delta = 0 - delta;
546 if (render->requestedSeekPosition != SEEK_INACTIVE)
547 slotSeek(render->requestedSeekPosition - delta);
548 else slotSeek(render->seekFramePosition() - delta);
550 if (eventDelta >= 0) slotForwardOneFrame();
551 else slotRewindOneFrame();
555 void Monitor::slotSetThumbFrame()
557 if (m_currentClip == NULL) {
560 m_currentClip->setClipThumbFrame((uint) render->seekFramePosition());
561 emit refreshClipThumbnail(m_currentClip->getId(), true);
564 void Monitor::slotExtractCurrentZone()
566 if (m_currentClip == NULL) return;
567 emit extractZone(m_currentClip->getId(), m_ruler->zone());
570 void Monitor::slotExtractCurrentFrame()
573 // check if we are using a proxy
574 if (m_currentClip && !m_currentClip->getProperty("proxy").isEmpty() && m_currentClip->getProperty("proxy") != "-") {
575 // using proxy, use original clip url to get frame
576 frame = render->extractFrame(render->seekFramePosition(), m_currentClip->fileURL().path());
578 else frame = render->extractFrame(render->seekFramePosition());
579 QPointer<KFileDialog> fs = new KFileDialog(KUrl(), "image/png", this);
580 fs->setOperationMode(KFileDialog::Saving);
581 fs->setMode(KFile::File);
582 fs->setConfirmOverwrite(true);
583 fs->setKeepLocation(true);
585 QString path = fs->selectedFile();
586 if (!path.isEmpty()) {
593 void Monitor::setTimePos(const QString &pos)
595 m_timePos->setValue(pos);
599 void Monitor::slotSeek()
601 slotSeek(m_timePos->getValue());
604 void Monitor::slotSeek(int pos)
606 if (render == NULL) return;
607 slotActivateMonitor();
608 render->seekToFrame(pos);
612 void Monitor::checkOverlay()
614 if (m_overlay == NULL) return;
616 int pos = m_timePos->getValue();//render->seekFramePosition();
617 QPoint zone = m_ruler->zone();
619 overlayText = i18n("In Point");
620 else if (pos == zone.y())
621 overlayText = i18n("Out Point");
624 overlayText = m_currentClip->markerComment(GenTime(pos, m_monitorManager->timecode().fps()));
625 if (!overlayText.isEmpty()) {
626 m_overlay->setOverlayText(overlayText, false);
631 if (m_overlay->isVisible() && overlayText.isEmpty()) m_overlay->setOverlayText(QString(), false);
632 else m_overlay->setOverlayText(overlayText);
635 void Monitor::slotStart()
637 slotActivateMonitor();
639 render->seekToFrame(0);
642 void Monitor::slotEnd()
644 slotActivateMonitor();
646 render->seekToFrame(render->getLength());
649 void Monitor::slotZoneStart()
651 slotActivateMonitor();
653 render->seekToFrame(m_ruler->zone().x());
656 void Monitor::slotZoneEnd()
658 slotActivateMonitor();
660 render->seekToFrame(m_ruler->zone().y());
663 void Monitor::slotRewind(double speed)
665 slotActivateMonitor();
667 double currentspeed = render->playSpeed();
668 if (currentspeed >= 0) render->play(-1);
669 else switch((int) currentspeed) {
682 } else render->play(speed);
683 //m_playAction->setChecked(true);
684 m_playAction->setIcon(m_pauseIcon);
687 void Monitor::slotForward(double speed)
689 slotActivateMonitor();
691 double currentspeed = render->playSpeed();
692 if (currentspeed <= 0) render->play(1);
693 else switch((int) currentspeed) {
706 } else render->play(speed);
707 //m_playAction->setChecked(true);
708 m_playAction->setIcon(m_pauseIcon);
711 void Monitor::slotRewindOneFrame(int diff)
713 slotActivateMonitor();
715 render->seekToFrameDiff(-diff);
719 void Monitor::slotForwardOneFrame(int diff)
721 slotActivateMonitor();
723 render->seekToFrameDiff(diff);
727 void Monitor::seekCursor(int pos)
729 if (m_ruler->slotNewValue(pos)) {
730 m_timePos->setValue(pos);
735 void Monitor::rendererStopped(int pos)
737 if (m_ruler->slotNewValue(pos)) {
738 m_timePos->setValue(pos);
741 m_playAction->setIcon(m_playIcon);
744 void Monitor::adjustRulerSize(int length)
746 if (length > 0) m_length = length;
747 m_ruler->adjustScale(m_length);
748 if (m_currentClip != NULL) {
749 QPoint zone = m_currentClip->zone();
750 m_ruler->setZone(zone.x(), zone.y());
756 if (render) render->stop();
759 void Monitor::start()
761 if (!isVisible() || !isActive()) return;
762 if (m_glWidget) m_glWidget->activateMonitor();
763 if (render) render->startConsumer();
766 void Monitor::refreshMonitor(bool visible)
768 if (visible && render) {
769 if (!slotActivateMonitor()) {
770 // the monitor was already active, simply refreshClipThumbnail
776 void Monitor::refreshMonitor()
783 void Monitor::pause()
785 if (render == NULL) return;
786 slotActivateMonitor();
788 //m_playAction->setChecked(true);
789 m_playAction->setIcon(m_playIcon);
792 void Monitor::unpause()
796 void Monitor::slotPlay()
798 if (render == NULL) return;
799 slotActivateMonitor();
800 if (render->isPlaying()) {
801 m_playAction->setIcon(m_playIcon);
802 render->switchPlay(false);
805 m_playAction->setIcon(m_pauseIcon);
806 render->switchPlay(true);
808 m_ruler->refreshRuler();
811 void Monitor::slotPlayZone()
813 if (render == NULL) return;
814 slotActivateMonitor();
815 QPoint p = m_ruler->zone();
816 render->playZone(GenTime(p.x(), m_monitorManager->timecode().fps()), GenTime(p.y(), m_monitorManager->timecode().fps()));
817 //m_playAction->setChecked(true);
818 m_playAction->setIcon(m_pauseIcon);
821 void Monitor::slotLoopZone()
823 if (render == NULL) return;
824 slotActivateMonitor();
825 QPoint p = m_ruler->zone();
826 render->loopZone(GenTime(p.x(), m_monitorManager->timecode().fps()), GenTime(p.y(), m_monitorManager->timecode().fps()));
827 //m_playAction->setChecked(true);
828 m_playAction->setIcon(m_pauseIcon);
831 void Monitor::slotLoopClip()
833 if (render == NULL || m_selectedClip == NULL)
835 slotActivateMonitor();
836 render->loopZone(m_selectedClip->startPos(), m_selectedClip->endPos());
837 //m_playAction->setChecked(true);
838 m_playAction->setIcon(m_pauseIcon);
841 void Monitor::updateClipProducer(Mlt::Producer *prod)
843 if (render == NULL) return;
844 render->setProducer(prod, render->seekFramePosition());
847 void Monitor::slotSetClipProducer(DocClipBase *clip, QPoint zone, bool forceUpdate, int position)
849 if (render == NULL) return;
850 if (clip == NULL && m_currentClip != NULL) {
851 m_currentClip->lastSeekPosition = render->seekFramePosition();
852 m_currentClip = NULL;
854 render->setProducer(NULL, -1);
858 if (clip != m_currentClip || forceUpdate) {
859 if (m_currentClip) m_currentClip->lastSeekPosition = render->seekFramePosition();
860 m_currentClip = clip;
861 if (position == -1) position = clip->lastSeekPosition;
863 Mlt::Producer *prod = NULL;
864 if (clip) prod = clip->getCloneProducer();
865 if (render->setProducer(prod, position) == -1) {
866 // MLT CONSUMER is broken
867 kDebug(QtWarningMsg) << "ERROR, Cannot start monitor";
871 slotActivateMonitor();
872 if (position == -1) position = render->seekFramePosition();
873 render->seek(position);
875 zone = m_currentClip->zone();
876 m_ruler->setZone(zone.x(), zone.y());
881 if (!zone.isNull()) {
882 m_ruler->setZone(zone.x(), zone.y());
883 render->seek(zone.x());
887 void Monitor::slotOpenFile(const QString &file)
889 if (render == NULL) return;
890 slotActivateMonitor();
891 render->loadUrl(file);
894 void Monitor::slotSaveZone()
896 if (render == NULL) return;
897 emit saveZone(render, m_ruler->zone(), m_currentClip);
899 //render->setSceneList(doc, 0);
902 void Monitor::setCustomProfile(const QString &profile, const Timecode &tc)
904 m_timePos->updateTimeCode(tc);
905 if (render == NULL) return;
906 if (!render->hasProfile(profile)) {
907 slotActivateMonitor();
908 render->resetProfile(profile);
909 if (m_glWidget) m_glWidget->setImageAspectRatio(render->dar());
913 void Monitor::resetProfile(const QString &profile)
915 m_timePos->updateTimeCode(m_monitorManager->timecode());
916 if (render == NULL) return;
917 if (!render->hasProfile(profile)) {
918 slotActivateMonitor();
919 render->resetProfile(profile);
920 if (m_glWidget) m_glWidget->setImageAspectRatio(render->dar());
923 m_effectWidget->resetProfile(render);
926 void Monitor::saveSceneList(const QString &path, const QDomElement &info)
928 if (render == NULL) return;
929 render->saveSceneList(path, info);
932 const QString Monitor::sceneList()
934 if (render == NULL) return QString();
935 return render->sceneList();
938 void Monitor::setClipZone(const QPoint &pos)
940 if (m_currentClip == NULL) return;
941 m_currentClip->setZone(pos);
944 void Monitor::slotSwitchDropFrames(bool show)
946 render->setDropFrames(show);
949 void Monitor::slotSwitchMonitorInfo(bool show)
951 KdenliveSettings::setDisplayMonitorInfo(show);
953 if (m_overlay) return;
954 if (m_glWidget->layout()) delete m_glWidget->layout();
955 m_overlay = new Overlay();
956 connect(m_overlay, SIGNAL(editMarker()), this, SLOT(slotEditMarker()));
957 QVBoxLayout *layout = new QVBoxLayout;
958 layout->addStretch(10);
959 layout->addWidget(m_overlay);
960 m_glWidget->setLayout(layout);
968 void Monitor::slotEditMarker()
970 if (m_editMarker) m_editMarker->trigger();
973 void Monitor::updateTimecodeFormat()
975 m_timePos->slotUpdateTimeCodeFormat();
978 QStringList Monitor::getZoneInfo() const
981 if (m_currentClip == NULL) return result;
982 result << m_currentClip->getId();
983 QPoint zone = m_ruler->zone();
984 result << QString::number(zone.x()) << QString::number(zone.y());
988 void Monitor::slotSetSelectedClip(AbstractClipItem* item)
991 if (m_loopClipAction) m_loopClipAction->setEnabled(true);
992 m_selectedClip = item;
994 if (m_loopClipAction) m_loopClipAction->setEnabled(false);
998 void Monitor::slotSetSelectedClip(ClipItem* item)
1000 if (item || (!item && !m_loopClipTransition)) {
1001 m_loopClipTransition = false;
1002 slotSetSelectedClip((AbstractClipItem*)item);
1006 void Monitor::slotSetSelectedClip(Transition* item)
1008 if (item || (!item && m_loopClipTransition)) {
1009 m_loopClipTransition = true;
1010 slotSetSelectedClip((AbstractClipItem*)item);
1015 void Monitor::slotShowEffectScene(bool show, bool manuallyTriggered)
1017 if (m_id == Kdenlive::ProjectMonitor) {
1018 if (!m_effectWidget->getVisibilityAction()->isChecked())
1020 if (m_effectWidget->isVisible() == show)
1022 setUpdatesEnabled(false);
1024 m_glWidget->setVisible(false);
1025 m_effectWidget->setVisible(true);
1026 m_effectWidget->getScene()->slotZoomFit();
1027 emit requestFrameForAnalysis(true);
1029 m_effectWidget->setVisible(false);
1030 emit requestFrameForAnalysis(false);
1031 m_glWidget->setVisible(true);
1033 if (!manuallyTriggered)
1034 m_effectWidget->showVisibilityButton(show);
1035 setUpdatesEnabled(true);
1036 videoBox->setEnabled(show);
1037 //render->doRefresh();
1041 MonitorEditWidget* Monitor::getEffectEdit()
1043 return m_effectWidget;
1046 bool Monitor::effectSceneDisplayed()
1048 return m_effectWidget->isVisible();
1051 void Monitor::slotSetVolume(int volume)
1053 KdenliveSettings::setVolume(volume);
1055 if (volume == 0) icon = KIcon("audio-volume-muted");
1056 else icon = KIcon("audio-volume-medium");
1057 static_cast <QToolButton *>(m_volumeWidget)->setIcon(icon);
1058 render->slotSetVolume(volume);
1061 void Monitor::slotShowVolume()
1063 m_volumePopup->move(mapToGlobal(m_toolbar->geometry().topLeft()) + QPoint(mapToParent(m_volumeWidget->geometry().bottomLeft()).x(), -m_volumePopup->height()));
1064 int vol = render->volume();
1065 // Disable widget if we cannot get the volume
1066 m_volumePopup->setEnabled(vol != -1);
1067 m_audioSlider->blockSignals(true);
1068 m_audioSlider->setValue(vol);
1069 m_audioSlider->blockSignals(false);
1070 m_volumePopup->show();
1073 AbstractRender *Monitor::abstractRender()
1078 void Monitor::reloadProducer(const QString &id)
1080 if (!m_currentClip) return;
1081 if (m_currentClip->getId() == id)
1082 slotSetClipProducer(m_currentClip, m_currentClip->zone(), true);
1085 QString Monitor::getMarkerThumb(GenTime pos)
1087 if (!m_currentClip) return QString();
1088 if (!m_currentClip->getClipHash().isEmpty()) {
1089 QString url = m_monitorManager->getProjectFolder() + "thumbs/" + m_currentClip->getClipHash() + '#' + QString::number((int) pos.frames(m_monitorManager->timecode().fps())) + ".png";
1090 if (QFile::exists(url)) return url;
1095 void Monitor::setPalette ( const QPalette & p)
1097 QWidget::setPalette(p);
1098 if (m_ruler) m_ruler->updatePalette();
1102 Overlay::Overlay(QWidget* parent) :
1105 //setAttribute(Qt::WA_TransparentForMouseEvents);
1106 setAutoFillBackground(true);
1107 setBackgroundRole(QPalette::Base);
1108 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
1109 setCursor(Qt::PointingHandCursor);
1114 void Overlay::mouseReleaseEvent ( QMouseEvent * event )
1120 void Overlay::mousePressEvent( QMouseEvent * event )
1126 void Overlay::mouseDoubleClickEvent ( QMouseEvent * event )
1132 void Overlay::setOverlayText(const QString &text, bool isZone)
1134 if (text.isEmpty()) {
1136 p.setColor(QPalette::Base, KdenliveSettings::window_background());
1145 p.setColor(QPalette::Text, Qt::white);
1146 if (isZone) p.setColor(QPalette::Base, QColor(200, 0, 0));
1147 else p.setColor(QPalette::Base, QColor(0, 0, 200));
1149 setText(' ' + text + ' ');
1154 #include "monitor.moc"