mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-07-06 04:52:09 -07:00
Add transform/scaling modes to GUI
Added zoom and stretch modes to GUI to mirror the transform modes available on Android. They are reachable through a context menu or shortcuts (Ctrl+S/Ctrl+Z). CLI options --stretch and --zoom have been added as well. Co-authored-by: Florian Märkl <info@florianmaerkl.de>
This commit is contained in:
parent
74d39e6314
commit
801f902bea
9 changed files with 207 additions and 28 deletions
|
@ -3,6 +3,8 @@
|
|||
#ifndef CHIAKI_AVOPENGLWIDGET_H
|
||||
#define CHIAKI_AVOPENGLWIDGET_H
|
||||
|
||||
#include "transformmode.h"
|
||||
|
||||
#include <chiaki/log.h>
|
||||
|
||||
#include <QOpenGLWidget>
|
||||
|
@ -74,21 +76,24 @@ class AVOpenGLWidget: public QOpenGLWidget
|
|||
public:
|
||||
static QSurfaceFormat CreateSurfaceFormat();
|
||||
|
||||
explicit AVOpenGLWidget(StreamSession *session, QWidget *parent = nullptr);
|
||||
explicit AVOpenGLWidget(StreamSession *session, QWidget *parent = nullptr, TransformMode transform_mode = TransformMode::Fit);
|
||||
~AVOpenGLWidget() override;
|
||||
|
||||
void SwapFrames();
|
||||
AVOpenGLFrame *GetBackgroundFrame() { return &frames[1 - frame_fg]; }
|
||||
|
||||
void SetTransformMode(TransformMode mode) { transform_mode = mode; }
|
||||
TransformMode GetTransformMode() const { return transform_mode; }
|
||||
|
||||
protected:
|
||||
TransformMode transform_mode;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
||||
void initializeGL() override;
|
||||
void paintGL() override;
|
||||
|
||||
private slots:
|
||||
void ResetMouseTimeout();
|
||||
public slots:
|
||||
void ResetMouseTimeout();
|
||||
void HideMouse();
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "sessionlog.h"
|
||||
#include "controllermanager.h"
|
||||
#include "settings.h"
|
||||
#include "transformmode.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QImage>
|
||||
|
@ -53,9 +54,17 @@ struct StreamSessionConnectInfo
|
|||
ChiakiConnectVideoProfile video_profile;
|
||||
unsigned int audio_buffer_size;
|
||||
bool fullscreen;
|
||||
TransformMode transform_mode;
|
||||
bool enable_keyboard;
|
||||
|
||||
StreamSessionConnectInfo(Settings *settings, ChiakiTarget target, QString host, QByteArray regist_key, QByteArray morning, bool fullscreen);
|
||||
StreamSessionConnectInfo(
|
||||
Settings *settings,
|
||||
ChiakiTarget target,
|
||||
QString host,
|
||||
QByteArray regist_key,
|
||||
QByteArray morning,
|
||||
bool fullscreen,
|
||||
TransformMode transform_mode);
|
||||
};
|
||||
|
||||
class StreamSession : public QObject
|
||||
|
@ -124,7 +133,7 @@ class StreamSession : public QObject
|
|||
#endif
|
||||
|
||||
void HandleKeyboardEvent(QKeyEvent *event);
|
||||
void HandleMouseEvent(QMouseEvent *event);
|
||||
bool HandleMouseEvent(QMouseEvent *event);
|
||||
|
||||
signals:
|
||||
void FfmpegFrameAvailable();
|
||||
|
|
|
@ -22,10 +22,14 @@ class StreamWindow: public QMainWindow
|
|||
const StreamSessionConnectInfo connect_info;
|
||||
StreamSession *session;
|
||||
|
||||
QAction *fullscreen_action;
|
||||
QAction *stretch_action;
|
||||
QAction *zoom_action;
|
||||
AVOpenGLWidget *av_widget;
|
||||
|
||||
void Init();
|
||||
void UpdateVideoTransform();
|
||||
void UpdateTransformModeActions();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
|
@ -42,6 +46,8 @@ class StreamWindow: public QMainWindow
|
|||
void SessionQuit(ChiakiQuitReason reason, const QString &reason_str);
|
||||
void LoginPINRequested(bool incorrect);
|
||||
void ToggleFullscreen();
|
||||
void ToggleStretch();
|
||||
void ToggleZoom();
|
||||
};
|
||||
|
||||
#endif // CHIAKI_GUI_STREAMWINDOW_H
|
||||
|
|
12
gui/include/transformmode.h
Normal file
12
gui/include/transformmode.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
// SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL
|
||||
|
||||
#ifndef CHIAKI_TRANSFORMMODE_H
|
||||
#define CHIAKI_TRANSFORMMODE_H
|
||||
|
||||
enum class TransformMode {
|
||||
Fit,
|
||||
Zoom,
|
||||
Stretch
|
||||
};
|
||||
|
||||
#endif
|
|
@ -122,9 +122,9 @@ QSurfaceFormat AVOpenGLWidget::CreateSurfaceFormat()
|
|||
return format;
|
||||
}
|
||||
|
||||
AVOpenGLWidget::AVOpenGLWidget(StreamSession *session, QWidget *parent)
|
||||
AVOpenGLWidget::AVOpenGLWidget(StreamSession *session, QWidget *parent, TransformMode transform_mode)
|
||||
: QOpenGLWidget(parent),
|
||||
session(session)
|
||||
session(session), transform_mode(transform_mode)
|
||||
{
|
||||
enum AVPixelFormat pixel_format = chiaki_ffmpeg_decoder_get_pixel_format(session->GetFfmpegDecoder());
|
||||
conversion_config = nullptr;
|
||||
|
@ -381,10 +381,10 @@ void AVOpenGLWidget::paintGL()
|
|||
vp_width = widget_width;
|
||||
vp_height = widget_height;
|
||||
}
|
||||
else
|
||||
else if(transform_mode == TransformMode::Fit)
|
||||
{
|
||||
float aspect = (float)frame->width / (float)frame->height;
|
||||
if(aspect < (float)widget_width / (float)widget_height)
|
||||
if(widget_height && aspect < (float)widget_width / (float)widget_height)
|
||||
{
|
||||
vp_height = widget_height;
|
||||
vp_width = (GLsizei)(vp_height * aspect);
|
||||
|
@ -395,6 +395,34 @@ void AVOpenGLWidget::paintGL()
|
|||
vp_height = (GLsizei)(vp_width / aspect);
|
||||
}
|
||||
}
|
||||
else if(transform_mode == TransformMode::Zoom)
|
||||
{
|
||||
float aspect = (float)frame->width / (float)frame->height;
|
||||
if(widget_height && aspect < (float)widget_width / (float)widget_height)
|
||||
{
|
||||
vp_width = widget_width;
|
||||
vp_height = (GLsizei)(vp_width / aspect);
|
||||
}
|
||||
else
|
||||
{
|
||||
vp_height = widget_height;
|
||||
vp_width = (GLsizei)(vp_height * aspect);
|
||||
}
|
||||
}
|
||||
else // transform_mode == TransformMode::Stretch
|
||||
{
|
||||
float aspect = (float)frame->width / (float)frame->height;
|
||||
if(widget_height && aspect < (float)widget_width / (float)widget_height)
|
||||
{
|
||||
vp_height = widget_height;
|
||||
vp_width = widget_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
vp_width = widget_width;
|
||||
vp_height = widget_height;
|
||||
}
|
||||
}
|
||||
|
||||
f->glViewport((widget_width - vp_width) / 2, (widget_height - vp_height) / 2, vp_width, vp_height);
|
||||
|
||||
|
|
|
@ -103,9 +103,15 @@ int real_main(int argc, char *argv[])
|
|||
QCommandLineOption morning_option("morning", "", "morning");
|
||||
parser.addOption(morning_option);
|
||||
|
||||
QCommandLineOption fullscreen_option("fullscreen", "Start window in fullscreen (only for use with stream command)");
|
||||
QCommandLineOption fullscreen_option("fullscreen", "Start window in fullscreen mode [maintains aspect ratio, adds black bars to fill unsused parts of screen if applicable] (only for use with stream command)");
|
||||
parser.addOption(fullscreen_option);
|
||||
|
||||
QCommandLineOption zoom_option("zoom", "Start window in fullscreen zoomed in to fit screen [maintains aspect ratio, cutting off edges of image to fill screen] (only for use with stream command)");
|
||||
parser.addOption(zoom_option);
|
||||
|
||||
QCommandLineOption stretch_option("stretch", "Start window in fullscreen stretched to fit screen [distorts aspect ratio to fill screen] (only for use with stream command)");
|
||||
parser.addOption(stretch_option);
|
||||
|
||||
parser.process(app);
|
||||
QStringList args = parser.positionalArguments();
|
||||
|
||||
|
@ -174,7 +180,21 @@ int real_main(int argc, char *argv[])
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
StreamSessionConnectInfo connect_info(&settings, target, host, regist_key, morning, parser.isSet(fullscreen_option));
|
||||
if ((parser.isSet(stretch_option) && (parser.isSet(zoom_option) || parser.isSet(fullscreen_option))) || (parser.isSet(zoom_option) && parser.isSet(fullscreen_option)))
|
||||
{
|
||||
printf("Must choose between fullscreen, zoom or stretch option.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
StreamSessionConnectInfo connect_info(
|
||||
&settings,
|
||||
target,
|
||||
host,
|
||||
regist_key,
|
||||
morning,
|
||||
parser.isSet(fullscreen_option),
|
||||
parser.isSet(zoom_option) ? TransformMode::Zoom : parser.isSet(stretch_option) ? TransformMode::Stretch : TransformMode::Fit);
|
||||
|
||||
return RunStream(app, connect_info);
|
||||
}
|
||||
#ifdef CHIAKI_ENABLE_CLI
|
||||
|
|
|
@ -249,7 +249,14 @@ void MainWindow::ServerItemWidgetTriggered()
|
|||
}
|
||||
|
||||
QString host = server.GetHostAddr();
|
||||
StreamSessionConnectInfo info(settings, server.registered_host.GetTarget(), host, server.registered_host.GetRPRegistKey(), server.registered_host.GetRPKey(), false);
|
||||
StreamSessionConnectInfo info(
|
||||
settings,
|
||||
server.registered_host.GetTarget(),
|
||||
host,
|
||||
server.registered_host.GetRPRegistKey(),
|
||||
server.registered_host.GetRPKey(),
|
||||
false,
|
||||
TransformMode::Fit);
|
||||
new StreamWindow(info);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -14,7 +14,14 @@
|
|||
|
||||
#define SETSU_UPDATE_INTERVAL_MS 4
|
||||
|
||||
StreamSessionConnectInfo::StreamSessionConnectInfo(Settings *settings, ChiakiTarget target, QString host, QByteArray regist_key, QByteArray morning, bool fullscreen)
|
||||
StreamSessionConnectInfo::StreamSessionConnectInfo(
|
||||
Settings *settings,
|
||||
ChiakiTarget target,
|
||||
QString host,
|
||||
QByteArray regist_key,
|
||||
QByteArray morning,
|
||||
bool fullscreen,
|
||||
TransformMode transform_mode)
|
||||
: settings(settings)
|
||||
{
|
||||
key_map = settings->GetControllerMappingForDecoding();
|
||||
|
@ -30,6 +37,7 @@ StreamSessionConnectInfo::StreamSessionConnectInfo(Settings *settings, ChiakiTar
|
|||
this->morning = morning;
|
||||
audio_buffer_size = settings->GetAudioBufferSize();
|
||||
this->fullscreen = fullscreen;
|
||||
this->transform_mode = transform_mode;
|
||||
this->enable_keyboard = false; // TODO: from settings
|
||||
}
|
||||
|
||||
|
@ -228,13 +236,16 @@ void StreamSession::SetLoginPIN(const QString &pin)
|
|||
chiaki_session_set_login_pin(&session, (const uint8_t *)data.constData(), data.size());
|
||||
}
|
||||
|
||||
void StreamSession::HandleMouseEvent(QMouseEvent *event)
|
||||
bool StreamSession::HandleMouseEvent(QMouseEvent *event)
|
||||
{
|
||||
if(event->button() != Qt::MouseButton::LeftButton)
|
||||
return false;
|
||||
if(event->type() == QEvent::MouseButtonPress)
|
||||
keyboard_state.buttons |= CHIAKI_CONTROLLER_BUTTON_TOUCHPAD;
|
||||
else
|
||||
keyboard_state.buttons &= ~CHIAKI_CONTROLLER_BUTTON_TOUCHPAD;
|
||||
SendFeedbackState();
|
||||
return true;
|
||||
}
|
||||
|
||||
void StreamSession::HandleKeyboardEvent(QKeyEvent *event)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <QMessageBox>
|
||||
#include <QCoreApplication>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
|
||||
StreamWindow::StreamWindow(const StreamSessionConnectInfo &connect_info, QWidget *parent)
|
||||
: QMainWindow(parent),
|
||||
|
@ -23,8 +24,6 @@ StreamWindow::StreamWindow(const StreamSessionConnectInfo &connect_info, QWidget
|
|||
|
||||
try
|
||||
{
|
||||
if(connect_info.fullscreen)
|
||||
showFullScreen();
|
||||
Init();
|
||||
}
|
||||
catch(const Exception &e)
|
||||
|
@ -40,6 +39,8 @@ StreamWindow::~StreamWindow()
|
|||
delete av_widget;
|
||||
}
|
||||
|
||||
#include <QGuiApplication>
|
||||
|
||||
void StreamWindow::Init()
|
||||
{
|
||||
session = new StreamSession(connect_info, this);
|
||||
|
@ -47,10 +48,36 @@ void StreamWindow::Init()
|
|||
connect(session, &StreamSession::SessionQuit, this, &StreamWindow::SessionQuit);
|
||||
connect(session, &StreamSession::LoginPINRequested, this, &StreamWindow::LoginPINRequested);
|
||||
|
||||
const QKeySequence fullscreen_shortcut = Qt::Key_F11;
|
||||
const QKeySequence stretch_shortcut = Qt::CTRL + Qt::Key_S;
|
||||
const QKeySequence zoom_shortcut = Qt::CTRL + Qt::Key_Z;
|
||||
|
||||
fullscreen_action = new QAction(tr("Fullscreen"), this);
|
||||
fullscreen_action->setCheckable(true);
|
||||
fullscreen_action->setShortcut(fullscreen_shortcut);
|
||||
addAction(fullscreen_action);
|
||||
connect(fullscreen_action, &QAction::triggered, this, &StreamWindow::ToggleFullscreen);
|
||||
|
||||
if(session->GetFfmpegDecoder())
|
||||
{
|
||||
av_widget = new AVOpenGLWidget(session, this);
|
||||
av_widget = new AVOpenGLWidget(session, this, connect_info.transform_mode);
|
||||
setCentralWidget(av_widget);
|
||||
|
||||
av_widget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(av_widget, &QWidget::customContextMenuRequested, this, [this](const QPoint &pos) {
|
||||
av_widget->ResetMouseTimeout();
|
||||
|
||||
QMenu menu(av_widget);
|
||||
menu.addAction(fullscreen_action);
|
||||
menu.addSeparator();
|
||||
menu.addAction(stretch_action);
|
||||
menu.addAction(zoom_action);
|
||||
releaseKeyboard();
|
||||
connect(&menu, &QMenu::aboutToHide, this, [this] {
|
||||
grabKeyboard();
|
||||
});
|
||||
menu.exec(av_widget->mapToGlobal(pos));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -63,13 +90,29 @@ void StreamWindow::Init()
|
|||
|
||||
session->Start();
|
||||
|
||||
auto fullscreen_action = new QAction(tr("Fullscreen"), this);
|
||||
fullscreen_action->setShortcut(Qt::Key_F11);
|
||||
addAction(fullscreen_action);
|
||||
connect(fullscreen_action, &QAction::triggered, this, &StreamWindow::ToggleFullscreen);
|
||||
stretch_action = new QAction(tr("Stretch"), this);
|
||||
stretch_action->setCheckable(true);
|
||||
stretch_action->setShortcut(stretch_shortcut);
|
||||
addAction(stretch_action);
|
||||
connect(stretch_action, &QAction::triggered, this, &StreamWindow::ToggleStretch);
|
||||
|
||||
zoom_action = new QAction(tr("Zoom"), this);
|
||||
zoom_action->setCheckable(true);
|
||||
zoom_action->setShortcut(zoom_shortcut);
|
||||
addAction(zoom_action);
|
||||
connect(zoom_action, &QAction::triggered, this, &StreamWindow::ToggleZoom);
|
||||
|
||||
resize(connect_info.video_profile.width, connect_info.video_profile.height);
|
||||
|
||||
if(connect_info.fullscreen)
|
||||
{
|
||||
showFullScreen();
|
||||
fullscreen_action->setChecked(true);
|
||||
}
|
||||
else
|
||||
show();
|
||||
|
||||
UpdateTransformModeActions();
|
||||
}
|
||||
|
||||
void StreamWindow::keyPressEvent(QKeyEvent *event)
|
||||
|
@ -86,20 +129,25 @@ void StreamWindow::keyReleaseEvent(QKeyEvent *event)
|
|||
|
||||
void StreamWindow::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if(session)
|
||||
session->HandleMouseEvent(event);
|
||||
if(session && session->HandleMouseEvent(event))
|
||||
return;
|
||||
QMainWindow::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void StreamWindow::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if(session)
|
||||
session->HandleMouseEvent(event);
|
||||
if(session && session->HandleMouseEvent(event))
|
||||
return;
|
||||
QMainWindow::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void StreamWindow::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
if(event->button() == Qt::MouseButton::LeftButton)
|
||||
{
|
||||
ToggleFullscreen();
|
||||
|
||||
return;
|
||||
}
|
||||
QMainWindow::mouseDoubleClickEvent(event);
|
||||
}
|
||||
|
||||
|
@ -175,15 +223,48 @@ void StreamWindow::LoginPINRequested(bool incorrect)
|
|||
void StreamWindow::ToggleFullscreen()
|
||||
{
|
||||
if(isFullScreen())
|
||||
{
|
||||
showNormal();
|
||||
fullscreen_action->setChecked(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
showFullScreen();
|
||||
if(av_widget)
|
||||
av_widget->HideMouse();
|
||||
fullscreen_action->setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
void StreamWindow::UpdateTransformModeActions()
|
||||
{
|
||||
TransformMode tm = av_widget ? av_widget->GetTransformMode() : TransformMode::Fit;
|
||||
stretch_action->setChecked(tm == TransformMode::Stretch);
|
||||
zoom_action->setChecked(tm == TransformMode::Zoom);
|
||||
}
|
||||
|
||||
void StreamWindow::ToggleStretch()
|
||||
{
|
||||
if(!av_widget)
|
||||
return;
|
||||
av_widget->SetTransformMode(
|
||||
av_widget->GetTransformMode() == TransformMode::Stretch
|
||||
? TransformMode::Fit
|
||||
: TransformMode::Stretch);
|
||||
UpdateTransformModeActions();
|
||||
}
|
||||
|
||||
void StreamWindow::ToggleZoom()
|
||||
{
|
||||
if(!av_widget)
|
||||
return;
|
||||
av_widget->SetTransformMode(
|
||||
av_widget->GetTransformMode() == TransformMode::Zoom
|
||||
? TransformMode::Fit
|
||||
: TransformMode::Zoom);
|
||||
UpdateTransformModeActions();
|
||||
}
|
||||
|
||||
void StreamWindow::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
UpdateVideoTransform();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue