Erster Commit
This commit is contained in:
251
src/MainWindow.cpp
Normal file
251
src/MainWindow.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
#include "MainWindow.h"
|
||||
#include "VideoWidget.h"
|
||||
#include "CaptureThread.h"
|
||||
#include "AudioThread.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QCloseEvent>
|
||||
#include <QStatusBar>
|
||||
#include <QMenuBar>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QDialog>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QFrame>
|
||||
|
||||
MainWindow::MainWindow(const QString& videoDevice,
|
||||
const QString& audioDevice,
|
||||
int targetFps,
|
||||
QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
, m_videoDevice(videoDevice)
|
||||
, m_audioDevice(audioDevice)
|
||||
{
|
||||
setWindowTitle("HDMI Viewer");
|
||||
resize(1280, 720);
|
||||
|
||||
m_video = new VideoWidget(this);
|
||||
setCentralWidget(m_video);
|
||||
|
||||
setupMenuBar();
|
||||
updateStatusBar();
|
||||
|
||||
// ── Capture ──────────────────────────────────────────────────────────────
|
||||
m_capture = new CaptureThread(videoDevice, targetFps, this);
|
||||
|
||||
connect(m_capture, &CaptureThread::frameReady,
|
||||
m_video, &VideoWidget::setFrame,
|
||||
Qt::QueuedConnection);
|
||||
connect(m_capture, &CaptureThread::errorOccurred,
|
||||
this, &MainWindow::onError,
|
||||
Qt::QueuedConnection);
|
||||
connect(m_capture, &CaptureThread::captureInfo,
|
||||
this, &MainWindow::onCaptureInfo,
|
||||
Qt::QueuedConnection);
|
||||
|
||||
m_capture->start();
|
||||
|
||||
// ── Audio ─────────────────────────────────────────────────────────────────
|
||||
if (!audioDevice.isEmpty()) {
|
||||
m_audio = new AudioThread(audioDevice, this);
|
||||
connect(m_audio, &AudioThread::errorOccurred,
|
||||
this, &MainWindow::onError,
|
||||
Qt::QueuedConnection);
|
||||
m_audio->start();
|
||||
}
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
stopAll();
|
||||
}
|
||||
|
||||
void MainWindow::setupMenuBar()
|
||||
{
|
||||
QMenu* helpMenu = menuBar()->addMenu("&Hilfe");
|
||||
|
||||
QAction* aboutAct = helpMenu->addAction("Über HDMI Viewer");
|
||||
aboutAct->setMenuRole(QAction::AboutRole);
|
||||
connect(aboutAct, &QAction::triggered, this, &MainWindow::showAbout);
|
||||
}
|
||||
|
||||
void MainWindow::showAbout()
|
||||
{
|
||||
auto* dlg = new QDialog(this);
|
||||
dlg->setWindowTitle("Über HDMI Viewer");
|
||||
dlg->setFixedSize(420, 340);
|
||||
dlg->setModal(true);
|
||||
|
||||
auto* root = new QVBoxLayout(dlg);
|
||||
root->setSpacing(0);
|
||||
root->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
// ── Header-Bereich ────────────────────────────────────────────────────────
|
||||
auto* header = new QWidget(dlg);
|
||||
header->setFixedHeight(90);
|
||||
header->setStyleSheet("background-color: #1e1e2e;");
|
||||
auto* headerLayout = new QVBoxLayout(header);
|
||||
headerLayout->setContentsMargins(24, 16, 24, 16);
|
||||
|
||||
auto* titleLabel = new QLabel("HDMI Viewer", header);
|
||||
titleLabel->setStyleSheet("font-size: 22px; font-weight: bold; color: #cdd6f4;");
|
||||
|
||||
auto* subtitleLabel = new QLabel("Live-Vorschau für HDMI-Grabber", header);
|
||||
subtitleLabel->setStyleSheet("font-size: 11px; color: #6c7086;");
|
||||
|
||||
headerLayout->addWidget(titleLabel);
|
||||
headerLayout->addWidget(subtitleLabel);
|
||||
|
||||
// ── Trennlinie ────────────────────────────────────────────────────────────
|
||||
auto* sep = new QFrame(dlg);
|
||||
sep->setFrameShape(QFrame::HLine);
|
||||
sep->setStyleSheet("color: #313244;");
|
||||
|
||||
// ── Info-Bereich ──────────────────────────────────────────────────────────
|
||||
auto* body = new QWidget(dlg);
|
||||
auto* grid = new QGridLayout(body);
|
||||
grid->setContentsMargins(24, 20, 24, 8);
|
||||
grid->setVerticalSpacing(10);
|
||||
grid->setHorizontalSpacing(16);
|
||||
grid->setColumnMinimumWidth(0, 100);
|
||||
|
||||
auto addRow = [&](int row, const QString& label, const QString& value) {
|
||||
auto* l = new QLabel(label, body);
|
||||
l->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
l->setStyleSheet("font-weight: bold; color: #a6adc8;");
|
||||
|
||||
auto* v = new QLabel(value, body);
|
||||
v->setStyleSheet("color: #cdd6f4;");
|
||||
v->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
|
||||
grid->addWidget(l, row, 0);
|
||||
grid->addWidget(v, row, 1);
|
||||
};
|
||||
|
||||
addRow(0, "Version", "1.3.0");
|
||||
addRow(1, "Entwickler", "Dany Thinnes");
|
||||
addRow(2, "Projekt", "Projekt Hirnfrei");
|
||||
addRow(3, "Framework", QString("Qt %1").arg(QT_VERSION_STR));
|
||||
addRow(4, "Sprache", "C++17");
|
||||
addRow(5, "Video-API", "V4L2 · MJPEG / YUYV / NV12");
|
||||
addRow(6, "Audio-API", "ALSA");
|
||||
|
||||
// ── Tastenkürzel-Hinweis ──────────────────────────────────────────────────
|
||||
auto* sep2 = new QFrame(body);
|
||||
sep2->setFrameShape(QFrame::HLine);
|
||||
sep2->setStyleSheet("color: #313244;");
|
||||
grid->addWidget(sep2, 7, 0, 1, 2);
|
||||
|
||||
auto* keysLabel = new QLabel(
|
||||
"<small><b>F</b> Vollbild ein/aus "
|
||||
"<b>Esc</b> Zurück zu Einstellungen</small>", body);
|
||||
keysLabel->setStyleSheet("color: #6c7086;");
|
||||
keysLabel->setAlignment(Qt::AlignCenter);
|
||||
grid->addWidget(keysLabel, 8, 0, 1, 2);
|
||||
|
||||
// ── Schließen-Button ──────────────────────────────────────────────────────
|
||||
auto* btnRow = new QHBoxLayout;
|
||||
btnRow->setContentsMargins(24, 8, 24, 20);
|
||||
auto* closeBtn = new QPushButton("Schließen", dlg);
|
||||
closeBtn->setDefault(true);
|
||||
closeBtn->setFixedWidth(100);
|
||||
btnRow->addStretch();
|
||||
btnRow->addWidget(closeBtn);
|
||||
connect(closeBtn, &QPushButton::clicked, dlg, &QDialog::accept);
|
||||
|
||||
root->addWidget(header);
|
||||
root->addWidget(sep);
|
||||
root->addWidget(body, 1);
|
||||
root->addLayout(btnRow);
|
||||
|
||||
dlg->exec();
|
||||
dlg->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::stopAll()
|
||||
{
|
||||
if (m_capture) {
|
||||
m_capture->stopAndWait();
|
||||
delete m_capture;
|
||||
m_capture = nullptr;
|
||||
}
|
||||
if (m_audio) {
|
||||
m_audio->stop();
|
||||
m_audio->wait();
|
||||
delete m_audio;
|
||||
m_audio = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
switch (event->key()) {
|
||||
case Qt::Key_F:
|
||||
toggleFullscreen();
|
||||
break;
|
||||
case Qt::Key_Escape:
|
||||
if (m_fullscreen) {
|
||||
toggleFullscreen();
|
||||
} else {
|
||||
m_wantsReopen = true;
|
||||
close();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
QMainWindow::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
stopAll();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void MainWindow::toggleFullscreen()
|
||||
{
|
||||
if (m_fullscreen) {
|
||||
showNormal();
|
||||
menuBar()->show();
|
||||
statusBar()->show();
|
||||
} else {
|
||||
showFullScreen();
|
||||
menuBar()->hide();
|
||||
statusBar()->hide();
|
||||
}
|
||||
m_fullscreen = !m_fullscreen;
|
||||
}
|
||||
|
||||
void MainWindow::updateStatusBar()
|
||||
{
|
||||
QString info;
|
||||
if (m_capWidth > 0)
|
||||
info = QString("%1×%2 @ %3fps %4 ")
|
||||
.arg(m_capWidth).arg(m_capHeight).arg(m_capFps).arg(m_capFmt);
|
||||
|
||||
info += QString("Video: %1 Audio: %2 [F] Vollbild [Esc] Einstellungen")
|
||||
.arg(m_videoDevice,
|
||||
m_audioDevice.isEmpty() ? QStringLiteral("–") : m_audioDevice);
|
||||
|
||||
statusBar()->showMessage(info);
|
||||
}
|
||||
|
||||
void MainWindow::onCaptureInfo(int width, int height, int fps, const QString& format)
|
||||
{
|
||||
m_capWidth = width;
|
||||
m_capHeight = height;
|
||||
m_capFps = fps;
|
||||
m_capFmt = format;
|
||||
updateStatusBar();
|
||||
setWindowTitle(QString("HDMI Viewer – %1×%2 @ %3fps %4")
|
||||
.arg(width).arg(height).arg(fps).arg(format));
|
||||
}
|
||||
|
||||
void MainWindow::onError(const QString& msg)
|
||||
{
|
||||
statusBar()->showMessage("⚠ " + msg, 8000);
|
||||
qWarning() << "[Error]" << msg;
|
||||
}
|
||||
Reference in New Issue
Block a user