Skip to content

Commit

Permalink
UI: Resize projector window by resolution or scale
Browse files Browse the repository at this point in the history
  • Loading branch information
fsworld009 committed Dec 1, 2022
1 parent 45f0b10 commit 8a86ae5
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 0 deletions.
2 changes: 2 additions & 0 deletions UI/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ target_sources(
window-log-reply.cpp
window-projector.cpp
window-projector.hpp
window-projector-custom-size-dialog.cpp
window-projector-custom-size-dialog.hpp
window-remux.cpp
window-remux.hpp)

Expand Down
4 changes: 4 additions & 0 deletions UI/data/locale/en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ SourceWindow="Windowed Projector (Source)"
MultiviewProjector="Multiview (Fullscreen)"
MultiviewWindowed="Multiview (Windowed)"
ResizeProjectorWindowToContent="Fit window to content"
ResizeProjectorWindow="Resize window"
ResizeProjectorWindowCustom="Custom..."
ResizeProjectorWindowCustomResolution="Resolution"
ResizeProjectorWindowCustomScale="Scale"
Clear="Clear"
Revert="Revert"
Show="Show"
Expand Down
94 changes: 94 additions & 0 deletions UI/window-projector-custom-size-dialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include <limits.h>
#include <QBoxLayout>
#include <QFrame>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QSize>
#include "obs-app.hpp"
#include "window-projector-custom-size-dialog.hpp"

OBSProjectorCustomSizeDialog::OBSProjectorCustomSizeDialog(QWidget *parent)
: QDialog(parent)
{
QSize parentSize = parent->size();
this->setWindowTitle(QTStr("ResizeProjectorWindow"));
this->setAttribute(Qt::WA_DeleteOnClose);

QVBoxLayout *layout = new QVBoxLayout(this);

// Input method dropdown
customMethod = new QComboBox();
customMethod->addItem(QTStr("ResizeProjectorWindowCustomResolution"));
customMethod->addItem(QTStr("ResizeProjectorWindowCustomScale"));
layout->addWidget(customMethod);
connect(customMethod,
QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&OBSProjectorCustomSizeDialog::ChangeCustomMethod);

// layout to contain both resolution and scale input
inputLayout = new QStackedLayout();

// resolution input
QFrame *resolutionInput = new QFrame();
QGridLayout *resolutionInputLayout = new QGridLayout();
resolutionInput->setLayout(resolutionInputLayout);

width = CreateSpinBox(parentSize.width());
resolutionInputLayout->addWidget(width, 0, 0);
resolutionInputLayout->setColumnStretch(0, 1);
QLabel *resolutionLabel = new QLabel(QString("x"));
resolutionInputLayout->addWidget(resolutionLabel, 0, 1);
height = CreateSpinBox(parentSize.height());
resolutionInputLayout->addWidget(height, 0, 2);
resolutionInputLayout->setColumnStretch(2, 1);
inputLayout->addWidget(resolutionInput);

// scale input
QFrame *scaleInput = new QFrame();
QGridLayout *scaleInputLayout = new QGridLayout();
scaleInput->setLayout(scaleInputLayout);
scale = CreateSpinBox(100);
scaleInputLayout->addWidget(scale, 0, 0);
scaleInputLayout->setColumnStretch(0, 1);
QLabel *scaleLabel = new QLabel(QString("%"));
scaleInputLayout->addWidget(scaleLabel, 0, 1);
inputLayout->addWidget(scaleInput);

// only show resolution input on open
inputLayout->setCurrentIndex(0);

layout->addLayout(inputLayout);

// OK button
QPushButton *okButton = new QPushButton(QTStr("OK"));
layout->addWidget(okButton);
connect(okButton, &QPushButton::clicked, this,
&OBSProjectorCustomSizeDialog::ConfirmAndClose);

this->setLayout(layout);
}

QSpinBox *OBSProjectorCustomSizeDialog::CreateSpinBox(int initValue)
{
QSpinBox *spinbox = new QSpinBox();
spinbox->setMinimum(1);
spinbox->setMaximum(INT_MAX);
spinbox->setValue(initValue);
return spinbox;
}

void OBSProjectorCustomSizeDialog::ChangeCustomMethod(int index)
{
inputLayout->setCurrentIndex(index);
}

void OBSProjectorCustomSizeDialog::ConfirmAndClose()
{
if (customMethod->currentIndex() == 0) {
emit ApplyResolution(width->value(), height->value());
} else {
emit ApplyScale(scale->value());
}
emit accept();
}
30 changes: 30 additions & 0 deletions UI/window-projector-custom-size-dialog.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <obs.hpp>
#include <QComboBox>
#include <QDialog>
#include <QStackedLayout>
#include <QSpinBox>

