Files
oak-editor/app/widget/viewer/viewersizer.cpp
T
itsmattkc 75d4cd899b use hardcoded namespace
The macro defined namespaces confused the hell out of lupdate and more or less broke translations permanently. Looks like the only way we can do it is to have a hardcoded namespace, which goes against my instinct, but honestly how likely is it that we'll change the namespace anyway (I guess forks might want to do it, but that's their problem ;) )
2020-11-17 20:24:42 +11:00

259 lines
7.2 KiB
C++

/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 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>
namespace olive {
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);
}
}