Skip to content
Merged
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
22 changes: 21 additions & 1 deletion src/gui/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2635,6 +2635,17 @@ MainWindow::MainWindow(QWidget* parent)
connect(pan, &PanadapterModel::wideChanged,
sw, &SpectrumWidget::setWideActive);
sw->setWideActive(pan->wideActive());
connect(pan, &PanadapterModel::wnbStateChanged,
sw, &SpectrumWidget::syncWnbState,
Qt::UniqueConnection);
connect(pan, &PanadapterModel::wnbStateChanged,
sw->overlayMenu(), &SpectrumOverlayMenu::syncWnbState,
Qt::UniqueConnection);
sw->syncWnbState(pan->wnbActive(), pan->wnbLevel(),
pan->wnbUpdating());
sw->overlayMenu()->syncWnbState(pan->wnbActive(),
pan->wnbLevel(),
pan->wnbUpdating());
}
return;
}
Expand Down Expand Up @@ -10380,6 +10391,14 @@ void MainWindow::wirePanadapter(PanadapterApplet* applet)
connect(pan, &PanadapterModel::wideChanged,
sw, &SpectrumWidget::setWideActive);
sw->setWideActive(pan->wideActive());
connect(pan, &PanadapterModel::wnbStateChanged,
sw, &SpectrumWidget::syncWnbState,
Qt::UniqueConnection);
connect(pan, &PanadapterModel::wnbStateChanged,
menu, &SpectrumOverlayMenu::syncWnbState,
Qt::UniqueConnection);
sw->syncWnbState(pan->wnbActive(), pan->wnbLevel(), pan->wnbUpdating());
menu->syncWnbState(pan->wnbActive(), pan->wnbLevel(), pan->wnbUpdating());

// Route confirmed level changes (min_dbm / max_dbm) from the radio to
// this pan's spectrum widget. Using the per-pan PanadapterModel signal
Expand Down Expand Up @@ -11168,7 +11187,8 @@ void MainWindow::wirePanadapter(PanadapterApplet* applet)
this, [this, sw, applet](bool on) {
m_radioModel.sendCommand(
QString("display pan set %1 wnb=%2").arg(applet->panId()).arg(on ? 1 : 0));
sw->setWnbActive(on);
// The radio echoes WNB state, level, and normalization progress.
// Let PanadapterModel drive the spectrum indicator and related menus.
auto& s = AppSettings::instance();
s.setValue(sw->settingsKey("DisplayWnbEnabled"), on ? "True" : "False");
s.save();
Expand Down
6 changes: 6 additions & 0 deletions src/gui/SpectrumOverlayMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1263,8 +1263,14 @@ void SpectrumOverlayMenu::toggleDisplayPanel()
}

void SpectrumOverlayMenu::setWnbState(bool on, int level)
{
syncWnbState(on, level, false);
}