class OBSProjectorCustomSizeDialog : public QDialog {
Q_OBJECT

public:
OBSProjectorCustomSizeDialog(QWidget *parent);

private:
QComboBox *customMethod;
QSpinBox *width;
QSpinBox *height;
QSpinBox *scale;
QStackedLayout *inputLayout;
QSpinBox *CreateSpinBox(int initValue);

signals:
void ApplyResolution(int width, int height);
void ApplyScale(int scale);

private slots:
void ChangeCustomMethod(int index);
void ConfirmAndClose();
};
102 changes: 102 additions & 0 deletions UI/window-projector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "qt-wrappers.hpp"
#include "platform.hpp"
#include "multiview.hpp"
#include "window-projector-custom-size-dialog.hpp"

static QList<OBSProjector *> multiviewProjectors;

Expand Down Expand Up @@ -290,6 +291,70 @@ void OBSProjector::mousePressEvent(QMouseEvent *event)
} else if (!this->isMaximized()) {
popup.addAction(QTStr("ResizeProjectorWindowToContent"),
this, SLOT(ResizeToContent()));

// Resize Window menu
QMenu *resizeWindowMenu =
new QMenu(QTStr("ResizeProjectorWindow"));

// Resize Window menu: preset resolution items
auto resizeToResolutionAction = [this](QAction *action) {
int width = action->property("width").toInt();
int height = action->property("height").toInt();
resize(width, height);
};

int resolutionPresets[][2] = {{1280, 720},
{1920, 1080},
{2560, 1440},
{3840, 2160}};
for (size_t i = 0;
i < sizeof(resolutionPresets) / (sizeof(int) * 2);
i++) {
QAction *resolution = new QAction(
QString("%1 x %2")
.arg(resolutionPresets[i][0])
.arg(resolutionPresets[i][1]),
this);
resolution->setProperty(
"width", resolutionPresets[i][0]);
resolution->setProperty(
"height", resolutionPresets[i][1]);
connect(resolution, &QAction::triggered,
std::bind(resizeToResolutionAction,
resolution));
resizeWindowMenu->addAction(resolution);
}
resizeWindowMenu->addSeparator();

// Resize Window menu: preset scale items
auto resizeToScaleAction = [this](QAction *action) {
double scale =
action->property("scale").toInt();
ResizeToScale(scale);
};

int scalePresets[] = {50, 75, 100, 125, 150, 200};

for (size_t i = 0;
i < sizeof(scalePresets) / sizeof(int); i++) {
QAction *scale = new QAction(
QString("%1%").arg(scalePresets[i]),
this);
scale->setProperty("scale", scalePresets[i]);
connect(scale, &QAction::triggered,
std::bind(resizeToScaleAction, scale));
resizeWindowMenu->addAction(scale);
}

resizeWindowMenu->addSeparator();

QAction *custom = new QAction(
QTStr("ResizeProjectorWindowCustom"), this);
connect(custom, &QAction::triggered, this,
&OBSProjector::OpenCustomWindowSizeDialog);
resizeWindowMenu->addAction(custom);

popup.addMenu(resizeWindowMenu);
}

QAction *hideFrameAction =
Expand Down Expand Up @@ -517,6 +582,43 @@ void OBSProjector::ResizeToContent()
resize(newX, newY);
}

QSize OBSProjector::GetTargetSize()
{
OBSSource source = GetSource();
if (source) {
return QSize(std::max(obs_source_get_width(source), 1u),
std::max(obs_source_get_height(source), 1u));
} else {
struct obs_video_info ovi;
obs_get_video_info(&ovi);
return QSize(ovi.base_width, ovi.base_height);
}
}

void OBSProjector::ResizeToScale(int scale)
{
QSize targetSize = GetTargetSize();
double scaleFactor = scale / 100.0;
resize(targetSize.width() * scaleFactor,
targetSize.height() * scaleFactor);
}

void OBSProjector::ResizeToResolution(int width, int height)
{
resize(width, height);
}

void OBSProjector::OpenCustomWindowSizeDialog()
{
OBSProjectorCustomSizeDialog *dialog =
new OBSProjectorCustomSizeDialog(this);
connect(dialog, &OBSProjectorCustomSizeDialog::ApplyResolution, this,
&OBSProjector::ResizeToResolution);
connect(dialog, &OBSProjectorCustomSizeDialog::ApplyScale, this,
&OBSProjector::ResizeToScale);
dialog->open();
}

void OBSProjector::AlwaysOnTopToggled(bool isAlwaysOnTop)
{
SetIsAlwaysOnTop(isAlwaysOnTop, true);
Expand Down
5 changes: 5 additions & 0 deletions UI/window-projector.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <QSize>
#include <obs.hpp>
#include "qt-display.hpp"
#include "multiview.hpp"
Expand Down Expand Up @@ -49,11 +50,15 @@ class OBSProjector : public OBSQTDisplay {
void SetMonitor(int monitor);

QScreen *screen = nullptr;
QSize GetTargetSize();

private slots:
void EscapeTriggered();
void OpenFullScreenProjector();
void ResizeToContent();
void ResizeToScale(int scale);
void ResizeToResolution(int width, int height);
void OpenCustomWindowSizeDialog();
void OpenWindowedProjector();
void AlwaysOnTopToggled(bool alwaysOnTop);
void ScreenRemoved(QScreen *screen_);
Expand Down

0 comments on commit 8a86ae5

Please sign in to comment.