Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 84 additions & 21 deletions src/gui/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,35 @@ constexpr const char* kSuppressAudioDeviceNotificationsKey =
"SuppressAudioDeviceNotifications";
constexpr int kTMate2DefaultOverlayDurationMs = 1500;
constexpr int kTMate2DefaultUserInteractionTimeoutMs = 2000;
constexpr const char* kStatusBarCompactLabelObjectName = "statusBarCompactLabel";

QString statusBarCompactLabelStyle(const QString& color)
{
return QStringLiteral(
"QLabel#statusBarCompactLabel { color: %1; font-size: 12px; background: transparent; }")
.arg(color);
}

void applyStatusBarCompactLabelStyle(QLabel* label, const QString& color)
{
if (!label) {
return;
}

label->setObjectName(kStatusBarCompactLabelObjectName);
AetherSDR::ThemeManager::instance().applyStyleSheet(label, statusBarCompactLabelStyle(color));
}

void setStatusBarStationText(QLabel* label, const QString& text)
{
if (!label) {
return;
}

label->setText(text);
label->ensurePolished();
label->setMinimumWidth(label->sizeHint().width() + 2);
}

#ifdef HAVE_HIDAPI
QString tmate2EncoderDefaultAction(int encoderIndex)
Expand Down Expand Up @@ -3796,6 +3825,7 @@ MainWindow::MainWindow(QWidget* parent)
this, [this](bool present) {
m_tgxlContainer->setVisible(present);
m_tgxlSeparator->setVisible(present);
updateStatusBarMinimumWidth();
// Auto-connect/disconnect direct TGXL connection for manual relay control (#469)
if (present) {
QString ip = m_radioModel.tunerModel().tgxlIp();
Expand Down Expand Up @@ -4003,6 +4033,7 @@ MainWindow::MainWindow(QWidget* parent)
connect(&m_radioModel, &RadioModel::amplifierChanged, this, [this, updatePgxlStyle](bool present) {
m_pgxlContainer->setVisible(present);
m_pgxlSeparator->setVisible(present);
updateStatusBarMinimumWidth();
m_appletPanel->setAmpVisible(present);
if (present) {
updatePgxlStyle();
Expand Down Expand Up @@ -5378,8 +5409,10 @@ MainWindow::MainWindow(QWidget* parent)

// Update station label (nickname arrives via status after connect)
const QString nick = m_radioModel.nickname();
if (!nick.isEmpty())
m_stationLabel->setText(nick);
if (!nick.isEmpty()) {
setStatusBarStationText(m_stationLabel, nick);
updateStatusBarMinimumWidth();
}
});

auto normalizeOscillatorValue = [](QString value) {
Expand Down Expand Up @@ -6437,6 +6470,29 @@ void MainWindow::resizeEvent(QResizeEvent* event)
}
}

void MainWindow::updateStatusBarMinimumWidth()
{
if (m_minimalMode || !m_statusBarContainer || statusBar()->isHidden()) {
return;
}

if (QLayout* layout = m_statusBarContainer->layout()) {
layout->activate();
}
m_statusBarContainer->updateGeometry();
statusBar()->updateGeometry();

const int sizeGripAllowance =
(m_sizeGrip && m_sizeGrip->isVisible()) ? m_sizeGrip->width() + 4 : 4;
const int statusMinWidth =
m_statusBarContainer->minimumSizeHint().width() + sizeGripAllowance;
const int screenWidthCap =
screen() ? screen()->availableGeometry().width() : statusMinWidth;
const int boundedMinWidth =
qBound(1024, statusMinWidth, qMax(1024, screenWidthCap));
setMinimumSize(boundedMinWidth, qMax(400, minimumHeight()));
}

#if defined(Q_OS_WIN)
void MainWindow::applyWindowsCustomFrame()
{
Expand Down Expand Up @@ -10620,7 +10676,7 @@ void MainWindow::buildUI()
AppSettings::instance().value("FramelessWindow", "True").toString() == "True");
AetherSDR::ThemeManager::instance().applyStyleSheet(statusBar(), "QStatusBar { background: {{color.background.0}}; border-top: 1px solid {{color.background.1}}; }"
"QStatusBar::item { border: none; }"
"QLabel { font-size: 21px; background: transparent; }");
"QLabel { background: transparent; }");

const QString valStyle = "QLabel { color: #8aa8c0; font-size: 21px; }";
const QString sepStyle = "QLabel { color: #304050; font-size: 21px; }";
Expand All @@ -10632,8 +10688,8 @@ void MainWindow::buildUI()

// Use a container with HBoxLayout for 3-section layout:
// [left items] → stretch → [STATION centered] → stretch → [right items]
auto* container = new QWidget(this);
auto* hbox = new QHBoxLayout(container);
m_statusBarContainer = new QWidget(this);
auto* hbox = new QHBoxLayout(m_statusBarContainer);
hbox->setContentsMargins(6, 0, 6, 0);
hbox->setSpacing(6);

Expand Down Expand Up @@ -10747,10 +10803,10 @@ void MainWindow::buildUI()
radioVbox->setSpacing(0);
radioVbox->setAlignment(Qt::AlignVCenter);
m_radioInfoLabel = new QLabel("");
AetherSDR::ThemeManager::instance().applyStyleSheet(m_radioInfoLabel, "QLabel { color: {{color.text.secondary}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(m_radioInfoLabel, QStringLiteral("{{color.text.secondary}}"));
m_radioInfoLabel->setAlignment(Qt::AlignCenter);
m_radioVersionLabel = new QLabel("");
AetherSDR::ThemeManager::instance().applyStyleSheet(m_radioVersionLabel, "QLabel { color: {{color.text.secondary}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(m_radioVersionLabel, QStringLiteral("{{color.text.secondary}}"));
m_radioVersionLabel->setAlignment(Qt::AlignCenter);
radioVbox->addWidget(m_radioInfoLabel);
radioVbox->addWidget(m_radioVersionLabel);
Expand All @@ -10763,6 +10819,8 @@ void MainWindow::buildUI()
AetherSDR::ThemeManager::instance().applyStyleSheet(m_stationNickLabel, "QLabel { color: {{color.text.primary}}; font-size: 21px; background: {{color.background.0}}; "
"border: 1px solid rgba(255,255,255,128); padding: 2px 12px; }");
m_stationNickLabel->setAlignment(Qt::AlignCenter);
m_stationNickLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
setStatusBarStationText(m_stationNickLabel, m_stationNickLabel->text());
m_stationNickLabel->setCursor(Qt::PointingHandCursor);
m_stationNickLabel->setToolTip("Double-click to connect/disconnect");
m_stationNickLabel->installEventFilter(this);
Expand All @@ -10784,10 +10842,10 @@ void MainWindow::buildUI()
gpsVbox->setSpacing(0);
gpsVbox->setAlignment(Qt::AlignVCenter);
m_gpsLabel = new QLabel("");
AetherSDR::ThemeManager::instance().applyStyleSheet(m_gpsLabel, "QLabel { color: {{color.text.secondary}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(m_gpsLabel, QStringLiteral("{{color.text.secondary}}"));
m_gpsLabel->setAlignment(Qt::AlignCenter);
m_gpsStatusLabel = new QLabel("");
AetherSDR::ThemeManager::instance().applyStyleSheet(m_gpsStatusLabel, "QLabel { color: {{color.text.secondary}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(m_gpsStatusLabel, QStringLiteral("{{color.text.secondary}}"));
m_gpsStatusLabel->setAlignment(Qt::AlignCenter);
gpsVbox->addWidget(m_gpsLabel);
gpsVbox->addWidget(m_gpsStatusLabel);
Expand All @@ -10804,11 +10862,11 @@ void MainWindow::buildUI()
cpuVbox->setSpacing(0);
cpuVbox->setAlignment(Qt::AlignVCenter);
m_cpuLabel = new QLabel("CPU: \u2014");
AetherSDR::ThemeManager::instance().applyStyleSheet(m_cpuLabel, "QLabel { color: {{color.text.secondary}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(m_cpuLabel, QStringLiteral("{{color.text.secondary}}"));
m_cpuLabel->setAlignment(Qt::AlignCenter);
m_cpuLabel->setToolTip("AetherSDR process CPU usage");
m_memLabel = new QLabel("Mem: \u2014");
AetherSDR::ThemeManager::instance().applyStyleSheet(m_memLabel, "QLabel { color: {{color.text.label}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(m_memLabel, QStringLiteral("{{color.text.label}}"));
m_memLabel->setAlignment(Qt::AlignCenter);
#if defined(Q_OS_WIN)
m_memLabel->setToolTip("AetherSDR process working set (matches Task Manager)");
Expand Down Expand Up @@ -10870,7 +10928,7 @@ void MainWindow::buildUI()
if (cpuPct >= 80.0) color = "#e05050";
else if (cpuPct >= 50.0) color = "#f0c040";
m_cpuLabel->setText(QString("CPU: %1%").arg(cpuPct, 0, 'f', 1));
m_cpuLabel->setStyleSheet(QString("QLabel { color: %1; font-size: 12px; }").arg(color));
applyStatusBarCompactLabelStyle(m_cpuLabel, color);
}

// Memory: report the "what the OS sees right now" footprint, not the
Expand Down Expand Up @@ -10923,13 +10981,13 @@ void MainWindow::buildUI()
paVbox->setSpacing(0);
paVbox->setAlignment(Qt::AlignVCenter);
m_paTempLabel = new QLabel("");
AetherSDR::ThemeManager::instance().applyStyleSheet(m_paTempLabel, "QLabel { color: {{color.text.secondary}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(m_paTempLabel, QStringLiteral("{{color.text.secondary}}"));
m_paTempLabel->setAlignment(Qt::AlignCenter);
m_paTempLabel->setCursor(Qt::PointingHandCursor);
m_paTempLabel->installEventFilter(this);
updatePaTempLabel();
m_supplyVoltLabel = new QLabel("");
AetherSDR::ThemeManager::instance().applyStyleSheet(m_supplyVoltLabel, "QLabel { color: {{color.text.label}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(m_supplyVoltLabel, QStringLiteral("{{color.text.label}}"));
m_supplyVoltLabel->setAlignment(Qt::AlignCenter);
paVbox->addWidget(m_paTempLabel);
paVbox->addWidget(m_supplyVoltLabel);
Expand All @@ -10946,11 +11004,11 @@ void MainWindow::buildUI()
netVbox->setSpacing(0);
netVbox->setAlignment(Qt::AlignVCenter);
auto* netTitle = new QLabel("Network:");
AetherSDR::ThemeManager::instance().applyStyleSheet(netTitle, "QLabel { color: {{color.text.secondary}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(netTitle, QStringLiteral("{{color.text.secondary}}"));
netTitle->setAlignment(Qt::AlignCenter);
netVbox->addWidget(netTitle);
m_networkLabel = new QLabel("");
AetherSDR::ThemeManager::instance().applyStyleSheet(m_networkLabel, "QLabel { color: {{color.text.label}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(m_networkLabel, QStringLiteral("{{color.text.label}}"));
m_networkLabel->setTextFormat(Qt::RichText);
m_networkLabel->setAlignment(Qt::AlignCenter);
m_networkLabel->setToolTip(buildNetworkTooltip(m_radioModel));
Expand Down Expand Up @@ -11066,18 +11124,19 @@ void MainWindow::buildUI()
timeVbox->setSpacing(0);
timeVbox->setAlignment(Qt::AlignVCenter);
m_gpsDateLabel = new QLabel("");
AetherSDR::ThemeManager::instance().applyStyleSheet(m_gpsDateLabel, "QLabel { color: {{color.text.secondary}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(m_gpsDateLabel, QStringLiteral("{{color.text.secondary}}"));
m_gpsDateLabel->setAlignment(Qt::AlignCenter);
m_gpsDateLabel->setMinimumWidth(kTelemetryStackMinWidth);
m_gpsTimeLabel = new QLabel("");
AetherSDR::ThemeManager::instance().applyStyleSheet(m_gpsTimeLabel, "QLabel { color: {{color.text.secondary}}; font-size: 12px; }");
applyStatusBarCompactLabelStyle(m_gpsTimeLabel, QStringLiteral("{{color.text.secondary}}"));
m_gpsTimeLabel->setAlignment(Qt::AlignCenter);
m_gpsTimeLabel->setMinimumWidth(kTelemetryStackMinWidth);
timeVbox->addWidget(m_gpsDateLabel);
timeVbox->addWidget(m_gpsTimeLabel);
hbox->addWidget(timeStack);

statusBar()->addWidget(container, 1);
statusBar()->addWidget(m_statusBarContainer, 1);
updateStatusBarMinimumWidth();
updateBandStackIndicator();

// S History Markers expiry — sweeps stale detections once per second
Expand Down Expand Up @@ -11275,7 +11334,8 @@ void MainWindow::onConnectionStateChanged(bool connected)
m_layoutRestoreUntilMs = kPanLayoutRestoreWaitingForFirstPan;
m_radioInfoLabel->setText(m_radioModel.model());
m_radioVersionLabel->setText(m_radioModel.version());
m_stationLabel->setText(m_radioModel.nickname());
setStatusBarStationText(m_stationLabel, m_radioModel.nickname());
updateStatusBarMinimumWidth();
m_connStatusLabel->setText("Connected");
m_connPanel->setStatusText("Connected");

Expand Down Expand Up @@ -11560,7 +11620,8 @@ void MainWindow::onConnectionStateChanged(bool connected)
m_connStatusLabel->setText("Disconnected");
m_radioInfoLabel->setText("");
m_radioVersionLabel->setText("");
m_stationLabel->setText("N0CALL");
setStatusBarStationText(m_stationLabel, QStringLiteral("N0CALL"));
updateStatusBarMinimumWidth();
AetherSDR::ThemeManager::instance().applyStyleSheet(m_tnfIndicator, "QLabel { color: {{color.background.2}}; font-weight: bold; font-size: 24px; }");
m_tnfIndicator->setToolTip(buildTnfTooltip(m_radioModel.tnfModel()));
if (auto* bandStackPanel = m_panStack ? m_panStack->bandStackPanel() : nullptr) {
Expand All @@ -11581,6 +11642,7 @@ void MainWindow::onConnectionStateChanged(bool connected)
m_pgxlConn.disconnect();
m_pgxlContainer->setVisible(false);
m_pgxlSeparator->setVisible(false);
updateStatusBarMinimumWidth();
m_txIndicator->setStyleSheet("QLabel { color: rgba(255,255,255,128); font-weight: bold; font-size: 21px; }");
m_txIndicator->setText("TX");
m_connPanel->setStatusText("Not connected");
Expand Down Expand Up @@ -15765,6 +15827,7 @@ void MainWindow::toggleMinimalMode(bool on)
// Restore title bar and status bar
m_titleBar->setMinimalMode(false);
statusBar()->show();
updateStatusBarMinimumWidth();

// Restore full geometry
QByteArray geom = QByteArray::fromBase64(
Expand Down
2 changes: 2 additions & 0 deletions src/gui/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ private slots:
void buildUI();
void buildMenuBar();
void applyDarkTheme();
void updateStatusBarMinimumWidth();

// Audio thread helpers — invoke AudioEngine methods on the worker thread (#502)
void audioStartRx();
Expand Down Expand Up @@ -762,6 +763,7 @@ private slots:
QLabel* m_txIndicator{nullptr};
QLabel* m_gpsDateLabel{nullptr};
QLabel* m_gpsTimeLabel{nullptr};
QWidget* m_statusBarContainer{nullptr};

// Active slice tracking for multi-slice support
int m_activeSliceId{-1};
Expand Down
Loading