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