| 355 | // ── Construction ────────────────────────────────────────────────────────────── |
| 356 | |
| 357 | VfoWidget::VfoWidget(QWidget* parent) |
| 358 | : QWidget(parent) |
| 359 | { |
| 360 | static bool s_a11yFactoryInstalled = false; |
| 361 | if (!s_a11yFactoryInstalled) { |
| 362 | s_a11yFactoryInstalled = true; |
| 363 | QAccessible::installFactory(vfoAccessibleFactory); |
| 364 | } |
| 365 | // Container scope — VFO flags are their own theming surface; inspector |
| 366 | // clicks should land here, not bubble up to `spectrum`. Lives under |
| 367 | // the spectrum scope so unset tokens inherit the spectrum overrides. |
| 368 | AetherSDR::theme::setContainer(this, QStringLiteral("spectrum/vfo")); |
| 369 | |
| 370 | setObjectName("VfoWidgetRoot"); |
| 371 | setMinimumWidth(WIDGET_W); |
| 372 | setMaximumWidth(WIDGET_W); |
| 373 | setAttribute(Qt::WA_TransparentForMouseEvents, false); |
| 374 | setAttribute(Qt::WA_TranslucentBackground); |
| 375 | setAutoFillBackground(false); |
| 376 | setStyleSheet(kBgStyle); |
| 377 | |
| 378 | m_signalMeterFraction = signalDbmToMeterFraction(m_signalDbm); |
| 379 | m_targetSignalMeterFraction = m_signalMeterFraction; |
| 380 | m_signalMeterAnimation.setTimerType(Qt::PreciseTimer); |
| 381 | m_signalMeterAnimation.setInterval(kSignalMeterAnimationIntervalMs); |
| 382 | connect(&m_signalMeterAnimation, &QTimer::timeout, this, &VfoWidget::animateSignalMeter); |
| 383 | |
| 384 | m_accessibleFrequencyTimer.setSingleShot(true); |
| 385 | connect(&m_accessibleFrequencyTimer, &QTimer::timeout, this, [this]() { |
| 386 | if (!QAccessible::isActive()) return; |
| 387 | if (m_pendingAccessibleFrequencyText == m_lastAccessibleFrequencyText) return; |
| 388 | m_lastAccessibleFrequencyText = m_pendingAccessibleFrequencyText; |
| 389 | QAccessibleValueChangeEvent event(m_freqLabel, m_pendingAccessibleFrequencyText); |
| 390 | QAccessible::updateAccessibility(&event); |
| 391 | }); |
| 392 | |
| 393 | buildUI(); |
| 394 | |
| 395 | // Meter view (standard S-Meter vs SmartMTR) is a global, live-updating |
| 396 | // choice owned by MeterViewController. Apply the current value, then track |
| 397 | // changes so a toggle on any flag updates this one too. Restores the |
| 398 | // persisted choice for flags opened later or after an app restart. |
| 399 | applyMeterView(MeterViewController::instance().smartMtr()); |
| 400 | connect(&MeterViewController::instance(), &MeterViewController::changed, |
| 401 | this, &VfoWidget::applyMeterView); |
| 402 | // Extremes options are also global + live: re-push to this flag's SmartMTR |
| 403 | // widget whenever any flag changes them. |
| 404 | connect(&MeterViewController::instance(), &MeterViewController::extremesChanged, |
| 405 | this, &VfoWidget::pushSmartMtrOptions); |
| 406 | // The TX-meter choice swaps the SmartMTR input (signal <-> mic) rather than |
| 407 | // its options, so re-push the input when it changes on any flag. |
| 408 | connect(&MeterViewController::instance(), &MeterViewController::txMeterChanged, |
| 409 | this, &VfoWidget::pushSmartMtrInput); |
| 410 | // The pushes above update this flag's rendering; also re-seed its option |
| 411 | // CONTROLS so a change made on another open flag's selector doesn't leave |
| 412 | // this flag's checkbox/combos showing a stale value. |
| 413 | connect(&MeterViewController::instance(), &MeterViewController::extremesChanged, |
| 414 | this, &VfoWidget::syncSmartMtrSettingsControls); |
nothing calls this directly
no test coverage detected