#include #include #include #include "channel/channelwebapiutils.h" #include "gui/buttonswitch.h" #include "feature/featureuiset.h" #include "ui_freqdisplaygui.h" #include "freqdisplay.h" #include "freqdisplaygui.h" namespace { constexpr const char* rxTxChannelKinds = "RT"; constexpr int pollIntervalMs = 1000; constexpr int minimumFrequencyFontPointSize = 10; } FreqDisplayGUI* FreqDisplayGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature) { return new FreqDisplayGUI(pluginAPI, featureUISet, feature); } void FreqDisplayGUI::destroy() { delete this; } void FreqDisplayGUI::resetToDefaults() { m_settings.resetToDefaults(); displaySettings(); applySettings(true); updateFrequencyText(); } QByteArray FreqDisplayGUI::serialize() const { return m_settings.serialize(); } bool FreqDisplayGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); updateFrequencyText(); return true; } resetToDefaults(); return false; } FreqDisplayGUI::FreqDisplayGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) : FeatureGUI(parent), ui(new Ui::FreqDisplayGUI), m_freqDisplay(reinterpret_cast(feature)), m_availableChannelOrFeatureHandler(QStringList(), rxTxChannelKinds), m_doApplySettings(true) { (void) pluginAPI; (void) featureUISet; m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); RollupContents *rollupContents = getRollupContents(); ui->setupUi(rollupContents); m_freqDisplay->setMessageQueueToGUI(&m_inputMessageQueue); m_settings = m_freqDisplay->getSettings(); connect( &m_availableChannelOrFeatureHandler, &AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged, this, &FreqDisplayGUI::channelsOrFeaturesChanged ); m_availableChannelOrFeatureHandler.scanAvailableChannelsAndFeatures(); connect(ui->channels, qOverload(&QComboBox::currentIndexChanged), this, &FreqDisplayGUI::on_channels_currentIndexChanged); connect(ui->fontFamily, &QFontComboBox::currentFontChanged, this, &FreqDisplayGUI::on_fontFamily_currentFontChanged); connect(ui->transparentBackground, &ButtonSwitch::toggled, this, &FreqDisplayGUI::on_transparentBackground_toggled); connect(&m_pollTimer, &QTimer::timeout, this, &FreqDisplayGUI::pollSelectedChannel); m_pollTimer.start(pollIntervalMs); displaySettings(); updateFrequencyText(); } FreqDisplayGUI::~FreqDisplayGUI() { delete ui; } void FreqDisplayGUI::setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; m_feature->setWorkspaceIndex(index); } void FreqDisplayGUI::displaySettings() { setWindowTitle(m_settings.m_title); setTitle(m_settings.m_title); // Populate font combo box with the saved font (or system default if empty) ui->fontFamily->blockSignals(true); if (!m_settings.m_fontName.isEmpty()) { ui->fontFamily->setCurrentFont(QFont(m_settings.m_fontName)); } ui->fontFamily->blockSignals(false); ui->transparentBackground->blockSignals(true); ui->transparentBackground->setChecked(m_settings.m_transparentBackground); ui->transparentBackground->blockSignals(false); applyTransparency(); updateChannelList(); } void FreqDisplayGUI::applySettings(bool force) { if (!m_doApplySettings) { return; } QStringList settingsKeys; settingsKeys.append("title"); settingsKeys.append("selectedChannel"); settingsKeys.append("workspaceIndex"); settingsKeys.append("geometryBytes"); settingsKeys.append("fontName"); settingsKeys.append("transparentBackground"); m_freqDisplay->applySettings(m_settings, settingsKeys, force); } void FreqDisplayGUI::updateChannelList() { m_availableChannels = m_availableChannelOrFeatureHandler.getAvailableChannelOrFeatureList(); ui->channels->blockSignals(true); ui->channels->clear(); int selectedIndex = -1; for (int i = 0; i < m_availableChannels.size(); ++i) { const QString longId = m_availableChannels.at(i).getLongId(); ui->channels->addItem(longId); if (longId == m_settings.m_selectedChannel) { selectedIndex = i; } } if ((selectedIndex < 0) && (m_availableChannels.size() > 0)) { selectedIndex = 0; } if (selectedIndex >= 0) { ui->channels->setCurrentIndex(selectedIndex); m_settings.m_selectedChannel = m_availableChannels.at(selectedIndex).getLongId(); } else { m_settings.m_selectedChannel.clear(); } ui->channels->blockSignals(false); } void FreqDisplayGUI::channelsOrFeaturesChanged(const QStringList& renameFrom, const QStringList& renameTo, const QStringList& removed, const QStringList& added) { (void) removed; (void) added; for (int i = 0; i < renameFrom.size() && i < renameTo.size(); ++i) { if (m_settings.m_selectedChannel == renameFrom.at(i)) { m_settings.m_selectedChannel = renameTo.at(i); } } updateChannelList(); applySettings(); updateFrequencyText(); } void FreqDisplayGUI::on_channels_currentIndexChanged(int index) { if ((index >= 0) && (index < m_availableChannels.size())) { m_settings.m_selectedChannel = m_availableChannels.at(index).getLongId(); } else { m_settings.m_selectedChannel.clear(); } applySettings(); updateFrequencyText(); } void FreqDisplayGUI::pollSelectedChannel() { updateFrequencyText(); } void FreqDisplayGUI::updateFrequencyText() { if (m_settings.m_selectedChannel.isEmpty()) { ui->frequencyValue->setText(tr("No channel selected")); updateFrequencyFont(); return; } const int channelListIndex = m_availableChannels.indexOfLongId(m_settings.m_selectedChannel); if (channelListIndex < 0) { ui->frequencyValue->setText(tr("Selected channel unavailable")); updateFrequencyFont(); return; } const auto& selectedChannel = m_availableChannels.at(channelListIndex); double centerFrequencyHz = 0.0; int offsetHz = 0; if (!ChannelWebAPIUtils::getCenterFrequency(selectedChannel.m_superIndex, centerFrequencyHz)) { ui->frequencyValue->setText(tr("Frequency unavailable")); updateFrequencyFont(); return; } if (!ChannelWebAPIUtils::getFrequencyOffset(selectedChannel.m_superIndex, selectedChannel.m_index, offsetHz)) { ui->frequencyValue->setText(tr("Offset unavailable")); updateFrequencyFont(); return; } const qint64 centerFrequency = qRound64(centerFrequencyHz); const qint64 channelOffset = static_cast(offsetHz); const qint64 absoluteFrequency = centerFrequency + channelOffset; ui->frequencyValue->setText(tr("%1 Hz").arg(QLocale().toString(absoluteFrequency))); updateFrequencyFont(); } void FreqDisplayGUI::updateFrequencyFont() { const int availableWidth = ui->frequencyValue->width(); const int availableHeight = ui->frequencyValue->height(); if (availableWidth <= 0 || availableHeight <= 0) { return; } const QString text = ui->frequencyValue->text(); if (text.isEmpty()) { return; } // Build a font with the user-chosen family (or the widget's current family if none saved) QFont font = ui->frequencyValue->font(); if (!m_settings.m_fontName.isEmpty()) { font.setFamily(m_settings.m_fontName); } // Probe at a large reference size to get accurate text dimensions, then // scale linearly to find the largest point size that fits in both directions. constexpr int probeSize = 200; font.setPointSize(probeSize); const QFontMetrics fm(font); const int textWidth = fm.horizontalAdvance(text); const int textHeight = fm.height(); if (textWidth <= 0 || textHeight <= 0) { return; } const int maxFromWidth = probeSize * availableWidth / textWidth; const int maxFromHeight = probeSize * availableHeight / textHeight; const int pointSize = qMax(minimumFrequencyFontPointSize, qMin(maxFromWidth, maxFromHeight)); font.setPointSize(pointSize); ui->frequencyValue->setFont(font); } void FreqDisplayGUI::applyTransparency() { if (m_settings.m_transparentBackground) { // Make the content area and frequency label fully transparent so that // only the text is visible over whatever is behind the window. ui->settingsContainer->setStyleSheet("background-color: transparent;"); ui->frequencyValue->setStyleSheet("background-color: transparent;"); } else { ui->settingsContainer->setStyleSheet(QString()); ui->frequencyValue->setStyleSheet(QString()); } } void FreqDisplayGUI::on_fontFamily_currentFontChanged(const QFont& font) { m_settings.m_fontName = font.family(); applySettings(); updateFrequencyFont(); } void FreqDisplayGUI::on_transparentBackground_toggled(bool checked) { m_settings.m_transparentBackground = checked; applyTransparency(); applySettings(); } void FreqDisplayGUI::resizeEvent(QResizeEvent *event) { FeatureGUI::resizeEvent(event); updateFrequencyFont(); }