Vollbildmodus für HDMI

This commit is contained in:
2026-09-15 20:21:22 +02:00
parent 934f32a3bd
commit 4a44d04c75
10 changed files with 576 additions and 411 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,3 @@
build/
uartscope-git/
uartscope-git/
*.tar.gz

View File

@@ -12,6 +12,33 @@
#include "v4l2worker.h"
// A borderless top-level window that mirrors the live video frame at full
// screen size. Opened from VideoWidget's "⛶" button; closes itself on
// Escape or a double-click anywhere on it.
class FullscreenVideoView : public QWidget
{
Q_OBJECT
public:
explicit FullscreenVideoView(QWidget *parent = nullptr);
void setFrame(const QImage &frame);
signals:
// Emitted from closeEvent() so VideoWidget can drop its pointer before
// the WA_DeleteOnClose deletion actually happens.
void closed();
protected:
void paintEvent(QPaintEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
void closeEvent(QCloseEvent *event) override;
private:
QImage m_frame;
};
// VideoWidget shows the live V4L2 preview and can additionally record it
// to an MP4 file. Recording works by piping raw BGRA frames into an
// external `ffmpeg` process (via QProcess/stdin), which encodes them to
@@ -54,6 +81,7 @@ private slots:
void onFreeze(bool frozen);
void onScreenshot();
void onRecordToggled(bool checked);
void onFullscreenToggle();
void refreshDeviceList();
protected:
@@ -83,8 +111,14 @@ private:
QPushButton *m_freezeBtn = nullptr;
QPushButton *m_screenshotBtn = nullptr;
QPushButton *m_recordBtn = nullptr;
QPushButton *m_fullscreenBtn = nullptr;
QLabel *m_infoLabel = nullptr;
// Fullscreen overlay window (nullptr when not open). Owns itself via
// Qt::WA_DeleteOnClose; VideoWidget just tracks whether one currently
// exists and forwards frames to it while it's open.
FullscreenVideoView *m_fullscreenView = nullptr;
// Recording state. m_recordProcess is the running ffmpeg instance (or
// nullptr when not recording); m_recordSize is the frame size the
// recording was started with, so a mid-stream resolution change (which

View File

@@ -9,6 +9,71 @@
#include <QMetaObject>
#include <QResizeEvent>
#include <QMessageBox>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QCloseEvent>
#include <QScreen>
// ── FullscreenVideoView ────────────────────────────────────────────────
FullscreenVideoView::FullscreenVideoView(QWidget *parent)
: QWidget(parent, Qt::Window)
{
setWindowTitle(tr("uartscope - Video (Fullscreen)"));
setAttribute(Qt::WA_DeleteOnClose);
setCursor(Qt::BlankCursor);
QPalette pal = palette();
pal.setColor(QPalette::Window, Qt::black);
setPalette(pal);
setAutoFillBackground(true);
}
void FullscreenVideoView::setFrame(const QImage &frame)
{
m_frame = frame;
update();
}
void FullscreenVideoView::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.fillRect(rect(), Qt::black);
if (m_frame.isNull()) {
p.setPen(QColor(0x44, 0x44, 0x44));
p.setFont(QFont("Sans", 14));
p.drawText(rect(), Qt::AlignCenter, tr("No signal"));
return;
}
const QImage scaled = m_frame.scaled(size(), Qt::KeepAspectRatio,
Qt::SmoothTransformation);
const QPoint origin((width() - scaled.width()) / 2,
(height() - scaled.height()) / 2);
p.drawImage(origin, scaled);
}
void FullscreenVideoView::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape || event->key() == Qt::Key_F11)
close();
else
QWidget::keyPressEvent(event);
}
void FullscreenVideoView::mouseDoubleClickEvent(QMouseEvent *)
{
close();
}
void FullscreenVideoView::closeEvent(QCloseEvent *event)
{
emit closed();
QWidget::closeEvent(event);
}
// ── VideoWidget ─────────────────────────────────────────────────────────
static QStringList enumerateVideoDevices()
{
@@ -44,6 +109,8 @@ VideoWidget::VideoWidget(QWidget *parent)
m_infoLabel->setText(tr("Stopped"));
if (m_recording)
stopRecording();
if (m_fullscreenView)
m_fullscreenView->close();
update();
});
connect(m_worker, &V4l2Worker::errorOccurred, this, [this](const QString &msg) {
@@ -63,6 +130,9 @@ void VideoWidget::shutdown()
return;
m_shutdownDone = true;
if (m_fullscreenView)
m_fullscreenView->close();
if (m_recording)
stopRecording();
@@ -119,12 +189,18 @@ void VideoWidget::setupUi()
m_recordBtn->setToolTip(tr("Record the live preview to an MP4 file (requires ffmpeg)"));
connect(m_recordBtn, &QPushButton::toggled, this, &VideoWidget::onRecordToggled);
m_fullscreenBtn = new QPushButton(tr("⛶"), this);
m_fullscreenBtn->setMaximumWidth(28);
m_fullscreenBtn->setToolTip(tr("Show video fullscreen (Esc or double-click to exit)"));
connect(m_fullscreenBtn, &QPushButton::clicked, this, &VideoWidget::onFullscreenToggle);
ctrlRow->addWidget(m_deviceCombo, 1);
ctrlRow->addWidget(refreshBtn);
ctrlRow->addWidget(m_startBtn);
ctrlRow->addWidget(m_freezeBtn);
ctrlRow->addWidget(m_screenshotBtn);
ctrlRow->addWidget(m_recordBtn);
ctrlRow->addWidget(m_fullscreenBtn);
layout->addLayout(ctrlRow);
m_infoLabel = new QLabel(tr("No device started"), this);
@@ -229,6 +305,9 @@ void VideoWidget::onNewFrame(const QImage &frame)
m_frame = frame;
updateScaled();
update();
if (m_fullscreenView)
m_fullscreenView->setFrame(frame);
}
void VideoWidget::clearFrame()
@@ -321,6 +400,28 @@ void VideoWidget::onRecordToggled(bool checked)
stopRecording();
}
void VideoWidget::onFullscreenToggle()
{
// Already open - a second click just closes it again.
if (m_fullscreenView) {
m_fullscreenView->close();
return;
}
m_fullscreenView = new FullscreenVideoView();
connect(m_fullscreenView, &FullscreenVideoView::closed, this, [this] {
m_fullscreenView = nullptr;
});
// Put it on whichever screen the main window currently lives on
// (useful when a second/HDMI display is attached), then go fullscreen.
if (QScreen *screen = this->screen())
m_fullscreenView->setGeometry(screen->geometry());
m_fullscreenView->setFrame(m_frame);
m_fullscreenView->showFullScreen();
}
void VideoWidget::startRecording()
{
if (m_frame.isNull()) {

View File

@@ -1,6 +1,6 @@
# Maintainer: diabolus <your@email.com>
pkgname=uartscope
pkgver=1.1.0.r1.gef335f2
pkgver=1.1.0.r2.g934f32a
pkgrel=1
pkgdesc="Qt6-based UART serial monitor with tag monitoring, table view and auto-reconnect"
arch=('x86_64' 'aarch64')

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -3,12 +3,12 @@
pkgname = uartscope
pkgbase = uartscope
xdata = pkgtype=pkg
pkgver = 1.1.0.r1.gef335f2-1
pkgver = 1.1.0.r2.g934f32a-1
pkgdesc = Qt6-based UART serial monitor with tag monitoring, table view and auto-reconnect
url = https://git.projekt-hirnfrei.de/diabolus/uartscope
builddate = 1787701264
builddate = 1788785731
packager = Unknown Packager
size = 434929
size = 455537
arch = x86_64
license = MIT
conflict = uartscope

Submodule uartscope-git/src/uartscope updated: ef335f2d9e...934f32a3bd

View File

@@ -1,3 +1,3 @@
ef335f2d9eaa98572ab305e5830a0372474163e8 not-for-merge branch 'main' of https://git.projekt-hirnfrei.de/diabolus/uartscope
934f32a3bd94355c2d92f37899c80b95374d9fac not-for-merge branch 'main' of https://git.projekt-hirnfrei.de/diabolus/uartscope
cc102c93eb17f7b910d8e74c3505f198bed77f10 not-for-merge tag 'v1.0.0' of https://git.projekt-hirnfrei.de/diabolus/uartscope
36923e16461bc15086c84187790dbcb5f0a5030f not-for-merge tag 'v1.1.0' of https://git.projekt-hirnfrei.de/diabolus/uartscope