]> git.sesse.net Git - kdenlive/blob - src/monitor.cpp
* Cleanup transode stabilize GUI: http://kdenlive.org/mantis/view.php?id=2930
[kdenlive] / src / monitor.cpp
1 /***************************************************************************
2  *   Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
3  *                                                                         *
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.                                   *
8  *                                                                         *
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.                          *
13  *                                                                         *
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  ***************************************************************************/
19
20
21 #include "monitor.h"
22 #include "smallruler.h"
23 #include "docclipbase.h"
24 #include "abstractclipitem.h"
25 #include "monitorscene.h"
26 #include "monitoreditwidget.h"
27 #include "kdenlivesettings.h"
28
29 #include <KDebug>
30 #include <KLocale>
31 #include <KFileDialog>
32 #include <KApplication>
33 #include <KMessageBox>
34
35 #include <QMouseEvent>
36 #include <QStylePainter>
37 #include <QMenu>
38 #include <QToolButton>
39 #include <QToolBar>
40 #include <QDesktopWidget>
41 #include <QLabel>
42 #include <QIntValidator>
43 #include <QVBoxLayout>
44
45
46 #define SEEK_INACTIVE (-1)
47
48
49 Monitor::Monitor(Kdenlive::MONITORID id, MonitorManager *manager, QString profile, QWidget *parent) :
50     AbstractMonitor(id, manager, parent),
51     render(NULL),
52     m_currentClip(NULL),
53     m_overlay(NULL),
54     m_scale(1),
55     m_length(2),
56     m_dragStarted(false),
57     m_contextMenu(NULL),
58     m_effectWidget(NULL),
59     m_selectedClip(NULL),
60     m_loopClipTransition(true),
61 #ifdef USE_OPENGL
62     m_glWidget(NULL),
63 #endif
64     m_editMarker(NULL)
65 {
66     QVBoxLayout *layout = new QVBoxLayout;
67     layout->setContentsMargins(0, 0, 0, 0);
68     layout->setSpacing(0);
69
70     // Video widget holder
71     layout->addWidget(videoBox, 10);
72     layout->addStretch();
73
74     // Get base size for icons
75     int s = style()->pixelMetric(QStyle::PM_SmallIconSize);
76
77
78     // Tool bar buttons
79     m_toolbar = new QToolBar(this);
80     m_toolbar->setIconSize(QSize(s, s));
81
82     m_playIcon = KIcon("media-playback-start");
83     m_pauseIcon = KIcon("media-playback-pause");
84
85
86     if (id != Kdenlive::dvdMonitor) {
87         m_toolbar->addAction(KIcon("kdenlive-zone-start"), i18n("Set zone start"), this, SLOT(slotSetZoneStart()));
88         m_toolbar->addAction(KIcon("kdenlive-zone-end"), i18n("Set zone end"), this, SLOT(slotSetZoneEnd()));
89     }
90
91     m_toolbar->addAction(KIcon("media-seek-backward"), i18n("Rewind"), this, SLOT(slotRewind()));
92     //m_toolbar->addAction(KIcon("media-skip-backward"), i18n("Rewind 1 frame"), this, SLOT(slotRewindOneFrame()));
93
94     QToolButton *playButton = new QToolButton(m_toolbar);
95     m_playMenu = new QMenu(i18n("Play..."), this);
96     m_playAction = m_playMenu->addAction(m_playIcon, i18n("Play"));
97     //m_playAction->setCheckable(true);
98     connect(m_playAction, SIGNAL(triggered()), this, SLOT(slotPlay()));
99
100     playButton->setMenu(m_playMenu);
101     playButton->setPopupMode(QToolButton::MenuButtonPopup);
102     m_toolbar->addWidget(playButton);
103
104     //m_toolbar->addAction(KIcon("media-skip-forward"), i18n("Forward 1 frame"), this, SLOT(slotForwardOneFrame()));
105     m_toolbar->addAction(KIcon("media-seek-forward"), i18n("Forward"), this, SLOT(slotForward()));
106
107     playButton->setDefaultAction(m_playAction);
108
109     if (id != Kdenlive::dvdMonitor) {
110         QToolButton *configButton = new QToolButton(m_toolbar);
111         m_configMenu = new QMenu(i18n("Misc..."), this);
112         configButton->setIcon(KIcon("system-run"));
113         configButton->setMenu(m_configMenu);
114         configButton->setPopupMode(QToolButton::QToolButton::InstantPopup);
115         m_toolbar->addWidget(configButton);
116
117         if (id == Kdenlive::clipMonitor) {
118             m_markerMenu = new QMenu(i18n("Go to marker..."), this);
119             m_markerMenu->setEnabled(false);
120             m_configMenu->addMenu(m_markerMenu);
121             connect(m_markerMenu, SIGNAL(triggered(QAction *)), this, SLOT(slotGoToMarker(QAction *)));
122         }
123         m_configMenu->addAction(KIcon("transform-scale"), i18n("Resize (100%)"), this, SLOT(slotSetSizeOneToOne()));
124         m_configMenu->addAction(KIcon("transform-scale"), i18n("Resize (50%)"), this, SLOT(slotSetSizeOneToTwo()));
125     }
126
127     // Create Volume slider popup
128     m_volumePopup = new QFrame(this, Qt::Popup);
129     QVBoxLayout *poplayout = new QVBoxLayout;
130     poplayout->setContentsMargins(0, 0, 0, 0);
131     m_audioSlider = new QSlider(Qt::Vertical);
132     m_audioSlider->setRange(0, 100);
133     poplayout->addWidget(m_audioSlider);
134     m_volumePopup->setLayout(poplayout);
135     KIcon icon;
136     if (KdenliveSettings::volume() == 0) icon = KIcon("audio-volume-muted");
137     else icon = KIcon("audio-volume-medium");
138
139     m_volumeWidget = m_toolbar->widgetForAction(m_toolbar->addAction(icon, i18n("Audio volume"), this, SLOT(slotShowVolume())));
140
141     // we need to show / hide the popup once so that it's geometry can be calculated in slotShowVolume
142     m_volumePopup->show();
143     m_volumePopup->hide();
144
145     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
146     setLayout(layout);
147     setMinimumHeight(200);
148
149     if (profile.isEmpty()) profile = KdenliveSettings::current_profile();
150
151     bool monitorCreated = false;
152 #ifdef Q_WS_MAC
153     createOpenGlWidget(videoBox, profile);
154     monitorCreated = true;
155     //m_glWidget->setFixedSize(width, height);
156 #elif defined(USE_OPENGL)
157     if (KdenliveSettings::openglmonitors()) {
158         monitorCreated = createOpenGlWidget(videoBox, profile);
159     }
160 #endif
161     if (!monitorCreated) {
162         createVideoSurface();
163         render = new Render(m_id, (int) videoSurface->winId(), profile, this);
164         connect(videoSurface, SIGNAL(refreshMonitor()), render, SLOT(doRefresh()));
165     }
166 #ifdef USE_OPENGL
167     else if (m_glWidget) {
168         QVBoxLayout *lay = new QVBoxLayout;
169         lay->setContentsMargins(0, 0, 0, 0);
170         lay->addWidget(m_glWidget);
171         videoBox->setLayout(lay);
172     }
173 #endif
174
175     // Monitor ruler
176     m_ruler = new SmallRuler(this, render);
177     if (id == Kdenlive::dvdMonitor) m_ruler->setZone(-3, -2);
178     layout->addWidget(m_ruler);
179     
180     connect(m_audioSlider, SIGNAL(valueChanged(int)), this, SLOT(slotSetVolume(int)));
181     connect(render, SIGNAL(durationChanged(int)), this, SLOT(adjustRulerSize(int)));
182     connect(render, SIGNAL(rendererStopped(int)), this, SLOT(rendererStopped(int)));
183     connect(render, SIGNAL(rendererPosition(int)), this, SLOT(seekCursor(int)));
184
185     if (id != Kdenlive::clipMonitor) {
186         connect(render, SIGNAL(rendererPosition(int)), this, SIGNAL(renderPosition(int)));
187         connect(render, SIGNAL(durationChanged(int)), this, SIGNAL(durationChanged(int)));
188         connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SIGNAL(zoneUpdated(QPoint)));
189     } else {
190         connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SLOT(setClipZone(QPoint)));
191     }
192
193     if (videoSurface) videoSurface->show();
194
195     if (id == Kdenlive::projectMonitor) {
196         m_effectWidget = new MonitorEditWidget(render, videoBox);
197         connect(m_effectWidget, SIGNAL(showEdit(bool, bool)), this, SLOT(slotShowEffectScene(bool, bool)));
198         m_toolbar->addAction(m_effectWidget->getVisibilityAction());
199         videoBox->layout()->addWidget(m_effectWidget);
200         m_effectWidget->hide();
201     }
202
203     QWidget *spacer = new QWidget(this);
204     spacer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
205     m_toolbar->addWidget(spacer);
206     m_timePos = new TimecodeDisplay(m_monitorManager->timecode(), this);
207     m_toolbar->addWidget(m_timePos);
208     connect(m_timePos, SIGNAL(timeCodeEditingFinished()), this, SLOT(slotSeek()));
209     m_toolbar->setMaximumHeight(s * 1.5);
210     layout->addWidget(m_toolbar);
211 }
212
213 Monitor::~Monitor()
214 {
215     delete m_ruler;
216     delete m_timePos;
217     delete m_overlay;
218     if (m_effectWidget)
219         delete m_effectWidget;
220     delete render;
221 }
222
223 QWidget *Monitor::container()
224 {
225     return videoBox;
226 }
227
228 #ifdef USE_OPENGL
229 bool Monitor::createOpenGlWidget(QWidget *parent, const QString profile)
230 {
231     render = new Render(id(), 0, profile, this);
232     m_glWidget = new VideoGLWidget(parent);
233     if (m_glWidget == NULL) {
234         // Creation failed, we are in trouble...
235         return false;
236     }
237     m_glWidget->setImageAspectRatio(render->dar());
238     m_glWidget->setBackgroundColor(KdenliveSettings::window_background());
239     connect(render, SIGNAL(showImageSignal(QImage)), m_glWidget, SLOT(showImage(QImage)));
240     return true;
241 }
242 #endif
243
244 void Monitor::setupMenu(QMenu *goMenu, QAction *playZone, QAction *loopZone, QMenu *markerMenu, QAction *loopClip)
245 {
246     m_contextMenu = new QMenu(this);
247     m_contextMenu->addMenu(m_playMenu);
248     if (goMenu)
249         m_contextMenu->addMenu(goMenu);
250     if (markerMenu) {
251         m_contextMenu->addMenu(markerMenu);
252         QList <QAction *>list = markerMenu->actions();
253         for (int i = 0; i < list.count(); i++) {
254             if (list.at(i)->data().toString() == "edit_marker") {
255                 m_editMarker = list.at(i);
256                 break;
257             }
258         }
259     }
260
261     m_playMenu->addAction(playZone);
262     m_playMenu->addAction(loopZone);
263     if (loopClip) {
264         m_loopClipAction = loopClip;
265         m_playMenu->addAction(loopClip);
266     }
267
268     //TODO: add save zone to timeline monitor when fixed
269     if (m_id == Kdenlive::clipMonitor) {
270         m_contextMenu->addMenu(m_markerMenu);
271         m_contextMenu->addAction(KIcon("document-save"), i18n("Save zone"), this, SLOT(slotSaveZone()));
272         QAction *extractZone = m_configMenu->addAction(KIcon("document-new"), i18n("Extract Zone"), this, SLOT(slotExtractCurrentZone()));
273         m_contextMenu->addAction(extractZone);
274     }
275     QAction *extractFrame = m_configMenu->addAction(KIcon("document-new"), i18n("Extract frame"), this, SLOT(slotExtractCurrentFrame()));
276     m_contextMenu->addAction(extractFrame);
277
278     if (m_id != Kdenlive::clipMonitor) {
279         QAction *splitView = m_contextMenu->addAction(KIcon("view-split-left-right"), i18n("Split view"), render, SLOT(slotSplitView(bool)));
280         splitView->setCheckable(true);
281         m_configMenu->addAction(splitView);
282     } else {
283         QAction *setThumbFrame = m_contextMenu->addAction(KIcon("document-new"), i18n("Set current image as thumbnail"), this, SLOT(slotSetThumbFrame()));
284         m_configMenu->addAction(setThumbFrame);
285     }
286
287     QAction *showTips = m_contextMenu->addAction(KIcon("help-hint"), i18n("Monitor overlay infos"));
288     showTips->setCheckable(true);
289     connect(showTips, SIGNAL(toggled(bool)), this, SLOT(slotSwitchMonitorInfo(bool)));
290     showTips->setChecked(KdenliveSettings::displayMonitorInfo());
291
292     QAction *dropFrames = m_contextMenu->addAction(KIcon(), i18n("Real time (drop frames)"));
293     dropFrames->setCheckable(true);
294     dropFrames->setChecked(true);
295     connect(dropFrames, SIGNAL(toggled(bool)), this, SLOT(slotSwitchDropFrames(bool)));
296
297     m_configMenu->addAction(showTips);
298     m_configMenu->addAction(dropFrames);
299
300 }
301
302 void Monitor::slotGoToMarker(QAction *action)
303 {
304     int pos = action->data().toInt();
305     slotSeek(pos);
306 }
307
308 void Monitor::slotSetSizeOneToOne()
309 {
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();
314     int height = render->renderHeight();
315     kDebug() << "// render info: " << width << "x" << height;
316     while (width >= maxWidth || height >= maxHeight) {
317         width = width * 0.8;
318         height = height * 0.8;
319     }
320     kDebug() << "// MONITOR; set SIZE: " << width << ", " << height;
321     videoBox->setFixedSize(width, height);
322     updateGeometry();
323     adjustSize();
324     //m_ui.video_frame->setMinimumSize(0, 0);
325     emit adjustMonitorSize();
326 }
327
328 void Monitor::slotSetSizeOneToTwo()
329 {
330     QRect r = QApplication::desktop()->screenGeometry();
331     const int maxWidth = r.width() - 20;
332     const int maxHeight = r.height() - 20;
333     int width = render->renderWidth() / 2;
334     int height = render->renderHeight() / 2;
335     kDebug() << "// render info: " << width << "x" << height;
336     while (width >= maxWidth || height >= maxHeight) {
337         width = width * 0.8;
338         height = height * 0.8;
339     }
340     kDebug() << "// MONITOR; set SIZE: " << width << ", " << height;
341     videoBox->setFixedSize(width, height);
342     updateGeometry();
343     adjustSize();
344     //m_ui.video_frame->setMinimumSize(0, 0);
345     emit adjustMonitorSize();
346 }
347
348 void Monitor::resetSize()
349 {
350     videoBox->setMinimumSize(0, 0);
351 }
352
353 QString Monitor::getTimecodeFromFrames(int pos)
354 {
355     return m_monitorManager->timecode().getTimecodeFromFrames(pos);
356 }
357
358 double Monitor::fps() const
359 {
360     return m_monitorManager->timecode().fps();
361 }
362
363 DocClipBase *Monitor::activeClip()
364 {
365     return m_currentClip;
366 }
367
368 void Monitor::updateMarkers(DocClipBase *source)
369 {
370     if (source == m_currentClip && source != NULL) {
371         m_markerMenu->clear();
372         QList <CommentedTime> markers = m_currentClip->commentedSnapMarkers();
373         if (!markers.isEmpty()) {
374             QList <int> marks;
375             for (int i = 0; i < markers.count(); i++) {
376                 int pos = (int) markers.at(i).time().frames(m_monitorManager->timecode().fps());
377                 marks.append(pos);
378                 QString position = m_monitorManager->timecode().getTimecode(markers.at(i).time()) + ' ' + markers.at(i).comment();
379                 QAction *go = m_markerMenu->addAction(position);
380                 go->setData(pos);
381             }
382         }
383         m_ruler->setMarkers(markers);
384         m_markerMenu->setEnabled(!m_markerMenu->isEmpty());
385     }
386 }
387
388 void Monitor::slotSeekToPreviousSnap()
389 {
390     if (m_currentClip) slotSeek(getSnapForPos(true).frames(m_monitorManager->timecode().fps()));
391 }
392
393 void Monitor::slotSeekToNextSnap()
394 {
395     if (m_currentClip) slotSeek(getSnapForPos(false).frames(m_monitorManager->timecode().fps()));
396 }
397
398 GenTime Monitor::position()
399 {
400     return render->seekPosition();
401 }
402
403 GenTime Monitor::getSnapForPos(bool previous)
404 {
405     QList <GenTime> snaps;
406     QList < GenTime > markers = m_currentClip->snapMarkers();
407     for (int i = 0; i < markers.size(); ++i) {
408         GenTime t = markers.at(i);
409         snaps.append(t);
410     }
411     QPoint zone = m_ruler->zone();
412     snaps.append(GenTime(zone.x(), m_monitorManager->timecode().fps()));
413     snaps.append(GenTime(zone.y(), m_monitorManager->timecode().fps()));
414     snaps.append(GenTime());
415     snaps.append(m_currentClip->duration());
416     qSort(snaps);
417
418     const GenTime pos = render->seekPosition();
419     for (int i = 0; i < snaps.size(); ++i) {
420         if (previous && snaps.at(i) >= pos) {
421             if (i == 0) i = 1;
422             return snaps.at(i - 1);
423         } else if (!previous && snaps.at(i) > pos) {
424             return snaps.at(i);
425         }
426     }
427     return GenTime();
428 }
429
430 void Monitor::slotZoneMoved(int start, int end)
431 {
432     m_ruler->setZone(start, end);
433     setClipZone(m_ruler->zone());
434     checkOverlay();
435 }
436
437 void Monitor::slotSetZoneStart()
438 {
439     m_ruler->setZoneStart();
440     emit zoneUpdated(m_ruler->zone());
441     setClipZone(m_ruler->zone());
442     checkOverlay();
443 }
444
445 void Monitor::slotSetZoneEnd()
446 {
447     m_ruler->setZoneEnd();
448     emit zoneUpdated(m_ruler->zone());
449     setClipZone(m_ruler->zone());
450     checkOverlay();
451 }
452
453 // virtual
454 void Monitor::mousePressEvent(QMouseEvent * event)
455 {
456     if (event->button() != Qt::RightButton) {
457         if (videoBox->geometry().contains(event->pos()) && (!m_overlay || !m_overlay->underMouse())) {
458             m_dragStarted = true;
459             m_DragStartPosition = event->pos();
460         }
461     } else if (m_contextMenu && (!m_effectWidget || !m_effectWidget->isVisible())) {
462         m_contextMenu->popup(event->globalPos());
463     }
464 }
465
466 void Monitor::resizeEvent(QResizeEvent *event)
467 {
468     Q_UNUSED(event);
469     if (render && isVisible() && isActive()) render->doRefresh();
470 }
471
472 void Monitor::slotSwitchFullScreen()
473 {
474     videoBox->switchFullScreen();
475 }
476
477 // virtual
478 void Monitor::mouseReleaseEvent(QMouseEvent * event)
479 {
480     if (m_dragStarted && event->button() != Qt::RightButton) {
481         if (videoBox->geometry().contains(event->pos()) && (!m_effectWidget || !m_effectWidget->isVisible())) {
482             if (isActive()) slotPlay();
483             else slotActivateMonitor();
484         } //else event->ignore(); //QWidget::mouseReleaseEvent(event);
485     }
486     m_dragStarted = false;
487     event->accept();
488 }
489
490 // virtual
491 void Monitor::mouseMoveEvent(QMouseEvent *event)
492 {
493     if (!m_dragStarted || m_currentClip == NULL) return;
494
495     if ((event->pos() - m_DragStartPosition).manhattanLength()
496             < QApplication::startDragDistance())
497         return;
498
499     {
500         QDrag *drag = new QDrag(this);
501         QMimeData *mimeData = new QMimeData;
502
503         QStringList list;
504         list.append(m_currentClip->getId());
505         QPoint p = m_ruler->zone();
506         list.append(QString::number(p.x()));
507         list.append(QString::number(p.y()));
508         QByteArray data;
509         data.append(list.join(";").toUtf8());
510         mimeData->setData("kdenlive/clip", data);
511         drag->setMimeData(mimeData);
512         /*QPixmap pix = m_currentClip->thumbnail();
513         drag->setPixmap(pix);
514         drag->setHotSpot(QPoint(0, 50));*/
515         drag->start(Qt::MoveAction);
516         /*Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction);
517         Qt::DropAction dropAction;
518         dropAction = drag->start(Qt::CopyAction | Qt::MoveAction);*/
519
520         //Qt::DropAction dropAction = drag->exec();
521
522     }
523     //event->accept();
524 }
525
526
527 /*void Monitor::dragMoveEvent(QDragMoveEvent * event) {
528     event->setDropAction(Qt::IgnoreAction);
529     event->setDropAction(Qt::MoveAction);
530     if (event->mimeData()->hasText()) {
531         event->acceptProposedAction();
532     }
533 }
534
535 Qt::DropActions Monitor::supportedDropActions() const {
536     // returns what actions are supported when dropping
537     return Qt::MoveAction;
538 }*/
539
540 QStringList Monitor::mimeTypes() const
541 {
542     QStringList qstrList;
543     // list of accepted mime types for drop
544     qstrList.append("kdenlive/clip");
545     return qstrList;
546 }
547
548 // virtual
549 void Monitor::wheelEvent(QWheelEvent * event)
550 {
551     slotMouseSeek(event->delta(), event->modifiers() == Qt::ControlModifier);
552     event->accept();
553 }
554
555 void Monitor::mouseDoubleClickEvent(QMouseEvent * event)
556 {
557     if (!KdenliveSettings::openglmonitors()) {
558         videoBox->switchFullScreen();
559         event->accept();
560     }
561 }
562
563 void Monitor::slotMouseSeek(int eventDelta, bool fast)
564 {
565     if (fast) {
566         int delta = m_monitorManager->timecode().fps();
567         if (eventDelta > 0) delta = 0 - delta;
568         if (render->requestedSeekPosition != SEEK_INACTIVE)
569             slotSeek(render->requestedSeekPosition - delta);
570         else slotSeek(render->seekFramePosition() - delta);
571     } else {
572         if (eventDelta >= 0) slotForwardOneFrame();
573         else slotRewindOneFrame();
574     }
575 }
576
577 void Monitor::slotSetThumbFrame()
578 {
579     if (m_currentClip == NULL) {
580         return;
581     }
582     m_currentClip->setClipThumbFrame((uint) render->seekFramePosition());
583     emit refreshClipThumbnail(m_currentClip->getId(), true);
584 }
585
586 void Monitor::slotExtractCurrentZone()
587 {
588     if (m_currentClip == NULL) return;
589     emit extractZone(m_currentClip->getId(), m_ruler->zone());
590 }
591
592 void Monitor::slotExtractCurrentFrame()
593 {
594     QImage frame;
595     // check if we are using a proxy
596     if (m_currentClip && !m_currentClip->getProperty("proxy").isEmpty() && m_currentClip->getProperty("proxy") != "-") {
597         // using proxy, use original clip url to get frame
598         frame = render->extractFrame(render->seekFramePosition(), m_currentClip->fileURL().path());
599     }
600     else frame = render->extractFrame(render->seekFramePosition());
601     QPointer<KFileDialog> fs = new KFileDialog(KUrl(), "image/png", this);
602     fs->setOperationMode(KFileDialog::Saving);
603     fs->setMode(KFile::File);
604     fs->setConfirmOverwrite(true);
605     fs->setKeepLocation(true);
606     fs->exec();
607     QString path;
608     if (fs) path = fs->selectedFile();
609     delete fs;
610     if (!path.isEmpty()) {
611         frame.save(path);
612     }
613 }
614
615 void Monitor::setTimePos(const QString &pos)
616 {
617     m_timePos->setValue(pos);
618     slotSeek();
619 }
620
621 void Monitor::slotSeek()
622 {
623     slotSeek(m_timePos->getValue());
624 }
625
626 void Monitor::slotSeek(int pos)
627 {
628     if (render == NULL) return;
629     slotActivateMonitor();
630     render->seekToFrame(pos);
631     m_ruler->update();
632 }
633
634 void Monitor::checkOverlay()
635 {
636     if (m_overlay == NULL) return;
637     QString overlayText;
638     int pos = m_timePos->getValue();//render->seekFramePosition();
639     QPoint zone = m_ruler->zone();
640     if (pos == zone.x())
641         overlayText = i18n("In Point");
642     else if (pos == zone.y())
643         overlayText = i18n("Out Point");
644     else {
645         if (m_currentClip) {
646             overlayText = m_currentClip->markerComment(GenTime(pos, m_monitorManager->timecode().fps()));
647             if (!overlayText.isEmpty()) {
648                 m_overlay->setOverlayText(overlayText, false);
649                 return;
650             }
651         }
652     }
653     if (m_overlay->isVisible() && overlayText.isEmpty()) m_overlay->setOverlayText(QString(), false);
654     else m_overlay->setOverlayText(overlayText);
655 }
656
657 void Monitor::slotStart()
658 {
659     slotActivateMonitor();
660     render->play(0);
661     render->seekToFrame(0);
662 }
663
664 void Monitor::slotEnd()
665 {
666     slotActivateMonitor();
667     render->play(0);
668     render->seekToFrame(render->getLength());
669 }
670
671 void Monitor::slotZoneStart()
672 {
673     slotActivateMonitor();
674     render->play(0);
675     render->seekToFrame(m_ruler->zone().x());
676 }
677
678 void Monitor::slotZoneEnd()
679 {
680     slotActivateMonitor();
681     render->play(0);
682     render->seekToFrame(m_ruler->zone().y());
683 }
684
685 void Monitor::slotRewind(double speed)
686 {
687     slotActivateMonitor();
688     if (speed == 0) {
689         double currentspeed = render->playSpeed();
690         if (currentspeed >= 0) render->play(-1);
691         else switch((int) currentspeed) {
692             case -1:
693                 render->play(-2);
694                 break;
695             case -2:
696                 render->play(-3);
697                 break;
698             case -3:
699                 render->play(-5);
700                 break;
701             default:
702                 render->play(-8);
703         }
704     } else render->play(speed);
705     //m_playAction->setChecked(true);
706     m_playAction->setIcon(m_pauseIcon);
707 }
708
709 void Monitor::slotForward(double speed)
710 {
711     slotActivateMonitor();
712     if (speed == 0) {
713         double currentspeed = render->playSpeed();
714         if (currentspeed <= 0) render->play(1);
715         else switch((int) currentspeed) {
716             case 1:
717                 render->play(2);
718                 break;
719             case 2:
720                 render->play(3);
721                 break;
722             case 3:
723                 render->play(5);
724                 break;
725             default:
726                 render->play(8);
727         }
728     } else render->play(speed);
729     //m_playAction->setChecked(true);
730     m_playAction->setIcon(m_pauseIcon);
731 }
732
733 void Monitor::slotRewindOneFrame(int diff)
734 {
735     slotActivateMonitor();
736     render->play(0);
737     render->seekToFrameDiff(-diff);
738     m_ruler->update();
739 }
740
741 void Monitor::slotForwardOneFrame(int diff)
742 {
743     slotActivateMonitor();
744     render->play(0);
745     render->seekToFrameDiff(diff);
746     m_ruler->update();
747 }
748
749 void Monitor::seekCursor(int pos)
750 {
751     if (m_ruler->slotNewValue(pos)) {
752         m_timePos->setValue(pos);
753         checkOverlay();
754     }
755 }
756
757 void Monitor::rendererStopped(int pos)
758 {
759     if (m_ruler->slotNewValue(pos)) {
760         m_timePos->setValue(pos);
761         checkOverlay();
762     }
763     m_playAction->setIcon(m_playIcon);
764 }
765
766 void Monitor::adjustRulerSize(int length)
767 {
768     if (length > 0) m_length = length;
769     m_ruler->adjustScale(m_length);
770     if (m_currentClip != NULL) {
771         QPoint zone = m_currentClip->zone();
772         m_ruler->setZone(zone.x(), zone.y());
773     }
774 }
775
776 void Monitor::stop()
777 {
778     if (render) render->stop();
779 }
780
781 void Monitor::start()
782 {
783     if (!isVisible() || !isActive()) return;
784 #ifdef USE_OPENGL    
785     if (m_glWidget) m_glWidget->activateMonitor();
786 #endif
787     if (render) render->startConsumer();
788 }
789
790 void Monitor::refreshMonitor(bool visible)
791 {
792     if (visible && render) {
793         if (!slotActivateMonitor()) {
794             // the monitor was already active, simply refreshClipThumbnail
795             render->doRefresh();
796         }
797     }
798 }
799
800 void Monitor::refreshMonitor()
801 {
802     if (isActive()) {
803         render->doRefresh();
804     }
805 }
806
807 void Monitor::pause()
808 {
809     if (render == NULL) return;
810     slotActivateMonitor();
811     render->pause();
812     //m_playAction->setChecked(true);
813     m_playAction->setIcon(m_playIcon);
814 }
815
816 void Monitor::unpause()
817 {
818 }
819
820 void Monitor::slotPlay()
821 {
822     if (render == NULL) return;
823     slotActivateMonitor();
824     if (render->isPlaying()) {
825         m_playAction->setIcon(m_playIcon);
826         render->switchPlay(false);
827     }
828     else {
829         m_playAction->setIcon(m_pauseIcon);
830         render->switchPlay(true);
831     }
832     m_ruler->refreshRuler();
833 }
834
835 void Monitor::slotPlayZone()
836 {
837     if (render == NULL) return;
838     slotActivateMonitor();
839     QPoint p = m_ruler->zone();
840     render->playZone(GenTime(p.x(), m_monitorManager->timecode().fps()), GenTime(p.y(), m_monitorManager->timecode().fps()));
841     //m_playAction->setChecked(true);
842     m_playAction->setIcon(m_pauseIcon);
843 }
844
845 void Monitor::slotLoopZone()
846 {
847     if (render == NULL) return;
848     slotActivateMonitor();
849     QPoint p = m_ruler->zone();
850     render->loopZone(GenTime(p.x(), m_monitorManager->timecode().fps()), GenTime(p.y(), m_monitorManager->timecode().fps()));
851     //m_playAction->setChecked(true);
852     m_playAction->setIcon(m_pauseIcon);
853 }
854
855 void Monitor::slotLoopClip()
856 {
857     if (render == NULL || m_selectedClip == NULL)
858         return;
859     slotActivateMonitor();
860     render->loopZone(m_selectedClip->startPos(), m_selectedClip->endPos());
861     //m_playAction->setChecked(true);
862     m_playAction->setIcon(m_pauseIcon);
863 }
864
865 void Monitor::updateClipProducer(Mlt::Producer *prod)
866 {
867     if (render == NULL) return;
868    render->setProducer(prod, render->seekFramePosition());
869 }
870
871 void Monitor::slotSetClipProducer(DocClipBase *clip, QPoint zone, bool forceUpdate, int position)
872 {
873     if (render == NULL) return;
874     if (clip == NULL && m_currentClip != NULL) {
875         m_currentClip->lastSeekPosition = render->seekFramePosition();
876         kDebug()<<"// SETTING NULL CLIP MONITOR";
877         m_currentClip = NULL;
878         m_length = -1;
879         render->setProducer(NULL, -1);
880         return;
881     }
882
883     if (clip != m_currentClip || forceUpdate) {
884         if (m_currentClip) m_currentClip->lastSeekPosition = render->seekFramePosition();
885         m_currentClip = clip;
886         if (position == -1) position = clip->lastSeekPosition;
887         updateMarkers(clip);
888         Mlt::Producer *prod = NULL;
889         if (clip) prod = clip->getCloneProducer();
890         if (render->setProducer(prod, position) == -1) {
891             // MLT CONSUMER is broken
892             kDebug(QtWarningMsg) << "ERROR, Cannot start monitor";
893         }
894     } else {
895         if (m_currentClip) {
896             slotActivateMonitor();
897             if (position == -1) position = render->seekFramePosition();
898             render->seek(position);
899         }
900     }
901     if (!zone.isNull()) {
902         m_ruler->setZone(zone.x(), zone.y());
903         render->seek(zone.x());
904     }
905 }
906
907 void Monitor::slotOpenFile(const QString &file)
908 {
909     if (render == NULL) return;
910     slotActivateMonitor();
911     render->loadUrl(file);
912 }
913
914 void Monitor::slotSaveZone()
915 {
916     if (render == NULL) return;
917     emit saveZone(render, m_ruler->zone(), m_currentClip);
918
919     //render->setSceneList(doc, 0);
920 }
921
922 void Monitor::setCustomProfile(const QString &profile, Timecode tc)
923 {
924     m_timePos->updateTimeCode(tc);
925     if (render == NULL) return;
926     if (!render->hasProfile(profile)) {
927         slotActivateMonitor();
928         render->resetProfile(profile);
929 #ifdef USE_OPENGL    
930         if (m_glWidget) m_glWidget->setImageAspectRatio(render->dar());
931 #endif
932     }
933 }
934
935 void Monitor::resetProfile(const QString &profile)
936 {
937     m_timePos->updateTimeCode(m_monitorManager->timecode());
938     if (render == NULL) return;
939     if (!render->hasProfile(profile)) {
940         slotActivateMonitor();
941         render->resetProfile(profile);
942 #ifdef USE_OPENGL
943         if (m_glWidget) m_glWidget->setImageAspectRatio(render->dar());
944 #endif
945     }
946     if (m_effectWidget)
947         m_effectWidget->resetProfile(render);
948 }
949
950 void Monitor::saveSceneList(QString path, QDomElement info)
951 {
952     if (render == NULL) return;
953     render->saveSceneList(path, info);
954 }
955
956 const QString Monitor::sceneList()
957 {
958     if (render == NULL) return QString();
959     return render->sceneList();
960 }
961
962 void Monitor::setClipZone(QPoint pos)
963 {
964     if (m_currentClip == NULL) return;
965     m_currentClip->setZone(pos);
966 }
967
968 void Monitor::slotSwitchDropFrames(bool show)
969 {
970     render->setDropFrames(show);
971 }
972
973 void Monitor::slotSwitchMonitorInfo(bool show)
974 {
975     KdenliveSettings::setDisplayMonitorInfo(show);
976     if (show) {
977         if (m_overlay) return;
978         if (videoSurface == NULL) {
979             // Using OpenGL display
980 #ifdef USE_OPENGL
981             if (m_glWidget->layout()) delete m_glWidget->layout();
982             m_overlay = new Overlay();
983             connect(m_overlay, SIGNAL(editMarker()), this, SLOT(slotEditMarker()));
984             QVBoxLayout *layout = new QVBoxLayout;
985             layout->addStretch(10);
986             layout->addWidget(m_overlay);
987             m_glWidget->setLayout(layout);
988 #endif
989         } else {
990             if (videoSurface->layout()) delete videoSurface->layout();
991             m_overlay = new Overlay();
992             connect(m_overlay, SIGNAL(editMarker()), this, SLOT(slotEditMarker()));
993             QVBoxLayout *layout = new QVBoxLayout;
994             layout->addStretch(10);
995             layout->addWidget(m_overlay);
996             videoSurface->setLayout(layout);
997             m_overlay->raise();
998             m_overlay->setHidden(true);
999         }
1000         checkOverlay();
1001     } else {
1002         delete m_overlay;
1003         m_overlay = NULL;
1004     }
1005 }
1006
1007 void Monitor::slotEditMarker()
1008 {
1009     if (m_editMarker) m_editMarker->trigger();
1010 }
1011
1012 void Monitor::updateTimecodeFormat()
1013 {
1014     m_timePos->slotUpdateTimeCodeFormat();
1015 }
1016
1017 QStringList Monitor::getZoneInfo() const
1018 {
1019     QStringList result;
1020     if (m_currentClip == NULL) return result;
1021     result << m_currentClip->getId();
1022     QPoint zone = m_ruler->zone();
1023     result << QString::number(zone.x()) << QString::number(zone.y());
1024     return result;
1025 }
1026
1027 void Monitor::slotSetSelectedClip(AbstractClipItem* item)
1028 {
1029     if (item) {
1030         m_loopClipAction->setEnabled(true);
1031         m_selectedClip = item;
1032     } else {
1033         m_loopClipAction->setEnabled(false);
1034     }
1035 }
1036
1037 void Monitor::slotSetSelectedClip(ClipItem* item)
1038 {
1039     if (item || (!item && !m_loopClipTransition)) {
1040         m_loopClipTransition = false;
1041         slotSetSelectedClip((AbstractClipItem*)item);
1042     }
1043 }
1044
1045 void Monitor::slotSetSelectedClip(Transition* item)
1046 {
1047     if (item || (!item && m_loopClipTransition)) {
1048         m_loopClipTransition = true;
1049         slotSetSelectedClip((AbstractClipItem*)item);
1050     }
1051 }
1052
1053
1054 void Monitor::slotShowEffectScene(bool show, bool manuallyTriggered)
1055 {
1056     if (m_id == Kdenlive::projectMonitor) {
1057         if (!m_effectWidget->getVisibilityAction()->isChecked())
1058             show = false;
1059         if (m_effectWidget->isVisible() == show)
1060             return;
1061         setUpdatesEnabled(false);
1062         if (show) {
1063             if (videoSurface) {
1064                 videoSurface->setVisible(false);
1065                 // Preview is handeled internally through the Render::showFrame method
1066                 render->disablePreview(true);
1067 #ifdef USE_OPENGL
1068             } else {
1069                 m_glWidget->setVisible(false);
1070 #endif
1071             }
1072             m_effectWidget->setVisible(true);
1073             m_effectWidget->getScene()->slotZoomFit();
1074             emit requestFrameForAnalysis(true);
1075         } else {    
1076             m_effectWidget->setVisible(false);
1077             emit requestFrameForAnalysis(false);
1078             if (videoSurface) {
1079                 videoSurface->setVisible(true);
1080                 // Preview is handeled internally through the Render::showFrame method
1081                 render->disablePreview(false);
1082             
1083 #ifdef USE_OPENGL
1084             } else {
1085                 m_glWidget->setVisible(true);
1086 #endif
1087             }
1088         }
1089         if (!manuallyTriggered)
1090             m_effectWidget->showVisibilityButton(show);
1091         setUpdatesEnabled(true);
1092         videoBox->setEnabled(show);
1093         //render->doRefresh();
1094     }
1095 }
1096
1097 MonitorEditWidget* Monitor::getEffectEdit()
1098 {
1099     return m_effectWidget;
1100 }
1101
1102 bool Monitor::effectSceneDisplayed()
1103 {
1104     return m_effectWidget->isVisible();
1105 }
1106
1107 void Monitor::slotSetVolume(int volume)
1108 {
1109     KdenliveSettings::setVolume(volume);
1110     KIcon icon;
1111     if (volume == 0) icon = KIcon("audio-volume-muted");
1112     else icon = KIcon("audio-volume-medium");
1113     static_cast <QToolButton *>(m_volumeWidget)->setIcon(icon);
1114     render->slotSetVolume(volume);
1115 }
1116
1117 void Monitor::slotShowVolume()
1118 {
1119     m_volumePopup->move(mapToGlobal(m_toolbar->geometry().topLeft()) + QPoint(mapToParent(m_volumeWidget->geometry().bottomLeft()).x(), -m_volumePopup->height()));
1120     int vol = render->volume();
1121     // Disable widget if we cannot get the volume
1122     m_volumePopup->setEnabled(vol != -1);
1123     m_audioSlider->blockSignals(true);
1124     m_audioSlider->setValue(vol);
1125     m_audioSlider->blockSignals(false);
1126     m_volumePopup->show();
1127 }
1128
1129 AbstractRender *Monitor::abstractRender()
1130 {
1131     return render;
1132 }
1133
1134 void Monitor::reloadProducer(const QString &id)
1135 {
1136     if (!m_currentClip) return;
1137     if (m_currentClip->getId() == id)
1138         slotSetClipProducer(m_currentClip, m_currentClip->zone(), true);
1139 }
1140
1141 QString Monitor::getMarkerThumb(GenTime pos)
1142 {
1143     if (!m_currentClip) return QString();
1144     if (!m_currentClip->getClipHash().isEmpty()) {
1145         QString url = m_monitorManager->getProjectFolder() + "thumbs/" + m_currentClip->getClipHash() + '#' + QString::number(pos.frames(m_monitorManager->timecode().fps())) + ".png";
1146         if (QFile::exists(url)) return url;
1147     }
1148     return QString();
1149 }
1150
1151 void Monitor::setPalette ( const QPalette & p)
1152 {
1153     QWidget::setPalette(p);
1154     if (m_ruler) m_ruler->updatePalette();
1155     
1156 }
1157
1158 Overlay::Overlay(QWidget* parent) :
1159     QLabel(parent)
1160 {
1161     //setAttribute(Qt::WA_TransparentForMouseEvents);
1162     setAutoFillBackground(true);
1163     setBackgroundRole(QPalette::Base);
1164     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
1165     setCursor(Qt::PointingHandCursor);
1166
1167 }
1168
1169 // virtual
1170 void Overlay::mouseReleaseEvent ( QMouseEvent * event )
1171 {
1172     event->ignore();
1173 }
1174
1175 // virtual
1176 void Overlay::mousePressEvent( QMouseEvent * event )
1177 {
1178     event->ignore();
1179 }
1180
1181 // virtual
1182 void Overlay::mouseDoubleClickEvent ( QMouseEvent * event )
1183 {
1184     emit editMarker();
1185     event->ignore();
1186 }
1187
1188 void Overlay::setOverlayText(const QString &text, bool isZone)
1189 {
1190     if (text.isEmpty()) {
1191         /*QPalette p;
1192         p.setColor(QPalette::Base, KdenliveSettings::window_background());
1193         setPalette(p);
1194         setText(QString());
1195         repaint();*/
1196         setHidden(true);
1197         return;
1198     }
1199     setHidden(true);
1200     QPalette p;
1201     p.setColor(QPalette::Text, Qt::white);
1202     if (isZone) p.setColor(QPalette::Base, QColor(200, 0, 0));
1203     else p.setColor(QPalette::Base, QColor(0, 0, 200));
1204     setPalette(p);
1205     setText(' ' + text + ' ');
1206     setHidden(false);
1207 }
1208
1209
1210 #include "monitor.moc"