/* This file is part of Clementine. Copyright 2010, David Sansome Clementine is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Clementine is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Clementine. If not, see . */ #include "visualisationcontainer.h" #include #include #include #include #include #include #include #include #include #include "config.h" #include "core/logging.h" #include "engines/gstengine.h" #include "projectmvisualisation.h" #include "ui/iconloader.h" #include "ui/screensaver.h" #include "visualisationoverlay.h" #include "visualisationselector.h" // Framerates const int VisualisationContainer::kLowFramerate = 15; const int VisualisationContainer::kMediumFramerate = 25; const int VisualisationContainer::kHighFramerate = 35; const int VisualisationContainer::kSuperHighFramerate = 60; const char* VisualisationContainer::kSettingsGroup = "Visualisations"; const int VisualisationContainer::kDefaultWidth = 828; const int VisualisationContainer::kDefaultHeight = 512; const int VisualisationContainer::kDefaultFps = kHighFramerate; const int VisualisationContainer::kDefaultTextureSize = 512; VisualisationContainer::VisualisationContainer(QWidget* parent) : QGraphicsView(parent), initialised_(false), engine_(nullptr), vis_(new ProjectMVisualisation(this)), overlay_(new VisualisationOverlay), selector_(new VisualisationSelector(this)), overlay_proxy_(nullptr), menu_(new QMenu(this)), fps_(kDefaultFps), size_(kDefaultTextureSize) { QSettings s; s.beginGroup(kSettingsGroup); if (!restoreGeometry(s.value("geometry").toByteArray())) { resize(kDefaultWidth, kDefaultHeight); } fps_ = s.value("fps", kDefaultFps).toInt(); size_ = s.value("size", kDefaultTextureSize).toInt(); QShortcut* close = new QShortcut(QKeySequence::Close, this); connect(close, SIGNAL(activated()), SLOT(close())); setMinimumSize(64, 64); } void VisualisationContainer::Init() { setWindowTitle(tr("Clementine Visualization")); setWindowIcon(QIcon(":/icon.png")); // Set up the graphics view setScene(vis_); setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); setViewportUpdateMode(QGraphicsView::FullViewportUpdate); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setFrameStyle(QFrame::NoFrame); // Add the overlay overlay_proxy_ = scene()->addWidget(overlay_); connect(overlay_, SIGNAL(OpacityChanged(qreal)), SLOT(ChangeOverlayOpacity(qreal))); connect(overlay_, SIGNAL(ShowPopupMenu(QPoint)), SLOT(ShowPopupMenu(QPoint))); ChangeOverlayOpacity(0.0); vis_->SetTextureSize(size_); SizeChanged(); // Selector selector_->SetVisualisation(vis_); // Settings menu menu_->addAction(IconLoader::Load("view-fullscreen", IconLoader::Base), tr("Toggle fullscreen"), this, SLOT(ToggleFullscreen())); QMenu* fps_menu = menu_->addMenu(tr("Framerate")); QActionGroup* fps_group = new QActionGroup(this); AddFramerateMenuItem(tr("Low (%1 fps)").arg(kLowFramerate), kLowFramerate, fps_, fps_group); AddFramerateMenuItem(tr("Medium (%1 fps)").arg(kMediumFramerate), kMediumFramerate, fps_, fps_group); AddFramerateMenuItem(tr("High (%1 fps)").arg(kHighFramerate), kHighFramerate, fps_, fps_group); AddFramerateMenuItem(tr("Super high (%1 fps)").arg(kSuperHighFramerate), kSuperHighFramerate, fps_, fps_group); fps_menu->addActions(fps_group->actions()); QMenu* quality_menu = menu_->addMenu(tr("Quality", "Visualisation quality")); QActionGroup* quality_group = new QActionGroup(this); AddQualityMenuItem(tr("Low (256x256)"), 256, size_, quality_group); AddQualityMenuItem(tr("Medium (512x512)"), 512, size_, quality_group); AddQualityMenuItem(tr("High (1024x1024)"), 1024, size_, quality_group); AddQualityMenuItem(tr("Super high (2048x2048)"), 2048, size_, quality_group); quality_menu->addActions(quality_group->actions()); menu_->addAction(tr("Select visualizations..."), selector_, SLOT(show())); menu_->addSeparator(); menu_->addAction(IconLoader::Load("application-exit", IconLoader::Base), tr("Close visualization"), this, SLOT(hide())); } void VisualisationContainer::AddFramerateMenuItem(const QString& name, int value, int def, QActionGroup* group) { QAction* action = group->addAction(name); action->setCheckable(true); action->setChecked(value == def); connect(action, &QAction::triggered, [this, value]() { SetFps(value); }); } void VisualisationContainer::AddQualityMenuItem(const QString& name, int value, int def, QActionGroup* group) { QAction* action = group->addAction(name); action->setCheckable(true); action->setChecked(value == def); connect(action, &QAction::triggered, [this, value]() { SetQuality(value); }); } void VisualisationContainer::SetEngine(GstEngine* engine) { engine_ = engine; if (isVisible()) engine_->AddBufferConsumer(vis_); } void VisualisationContainer::showEvent(QShowEvent* e) { qLog(Debug) << "Showing visualization"; if (!initialised_) { if (!QGLFormat::hasOpenGL()) { hide(); QMessageBox::warning(this, tr("Clementine Visualization"), tr("Your system is missing OpenGL support, " "visualizations are unavailable."), QMessageBox::Close); return; } Init(); initialised_ = true; } QGraphicsView::showEvent(e); update_timer_.start(1000 / fps_, this); if (engine_) engine_->AddBufferConsumer(vis_); } void VisualisationContainer::hideEvent(QHideEvent* e) { qLog(Debug) << "Hiding visualization"; QGraphicsView::hideEvent(e); update_timer_.stop(); if (engine_) engine_->RemoveBufferConsumer(vis_); } void VisualisationContainer::closeEvent(QCloseEvent* e) { // Don't close the window. Just hide it. e->ignore(); hide(); } void VisualisationContainer::resizeEvent(QResizeEvent* e) { QGraphicsView::resizeEvent(e); SizeChanged(); } void VisualisationContainer::SizeChanged() { // Save the geometry QSettings s; s.beginGroup(kSettingsGroup); s.setValue("geometry", saveGeometry()); // Resize the scene if (scene()) scene()->setSceneRect(QRect(QPoint(0, 0), size())); // Resize the overlay if (overlay_) overlay_->resize(size()); } void VisualisationContainer::timerEvent(QTimerEvent* e) { QGraphicsView::timerEvent(e); if (e->timerId() == update_timer_.timerId()) scene()->update(); } void VisualisationContainer::SetActions(QAction* previous, QAction* play_pause, QAction* stop, QAction* next) { overlay_->SetActions(previous, play_pause, stop, next); } void VisualisationContainer::SongMetadataChanged(const Song& metadata) { overlay_->SetSongTitle( QString("%1 - %2").arg(metadata.artist(), metadata.title())); } void VisualisationContainer::Stopped() { overlay_->SetSongTitle(tr("Clementine")); } void VisualisationContainer::ChangeOverlayOpacity(qreal value) { overlay_proxy_->setOpacity(value); // Hide the cursor if the overlay is hidden if (value < 0.5) viewport()->setCursor(Qt::BlankCursor); else viewport()->unsetCursor(); } void VisualisationContainer::enterEvent(QEvent* e) { QGraphicsView::enterEvent(e); overlay_->SetVisible(true); } void VisualisationContainer::leaveEvent(QEvent* e) { QGraphicsView::leaveEvent(e); overlay_->SetVisible(false); } void VisualisationContainer::mouseMoveEvent(QMouseEvent* e) { QGraphicsView::mouseMoveEvent(e); overlay_->SetVisible(true); } void VisualisationContainer::mouseDoubleClickEvent(QMouseEvent* e) { QGraphicsView::mouseDoubleClickEvent(e); ToggleFullscreen(); } void VisualisationContainer::contextMenuEvent(QContextMenuEvent* event) { QGraphicsView::contextMenuEvent(event); ShowPopupMenu(event->pos()); } void VisualisationContainer::keyReleaseEvent(QKeyEvent* event) { if (event->matches(QKeySequence::Close) || event->key() == Qt::Key_Escape) { if (isFullScreen()) ToggleFullscreen(); else hide(); return; } QGraphicsView::keyReleaseEvent(event); } void VisualisationContainer::ToggleFullscreen() { setWindowState(windowState() ^ Qt::WindowFullScreen); Screensaver* screensaver = Screensaver::GetScreensaver(); if (screensaver) isFullScreen() ? screensaver->Inhibit() : screensaver->Uninhibit(); } void VisualisationContainer::SetFps(int fps) { fps_ = fps; // Save settings QSettings s; s.beginGroup(kSettingsGroup); s.setValue("fps", fps_); update_timer_.stop(); update_timer_.start(1000 / fps_, this); } void VisualisationContainer::ShowPopupMenu(const QPoint& pos) { menu_->popup(mapToGlobal(pos)); } void VisualisationContainer::SetQuality(int size) { size_ = size; // Save settings QSettings s; s.beginGroup(kSettingsGroup); s.setValue("size", size_); vis_->SetTextureSize(size_); }