Vollbildmodus für HDMI
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
build/
|
||||
uartscope-git/
|
||||
*.tar.gz
|
||||
@@ -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
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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.
@@ -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
|
||||
|
||||
Binary file not shown.
Submodule uartscope-git/src/uartscope updated: ef335f2d9e...934f32a3bd
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user