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 "widgets/videosurface.h"
28 #include "widgets/videoglwidget.h"
29 #include "kdenlivesettings.h"
32 #include <KLocalizedString>
33 #include <KFileDialog>
34 #include <KApplication>
35 #include <KMessageBox>
36 #include <KSelectAction>
38 #include <QMouseEvent>
39 #include <QStylePainter>
41 #include <QToolButton>
43 #include <QDesktopWidget>
45 #include <QIntValidator>
46 #include <QVBoxLayout>
50 #define SEEK_INACTIVE (-1)
53 Monitor::Monitor(Kdenlive::MonitorId id, MonitorManager *manager, QGLWidget *glContext, QString profile, QWidget *parent) :
54 AbstractMonitor(id, manager, parent)
60 , m_dragStarted(false)
61 , m_loopClipAction(NULL)
63 , m_effectWidget(NULL)
64 , m_selectedClip(NULL)
65 , m_loopClipTransition(true)
66 , m_parentGLContext(glContext)
70 QVBoxLayout *layout = new QVBoxLayout;
71 layout->setContentsMargins(0, 0, 0, 0);
72 layout->setSpacing(0);
74 // Video widget holder
75 layout->addWidget(videoBox, 10);
78 // Get base size for icons
79 int s = style()->pixelMetric(QStyle::PM_SmallIconSize);
83 m_toolbar = new QToolBar(this);
84 m_toolbar->setIconSize(QSize(s, s));
86 m_playIcon = KIcon("media-playback-start");
87 m_pauseIcon = KIcon("media-playback-pause");
90 if (id != Kdenlive::DvdMonitor) {
91 m_toolbar->addAction(KIcon("kdenlive-zone-start"), i18n("Set zone start"), this, SLOT(slotSetZoneStart()));
92 m_toolbar->addAction(KIcon("kdenlive-zone-end"), i18n("Set zone end"), this, SLOT(slotSetZoneEnd()));
95 m_toolbar->addAction(KIcon("media-seek-backward"), i18n("Rewind"), this, SLOT(slotRewind()));
96 //m_toolbar->addAction(KIcon("media-skip-backward"), i18n("Rewind 1 frame"), this, SLOT(slotRewindOneFrame()));
98 QToolButton *playButton = new QToolButton(m_toolbar);
99 m_playMenu = new QMenu(i18n("Play..."), this);
100 m_playAction = m_playMenu->addAction(m_playIcon, i18n("Play"));
101 //m_playAction->setCheckable(true);
102 connect(m_playAction, SIGNAL(triggered()), this, SLOT(slotPlay()));
104 playButton->setMenu(m_playMenu);
105 playButton->setPopupMode(QToolButton::MenuButtonPopup);
106 m_toolbar->addWidget(playButton);
108 //m_toolbar->addAction(KIcon("media-skip-forward"), i18n("Forward 1 frame"), this, SLOT(slotForwardOneFrame()));
109 m_toolbar->addAction(KIcon("media-seek-forward"), i18n("Forward"), this, SLOT(slotForward()));
111 playButton->setDefaultAction(m_playAction);
113 if (id != Kdenlive::DvdMonitor) {
114 QToolButton *configButton = new QToolButton(m_toolbar);
115 m_configMenu = new QMenu(i18n("Misc..."), this);
116 configButton->setIcon(KIcon("system-run"));
117 configButton->setMenu(m_configMenu);
118 configButton->setPopupMode(QToolButton::QToolButton::InstantPopup);
119 m_toolbar->addWidget(configButton);
121 if (id == Kdenlive::ClipMonitor) {
122 m_markerMenu = new QMenu(i18n("Go to marker..."), this);
123 m_markerMenu->setEnabled(false);
124 m_configMenu->addMenu(m_markerMenu);
125 connect(m_markerMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotGoToMarker(QAction*)));
127 m_configMenu->addAction(KIcon("transform-scale"), i18n("Resize (100%)"), this, SLOT(slotSetSizeOneToOne()));
128 m_configMenu->addAction(KIcon("transform-scale"), i18n("Resize (50%)"), this, SLOT(slotSetSizeOneToTwo()));
131 // Create Volume slider popup
132 m_volumePopup = new QFrame(this, Qt::Popup);
133 QVBoxLayout *poplayout = new QVBoxLayout;
134 poplayout->setContentsMargins(0, 0, 0, 0);
135 m_audioSlider = new QSlider(Qt::Vertical);
136 m_audioSlider->setRange(0, 100);
137 poplayout->addWidget(m_audioSlider);
138 m_volumePopup->setLayout(poplayout);
140 if (KdenliveSettings::volume() == 0) icon = KIcon("audio-volume-muted");
141 else icon = KIcon("audio-volume-medium");
143 m_volumeWidget = m_toolbar->widgetForAction(m_toolbar->addAction(icon, i18n("Audio volume"), this, SLOT(slotShowVolume())));
145 // we need to show / hide the popup once so that it's geometry can be calculated in slotShowVolume
146 m_volumePopup->show();
147 m_volumePopup->hide();
149 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
151 setMinimumHeight(200);
153 if (profile.isEmpty())
154 profile = KdenliveSettings::current_profile();
156 createOpenGlWidget(videoBox, profile);
157 QVBoxLayout *lay = new QVBoxLayout;
158 lay->setContentsMargins(0, 0, 0, 0);
159 lay->addWidget(m_glWidget);
160 videoBox->setLayout(lay);
163 m_ruler = new SmallRuler(this, render);
164 if (id == Kdenlive::DvdMonitor) m_ruler->setZone(-3, -2);
165 layout->addWidget(m_ruler);
167 connect(m_audioSlider, SIGNAL(valueChanged(int)), this, SLOT(slotSetVolume(int)));
168 connect(render, SIGNAL(durationChanged(int)), this, SLOT(adjustRulerSize(int)));
169 connect(render, SIGNAL(rendererStopped(int)), this, SLOT(rendererStopped(int)));
170 connect(render, SIGNAL(rendererPosition(int)), this, SLOT(seekCursor(int)));
172 if (id != Kdenlive::ClipMonitor) {
173 connect(render, SIGNAL(rendererPosition(int)), this, SIGNAL(renderPosition(int)));
174 connect(render, SIGNAL(durationChanged(int)), this, SIGNAL(durationChanged(int)));
175 connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SIGNAL(zoneUpdated(QPoint)));
177 connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SLOT(setClipZone(QPoint)));
180 if (id == Kdenlive::ProjectMonitor) {
181 m_effectWidget = new MonitorEditWidget(render, videoBox);
182 connect(m_effectWidget, SIGNAL(showEdit(bool,bool)), this, SLOT(slotShowEffectScene(bool,bool)));
183 m_toolbar->addAction(m_effectWidget->getVisibilityAction());
184 videoBox->layout()->addWidget(m_effectWidget);
185 m_effectWidget->hide();
188 QWidget *spacer = new QWidget(this);
189 spacer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
190 m_toolbar->addWidget(spacer);
191 m_timePos = new TimecodeDisplay(m_monitorManager->timecode(), this);
192 m_toolbar->addWidget(m_timePos);
193 connect(m_timePos, SIGNAL(timeCodeEditingFinished()), this, SLOT(slotSeek()));
194 m_toolbar->setMaximumHeight(m_timePos->height());
195 layout->addWidget(m_toolbar);
204 delete m_effectWidget;
208 QWidget *Monitor::container()
213 void Monitor::createOpenGlWidget(QWidget *parent, const QString &profile)
215 m_glWidget = new VideoGLWidget(parent, m_parentGLContext);
216 render = new Render(id(), 0, profile, this, m_glWidget);
217 if (m_glWidget == NULL) {
218 // Creation failed, we are in trouble...
219 QMessageBox::critical(this, i18n("Missing OpenGL support"),
220 i18n("You need working OpenGL support to run Kdenlive. Exiting."));
223 m_glWidget->setImageAspectRatio(render->dar());
224 m_glWidget->setBackgroundColor(KdenliveSettings::window_background());
225 connect(render, SIGNAL(showImageSignal(QImage)), m_glWidget, SLOT(showImage(QImage)));
226 connect(render, SIGNAL(showImageSignal(GLuint)), m_glWidget, SLOT(showImage(GLuint)));
229 void Monitor::setupMenu(QMenu *goMenu, QAction *playZone, QAction *loopZone, QMenu *markerMenu, QAction *loopClip)
231 m_contextMenu = new QMenu(this);
232 m_contextMenu->addMenu(m_playMenu);
234 m_contextMenu->addMenu(goMenu);
236 m_contextMenu->addMenu(markerMenu);
237 QList <QAction *>list = markerMenu->actions();
238 for (int i = 0; i < list.count(); ++i) {
239 if (list.at(i)->data().toString() == "edit_marker") {
240 m_editMarker = list.at(i);
246 m_playMenu->addAction(playZone);
247 m_playMenu->addAction(loopZone);
249 m_loopClipAction = loopClip;
250 m_playMenu->addAction(loopClip);
253 //TODO: add save zone to timeline monitor when fixed
254 if (m_id == Kdenlive::ClipMonitor) {
255 m_contextMenu->addMenu(m_markerMenu);
256 m_contextMenu->addAction(KIcon("document-save"), i18n("Save zone"), this, SLOT(slotSaveZone()));
257 QAction *extractZone = m_configMenu->addAction(KIcon("document-new"), i18n("Extract Zone"), this, SLOT(slotExtractCurrentZone()));
258 m_contextMenu->addAction(extractZone);
260 QAction *extractFrame = m_configMenu->addAction(KIcon("document-new"), i18n("Extract frame"), this, SLOT(slotExtractCurrentFrame()));
261 m_contextMenu->addAction(extractFrame);
263 if (m_id != Kdenlive::ClipMonitor) {
264 QAction *splitView = m_contextMenu->addAction(KIcon("view-split-left-right"), i18n("Split view"), render, SLOT(slotSplitView(bool)));
265 splitView->setCheckable(true);
266 m_configMenu->addAction(splitView);
268 QAction *setThumbFrame = m_contextMenu->addAction(KIcon("document-new"), i18n("Set current image as thumbnail"), this, SLOT(slotSetThumbFrame()));
269 m_configMenu->addAction(setThumbFrame);
272 QAction *showTips = m_contextMenu->addAction(KIcon("help-hint"), i18n("Monitor overlay infos"));
273 showTips->setCheckable(true);
274 connect(showTips, SIGNAL(toggled(bool)), this, SLOT(slotSwitchMonitorInfo(bool)));
275 showTips->setChecked(KdenliveSettings::displayMonitorInfo());
277 QAction *dropFrames = m_contextMenu->addAction(KIcon(), i18n("Real time (drop frames)"));
278 dropFrames->setCheckable(true);
279 dropFrames->setChecked(true);
280 connect(dropFrames, SIGNAL(toggled(bool)), this, SLOT(slotSwitchDropFrames(bool)));
282 m_configMenu->addAction(showTips);
283 m_configMenu->addAction(dropFrames);
286 void Monitor::slotGoToMarker(QAction *action)
288 int pos = action->data().toInt();
292 void Monitor::slotSetSizeOneToOne()
294 QRect r = QApplication::desktop()->screenGeometry();
295 const int maxWidth = r.width() - 20;
296 const int maxHeight = r.height() - 20;
297 int width = render->renderWidth();
298 int height = render->renderHeight();
299 kDebug() << "// render info: " << width << "x" << height;
300 while (width >= maxWidth || height >= maxHeight) {
302 height = height * 0.8;
304 kDebug() << "// MONITOR; set SIZE: " << width << ", " << height;
305 videoBox->setFixedSize(width, height);
308 //m_ui.video_frame->setMinimumSize(0, 0);
309 emit adjustMonitorSize();
312 void Monitor::slotSetSizeOneToTwo()
314 QRect r = QApplication::desktop()->screenGeometry();
315 const int maxWidth = r.width() - 20;
316 const int maxHeight = r.height() - 20;
317 int width = render->renderWidth() / 2;
318 int height = render->renderHeight() / 2;
319 kDebug() << "// render info: " << width << "x" << height;
320 while (width >= maxWidth || height >= maxHeight) {
322 height = height * 0.8;
324 kDebug() << "// MONITOR; set SIZE: " << width << ", " << height;
325 videoBox->setFixedSize(width, height);
328 //m_ui.video_frame->setMinimumSize(0, 0);
329 emit adjustMonitorSize();
332 void Monitor::resetSize()
334 videoBox->setMinimumSize(0, 0);
337 QString Monitor::getTimecodeFromFrames(int pos)
339 return m_monitorManager->timecode().getTimecodeFromFrames(pos);
342 double Monitor::fps() const
344 return m_monitorManager->timecode().fps();
347 DocClipBase *Monitor::activeClip()
349 return m_currentClip;
352 void Monitor::updateMarkers(DocClipBase *source)
354 if (source == m_currentClip && source != NULL) {
355 m_markerMenu->clear();
356 QList <CommentedTime> markers = m_currentClip->commentedSnapMarkers();
357 if (!markers.isEmpty()) {
359 for (int i = 0; i < markers.count(); ++i) {
360 int pos = (int) markers.at(i).time().frames(m_monitorManager->timecode().fps());
362 QString position = m_monitorManager->timecode().getTimecode(markers.at(i).time()) + ' ' + markers.at(i).comment();
363 QAction *go = m_markerMenu->addAction(position);
367 m_ruler->setMarkers(markers);
368 m_markerMenu->setEnabled(!m_markerMenu->isEmpty());
372 void Monitor::setMarkers(const QList<CommentedTime> &markers)
374 m_ruler->setMarkers(markers);
377 void Monitor::slotSeekToPreviousSnap()
379 if (m_currentClip) slotSeek(getSnapForPos(true).frames(m_monitorManager->timecode().fps()));
382 void Monitor::slotSeekToNextSnap()
384 if (m_currentClip) slotSeek(getSnapForPos(false).frames(m_monitorManager->timecode().fps()));
387 GenTime Monitor::position()
389 return render->seekPosition();
392 GenTime Monitor::getSnapForPos(bool previous)
394 QList <GenTime> snaps;
395 QList < GenTime > markers = m_currentClip->snapMarkers();
396 for (int i = 0; i < markers.size(); ++i) {
397 GenTime t = markers.at(i);
400 QPoint zone = m_ruler->zone();
401 snaps.append(GenTime(zone.x(), m_monitorManager->timecode().fps()));
402 snaps.append(GenTime(zone.y(), m_monitorManager->timecode().fps()));
403 snaps.append(GenTime());
404 snaps.append(m_currentClip->duration());
407 const GenTime pos = render->seekPosition();
408 for (int i = 0; i < snaps.size(); ++i) {
409 if (previous && snaps.at(i) >= pos) {
411 return snaps.at(i - 1);
412 } else if (!previous && snaps.at(i) > pos) {
419 void Monitor::slotZoneMoved(int start, int end)
421 m_ruler->setZone(start, end);
422 setClipZone(m_ruler->zone());
426 void Monitor::slotSetZoneStart()
428 m_ruler->setZoneStart();
429 emit zoneUpdated(m_ruler->zone());
430 setClipZone(m_ruler->zone());
434 void Monitor::slotSetZoneEnd()
436 m_ruler->setZoneEnd();
437 emit zoneUpdated(m_ruler->zone());
438 setClipZone(m_ruler->zone());
443 void Monitor::mousePressEvent(QMouseEvent * event)
445 if (render) render->setActiveMonitor();
446 if (event->button() != Qt::RightButton) {
447 if (videoBox->geometry().contains(event->pos()) && (!m_overlay || !m_overlay->underMouse())) {
448 m_dragStarted = true;
449 m_DragStartPosition = event->pos();
451 } else if (m_contextMenu && (!m_effectWidget || !m_effectWidget->isVisible())) {
452 m_contextMenu->popup(event->globalPos());
456 void Monitor::resizeEvent(QResizeEvent *event)
459 if (render && isVisible() && isActive()) render->doRefresh();
462 void Monitor::slotSwitchFullScreen()
464 videoBox->switchFullScreen();
468 void Monitor::mouseReleaseEvent(QMouseEvent * event)
470 if (m_dragStarted && event->button() != Qt::RightButton) {
471 if (videoBox->geometry().contains(event->pos()) && (!m_effectWidget || !m_effectWidget->isVisible())) {
472 if (isActive()) slotPlay();
473 else slotActivateMonitor();
474 } //else event->ignore(); //QWidget::mouseReleaseEvent(event);
476 m_dragStarted = false;
481 void Monitor::mouseMoveEvent(QMouseEvent *event)
483 if (!m_dragStarted || m_currentClip == NULL) return;
485 if ((event->pos() - m_DragStartPosition).manhattanLength()
486 < QApplication::startDragDistance())
490 QDrag *drag = new QDrag(this);
491 QMimeData *mimeData = new QMimeData;
494 list.append(m_currentClip->getId());
495 QPoint p = m_ruler->zone();
496 list.append(QString::number(p.x()));
497 list.append(QString::number(p.y()));
499 data.append(list.join(";").toUtf8());
500 mimeData->setData("kdenlive/clip", data);
501 drag->setMimeData(mimeData);
502 /*QPixmap pix = m_currentClip->thumbnail();
503 drag->setPixmap(pix);
504 drag->setHotSpot(QPoint(0, 50));*/
505 drag->start(Qt::MoveAction);
506 /*Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction);
507 Qt::DropAction dropAction;
508 dropAction = drag->start(Qt::CopyAction | Qt::MoveAction);*/
510 //Qt::DropAction dropAction = drag->exec();
517 /*void Monitor::dragMoveEvent(QDragMoveEvent * event) {
518 event->setDropAction(Qt::IgnoreAction);
519 event->setDropAction(Qt::MoveAction);
520 if (event->mimeData()->hasText()) {
521 event->acceptProposedAction();
525 Qt::DropActions Monitor::supportedDropActions() const {
526 // returns what actions are supported when dropping
527 return Qt::MoveAction;
530 QStringList Monitor::mimeTypes() const
532 QStringList qstrList;
533 // list of accepted mime types for drop
534 qstrList.append("kdenlive/clip");
539 void Monitor::wheelEvent(QWheelEvent * event)
541 slotMouseSeek(event->delta(), event->modifiers() == Qt::ControlModifier);
545 void Monitor::slotMouseSeek(int eventDelta, bool fast)
548 int delta = m_monitorManager->timecode().fps();
549 if (eventDelta > 0) delta = 0 - delta;
550 if (render->requestedSeekPosition != SEEK_INACTIVE)
551 slotSeek(render->requestedSeekPosition - delta);
552 else slotSeek(render->seekFramePosition() - delta);
554 if (eventDelta >= 0) slotForwardOneFrame();
555 else slotRewindOneFrame();
559 void Monitor::slotSetThumbFrame()
561 if (m_currentClip == NULL) {
564 m_currentClip->setClipThumbFrame((uint) render->seekFramePosition());
565 emit refreshClipThumbnail(m_currentClip->getId(), true);
568 void Monitor::slotExtractCurrentZone()
570 if (m_currentClip == NULL) return;
571 emit extractZone(m_currentClip->getId(), m_ruler->zone());
574 void Monitor::slotExtractCurrentFrame()
577 // check if we are using a proxy
578 if (m_currentClip && !m_currentClip->getProperty("proxy").isEmpty() && m_currentClip->getProperty("proxy") != "-") {
579 // using proxy, use original clip url to get frame
580 frame = render->extractFrame(render->seekFramePosition(), m_currentClip->fileURL().path());
582 else frame = render->extractFrame(render->seekFramePosition());
583 QPointer<KFileDialog> fs = new KFileDialog(KUrl(), "image/png", this);
584 fs->setOperationMode(KFileDialog::Saving);
585 fs->setMode(KFile::File);
586 fs->setConfirmOverwrite(true);
587 fs->setKeepLocation(true);
589 QString path = fs->selectedFile();
590 if (!path.isEmpty()) {
597 void Monitor::setTimePos(const QString &pos)
599 m_timePos->setValue(pos);
603 void Monitor::slotSeek()
605 slotSeek(m_timePos->getValue());
608 void Monitor::slotSeek(int pos)
610 if (render == NULL) return;
611 slotActivateMonitor();
612 render->seekToFrame(pos);
616 void Monitor::checkOverlay()
618 if (m_overlay == NULL) return;
620 int pos = m_timePos->getValue();//render->seekFramePosition();
621 QPoint zone = m_ruler->zone();
623 overlayText = i18n("In Point");
624 else if (pos == zone.y())
625 overlayText = i18n("Out Point");
628 overlayText = m_currentClip->markerComment(GenTime(pos, m_monitorManager->timecode().fps()));
629 if (!overlayText.isEmpty()) {
630 m_overlay->setOverlayText(overlayText, false);
635 if (m_overlay->isVisible() && overlayText.isEmpty()) m_overlay->setOverlayText(QString(), false);
636 else m_overlay->setOverlayText(overlayText);
639 void Monitor::slotStart()
641 slotActivateMonitor();
643 render->seekToFrame(0);
646 void Monitor::slotEnd()
648 slotActivateMonitor();
650 render->seekToFrame(render->getLength());
653 void Monitor::slotZoneStart()
655 slotActivateMonitor();
657 render->seekToFrame(m_ruler->zone().x());
660 void Monitor::slotZoneEnd()
662 slotActivateMonitor();
664 render->seekToFrame(m_ruler->zone().y());
667 void Monitor::slotRewind(double speed)
669 slotActivateMonitor();
671 double currentspeed = render->playSpeed();
672 if (currentspeed >= 0) render->play(-1);
673 else switch((int) currentspeed) {
686 } else render->play(speed);
687 //m_playAction->setChecked(true);
688 m_playAction->setIcon(m_pauseIcon);
691 void Monitor::slotForward(double speed)
693 slotActivateMonitor();
695 double currentspeed = render->playSpeed();
696 if (currentspeed <= 0) render->play(1);
697 else switch((int) currentspeed) {
710 } else render->play(speed);
711 //m_playAction->setChecked(true);
712 m_playAction->setIcon(m_pauseIcon);
715 void Monitor::slotRewindOneFrame(int diff)
717 slotActivateMonitor();
719 render->seekToFrameDiff(-diff);
723 void Monitor::slotForwardOneFrame(int diff)
725 slotActivateMonitor();
727 render->seekToFrameDiff(diff);
731 void Monitor::seekCursor(int pos)
733 if (m_ruler->slotNewValue(pos)) {
734 m_timePos->setValue(pos);
739 void Monitor::rendererStopped(int pos)
741 if (m_ruler->slotNewValue(pos)) {
742 m_timePos->setValue(pos);
745 m_playAction->setIcon(m_playIcon);
748 void Monitor::adjustRulerSize(int length)
750 if (length > 0) m_length = length;
751 m_ruler->adjustScale(m_length);
752 if (m_currentClip != NULL) {
753 QPoint zone = m_currentClip->zone();
754 m_ruler->setZone(zone.x(), zone.y());
760 if (render) render->stop();
763 void Monitor::start()
765 if (!isVisible() || !isActive()) return;
766 if (m_glWidget) m_glWidget->activateMonitor();
767 if (render) render->startConsumer();
770 void Monitor::refreshMonitor(bool visible)
772 if (visible && render) {
773 if (!slotActivateMonitor()) {
774 // the monitor was already active, simply refreshClipThumbnail
780 void Monitor::refreshMonitor()
787 void Monitor::pause()
789 if (render == NULL) return;
790 slotActivateMonitor();
792 //m_playAction->setChecked(true);
793 m_playAction->setIcon(m_playIcon);
796 void Monitor::unpause()
800 void Monitor::slotPlay()
802 if (render == NULL) return;
803 slotActivateMonitor();
804 if (render->isPlaying()) {
805 m_playAction->setIcon(m_playIcon);
806 render->switchPlay(false);
809 m_playAction->setIcon(m_pauseIcon);
810 render->switchPlay(true);
812 m_ruler->refreshRuler();
815 void Monitor::slotPlayZone()
817 if (render == NULL) return;
818 slotActivateMonitor();
819 QPoint p = m_ruler->zone();
820 render->playZone(GenTime(p.x(), m_monitorManager->timecode().fps()), GenTime(p.y(), m_monitorManager->timecode().fps()));
821 //m_playAction->setChecked(true);
822 m_playAction->setIcon(m_pauseIcon);
825 void Monitor::slotLoopZone()
827 if (render == NULL) return;
828 slotActivateMonitor();
829 QPoint p = m_ruler->zone();
830 render->loopZone(GenTime(p.x(), m_monitorManager->timecode().fps()), GenTime(p.y(), m_monitorManager->timecode().fps()));
831 //m_playAction->setChecked(true);
832 m_playAction->setIcon(m_pauseIcon);
835 void Monitor::slotLoopClip()
837 if (render == NULL || m_selectedClip == NULL)
839 slotActivateMonitor();
840 render->loopZone(m_selectedClip->startPos(), m_selectedClip->endPos());
841 //m_playAction->setChecked(true);
842 m_playAction->setIcon(m_pauseIcon);
845 void Monitor::updateClipProducer(Mlt::Producer *prod)
847 if (render == NULL) return;
848 render->setProducer(prod, render->seekFramePosition());
851 void Monitor::slotSetClipProducer(DocClipBase *clip, QPoint zone, bool forceUpdate, int position)
853 if (render == NULL) return;
854 if (clip == NULL && m_currentClip != NULL) {
855 m_currentClip->lastSeekPosition = render->seekFramePosition();
856 m_currentClip = NULL;
858 render->setProducer(NULL, -1);
862 if (clip != m_currentClip || forceUpdate) {
863 if (m_currentClip) m_currentClip->lastSeekPosition = render->seekFramePosition();
864 m_currentClip = clip;
865 if (position == -1) position = clip->lastSeekPosition;
867 Mlt::Producer *prod = NULL;
868 if (clip) prod = clip->getCloneProducer();
869 if (render->setProducer(prod, position) == -1) {
870 // MLT CONSUMER is broken
871 kDebug(QtWarningMsg) << "ERROR, Cannot start monitor";
875 slotActivateMonitor();
876 if (position == -1) position = render->seekFramePosition();
877 render->seek(position);
879 zone = m_currentClip->zone();
880 m_ruler->setZone(zone.x(), zone.y());
885 if (!zone.isNull()) {
886 m_ruler->setZone(zone.x(), zone.y());
887 render->seek(zone.x());
891 void Monitor::slotOpenFile(const QString &file)
893 if (render == NULL) return;
894 slotActivateMonitor();
895 render->loadUrl(file);
898 void Monitor::slotSaveZone()
900 if (render == NULL) return;
901 emit saveZone(render, m_ruler->zone(), m_currentClip);
903 //render->setSceneList(doc, 0);
906 void Monitor::setCustomProfile(const QString &profile, const Timecode &tc)
908 m_timePos->updateTimeCode(tc);
909 if (render == NULL) return;
910 if (!render->hasProfile(profile)) {
911 slotActivateMonitor();
912 render->resetProfile(profile);
913 if (m_glWidget) m_glWidget->setImageAspectRatio(render->dar());
917 void Monitor::resetProfile(const QString &profile)
919 m_timePos->updateTimeCode(m_monitorManager->timecode());
920 if (render == NULL) return;
921 if (!render->hasProfile(profile)) {
922 slotActivateMonitor();
923 render->resetProfile(profile);
924 if (m_glWidget) m_glWidget->setImageAspectRatio(render->dar());
927 m_effectWidget->resetProfile(render);
930 void Monitor::saveSceneList(const QString &path, const QDomElement &info)
932 if (render == NULL) return;
933 render->saveSceneList(path, info);
936 const QString Monitor::sceneList()
938 if (render == NULL) return QString();
939 return render->sceneList();
942 void Monitor::setClipZone(const QPoint &pos)
944 if (m_currentClip == NULL) return;
945 m_currentClip->setZone(pos);
948 void Monitor::slotSwitchDropFrames(bool show)
950 render->setDropFrames(show);
953 void Monitor::slotSwitchMonitorInfo(bool show)
955 KdenliveSettings::setDisplayMonitorInfo(show);
957 if (m_overlay) return;
958 if (m_glWidget->layout()) delete m_glWidget->layout();
959 m_overlay = new Overlay();
960 connect(m_overlay, SIGNAL(editMarker()), this, SLOT(slotEditMarker()));
961 QVBoxLayout *layout = new QVBoxLayout;
962 layout->addStretch(10);
963 layout->addWidget(m_overlay);
964 m_glWidget->setLayout(layout);
972 void Monitor::slotEditMarker()
974 if (m_editMarker) m_editMarker->trigger();
977 void Monitor::updateTimecodeFormat()
979 m_timePos->slotUpdateTimeCodeFormat();
982 QStringList Monitor::getZoneInfo() const
985 if (m_currentClip == NULL) return result;
986 result << m_currentClip->getId();
987 QPoint zone = m_ruler->zone();
988 result << QString::number(zone.x()) << QString::number(zone.y());
992 void Monitor::slotSetSelectedClip(AbstractClipItem* item)
995 if (m_loopClipAction) m_loopClipAction->setEnabled(true);
996 m_selectedClip = item;
998 if (m_loopClipAction) m_loopClipAction->setEnabled(false);
1002 void Monitor::slotSetSelectedClip(ClipItem* item)
1004 if (item || (!item && !m_loopClipTransition)) {
1005 m_loopClipTransition = false;
1006 slotSetSelectedClip((AbstractClipItem*)item);
1010 void Monitor::slotSetSelectedClip(Transition* item)
1012 if (item || (!item && m_loopClipTransition)) {
1013 m_loopClipTransition = true;
1014 slotSetSelectedClip((AbstractClipItem*)item);
1019 void Monitor::slotShowEffectScene(bool show, bool manuallyTriggered)
1021 if (m_id == Kdenlive::ProjectMonitor) {
1022 if (!m_effectWidget->getVisibilityAction()->isChecked())
1024 if (m_effectWidget->isVisible() == show)
1026 setUpdatesEnabled(false);
1028 m_glWidget->setVisible(false);
1029 m_effectWidget->setVisible(true);
1030 m_effectWidget->getScene()->slotZoomFit();
1031 emit requestFrameForAnalysis(true);
1033 m_effectWidget->setVisible(false);
1034 emit requestFrameForAnalysis(false);
1035 m_glWidget->setVisible(true);
1037 if (!manuallyTriggered)
1038 m_effectWidget->showVisibilityButton(show);
1039 setUpdatesEnabled(true);
1040 videoBox->setEnabled(show);
1041 //render->doRefresh();
1045 MonitorEditWidget* Monitor::getEffectEdit()
1047 return m_effectWidget;
1050 bool Monitor::effectSceneDisplayed()
1052 return m_effectWidget->isVisible();
1055 void Monitor::slotSetVolume(int volume)
1057 KdenliveSettings::setVolume(volume);
1059 if (volume == 0) icon = KIcon("audio-volume-muted");
1060 else icon = KIcon("audio-volume-medium");
1061 static_cast <QToolButton *>(m_volumeWidget)->setIcon(icon);
1062 render->slotSetVolume(volume);
1065 void Monitor::slotShowVolume()
1067 m_volumePopup->move(mapToGlobal(m_toolbar->geometry().topLeft()) + QPoint(mapToParent(m_volumeWidget->geometry().bottomLeft()).x(), -m_volumePopup->height()));
1068 int vol = render->volume();
1069 // Disable widget if we cannot get the volume
1070 m_volumePopup->setEnabled(vol != -1);
1071 m_audioSlider->blockSignals(true);
1072 m_audioSlider->setValue(vol);
1073 m_audioSlider->blockSignals(false);
1074 m_volumePopup->show();
1077 AbstractRender *Monitor::abstractRender()
1082 void Monitor::reloadProducer(const QString &id)
1084 if (!m_currentClip) return;
1085 if (m_currentClip->getId() == id)
1086 slotSetClipProducer(m_currentClip, m_currentClip->zone(), true);
1089 QString Monitor::getMarkerThumb(GenTime pos)
1091 if (!m_currentClip) return QString();
1092 if (!m_currentClip->getClipHash().isEmpty()) {
1093 QString url = m_monitorManager->getProjectFolder() + "thumbs/" + m_currentClip->getClipHash() + '#' + QString::number((int) pos.frames(m_monitorManager->timecode().fps())) + ".png";
1094 if (QFile::exists(url)) return url;
1099 void Monitor::setPalette ( const QPalette & p)
1101 QWidget::setPalette(p);
1102 if (m_ruler) m_ruler->updatePalette();
1106 Overlay::Overlay(QWidget* parent) :
1109 //setAttribute(Qt::WA_TransparentForMouseEvents);
1110 setAutoFillBackground(true);
1111 setBackgroundRole(QPalette::Base);
1112 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
1113 setCursor(Qt::PointingHandCursor);
1118 void Overlay::mouseReleaseEvent ( QMouseEvent * event )
1124 void Overlay::mousePressEvent( QMouseEvent * event )
1130 void Overlay::mouseDoubleClickEvent ( QMouseEvent * event )
1136 void Overlay::setOverlayText(const QString &text, bool isZone)
1138 if (text.isEmpty()) {
1140 p.setColor(QPalette::Base, KdenliveSettings::window_background());
1149 p.setColor(QPalette::Text, Qt::white);
1150 if (isZone) p.setColor(QPalette::Base, QColor(200, 0, 0));
1151 else p.setColor(QPalette::Base, QColor(0, 0, 200));
1153 setText(' ' + text + ' ');
1158 #include "monitor.moc"