From 060c3b088304a20b92b49824cb174316890167de Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Wed, 22 Feb 2023 10:41:17 -0800 Subject: [PATCH] viewersizer: use float for all calculations, center manual zoom --- app/widget/viewer/viewer.cpp | 9 ++-- app/widget/viewer/viewersizer.cpp | 73 ++++++++++++++++++++----------- app/widget/viewer/viewersizer.h | 15 ++++--- 3 files changed, 62 insertions(+), 35 deletions(-) diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 791e0454a..70e973ddd 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -1376,10 +1376,10 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos) Menu* zoom_menu = new Menu(tr("Zoom"), &menu); menu.addMenu(zoom_menu); - zoom_menu->addAction(tr("Fit"))->setData(0); + zoom_menu->addAction(tr("Fit"))->setData(-1); for (int i=0;iaddAction(tr("%1%").arg(z))->setData(z); + double z = ViewerSizer::kZoomLevels[i]; + zoom_menu->addAction(tr("%1%").arg(z * 100.0))->setData(z); } connect(zoom_menu, &QMenu::triggered, this, &ViewerWidget::SetZoomFromMenu); @@ -1822,7 +1822,8 @@ void ViewerWidget::UpdateRendererAudioParameters() void ViewerWidget::SetZoomFromMenu(QAction *action) { - sizer_->SetZoom(action->data().toInt()); + auto s = sizer_->GetContainerSize(); + sizer_->SetZoomAnchored(action->data().toDouble(), s.width()/2, s.height()/2); } void ViewerWidget::ViewerInvalidatedVideoRange(const TimeRange &range) diff --git a/app/widget/viewer/viewersizer.cpp b/app/widget/viewer/viewersizer.cpp index 51be32d62..86f4c6079 100644 --- a/app/widget/viewer/viewersizer.cpp +++ b/app/widget/viewer/viewersizer.cpp @@ -35,7 +35,7 @@ ViewerSizer::ViewerSizer(QWidget *parent) : width_(0), height_(0), pixel_aspect_(1), - zoom_(0), + zoom_(-1), current_widget_scale_(0) { horiz_scrollbar_ = new QScrollBar(Qt::Horizontal, this); @@ -64,6 +64,12 @@ void ViewerSizer::SetWidget(QWidget *widget) } } +QSize ViewerSizer::GetContainerSize() const +{ + double s = GetRealCurrentZoom(); + return QSize(std::min(this->width(), int(width_ * s)) - vert_scrollbar_->width(), std::min(int(height_ * s), this->height()) - horiz_scrollbar_->height()); +} + void ViewerSizer::SetChildSize(int width, int height) { width_ = width; @@ -79,13 +85,36 @@ void ViewerSizer::SetPixelAspectRatio(const rational &pixel_aspect) UpdateSize(); } -void ViewerSizer::SetZoom(int percent) +void ViewerSizer::SetZoom(double percent) { zoom_ = percent; UpdateSize(); } +void ViewerSizer::SetZoomAnchored(double next_scale, double cursor_x, double cursor_y) +{ + if (next_scale > 0) { + double cur_scale = GetRealCurrentZoom(); + + // Clamp scale within safe values + next_scale = std::clamp(next_scale, kZoomLevels[0], kZoomLevels[kZoomLevelCount-1]); + + int anchor_x = qRound(double(cursor_x + horiz_scrollbar_->value()) / cur_scale * next_scale - cursor_x); + int anchor_y = qRound(double(cursor_y + vert_scrollbar_->value()) / cur_scale * next_scale - cursor_y); + + SetZoom(next_scale); + + horiz_scrollbar_->setValue(anchor_x); + vert_scrollbar_->setValue(anchor_y); + } else { + SetZoom(-1); + + horiz_scrollbar_->setValue(0); + vert_scrollbar_->setValue(0); + } +} + void ViewerSizer::HandDragMove(int x, int y) { if (horiz_scrollbar_->isVisible()) { @@ -104,28 +133,9 @@ bool ViewerSizer::eventFilter(QObject *watched, QEvent *event) QWheelEvent *w = static_cast(event); if (HandMovableView::WheelEventIsAZoomEvent(w)) { - int current_percent = zoom_; - if (current_percent == 0) { - // Currently set to "fit" - current_percent = current_widget_scale_; - } - - double cur_scale = current_percent * 0.01; - - current_percent *= HandMovableView::GetScrollZoomMultiplier(w); - current_percent = std::clamp(current_percent, kZoomLevels[0], kZoomLevels[kZoomLevelCount-1]); - - double next_scale = current_percent * 0.01; - + double next_scale = GetRealCurrentZoom() * HandMovableView::GetScrollZoomMultiplier(w); QPointF cursor_pos = w->position(); - - int anchor_x = qRound(double(cursor_pos.x() + horiz_scrollbar_->value()) / cur_scale * next_scale - cursor_pos.x()); - int anchor_y = qRound(double(cursor_pos.y() + vert_scrollbar_->value()) / cur_scale * next_scale - cursor_pos.y()); - - SetZoom(current_percent); - - horiz_scrollbar_->setValue(anchor_x); - vert_scrollbar_->setValue(anchor_y); + SetZoomAnchored(next_scale, cursor_pos.x(), cursor_pos.y()); } else { // Pass scroll values to scrollbars QPoint p = w->pixelDelta(); @@ -218,12 +228,12 @@ void ViewerSizer::UpdateSize() } - current_widget_scale_ = current_scale * 100; + current_widget_scale_ = current_scale; if (zoom_ > 0) { // Scale to get to the requested zoom - double zoom_diff = (zoom_ * 0.01) / current_scale; + double zoom_diff = zoom_ / current_scale; child_matrix.scale(zoom_diff, zoom_diff, 1.0); } @@ -235,7 +245,18 @@ void ViewerSizer::UpdateSize() int ViewerSizer::GetZoomedValue(int value) { - return qRound(value * static_cast(zoom_) * 0.01); + return qRound(value * zoom_); +} + +double ViewerSizer::GetRealCurrentZoom() const +{ + if (zoom_ < 0) { + // Currently set to "fit" + return current_widget_scale_; + } else { + // Explicit zoom set + return zoom_; + } } void ViewerSizer::ScrollBarMoved() diff --git a/app/widget/viewer/viewersizer.h b/app/widget/viewer/viewersizer.h index 90157be6d..189e99a27 100644 --- a/app/widget/viewer/viewersizer.h +++ b/app/widget/viewer/viewersizer.h @@ -51,8 +51,10 @@ public: */ void SetWidget(QWidget* widget); - static constexpr int kZoomLevelCount = 8; - static constexpr int kZoomLevels[kZoomLevelCount] = {10, 25, 50, 75, 100, 150, 200, 400}; + QSize GetContainerSize() const; + + static constexpr int kZoomLevelCount = 10; + static constexpr double kZoomLevels[kZoomLevelCount] = {0.05, 0.1, 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 4.0, 8.0}; public slots: /** @@ -72,7 +74,8 @@ public slots: * * The number is an integer percentage (100 = 100%). Set to 0 to auto-fit. */ - void SetZoom(int percent); + void SetZoom(double percent); + void SetZoomAnchored(double percent, double cursor_x, double cursor_y); void HandDragMove(int x, int y); @@ -97,6 +100,8 @@ private: int GetZoomedValue(int value); + double GetRealCurrentZoom() const; + /** * @brief Reference to widget * @@ -115,8 +120,8 @@ private: /** * @brief Internal zoom value */ - int zoom_; - int current_widget_scale_; + double zoom_; + double current_widget_scale_; QScrollBar* horiz_scrollbar_; QScrollBar* vert_scrollbar_;