diff --git a/app/panel/viewer/viewerbase.cpp b/app/panel/viewer/viewerbase.cpp index 5918894f4..50733e94f 100644 --- a/app/panel/viewer/viewerbase.cpp +++ b/app/panel/viewer/viewerbase.cpp @@ -53,3 +53,8 @@ void ViewerPanelBase::ConnectPixelSamplerPanel(PixelSamplerPanel *psp) connect(psp, &PixelSamplerPanel::visibilityChanged, vw, &ViewerWidget::SetSignalCursorColorEnabled); connect(vw, &ViewerWidget::CursorColor, psp, &PixelSamplerPanel::SetValues); } + +void ViewerPanelBase::SetFullScreen(QScreen *screen) +{ + static_cast(GetTimeBasedWidget())->SetFullScreen(screen); +} diff --git a/app/panel/viewer/viewerbase.h b/app/panel/viewer/viewerbase.h index d3c3f1c98..ac2d9d7b8 100644 --- a/app/panel/viewer/viewerbase.h +++ b/app/panel/viewer/viewerbase.h @@ -27,6 +27,11 @@ public: void ConnectPixelSamplerPanel(PixelSamplerPanel *psp); + /** + * @brief Wrapper for ViewerWidget::SetFullScreen() + */ + void SetFullScreen(QScreen* screen = nullptr); + }; #endif // VIEWERPANELBASE_H diff --git a/app/widget/menu/menu.cpp b/app/widget/menu/menu.cpp index 78db32654..66883bbf4 100644 --- a/app/widget/menu/menu.cpp +++ b/app/widget/menu/menu.cpp @@ -116,6 +116,9 @@ void Menu::ConformItem(QAction* a, const QString &id, const QObject *receiver, c if (!key.isEmpty()) { a->setShortcut(key); a->setProperty("keydefault", key); + + // Set to application context so that ViewerWindows still trigger shortcuts + a->setShortcutContext(Qt::ApplicationShortcut); } if (receiver != nullptr) { diff --git a/app/widget/viewer/CMakeLists.txt b/app/widget/viewer/CMakeLists.txt index 44bcbbb54..d010f11d8 100644 --- a/app/widget/viewer/CMakeLists.txt +++ b/app/widget/viewer/CMakeLists.txt @@ -28,5 +28,7 @@ set(OLIVE_SOURCES widget/viewer/viewerglwidget.cpp widget/viewer/viewersizer.h widget/viewer/viewersizer.cpp + widget/viewer/viewerwindow.h + widget/viewer/viewerwindow.cpp PARENT_SCOPE ) diff --git a/app/widget/viewer/footageviewer.cpp b/app/widget/viewer/footageviewer.cpp index 706e63dc5..b1a8821d1 100644 --- a/app/widget/viewer/footageviewer.cpp +++ b/app/widget/viewer/footageviewer.cpp @@ -13,7 +13,7 @@ FootageViewerWidget::FootageViewerWidget(QWidget *parent) : audio_node_ = new AudioInput(); viewer_node_ = new ViewerOutput(); - connect(gl_widget_, &ViewerGLWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag); + connect(main_gl_widget(), &ViewerGLWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag); controls_->SetAudioVideoDragButtonsVisible(true); connect(controls_, &PlaybackControls::VideoPressed, this, &FootageViewerWidget::StartVideoDrag); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index d1f855a2a..25248f95e 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -21,8 +21,10 @@ #include "viewer.h" #include +#include #include #include +#include #include #include @@ -55,11 +57,12 @@ ViewerWidget::ViewerWidget(QWidget *parent) : sizer_ = new ViewerSizer(); stack_->addWidget(sizer_); - gl_widget_ = new ViewerGLWidget(); - connect(gl_widget_, &ViewerGLWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu); - connect(gl_widget_, &ViewerGLWidget::CursorColor, this, &ViewerWidget::CursorColor); - connect(sizer_, &ViewerSizer::RequestMatrix, gl_widget_, &ViewerGLWidget::SetMatrix); - sizer_->SetWidget(gl_widget_); + ViewerGLWidget* main_widget = new ViewerGLWidget(); + connect(main_widget, &ViewerGLWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu); + connect(main_widget, &ViewerGLWidget::CursorColor, this, &ViewerWidget::CursorColor); + connect(sizer_, &ViewerSizer::RequestMatrix, main_widget, &ViewerGLWidget::SetMatrix); + sizer_->SetWidget(main_widget); + gl_widgets_.append(main_widget); // Create waveform view when audio is connected and video isn't waveform_view_ = new AudioWaveformView(); @@ -145,12 +148,18 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n) SizeChangedSlot(n->video_params().width(), n->video_params().height()); LengthChangedSlot(n->Length()); + ColorManager* using_manager; if (override_color_manager_) { - gl_widget_->ConnectColorManager(override_color_manager_); + using_manager = override_color_manager_; } else if (n->parent()) { - gl_widget_->ConnectColorManager(static_cast(n->parent())->project()->color_manager()); + using_manager = static_cast(n->parent())->project()->color_manager(); } else { qWarning() << "Failed to find a suitable color manager for the connected viewer node"; + using_manager = nullptr; + } + + foreach (ViewerGLWidget* glw, gl_widgets_) { + glw->ConnectColorManager(using_manager); } divider_ = CalculateDivider(); @@ -181,7 +190,9 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n) // Effectively disables the viewer and clears the state SizeChangedSlot(0, 0); - gl_widget_->DisconnectColorManager(); + foreach (ViewerGLWidget* glw, gl_widgets_) { + glw->DisconnectColorManager(); + } waveform_view_->ConnectTimelinePoints(nullptr); } @@ -213,6 +224,16 @@ void ViewerWidget::resizeEvent(QResizeEvent *event) UpdateMinimumScale(); } +const QList &ViewerWidget::gl_widgets() const +{ + return gl_widgets_; +} + +ViewerGLWidget *ViewerWidget::main_gl_widget() const +{ + return gl_widgets_.first(); +} + void ViewerWidget::TogglePlayPause() { if (IsPlaying()) { @@ -249,7 +270,43 @@ void ViewerWidget::SetOverrideSize(int width, int height) void ViewerWidget::SetMatrix(const QMatrix4x4 &mat) { - gl_widget_->SetMatrix(mat); + foreach (ViewerGLWidget* glw, gl_widgets_) { + glw->SetMatrix(mat); + } +} + +void ViewerWidget::SetFullScreen(QScreen *screen) +{ + if (!screen) { + // Try to find the screen that contains the mouse cursor currently + foreach (QScreen* test, QGuiApplication::screens()) { + if (test->geometry().contains(QCursor::pos())) { + screen = test; + break; + } + } + + // Fallback, just use the first screen + if (!screen) { + screen = QGuiApplication::screens().first(); + } + } + + ViewerWindow* vw = new ViewerWindow(this); + + vw->showFullScreen(); + vw->setGeometry(screen->geometry()); + vw->gl_widget()->ConnectColorManager(main_gl_widget()->color_manager()); + main_gl_widget()->ConnectSibling(vw->gl_widget()); + connect(vw, &ViewerWindow::destroyed, this, &ViewerWidget::WindowAboutToClose); + connect(vw->gl_widget(), &ViewerGLWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu); + + if (GetConnectedNode()) { + vw->SetResolution(GetConnectedNode()->video_params().width(), GetConnectedNode()->video_params().height()); + } + + windows_.append(vw); + gl_widgets_.append(vw->gl_widget()); } VideoRenderBackend *ViewerWidget::video_renderer() const @@ -260,12 +317,12 @@ VideoRenderBackend *ViewerWidget::video_renderer() const void ViewerWidget::UpdateTextureFromNode(const rational& time) { if (!GetConnectedNode() || time >= GetConnectedNode()->Length()) { - gl_widget_->SetImage(QString()); + main_gl_widget()->SetImage(QString()); } else { QString frame_fn = video_renderer_->GetCachedFrame(time); if (!frame_fn.isEmpty()) { - gl_widget_->SetImage(frame_fn); + main_gl_widget()->SetImage(frame_fn); } } } @@ -294,7 +351,7 @@ void ViewerWidget::PlayInternal(int speed) controls_->ShowPauseButton(); if (stack_->currentWidget() == sizer_) { - connect(gl_widget_, &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate); + connect(main_gl_widget(), &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate); } else { connect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate); } @@ -325,7 +382,7 @@ int ViewerWidget::CalculateDivider() { if (GetConnectedNode() && Config::Current()["AutoSelectDivider"].toBool()) { int long_side_of_video = qMax(GetConnectedNode()->video_params().width(), GetConnectedNode()->video_params().height()); - int long_side_of_widget = qMax(gl_widget_->width(), gl_widget_->height()); + int long_side_of_widget = qMax(main_gl_widget()->width(), main_gl_widget()->height()); return qMax(1, long_side_of_video / long_side_of_widget); } @@ -356,6 +413,19 @@ void ViewerWidget::UpdateStack() } } +void ViewerWidget::ContextMenuSetFullScreen(QAction *action) +{ + SetFullScreen(QGuiApplication::screens().at(action->data().toInt())); +} + +void ViewerWidget::WindowAboutToClose() +{ + ViewerWindow* vw = static_cast(sender()); + + windows_.removeAll(vw); + gl_widgets_.removeAll(vw->gl_widget()); +} + void ViewerWidget::UpdateRendererParameters() { if (!GetConnectedNode()) { @@ -385,40 +455,42 @@ void ViewerWidget::UpdateRendererParameters() void ViewerWidget::ShowContextMenu(const QPoint &pos) { - QMenu menu(this); + QMenu menu(static_cast(sender())); + + context_menu_widget_ = static_cast(sender()); // Color options - if (gl_widget_->color_manager() && color_menu_enabled_) { - QStringList displays = gl_widget_->color_manager()->ListAvailableDisplays(); + if (context_menu_widget_->color_manager() && color_menu_enabled_) { + QStringList displays = context_menu_widget_->color_manager()->ListAvailableDisplays(); QMenu* ocio_display_menu = menu.addMenu(tr("Display")); - connect(ocio_display_menu, &QMenu::triggered, this, &ViewerWidget::ColorDisplayChanged); + connect(ocio_display_menu, &QMenu::triggered, this, &ViewerWidget::ContextMenuOCIODisplay); foreach (const QString& d, displays) { QAction* action = ocio_display_menu->addAction(d); action->setCheckable(true); - action->setChecked(gl_widget_->ocio_display() == d); + action->setChecked(context_menu_widget_->ocio_display() == d); action->setData(d); } - QStringList views = gl_widget_->color_manager()->ListAvailableViews(gl_widget_->ocio_display()); + QStringList views = context_menu_widget_->color_manager()->ListAvailableViews(context_menu_widget_->ocio_display()); QMenu* ocio_view_menu = menu.addMenu(tr("View")); - connect(ocio_view_menu, &QMenu::triggered, this, &ViewerWidget::ColorViewChanged); + connect(ocio_view_menu, &QMenu::triggered, this, &ViewerWidget::ContextMenuOCIOView); foreach (const QString& v, views) { QAction* action = ocio_view_menu->addAction(v); action->setCheckable(true); - action->setChecked(gl_widget_->ocio_view() == v); + action->setChecked(context_menu_widget_->ocio_view() == v); action->setData(v); } - QStringList looks = gl_widget_->color_manager()->ListAvailableLooks(); + QStringList looks = context_menu_widget_->color_manager()->ListAvailableLooks(); QMenu* ocio_look_menu = menu.addMenu(tr("Look")); - connect(ocio_look_menu, &QMenu::triggered, this, &ViewerWidget::ColorLookChanged); + connect(ocio_look_menu, &QMenu::triggered, this, &ViewerWidget::ContextMenuOCIOLook); QAction* no_look_action = ocio_look_menu->addAction(tr("(None)")); no_look_action->setCheckable(true); - no_look_action->setChecked(gl_widget_->ocio_look().isEmpty()); + no_look_action->setChecked(context_menu_widget_->ocio_look().isEmpty()); foreach (const QString& l, looks) { QAction* action = ocio_look_menu->addAction(l); action->setCheckable(true); - action->setChecked(gl_widget_->ocio_look() == l); + action->setChecked(context_menu_widget_->ocio_look() == l); action->setData(l); } @@ -434,6 +506,13 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos) } connect(playback_resolution_menu, &QMenu::triggered, this, &ViewerWidget::SetDividerFromMenu); + foreach (QAction* a, playback_resolution_menu->actions()) { + a->setCheckable(true); + if (a->data() == divider_) { + a->setChecked(true); + } + } + // Viewer Zoom Level QMenu* zoom_menu = menu.addMenu(tr("Zoom")); int zoom_levels[] = {10, 25, 50, 75, 100, 150, 200, 400}; @@ -443,12 +522,18 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos) } connect(zoom_menu, &QMenu::triggered, this, &ViewerWidget::SetZoomFromMenu); - foreach (QAction* a, playback_resolution_menu->actions()) { - a->setCheckable(true); - if (a->data() == divider_) { - a->setChecked(true); - } + // Full Screen Menu + QMenu* full_screen_menu = menu.addMenu(tr("Full Screen")); + for (int i=0;iaddAction(tr("Screen %1: %2x%3").arg(QString::number(i), + QString::number(s->size().width()), + QString::number(s->size().height()))); + + a->setData(i); } + connect(full_screen_menu, &QMenu::triggered, this, &ViewerWidget::ContextMenuSetFullScreen); menu.exec(static_cast(sender())->mapToGlobal(pos)); } @@ -466,7 +551,7 @@ void ViewerWidget::Pause() controls_->ShowPlayButton(); if (stack_->currentWidget() == sizer_) { - disconnect(gl_widget_, &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate); + disconnect(main_gl_widget(), &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate); } else { disconnect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate); } @@ -514,27 +599,49 @@ void ViewerWidget::ShuttleRight() void ViewerWidget::SetOCIOParameters(const QString &display, const QString &view, const QString &look) { - gl_widget_->SetOCIOParameters(display, view, look); + SetOCIOParameters(display, view, look, main_gl_widget()); +} + +void ViewerWidget::SetOCIOParameters(const QString &display, const QString &view, const QString &look, ViewerGLWidget* sender) +{ + sender->SetOCIOParameters(display, view, look); } void ViewerWidget::SetOCIODisplay(const QString &display) { - gl_widget_->SetOCIODisplay(display); + SetOCIODisplay(display, main_gl_widget()); +} + +void ViewerWidget::SetOCIODisplay(const QString &display, ViewerGLWidget* sender) +{ + sender->SetOCIODisplay(display); } void ViewerWidget::SetOCIOView(const QString &view) { - gl_widget_->SetOCIOView(view); + SetOCIOView(view, main_gl_widget()); } void ViewerWidget::SetOCIOLook(const QString &look) { - gl_widget_->SetOCIOLook(look); + SetOCIOLook(look, main_gl_widget()); +} + +void ViewerWidget::SetOCIOView(const QString &view, ViewerGLWidget* sender) +{ + sender->SetOCIOView(view); +} + +void ViewerWidget::SetOCIOLook(const QString &look, ViewerGLWidget* sender) +{ + sender->SetOCIOLook(look); } void ViewerWidget::SetSignalCursorColorEnabled(bool e) { - gl_widget_->SetSignalCursorColorEnabled(e); + foreach (ViewerGLWidget* glw, gl_widgets_) { + glw->SetSignalCursorColorEnabled(e); + } } void ViewerWidget::TimebaseChangedEvent(const rational &timebase) @@ -576,6 +683,10 @@ void ViewerWidget::RendererCachedTime(const rational &time, qint64 job_time) void ViewerWidget::SizeChangedSlot(int width, int height) { sizer_->SetChildSize(width, height); + + foreach (ViewerWindow* vw, windows_) { + vw->SetResolution(width, height); + } } void ViewerWidget::LengthChangedSlot(const rational &length) @@ -585,19 +696,19 @@ void ViewerWidget::LengthChangedSlot(const rational &length) UpdateMinimumScale(); } -void ViewerWidget::ColorDisplayChanged(QAction* action) +void ViewerWidget::ContextMenuOCIODisplay(QAction* action) { - SetOCIODisplay(action->data().toString()); + SetOCIODisplay(action->data().toString(), context_menu_widget_); } -void ViewerWidget::ColorViewChanged(QAction *action) +void ViewerWidget::ContextMenuOCIOView(QAction *action) { - SetOCIOView(action->data().toString()); + SetOCIOView(action->data().toString(), context_menu_widget_); } -void ViewerWidget::ColorLookChanged(QAction *action) +void ViewerWidget::ContextMenuOCIOLook(QAction *action) { - SetOCIOLook(action->data().toString()); + SetOCIOLook(action->data().toString(), context_menu_widget_); } void ViewerWidget::SetDividerFromMenu(QAction *action) diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 87a817966..3bf9650f9 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -36,6 +36,7 @@ #include "render/backend/audio/audiobackend.h" #include "viewerglwidget.h" #include "viewersizer.h" +#include "viewerwindow.h" #include "widget/playbackcontrols/playbackcontrols.h" #include "widget/timebased/timebased.h" @@ -70,6 +71,13 @@ public: void SetMatrix(const QMatrix4x4& mat); + /** + * @brief Creates a ViewerWindow widget and places it full screen on another screen + * + * If `screen` is nullptr, the screen will be automatically selected as whichever one contains the mouse cursor. + */ + void SetFullScreen(QScreen* screen = nullptr); + VideoRenderBackend* video_renderer() const; public slots: @@ -132,10 +140,11 @@ protected: OpenGLBackend* video_renderer_; AudioBackend* audio_renderer_; - ViewerGLWidget* gl_widget_; - PlaybackControls* controls_; + const QList &gl_widgets() const; + ViewerGLWidget* main_gl_widget() const; + private: void UpdateTimeInternal(int64_t i); @@ -149,6 +158,11 @@ private: void UpdateMinimumScale(); + void SetOCIOParameters(const QString& display, const QString& view, const QString& look, ViewerGLWidget* sender); + void SetOCIODisplay(const QString& display, ViewerGLWidget* sender); + void SetOCIOView(const QString& view, ViewerGLWidget* sender); + void SetOCIOLook(const QString& look, ViewerGLWidget* sender); + QStackedWidget* stack_; ViewerSizer* sizer_; @@ -172,6 +186,12 @@ private: AudioWaveformView* waveform_view_; + QList windows_; + + QList gl_widgets_; + + ViewerGLWidget* context_menu_widget_; + private slots: void PlaybackTimerUpdate(); @@ -188,17 +208,17 @@ private slots: /** * @brief Slot called whenever this viewer's OCIO display setting has changed */ - void ColorDisplayChanged(QAction* action); + void ContextMenuOCIODisplay(QAction* action); /** * @brief Slot called whenever this viewer's OCIO view setting has changed */ - void ColorViewChanged(QAction* action); + void ContextMenuOCIOView(QAction* action); /** * @brief Slot called whenever this viewer's OCIO look setting has changed */ - void ColorLookChanged(QAction* action); + void ContextMenuOCIOLook(QAction* action); void SetDividerFromMenu(QAction* action); @@ -208,6 +228,10 @@ private slots: void UpdateStack(); + void ContextMenuSetFullScreen(QAction* action); + + void WindowAboutToClose(); + }; #endif // VIEWER_WIDGET_H diff --git a/app/widget/viewer/viewerglwidget.cpp b/app/widget/viewer/viewerglwidget.cpp index c2b1f5db1..b58c7228d 100644 --- a/app/widget/viewer/viewerglwidget.cpp +++ b/app/widget/viewer/viewerglwidget.cpp @@ -114,6 +114,8 @@ void ViewerGLWidget::SetImage(const QString &fn) texture_.Upload(load_buffer_.data()); + emit LoadedBuffer(&load_buffer_); + doneCurrent(); has_image_ = true; @@ -128,12 +130,16 @@ void ViewerGLWidget::SetImage(const QString &fn) } update(); + + if (has_image_) { + emit LoadedBuffer(&load_buffer_); + } else { + emit LoadedBuffer(nullptr); + } } void ViewerGLWidget::SetSignalCursorColorEnabled(bool e) { - qDebug() << e; - signal_cursor_color_ = e; setMouseTracking(e); @@ -149,6 +155,28 @@ void ViewerGLWidget::SetSignalCursorColorEnabled(bool e) } } +void ViewerGLWidget::SetImageFromLoadBuffer(Frame *in_buffer) +{ + has_image_ = in_buffer; + + if (has_image_) { + makeCurrent(); + + if (!texture_.IsCreated() + || texture_.width() != in_buffer->width() + || texture_.height() != in_buffer->height() + || texture_.format() != in_buffer->format()) { + texture_.Create(context(), in_buffer->width(), in_buffer->height(), in_buffer->format(), in_buffer->data()); + } else { + texture_.Upload(in_buffer->data()); + } + + doneCurrent(); + } + + update(); +} + void ViewerGLWidget::SetOCIODisplay(const QString &display) { ocio_display_ = display; @@ -198,6 +226,12 @@ const QString &ViewerGLWidget::ocio_look() const return ocio_look_; } +void ViewerGLWidget::ConnectSibling(ViewerGLWidget *sibling) +{ + connect(this, &ViewerGLWidget::LoadedBuffer, sibling, &ViewerGLWidget::SetImageFromLoadBuffer, Qt::QueuedConnection); + sibling->SetImageFromLoadBuffer(&load_buffer_); +} + void ViewerGLWidget::mousePressEvent(QMouseEvent *event) { QOpenGLWidget::mousePressEvent(event); diff --git a/app/widget/viewer/viewerglwidget.h b/app/widget/viewer/viewerglwidget.h index 2110b236e..2fbf05b1d 100644 --- a/app/widget/viewer/viewerglwidget.h +++ b/app/widget/viewer/viewerglwidget.h @@ -81,6 +81,10 @@ public: const QString& ocio_view() const; const QString& ocio_look() const; + const QMatrix4x4& GetMatrix(); + + void ConnectSibling(ViewerGLWidget* sibling); + public slots: /** * @brief Set the texture to draw and draw it @@ -130,6 +134,14 @@ public slots: */ void SetSignalCursorColorEnabled(bool e); + /** + * @brief Overrides the image with the load buffer of another ViewerGLWidget + * + * If there are multiple ViewerGLWidgets showing the same thing, this is faster than decoding the image from file + * each time. + */ + void SetImageFromLoadBuffer(Frame* in_buffer); + signals: /** * @brief Signal emitted when the user starts dragging from the viewer @@ -141,6 +153,11 @@ signals: */ void CursorColor(const Color& reference, const Color& display); + /** + * @brief Connect this to the SetImageFromLoadBuffer() slot of another ViewerGLWidget to show the same thing + */ + void LoadedBuffer(Frame* load_buffer); + protected: /** * @brief Override the mouse press event simply to emit the DragStarted() signal diff --git a/app/widget/viewer/viewerwindow.cpp b/app/widget/viewer/viewerwindow.cpp new file mode 100644 index 000000000..b66b9b088 --- /dev/null +++ b/app/widget/viewer/viewerwindow.cpp @@ -0,0 +1,55 @@ +#include "viewerwindow.h" + +#include +#include + +ViewerWindow::ViewerWindow(QWidget *parent) : + QWidget(parent, Qt::Window | Qt::WindowStaysOnTopHint) +{ + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(0); + + gl_widget_ = new ViewerGLWidget(); + layout->addWidget(gl_widget_); +} + +ViewerGLWidget *ViewerWindow::gl_widget() const +{ + return gl_widget_; +} + +void ViewerWindow::SetResolution(int width, int height) +{ + // Set GL widget matrix to maintain this texture's aspect ratio + double window_ar = static_cast(this->width()) / static_cast(this->height()); + double image_ar = static_cast(width) / static_cast(height); + + QMatrix4x4 mat; + + if (window_ar > image_ar) { + // Window is wider than image, adjust X scale + mat.scale(image_ar / window_ar, 1.0f, 1.0f); + } else if (window_ar < image_ar) { + // Window is taller than image, adjust Y scale + mat.scale(1.0f, window_ar / image_ar, 1.0f); + } + + gl_widget_->SetMatrix(mat); +} + +void ViewerWindow::keyPressEvent(QKeyEvent *e) +{ + QWidget::keyPressEvent(e); + + if (e->key() == Qt::Key_Escape) { + close(); + } +} + +void ViewerWindow::closeEvent(QCloseEvent *e) +{ + QWidget::closeEvent(e); + + deleteLater(); +} diff --git a/app/widget/viewer/viewerwindow.h b/app/widget/viewer/viewerwindow.h new file mode 100644 index 000000000..8ad17229b --- /dev/null +++ b/app/widget/viewer/viewerwindow.h @@ -0,0 +1,30 @@ +#ifndef VIEWERWINDOW_H +#define VIEWERWINDOW_H + +#include + +#include "viewerglwidget.h" + +class ViewerWindow : public QWidget +{ +public: + ViewerWindow(QWidget* parent = nullptr); + + ViewerGLWidget* gl_widget() const; + + /** + * @brief Used to adjust resulting picture to be the right aspect ratio + */ + void SetResolution(int width, int height); + +protected: + virtual void keyPressEvent(QKeyEvent* e) override; + + virtual void closeEvent(QCloseEvent* e) override; + +private: + ViewerGLWidget* gl_widget_; + +}; + +#endif // VIEWERWINDOW_H diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp index 1034fe378..8e66bffe4 100644 --- a/app/window/mainwindow/mainmenu.cpp +++ b/app/window/mainwindow/mainmenu.cpp @@ -164,7 +164,7 @@ MainMenu::MainMenu(QMainWindow *parent) : view_full_screen_item_ = view_menu_->AddItem("fullscreen", parent, SLOT(SetFullscreen(bool)), "F11"); view_full_screen_item_->setCheckable(true); - view_full_screen_viewer_item_ = view_menu_->AddItem("fullscreenviewer", nullptr, nullptr); + view_full_screen_viewer_item_ = view_menu_->AddItem("fullscreenviewer", this, SLOT(FullScreenViewerTriggered())); // // PLAYBACK MENU @@ -509,6 +509,11 @@ void MainMenu::SetMarkerTriggered() PanelManager::instance()->CurrentlyFocused()->SetMarker(); } +void MainMenu::FullScreenViewerTriggered() +{ + PanelManager::instance()->MostRecentlyFocused()->SetFullScreen(); +} + void MainMenu::Retranslate() { // MenuShared is not a QWidget and therefore does not receive a LanguageEvent, we use MainMenu's to update it diff --git a/app/window/mainwindow/mainmenu.h b/app/window/mainwindow/mainmenu.h index d45b0818a..bc70bed3c 100644 --- a/app/window/mainwindow/mainmenu.h +++ b/app/window/mainwindow/mainmenu.h @@ -142,6 +142,8 @@ private slots: void SetMarkerTriggered(); + void FullScreenViewerTriggered(); + private: /** * @brief Set strings based on the current application language.