void SpectrumOverlayMenu::syncWnbState(bool on, int level, bool updating)
{
QSignalBlocker b1(m_wnbBtn), b2(m_wnbSlider);
Q_UNUSED(updating);
m_wnbBtn->setChecked(on);
m_wnbSlider->setValue(level);
m_wnbLabel->setText(QString::number(level));
Expand Down
1 change: 1 addition & 0 deletions src/gui/SpectrumOverlayMenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class SpectrumOverlayMenu : public QWidget {
// Connect/disconnect the ANT panel to a slice model.
void setSlice(SliceModel* slice);
void setWnbState(bool on, int level);
void syncWnbState(bool on, int level, bool updating);
void setRfGain(int gain);
void setRfGainRange(int low, int high, int step);
void syncNoiseFloorPosition(int pos);
Expand Down
117 changes: 66 additions & 51 deletions src/gui/SpectrumWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4551,13 +4551,17 @@ void SpectrumWidget::renderGpuFrame(QRhiCommandBuffer* cb)
if (m_centerMhz != m_lastDetectCenter || m_bandwidthMhz != m_lastDetectBw ||
m_refLevel != m_lastDetectRef || m_dynamicRange != m_lastDetectDyn ||
m_spectrumFrac != m_lastDetectFrac ||
m_wnbActive != m_lastDetectWnb || m_rfGainValue != m_lastDetectRfGain ||
m_wnbActive != m_lastDetectWnb ||
m_wnbUpdating != m_lastDetectWnbUpdating ||
m_rfGainValue != m_lastDetectRfGain ||
m_wideActive != m_lastDetectWide) {
markOverlayDirty();
m_lastDetectCenter = m_centerMhz; m_lastDetectBw = m_bandwidthMhz;
m_lastDetectRef = m_refLevel; m_lastDetectDyn = m_dynamicRange;
m_lastDetectFrac = m_spectrumFrac;
m_lastDetectWnb = m_wnbActive; m_lastDetectRfGain = m_rfGainValue;
m_lastDetectWnb = m_wnbActive;
m_lastDetectWnbUpdating = m_wnbUpdating;
m_lastDetectRfGain = m_rfGainValue;
m_lastDetectWide = m_wideActive;
}
}
Expand Down Expand Up @@ -4726,50 +4730,56 @@ void SpectrumWidget::renderGpuFrame(QRhiCommandBuffer* cb)
if (m_wnbActive || m_rfGainValue != 0 || showProp || m_wideActive) {
QFont indFont(p.font().family(), 14, QFont::Bold);
p.setFont(indFont);
p.setPen(QColor(0xc8, 0xd8, 0xe8, 180));
const QColor indicatorColor(0xc8, 0xd8, 0xe8, 180);
const QColor wnbDimColor(0xc8, 0xd8, 0xe8, 84);
const QFontMetrics fm(indFont);
int y = specRect.top() + fm.ascent() + 4;
// Build combined label (left to right: prop, WNB, RF gain, WIDE), right-align
QString label;
if (showProp) {
label += QString("K%1 A%2 SFI %3")
.arg(m_propKIndex, 0, 'f', 2)
.arg(m_propAIndex)
.arg(m_propSfi);
}
if (m_wnbActive) {
if (!label.isEmpty()) { label += QStringLiteral(" "); }
label += QStringLiteral("WNB");
const int y = specRect.top() + fm.ascent() + 4;
const int rightEdge = specRect.right() - DBM_STRIP_W - 8;
int x = rightEdge;
int leftEdge = rightEdge;
auto drawSegment = [&](const QString& text, const QColor& color) {
const int textWidth = fm.horizontalAdvance(text);
x -= textWidth;
leftEdge = x;
p.setPen(color);
p.drawText(x, y, text);
x -= 10;
};

if (m_wideActive) {
drawSegment(QStringLiteral("WIDE"), indicatorColor);
}
if (m_rfGainValue != 0) {
if (!label.isEmpty()) { label += QStringLiteral(" "); }
label += QStringLiteral("%1%2 dB")
.arg(m_rfGainValue > 0 ? "+" : "").arg(m_rfGainValue);
drawSegment(
QStringLiteral("%1%2 dB")
.arg(m_rfGainValue > 0 ? "+" : "")
.arg(m_rfGainValue),
indicatorColor);
}
if (m_wideActive) {
if (!label.isEmpty()) { label += QStringLiteral(" "); }
label += QStringLiteral("WIDE");
if (m_wnbActive) {
drawSegment(QStringLiteral("WNB"),
m_wnbUpdating ? wnbDimColor : indicatorColor);
}
int x = specRect.right() - DBM_STRIP_W - 8 - fm.horizontalAdvance(label);
p.drawText(x, y, label);

// Bounding rect of the full strip — used to suppress
// single-click-to-tune when clicking on these indicators (#1564).
m_indicatorStripRect = QRect(x, y - fm.ascent(),
fm.horizontalAdvance(label),
fm.height());

// Store click rect for the prop portion only
if (showProp) {
QString propText = QString("K%1 A%2 SFI %3")
const QString propText = QString("K%1 A%2 SFI %3")
.arg(m_propKIndex, 0, 'f', 2)
.arg(m_propAIndex)
.arg(m_propSfi);
int propW = fm.horizontalAdvance(propText);
const int propW = fm.horizontalAdvance(propText);
x -= propW;
leftEdge = x;
p.setPen(indicatorColor);
p.drawText(x, y, propText);
m_propClickRect = QRect(x, y - fm.ascent(), propW, fm.height());
} else {
m_propClickRect = QRect();
}

// Bounding rect of the full strip — used to suppress
// single-click-to-tune when clicking on these indicators (#1564).
m_indicatorStripRect = QRect(leftEdge, y - fm.ascent(),
rightEdge - leftEdge,
fm.height());
} else {
m_indicatorStripRect = QRect();
}
Expand Down Expand Up @@ -5413,49 +5423,54 @@ void SpectrumWidget::paintEvent(QPaintEvent* ev)
indFont.setPointSize(18);
indFont.setBold(true);
p.setFont(indFont);
p.setPen(QColor(255, 255, 255, 84));
const QColor indicatorColor(255, 255, 255, 84);
const QColor wnbActiveColor(0xc8, 0xd8, 0xe8, 180);
const QColor wnbDimColor(0xc8, 0xd8, 0xe8, 84);

const QFontMetrics fm(indFont);
const int rightEdge = specRect.right() - DBM_STRIP_W - 6;
const int topY = specRect.top() + fm.ascent() + 2;

int x = rightEdge;
int leftEdge = rightEdge;
auto drawSegment = [&](const QString& text, const QColor& color) {
const int textWidth = fm.horizontalAdvance(text);
x -= textWidth;
leftEdge = x;
p.setPen(color);
p.drawText(x, topY, text);
x -= 10;
};

// WIDE (rightmost)
if (m_wideActive) {
int ww = fm.horizontalAdvance("WIDE");
x -= ww;
p.drawText(x, topY, "WIDE");
x -= 10;
drawSegment(QStringLiteral("WIDE"), indicatorColor);
}

// RF Gain (to the left of WIDE)
if (m_rfGainValue != 0) {
QString gainStr = (m_rfGainValue > 0)
const QString gainStr = (m_rfGainValue > 0)
? QString("+%1dB").arg(m_rfGainValue)
: QString("%1dB").arg(m_rfGainValue);
int gw = fm.horizontalAdvance(gainStr);
x -= gw;
p.drawText(x, topY, gainStr);
x -= 10; // gap between labels
drawSegment(gainStr, indicatorColor);
}

// WNB (to the left of RF Gain)
if (m_wnbActive) {
int ww = fm.horizontalAdvance("WNB");
x -= ww;
p.drawText(x, topY, "WNB");
x -= 10;
drawSegment(QStringLiteral("WNB"),
m_wnbUpdating ? wnbDimColor : wnbActiveColor);
}

// Prop forecast (leftmost: "K3 A12 SFI 110")
if (showProp) {
QString propStr = QString("K%1 A%2 SFI %3")
const QString propStr = QString("K%1 A%2 SFI %3")
.arg(m_propKIndex, 0, 'f', 2)
.arg(m_propAIndex)
.arg(m_propSfi);
int pw = fm.horizontalAdvance(propStr);
const int pw = fm.horizontalAdvance(propStr);
x -= pw;
leftEdge = x;
p.setPen(indicatorColor);
p.drawText(x, topY, propStr);
m_propClickRect = QRect(x, topY - fm.ascent(), pw, fm.height());
} else {
Expand All @@ -5464,8 +5479,8 @@ void SpectrumWidget::paintEvent(QPaintEvent* ev)

// Bounding rect of the full strip (prop + WNB + RF Gain + WIDE) —
// used to suppress single-click-to-tune within (#1564).
m_indicatorStripRect = QRect(x, topY - fm.ascent(),
rightEdge - x, fm.height());
m_indicatorStripRect = QRect(leftEdge, topY - fm.ascent(),
rightEdge - leftEdge, fm.height());
} else {
m_indicatorStripRect = QRect();
}
Expand Down
13 changes: 12 additions & 1 deletion src/gui/SpectrumWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,18 @@ class SpectrumWidget : public SPECTRUM_BASE_CLASS {

// WNB and RF gain state for on-screen indicators.
bool wnbActive() const { return m_wnbActive; }
bool wnbUpdating() const { return m_wnbUpdating; }
int rfGainValue() const { return m_rfGainValue; }
bool wideActive() const { return m_wideActive; }
void setWnbActive(bool on) { m_wnbActive = on; markOverlayDirty(); }
void setWnbActive(bool on) { syncWnbState(on, 0, false); }
void syncWnbState(bool on, int level, bool updating) {
Q_UNUSED(level);
if (m_wnbActive != on || m_wnbUpdating != updating) {
m_wnbActive = on;
m_wnbUpdating = updating;
markOverlayDirty();
}
}
void setRfGain(int gain) {
if (m_rfGainValue != gain) {
m_rfGainValue = gain;
Expand Down Expand Up @@ -800,6 +809,7 @@ class SpectrumWidget : public SPECTRUM_BASE_CLASS {

// On-screen indicators (WNB, RF Gain)
bool m_wnbActive{false};
bool m_wnbUpdating{false};
int m_rfGainValue{0};
bool m_wideActive{false};

Expand Down Expand Up @@ -849,6 +859,7 @@ class SpectrumWidget : public SPECTRUM_BASE_CLASS {
float m_lastDetectDyn{0};
float m_lastDetectFrac{0};
bool m_lastDetectWnb{false};
bool m_lastDetectWnbUpdating{false};
int m_lastDetectRfGain{0};
bool m_lastDetectWide{false};

Expand Down
30 changes: 26 additions & 4 deletions src/models/PanadapterModel.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "PanadapterModel.h"
#include "core/PerfTelemetry.h"
#include <QDebug>
#include <algorithm>

namespace AetherSDR {

Expand Down Expand Up @@ -79,15 +80,36 @@ void PanadapterModel::applyPanStatus(const QMap<QString, QString>& kvs)
m_preamp = pre;
}
}
// FlexLib v4.2.18 exposes wnb_updating on display pan status while the
// radio normalizes the SCU-level WNB threshold; keep it distinct from
// the per-pan WNB enable flag.
bool wnbStateDirty = false;
if (kvs.contains("wnb")) {
bool w = kvs["wnb"].toInt() != 0;
int lvl = kvs.value("wnb_level", QString::number(m_wnbLevel)).toInt();
if (w != m_wnbActive || lvl != m_wnbLevel) {
const bool w = kvs["wnb"].toInt() != 0;
if (w != m_wnbActive) {
m_wnbActive = w;
wnbStateDirty = true;
}
}
if (kvs.contains("wnb_level")) {
bool ok = false;
const int lvl = std::clamp(kvs["wnb_level"].toInt(&ok), 0, 100);
if (ok && lvl != m_wnbLevel) {
m_wnbLevel = lvl;
emit wnbChanged(m_wnbActive, m_wnbLevel);
wnbStateDirty = true;
}
}
if (kvs.contains("wnb_updating")) {
const bool updating = kvs["wnb_updating"].toInt() != 0;
if (updating != m_wnbUpdating) {
m_wnbUpdating = updating;
wnbStateDirty = true;
}
}
if (wnbStateDirty) {
emit wnbChanged(m_wnbActive, m_wnbLevel);
emit wnbStateChanged(m_wnbActive, m_wnbLevel, m_wnbUpdating);
}
if (kvs.contains("wide")) {
bool wide = kvs["wide"].toInt() != 0;
if (wide != m_wideActive) {
Expand Down
3 changes: 3 additions & 0 deletions src/models/PanadapterModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class PanadapterModel : public QObject {
void setRfGainInfo(int low, int high, int step);
bool wnbActive() const { return m_wnbActive; }
int wnbLevel() const { return m_wnbLevel; }
bool wnbUpdating() const { return m_wnbUpdating; }
bool wideActive() const { return m_wideActive; }
int fps() const { return m_fps; }
int waterfallLineDuration() const { return m_waterfallLineDuration; }
Expand Down Expand Up @@ -68,6 +69,7 @@ class PanadapterModel : public QObject {
void rfGainChanged(int gain);
void rfGainInfoChanged(int low, int high, int step);
void wnbChanged(bool active, int level);
void wnbStateChanged(bool active, int level, bool updating);
void wideChanged(bool active);
void fpsChanged(int fps);
void fpsReported(int fps);
Expand All @@ -90,6 +92,7 @@ class PanadapterModel : public QObject {
int m_rfGainHigh{32};
int m_rfGainStep{8};
bool m_wnbActive{false};
bool m_wnbUpdating{false};
bool m_wideActive{false};
int m_wnbLevel{50};
int m_fps{-1};
Expand Down
Loading