1 #include <sstream>
2 #include <stdexcept>
3 #include <cmath>
4 #include "mainwindow.h"
5 #include "ui_mainwindow.h"
6 #include "openfiledialog.h"
7 #include "helpers.h"
8 #include "platform/unify.h"
9 #include "platform/devicemanager.h"
10 #include <QDesktopWidget>
11 #include <QStyle>
12 #include <QWindow>
13 #include <QMenuBar>
14 #include <QSizeGrip>
15 #include <QMimeData>
16 #include <QJsonDocument>
17 #include <QFileDialog>
18 #include <QInputDialog>
19 #include <QTime>
20 #include <QDesktopServices>
21 #include <QMessageBox>
22 #include <QLibraryInfo>
23 #include <QToolTip>
24 #include <QStyle>
25
26 using namespace Helpers;
27 static const char SKIPACTION[] = "Skip";
28
29
MainWindow(QWidget * parent)30 MainWindow::MainWindow(QWidget *parent) :
31 QMainWindow(parent),
32 ui(new Ui::MainWindow)
33 {
34 ui->setupUi(this);
35 setupMenu();
36 setupContextMenu();
37 setupActionGroups();
38 setupPositionSlider();
39 setupVolumeSlider();
40 setupMpvHost();
41 setupMpvObject();
42 setupPlaylist();
43 setupStatus();
44 setupSizing();
45 setupBottomArea();
46 setupHideTimer();
47 setupIconThemer();
48
49 mpvw->installEventFilter(this);
50 playlistWindow_->installEventFilter(this);
51
52 connectActionsToSignals();
53 connectActionsToSlots();
54 connectButtonsToActions();
55 connectPlaylistWindowToActions();
56 globalizeAllActions();
57 setUiEnabledState(false);
58 setDiscState(false);
59
60 // Sync with X11
61 if (Platform::isUnix) {
62 setAttribute(Qt::WA_DontShowOnScreen, true);
63 show();
64 qApp->processEvents(QEventLoop::AllEvents |
65 QEventLoop::WaitForMoreEvents,
66 50);
67 hide();
68 setAttribute(Qt::WA_DontShowOnScreen, false);
69 }
70 }
71
~MainWindow()72 MainWindow::~MainWindow()
73 {
74 mpvObject_->setWidgetType(Helpers::NullWidget);
75
76 delete ui;
77 ui = nullptr;
78 }
79
mpvObject()80 MpvObject *MainWindow::mpvObject()
81 {
82 return mpvObject_;
83 }
84
mpvHost()85 QMainWindow *MainWindow::mpvHost()
86 {
87 return mpvHost_;
88 }
89
playlistWindow()90 PlaylistWindow *MainWindow::playlistWindow()
91 {
92 return playlistWindow_;
93 }
94
actionsToList(QList<QAction * > & actionList,const QList<QAction * > & actions)95 static void actionsToList(QList<QAction*> &actionList, const QList<QAction*> &actions) {
96 for (QAction *a : actions) {
97 if (a->data().toString() == SKIPACTION)
98 continue;
99 if (a->menu())
100 actionsToList(actionList, a->menu()->actions());
101 else if (!a->isSeparator())
102 actionList.append(a);
103 }
104 }
105
editableActions()106 QList<QAction *> MainWindow::editableActions()
107 {
108 QList<QAction*> actionList;
109 actionsToList(actionList, actions());
110 return actionList;
111 }
112
mouseMapDefaults()113 QVariantMap MainWindow::mouseMapDefaults()
114 {
115 QVariantMap commandMap;
116 auto actionToMap = [&commandMap](QAction *a, const MouseState &m) {
117 Command c;
118 c.fromAction(a);
119 c.mouseWindowed = m;
120 c.mouseFullscreen = m;
121 commandMap.insert(a->objectName(), c.toVMap());
122 };
123 actionToMap(ui->actionViewFullscreen, {MouseState::Left,0,MouseState::PressTwice});
124 actionToMap(ui->actionPlayPause, {MouseState::Left,0,MouseState::MouseDown});
125 actionToMap(ui->actionNavigateChaptersNext, {MouseState::Forward,0,MouseState::MouseDown});
126 actionToMap(ui->actionNavigateChaptersPrevious, {MouseState::Back,0,MouseState::MouseDown});
127 actionToMap(ui->actionPlayVolumeDown, {MouseState::Wheel,0,MouseState::MouseDown});
128 actionToMap(ui->actionPlayVolumeUp, {MouseState::Wheel,0,MouseState::MouseUp});
129 return commandMap;
130 }
131
state()132 QVariantMap MainWindow::state()
133 {
134 #define WRAP(a) \
135 a->objectName(), a->isChecked()
136 return QVariantMap {
137 { "decorationState", int(decorationState_) },
138 { WRAP(ui->actionViewHideSeekbar) },
139 { WRAP(ui->actionViewHideControls) },
140 { WRAP(ui->actionViewHideInformation) },
141 { WRAP(ui->actionViewHideStatistics) },
142 { WRAP(ui->actionViewHideStatus) },
143 { WRAP(ui->actionViewHideSubresync) },
144 { WRAP(ui->actionViewHidePlaylist) },
145 { WRAP(ui->actionViewHideCapture) },
146 { WRAP(ui->actionViewHideNavigation) },
147 { WRAP(ui->actionViewHideLog) },
148 { WRAP(ui->actionViewHideLibrary) },
149 { WRAP(ui->actionViewOntopDefault) },
150 { WRAP(ui->actionViewOntopAlways) },
151 { WRAP(ui->actionViewOntopPlaying) },
152 { WRAP(ui->actionViewOntopVideo) },
153 { WRAP(ui->actionViewFullscreen) },
154 { WRAP(ui->actionPlaySubtitlesEnabled) },
155 { "shownStatsPage", mpvObject_->selectedStatsPage() }
156 };
157 #undef WRAP
158 }
159
setState(const QVariantMap & map)160 void MainWindow::setState(const QVariantMap &map)
161 {
162 #define UNWRAP(a,b) \
163 a->setChecked(map.value(a->objectName(), b).toBool())
164
165 setUiDecorationState(DecorationState(map["decorationState"].toInt()));
166 UNWRAP(ui->actionViewHideSeekbar, true);
167 UNWRAP(ui->actionViewHideControls, true);
168 UNWRAP(ui->actionViewHideInformation, false);
169 UNWRAP(ui->actionViewHideStatistics, false);
170 UNWRAP(ui->actionViewHideStatus, true);
171 UNWRAP(ui->actionViewHideSubresync, false);
172 UNWRAP(ui->actionViewHidePlaylist, true);
173 UNWRAP(ui->actionViewHideCapture, false);
174 UNWRAP(ui->actionViewHideNavigation, false);
175 UNWRAP(ui->actionViewHideLog, false);
176 UNWRAP(ui->actionViewHideLibrary, false);
177 UNWRAP(ui->actionViewOntopDefault, true);
178 UNWRAP(ui->actionViewOntopAlways, false);
179 UNWRAP(ui->actionViewOntopPlaying, false);
180 UNWRAP(ui->actionViewOntopVideo, false);
181 UNWRAP(ui->actionViewFullscreen, false);
182 UNWRAP(ui->actionPlaySubtitlesEnabled, true);
183 on_actionPlaySubtitlesEnabled_triggered(ui->actionPlaySubtitlesEnabled->isChecked());
184 setOSDPage(map.value("shownStatsPage",0).toInt());
185 updateOnTop();
186
187 #undef UNWRAP
188 }
189
setScreensaverAbilities(QSet<ScreenSaver::Ability> ab)190 void MainWindow::setScreensaverAbilities(QSet<ScreenSaver::Ability> ab)
191 {
192 ui->actionPlayAfterOnceStandby->setVisible(ab.contains(ScreenSaver::Suspend));
193 ui->actionPlayAfterOnceHibernate->setVisible(ab.contains(ScreenSaver::Hibernate));
194 ui->actionPlayAfterOnceShutdown->setVisible(ab.contains(ScreenSaver::Shutdown));
195 ui->actionPlayAfterOnceLogoff->setVisible(ab.contains(ScreenSaver::LogOff));
196 ui->actionPlayAfterOnceLock->setVisible(ab.contains(ScreenSaver::LockScreen));
197 }
198
desirableSize(bool first_run)199 QSize MainWindow::desirableSize(bool first_run)
200 {
201 if (zoomMode == FitToWindow)
202 return size();
203
204 // Grab device pixel ratio (2=HiDPI screen)
205 qreal ratio = devicePixelRatio();
206
207 // calculate available area for the window
208 QDesktopWidget *desktop = qApp->desktop();
209 QRect available = first_run ? Helpers::availableGeometryFromPoint(QCursor::pos())
210 : desktop->availableGeometry(this);
211 QSize frameDiff = this->frameGeometry().size() - this->geometry().size();
212 available.adjust(0, 0, -frameDiff.width(), -frameDiff.height());
213
214 // calculate player size
215 QSize player = mpvObject_->videoSize() / ratio;
216 double factor = sizeFactor();
217 if (!isPlaying || player.isEmpty()) {
218 player = noVideoSize_;
219 factor = std::max(1.0, sizeFactor());
220 }
221
222 // calculate the amount taken by widgets outside the video frame
223 QSize mpvSize = mpvw ? mpvw->size() : noVideoSize_;
224 QSize fudgeFactor = size() - mpvSize;
225
226 // calculate desired client size, depending upon the zoom mode
227 QSize wanted;
228 if (zoomMode == RegularZoom) {
229 wanted = QSize(int(player.width()*factor + 0.5),
230 int(player.height()*factor + 0.5));
231 } else {
232 wanted = (available.size() - fudgeFactor) * fitFactor_;
233 if (zoomMode == Autofit) {
234 wanted = player.scaled(wanted.width(), wanted.height(),
235 Qt::KeepAspectRatio);
236 } else if (zoomMode == AutofitLarger) {
237 if (wanted.height() > player.height()
238 || wanted.width() > player.width()) {
239 // window is larger than player size, so set to player size
240 wanted = player;
241 } else {
242 // window is smaller than player size, so limit new window
243 // size to contain a player rectangle
244 wanted = player.scaled(wanted.width(), wanted.height(),
245 Qt::KeepAspectRatio);
246 }
247 } else { // zoomMode == AutofitSmaller
248 if (player.height() < wanted.height()
249 || player.width() < wanted.width()) {
250 // player size is smaller than wanted window, so make it larger
251 wanted = player.scaled(wanted.width(), wanted.height(),
252 Qt::KeepAspectRatioByExpanding);
253 } else {
254 // player size is larger than wanted, so use the player size
255 wanted = player;
256 }
257 }
258 }
259 return wanted + fudgeFactor;
260 }
261
desirablePosition(QSize & size,bool first_run)262 QPoint MainWindow::desirablePosition(QSize &size, bool first_run)
263 {
264 QDesktopWidget *desktop = qApp->desktop();
265
266 QRect available = first_run ? Helpers::availableGeometryFromPoint(QCursor::pos())
267 : desktop->availableGeometry(this);
268 QSize frameDiff = this->frameGeometry().size() - this->geometry().size();
269 available.adjust(0, 0, -frameDiff.width(), -frameDiff.height());
270 if (size.height() > available.height())
271 size.setHeight(available.height());
272 if (size.width() > available.width())
273 size.setWidth(available.width());
274
275 QPoint clientOffset = geometry().topLeft() - pos();
276 return QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter,
277 size, available).topLeft() + clientOffset;
278 }
279
unfreezeWindow()280 void MainWindow::unfreezeWindow()
281 {
282 frozenWindow = false;
283 }
284
resizeEvent(QResizeEvent * event)285 void MainWindow::resizeEvent(QResizeEvent *event)
286 {
287 Q_UNUSED(event)
288 updateBottomAreaGeometry();
289 checkBottomArea(QCursor::pos());
290 }
291
eventFilter(QObject * object,QEvent * event)292 bool MainWindow::eventFilter(QObject *object, QEvent *event)
293 {
294 bool insideMpv = mpvw ? object == mpvw : false;
295 if ((insideMpv || object == playlistWindow_) && event->type() == QEvent::MouseMove) {
296 this->mouseMoveEvent(static_cast<QMouseEvent*>(event));
297 }
298 return QMainWindow::eventFilter(object, event);
299 }
300
closeEvent(QCloseEvent * event)301 void MainWindow::closeEvent(QCloseEvent *event)
302 {
303 event->accept();
304 emit instanceShouldQuit();
305 }
306
mouseMoveEvent(QMouseEvent * event)307 void MainWindow::mouseMoveEvent(QMouseEvent *event)
308 {
309 if (fullscreenMode_)
310 checkBottomArea(event->globalPos());
311 }
312
insideWidget(QPoint p,QWidget * mpvw)313 static bool insideWidget(QPoint p, QWidget *mpvw) {
314 if (mpvw == nullptr)
315 return false;
316 QRect rc(mpvw->mapToGlobal(QPoint()), mpvw->size());
317 return rc.contains(p);
318 }
319
mousePressEvent(QMouseEvent * event)320 void MainWindow::mousePressEvent(QMouseEvent *event)
321 {
322 bool ok = mpvw ? insideWidget(event->globalPos(), mpvw) : false;
323 if (ok && mouseStateEvent(MouseState::fromMouseEvent(event, MouseState::MouseDown)))
324 event->accept();
325 else
326 QMainWindow::mousePressEvent(event);
327 }
328
mouseDoubleClickEvent(QMouseEvent * event)329 void MainWindow::mouseDoubleClickEvent(QMouseEvent *event)
330 {
331 bool ok = mpvw ? insideWidget(event->globalPos(), mpvw) : false;
332 if (ok && mouseStateEvent(MouseState::fromMouseEvent(event, MouseState::PressTwice)))
333 event->accept();
334 mousePressEvent(event);
335 }
336
mouseReleaseEvent(QMouseEvent * event)337 void MainWindow::mouseReleaseEvent(QMouseEvent *event)
338 {
339 bool ok = mpvw ? insideWidget(event->globalPos(), mpvw) : false;
340 if (ok && mouseStateEvent(MouseState::fromMouseEvent(event, MouseState::MouseUp)))
341 event->accept();
342 else
343 QMainWindow::mouseReleaseEvent(event);
344 }
345
wheelEvent(QWheelEvent * event)346 void MainWindow::wheelEvent(QWheelEvent *event)
347 {
348 // Deprecated way
349 bool ok = mpvw ? insideWidget(event->globalPos(), mpvw) : false;
350 // Non-deprecated way since Qt 5.15
351 //QPointF gp = event->globalPosition();
352 //bool ok = mpvw ? insideWidget({int(gp.rx()),int(gp.ry())}, mpvw) : false;
353 if (ok && mouseStateEvent(MouseState::fromWheelEvent(event)))
354 event->accept();
355 else
356 QMainWindow::wheelEvent(event);
357 }
358
dragEnterEvent(QDragEnterEvent * event)359 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
360 {
361 if (event->mimeData()->hasUrls())
362 event->accept();
363 }
364
dropEvent(QDropEvent * event)365 void MainWindow::dropEvent(QDropEvent *event)
366 {
367 emit severalFilesOpened(event->mimeData()->urls(), true);
368 }
369
mouseStateEvent(const MouseState & state)370 bool MainWindow::mouseStateEvent(const MouseState &state)
371 {
372 MouseStateMap &mouseMap = fullscreenMode_ ? mouseMapFullscreen
373 : mouseMapWindowed;
374
375 if (mouseMap.contains(state)) {
376 QAction *action = mouseMap[state];
377 if (!action->isEnabled())
378 return true;
379 if (action->isCheckable())
380 action->setChecked(!action->isChecked());
381 emit action->triggered(action->isChecked());
382 return true;
383 }
384 return false;
385 }
386
positionSlider()387 MediaSlider *MainWindow::positionSlider()
388 {
389 return positionSlider_;
390 }
391
volumeSlider()392 VolumeSlider *MainWindow::volumeSlider()
393 {
394 return volumeSlider_;
395 }
396
decorationState()397 MainWindow::DecorationState MainWindow::decorationState()
398 {
399 return decorationState_;
400 }
401
fullscreenMode()402 bool MainWindow::fullscreenMode()
403 {
404 return fullscreenMode_;
405 }
406
noVideoSize()407 QSize MainWindow::noVideoSize()
408 {
409 return noVideoSize_;
410 }
411
sizeFactor()412 double MainWindow::sizeFactor()
413 {
414 return sizeFactor_;
415 }
416
setFullscreenMode(bool fullscreenMode)417 void MainWindow::setFullscreenMode(bool fullscreenMode)
418 {
419 if (fullscreenMode_ == fullscreenMode)
420 return;
421
422 // This is where the monitor settings should be honored.
423 // For now, use the current screen.
424 windowHandle()->setScreen(windowHandle()->screen());
425
426 // save maximized state if changing from windowed to fullscreen
427 if (!fullscreenMode_ && fullscreenMode)
428 fullscreenMaximized = isMaximized();
429
430 fullscreenMode_ = fullscreenMode;
431 if (fullscreenMode)
432 showFullScreen();
433 else if (fullscreenMaximized)
434 showMaximized();
435 else
436 showNormal();
437
438 ui->actionViewFullscreenEscape->setEnabled(fullscreenMode);
439 updateMouseHideTime();
440
441 //REMOVEME: work around OpenGL blackness bug after fullscreen
442 QTimer::singleShot(50, this, [this]() {
443 positionSlider_->update();
444 volumeSlider_->update();
445 timePosition->update();
446 timeDuration->update();
447 });
448 emit fullscreenModeChanged(fullscreenMode_);
449 }
450
setDiscState(bool playingADisc)451 void MainWindow::setDiscState(bool playingADisc)
452 {
453 ui->actionNavigateMenuTitle->setEnabled(playingADisc);
454 ui->actionNavigateMenuRoot->setEnabled(playingADisc);
455 ui->actionNavigateMenuSubtitle->setEnabled(playingADisc);
456 ui->actionNavigateMenuAudio->setEnabled(playingADisc);
457 ui->actionNavigateMenuAngle->setEnabled(playingADisc);
458 ui->actionNavigateMenuChapter->setEnabled(playingADisc);
459 }
460
setupMenu()461 void MainWindow::setupMenu()
462 {
463 // Work around separators with text in the designer not showing as
464 // sections
465 ui->menuPlayAfter->insertSection(ui->actionPlayAfterOnceExit,
466 tr("Once"));
467 ui->menuPlayAfter->insertSection(ui->actionPlayAfterAlwaysExit,
468 tr("Every time"));
469
470 ui->infoStats->setVisible(false);
471
472 QString quickOpenKeys = Platform::isMac ? tr("Alt+Q") : tr("Ctrl+Q");
473 ui->actionFileOpenQuick->setShortcut(quickOpenKeys);
474
475 connect(Platform::deviceManager(), &DeviceManager::deviceListChanged,
476 this, [this]() { updateDiscList(); });
477 }
478
setupContextMenu()479 void MainWindow::setupContextMenu()
480 {
481 contextMenu = new QMenu(this);
482
483 contextMenu->addMenu(ui->menuFile);
484 contextMenu->addSeparator();
485 contextMenu->addAction(ui->actionPlayPause);
486 contextMenu->addAction(ui->actionPlayStop);
487 contextMenu->addSeparator();
488 contextMenu->addAction(ui->actionViewFullscreen);
489 contextMenu->addMenu(ui->menuNavigate);
490 contextMenu->addMenu(ui->menuFavorites);
491 contextMenu->addSeparator();
492 contextMenu->addMenu(ui->menuPlayAudio);
493 contextMenu->addMenu(ui->menuPlaySubtitles);
494 contextMenu->addMenu(ui->menuPlayVideo);
495 contextMenu->addSeparator();
496 contextMenu->addMenu(ui->menuPlayVolume);
497 contextMenu->addMenu(ui->menuPlayAfter);
498 contextMenu->addSeparator();
499
500 QMenu *contextView = new QMenu(tr("View"), this);
501 contextView->addMenu(ui->menuViewOntop);
502 contextView->addSeparator();
503 contextView->addAction(ui->actionViewHideMenu);
504 contextView->addAction(ui->actionViewHideSeekbar);
505 contextView->addAction(ui->actionViewHideControls);
506 contextView->addAction(ui->actionViewHideInformation);
507 contextView->addAction(ui->actionViewHideStatistics);
508 contextView->addAction(ui->actionViewHideStatus);
509 contextView->addAction(ui->actionViewHideSubresync);
510 contextView->addAction(ui->actionViewHidePlaylist);
511 contextView->addAction(ui->actionViewHideCapture);
512 contextView->addAction(ui->actionViewHideNavigation);
513 contextView->addMenu(ui->menuViewPresets);
514
515 contextMenu->addMenu(contextView);
516 contextMenu->addAction(ui->actionFileProperties);
517 contextMenu->addAction(ui->actionViewOptions);
518 contextMenu->addSeparator();
519 contextMenu->addAction(ui->actionFileExit);
520 }
521
setupActionGroups()522 void MainWindow::setupActionGroups()
523 {
524 QActionGroup *ag;
525
526 ag = new QActionGroup(this);
527 ag->addAction(ui->actionViewOSDNone);
528 ag->addAction(ui->actionViewOSDMessages);
529 ag->addAction(ui->actionViewOSDStatistics);
530 ag->addAction(ui->actionViewOSDFrameTimings);
531
532 ag = new QActionGroup(this);
533 ag->addAction(ui->actionViewZoom025);
534 ag->addAction(ui->actionViewZoom050);
535 ag->addAction(ui->actionViewZoom075);
536 ag->addAction(ui->actionViewZoom100);
537 ag->addAction(ui->actionViewZoom150);
538 ag->addAction(ui->actionViewZoom200);
539 ag->addAction(ui->actionViewZoom300);
540 ag->addAction(ui->actionViewZoom400);
541 ag->addAction(ui->actionViewZoomAutofit);
542 ag->addAction(ui->actionViewZoomAutofitLarger);
543 ag->addAction(ui->actionViewZoomAutofitSmaller);
544 ag->addAction(ui->actionViewZoomDisable);
545
546 ag = new QActionGroup(this);
547 ag->addAction(ui->actionViewOntopDefault);
548 ag->addAction(ui->actionViewOntopAlways);
549 ag->addAction(ui->actionViewOntopPlaying);
550 ag->addAction(ui->actionViewOntopVideo);
551
552 ag = new QActionGroup(this);
553 ag->addAction(ui->actionPlayAfterOnceExit);
554 ag->addAction(ui->actionPlayAfterOnceHibernate);
555 ag->addAction(ui->actionPlayAfterOnceLock);
556 ag->addAction(ui->actionPlayAfterOnceLogoff);
557 ag->addAction(ui->actionPlayAfterOnceNothing);
558 ag->addAction(ui->actionPlayAfterOnceRepeat);
559 ag->addAction(ui->actionPlayAfterOnceShutdown);
560 ag->addAction(ui->actionPlayAfterOnceStandby);
561
562 ag = new QActionGroup(this);
563 ag->addAction(ui->actionPlayAfterAlwaysExit);
564 ag->addAction(ui->actionPlayAfterAlwaysNext);
565 ag->addAction(ui->actionPlayAfterAlwaysNothing);
566 ag->addAction(ui->actionPlayAfterAlwaysRepeat);
567 }
568
setupPositionSlider()569 void MainWindow::setupPositionSlider()
570 {
571 positionSlider_ = new MediaSlider();
572 ui->seekbar->layout()->addWidget(positionSlider_);
573 connect(positionSlider_, &MediaSlider::sliderMoved,
574 this, &MainWindow::position_sliderMoved);
575 connect(positionSlider_, &MediaSlider::hoverValue,
576 this, &MainWindow::position_hoverValue);
577 }
578
setupVolumeSlider()579 void MainWindow::setupVolumeSlider()
580 {
581 volumeSlider_ = new VolumeSlider();
582 volumeSlider_->setMinimumWidth(50);
583 volumeSlider_->setMinimum(0);
584 volumeSlider_->setMaximum(130);
585 volumeSlider_->setValue(100);
586 ui->controlbar->layout()->addWidget(volumeSlider_);
587 connect(volumeSlider_, &VolumeSlider::sliderMoved,
588 this, &MainWindow::volume_sliderMoved);
589 }
590
setupMpvHost()591 void MainWindow::setupMpvHost()
592 {
593 // Create a special QMainWindow widget so that the playlist window will
594 // dock around it rather than ourselves
595 mpvHost_ = new QMainWindow(this);
596 mpvHost_->setSizePolicy(QSizePolicy(QSizePolicy::Ignored,
597 QSizePolicy::Ignored));
598 ui->mpvWidget->layout()->addWidget(mpvHost_);
599 }
600
setupMpvObject()601 void MainWindow::setupMpvObject()
602 {
603 mpvObject_ = new MpvObject(this, "Media Player Classic Qute Theater");
604 mpvObject_->setHostWindow(mpvHost_);
605 setupMpvWidget(Helpers::GlCbWidget);
606 connect(mpvObject_, &MpvObject::logoSizeChanged,
607 this, &MainWindow::setNoVideoSize);
608 }
609
setupMpvWidget(Helpers::MpvWidgetType widgetType)610 void MainWindow::setupMpvWidget(Helpers::MpvWidgetType widgetType)
611 {
612 bool embeddedBottomArea = ui->bottomArea->parentWidget() == mpvw;
613 if (embeddedBottomArea) {
614 reparentBottomArea(false);
615 }
616
617 mpvw = nullptr;
618 mpvObject_->setWidgetType(widgetType);
619 mpvw = mpvObject_->mpvWidget();
620 if (!mpvw)
621 throw(std::runtime_error("Video widget not created"));
622 // CHECKME: signal could be in mpvObject and reflected internally
623 connect(mpvw, &QWidget::customContextMenuRequested,
624 this, &MainWindow::mpvw_customContextMenuRequested);
625 // CHECKME: mouse tracking could be set by mpvObject's setWidgetType func
626 mpvw->setMouseTracking(true);
627
628 if (embeddedBottomArea)
629 reparentBottomArea(true);
630 }
631
setupPlaylist()632 void MainWindow::setupPlaylist()
633 {
634 playlistWindow_ = new PlaylistWindow(this);
635 mpvHost_->addDockWidget(Qt::RightDockWidgetArea, playlistWindow_);
636 connect(playlistWindow_, &PlaylistWindow::windowDocked,
637 this, &MainWindow::playlistWindow_windowDocked);
638 connect(playlistWindow_, &PlaylistWindow::playlistAddItem,
639 this, &MainWindow::playlistWindow_playlistAddItem);
640 connect(playlistWindow_, &PlaylistWindow::currentPlaylistHasItems,
641 ui->play, &QPushButton::setEnabled);
642 QList<QWidget *> playlistWidgets = playlistWindow_->findChildren<QWidget *>();
643 foreach(QWidget *w, playlistWidgets)
644 w->setMouseTracking(true);
645 playlistWindow_->setMouseTracking(true);
646 }
647
setupStatus()648 void MainWindow::setupStatus()
649 {
650 timePosition = new StatusTime();
651 ui->statusbarLayout->insertWidget(2, timePosition);
652 timeDuration = new StatusTime();
653 ui->statusbarLayout->insertWidget(4, timeDuration);
654 }
655
setupSizing()656 void MainWindow::setupSizing()
657 {
658 QSizeGrip *gripper = new QSizeGrip(this);
659 ui->statusbar->layout()->addWidget(gripper);
660 }
661
setupBottomArea()662 void MainWindow::setupBottomArea()
663 {
664 QList<QWidget *> bottomWidgets = ui->bottomArea->findChildren<QWidget *>();
665 foreach(QWidget *w, bottomWidgets)
666 w->setMouseTracking(true);
667 ui->bottomArea->setMouseTracking(true);
668 }
669
setupIconThemer()670 void MainWindow::setupIconThemer()
671 {
672 QVector<IconThemer::IconData> data {
673 { ui->play, "media-playback-start", {} },
674 { ui->pause, "media-playback-pause", {} },
675 { ui->stop, "media-playback-stop", {} },
676 { ui->skipBackward, "go-previous", {} },
677 { ui->skipForward, "go-next", {} },
678 { ui->speedDecrease, "media-seek-backward", {} },
679 { ui->speedIncrease, "media-seek-forward", {} },
680 { ui->stepBackward, "media-skip-backward", {} },
681 { ui->stepForward, "media-skip-forward", {} },
682 { ui->loopA, "zone-in", {} },
683 { ui->loopB, "zone-out", {} },
684 { ui->subs, "view-media-subtitles", "view-media-subtitles-hidden" },
685 { ui->mute, "player-volume", "player-volume-muted" }
686 };
687 for (auto &d : data)
688 themer.addIconData(d);
689 }
690
setupHideTimer()691 void MainWindow::setupHideTimer()
692 {
693 hideTimer.setSingleShot(true);
694 connect(&hideTimer, &QTimer::timeout,
695 this, &MainWindow::hideTimer_timeout);
696 }
697
connectActionsToSignals()698 void MainWindow::connectActionsToSignals()
699 {
700 connect(ui->actionFileSaveThumbnails, &QAction::triggered,
701 this, &MainWindow::takeThumbnails);
702 connect(ui->actionFileProperties, &QAction::triggered,
703 this, &MainWindow::showFileProperties);
704 }
705
connectActionsToSlots()706 void MainWindow::connectActionsToSlots()
707 {
708 connect(ui->actionHelpAboutQt, &QAction::triggered,
709 qApp, &QApplication::aboutQt);
710 }
711
connectButtonsToActions()712 void MainWindow::connectButtonsToActions()
713 {
714 connect(ui->pause, &QPushButton::clicked,
715 ui->actionPlayPause, &QAction::triggered);
716 connect(ui->stop, &QPushButton::clicked,
717 ui->actionPlayStop, &QAction::triggered);
718
719 connect(ui->speedDecrease, &QPushButton::clicked,
720 ui->actionPlayRateDecrease, &QAction::triggered);
721 connect(ui->speedIncrease, &QPushButton::clicked,
722 ui->actionPlayRateIncrease, &QAction::triggered);
723
724 connect(ui->skipBackward, &QPushButton::clicked,
725 ui->actionNavigateChaptersPrevious, &QAction::triggered);
726 connect(ui->stepBackward, &QPushButton::clicked,
727 ui->actionPlayFrameBackward, &QAction::triggered);
728 connect(ui->stepForward, &QPushButton::clicked,
729 ui->actionPlayFrameForward, &QAction::triggered);
730 connect(ui->skipForward, &QPushButton::clicked,
731 ui->actionNavigateChaptersNext, &QAction::triggered);
732
733 connect(ui->loopA, &QPushButton::clicked,
734 ui->actionPlayLoopStart, &QAction::triggered);
735 connect(ui->loopB, &QPushButton::clicked,
736 ui->actionPlayLoopEnd, &QAction::triggered);
737
738 connect(ui->subs, &QPushButton::toggled, this,
739 [this](bool checked) { on_actionPlaySubtitlesEnabled_triggered(!checked); });
740 connect(ui->mute, &QPushButton::toggled,
741 ui->actionPlayVolumeMute, &QAction::toggled);
742 }
743
connectPlaylistWindowToActions()744 void MainWindow::connectPlaylistWindowToActions()
745 {
746 connect(ui->actionPlaylistCopy, &QAction::triggered,
747 playlistWindow_, &PlaylistWindow::copy);
748 connect(ui->actionPlaylistCopyQueue, &QAction::triggered,
749 playlistWindow_, &PlaylistWindow::copyQueue);
750 connect(ui->actionPlaylistPaste, &QAction::triggered,
751 playlistWindow_, &PlaylistWindow::paste);
752 connect(ui->actionPlaylistPasteQueue, &QAction::triggered,
753 playlistWindow_, &PlaylistWindow::pasteQueue);
754
755 connect(ui->actionPlaylistNewTab, &QAction::triggered,
756 playlistWindow_, &PlaylistWindow::newTab);
757 connect(ui->actionPlaylistCloseTab, &QAction::triggered,
758 playlistWindow_, &PlaylistWindow::closeTab);
759 connect(ui->actionPlaylistDuplicateTab, &QAction::triggered,
760 playlistWindow_, &PlaylistWindow::duplicateTab);
761 connect(ui->actionPlaylistImport, &QAction::triggered,
762 playlistWindow_, &PlaylistWindow::importTab);
763 connect(ui->actionPlaylistExport, &QAction::triggered,
764 playlistWindow_, &PlaylistWindow::exportTab);
765 connect(ui->actionPlaylistPlayCurrent, &QAction::triggered,
766 playlistWindow_, &PlaylistWindow::playCurrentItem);
767 connect(ui->actionPlaylistShowQuickQueue, &QAction::triggered,
768 playlistWindow_, &PlaylistWindow::setQueueMode);
769 connect(ui->actionPlaylistQuickQueue, &QAction::triggered,
770 playlistWindow_, &PlaylistWindow::quickQueue);
771 connect(ui->actionPlaylistQueueVisible, &QAction::triggered,
772 playlistWindow_, &PlaylistWindow::visibleToQueue);
773 connect(ui->actionPlaylistFinishSearching, &QAction::triggered,
774 playlistWindow_, &PlaylistWindow::finishSearch);
775
776 connect(ui->actionPlaylistExtraIncrement, &QAction::triggered,
777 playlistWindow_, &PlaylistWindow::incExtraPlayTimes);
778 connect(ui->actionPlaylistExtraDecrement, &QAction::triggered,
779 playlistWindow_, &PlaylistWindow::decExtraPlayTimes);
780 connect(ui->actionPlaylistExtraZero, &QAction::triggered,
781 playlistWindow_, &PlaylistWindow::zeroExtraPlayTimes);
782 }
783
globalizeAllActions()784 void MainWindow::globalizeAllActions()
785 {
786 for (QAction *a : ui->menubar->actions()) {
787 addAction(a);
788 }
789 addAction(ui->actionPlaySeekForwards);
790 addAction(ui->actionPlaySeekForwardsFine);
791 addAction(ui->actionPlaySeekBackwards);
792 addAction(ui->actionPlaySeekBackwardsFine);
793 }
794
setUiDecorationState(DecorationState state)795 void MainWindow::setUiDecorationState(DecorationState state)
796 {
797 QString actionTexts[] = { tr("Hide &Menu"), tr("Hide &Borders"),
798 tr("Sho&w Caption and Menu") };
799 ui->actionViewHideMenu->setText(actionTexts[static_cast<int>(state)]);
800 decorationState_ = state;
801
802 if (state == AllDecorations && !ui->menubar->isVisible()) {
803 ui->menubar->show();
804 } else if (state != AllDecorations && ui->menubar->isVisible()) {
805 ui->menubar->hide();
806 }
807
808 updateWindowFlags();
809 }
810
setOSDPage(int page)811 void MainWindow::setOSDPage(int page)
812 {
813 ui->actionViewOSDNone->setChecked(page == -1);
814 ui->actionViewOSDMessages->setChecked(page == 0);
815 ui->actionViewOSDStatistics->setChecked(page == 1);
816 ui->actionViewOSDFrameTimings->setChecked(page == 2);
817 mpvObject_->showStatsPage(page);
818 }
819
setUiEnabledState(bool enabled)820 void MainWindow::setUiEnabledState(bool enabled)
821 {
822 positionSlider_->setEnabled(enabled);
823 if (!enabled) {
824 positionSlider_->setLoopA(-1);
825 positionSlider_->setLoopB(-1);
826 }
827
828 ui->pause->setEnabled(enabled);
829 ui->stop->setEnabled(enabled);
830 ui->stepBackward->setEnabled(enabled);
831 ui->speedDecrease->setEnabled(enabled);
832 ui->speedIncrease->setEnabled(enabled);
833 ui->stepForward->setEnabled(enabled);
834 ui->skipBackward->setEnabled(enabled);
835 ui->skipForward->setEnabled(enabled);
836 ui->loopA->setEnabled(enabled);
837 ui->loopB->setEnabled(enabled);
838
839 ui->mute->setEnabled(enabled);
840 volumeSlider()->setEnabled(enabled);
841
842 ui->pause->setChecked(false);
843 ui->actionPlayPause->setChecked(false);
844
845 ui->actionFileOpenDevice->setEnabled(false);
846 ui->actionFileClose->setEnabled(enabled);
847 ui->actionFileSaveCopy->setEnabled(enabled);
848 ui->actionFileSaveImage->setEnabled(enabled);
849 ui->actionFileSaveImageAuto->setEnabled(enabled);
850 ui->actionFileSavePlainImage->setEnabled(enabled);
851 ui->actionFileSavePlainImageAuto->setEnabled(enabled);
852 ui->actionFileSaveWindowImage->setEnabled(enabled);
853 ui->actionFileSaveWindowImageAuto->setEnabled(enabled);
854 ui->actionFileSaveThumbnails->setEnabled(enabled);
855 ui->actionFileExportEncode->setEnabled(enabled && false);
856 ui->actionFileLoadSubtitle->setEnabled(enabled);
857 ui->actionFileSaveSubtitle->setEnabled(enabled && false);
858 ui->actionFileSubtitleDatabaseDownload->setEnabled(enabled && false);
859 ui->actionPlayPause->setEnabled(enabled);
860 ui->actionPlayStop->setEnabled(enabled);
861 ui->actionPlayFrameBackward->setEnabled(enabled);
862 ui->actionPlayFrameForward->setEnabled(enabled);
863 ui->actionPlayRateDecrease->setEnabled(enabled);
864 ui->actionPlayRateIncrease->setEnabled(enabled);
865 ui->actionPlayRateReset->setEnabled(enabled);
866 ui->actionPlayVolumeUp->setEnabled(enabled);
867 ui->actionPlayVolumeDown->setEnabled(enabled);
868 ui->actionPlayVolumeMute->setEnabled(enabled);
869 ui->actionNavigateChaptersPrevious->setEnabled(enabled);
870 ui->actionNavigateChaptersNext->setEnabled(enabled);
871 ui->actionNavigateGoto->setEnabled(false);
872 ui->actionFavoritesAdd->setEnabled(enabled);
873
874 ui->menuFileSubtitleDatabase->setEnabled(false);
875 ui->menuPlayLoop->setEnabled(enabled);
876 ui->menuPlayAudio->setEnabled(enabled);
877 ui->menuPlaySubtitles->setEnabled(enabled);
878 ui->menuPlayVideo->setEnabled(enabled);
879 ui->menuNavigateChapters->setEnabled(enabled && false);
880 }
881
reparentBottomArea(bool overlay)882 void MainWindow::reparentBottomArea(bool overlay)
883 {
884 // TODO: changing the presentation method will need to check if the
885 // bottom area is inside the mpv widget!
886 bool inLayout = ui->centralwidget->layout()->indexOf(ui->bottomArea) >= 0;
887 if (overlay && inLayout) {
888 bottomAreaHeight = ui->bottomArea->height();
889 ui->centralwidget->layout()->removeWidget(ui->bottomArea);
890 ui->bottomArea->setParent(nullptr);
891 ui->bottomArea->setParent(mpvw ? mpvw : mpvHost_);
892 }
893 if (!overlay && !inLayout) {
894 ui->bottomArea->setParent(nullptr);
895 ui->centralwidget->layout()->addWidget(ui->bottomArea);
896 ui->bottomArea->show();
897 }
898 }
899
checkBottomArea(QPoint mousePosition)900 void MainWindow::checkBottomArea(QPoint mousePosition)
901 {
902 if (!fullscreenMode_)
903 return;
904
905 QPoint relMousePosition;
906 bool startTimer = false;
907 switch (bottomAreaBehavior) {
908 case Helpers::NeverShown:
909 if (ui->bottomArea->isVisible())
910 ui->bottomArea->hide();
911 break;
912 case Helpers::ShowWhenHovering:
913 if (mpvw == nullptr)
914 break;
915 relMousePosition = mpvw->mapFromGlobal(mousePosition);
916 if (ui->bottomArea->geometry().contains(relMousePosition)) {
917 if (ui->bottomArea->isHidden())
918 ui->bottomArea->show();
919 } else if (ui->bottomArea->isVisible() && !hideTimer.isActive()) {
920 startTimer = true;
921 }
922 break;
923 case Helpers::ShowWhenMoving:
924 if (mpvw == nullptr)
925 break;
926 relMousePosition = mapFromGlobal(mousePosition);
927 if (mpvw->geometry().contains(relMousePosition)) {
928 if (ui->bottomArea->isHidden())
929 ui->bottomArea->show();
930 startTimer = true;
931 } else if (ui->bottomArea->isVisible() && !hideTimer.isActive()) {
932 startTimer = true;
933 }
934 break;
935 case Helpers::AlwaysShow:
936 if (ui->bottomArea->isHidden())
937 ui->bottomArea->show();
938 break;
939 }
940
941 if (startTimer) {
942 if (!bottomAreaHideTime)
943 ui->bottomArea->hide();
944 else
945 hideTimer.start();
946 }
947 }
948
updateBottomAreaGeometry()949 void MainWindow::updateBottomAreaGeometry()
950 {
951 if (!fullscreenMode_)
952 return;
953
954 QSize sz = size();
955 bottomAreaHeight = ui->bottomArea->height();
956 if (playlistWindow_->isVisible() && !fullscreenHidePanels)
957 sz -= QSize(playlistWindow_->width(), 0);
958 ui->bottomArea->setGeometry(0, sz.height() - bottomAreaHeight,
959 sz.width(), bottomAreaHeight);
960 }
961
updateTime()962 void MainWindow::updateTime()
963 {
964 double length = mpvObject_->playLength();
965 double time = mpvObject_->playTime();
966 timeDuration->setTime(length, length);
967 timePosition->setTime(time, length);
968 }
969
updateFramedrops()970 void MainWindow::updateFramedrops()
971 {
972 ui->framedrops->setText(QString("vo: %1, decoder: %2")
973 .arg(displayDrops > 0 ? displayDrops : 0)
974 .arg(decoderDrops > 0 ? decoderDrops : 0));
975 }
976
updateBitrate()977 void MainWindow::updateBitrate()
978 {
979 ui->bitrate->setText(QString("v: %1 kb/s, a: %2 kb/s")
980 .arg(std::lrint(videoBitrate / 1000))
981 .arg(std::lrint(audioBitrate / 1000)));
982 }
983
updateSize(bool first_run)984 void MainWindow::updateSize(bool first_run)
985 {
986 if (frozenWindow)
987 return;
988
989 if (!first_run && (isMaximized() || isFullScreen()))
990 return;
991
992 if (zoomMode == FitToWindow)
993 return;
994
995 QSize desired = desirableSize(first_run);
996 QPoint desiredPlace = desirablePosition(desired, first_run);
997 QRect where = geometry();
998 if (zoomCenter)
999 where.moveTopLeft(desiredPlace);
1000 where.setSize(desired);
1001 setGeometry(where);
1002 show();
1003 }
1004
updateInfostats()1005 void MainWindow::updateInfostats()
1006 {
1007 bool infoShow = ui->actionViewHideInformation->isChecked();
1008 bool statShow = ui->actionViewHideStatistics->isChecked();
1009
1010 ui->chapter->setVisible(infoShow);
1011 ui->chapterLabel->setVisible(infoShow);
1012
1013 ui->framerate->setVisible(statShow);
1014 ui->framerateLabel->setVisible(statShow);
1015 ui->avsync->setVisible(statShow);
1016 ui->avsyncLabel->setVisible(statShow);
1017 ui->framedrops->setVisible(statShow);
1018 ui->framedropsLabel->setVisible(statShow);
1019 ui->bitrate->setVisible(statShow);
1020 ui->bitrateLabel->setVisible(statShow);
1021
1022 ui->infoStats->setVisible(infoShow || statShow);
1023 }
1024
updateOnTop()1025 void MainWindow::updateOnTop()
1026 {
1027 switch (onTopMode) {
1028 case AlwaysOnTop:
1029 showOnTop = true;
1030 break;
1031 case OnTopWhenPlaying:
1032 showOnTop = isPlaying;
1033 break;
1034 case OnTopForVideos:
1035 showOnTop = isPlaying && hasVideo;
1036 break;
1037 default:
1038 showOnTop = false;
1039 }
1040 updateWindowFlags();
1041 }
1042
updateWindowFlags()1043 void MainWindow::updateWindowFlags()
1044 {
1045 if (frozenWindow)
1046 return;
1047
1048 Qt::WindowFlags flags = windowFlags();
1049 Qt::WindowFlags old = flags;
1050 bool isOnTop = flags.testFlag(Qt::WindowStaysOnTopHint);
1051 bool isFrameless = flags.testFlag(Qt::FramelessWindowHint);
1052
1053 if (showOnTop && !isOnTop)
1054 flags |= Qt::WindowStaysOnTopHint;
1055 else if (!showOnTop && isOnTop)
1056 flags &= ~Qt::WindowStaysOnTopHint;
1057
1058 if (decorationState_ == NoDecorations && !isFrameless)
1059 flags |= Qt::FramelessWindowHint;
1060 else if (decorationState_ != NoDecorations && isFrameless)
1061 flags &= ~Qt::FramelessWindowHint;
1062
1063 if (old != flags) {
1064 QTimer::singleShot(50, this, [this,flags]() {
1065 setWindowFlags(flags);
1066 show();
1067 });
1068 }
1069 }
1070
updateMouseHideTime()1071 void MainWindow::updateMouseHideTime()
1072 {
1073 mpvObject_->setMouseHideTime(fullscreenMode_
1074 ? mouseHideTimeFullscreen
1075 : mouseHideTimeWindowed);
1076 }
1077
1078
updateDiscList()1079 void MainWindow::updateDiscList()
1080 {
1081 bool addedSomething = false;
1082 auto func = [&](DeviceInfo *device) -> void {
1083 if (device->deviceType != DeviceInfo::OpticalDrive &&
1084 device->deviceType != DeviceInfo::RemovableDrive)
1085 return;
1086 QAction *a = new QAction(device->toDisplayString());
1087 connect(a, &QAction::triggered,
1088 this, [this,device]() {
1089 if (Platform::deviceManager()->isDeviceValid(device)) {
1090 device->mount();
1091 if (!device->mountedPath.isEmpty())
1092 emit dvdbdOpened(QUrl::fromLocalFile(device->mountedPath));
1093 }
1094 });
1095 a->setData(SKIPACTION);
1096 ui->menuFileOpenDisc->addAction(a);
1097 addedSomething = true;
1098 };
1099 ui->menuFileOpenDisc->clear();
1100 Platform::deviceManager()->iterateDevices(func);
1101 ui->menuFileOpenDisc->setEnabled(addedSomething);
1102 }
1103
doQuickOpenFileDialog()1104 QList<QUrl> MainWindow::doQuickOpenFileDialog()
1105 {
1106 QList<QUrl> urls;
1107 static QUrl lastDir;
1108 static QString filter;
1109 if (filter.isEmpty())
1110 filter = Helpers::fileOpenFilter();
1111
1112 urls = QFileDialog::getOpenFileUrls(this, tr("Quick Open"), lastDir, filter);
1113 if (!urls.isEmpty())
1114 lastDir = urls[0];
1115 return urls;
1116 }
1117
setFreestanding(bool freestanding)1118 void MainWindow::setFreestanding(bool freestanding)
1119 {
1120 freestanding_ = freestanding;
1121 setMediaTitle(QString());
1122 }
1123
setNoVideoSize(const QSize & size)1124 void MainWindow::setNoVideoSize(const QSize &size)
1125 {
1126 noVideoSize_ = size.expandedTo(QSize(500,270));
1127 updateSize();
1128 }
1129
setWindowedMouseMap(const MouseStateMap & map)1130 void MainWindow::setWindowedMouseMap(const MouseStateMap &map)
1131 {
1132 mouseMapWindowed = map;
1133 }
1134
setFullscreenMouseMap(const MouseStateMap & map)1135 void MainWindow::setFullscreenMouseMap(const MouseStateMap &map)
1136 {
1137 mouseMapFullscreen = map;
1138 }
1139
setRecentDocuments(QList<TrackInfo> tracks)1140 void MainWindow::setRecentDocuments(QList<TrackInfo> tracks)
1141 {
1142 bool isEmpty = tracks.count() == 0;
1143 ui->menuFileRecent->clear();
1144 ui->menuFileRecent->setDisabled(isEmpty);
1145 if (isEmpty)
1146 return;
1147
1148 for (int i = 0; i < tracks.count(); i++) {
1149 TrackInfo track = tracks[i];
1150 QString displayString = track.url.fileName();
1151 QAction *a = new QAction(QString("%1 - %2").arg(i).arg(displayString),
1152 this);
1153 connect(a, &QAction::triggered, this, [=]() {
1154 emit recentOpened(track);
1155 });
1156 ui->menuFileRecent->addAction(a);
1157 }
1158 ui->menuFileRecent->addSeparator();
1159 ui->menuFileRecent->addAction(ui->actionFileRecentClear);
1160 }
1161
setFavoriteTracks(QList<TrackInfo> files,QList<TrackInfo> streams)1162 void MainWindow::setFavoriteTracks(QList<TrackInfo> files, QList<TrackInfo> streams)
1163 {
1164 auto addAction = [&](QAction *a) {
1165 menuFavoritesTail.append(a);
1166 ui->menuFavorites->addAction(a);
1167 };
1168 auto addSeperator = [&]() {
1169 auto a = new QAction(this);
1170 a->setSeparator(true);
1171 addAction(a);
1172 };
1173 auto addNotice = [&](QString notice) {
1174 auto a = new QAction(this);
1175 a->setText(notice);
1176 a->setEnabled(false);
1177 addAction(a);
1178 };
1179 auto addTracks = [&](const QList<TrackInfo> &tracks) {
1180 for (const auto &t : tracks) {
1181 auto a = new QAction(this);
1182 a->setText(t.text);
1183 connect(a, &QAction::triggered,
1184 a, [t, this]() {
1185 emit this->recentOpened(t);
1186 });
1187 addAction(a);
1188 }
1189 };
1190
1191 for (auto a : qAsConst(menuFavoritesTail))
1192 delete a;
1193 menuFavoritesTail.clear();
1194
1195 addSeperator();
1196 if (files.empty())
1197 addNotice(tr("No files favorited"));
1198 else
1199 addTracks(files);
1200 addSeperator();
1201 if (streams.empty())
1202 addNotice(tr("No streams favorited"));
1203 else
1204 addTracks(streams);
1205 }
1206
setIconTheme(IconThemer::FolderMode mode,QString fallback,QString custom)1207 void MainWindow::setIconTheme(IconThemer::FolderMode mode, QString fallback, QString custom)
1208 {
1209 themer.setIconFolders(mode, fallback, custom);
1210 }
1211
setInfoColors(const QColor & foreground,const QColor & background)1212 void MainWindow::setInfoColors(const QColor &foreground, const QColor &background)
1213 {
1214 QColor fg = foreground.isValid() ? foreground : QColor(255,255,255);
1215 QColor bg = background.isValid() ? background : QColor(0,0,0);
1216 QString css = QString("color: %1; background: %2;").arg(fg.name(), bg.name());
1217 ui->infoSection->setStyleSheet(css);
1218 }
1219
setTime(double time,double length)1220 void MainWindow::setTime(double time, double length)
1221 {
1222 positionSlider_->setMaximum(length >= 0 ? length : 0);
1223 positionSlider_->setValue(time >= 0 ? time : 0);
1224 updateTime();
1225 }
1226
setMediaTitle(QString title)1227 void MainWindow::setMediaTitle(QString title)
1228 {
1229 QString window_title("Media Player Classic Qute Theater");
1230
1231 if (freestanding_)
1232 window_title.append(tr(" [Freestanding]"));
1233 if (!title.isEmpty())
1234 window_title.append(" - ").append(title);
1235 setWindowTitle(window_title);
1236 }
1237
setChapterTitle(QString title)1238 void MainWindow::setChapterTitle(QString title)
1239 {
1240 ui->chapter->setText(!title.isEmpty() ? title : "-");
1241 }
1242
setVideoSize(QSize size)1243 void MainWindow::setVideoSize(QSize size)
1244 {
1245 (void)size;
1246 updateSize();
1247 }
1248
setVolumeStep(int stepSize)1249 void MainWindow::setVolumeStep(int stepSize)
1250 {
1251 volumeStep = stepSize;
1252 }
1253
setSizeFactor(double factor)1254 void MainWindow::setSizeFactor(double factor)
1255 {
1256 sizeFactor_ = factor;
1257 if (sizeFactor_ != 0)
1258 updateSize();
1259 }
1260
setFitFactor(double fitFactor)1261 void MainWindow::setFitFactor(double fitFactor)
1262 {
1263 fitFactor_ = fitFactor;
1264 }
1265
setZoomMode(ZoomMode mode)1266 void MainWindow::setZoomMode(ZoomMode mode)
1267 {
1268 zoomMode = mode;
1269 }
1270
setZoomPreset(int which,double fitFactor)1271 void MainWindow::setZoomPreset(int which, double fitFactor)
1272 {
1273 double factor[] = { 1.0, 1.0, 1.0, 1.0,
1274 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 4.0 };
1275 ZoomMode mode[] = { Autofit, AutofitLarger, AutofitSmaller, FitToWindow,
1276 RegularZoom, RegularZoom, RegularZoom, RegularZoom,
1277 RegularZoom, RegularZoom, RegularZoom, RegularZoom };
1278 QAction *action[] = {
1279 ui->actionViewZoomAutofit, ui->actionViewZoomAutofitLarger,
1280 ui->actionViewZoomAutofitSmaller, ui->actionViewZoomDisable,
1281 ui->actionViewZoom025, ui->actionViewZoom050, ui->actionViewZoom075,
1282 ui->actionViewZoom100, ui->actionViewZoom150, ui->actionViewZoom200,
1283 ui->actionViewZoom300, ui->actionViewZoom400 };
1284
1285 if (fitFactor >= 0.0)
1286 setFitFactor(fitFactor);
1287 setZoomMode(mode[which + 4]);
1288 setSizeFactor(factor[which + 4]);
1289 action[which+4]->setChecked(true);
1290 }
1291
setZoomCenter(bool yes)1292 void MainWindow::setZoomCenter(bool yes)
1293 {
1294 zoomCenter = yes;
1295 }
1296
setMouseHideTimeFullscreen(int msec)1297 void MainWindow::setMouseHideTimeFullscreen(int msec)
1298 {
1299 mouseHideTimeFullscreen = msec;
1300 updateMouseHideTime();
1301 }
1302
setMouseHideTimeWindowed(int msec)1303 void MainWindow::setMouseHideTimeWindowed(int msec)
1304 {
1305 mouseHideTimeWindowed = msec;
1306 updateMouseHideTime();
1307 }
1308
setBottomAreaBehavior(ControlHiding method)1309 void MainWindow::setBottomAreaBehavior(ControlHiding method)
1310 {
1311 bottomAreaBehavior = method;
1312 if (fullscreenMode_)
1313 checkBottomArea(QCursor::pos());
1314 }
1315
setBottomAreaHideTime(int milliseconds)1316 void MainWindow::setBottomAreaHideTime(int milliseconds)
1317 {
1318 bottomAreaHideTime = milliseconds;
1319 hideTimer.setInterval(milliseconds);
1320 }
1321
setTimeTooltip(bool shown,bool above)1322 void MainWindow::setTimeTooltip(bool shown, bool above)
1323 {
1324 timeTooltipShown = shown;
1325 timeTooltipAbove = above;
1326 }
1327
setFullscreenHidePanels(bool hidden)1328 void MainWindow::setFullscreenHidePanels(bool hidden)
1329 {
1330 fullscreenHidePanels = hidden;
1331 if (fullscreenMode_ && !playlistWindow_->isFloating()) {
1332 if (hidden && playlistWindow_->isVisible()) {
1333 playlistWindow_->hide();
1334 updateBottomAreaGeometry();
1335 } else if (!hidden && playlistWindow_->isHidden()) {
1336 playlistWindow_->show();
1337 updateBottomAreaGeometry();
1338 }
1339 }
1340 }
1341
setPlaybackState(PlaybackManager::PlaybackState state)1342 void MainWindow::setPlaybackState(PlaybackManager::PlaybackState state)
1343 {
1344 ui->status->setText(state==PlaybackManager::StoppedState ? tr("Stopped") :
1345 state==PlaybackManager::PausedState ? tr("Paused") :
1346 state==PlaybackManager::PlayingState ? tr("Playing") :
1347 state==PlaybackManager::BufferingState ? tr("Buffering") :
1348 tr("Unknown"));
1349 isPlaying = state != PlaybackManager::StoppedState;
1350 isPaused = state == PlaybackManager::PausedState;
1351 setUiEnabledState(state != PlaybackManager::StoppedState);
1352 if (isPaused) {
1353 ui->actionPlayPause->setChecked(true);
1354 ui->pause->setChecked(true);
1355 }
1356 if (state == PlaybackManager::WaitingState) {
1357 mpvObject_->setLoopPoints(-1, -1);
1358 positionSlider_->setLoopA(-1);
1359 positionSlider_->setLoopB(-1);
1360 }
1361 updateOnTop();
1362 }
1363
setPlaybackType(PlaybackManager::PlaybackType type)1364 void MainWindow::setPlaybackType(PlaybackManager::PlaybackType type)
1365 {
1366 setUiEnabledState(type != PlaybackManager::None);
1367 }
1368
setChapters(QList<QPair<double,QString>> chapters)1369 void MainWindow::setChapters(QList<QPair<double, QString>> chapters)
1370 {
1371 positionSlider_->clearTicks();
1372 ui->menuNavigateChapters->clear();
1373 int64_t index = 0;
1374 for (const QPair<double,QString> &chapter : chapters) {
1375 positionSlider_->setTick(chapter.first, chapter.second);
1376 QAction *action = new QAction(this);
1377 action->setText(chapter.second);
1378 connect (action, &QAction::triggered, this, [this,index]() {
1379 emit chapterSelected(index);
1380 });
1381 ui->menuNavigateChapters->addAction(action);
1382 ++index;
1383 }
1384 }
1385
setAudioTracks(QList<QPair<int64_t,QString>> tracks)1386 void MainWindow::setAudioTracks(QList<QPair<int64_t, QString>> tracks)
1387 {
1388 ui->menuPlayAudio->clear();
1389 for (const QPair<int64_t, QString> &track : tracks) {
1390 QAction *action = new QAction(this);
1391 action->setText(track.second);
1392 int64_t index = track.first;
1393 connect(action, &QAction::triggered, this, [this,index] {
1394 emit audioTrackSelected(index);
1395 });
1396 ui->menuPlayAudio->addAction(action);
1397 }
1398 hasAudio = !tracks.isEmpty();
1399 }
1400
setVideoTracks(QList<QPair<int64_t,QString>> tracks)1401 void MainWindow::setVideoTracks(QList<QPair<int64_t, QString>> tracks)
1402 {
1403 ui->menuPlayVideo->clear();
1404 for (const QPair<int64_t, QString> &track : tracks) {
1405 QAction *action = new QAction(this);
1406 action->setText(track.second);
1407 int64_t index = track.first;
1408 connect(action, &QAction::triggered, this, [this,index]() {
1409 emit videoTrackSelected(index);
1410 });
1411 ui->menuPlayVideo->addAction(action);
1412 }
1413 hasVideo = !tracks.isEmpty();
1414 updateOnTop();
1415 }
1416
setSubtitleTracks(QList<QPair<int64_t,QString>> tracks)1417 void MainWindow::setSubtitleTracks(QList<QPair<int64_t, QString> > tracks)
1418 {
1419 ui->menuPlaySubtitles->clear();
1420 hasSubs = !tracks.isEmpty();
1421 ui->actionPlaySubtitlesEnabled->setEnabled(hasSubs);
1422 ui->subs->setEnabled(hasSubs);
1423 ui->actionPlaySubtitlesNext->setEnabled(hasSubs);
1424 ui->actionPlaySubtitlesPrevious->setEnabled(hasSubs);
1425 if (!hasSubs)
1426 return;
1427 ui->menuPlaySubtitles->addAction(ui->actionPlaySubtitlesEnabled);
1428 ui->menuPlaySubtitles->addAction(ui->actionPlaySubtitlesNext);
1429 ui->menuPlaySubtitles->addAction(ui->actionPlaySubtitlesPrevious);
1430 ui->menuPlaySubtitles->addSeparator();
1431 for (const QPair<int64_t, QString> &track : tracks) {
1432 QAction *action = new QAction(this);
1433 action->setText(track.second);
1434 int64_t index = track.first;
1435 connect(action, &QAction::triggered, this, [this,index]() {
1436 emit subtitleTrackSelected(index);
1437 });
1438 ui->menuPlaySubtitles->addAction(action);
1439 }
1440 }
1441
setVolume(int level)1442 void MainWindow::setVolume(int level)
1443 {
1444 volumeSlider_->setValue(level);
1445 emit volumeChanged(level);
1446 }
1447
setVolumeDouble(double level)1448 void MainWindow::setVolumeDouble(double level)
1449 {
1450 volumeSlider_->setValue(level*100);
1451 emit volumeChanged(static_cast<int64_t>(level*100));
1452 }
1453
setVolumeMax(int level)1454 void MainWindow::setVolumeMax(int level)
1455 {
1456 volumeSlider_->setMaximum(level);
1457 }
1458
setTimeShortMode(bool shortened)1459 void MainWindow::setTimeShortMode(bool shortened)
1460 {
1461 timePosition->setShortMode(shortened);
1462 timeDuration->setShortMode(shortened);
1463 }
1464
resetPlayAfterOnce()1465 void MainWindow::resetPlayAfterOnce()
1466 {
1467 ui->actionPlayAfterOnceNothing->setChecked(true);
1468 }
1469
setPlayAfterAlways(AfterPlayback action)1470 void MainWindow::setPlayAfterAlways(AfterPlayback action)
1471 {
1472 QMap<Helpers::AfterPlayback, QAction*> map {
1473 { Helpers::DoNothingAfter, ui->actionPlayAfterAlwaysNothing },
1474 { Helpers::RepeatAfter, ui->actionPlayAfterAlwaysRepeat },
1475 { Helpers::PlayNextAfter, ui->actionPlayAfterAlwaysNext },
1476 { Helpers::ExitAfter, ui->actionPlayAfterAlwaysExit }
1477 };
1478 if (map.contains(action))
1479 map[action]->setChecked(true);
1480 }
1481
setFps(double fps)1482 void MainWindow::setFps(double fps)
1483 {
1484 ui->framerate->setText(std::isnan(fps) ? "-" : QString::number(fps, 'f', 2));
1485 }
1486
setAvsync(double sync)1487 void MainWindow::setAvsync(double sync)
1488 {
1489 ui->avsync->setText(std::isnan(sync) ? "-" : QString::number(sync, 'f', 3));
1490 }
1491
setDisplayFramedrops(int64_t count)1492 void MainWindow::setDisplayFramedrops(int64_t count)
1493 {
1494 displayDrops = count;
1495 updateFramedrops();
1496 }
1497
setDecoderFramedrops(int64_t count)1498 void MainWindow::setDecoderFramedrops(int64_t count)
1499 {
1500 decoderDrops = count;
1501 updateFramedrops();
1502 }
1503
setAudioBitrate(double bitrate)1504 void MainWindow::setAudioBitrate(double bitrate)
1505 {
1506 audioBitrate = bitrate;
1507 updateBitrate();
1508 }
1509
setVideoBitrate(double bitrate)1510 void MainWindow::setVideoBitrate(double bitrate)
1511 {
1512 videoBitrate = bitrate;
1513 updateBitrate();
1514 }
1515
logWindowClosed()1516 void MainWindow::logWindowClosed()
1517 {
1518 ui->actionViewHideLog->setChecked(false);
1519 }
1520
libraryWindowClosed()1521 void MainWindow::libraryWindowClosed()
1522 {
1523 ui->actionViewHideLibrary->setChecked(false);
1524 }
1525
setPlaylistVisibleState(bool yes)1526 void MainWindow::setPlaylistVisibleState(bool yes) {
1527 if (fullscreenMode_)
1528 return;
1529 if (!ui)
1530 return;
1531 ui->actionFileOpenQuick->setText(yes ? tr("&Quick Add To Playlist")
1532 : tr("&Quick Open File"));
1533 ui->actionViewHidePlaylist->setChecked(yes);
1534 }
1535
setPlaylistQuickQueueMode(bool yes)1536 void MainWindow::setPlaylistQuickQueueMode(bool yes)
1537 {
1538 if (!ui)
1539 return;
1540 ui->actionPlaylistShowQuickQueue->setChecked(yes);
1541 ui->actionPlaylistQuickQueue->setEnabled(!yes);
1542 ui->actionPlaylistQueueVisible->setEnabled(!yes);
1543 }
1544
on_actionFileOpenQuick_triggered()1545 void MainWindow::on_actionFileOpenQuick_triggered()
1546 {
1547 QList<QUrl> urls = doQuickOpenFileDialog();
1548 if (urls.isEmpty())
1549 return;
1550 emit severalFilesOpened(urls);
1551 }
1552
on_actionFileOpen_triggered()1553 void MainWindow::on_actionFileOpen_triggered()
1554 {
1555 OpenFileDialog d;
1556 if (!d.exec())
1557 return;
1558
1559 emit fileOpened(d.file(), d.subs());
1560 }
1561
on_actionFileOpenDvdbd_triggered()1562 void MainWindow::on_actionFileOpenDvdbd_triggered()
1563 {
1564 QUrl dir;
1565 static QUrl lastDir;
1566 dir = QFileDialog::getExistingDirectoryUrl(this, tr("Open Directory"),
1567 lastDir);
1568 if (dir.isEmpty())
1569 return;
1570 lastDir = dir;
1571 emit dvdbdOpened(dir);
1572 }
1573
on_actionFileOpenDirectory_triggered()1574 void MainWindow::on_actionFileOpenDirectory_triggered()
1575 {
1576 QUrl url;
1577 static QUrl lastDir;
1578 url = QFileDialog::getExistingDirectoryUrl(this, tr("Open Directory"),
1579 lastDir);
1580 if (url.isEmpty())
1581 return;
1582 lastDir = url;
1583
1584 // If we pass the directory and let Helpers::filterUrls handle it,
1585 // we may freeze if the user selects the root folder. So only
1586 // pass through the folder contents for now. To expand all
1587 // subfolders, Drag-and-drop or pass folders through the cli.
1588 QDir dir(url.toLocalFile());
1589 QList<QUrl> list;
1590 QFileInfoList f = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files);
1591 for (auto &file : f)
1592 list.append(QUrl::fromLocalFile(file.absoluteFilePath()));
1593 emit severalFilesOpened(list);
1594 }
1595
on_actionFileOpenNetworkStream_triggered()1596 void MainWindow::on_actionFileOpenNetworkStream_triggered()
1597 {
1598 QInputDialog *qid = new QInputDialog(this);
1599 qid->setAttribute(Qt::WA_DeleteOnClose);
1600 qid->setWindowModality(Qt::WindowModal);
1601 qid->setWindowTitle(tr("Enter Network Stream"));
1602 qid->setLabelText(tr("Network Stream"));
1603 connect(qid, &QInputDialog::accepted, this, [=] () {
1604 emit streamOpened(QUrl::fromUserInput(qid->textValue()));
1605 });
1606 qid->show();
1607 }
1608
on_actionFileRecentClear_triggered()1609 void MainWindow::on_actionFileRecentClear_triggered()
1610 {
1611 emit recentClear();
1612 }
1613
on_actionFileSaveImage_triggered()1614 void MainWindow::on_actionFileSaveImage_triggered()
1615 {
1616 emit takeImage(Helpers::SubsRender);
1617 }
1618
on_actionFileSaveImageAuto_triggered()1619 void MainWindow::on_actionFileSaveImageAuto_triggered()
1620 {
1621 emit takeImageAutomatically(Helpers::SubsRender);
1622 }
1623
on_actionFileSavePlainImage_triggered()1624 void MainWindow::on_actionFileSavePlainImage_triggered()
1625 {
1626 emit takeImage(Helpers::VideoRender);
1627 }
1628
on_actionFileSavePlainImageAuto_triggered()1629 void MainWindow::on_actionFileSavePlainImageAuto_triggered()
1630 {
1631 emit takeImageAutomatically(Helpers::VideoRender);
1632 }
1633
on_actionFileSaveWindowImage_triggered()1634 void MainWindow::on_actionFileSaveWindowImage_triggered()
1635 {
1636 emit takeImage(Helpers::WindowRender);
1637 }
1638
on_actionFileSaveWindowImageAuto_triggered()1639 void MainWindow::on_actionFileSaveWindowImageAuto_triggered()
1640 {
1641 emit takeImageAutomatically(Helpers::WindowRender);
1642 }
1643
on_actionFileLoadSubtitle_triggered()1644 void MainWindow::on_actionFileLoadSubtitle_triggered()
1645 {
1646 QUrl url;
1647 static QUrl lastUrl;
1648 url = QFileDialog::getOpenFileUrl(this, tr("Open Subtitle"), lastUrl);
1649 if (url.isEmpty())
1650 return;
1651 lastUrl = url;
1652 emit subtitlesLoaded(url);
1653 }
1654
on_actionFileClose_triggered()1655 void MainWindow::on_actionFileClose_triggered()
1656 {
1657 on_actionPlayStop_triggered();
1658 }
1659
on_actionFileExit_triggered()1660 void MainWindow::on_actionFileExit_triggered()
1661 {
1662 close();
1663 }
1664
on_actionViewHideMenu_triggered()1665 void MainWindow::on_actionViewHideMenu_triggered()
1666 {
1667 // View/hide are unmanaged when in fullscreen mode
1668 if (fullscreenMode_)
1669 return;
1670
1671 DecorationState nextState[] = { NoMenu, NoDecorations, AllDecorations };
1672 setUiDecorationState(nextState[static_cast<int>(decorationState_)]);
1673 updateSize();
1674 }
1675
on_actionViewHideSeekbar_toggled(bool checked)1676 void MainWindow::on_actionViewHideSeekbar_toggled(bool checked)
1677 {
1678 if (checked && ui->seekbar->isHidden())
1679 ui->seekbar->show();
1680 else if (!checked && ui->seekbar->isVisible())
1681 ui->seekbar->hide();
1682 ui->controlSection->adjustSize();
1683 updateSize();
1684 }
1685
on_actionViewHideControls_toggled(bool checked)1686 void MainWindow::on_actionViewHideControls_toggled(bool checked)
1687 {
1688 if (checked && ui->controlbar->isHidden())
1689 ui->controlbar->show();
1690 else if (!checked && ui->controlbar->isVisible())
1691 ui->controlbar->hide();
1692 ui->controlSection->adjustSize();
1693 updateSize();
1694 }
1695
on_actionViewHideInformation_toggled(bool checked)1696 void MainWindow::on_actionViewHideInformation_toggled(bool checked)
1697 {
1698 Q_UNUSED(checked)
1699 updateInfostats();
1700 updateSize();
1701 }
1702
on_actionViewHideStatistics_toggled(bool checked)1703 void MainWindow::on_actionViewHideStatistics_toggled(bool checked)
1704 {
1705 Q_UNUSED(checked)
1706 updateInfostats();
1707 updateSize();
1708 }
1709
on_actionViewHideStatus_toggled(bool checked)1710 void MainWindow::on_actionViewHideStatus_toggled(bool checked)
1711 {
1712 if (checked && ui->statusbar->isHidden())
1713 ui->statusbar->show();
1714 else if (!checked && ui->statusbar->isVisible())
1715 ui->statusbar->hide();
1716 updateSize();
1717 }
1718
on_actionViewHideSubresync_toggled(bool checked)1719 void MainWindow::on_actionViewHideSubresync_toggled(bool checked)
1720 {
1721 (void)checked;
1722
1723 updateSize();
1724 }
1725
on_actionViewHidePlaylist_toggled(bool checked)1726 void MainWindow::on_actionViewHidePlaylist_toggled(bool checked)
1727 {
1728 if (fullscreenMode_ && fullscreenHidePanels)
1729 return;
1730
1731 if (isMinimized())
1732 return;
1733
1734 if (checked && playlistWindow_->isHidden())
1735 playlistWindow_->show();
1736 else if (!checked && playlistWindow_->isVisible())
1737 playlistWindow_->hide();
1738
1739 if (fullscreenMode_ && !fullscreenHidePanels)
1740 updateBottomAreaGeometry();
1741
1742 updateSize();
1743 }
1744
on_actionViewHideCapture_toggled(bool checked)1745 void MainWindow::on_actionViewHideCapture_toggled(bool checked)
1746 {
1747 (void)checked;
1748
1749 updateSize();
1750 }
1751
on_actionViewHideNavigation_toggled(bool checked)1752 void MainWindow::on_actionViewHideNavigation_toggled(bool checked)
1753 {
1754 (void)checked;
1755
1756 updateSize();
1757 }
1758
1759
on_actionViewHideLog_toggled(bool checked)1760 void MainWindow::on_actionViewHideLog_toggled(bool checked)
1761 {
1762 if (checked)
1763 emit showLogWindow();
1764 else
1765 emit hideLogWindow();
1766 }
1767
on_actionViewHideLibrary_toggled(bool checked)1768 void MainWindow::on_actionViewHideLibrary_toggled(bool checked)
1769 {
1770 if (checked)
1771 emit showLibraryWindow();
1772 else
1773 emit hideLibraryWindow();
1774 }
1775
on_actionViewPresetsMinimal_triggered()1776 void MainWindow::on_actionViewPresetsMinimal_triggered()
1777 {
1778 setUiDecorationState(NoDecorations);
1779 ui->actionViewHideSeekbar->setChecked(false);
1780 ui->actionViewHideControls->setChecked(false);
1781 ui->actionViewHideInformation->setChecked(false);
1782 ui->actionViewHideStatistics->setChecked(false);
1783 ui->actionViewHideStatus->setChecked(false);
1784 ui->actionViewHideSubresync->setChecked(false);
1785 ui->actionViewHideCapture->setChecked(false);
1786 ui->actionViewHideNavigation->setChecked(false);
1787 }
1788
on_actionViewPresetsCompact_triggered()1789 void MainWindow::on_actionViewPresetsCompact_triggered()
1790 {
1791 // we should set our menu state to something like Framed, but we can't
1792 // reliably do that across window managers.
1793 setUiDecorationState(NoDecorations);
1794 ui->actionViewHideMenu->setChecked(true);
1795 ui->actionViewHideSeekbar->setChecked(true);
1796 ui->actionViewHideControls->setChecked(false);
1797 ui->actionViewHideInformation->setChecked(false);
1798 ui->actionViewHideStatistics->setChecked(false);
1799 ui->actionViewHideStatus->setChecked(false);
1800 ui->actionViewHideSubresync->setChecked(false);
1801 ui->actionViewHideCapture->setChecked(false);
1802 ui->actionViewHideNavigation->setChecked(false);
1803 }
1804
on_actionViewPresetsNormal_triggered()1805 void MainWindow::on_actionViewPresetsNormal_triggered()
1806 {
1807 setUiDecorationState(AllDecorations);
1808 ui->actionViewHideMenu->setChecked(true);
1809 ui->actionViewHideSeekbar->setChecked(true);
1810 ui->actionViewHideControls->setChecked(true);
1811 ui->actionViewHideInformation->setChecked(false);
1812 ui->actionViewHideStatistics->setChecked(false);
1813 ui->actionViewHideStatus->setChecked(true);
1814 ui->actionViewHideSubresync->setChecked(false);
1815 ui->actionViewHideCapture->setChecked(false);
1816 ui->actionViewHideNavigation->setChecked(false);
1817 }
1818
on_actionViewOSDNone_triggered()1819 void MainWindow::on_actionViewOSDNone_triggered()
1820 {
1821 mpvObject_->showStatsPage(-1);
1822 }
1823
on_actionViewOSDMessages_triggered()1824 void MainWindow::on_actionViewOSDMessages_triggered()
1825 {
1826 mpvObject_->showStatsPage(0);
1827 }
1828
on_actionViewOSDStatistics_triggered()1829 void MainWindow::on_actionViewOSDStatistics_triggered()
1830 {
1831 mpvObject_->showStatsPage(1);
1832 }
1833
on_actionViewOSDFrameTimings_triggered()1834 void MainWindow::on_actionViewOSDFrameTimings_triggered()
1835 {
1836 mpvObject_->showStatsPage(2);
1837 }
1838
on_actionViewOSDCycle_triggered()1839 void MainWindow::on_actionViewOSDCycle_triggered()
1840 {
1841 QActionGroup *osdActionGroup = ui->actionViewOSDMessages->actionGroup();
1842 QAction *nextOsdAction;
1843 int newpage;
1844
1845 newpage = mpvObject_->cycleStatsPage();
1846 nextOsdAction = osdActionGroup->actions().value(newpage+1, nullptr);
1847 if (nextOsdAction)
1848 nextOsdAction->setChecked(true);
1849 }
1850
on_actionViewFullscreen_toggled(bool checked)1851 void MainWindow::on_actionViewFullscreen_toggled(bool checked)
1852 {
1853 setFullscreenMode(checked);
1854 reparentBottomArea(checked);
1855
1856 if (checked) {
1857 menuBar()->hide();
1858 if (fullscreenHidePanels && !playlistWindow_->isFloating())
1859 playlistWindow_->hide();
1860 } else {
1861 if (decorationState_ == AllDecorations)
1862 menuBar()->show();
1863 ui->bottomArea->show();
1864 if (ui->actionViewHidePlaylist->isChecked())
1865 playlistWindow_->show();
1866 }
1867 }
1868
on_actionViewFullscreenEscape_triggered()1869 void MainWindow::on_actionViewFullscreenEscape_triggered()
1870 {
1871 ui->actionViewFullscreen->setChecked(false);
1872 }
1873
on_actionViewZoom025_triggered()1874 void MainWindow::on_actionViewZoom025_triggered()
1875 {
1876 setZoomPreset(0);
1877 emit zoomPresetChanged(0);
1878 }
1879
on_actionViewZoom050_triggered()1880 void MainWindow::on_actionViewZoom050_triggered()
1881 {
1882 setZoomPreset(1);
1883 emit zoomPresetChanged(1);
1884 }
1885
on_actionViewZoom075_triggered()1886 void MainWindow::on_actionViewZoom075_triggered()
1887 {
1888 setZoomPreset(2);
1889 emit zoomPresetChanged(2);
1890 }
1891
on_actionViewZoom100_triggered()1892 void MainWindow::on_actionViewZoom100_triggered()
1893 {
1894 setZoomPreset(3);
1895 emit zoomPresetChanged(3);
1896 }
1897
on_actionViewZoom150_triggered()1898 void MainWindow::on_actionViewZoom150_triggered()
1899 {
1900 setZoomPreset(4);
1901 emit zoomPresetChanged(4);
1902 }
1903
on_actionViewZoom200_triggered()1904 void MainWindow::on_actionViewZoom200_triggered()
1905 {
1906 setZoomPreset(5);
1907 emit zoomPresetChanged(5);
1908 }
1909
on_actionViewZoom300_triggered()1910 void MainWindow::on_actionViewZoom300_triggered()
1911 {
1912 setZoomPreset(6);
1913 emit zoomPresetChanged(6);
1914 }
1915
on_actionViewZoom400_triggered()1916 void MainWindow::on_actionViewZoom400_triggered()
1917 {
1918 setZoomPreset(7);
1919 emit zoomPresetChanged(7);
1920 }
1921
on_actionViewZoomAutofit_triggered()1922 void MainWindow::on_actionViewZoomAutofit_triggered()
1923 {
1924 setZoomPreset(-4);
1925 emit zoomPresetChanged(-4);
1926 }
1927
on_actionViewZoomAutofitLarger_triggered()1928 void MainWindow::on_actionViewZoomAutofitLarger_triggered()
1929 {
1930 setZoomPreset(-3);
1931 emit zoomPresetChanged(-3);
1932 }
1933
on_actionViewZoomAutofitSmaller_triggered()1934 void MainWindow::on_actionViewZoomAutofitSmaller_triggered()
1935 {
1936 setZoomPreset(-2);
1937 emit zoomPresetChanged(-2);
1938 }
1939
on_actionViewZoomDisable_triggered()1940 void MainWindow::on_actionViewZoomDisable_triggered()
1941 {
1942 setZoomPreset(-1);
1943 emit zoomPresetChanged(-1);
1944 }
1945
on_actionViewOntopDefault_toggled(bool checked)1946 void MainWindow::on_actionViewOntopDefault_toggled(bool checked)
1947 {
1948 if (!checked)
1949 return;
1950 onTopMode = OnTopDefault;
1951 updateOnTop();
1952 }
1953
on_actionViewOntopAlways_toggled(bool checked)1954 void MainWindow::on_actionViewOntopAlways_toggled(bool checked)
1955 {
1956 if (!checked)
1957 return;
1958 onTopMode = AlwaysOnTop;
1959 updateOnTop();
1960 }
1961
on_actionViewOntopPlaying_toggled(bool checked)1962 void MainWindow::on_actionViewOntopPlaying_toggled(bool checked)
1963 {
1964 if (!checked)
1965 return;
1966 onTopMode = OnTopWhenPlaying;
1967 updateOnTop();
1968 }
1969
on_actionViewOntopVideo_toggled(bool checked)1970 void MainWindow::on_actionViewOntopVideo_toggled(bool checked)
1971 {
1972 if (!checked)
1973 return;
1974 onTopMode = OnTopForVideos;
1975 updateOnTop();
1976 }
1977
on_actionViewOptions_triggered()1978 void MainWindow::on_actionViewOptions_triggered()
1979 {
1980 emit optionsOpenRequested();
1981 }
1982
on_actionPlayPause_triggered(bool checked)1983 void MainWindow::on_actionPlayPause_triggered(bool checked)
1984 {
1985 if (checked)
1986 emit paused();
1987 else
1988 emit unpaused();
1989 }
1990
on_actionPlayStop_triggered()1991 void MainWindow::on_actionPlayStop_triggered()
1992 {
1993 emit stopped();
1994 isPlaying = false;
1995 updateSize();
1996 }
1997
on_actionPlayFrameBackward_triggered()1998 void MainWindow::on_actionPlayFrameBackward_triggered()
1999 {
2000 emit stepBackward();
2001 }
2002
on_actionPlayFrameForward_triggered()2003 void MainWindow::on_actionPlayFrameForward_triggered()
2004 {
2005 emit stepForward();
2006 }
2007
on_actionPlayRateDecrease_triggered()2008 void MainWindow::on_actionPlayRateDecrease_triggered()
2009 {
2010 emit speedDown();
2011 }
2012
on_actionPlayRateIncrease_triggered()2013 void MainWindow::on_actionPlayRateIncrease_triggered()
2014 {
2015 emit speedUp();
2016 }
2017
on_actionPlayRateReset_triggered()2018 void MainWindow::on_actionPlayRateReset_triggered()
2019 {
2020 emit speedReset();
2021 }
2022
on_actionPlaySeekForwards_triggered()2023 void MainWindow::on_actionPlaySeekForwards_triggered()
2024 {
2025 emit relativeSeek(true, false);
2026 }
2027
on_actionPlaySeekBackwards_triggered()2028 void MainWindow::on_actionPlaySeekBackwards_triggered()
2029 {
2030 emit relativeSeek(false, false);
2031 }
2032
on_actionPlaySeekForwardsFine_triggered()2033 void MainWindow::on_actionPlaySeekForwardsFine_triggered()
2034 {
2035 emit relativeSeek(true, true);
2036 }
2037
on_actionPlaySeekBackwardsFine_triggered()2038 void MainWindow::on_actionPlaySeekBackwardsFine_triggered()
2039 {
2040 emit relativeSeek(false, true);
2041 }
2042
on_actionPlaySubtitlesEnabled_triggered(bool checked)2043 void MainWindow::on_actionPlaySubtitlesEnabled_triggered(bool checked)
2044 {
2045 emit subtitlesEnabled(checked);
2046 ui->actionPlaySubtitlesEnabled->setChecked(checked);
2047 ui->subs->setChecked(!checked);
2048 }
2049
on_actionPlaySubtitlesNext_triggered()2050 void MainWindow::on_actionPlaySubtitlesNext_triggered()
2051 {
2052 emit nextSubtitleSelected();
2053 }
2054
on_actionPlaySubtitlesPrevious_triggered()2055 void MainWindow::on_actionPlaySubtitlesPrevious_triggered()
2056 {
2057 emit previousSubtitleSelected();
2058 }
2059
on_actionPlayLoopStart_triggered()2060 void MainWindow::on_actionPlayLoopStart_triggered()
2061 {
2062 positionSlider_->setLoopA(mpvObject_->playTime());
2063 if (ui->actionPlayLoopUse->isChecked())
2064 mpvObject_->setLoopPoints(positionSlider_->loopA(),
2065 positionSlider_->loopB());
2066 }
2067
on_actionPlayLoopEnd_triggered()2068 void MainWindow::on_actionPlayLoopEnd_triggered()
2069 {
2070 positionSlider_->setLoopB(mpvObject_->playTime());
2071 if (ui->actionPlayLoopUse->isChecked())
2072 mpvObject_->setLoopPoints(positionSlider_->loopA(),
2073 positionSlider_->loopB());
2074 }
2075
on_actionPlayLoopUse_triggered(bool checked)2076 void MainWindow::on_actionPlayLoopUse_triggered(bool checked)
2077 {
2078 if (checked && !positionSlider_->isLoopEmpty()) {
2079 mpvObject_->setLoopPoints(positionSlider_->loopA(),
2080 positionSlider_->loopB());
2081 } else if (checked) {
2082 ui->actionPlayLoopUse->setChecked(false);
2083 } else {
2084 mpvObject_->setLoopPoints(-1, -1);
2085 }
2086 }
2087
on_actionPlayLoopClear_triggered()2088 void MainWindow::on_actionPlayLoopClear_triggered()
2089 {
2090 ui->actionPlayLoopUse->setChecked(false);
2091 mpvObject_->setLoopPoints(-1, -1);
2092 positionSlider_->setLoopA(-1);
2093 positionSlider_->setLoopB(-1);
2094 }
2095
on_actionPlayVolumeUp_triggered()2096 void MainWindow::on_actionPlayVolumeUp_triggered()
2097 {
2098 int newvol = int(std::min(volumeSlider_->value() + volumeStep, volumeSlider_->maximum()));
2099 emit volumeChanged(newvol);
2100 volumeSlider_->setValue(newvol);
2101 }
2102
on_actionPlayVolumeDown_triggered()2103 void MainWindow::on_actionPlayVolumeDown_triggered()
2104 {
2105 int newvol = int(std::max(volumeSlider_->value() - volumeStep, volumeSlider_->minimum()));
2106 emit volumeChanged(newvol);
2107 volumeSlider_->setValue(newvol);
2108 }
2109
on_actionPlayVolumeMute_toggled(bool checked)2110 void MainWindow::on_actionPlayVolumeMute_toggled(bool checked)
2111 {
2112 if (!isPlaying)
2113 return;
2114 emit volumeMuteChanged(checked);
2115 ui->actionPlayVolumeMute->setChecked(checked);
2116 ui->mute->setChecked(checked);
2117 }
2118
on_actionPlayAfterOnceExit_triggered()2119 void MainWindow::on_actionPlayAfterOnceExit_triggered()
2120 {
2121 emit afterPlaybackOnce(Helpers::ExitAfter);
2122 }
2123
on_actionPlayAfterOnceStandby_triggered()2124 void MainWindow::on_actionPlayAfterOnceStandby_triggered()
2125 {
2126 emit afterPlaybackOnce(Helpers::StandByAfter);
2127 }
2128
on_actionPlayAfterOnceHibernate_triggered()2129 void MainWindow::on_actionPlayAfterOnceHibernate_triggered()
2130 {
2131 emit afterPlaybackOnce(Helpers::HibernateAfter);
2132 }
2133
on_actionPlayAfterOnceShutdown_triggered()2134 void MainWindow::on_actionPlayAfterOnceShutdown_triggered()
2135 {
2136 emit afterPlaybackOnce(Helpers::ShutdownAfter);
2137 }
2138
on_actionPlayAfterOnceLogoff_triggered()2139 void MainWindow::on_actionPlayAfterOnceLogoff_triggered()
2140 {
2141 emit afterPlaybackOnce(Helpers::LogOffAfter);
2142 }
2143
on_actionPlayAfterOnceLock_triggered()2144 void MainWindow::on_actionPlayAfterOnceLock_triggered()
2145 {
2146 emit afterPlaybackOnce(Helpers::LockAfter);
2147 }
2148
on_actionPlayAfterOnceNothing_triggered()2149 void MainWindow::on_actionPlayAfterOnceNothing_triggered()
2150 {
2151 emit afterPlaybackOnce(Helpers::DoNothingAfter);
2152 }
2153
on_actionPlayAfterOnceRepeat_triggered()2154 void MainWindow::on_actionPlayAfterOnceRepeat_triggered()
2155 {
2156 emit afterPlaybackOnce(Helpers::RepeatAfter);
2157 }
2158
on_actionPlayAfterAlwaysRepeat_triggered()2159 void MainWindow::on_actionPlayAfterAlwaysRepeat_triggered()
2160 {
2161 emit afterPlaybackAlways(Helpers::RepeatAfter);
2162 }
2163
on_actionPlayAfterAlwaysExit_triggered()2164 void MainWindow::on_actionPlayAfterAlwaysExit_triggered()
2165 {
2166 emit afterPlaybackAlways(Helpers::ExitAfter);
2167 }
2168
on_actionPlayAfterAlwaysNothing_triggered()2169 void MainWindow::on_actionPlayAfterAlwaysNothing_triggered()
2170 {
2171 emit afterPlaybackAlways(Helpers::DoNothingAfter);
2172 }
2173
on_actionPlayAfterAlwaysNext_triggered()2174 void MainWindow::on_actionPlayAfterAlwaysNext_triggered()
2175 {
2176 emit afterPlaybackAlways(Helpers::PlayNextAfter);
2177 }
2178
on_actionNavigateChaptersPrevious_triggered()2179 void MainWindow::on_actionNavigateChaptersPrevious_triggered()
2180 {
2181 emit chapterPrevious();
2182 }
2183
on_actionNavigateChaptersNext_triggered()2184 void MainWindow::on_actionNavigateChaptersNext_triggered()
2185 {
2186 emit chapterNext();
2187 }
2188
on_actionHelpHomepage_triggered()2189 void MainWindow::on_actionHelpHomepage_triggered()
2190 {
2191 QDesktopServices::openUrl(QUrl("https://github.com/cmdrkotori/mpc-qt-origin"));
2192 }
2193
on_actionHelpAbout_triggered()2194 void MainWindow::on_actionHelpAbout_triggered()
2195 {
2196 #if defined(MPCQT_DEVELOPMENT)
2197 #define BUILD_VERSION_STR QString("%1 (%2)").arg(devBuild, MPCQT_VERSION_STR)
2198 #elif defined(MPCQT_VERSION_STR)
2199 #define BUILD_VERSION_STR versionFmt.arg(MPCQT_VERSION_STR)
2200 #else
2201 #define BUILD_VERSION_STR devBuild
2202 #endif
2203 QString devBuild = tr("Development Build");
2204 QString versionFmt = tr("Version %1");
2205 QString dateLineFmt = tr("Built on %1 at %2");
2206 QString dateLine;
2207
2208 #if defined(MPCQT_DEVELOPMENT)
2209 QDate buildDate = Helpers::dateFromCFormat(__DATE__);
2210 QTime buildTime = Helpers::timeFromCFormat(__TIME__);
2211 dateLine = "<br>" + dateLineFmt.arg(buildDate.toString(Qt::DefaultLocaleShortDate),
2212 buildTime.toString(Qt::DefaultLocaleShortDate));
2213 #endif
2214
2215 QMessageBox::about(this, tr("About Media Player Classic Qute Theater"),
2216 "<h2>" + tr("Media Player Classic Qute Theater") + "</h2>" +
2217 "<p>" + tr("A clone of Media Player Classic written in Qt") +
2218 "<br>" + tr("Based on Qt %1 and %2").arg(QT_VERSION_STR, mpvObject_->mpvVersion()) +
2219 "<p>" + BUILD_VERSION_STR +
2220 dateLine +
2221 "<h3>LICENSE</h3>"
2222 "<p> Copyright (C) 2015"
2223 "<p>"
2224 "This program is free software; you can redistribute it and/or modify "
2225 "it under the terms of the GNU General Public License as published by "
2226 "the Free Software Foundation; either version 2 of the License, or "
2227 "(at your option) any later version."
2228 "<p>"
2229 "This program is distributed in the hope that it will be useful, "
2230 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
2231 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
2232 "GNU General Public License for more details."
2233 "<p>"
2234 "You should have received a copy of the GNU General Public License "
2235 "along with this program; if not, write to the Free Software "
2236 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA "
2237 "02110-1301 USA.");
2238 }
2239
2240
mpvw_customContextMenuRequested(const QPoint & pos)2241 void MainWindow::mpvw_customContextMenuRequested(const QPoint &pos)
2242 {
2243 if (mpvw == nullptr)
2244 return;
2245 contextMenu->popup(mpvw->mapToGlobal(pos));
2246 }
2247
position_sliderMoved(int position)2248 void MainWindow::position_sliderMoved(int position)
2249 {
2250 emit timeSelected(position);
2251 }
2252
position_hoverValue(double value,QString text,double x)2253 void MainWindow::position_hoverValue(double value, QString text, double x)
2254 {
2255 if (!timeTooltipShown)
2256 return;
2257 if (text.isEmpty())
2258 text = tr("<unknown>");
2259
2260 QString t = QString("%1 - %2").arg(Helpers::toDateFormat(value), text);
2261 QPoint where = positionSlider_->mapToGlobal(QPoint(int(x), timeTooltipAbove ? -40 : 0));
2262 QToolTip::showText(where, t, positionSlider_);
2263
2264 //FIXME: use a widget not the system tooltip?
2265 }
2266
on_play_clicked()2267 void MainWindow::on_play_clicked()
2268 {
2269 if (!isPlaying) {
2270 emit playCurrentItemRequested();
2271 return;
2272 }
2273 if (isPaused) {
2274 emit unpaused();
2275 isPaused = false;
2276 ui->pause->setChecked(false);
2277 } else {
2278 emit paused();
2279 isPaused = true;
2280 ui->pause->setChecked(true);
2281 }
2282 }
2283
volume_sliderMoved(double position)2284 void MainWindow::volume_sliderMoved(double position)
2285 {
2286 emit volumeChanged(int(position));
2287 }
2288
playlistWindow_windowDocked()2289 void MainWindow::playlistWindow_windowDocked()
2290 {
2291 if (fullscreenMode_ && fullscreenHidePanels)
2292 playlistWindow_->hide();
2293 }
2294
playlistWindow_playlistAddItem(const QUuid & playlistUuid)2295 void MainWindow::playlistWindow_playlistAddItem(const QUuid &playlistUuid)
2296 {
2297 QList<QUrl> urls = doQuickOpenFileDialog();
2298 if (urls.isEmpty())
2299 return;
2300 emit severalFilesOpenedForPlaylist(playlistUuid, urls);
2301 }
2302
hideTimer_timeout()2303 void MainWindow::hideTimer_timeout()
2304 {
2305 if (mpvw == nullptr)
2306 return;
2307 if (fullscreenMode_ &&
2308 !ui->bottomArea->geometry().contains(mpvw->mapFromGlobal(QCursor::pos())))
2309 ui->bottomArea->hide();
2310 }
2311
on_actionPlaylistSearch_triggered()2312 void MainWindow::on_actionPlaylistSearch_triggered()
2313 {
2314 if (playlistWindow_->isHidden())
2315 playlistWindow_->show();
2316 playlistWindow_->revealSearch();
2317 }
2318
2319
on_actionFavoritesAdd_triggered()2320 void MainWindow::on_actionFavoritesAdd_triggered()
2321 {
2322 emit favoriteCurrentTrack();
2323 }
2324
on_actionFavoritesOrganize_triggered()2325 void MainWindow::on_actionFavoritesOrganize_triggered()
2326 {
2327 emit organizeFavorites();
2328 }
2329