]> git.sesse.net Git - kdenlive/blob - src/monitor.cpp
290ab3f9b980dd71d13ac1bc7e935345506c403c
[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 "renderer.h"
23 #include "monitormanager.h"
24 #include "smallruler.h"
25 #include "docclipbase.h"
26 #include "monitorscene.h"
27 #include "abstractclipitem.h"
28 #include "kdenlivesettings.h"
29
30 #include <KDebug>
31 #include <KLocale>
32 #include <KFileDialog>
33 #include <KApplication>
34 #include <KMessageBox>
35
36 #include <QMouseEvent>
37 #include <QStylePainter>
38 #include <QMenu>
39 #include <QToolButton>
40 #include <QToolBar>
41 #include <QDesktopWidget>
42 #include <QLabel>
43 #include <QIntValidator>
44 #include <QVBoxLayout>
45 #include <QGraphicsView>
46
47
48 Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget *parent) :
49     QWidget(parent),
50     render(NULL),
51     m_name(name),
52     m_monitorManager(manager),
53     m_currentClip(NULL),
54     m_ruler(new SmallRuler(m_monitorManager)),
55     m_overlay(NULL),
56     m_isActive(false),
57     m_scale(1),
58     m_length(0),
59     m_dragStarted(false),
60     m_monitorRefresh(NULL),
61     m_effectScene(NULL),
62     m_effectView(NULL),
63     m_selectedClip(NULL),
64     m_loopClipTransition(true)
65
66 {
67     QVBoxLayout *layout = new QVBoxLayout;
68     layout->setContentsMargins(0, 0, 0, 0);
69     layout->setSpacing(0);
70
71     // Video widget holder
72     m_videoBox = new VideoContainer(this);
73     m_videoBox->setContentsMargins(0, 0, 0, 0);
74     m_videoBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
75     layout->addWidget(m_videoBox, 10);
76     layout->addStretch();
77
78     // Get base size for icons
79     int s = style()->pixelMetric(QStyle::PM_SmallIconSize);
80
81     // Monitor ruler
82     layout->addWidget(m_ruler);
83     // Tool bar buttons
84     QToolBar *toolbar = new QToolBar(name, this);
85     toolbar->setIconSize(QSize(s, s));
86
87     m_playIcon = KIcon("media-playback-start");
88     m_pauseIcon = KIcon("media-playback-pause");
89
90     if (name != "chapter") {
91         toolbar->addAction(KIcon("kdenlive-zone-start"), i18n("Set zone start"), this, SLOT(slotSetZoneStart()));
92         toolbar->addAction(KIcon("kdenlive-zone-end"), i18n("Set zone end"), this, SLOT(slotSetZoneEnd()));
93     } else {
94         m_ruler->setZone(-3, -2);
95     }
96
97     toolbar->addAction(KIcon("media-seek-backward"), i18n("Rewind"), this, SLOT(slotRewind()));
98     //toolbar->addAction(KIcon("media-skip-backward"), i18n("Rewind 1 frame"), this, SLOT(slotRewindOneFrame()));
99
100     QToolButton *playButton = new QToolButton(toolbar);
101     m_playMenu = new QMenu(i18n("Play..."), this);
102     m_playAction = m_playMenu->addAction(m_playIcon, i18n("Play"));
103     //m_playAction->setCheckable(true);
104     connect(m_playAction, SIGNAL(triggered()), this, SLOT(slotPlay()));
105
106     playButton->setMenu(m_playMenu);
107     playButton->setPopupMode(QToolButton::MenuButtonPopup);
108     toolbar->addWidget(playButton);
109
110     //toolbar->addAction(KIcon("media-skip-forward"), i18n("Forward 1 frame"), this, SLOT(slotForwardOneFrame()));
111     toolbar->addAction(KIcon("media-seek-forward"), i18n("Forward"), this, SLOT(slotForward()));
112
113     playButton->setDefaultAction(m_playAction);
114
115     if (name != "chapter") {
116         QToolButton *configButton = new QToolButton(toolbar);
117         m_configMenu = new QMenu(i18n("Misc..."), this);
118         configButton->setIcon(KIcon("system-run"));
119         configButton->setMenu(m_configMenu);
120         configButton->setPopupMode(QToolButton::QToolButton::InstantPopup);
121         toolbar->addWidget(configButton);
122
123         if (name == "clip") {
124             m_markerMenu = new QMenu(i18n("Go to marker..."), this);
125             m_markerMenu->setEnabled(false);
126             m_configMenu->addMenu(m_markerMenu);
127             connect(m_markerMenu, SIGNAL(triggered(QAction *)), this, SLOT(slotGoToMarker(QAction *)));
128         }
129         m_configMenu->addAction(KIcon("transform-scale"), i18n("Resize (100%)"), this, SLOT(slotSetSizeOneToOne()));
130         m_configMenu->addAction(KIcon("transform-scale"), i18n("Resize (50%)"), this, SLOT(slotSetSizeOneToTwo()));
131     }
132
133     QWidget *spacer = new QWidget(this);
134     spacer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
135     toolbar->addWidget(spacer);
136     m_timePos = new TimecodeDisplay(m_monitorManager->timecode(), this);
137     toolbar->addWidget(m_timePos);
138     connect(m_timePos, SIGNAL(editingFinished()), this, SLOT(slotSeek()));
139     toolbar->setMaximumHeight(s * 1.5);
140     layout->addWidget(toolbar);
141
142     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
143     setLayout(layout);
144     setMinimumHeight(200);
145
146     if (profile.isEmpty()) profile = KdenliveSettings::current_profile();
147
148     bool monitorCreated = false;
149 #ifdef Q_WS_MAC
150     createOpenGlWidget(videoBox, profile);
151     monitorCreated = true;
152     //m_glWidget->setFixedSize(width, height);
153 #elif defined (USE_OPEN_GL)
154     if (KdenliveSettings::openglmonitors()) {
155         monitorCreated = createOpenGlWidget(m_videoBox, profile);
156     }
157 #endif
158     QVBoxLayout *lay = new QVBoxLayout;
159     lay->setContentsMargins(0, 0, 0, 0);
160     if (!monitorCreated) {
161         m_monitorRefresh = new MonitorRefresh;
162         lay->addWidget(m_monitorRefresh);
163         m_videoBox->setLayout(lay);
164         render = new Render(m_name, (int) m_monitorRefresh->winId(), profile, this);
165         m_monitorRefresh->setRenderer(render);
166     }
167
168     connect(m_ruler, SIGNAL(seekRenderer(int)), this, SLOT(slotSeek(int)));
169     connect(render, SIGNAL(durationChanged(int)), this, SLOT(adjustRulerSize(int)));
170     connect(render, SIGNAL(rendererStopped(int)), this, SLOT(rendererStopped(int)));
171
172     //render->createVideoXWindow(m_ui.video_frame->winId(), -1);
173
174     if (name != "clip") {
175         connect(render, SIGNAL(rendererPosition(int)), this, SIGNAL(renderPosition(int)));
176         connect(render, SIGNAL(durationChanged(int)), this, SIGNAL(durationChanged(int)));
177         connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SIGNAL(zoneUpdated(QPoint)));
178     } else {
179         connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SLOT(setClipZone(QPoint)));
180     }
181
182     if (m_monitorRefresh) m_monitorRefresh->show();
183
184     if (name == "project") {
185         m_effectScene = new MonitorScene(render);
186         m_effectView = new QGraphicsView(m_effectScene, m_videoBox);
187         lay->addWidget(m_effectView);
188         m_effectView->setRenderHints(QFlags<QPainter::RenderHint>());
189         m_effectView->scale(((double) render->renderWidth()) / render->frameRenderWidth(), 1.0);
190         m_effectView->setMouseTracking(true);
191         m_effectScene->setUp();
192         m_effectView->hide();
193     }
194 }
195
196 Monitor::~Monitor()
197 {
198     delete m_ruler;
199     delete m_timePos;
200     delete m_overlay;
201     if (m_name == "project") {
202         delete m_effectView;
203         delete m_effectScene;
204     }
205     delete m_monitorRefresh;
206     delete render;
207 }
208
209 QWidget *Monitor::container()
210 {
211     return m_videoBox;
212 }
213
214 QString Monitor::name() const
215 {
216     return m_name;
217 }
218
219 #if defined(Q_WS_MAC) || defined(USE_OPEN_GL)
220 bool Monitor::createOpenGlWidget(QWidget *parent, const QString profile)
221 {
222     render = new Render(m_name, 0, profile, this);
223     m_glWidget = new VideoGLWidget(parent);
224     if (m_glWidget == NULL) {
225         // Creation failed, we are in trouble...
226         return false;
227     }
228     m_glWidget->setImageAspectRatio(render->dar());
229     m_glWidget->setBackgroundColor(KdenliveSettings::window_background());
230     connect(render, SIGNAL(showImageSignal(QImage)), m_glWidget, SLOT(showImage(QImage)));
231     return true;
232 }
233 #endif
234
235 void Monitor::setupMenu(QMenu *goMenu, QAction *playZone, QAction *loopZone, QMenu *markerMenu, QAction *loopClip)
236 {
237     m_contextMenu = new QMenu(this);
238     m_contextMenu->addMenu(m_playMenu);
239     if (goMenu)
240         m_contextMenu->addMenu(goMenu);
241     if (markerMenu)
242         m_contextMenu->addMenu(markerMenu);
243
244     m_playMenu->addAction(playZone);
245     m_playMenu->addAction(loopZone);
246     if (loopClip) {
247         m_loopClipAction = loopClip;
248         m_playMenu->addAction(loopClip);
249     }
250
251     //TODO: add save zone to timeline monitor when fixed
252     if (m_name == "clip") {
253         m_contextMenu->addMenu(m_markerMenu);
254         m_contextMenu->addAction(KIcon("document-save"), i18n("Save zone"), this, SLOT(slotSaveZone()));
255     }
256     QAction *extractFrame = m_configMenu->addAction(KIcon("document-new"), i18n("Extract frame"), this, SLOT(slotExtractCurrentFrame()));
257     m_contextMenu->addAction(extractFrame);
258
259     if (m_name != "clip") {
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);
263     } else {
264         QAction *setThumbFrame = m_contextMenu->addAction(KIcon("document-new"), i18n("Set current image as thumbnail"), this, SLOT(slotSetThumbFrame()));
265         m_configMenu->addAction(setThumbFrame);
266     }
267
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());
272
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)));
277
278     m_configMenu->addAction(showTips);
279     m_configMenu->addAction(dropFrames);
280
281 }
282
283 void Monitor::slotGoToMarker(QAction *action)
284 {
285     int pos = action->data().toInt();
286     slotSeek(pos);
287 }
288
289 void Monitor::slotSetSizeOneToOne()
290 {
291     QRect r = QApplication::desktop()->screenGeometry();
292     const int maxWidth = r.width() - 20;
293     const int maxHeight = r.height() - 20;
294     int width = render->renderWidth();
295     int height = render->renderHeight();
296     kDebug() << "// render info: " << width << "x" << height;
297     while (width >= maxWidth || height >= maxHeight) {
298         width = width * 0.8;
299         height = height * 0.8;
300     }
301     kDebug() << "// MONITOR; set SIZE: " << width << ", " << height;
302     m_videoBox->setFixedSize(width, height);
303     updateGeometry();
304     adjustSize();
305     //m_ui.video_frame->setMinimumSize(0, 0);
306     emit adjustMonitorSize();
307 }
308
309 void Monitor::slotSetSizeOneToTwo()
310 {
311     QRect r = QApplication::desktop()->screenGeometry();
312     const int maxWidth = r.width() - 20;
313     const int maxHeight = r.height() - 20;
314     int width = render->renderWidth() / 2;
315     int height = render->renderHeight() / 2;
316     kDebug() << "// render info: " << width << "x" << height;
317     while (width >= maxWidth || height >= maxHeight) {
318         width = width * 0.8;
319         height = height * 0.8;
320     }
321     kDebug() << "// MONITOR; set SIZE: " << width << ", " << height;
322     m_videoBox->setFixedSize(width, height);
323     updateGeometry();
324     adjustSize();
325     //m_ui.video_frame->setMinimumSize(0, 0);
326     emit adjustMonitorSize();
327 }
328
329 void Monitor::resetSize()
330 {
331     m_videoBox->setMinimumSize(0, 0);
332 }
333
334 DocClipBase *Monitor::activeClip()
335 {
336     return m_currentClip;
337 }
338
339 void Monitor::updateMarkers(DocClipBase *source)
340 {
341     if (source == m_currentClip && source != NULL) {
342         m_markerMenu->clear();
343         QList <CommentedTime> markers = m_currentClip->commentedSnapMarkers();
344         if (!markers.isEmpty()) {
345             QList <int> marks;
346             for (int i = 0; i < markers.count(); i++) {
347                 int pos = (int) markers.at(i).time().frames(m_monitorManager->timecode().fps());
348                 marks.append(pos);
349                 QString position = m_monitorManager->timecode().getTimecode(markers.at(i).time()) + ' ' + markers.at(i).comment();
350                 QAction *go = m_markerMenu->addAction(position);
351                 go->setData(pos);
352             }
353             m_ruler->setMarkers(marks);
354         } else m_ruler->setMarkers(QList <int>());
355         m_markerMenu->setEnabled(!m_markerMenu->isEmpty());
356     }
357 }
358
359 void Monitor::slotSeekToPreviousSnap()
360 {
361     if (m_currentClip) slotSeek(getSnapForPos(true).frames(m_monitorManager->timecode().fps()));
362 }
363
364 void Monitor::slotSeekToNextSnap()
365 {
366     if (m_currentClip) slotSeek(getSnapForPos(false).frames(m_monitorManager->timecode().fps()));
367 }
368
369 GenTime Monitor::position()
370 {
371     return render->seekPosition();
372 }
373
374 GenTime Monitor::getSnapForPos(bool previous)
375 {
376     QList <GenTime> snaps;
377     QList < GenTime > markers = m_currentClip->snapMarkers();
378     for (int i = 0; i < markers.size(); ++i) {
379         GenTime t = markers.at(i);
380         snaps.append(t);
381     }
382     QPoint zone = m_ruler->zone();
383     snaps.append(GenTime(zone.x(), m_monitorManager->timecode().fps()));
384     snaps.append(GenTime(zone.y(), m_monitorManager->timecode().fps()));
385     snaps.append(GenTime());
386     snaps.append(m_currentClip->duration());
387     qSort(snaps);
388
389     const GenTime pos = render->seekPosition();
390     for (int i = 0; i < snaps.size(); ++i) {
391         if (previous && snaps.at(i) >= pos) {
392             if (i == 0) i = 1;
393             return snaps.at(i - 1);
394         } else if (!previous && snaps.at(i) > pos) {
395             return snaps.at(i);
396         }
397     }
398     return GenTime();
399 }
400
401 void Monitor::slotZoneMoved(int start, int end)
402 {
403     m_ruler->setZone(start, end);
404     checkOverlay();
405     setClipZone(m_ruler->zone());
406 }
407
408 void Monitor::slotSetZoneStart()
409 {
410     m_ruler->setZone(render->seekFramePosition(), -1);
411     emit zoneUpdated(m_ruler->zone());
412     checkOverlay();
413     setClipZone(m_ruler->zone());
414 }
415
416 void Monitor::slotSetZoneEnd()
417 {
418     m_ruler->setZone(-1, render->seekFramePosition());
419     emit zoneUpdated(m_ruler->zone());
420     checkOverlay();
421     setClipZone(m_ruler->zone());
422 }
423
424 // virtual
425 void Monitor::mousePressEvent(QMouseEvent * event)
426 {
427     if (event->button() != Qt::RightButton) {
428         if (m_videoBox->underMouse()) {
429             m_dragStarted = true;
430             m_DragStartPosition = event->pos();
431         }
432     } else m_contextMenu->popup(event->globalPos());
433 }
434
435 void Monitor::slotSwitchFullScreen()
436 {
437     m_videoBox->switchFullScreen();
438 }
439
440 // virtual
441 void Monitor::mouseReleaseEvent(QMouseEvent * event)
442 {
443     if (m_dragStarted) {
444         if (m_videoBox->underMouse() && (!m_effectView || !m_effectView->isVisible())) {
445             if (isActive()) slotPlay();
446             else activateMonitor();
447         } else QWidget::mouseReleaseEvent(event);
448         m_dragStarted = false;
449     }
450 }
451
452 // virtual
453 void Monitor::mouseMoveEvent(QMouseEvent *event)
454 {
455     // kDebug() << "// DRAG STARTED, MOUSE MOVED: ";
456     if (!m_dragStarted || m_currentClip == NULL) return;
457
458     if ((event->pos() - m_DragStartPosition).manhattanLength()
459             < QApplication::startDragDistance())
460         return;
461
462     {
463         QDrag *drag = new QDrag(this);
464         QMimeData *mimeData = new QMimeData;
465
466         QStringList list;
467         list.append(m_currentClip->getId());
468         QPoint p = m_ruler->zone();
469         list.append(QString::number(p.x()));
470         list.append(QString::number(p.y()));
471         QByteArray data;
472         data.append(list.join(";").toUtf8());
473         mimeData->setData("kdenlive/clip", data);
474         drag->setMimeData(mimeData);
475         QPixmap pix = m_currentClip->thumbnail();
476         drag->setPixmap(pix);
477         drag->setHotSpot(QPoint(0, 50));
478         drag->start(Qt::MoveAction);
479
480         //Qt::DropAction dropAction;
481         //dropAction = drag->start(Qt::CopyAction | Qt::MoveAction);
482
483         //Qt::DropAction dropAction = drag->exec();
484
485     }
486     //event->accept();
487 }
488
489 /*void Monitor::dragMoveEvent(QDragMoveEvent * event) {
490     event->setDropAction(Qt::IgnoreAction);
491     event->setDropAction(Qt::MoveAction);
492     if (event->mimeData()->hasText()) {
493         event->acceptProposedAction();
494     }
495 }
496
497 Qt::DropActions Monitor::supportedDropActions() const {
498     // returns what actions are supported when dropping
499     return Qt::MoveAction;
500 }*/
501
502 QStringList Monitor::mimeTypes() const
503 {
504     QStringList qstrList;
505     // list of accepted mime types for drop
506     qstrList.append("kdenlive/clip");
507     return qstrList;
508 }
509
510 // virtual
511 void Monitor::wheelEvent(QWheelEvent * event)
512 {
513     slotMouseSeek(event->delta(), event->modifiers() == Qt::ControlModifier);
514     event->accept();
515 }
516
517 void Monitor::slotMouseSeek(int eventDelta, bool fast)
518 {
519     if (fast) {
520         int delta = m_monitorManager->timecode().fps();
521         if (eventDelta > 0) delta = 0 - delta;
522         slotSeek(render->seekFramePosition() - delta);
523     } else {
524         if (eventDelta >= 0) slotForwardOneFrame();
525         else slotRewindOneFrame();
526     }
527 }
528
529 void Monitor::slotSetThumbFrame()
530 {
531     if (m_currentClip == NULL) {
532         return;
533     }
534     m_currentClip->setClipThumbFrame((uint) render->seekFramePosition());
535     emit refreshClipThumbnail(m_currentClip->getId());
536 }
537
538 void Monitor::slotExtractCurrentFrame()
539 {
540     QImage frame = render->extractFrame(render->seekFramePosition());
541     KFileDialog *fs = new KFileDialog(KUrl(), "image/png", this);
542     fs->setOperationMode(KFileDialog::Saving);
543     fs->setMode(KFile::File);
544 #if KDE_IS_VERSION(4,2,0)
545     fs->setConfirmOverwrite(true);
546 #endif
547     fs->setKeepLocation(true);
548     fs->exec();
549     QString path = fs->selectedFile();
550     delete fs;
551     if (!path.isEmpty()) {
552         frame.save(path);
553     }
554 }
555
556 bool Monitor::isActive() const
557 {
558     return m_isActive;
559 }
560
561 void Monitor::activateMonitor()
562 {
563     if (!m_isActive) {
564         m_monitorManager->slotSwitchMonitors(m_name == "clip");
565     }
566 }
567
568 void Monitor::setTimePos(const QString &pos)
569 {
570     m_timePos->setValue(pos);
571     slotSeek();
572 }
573
574 void Monitor::slotSeek()
575 {
576     slotSeek(m_timePos->getValue());
577 }
578
579 void Monitor::slotSeek(int pos)
580 {
581     activateMonitor();
582     if (render == NULL) return;
583     render->seekToFrame(pos);
584 }
585
586 void Monitor::checkOverlay()
587 {
588     if (m_overlay == NULL) return;
589     int pos = render->seekFramePosition();
590     QPoint zone = m_ruler->zone();
591     if (pos == zone.x())
592         m_overlay->setOverlayText(i18n("In Point"));
593     else if (pos == zone.y())
594         m_overlay->setOverlayText(i18n("Out Point"));
595     else {
596         if (m_currentClip) {
597             QString markerComment = m_currentClip->markerComment(GenTime(pos, m_monitorManager->timecode().fps()));
598             if (markerComment.isEmpty())
599                 m_overlay->setHidden(true);
600             else
601                 m_overlay->setOverlayText(markerComment, false);
602         } else m_overlay->setHidden(true);
603     }
604 }
605
606 void Monitor::slotStart()
607 {
608     activateMonitor();
609     render->play(0);
610     render->seekToFrame(0);
611 }
612
613 void Monitor::slotEnd()
614 {
615     activateMonitor();
616     render->play(0);
617     render->seekToFrame(render->getLength());
618 }
619
620 void Monitor::slotZoneStart()
621 {
622     activateMonitor();
623     render->play(0);
624     render->seekToFrame(m_ruler->zone().x());
625 }
626
627 void Monitor::slotZoneEnd()
628 {
629     activateMonitor();
630     render->play(0);
631     render->seekToFrame(m_ruler->zone().y());
632 }
633
634 void Monitor::slotRewind(double speed)
635 {
636     activateMonitor();
637     if (speed == 0) {
638         double currentspeed = render->playSpeed();
639         if (currentspeed >= 0) render->play(-2);
640         else render->play(currentspeed * 2);
641     } else render->play(speed);
642     //m_playAction->setChecked(true);
643     m_playAction->setIcon(m_pauseIcon);
644 }
645
646 void Monitor::slotForward(double speed)
647 {
648     activateMonitor();
649     if (speed == 0) {
650         double currentspeed = render->playSpeed();
651         if (currentspeed <= 1) render->play(2);
652         else render->play(currentspeed * 2);
653     } else render->play(speed);
654     //m_playAction->setChecked(true);
655     m_playAction->setIcon(m_pauseIcon);
656 }
657
658 void Monitor::slotRewindOneFrame(int diff)
659 {
660     activateMonitor();
661     render->play(0);
662     render->seekToFrameDiff(-diff);
663 }
664
665 void Monitor::slotForwardOneFrame(int diff)
666 {
667     activateMonitor();
668     render->play(0);
669     render->seekToFrameDiff(diff);
670 }
671
672 void Monitor::seekCursor(int pos)
673 {
674     activateMonitor();
675     if (m_ruler->slotNewValue(pos)) {
676         checkOverlay();
677         m_timePos->setValue(pos);
678     }
679 }
680
681 void Monitor::rendererStopped(int pos)
682 {
683     if (m_ruler->slotNewValue(pos)) {
684         checkOverlay();
685         m_timePos->setValue(pos);
686     }
687     disconnect(m_playAction, SIGNAL(triggered()), this, SLOT(slotPlay()));
688     //m_playAction->setChecked(false);
689     connect(m_playAction, SIGNAL(triggered()), this, SLOT(slotPlay()));
690     m_playAction->setIcon(m_playIcon);
691 }
692
693 void Monitor::adjustRulerSize(int length)
694 {
695     if (length > 0) m_length = length;
696     m_ruler->adjustScale(m_length);
697     if (m_currentClip != NULL) {
698         QPoint zone = m_currentClip->zone();
699         m_ruler->setZone(zone.x(), zone.y());
700     }
701 }
702
703 void Monitor::stop()
704 {
705     m_isActive = false;
706     disconnect(render, SIGNAL(rendererPosition(int)), this, SLOT(seekCursor(int)));
707     if (render) render->stop();
708 }
709
710 void Monitor::start()
711 {
712     m_isActive = true;
713     if (render) render->start();
714     connect(render, SIGNAL(rendererPosition(int)), this, SLOT(seekCursor(int)));
715 }
716
717 void Monitor::refreshMonitor(bool visible)
718 {
719     if (visible && render && !m_isActive) {
720         activateMonitor();
721         render->doRefresh(); //askForRefresh();
722     }
723 }
724
725 void Monitor::refreshMonitor()
726 {
727     if (m_isActive) {
728         render->doRefresh();
729     }
730 }
731
732 void Monitor::pause()
733 {
734     if (render == NULL) return;
735     activateMonitor();
736     render->pause();
737     //m_playAction->setChecked(true);
738     m_playAction->setIcon(m_playIcon);
739 }
740
741 void Monitor::slotPlay()
742 {
743     if (render == NULL) return;
744     activateMonitor();
745     if (render->playSpeed() == 0) {
746         //m_playAction->setChecked(true);
747         m_playAction->setIcon(m_pauseIcon);
748     } else {
749         //m_playAction->setChecked(false);
750         m_playAction->setIcon(m_playIcon);
751     }
752     render->switchPlay();
753 }
754
755 void Monitor::slotPlayZone()
756 {
757     if (render == NULL) return;
758     activateMonitor();
759     QPoint p = m_ruler->zone();
760     render->playZone(GenTime(p.x(), m_monitorManager->timecode().fps()), GenTime(p.y(), m_monitorManager->timecode().fps()));
761     //m_playAction->setChecked(true);
762     m_playAction->setIcon(m_pauseIcon);
763 }
764
765 void Monitor::slotLoopZone()
766 {
767     if (render == NULL) return;
768     activateMonitor();
769     QPoint p = m_ruler->zone();
770     render->loopZone(GenTime(p.x(), m_monitorManager->timecode().fps()), GenTime(p.y(), m_monitorManager->timecode().fps()));
771     //m_playAction->setChecked(true);
772     m_playAction->setIcon(m_pauseIcon);
773 }
774
775 void Monitor::slotLoopClip()
776 {
777     if (render == NULL || m_selectedClip == NULL)
778         return;
779     activateMonitor();
780     render->loopZone(m_selectedClip->startPos(), m_selectedClip->endPos());
781     //m_playAction->setChecked(true);
782     m_playAction->setIcon(m_pauseIcon);
783 }
784
785 void Monitor::slotSetXml(DocClipBase *clip, QPoint zone, const int position)
786 {
787     if (render == NULL) return;
788     if (clip == NULL && m_currentClip != NULL) {
789         m_currentClip = NULL;
790         m_length = -1;
791         render->setProducer(NULL, -1);
792         return;
793     }
794     if (m_currentClip != NULL || clip != NULL) activateMonitor();
795     if (clip != m_currentClip) {
796         m_currentClip = clip;
797         updateMarkers(clip);
798         if (render->setProducer(clip->producer(), position) == -1) {
799             // MLT CONSUMER is broken
800             kDebug(QtWarningMsg) << "ERROR, Cannot start monitor";
801         }
802     } else if (position != -1) render->seek(GenTime(position, m_monitorManager->timecode().fps()));
803     if (!zone.isNull()) {
804         m_ruler->setZone(zone.x(), zone.y());
805         render->seek(GenTime(zone.x(), m_monitorManager->timecode().fps()));
806     }
807 }
808
809 void Monitor::slotOpenFile(const QString &file)
810 {
811     if (render == NULL) return;
812     activateMonitor();
813     QDomDocument doc;
814     QDomElement mlt = doc.createElement("mlt");
815     doc.appendChild(mlt);
816     QDomElement prod = doc.createElement("producer");
817     mlt.appendChild(prod);
818     prod.setAttribute("mlt_service", "avformat");
819     prod.setAttribute("resource", file);
820     render->setSceneList(doc, 0);
821 }
822
823 void Monitor::slotSaveZone()
824 {
825     if (render == NULL) return;
826     emit saveZone(render, m_ruler->zone());
827
828     //render->setSceneList(doc, 0);
829 }
830
831 void Monitor::resetProfile(const QString profile)
832 {
833     m_timePos->updateTimeCode(m_monitorManager->timecode());
834     if (render == NULL) return;
835     render->resetProfile(profile);
836     if (m_effectScene) {
837         m_effectView->scale(((double) render->renderWidth()) / render->frameRenderWidth(), 1.0);
838         m_effectScene->resetProfile();
839     }
840 }
841
842 void Monitor::saveSceneList(QString path, QDomElement info)
843 {
844     if (render == NULL) return;
845     render->saveSceneList(path, info);
846 }
847
848 const QString Monitor::sceneList()
849 {
850     if (render == NULL) return QString();
851     return render->sceneList();
852 }
853
854 void Monitor::setClipZone(QPoint pos)
855 {
856     if (m_currentClip == NULL) return;
857     m_currentClip->setZone(pos);
858 }
859
860 void Monitor::slotSwitchDropFrames(bool show)
861 {
862     render->setDropFrames(show);
863 }
864
865 void Monitor::slotSwitchMonitorInfo(bool show)
866 {
867     KdenliveSettings::setDisplayMonitorInfo(show);
868     if (show) {
869         if (m_overlay) return;
870         if (m_monitorRefresh == NULL) {
871             // Using OpenGL display
872 #if defined(Q_WS_MAC) || defined(USE_OPEN_GL)
873             m_overlay = new Overlay(m_glWidget);
874 #endif
875         } else {
876             m_overlay = new Overlay(m_monitorRefresh);
877             m_overlay->raise();
878             m_overlay->setHidden(true);
879         }
880     } else {
881         delete m_overlay;
882         m_overlay = NULL;
883     }
884 }
885
886 void Monitor::updateTimecodeFormat()
887 {
888     m_timePos->slotUpdateTimeCodeFormat();
889 }
890
891 QStringList Monitor::getZoneInfo() const
892 {
893     QStringList result;
894     if (m_currentClip == NULL) return result;
895     result << m_currentClip->getId();
896     QPoint zone = m_ruler->zone();
897     result << QString::number(zone.x()) << QString::number(zone.y());
898     return result;
899 }
900
901 void Monitor::slotSetSelectedClip(AbstractClipItem* item)
902 {
903     if (item) {
904         m_loopClipAction->setEnabled(true);
905         m_selectedClip = item;
906     } else {
907         m_loopClipAction->setEnabled(false);
908     }
909 }
910
911 void Monitor::slotSetSelectedClip(ClipItem* item)
912 {
913     if (item || (!item && !m_loopClipTransition)) {
914         m_loopClipTransition = false;
915         slotSetSelectedClip((AbstractClipItem*)item);
916     }
917 }
918
919 void Monitor::slotSetSelectedClip(Transition* item)
920 {
921     if (item || (!item && m_loopClipTransition)) {
922         m_loopClipTransition = true;
923         slotSetSelectedClip((AbstractClipItem*)item);
924     }
925 }
926
927
928 void Monitor::slotEffectScene(bool show)
929 {
930     if (m_name == "project") {
931         if (m_monitorRefresh) {
932             m_monitorRefresh->setVisible(!show);
933         } else {
934 #if defined(Q_WS_MAC) || defined(USE_OPEN_GL)
935             m_glWidget->setVisible(!show);
936 #endif
937         }
938         m_effectView->setVisible(show);
939         emit requestFrameForAnalysis(show);
940         if (show) {
941             render->doRefresh();
942             m_effectScene->slotZoomFit();
943         }
944     }
945 }
946
947 MonitorScene * Monitor::getEffectScene()
948 {
949     return m_effectScene;
950 }
951
952 bool Monitor::effectSceneDisplayed()
953 {
954     return m_effectView->isVisible();
955 }
956
957 MonitorRefresh::MonitorRefresh(QWidget* parent) :
958     QWidget(parent)
959     , m_renderer(NULL)
960 {
961     // MonitorRefresh is used as container for the SDL display (it's window id is passed to SDL)
962     setAttribute(Qt::WA_PaintOnScreen);
963     setAttribute(Qt::WA_OpaquePaintEvent);
964     //setAttribute(Qt::WA_NoSystemBackground);
965 }
966
967 void MonitorRefresh::setRenderer(Render* render)
968 {
969     m_renderer = render;
970 }
971
972 void MonitorRefresh::paintEvent(QPaintEvent *event)
973 {
974     Q_UNUSED(event);
975     if (m_renderer) m_renderer->doRefresh();
976 }
977
978 Overlay::Overlay(QWidget* parent) :
979     QLabel(parent)
980 {
981     setAttribute(Qt::WA_TransparentForMouseEvents);
982     //setAttribute(Qt::WA_OpaquePaintEvent);
983     //setAttribute(Qt::WA_NoSystemBackground);
984     setAutoFillBackground(true);
985     setBackgroundRole(QPalette::Base);
986 }
987
988 void Overlay::setOverlayText(const QString &text, bool isZone)
989 {
990     setHidden(true);
991     m_isZone = isZone;
992     QPalette p;
993     p.setColor(QPalette::Text, Qt::white);
994     if (m_isZone) p.setColor(QPalette::Base, QColor(200, 0, 0));
995     else p.setColor(QPalette::Base, QColor(0, 0, 200));
996     setPalette(p);
997     setText(' ' + text + ' ');
998     setHidden(false);
999     update();
1000 }
1001
1002 VideoContainer::VideoContainer(Monitor* parent) :
1003     QFrame()
1004     , m_monitor(parent)
1005 {
1006     setFrameShape(QFrame::NoFrame);
1007     setFocusPolicy(Qt::ClickFocus);
1008     setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
1009 }
1010
1011 // virtual
1012 void VideoContainer::mousePressEvent(QMouseEvent * event)
1013 {
1014     if (m_monitor->underMouse()) event->setAccepted(false);
1015 }
1016
1017 // virtual
1018 void VideoContainer::mouseReleaseEvent(QMouseEvent * event)
1019 {
1020     if (m_monitor->underMouse()) event->setAccepted(false);
1021     else {
1022         if (m_monitor->isActive()) {
1023             m_monitor->slotPlay();
1024             event->accept();
1025         }
1026     }
1027 }
1028
1029 // virtual
1030 void VideoContainer::mouseMoveEvent(QMouseEvent *event)
1031 {
1032     if (m_monitor->underMouse()) event->setAccepted(false);
1033 }
1034
1035 // virtual
1036 void VideoContainer::keyPressEvent(QKeyEvent *event)
1037 {
1038     // Exit fullscreen with Esc key
1039     if (event->key() == Qt::Key_Escape && isFullScreen()) {
1040         switchFullScreen();
1041         event->setAccepted(true);
1042     } else event->setAccepted(false);
1043 }
1044
1045 // virtual
1046 void VideoContainer::wheelEvent(QWheelEvent * event)
1047 {
1048     if (m_monitor->underMouse()) event->setAccepted(false);
1049     else {
1050         m_monitor->slotMouseSeek(event->delta(), event->modifiers() == Qt::ControlModifier);
1051         event->accept();
1052     }
1053 }
1054
1055 void VideoContainer::mouseDoubleClickEvent(QMouseEvent * event)
1056 {
1057     if (!KdenliveSettings::openglmonitors())
1058         switchFullScreen();
1059 }
1060
1061 void VideoContainer::switchFullScreen()
1062 {
1063     // TODO: disable screensaver?
1064     Qt::WindowFlags flags = windowFlags();
1065     if (!isFullScreen()) {
1066         // Check if we ahave a multiple monitor setup
1067         setUpdatesEnabled(false);
1068 #if QT_VERSION >= 0x040600
1069         int monitors = QApplication::desktop()->screenCount();
1070 #else
1071         int monitors = QApplication::desktop()->numScreens();
1072 #endif
1073         if (monitors > 1) {
1074             QRect screenres;
1075             // Move monitor widget to the second screen (one screen for Kdenlive, the other one for the Monitor widget
1076             int currentScreen = QApplication::desktop()->screenNumber(this);
1077             if (currentScreen < monitors - 1)
1078                 screenres = QApplication::desktop()->screenGeometry(currentScreen + 1);
1079             else
1080                 screenres = QApplication::desktop()->screenGeometry(currentScreen - 1);
1081             move(QPoint(screenres.x(), screenres.y()));
1082             resize(screenres.width(), screenres.height());
1083         }
1084
1085         m_baseFlags = flags & (Qt::Window | Qt::SubWindow);
1086         flags |= Qt::Window;
1087         flags ^= Qt::SubWindow;
1088         setWindowFlags(flags);
1089 #ifdef Q_WS_X11
1090         // This works around a bug with Compiz
1091         // as the window must be visible before we can set the state
1092         show();
1093         raise();
1094         setWindowState(windowState() | Qt::WindowFullScreen);   // set
1095 #else
1096         setWindowState(windowState() | Qt::WindowFullScreen);   // set
1097         setUpdatesEnabled(true);
1098         show();
1099 #endif
1100     } else {
1101         setUpdatesEnabled(false);
1102         flags ^= (Qt::Window | Qt::SubWindow); //clear the flags...
1103         flags |= m_baseFlags; //then we reset the flags (window and subwindow)
1104         setWindowFlags(flags);
1105         setWindowState(windowState()  ^ Qt::WindowFullScreen);   // reset
1106         setUpdatesEnabled(true);
1107         show();
1108     }
1109     m_monitor->pause();
1110 }
1111
1112
1113 #include "monitor.moc"