259 lines
7.3 KiB
C++
259 lines
7.3 KiB
C++
/***
|
|
|
|
Olive - Non-Linear Video Editor
|
|
Copyright (C) 2019 Olive Team
|
|
|
|
This program 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.
|
|
|
|
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
#include "viewersizer.h"
|
|
|
|
#include <QMatrix4x4>
|
|
|
|
OLIVE_NAMESPACE_ENTER
|
|
|
|
ViewerSizer::ViewerSizer(QWidget *parent) :
|
|
QWidget(parent),
|
|
widget_(nullptr),
|
|
width_(0),
|
|
height_(0),
|
|
pixel_aspect_(1),
|
|
zoom_(0)
|
|
{
|
|
horiz_scrollbar_ = new QScrollBar(Qt::Horizontal, this);
|
|
horiz_scrollbar_->setVisible(false);
|
|
connect(horiz_scrollbar_, &QScrollBar::valueChanged, this, &ViewerSizer::ScrollBarMoved);
|
|
|
|
vert_scrollbar_ = new QScrollBar(Qt::Vertical, this);
|
|
vert_scrollbar_->setVisible(false);
|
|
connect(vert_scrollbar_, &QScrollBar::valueChanged, this, &ViewerSizer::ScrollBarMoved);
|
|
}
|
|
|
|
void ViewerSizer::SetWidget(QWidget *widget)
|
|
{
|
|
// Delete any previous widgets occupying this space
|
|
delete widget_;
|
|
|
|
widget_ = widget;
|
|
|
|
if (widget_ != nullptr) {
|
|
widget_->setParent(this);
|
|
|
|
UpdateSize();
|
|
}
|
|
}
|
|
|
|
void ViewerSizer::SetChildSize(int width, int height)
|
|
{
|
|
width_ = width;
|
|
height_ = height;
|
|
|
|
UpdateSize();
|
|
}
|
|
|
|
void ViewerSizer::SetPixelAspectRatio(const rational &pixel_aspect)
|
|
{
|
|
pixel_aspect_ = pixel_aspect;
|
|
|
|
UpdateSize();
|
|
}
|
|
|
|
void ViewerSizer::SetZoom(int percent)
|
|
{
|
|
zoom_ = percent;
|
|
|
|
UpdateSize();
|
|
}
|
|
|
|
void ViewerSizer::HandDragMove(int x, int y)
|
|
{
|
|
if (horiz_scrollbar_->isVisible()) {
|
|
horiz_scrollbar_->setValue(horiz_scrollbar_->value() - x);
|
|
}
|
|
|
|
if (vert_scrollbar_->isVisible()) {
|
|
vert_scrollbar_->setValue(vert_scrollbar_->value() - y);
|
|
}
|
|
}
|
|
|
|
void ViewerSizer::resizeEvent(QResizeEvent *event)
|
|
{
|
|
QWidget::resizeEvent(event);
|
|
|
|
UpdateSize();
|
|
}
|
|
|
|
void ViewerSizer::UpdateSize()
|
|
{
|
|
if (widget_ == nullptr) {
|
|
return;
|
|
}
|
|
|
|
// If the aspect ratio is 0, the widget is always hidden
|
|
if (!width_ || !height_) {
|
|
widget_->setVisible(false);
|
|
return;
|
|
}
|
|
|
|
widget_->setVisible(true);
|
|
|
|
QSize child_size;
|
|
QMatrix4x4 child_matrix;
|
|
|
|
int available_width = width();
|
|
int available_height = height();
|
|
double sequence_aspect_ratio = static_cast<double>(width_) / static_cast<double>(height_)
|
|
* pixel_aspect_.toDouble();
|
|
|
|
if (zoom_ <= 0) {
|
|
|
|
// If zoom is zero or negative, we auto-fit
|
|
double our_aspect_ratio = static_cast<double>(available_width) / static_cast<double>(available_height);
|
|
|
|
child_size = size();
|
|
|
|
if (our_aspect_ratio > sequence_aspect_ratio) {
|
|
// This container is wider than the image, scale by height
|
|
child_size = QSize(qRound(child_size.height() * sequence_aspect_ratio), available_height);
|
|
} else {
|
|
// This container is taller than the image, scale by width
|
|
child_size = QSize(available_width, qRound(child_size.width() / sequence_aspect_ratio));
|
|
}
|
|
|
|
// No scrollbars necessary for auto-fit
|
|
horiz_scrollbar_->setVisible(false);
|
|
vert_scrollbar_->setVisible(false);
|
|
|
|
} else {
|
|
|
|
float x_scale = 1.0f;
|
|
float y_scale = 1.0f;
|
|
|
|
int zoomed_width = GetZoomedValue(width_);
|
|
int zoomed_height = GetZoomedValue(height_);
|
|
|
|
bool child_exceeds_parent_width = (zoomed_width > available_width);
|
|
bool child_exceeds_parent_height = (zoomed_height > available_height);
|
|
|
|
if (child_exceeds_parent_width != child_exceeds_parent_height) {
|
|
// One scrollbar definitely needs to be shown, so it's a matter of determining if the other
|
|
// does too since adding one scrollbar necessary limits the total area
|
|
|
|
if (child_exceeds_parent_height) {
|
|
// A vertical scrollbar will need to be shown, which limits the width
|
|
child_exceeds_parent_width = (zoomed_width > available_width - vert_scrollbar_->sizeHint().width());
|
|
} else {
|
|
// A horizontal scrollbar will need to be shown, which limits the height
|
|
child_exceeds_parent_height = (zoomed_height > available_height - horiz_scrollbar_->sizeHint().height());
|
|
}
|
|
}
|
|
|
|
horiz_scrollbar_->setVisible(child_exceeds_parent_width);
|
|
vert_scrollbar_->setVisible(child_exceeds_parent_height);
|
|
|
|
if (vert_scrollbar_->isVisible()) {
|
|
// Limit available width for further calculations
|
|
available_width -= vert_scrollbar_->sizeHint().width();
|
|
}
|
|
|
|
if (horiz_scrollbar_->isVisible()) {
|
|
// Limit available height for further calculations
|
|
available_height -= horiz_scrollbar_->sizeHint().height();
|
|
}
|
|
|
|
if (horiz_scrollbar_->isVisible()) {
|
|
x_scale = static_cast<double>(zoomed_width) / static_cast<double>(available_width);
|
|
|
|
// Update scrollbar sizes
|
|
int horiz_width = this->width();
|
|
|
|
if (vert_scrollbar_->isVisible()) {
|
|
horiz_width -= vert_scrollbar_->sizeHint().width();
|
|
}
|
|
|
|
horiz_scrollbar_->resize(horiz_width, horiz_scrollbar_->sizeHint().height());
|
|
horiz_scrollbar_->move(0, this->height() - horiz_scrollbar_->height() - 1);
|
|
horiz_scrollbar_->setMaximum(zoomed_width - available_width);
|
|
horiz_scrollbar_->setPageStep(available_width);
|
|
|
|
zoomed_width = available_width;
|
|
}
|
|
|
|
if (vert_scrollbar_->isVisible()) {
|
|
y_scale = static_cast<double>(zoomed_height) / static_cast<double>(available_height);
|
|
|
|
// Update scrollbar sizes
|
|
int vert_height = this->height();
|
|
|
|
if (horiz_scrollbar_->isVisible()) {
|
|
vert_height -= horiz_scrollbar_->sizeHint().height();
|
|
}
|
|
|
|
vert_scrollbar_->resize(vert_scrollbar_->sizeHint().width(), vert_height);
|
|
vert_scrollbar_->move(this->width() - vert_scrollbar_->width() - 1, 0);
|
|
vert_scrollbar_->setMaximum(zoomed_height - available_height);
|
|
vert_scrollbar_->setPageStep(available_height);
|
|
|
|
zoomed_height = available_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_->move(available_width / 2 - child_size.width() / 2,
|
|
available_height / 2 - child_size.height() / 2);
|
|
|
|
emit RequestScale(child_matrix);
|
|
|
|
ScrollBarMoved();
|
|
}
|
|
|
|
int ViewerSizer::GetZoomedValue(int value)
|
|
{
|
|
return qRound(value * static_cast<double>(zoom_) * 0.01);
|
|
}
|
|
|
|
void ViewerSizer::ScrollBarMoved()
|
|
{
|
|
QMatrix4x4 mat;
|
|
|
|
float x_scroll, y_scroll;
|
|
|
|
if (horiz_scrollbar_->isVisible()) {
|
|
int zoomed_width = GetZoomedValue(width_);
|
|
x_scroll = (zoomed_width/2 - horiz_scrollbar_->value() - widget_->width() / 2) * (2.0 / zoomed_width);
|
|
} else {
|
|
x_scroll = 0;
|
|
}
|
|
|
|
if (vert_scrollbar_->isVisible()) {
|
|
int zoomed_height = GetZoomedValue(height_);
|
|
y_scroll = (zoomed_height/2 - vert_scrollbar_->value() - widget_->height() / 2) * (2.0 / zoomed_height);
|
|
} else {
|
|
y_scroll = 0;
|
|
}
|
|
|
|
// Zero translate is centered, so we need to determine how much "off center" we are
|
|
mat.translate(x_scroll, y_scroll);
|
|
|
|
emit RequestTranslate(mat);
|
|
}
|
|
|
|
OLIVE_NAMESPACE_EXIT
|