viewer: implemented basic zoom

No scrolling functionality yet, but the zoom is functional and efficient.
This commit is contained in:
itsmattkc
2020-03-13 16:41:09 +11:00
parent 0418c8ab85
commit c1c8067ee7
5 changed files with 113 additions and 33 deletions
+21 -7
View File
@@ -57,11 +57,11 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
gl_widget_ = new ViewerGLWidget(); gl_widget_ = new ViewerGLWidget();
connect(gl_widget_, &ViewerGLWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu); connect(gl_widget_, &ViewerGLWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
connect(sizer_, &ViewerSizer::RequestMatrix, gl_widget_, &ViewerGLWidget::SetMatrix);
sizer_->SetWidget(gl_widget_); sizer_->SetWidget(gl_widget_);
// Create waveform view when audio is connected and video isn't // Create waveform view when audio is connected and video isn't
waveform_view_ = new WaveformView(); waveform_view_ = new WaveformView();
stack_->addWidget(waveform_view_); stack_->addWidget(waveform_view_);
// Create time ruler // Create time ruler
@@ -272,7 +272,7 @@ void ViewerWidget::PlayInternal(int speed)
controls_->ShowPauseButton(); controls_->ShowPauseButton();
if (stack_->currentWidget() == gl_widget_) { if (stack_->currentWidget() == sizer_) {
connect(gl_widget_, &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate); connect(gl_widget_, &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
} else { } else {
connect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate); connect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate);
@@ -315,7 +315,7 @@ int ViewerWidget::CalculateDivider()
void ViewerWidget::UpdateStack() void ViewerWidget::UpdateStack()
{ {
if (!GetConnectedNode() || GetConnectedNode()->texture_input()->IsConnected()) { if (!GetConnectedNode() || GetConnectedNode()->texture_input()->IsConnected()) {
stack_->setCurrentWidget(gl_widget_); stack_->setCurrentWidget(sizer_);
} else { } else {
stack_->setCurrentWidget(waveform_view_); stack_->setCurrentWidget(waveform_view_);
} }
@@ -393,12 +393,21 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos)
// Playback resolution // Playback resolution
QMenu* playback_resolution_menu = menu.addMenu(tr("Resolution")); QMenu* playback_resolution_menu = menu.addMenu(tr("Resolution"));
playback_resolution_menu->addAction(tr("Full"))->setData(1); playback_resolution_menu->addAction(tr("Full"))->setData(1);
playback_resolution_menu->addAction(tr("1/2"))->setData(2); int dividers[] = {2, 4, 8, 16};
playback_resolution_menu->addAction(tr("1/4"))->setData(4); for (int i=0;i<4;i++) {
playback_resolution_menu->addAction(tr("1/8"))->setData(8); playback_resolution_menu->addAction(tr("1/%1").arg(dividers[i]))->setData(dividers[i]);
playback_resolution_menu->addAction(tr("1/16"))->setData(16); }
connect(playback_resolution_menu, &QMenu::triggered, this, &ViewerWidget::SetDividerFromMenu); connect(playback_resolution_menu, &QMenu::triggered, this, &ViewerWidget::SetDividerFromMenu);
// Viewer Zoom Level
QMenu* zoom_menu = menu.addMenu(tr("Zoom"));
int zoom_levels[] = {10, 25, 50, 75, 100, 150, 200, 400};
zoom_menu->addAction(tr("Fit"))->setData(0);
for (int i=0;i<8;i++) {
zoom_menu->addAction(tr("%1%").arg(zoom_levels[i]))->setData(zoom_levels[i]);
}
connect(zoom_menu, &QMenu::triggered, this, &ViewerWidget::SetZoomFromMenu);
foreach (QAction* a, playback_resolution_menu->actions()) { foreach (QAction* a, playback_resolution_menu->actions()) {
a->setCheckable(true); a->setCheckable(true);
if (a->data() == divider_) { if (a->data() == divider_) {
@@ -564,6 +573,11 @@ void ViewerWidget::SetDividerFromMenu(QAction *action)
UpdateRendererParameters(); UpdateRendererParameters();
} }
void ViewerWidget::SetZoomFromMenu(QAction *action)
{
sizer_->SetZoom(action->data().toInt());
}
void ViewerWidget::InvalidateVisible() void ViewerWidget::InvalidateVisible()
{ {
video_renderer_->InvalidateCache(TimeRange(GetTime(), GetTime())); video_renderer_->InvalidateCache(TimeRange(GetTime(), GetTime()));
+2
View File
@@ -187,6 +187,8 @@ private slots:
void SetDividerFromMenu(QAction* action); void SetDividerFromMenu(QAction* action);
void SetZoomFromMenu(QAction* action);
void InvalidateVisible(); void InvalidateVisible();
void UpdateStack(); void UpdateStack();
+12 -12
View File
@@ -68,18 +68,17 @@ public:
*/ */
void DisconnectColorManager(); void DisconnectColorManager();
/**
* @brief Set the transformation matrix to draw with
*
* Set this if you want the drawing to pass through some sort of transform (most of the time you won't want this).
*/
void SetMatrix(const QMatrix4x4& mat);
/** /**
* @brief Set an image to load and display on screen * @brief Set an image to load and display on screen
*/ */
void SetImage(const QString& fn); void SetImage(const QString& fn);
ColorManager* color_manager() const;
const QString& ocio_display() const;
const QString& ocio_view() const;
const QString& ocio_look() const;
public slots: public slots:
/** /**
* @brief Set the texture to draw and draw it * @brief Set the texture to draw and draw it
@@ -113,11 +112,12 @@ public slots:
*/ */
void SetOCIOLook(const QString& look); void SetOCIOLook(const QString& look);
ColorManager* color_manager() const; /**
* @brief Set the transformation matrix to draw with
const QString& ocio_display() const; *
const QString& ocio_view() const; * Set this if you want the drawing to pass through some sort of transform (most of the time you won't want this).
const QString& ocio_look() const; */
void SetMatrix(const QMatrix4x4& mat);
signals: signals:
void DragStarted(); void DragStarted();
+57 -14
View File
@@ -1,9 +1,12 @@
#include "viewersizer.h" #include "viewersizer.h"
#include <QMatrix4x4>
ViewerSizer::ViewerSizer(QWidget *parent) : ViewerSizer::ViewerSizer(QWidget *parent) :
QWidget(parent), QWidget(parent),
widget_(nullptr), widget_(nullptr),
aspect_ratio_(0) aspect_ratio_(0),
zoom_(0)
{ {
} }
@@ -23,15 +26,25 @@ void ViewerSizer::SetWidget(QWidget *widget)
void ViewerSizer::SetChildSize(int width, int height) void ViewerSizer::SetChildSize(int width, int height)
{ {
if (height == 0) { width_ = width;
height_ = height;
if (!width_ || !height_) {
aspect_ratio_ = 0; aspect_ratio_ = 0;
} else { } else {
aspect_ratio_ = static_cast<double>(width) / static_cast<double>(height); aspect_ratio_ = static_cast<double>(width_) / static_cast<double>(height_);
} }
UpdateSize(); UpdateSize();
} }
void ViewerSizer::SetZoom(int percent)
{
zoom_ = percent;
UpdateSize();
}
void ViewerSizer::resizeEvent(QResizeEvent *event) void ViewerSizer::resizeEvent(QResizeEvent *event)
{ {
QWidget::resizeEvent(event); QWidget::resizeEvent(event);
@@ -53,21 +66,51 @@ void ViewerSizer::UpdateSize()
widget_->setVisible(true); widget_->setVisible(true);
double our_aspect_ratio = static_cast<double>(width()) / static_cast<double>(height()); QSize child_size;
QMatrix4x4 child_matrix;
QPoint child_pos; if (zoom_ <= 0) {
QSize child_size = size();
// If zoom is 0, we auto-fit
double our_aspect_ratio = static_cast<double>(width()) / static_cast<double>(height());
child_size = size();
if (our_aspect_ratio > aspect_ratio_) {
// This container is wider than the image, scale by height
child_size = QSize(qRound(child_size.height() * aspect_ratio_), height());
} else {
// This container is taller than the image, scale by width
child_size = QSize(width(), qRound(child_size.width() / aspect_ratio_));
}
if (our_aspect_ratio > aspect_ratio_) {
// This container is wider than the image, scale by height
child_size.setWidth(qRound(child_size.height() * aspect_ratio_));
child_pos.setX(width() / 2 - child_size.width() / 2);
} else { } else {
// This container is taller than the image, scale by width
child_size.setHeight(qRound(child_size.width() / aspect_ratio_)); float x_scale = 1.0f;
child_pos.setY(height() / 2 - child_size.height() / 2); float y_scale = 1.0f;
int zoomed_width = qRound(width_ * static_cast<double>(zoom_) * 0.01);
int zoomed_height = qRound(height_ * static_cast<double>(zoom_) * 0.01);
if (zoomed_width > width()) {
x_scale = static_cast<double>(zoomed_width) / static_cast<double>(width());
zoomed_width = width();
}
if (zoomed_height > height()) {
y_scale = static_cast<double>(zoomed_height) / static_cast<double>(height());
zoomed_height = height();
}
// Rather than make a huge surface, we still crop at our width/height and then signal a matrix
child_matrix.scale(x_scale, y_scale, 1.0F);
child_size = QSize(zoomed_width, zoomed_height);
} }
widget_->resize(child_size); widget_->resize(child_size);
widget_->move(child_pos); widget_->move(width() / 2 - child_size.width() / 2, height() / 2 - child_size.height() / 2);
emit RequestMatrix(child_matrix);
} }
+21
View File
@@ -52,6 +52,16 @@ public:
*/ */
void SetChildSize(int width, int height); void SetChildSize(int width, int height);
/**
* @brief Set the zoom value of the child widget
*
* The number is an integer percentage (100 = 100%). Set to 0 to auto-fit.
*/
void SetZoom(int percent);
signals:
void RequestMatrix(const QMatrix4x4& matrix);
protected: protected:
/** /**
* @brief Listen for resize events to ensure the child widget remains correctly sized * @brief Listen for resize events to ensure the child widget remains correctly sized
@@ -71,11 +81,22 @@ private:
*/ */
QWidget* widget_; QWidget* widget_;
/**
* @brief Internal resolution values
*/
int width_;
int height_;
/** /**
* @brief Aspect ratio calculated from the size provided by SetChildSize() * @brief Aspect ratio calculated from the size provided by SetChildSize()
*/ */
double aspect_ratio_; double aspect_ratio_;
/**
* @brief Internal zoom value
*/
int zoom_;
}; };
#endif // VIEWERSIZER_H #endif // VIEWERSIZER_H