#include "spectrumscope.h" #include "logcategories.h" #include "rigidentities.h" spectrumScope::spectrumScope(QWidget *parent) : QGroupBox{parent} { QMutexLocker locker(&mutex); this->setObjectName("Spectrum Scope"); this->setTitle("Band"); queue = cachingQueue::getInstance(); spectrum = new QCustomPlot(); layout = new QVBoxLayout(this); splitter = new QSplitter(this); layout->addWidget(splitter); splitter->setOrientation(Qt::Vertical); controlLayout = new QHBoxLayout(); enableCheckBox = new QCheckBox("Enable"); enableCheckBox->setTristate(true); enableCheckBox->setToolTip("Checked=WF enable, Unchecked=WF disable, Partial=Enable WF but no local display"); enableCheckBox->setCheckState(Qt::CheckState::Checked); //scopeModeLabel = new QLabel("Spectrum Mode:"); scopeModeCombo = new QComboBox(); scopeModeCombo->setAccessibleDescription("Spectrum Mode"); //spanLabel = new QLabel("Span:"); spanCombo = new QComboBox(); spanCombo->setAccessibleDescription("Spectrum Span"); spanCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); //edgeLabel = new QLabel("Edge:"); edgeCombo = new QComboBox(); edgeCombo->setAccessibleDescription("Spectrum Edge"); edgeButton = new QPushButton("Custom Edge"); edgeButton->setToolTip("Define a custom (fixed) scope edge"); toFixedButton = new QPushButton("To Fixed"); toFixedButton->setToolTip("<html><head/><body><p>Press button to convert center mode spectrum to fixed mode, preserving the range. This allows you to tune without the spectrum moving, in the same currently-visible range that you see now. </p><p><br/></p><p>The currently-selected edge slot will be overridden.</p></body></html>"); holdButton = new QPushButton("HOLD"); holdButton->setCheckable(true); holdButton->setFocusPolicy(Qt::NoFocus); controlSpacer = new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Fixed); midSpacer = new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Fixed); clearPeaksButton = new QPushButton("Clear Peaks"); configButton = new QPushButton("Conf"); configButton->setAccessibleName("Configure Scope"); configButton->setAccessibleDescription("Change various settings of the current Scope"); configButton->setToolTip("Configure Scope"); modeCombo = new QComboBox(); dataCombo = new QComboBox(); filterCombo = new QComboBox(); spanCombo->setVisible(false); edgeCombo->setVisible(false); edgeButton->setVisible(false); toFixedButton->setVisible(false); spectrum = new QCustomPlot(); waterfall = new QCustomPlot(); splitter->addWidget(spectrum); splitter->addWidget(waterfall); splitter->setHandleWidth(5); spectrum->axisRect()->setMargins(QMargins(0,0,0,0)); waterfall->axisRect()->setMargins(QMargins(0,0,0,0)); layout->addLayout(controlLayout); controlLayout->addWidget(enableCheckBox); controlLayout->addWidget(scopeModeCombo); controlLayout->addWidget(spanCombo); controlLayout->addWidget(edgeCombo); controlLayout->addWidget(edgeButton); controlLayout->addWidget(toFixedButton); controlLayout->addWidget(holdButton); controlLayout->addSpacerItem(controlSpacer); controlLayout->addWidget(modeCombo); controlLayout->addWidget(dataCombo); controlLayout->addWidget(filterCombo); controlLayout->addSpacerItem(midSpacer); controlLayout->addWidget(clearPeaksButton); controlLayout->addWidget(configButton); this->layout->setContentsMargins(5,5,5,5); scopeModeCombo->addItem("Center Mode", (spectrumMode_t)spectModeCenter); scopeModeCombo->addItem("Fixed Mode", (spectrumMode_t)spectModeFixed); scopeModeCombo->addItem("Scroll-C", (spectrumMode_t)spectModeScrollC); scopeModeCombo->addItem("Scroll-F", (spectrumMode_t)spectModeScrollF); scopeModeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); edgeCombo->insertItems(0, QStringList({"Fixed Edge 1","Fixed Edge 2","Fixed Edge 3","Fixed Edge 4"})); //edgeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); // Spectrum Plot setup passbandIndicator = new QCPItemRect(spectrum); passbandIndicator->setAntialiased(true); passbandIndicator->setPen(QPen(Qt::red)); passbandIndicator->setBrush(QBrush(Qt::red)); passbandIndicator->setSelectable(true); pbtIndicator = new QCPItemRect(spectrum); pbtIndicator->setAntialiased(true); pbtIndicator->setPen(QPen(Qt::red)); pbtIndicator->setBrush(QBrush(Qt::red)); pbtIndicator->setSelectable(true); pbtIndicator->setVisible(false); freqIndicatorLine = new QCPItemLine(spectrum); freqIndicatorLine->setAntialiased(true); freqIndicatorLine->setPen(QPen(Qt::blue)); oorIndicator = new QCPItemText(spectrum); oorIndicator->setVisible(false); oorIndicator->setAntialiased(true); oorIndicator->setPen(QPen(Qt::red)); oorIndicator->setBrush(QBrush(Qt::red)); oorIndicator->setFont(QFont(font().family(), 14)); oorIndicator->setPositionAlignment(Qt::AlignVCenter | Qt::AlignHCenter); oorIndicator->position->setType(QCPItemPosition::ptAxisRectRatio); // Positioned relative to the current plot rect oorIndicator->setText("SCOPE OUT OF RANGE"); oorIndicator->position->setCoords(0.5f,0.5f); ovfIndicator = new QCPItemText(spectrum); ovfIndicator->setVisible(false); ovfIndicator->setAntialiased(true); ovfIndicator->setPen(QPen(Qt::red)); ovfIndicator->setColor(Qt::red); ovfIndicator->setFont(QFont(font().family(), 10)); ovfIndicator->setPositionAlignment(Qt::AlignLeft | Qt::AlignTop); ovfIndicator->position->setType(QCPItemPosition::ptAxisRectRatio); // Positioned relative to the current plot rect ovfIndicator->setText(" OVF "); ovfIndicator->position->setCoords(0.01f,0.0f); spectrum->addGraph(); // primary spectrum->addGraph(0, 0); // secondary, peaks, same axis as first. spectrum->addLayer( "Top Layer", spectrum->layer("main")); spectrum->graph(0)->setLayer("Top Layer"); QColor color(20+200/4.0*1,70*(1.6-1/4.0), 150, 150); spectrum->graph(1)->setLineStyle(QCPGraph::lsLine); spectrum->graph(1)->setPen(QPen(color.lighter(200))); spectrum->graph(1)->setBrush(QBrush(color)); freqIndicatorLine->start->setCoords(0.5, 0); freqIndicatorLine->end->setCoords(0.5, 160); passbandIndicator->topLeft->setCoords(0.5, 0); passbandIndicator->bottomRight->setCoords(0.5, 160); pbtIndicator->topLeft->setCoords(0.5, 0); pbtIndicator->bottomRight->setCoords(0.5, 160); // Waterfall setup waterfall->addGraph(); colorMap = new QCPColorMap(waterfall->xAxis, waterfall->yAxis); colorMapData = NULL; #if QCUSTOMPLOT_VERSION < 0x020001 this->addPlottable(colorMap); #endif connect(scopeModeCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedScopeMode(int))); connect(spanCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedSpan(int))); connect(configButton,SIGNAL(pressed()), this, SLOT(configPressed())); connect(toFixedButton,SIGNAL(pressed()), this, SLOT(toFixedPressed())); connect(edgeCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedEdge(int))); connect(edgeButton,SIGNAL(pressed()), this, SLOT(customSpanPressed())); connect(holdButton,SIGNAL(toggled(bool)), this, SLOT(holdPressed(bool))); connect(modeCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedMode(int))); connect(filterCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedMode(int))); connect(dataCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedMode(int))); connect(clearPeaksButton,SIGNAL(pressed()), this, SLOT(clearPeaks())); connect(spectrum, SIGNAL(mouseDoubleClick(QMouseEvent*)), this, SLOT(doubleClick(QMouseEvent*))); connect(waterfall, SIGNAL(mouseDoubleClick(QMouseEvent*)), this, SLOT(doubleClick(QMouseEvent*))); connect(spectrum, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(scopeClick(QMouseEvent*))); connect(waterfall, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(waterfallClick(QMouseEvent*))); connect(spectrum, SIGNAL(mouseRelease(QMouseEvent*)), this, SLOT(scopeMouseRelease(QMouseEvent*))); connect(spectrum, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(scopeMouseMove(QMouseEvent *))); connect(waterfall, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(scroll(QWheelEvent*))); connect(spectrum, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(scroll(QWheelEvent*))); showHideControls(spectrumMode_t::spectModeCenter); } void spectrumScope::prepareScope(uint maxAmp, uint spectWidth) { this->spectWidth = spectWidth; this->maxAmp = maxAmp; } bool spectrumScope::prepareWf(uint wf) { QMutexLocker locker(&mutex); bool ret=true; this->wfLength = wf; this->wfLengthMax = 1024; // Initialize before use! QByteArray empty((int)spectWidth, '\x01'); spectrumPeaks = QByteArray( (int)spectWidth, '\x01' ); //unsigned int oldSize = wfimage.size(); if (!wfimage.empty() && wfimage.first().size() != spectWidth) { // Width of waterfall has changed! wfimage.clear(); } for(unsigned int i = wfimage.size(); i < wfLength; i++) { wfimage.append(empty); } wfimage.remove(wfLength, wfimage.size()-wfLength); wfimage.squeeze(); colorMap->data()->clear(); colorMap->data()->setValueRange(QCPRange(0, wfLength-1)); colorMap->data()->setKeyRange(QCPRange(0, spectWidth-1)); colorMap->setDataRange(QCPRange(plotFloor, plotCeiling)); colorMap->setGradient(static_cast(currentTheme)); if(colorMapData != Q_NULLPTR) { delete colorMapData; } colorMapData = new QCPColorMapData(spectWidth, wfLength, QCPRange(0, spectWidth-1), QCPRange(0, wfLength-1)); colorMap->setData(colorMapData,true); // Copy the colorMap so deleting it won't result in crash! waterfall->yAxis->setRangeReversed(true); waterfall->xAxis->setVisible(false); scopePrepared = true; return ret; } void spectrumScope::setRange(int floor, int ceiling) { maxAmp = ceiling; if (spectrum != Q_NULLPTR) spectrum->yAxis->setRange(QCPRange(floor, ceiling)); if (colorMap != Q_NULLPTR) colorMap->setDataRange(QCPRange(floor,ceiling)); } void spectrumScope::colorPreset(colorPrefsType *cp) { if (cp == Q_NULLPTR) { return; } colors = *cp; spectrum->setBackground(cp->plotBackground); spectrum->xAxis->grid()->setPen(cp->gridColor); spectrum->yAxis->grid()->setPen(cp->gridColor); spectrum->legend->setTextColor(cp->textColor); spectrum->legend->setBorderPen(cp->gridColor); spectrum->legend->setBrush(cp->gridColor); spectrum->xAxis->setTickLabelColor(cp->textColor); spectrum->xAxis->setLabelColor(cp->gridColor); spectrum->yAxis->setTickLabelColor(cp->textColor); spectrum->yAxis->setLabelColor(cp->gridColor); spectrum->xAxis->setBasePen(cp->axisColor); spectrum->xAxis->setTickPen(cp->axisColor); spectrum->yAxis->setBasePen(cp->axisColor); spectrum->yAxis->setTickPen(cp->axisColor); freqIndicatorLine->setPen(QPen(cp->tuningLine)); passbandIndicator->setPen(QPen(cp->passband)); passbandIndicator->setBrush(QBrush(cp->passband)); pbtIndicator->setPen(QPen(cp->pbt)); pbtIndicator->setBrush(QBrush(cp->pbt)); spectrum->graph(0)->setPen(QPen(cp->spectrumLine)); spectrum->graph(0)->setBrush(QBrush(cp->spectrumFill)); spectrum->graph(1)->setPen(QPen(cp->underlayLine)); spectrum->graph(1)->setBrush(QBrush(cp->underlayFill)); waterfall->yAxis->setBasePen(cp->wfAxis); waterfall->yAxis->setTickPen(cp->wfAxis); waterfall->xAxis->setBasePen(cp->wfAxis); waterfall->xAxis->setTickPen(cp->wfAxis); waterfall->xAxis->setLabelColor(cp->wfGrid); waterfall->yAxis->setLabelColor(cp->wfGrid); waterfall->xAxis->setTickLabelColor(cp->wfText); waterfall->yAxis->setTickLabelColor(cp->wfText); waterfall->setBackground(cp->wfBackground); } bool spectrumScope::update(scopeData data) { if (!scopePrepared ) { return false; } bool updateRange = false; if (data.startFreq != lowerFreq || data.endFreq != upperFreq) { if(underlayMode == underlayPeakHold) { // TODO: create non-button function to do this // This will break if the button is ever moved or renamed. clearPeaks(); } else { plasmaPrepared = false; preparePlasma(); } // Inform other threads (cluster) that the frequency range has changed. emit frequencyRange(sub, data.startFreq, data.endFreq); } lowerFreq = data.startFreq; upperFreq = data.endFreq; //qInfo(logSystem()) << "start: " << data.startFreq << " end: " << data.endFreq; quint16 specLen = data.data.length(); QVector x(spectWidth), y(spectWidth), y2(spectWidth); for(int i=0; i < spectWidth; i++) { x[i] = (i * (data.endFreq-data.startFreq)/spectWidth) + data.startFreq; } for(int i=0; i< specLen; i++) { y[i] = (unsigned char)data.data.at(i); if(underlayMode == underlayPeakHold) { if((unsigned char)data.data.at(i) > (unsigned char)spectrumPeaks.at(i)) { spectrumPeaks[i] = data.data.at(i); } y2[i] = (unsigned char)spectrumPeaks.at(i); } } plasmaMutex.lock(); spectrumPlasma.push_front(data.data); if(spectrumPlasma.size() > (int)spectrumPlasmaSize) { spectrumPlasma.pop_back(); } plasmaMutex.unlock(); QMutexLocker locker(&mutex); if ((plotFloor != oldPlotFloor) || (plotCeiling != oldPlotCeiling)){ updateRange = true; } #if QCUSTOMPLOT_VERSION < 0x020000 spectrum->graph(0)->setData(x, y); #else spectrum->graph(0)->setData(x, y, true); #endif if((freq.MHzDouble < data.endFreq) && (freq.MHzDouble > data.startFreq)) { freqIndicatorLine->start->setCoords(freq.MHzDouble, 0); freqIndicatorLine->end->setCoords(freq.MHzDouble, maxAmp); double pbStart = 0.0; double pbEnd = 0.0; switch (mode.mk) { case modeLSB: case modeRTTY: case modePSK_R: pbStart = freq.MHzDouble - passbandCenterFrequency - (passbandWidth / 2); pbEnd = freq.MHzDouble - passbandCenterFrequency + (passbandWidth / 2); break; case modeCW: if (passbandWidth < 0.0006) { pbStart = freq.MHzDouble - (passbandWidth / 2); pbEnd = freq.MHzDouble + (passbandWidth / 2); } else { pbStart = freq.MHzDouble + passbandCenterFrequency - passbandWidth; pbEnd = freq.MHzDouble + passbandCenterFrequency; } break; case modeCW_R: if (passbandWidth < 0.0006) { pbStart = freq.MHzDouble - (passbandWidth / 2); pbEnd = freq.MHzDouble + (passbandWidth / 2); } else { pbStart = freq.MHzDouble - passbandCenterFrequency; pbEnd = freq.MHzDouble + passbandWidth - passbandCenterFrequency; } break; default: pbStart = freq.MHzDouble + passbandCenterFrequency - (passbandWidth / 2); pbEnd = freq.MHzDouble + passbandCenterFrequency + (passbandWidth / 2); break; } passbandIndicator->topLeft->setCoords(pbStart, 0); passbandIndicator->bottomRight->setCoords(pbEnd, maxAmp); if ((mode.mk == modeCW || mode.mk == modeCW_R) && passbandWidth > 0.0006) { pbtDefault = round((passbandWidth - (cwPitch / 1000000.0)) * 200000.0) / 200000.0; } else { pbtDefault = 0.0; } if ((PBTInner - pbtDefault || PBTOuter - pbtDefault) && passbandAction != passbandResizing && mode.mk != modeFM) { pbtIndicator->setVisible(true); } else { pbtIndicator->setVisible(false); } /* pbtIndicator displays the intersection between PBTInner and PBTOuter */ if (mode.mk == modeLSB || mode.mk == modeCW || mode.mk == modeRTTY) { pbtIndicator->topLeft->setCoords(qMax(pbStart - (PBTInner / 2) + (pbtDefault / 2), pbStart - (PBTOuter / 2) + (pbtDefault / 2)), 0); pbtIndicator->bottomRight->setCoords(qMin(pbStart - (PBTInner / 2) + (pbtDefault / 2) + passbandWidth, pbStart - (PBTOuter / 2) + (pbtDefault / 2) + passbandWidth), maxAmp); } else { pbtIndicator->topLeft->setCoords(qMax(pbStart + (PBTInner / 2) - (pbtDefault / 2), pbStart + (PBTOuter / 2) - (pbtDefault / 2)), 0); pbtIndicator->bottomRight->setCoords(qMin(pbStart + (PBTInner / 2) - (pbtDefault / 2) + passbandWidth, pbStart + (PBTOuter / 2) - (pbtDefault / 2) + passbandWidth), maxAmp); } //qDebug() << "Default" << pbtDefault << "Inner" << PBTInner << "Outer" << PBTOuter << "Pass" << passbandWidth << "Center" << passbandCenterFrequency << "CW" << cwPitch; } #if QCUSTOMPLOT_VERSION < 0x020000 if (underlayMode == underlayPeakHold) { spectrum->graph(1)->setData(x, y2); // peaks } else if (underlayMode != underlayNone) { computePlasma(); spectrum->graph(1)->setData(x, spectrumPlasmaLine); } else { spectrum->graph(1)->setData(x, y2); // peaks, but probably cleared out } #else if (underlayMode == underlayPeakHold) { spectrum->graph(1)->setData(x, y2, true); // peaks } else if (underlayMode != underlayNone) { computePlasma(); spectrum->graph(1)->setData(x, spectrumPlasmaLine, true); } else { spectrum->graph(1)->setData(x, y2, true); // peaks, but probably cleared out } #endif if(updateRange) spectrum->yAxis->setRange(plotFloor, plotCeiling); spectrum->xAxis->setRange(data.startFreq, data.endFreq); spectrum->replot(); if(specLen == spectWidth) { wfimage.prepend(data.data); wfimage.pop_back(); QByteArray wfRow; // Waterfall: for(int row = 0; row < wfLength; row++) { wfRow = wfimage.at(row); for(int col = 0; col < spectWidth; col++) { colorMap->data()->setCell( col, row, (unsigned char)wfRow.at(col)); } } if(updateRange) { colorMap->setDataRange(QCPRange(wfFloor, wfCeiling)); } waterfall->yAxis->setRange(0,wfLength - 1); waterfall->xAxis->setRange(0, spectWidth-1); waterfall->replot(); /* #if defined (USB_CONTROLLER) // Send to USB Controllers if requested auto i = usbDevices.begin(); while (i != usbDevices.end()) { if (i.value().connected && i.value().type.model == usbDeviceType::StreamDeckPlus && i.value().lcd == funcLCDWaterfall ) { lcdImage = waterfall->toPixmap().toImage(); emit sendControllerRequest(&i.value(), usbFeatureType::featureLCD, 0, "", &lcdImage); } else if (i.value().connected && i.value().type.model == usbDeviceType::StreamDeckPlus && i.value().lcd == funcLCDSpectrum) { lcdImage = spectrum->toPixmap().toImage(); emit sendControllerRequest(&i.value(), usbFeatureType::featureLCD, 0, "", &lcdImage); } ++i; } #endif */ } oldPlotFloor = plotFloor; oldPlotCeiling = plotCeiling; if (data.oor && !oorIndicator->visible()) { oorIndicator->setVisible(true); qInfo(logSystem()) << "Scope out of range"; } else if (!data.oor && oorIndicator->visible()) { oorIndicator->setVisible(false); } return true; } // Plasma functions void spectrumScope::preparePlasma() { QMutexLocker locker(&plasmaMutex); if(plasmaPrepared) return; if(spectrumPlasmaSize == 0) spectrumPlasmaSize = 128; spectrumPlasma.clear(); spectrumPlasma.squeeze(); plasmaPrepared = true; } void spectrumScope::resizePlasmaBuffer(int size) { QMutexLocker locker(&plasmaMutex); QByteArray empty((int)spectWidth, '\x01'); int oldSize = spectrumPlasma.size(); if(oldSize < size) { spectrumPlasma.resize(size); for(int p=oldSize; p < size; p++) { spectrumPlasma.append(empty); } } else if (oldSize > size){ for(int p = oldSize; p > size; p--) { spectrumPlasma.pop_back(); } } spectrumPlasma.squeeze(); } void spectrumScope::clearPeaks() { spectrumPeaks = QByteArray( (int)spectWidth, '\x01' ); clearPlasma(); } void spectrumScope::clearPlasma() { QMutexLocker locker(&plasmaMutex); QByteArray empty((int)spectWidth, '\x01'); int pSize = spectrumPlasma.size(); for(int i=0; i < pSize; i++) { spectrumPlasma[i] = empty; } } void spectrumScope::computePlasma() { QMutexLocker locker(&plasmaMutex); spectrumPlasmaLine.clear(); spectrumPlasmaLine.resize(spectWidth); int specPlasmaSize = spectrumPlasma.size(); if(underlayMode == underlayAverageBuffer) { for(int col=0; col < spectWidth; col++) { for(int pos=0; pos < specPlasmaSize; pos++) { spectrumPlasmaLine[col] += (unsigned char)spectrumPlasma[pos][col]; } spectrumPlasmaLine[col] = spectrumPlasmaLine[col] / specPlasmaSize; } } else if (underlayMode == underlayPeakBuffer){ // peak mode, running peak display for(int col=0; col < spectWidth; col++) { for(int pos=0; pos < specPlasmaSize; pos++) { if((double)((unsigned char)spectrumPlasma[pos][col]) > spectrumPlasmaLine[col]) spectrumPlasmaLine[col] = (unsigned char)spectrumPlasma[pos][col]; } } } } void spectrumScope::showHideControls(spectrumMode_t mode) { if((mode==spectModeCenter) || (mode==spectModeScrollC)) { edgeCombo->hide(); edgeButton->hide(); toFixedButton->show(); spanCombo->show(); } else { edgeCombo->show(); edgeButton->show(); toFixedButton->hide(); spanCombo->hide(); } } void spectrumScope::enableScope(bool en) { this->splitter->setVisible(en); // Hide these controls if disabled if (!en) { this->edgeCombo->setVisible(en); this->edgeButton->setVisible(en); this->toFixedButton->setVisible(en); this->spanCombo->setVisible(en); } this->clearPeaksButton->setVisible(en); this->holdButton->setVisible(en); this->configButton->setVisible(en); } void spectrumScope::selectScopeMode(spectrumMode_t m) { scopeModeCombo->blockSignals(true); scopeModeCombo->setCurrentIndex(scopeModeCombo->findData(m)); scopeModeCombo->blockSignals(false); showHideControls(m); } void spectrumScope::selectSpan(centerSpanData s) { spanCombo->blockSignals(true); spanCombo->setCurrentIndex(spanCombo->findText(s.name)); spanCombo->blockSignals(false); } void spectrumScope::updatedScopeMode(int index) { //spectrumMode_t s = static_cast(scopeModeCombo->itemData(index).toInt()); spectrumMode_t s = scopeModeCombo->itemData(index).value(); queue->add(priorityImmediate,queueItem((sub?funcScopeSubMode:funcScopeMainMode),QVariant::fromValue(s),false,sub)); showHideControls(s); } void spectrumScope::updatedSpan(int index) { queue->add(priorityImmediate,queueItem((sub?funcScopeSubSpan:funcScopeMainSpan),spanCombo->itemData(index),false,sub)); } void spectrumScope::updatedMode(int index) { Q_UNUSED(index) // We don't know where it came from! modeInfo mi = modeCombo->currentData().value(); mi.filter = filterCombo->currentData().toInt(); mi.data = dataCombo->currentIndex(); queue->add(priorityImmediate,queueItem((sub?funcUnselectedMode:funcSelectedMode),QVariant::fromValue(mi),false,sub)); } void spectrumScope::updatedEdge(int index) { queue->add(priorityImmediate,queueItem((sub?funcScopeSubEdge:funcScopeMainEdge),QVariant::fromValue(index+1),false,sub)); } void spectrumScope::toFixedPressed() { int currentEdge = edgeCombo->currentIndex(); bool dialogOk = false; bool numOk = false; QStringList edges; edges << "1" << "2" << "3" << "4"; QString item = QInputDialog::getItem(this, "Select Edge", "Edge to replace:", edges, currentEdge, false, &dialogOk); if(dialogOk) { int edge = QString(item).toInt(&numOk,10); if(numOk) { edgeCombo->blockSignals(true); edgeCombo->setCurrentIndex(edge-1); edgeCombo->blockSignals(false); queue->add(priorityImmediate,queueItem(funcScopeFixedEdgeFreq,QVariant::fromValue(spectrumBounds(lowerFreq, upperFreq, edge)),false,sub)); queue->add(priorityImmediate,queueItem((sub?funcScopeSubMode:funcScopeMainMode),QVariant::fromValue(spectrumMode_t::spectModeFixed),false,sub)); } } } void spectrumScope::customSpanPressed() { double lowFreq = lowerFreq; double highFreq = upperFreq; QString freqstring = QString("%1, %2").arg(lowFreq).arg(highFreq); bool ok; QString userFreq = QInputDialog::getText(this, "Scope Edges", "Please enter desired scope edges, in MHz,\nwith a comma between the low and high range.", QLineEdit::Normal, freqstring, &ok); if(!ok) return; QString clean = userFreq.trimmed().replace(" ", ""); QStringList freqs = clean.split(","); if(freqs.length() == 2) { lowFreq = QString(freqs.at(0)).toDouble(&ok); if(ok) { highFreq = QString(freqs.at(1)).toDouble(&ok); if(ok) { qDebug(logGui()) << "setting edge to: " << lowFreq << ", " << highFreq << ", edge num: " << edgeCombo->currentIndex() + 1; queue->add(priorityImmediate,queueItem(funcScopeFixedEdgeFreq, QVariant::fromValue(spectrumBounds(lowFreq, highFreq, edgeCombo->currentIndex() + 1)))); return; } } goto errMsg; } else { goto errMsg; } errMsg: { QMessageBox URLmsgBox; URLmsgBox.setText("Error, could not interpret your input.\
Please make sure to place a comma between the frequencies.\
For example: '7.200, 7.300'"); URLmsgBox.exec(); return; } } void spectrumScope::doubleClick(QMouseEvent *me) { if (me->button() == Qt::LeftButton) { double x; freqt freqGo; if (!lock) { //y = plot->yAxis->pixelToCoord(me->pos().y()); x = spectrum->xAxis->pixelToCoord(me->pos().x()); freqGo.Hz = x * 1E6; freqGo.Hz = roundFrequency(freqGo.Hz, stepSize); freqGo.MHzDouble = (float)freqGo.Hz / 1E6; queue->add(priorityImmediate,queueItem((sub?funcUnselectedFreq:funcSelectedFreq),QVariant::fromValue(freqGo),false,sub)); } } else if (me->button() == Qt::RightButton) { QCPAbstractItem* item = spectrum->itemAt(me->pos(), true); QCPItemRect* rectItem = dynamic_cast (item); if (rectItem != nullptr) { double pbFreq = (pbtDefault / passbandWidth) * 127.0; qint16 newFreq = pbFreq + 128; queue->add(priorityImmediate,queueItem(funcPBTInner,QVariant::fromValue(newFreq),false,sub)); queue->add(priorityImmediate,queueItem(funcPBTOuter,QVariant::fromValue(newFreq),false,sub)); } } } void spectrumScope::scopeClick(QMouseEvent* me) { QCPAbstractItem* item = spectrum->itemAt(me->pos(), true); QCPItemText* textItem = dynamic_cast (item); QCPItemRect* rectItem = dynamic_cast (item); #if QCUSTOMPLOT_VERSION < 0x020000 int leftPix = (int)passbandIndicator->left->pixelPoint().x(); int rightPix = (int)passbandIndicator->right->pixelPoint().x(); int pbtLeftPix = (int)pbtIndicator->left->pixelPoint().x(); int pbtRightPix = (int)pbtIndicator->right->pixelPoint().x(); #else int leftPix = (int)passbandIndicator->left->pixelPosition().x(); int rightPix = (int)passbandIndicator->right->pixelPosition().x(); int pbtLeftPix = (int)pbtIndicator->left->pixelPosition().x(); int pbtRightPix = (int)pbtIndicator->right->pixelPosition().x(); #endif int pbtCenterPix = pbtLeftPix + ((pbtRightPix - pbtLeftPix) / 2); int cursor = me->pos().x(); if (me->button() == Qt::LeftButton) { this->mousePressFreq = spectrum->xAxis->pixelToCoord(cursor); if (textItem != nullptr) { QMap::iterator spot = clusterSpots.find(textItem->text()); if (spot != clusterSpots.end() && spot.key() == textItem->text()) { qInfo(logGui()) << "Clicked on spot:" << textItem->text(); freqt freqGo; freqGo.Hz = (spot.value()->frequency) * 1E6; freqGo.MHzDouble = spot.value()->frequency; queue->add(priorityImmediate,queueItem((sub?funcUnselectedFreq:funcSelectedFreq),QVariant::fromValue(freqGo),false,sub)); } } else if (passbandAction == passbandStatic && rectItem != nullptr) { if ((cursor <= leftPix && cursor > leftPix - 10) || (cursor >= rightPix && cursor < rightPix + 10)) { passbandAction = passbandResizing; } } // TODO clickdragtuning and sending messages to statusbar else if (clickDragTuning) { showStatusBarText(QString("Selected %1 MHz").arg(this->mousePressFreq)); } else { showStatusBarText(QString("Selected %1 MHz").arg(this->mousePressFreq)); } } else if (me->button() == Qt::RightButton) { if (textItem != nullptr) { QMap::iterator spot = clusterSpots.find(textItem->text()); if (spot != clusterSpots.end() && spot.key() == textItem->text()) { // parent and children are destroyed on close QDialog* spotDialog = new QDialog(); QVBoxLayout* vlayout = new QVBoxLayout; //spotDialog->setFixedSize(240, 100); spotDialog->setBaseSize(1, 1); spotDialog->setWindowTitle(spot.value()->dxcall); QLabel* dxcall = new QLabel(QString("DX:%1").arg(spot.value()->dxcall)); QLabel* spotter = new QLabel(QString("Spotter:%1").arg(spot.value()->spottercall)); QLabel* frequency = new QLabel(QString("Frequency:%1 MHz").arg(spot.value()->frequency)); QLabel* comment = new QLabel(QString("Comment:%1").arg(spot.value()->comment)); QAbstractButton* bExit = new QPushButton("Close"); vlayout->addWidget(dxcall); vlayout->addWidget(spotter); vlayout->addWidget(frequency); vlayout->addWidget(comment); vlayout->addWidget(bExit); spotDialog->setLayout(vlayout); spotDialog->show(); spotDialog->connect(bExit, SIGNAL(clicked()), spotDialog, SLOT(close())); } } else if (passbandAction == passbandStatic && rectItem != nullptr) { if (cursor <= pbtLeftPix && cursor > pbtLeftPix - 10) { passbandAction = pbtInnerMove; } else if (cursor >= pbtRightPix && cursor < pbtRightPix + 10) { passbandAction = pbtOuterMove; } else if (cursor > pbtCenterPix - 20 && cursor < pbtCenterPix + 20) { passbandAction = pbtMoving; } this->mousePressFreq = spectrum->xAxis->pixelToCoord(cursor); } } } void spectrumScope::scopeMouseRelease(QMouseEvent* me) { QCPAbstractItem* item = spectrum->itemAt(me->pos(), true); QCPItemText* textItem = dynamic_cast (item); if (textItem == nullptr && clickDragTuning) { this->mouseReleaseFreq = spectrum->xAxis->pixelToCoord(me->pos().x()); double delta = mouseReleaseFreq - mousePressFreq; qInfo(logGui()) << "Mouse release delta: " << delta; } if (passbandAction != passbandStatic) { passbandAction = passbandStatic; } } void spectrumScope::scopeMouseMove(QMouseEvent* me) { QCPAbstractItem* item = spectrum->itemAt(me->pos(), true); QCPItemText* textItem = dynamic_cast (item); QCPItemRect* rectItem = dynamic_cast (item); #if QCUSTOMPLOT_VERSION < 0x020000 int leftPix = (int)passbandIndicator->left->pixelPoint().x(); int rightPix = (int)passbandIndicator->right->pixelPoint().x(); int pbtLeftPix = (int)pbtIndicator->left->pixelPoint().x(); int pbtRightPix = (int)pbtIndicator->right->pixelPoint().x(); #else int leftPix = (int)passbandIndicator->left->pixelPosition().x(); int rightPix = (int)passbandIndicator->right->pixelPosition().x(); int pbtLeftPix = (int)pbtIndicator->left->pixelPosition().x(); int pbtRightPix = (int)pbtIndicator->right->pixelPosition().x(); #endif int pbtCenterPix = pbtLeftPix + ((pbtRightPix - pbtLeftPix) / 2); int cursor = me->pos().x(); double movedFrequency = spectrum->xAxis->pixelToCoord(cursor) - mousePressFreq; if (passbandAction == passbandStatic && rectItem != nullptr) { if ((cursor <= leftPix && cursor > leftPix - 10) || (cursor >= rightPix && cursor < rightPix + 10) || (cursor <= pbtLeftPix && cursor > pbtLeftPix - 10) || (cursor >= pbtRightPix && cursor < pbtRightPix + 10)) { setCursor(Qt::SizeHorCursor); } else if (cursor > pbtCenterPix - 20 && cursor < pbtCenterPix + 20) { setCursor(Qt::OpenHandCursor); } } else if (passbandAction == passbandResizing) { static double lastFreq = movedFrequency; if (lastFreq - movedFrequency > 0.000049 || movedFrequency - lastFreq > 0.000049) { // We are currently resizing the passband. double pb = 0.0; double origin = passbandCenterFrequency; if (mode.mk == modeLSB) { origin = - passbandCenterFrequency; } if (spectrum->xAxis->pixelToCoord(cursor) >= freq.MHzDouble + origin) { pb = spectrum->xAxis->pixelToCoord(cursor) - passbandIndicator->topLeft->coords().x(); } else { pb = passbandIndicator->bottomRight->coords().x() - spectrum->xAxis->pixelToCoord(cursor); } queue->add(priorityImmediate,queueItem(funcFilterWidth,QVariant::fromValue(pb * 1000000),false,sub)); //qInfo() << "New passband" << uint(pb * 1000000); lastFreq = movedFrequency; } } else if (passbandAction == pbtMoving) { //qint16 shift = (qint16)(level - 128); //TPBFInner = (double)(shift / 127.0) * (passbandWidth); // Only move if more than 100Hz static double lastFreq = movedFrequency; if (lastFreq - movedFrequency > 0.000049 || movedFrequency - lastFreq > 0.000049) { double innerFreq = ((double)(PBTInner + movedFrequency) / passbandWidth) * 127.0; double outerFreq = ((double)(PBTOuter + movedFrequency) / passbandWidth) * 127.0; qint16 newInFreq = innerFreq + 128; qint16 newOutFreq = outerFreq + 128; if (newInFreq >= 0 && newInFreq <= 255 && newOutFreq >= 0 && newOutFreq <= 255) { qDebug() << QString("Moving passband by %1 Hz (Inner %2) (Outer %3) Mode:%4").arg((qint16)(movedFrequency * 1000000)) .arg(newInFreq).arg(newOutFreq).arg(mode.mk); queue->add(priorityImmediate,queueItem(funcPBTInner,QVariant::fromValue(newInFreq),false,sub)); queue->add(priorityImmediate,queueItem(funcPBTOuter,QVariant::fromValue(newOutFreq),false,sub)); } lastFreq = movedFrequency; } } else if (passbandAction == pbtInnerMove) { static double lastFreq = movedFrequency; if (lastFreq - movedFrequency > 0.000049 || movedFrequency - lastFreq > 0.000049) { double pbFreq = ((double)(PBTInner + movedFrequency) / passbandWidth) * 127.0; qint16 newFreq = pbFreq + 128; if (newFreq >= 0 && newFreq <= 255) { queue->add(priorityImmediate,queueItem(funcPBTInner,QVariant::fromValue(newFreq),false,sub)); } lastFreq = movedFrequency; } } else if (passbandAction == pbtOuterMove) { static double lastFreq = movedFrequency; if (lastFreq - movedFrequency > 0.000049 || movedFrequency - lastFreq > 0.000049) { double pbFreq = ((double)(PBTOuter + movedFrequency) / passbandWidth) * 127.0; qint16 newFreq = pbFreq + 128; if (newFreq >= 0 && newFreq <= 255) { queue->add(priorityImmediate,queueItem(funcPBTOuter,QVariant::fromValue(newFreq),false,sub)); } lastFreq = movedFrequency; } } else if (passbandAction == passbandStatic && me->buttons() == Qt::LeftButton && textItem == nullptr && clickDragTuning) { double delta = spectrum->xAxis->pixelToCoord(cursor) - mousePressFreq; qDebug(logGui()) << "Mouse moving delta: " << delta; if( (( delta < -0.0001 ) || (delta > 0.0001)) && ((delta < 0.501) && (delta > -0.501)) ) { freqt freqGo; freqGo.Hz = (freq.MHzDouble + delta) * 1E6; freqGo.Hz = roundFrequency(freqGo.Hz, stepSize); freqGo.MHzDouble = (float)freqGo.Hz / 1E6; queue->add(priorityImmediate,queueItem((sub?funcUnselectedFreq:funcSelectedFreq),QVariant::fromValue(freqGo),false,sub)); } } else { setCursor(Qt::ArrowCursor); } } void spectrumScope::waterfallClick(QMouseEvent *me) { double x = spectrum->xAxis->pixelToCoord(me->pos().x()); emit showStatusBarText(QString("Selected %1 MHz").arg(x)); } void spectrumScope::scroll(QWheelEvent *we) { int clicks = we->angleDelta().y() / 120; if (!(we->angleDelta().y() / 120)) return; unsigned int stepsHz = stepSize; Qt::KeyboardModifiers key = we->modifiers(); if ((key == Qt::ShiftModifier) && (stepsHz != 1)) { stepsHz /= 10; } else if (key == Qt::ControlModifier) { stepsHz *= 10; } freqt f; f.Hz = roundFrequency(freq.Hz, clicks, stepsHz); f.MHzDouble = f.Hz / (double)1E6; freq = f; // Do we need to do this? queue->add(priorityImmediate,queueItem((sub?funcUnselectedFreq:funcSelectedFreq),QVariant::fromValue(f),false,sub)); //ui->freqLabel->setText(QString("%1").arg(f.MHzDouble, 0, 'f')); qInfo() << "Moving to freq:" << f.Hz << "step" << stepsHz; } void spectrumScope::receiveMode(modeInfo m) { // Update mode information if mode/filter/data has changed. // Not all rigs send data so this "might" need to be updated independantly? if (mode.reg != m.reg || m.filter != mode.filter || m.data != mode.data) { qInfo(logSystem()) << __func__ << QString("Received new mode for %0: %1 (%2) filter:%3 data:%4") .arg((sub?"Sub":"Main")).arg(QString::number(m.mk,16)).arg(m.name).arg(m.filter).arg(m.data) ; if (mode.mk != m.mk) { for (int i=0;icount();i++) { modeInfo mi = modeCombo->itemData(i).value(); if (mi.mk == m.mk) { modeCombo->blockSignals(true); modeCombo->setCurrentIndex(i); modeCombo->blockSignals(false); break; } } } if (m.filter && mode.filter != m.filter) { filterCombo->blockSignals(true); filterCombo->setCurrentIndex(filterCombo->findData(m.filter)); filterCombo->blockSignals(false); } if (mode.data != m.data) { dataCombo->blockSignals(true); dataCombo->setCurrentIndex(m.data); dataCombo->blockSignals(false); } if (m.mk != mode.mk) { // We have changed mode so "may" need to change regular commands passbandCenterFrequency = 0.0; // If new mode doesn't allow bandwidth control, disable filterwidth and pbt. if (m.bw) { queue->addUnique(priorityHigh,funcPBTInner,true,sub); queue->addUnique(priorityHigh,funcPBTOuter,true,sub); queue->addUnique(priorityHigh,funcFilterWidth,true,sub); } else{ queue->del(funcPBTInner,sub); queue->del(funcPBTOuter,sub); queue->del(funcFilterWidth,sub); } switch (m.mk) { case modeLSB: case modeUSB: passbandCenterFrequency = 0.0015; case modeRTTY: case modeRTTY_R: case modePSK: case modePSK_R: case modeAM: queue->del(funcCwPitch,sub); queue->del(funcDashRatio,sub); queue->del(funcKeySpeed,sub); break; case modeCW: case modeCW_R: queue->addUnique(priorityLow,funcCwPitch,true,sub); queue->addUnique(priorityLow,funcDashRatio,true,sub); queue->addUnique(priorityLow,funcKeySpeed,true,sub); break; default: // FM and digital modes are fixed width, not sure about any other modes? if (mode.filter == 1) passbandWidth = 0.015; else if (mode.filter == 2) passbandWidth = 0.010; else passbandWidth = 0.007; break; queue->del(funcCwPitch,sub); queue->del(funcDashRatio,sub); queue->del(funcKeySpeed,sub); break; } } mode = m; } } quint64 spectrumScope::roundFrequency(quint64 frequency, unsigned int tsHz) { return roundFrequency(frequency, 0, tsHz); } quint64 spectrumScope::roundFrequency(quint64 frequency, int steps, unsigned int tsHz) { if(steps > 0) { frequency = frequency + (quint64)(steps*tsHz); } else if (steps < 0) { frequency = frequency - std::min((quint64)(abs(steps)*tsHz), frequency); } quint64 rounded = frequency; if(tuningFloorZeros) { rounded = ((frequency % tsHz) > tsHz/2) ? frequency + tsHz - frequency%tsHz : frequency - frequency%tsHz; } return rounded; } void spectrumScope::receiveCwPitch(uchar pitch) { if (mode.mk == modeCW || mode.mk == modeCW_R) { quint16 p = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0; if (p != cwPitch) { passbandCenterFrequency = p / 2000000.0; qInfo(logSystem()) << QString("%0 Received new CW Pitch %1 Hz was %2 (center freq %3 MHz)").arg((sub?"Sub":"Main")).arg(p).arg(cwPitch).arg(passbandCenterFrequency); cwPitch = p; } } } void spectrumScope::receivePassband(quint16 pass) { double pb = (double)(pass / 1000000.0); if (passbandWidth != pb) { passbandWidth = pb; //trxadj->updatePassband(pass); qInfo(logSystem()) << QString("%0 Received new IF Filter/Passband %1 Hz").arg(sub?"Sub":"Main").arg(pass); emit showStatusBarText(QString("%0 IF filter width %1 Hz (%2 MHz)").arg(sub?"Sub":"Main").arg(pass).arg(passbandWidth)); } } void spectrumScope::selected(bool en) { if (en) this->setStyleSheet("QGroupBox { border:2px solid red;}"); else this->setStyleSheet("QGroupBox { border:2px solid gray;}"); } void spectrumScope::holdPressed(bool en) { queue->add(priorityImmediate,queueItem(sub?funcScopeSubHold:funcScopeMainHold,QVariant::fromValue(en),false,sub)); } void spectrumScope::setHold(bool h) { this->holdButton->blockSignals(true); this->holdButton->setChecked(h); this->holdButton->blockSignals(false); } void spectrumScope::setSpeed(uchar s) { this->currentSpeed = s; } void spectrumScope::receiveSpots(QList spots) { //QElapsedTimer timer; //timer.start(); bool current = false; if (clusterSpots.size() > 0) { current=clusterSpots.begin().value()->current; } foreach(spotData s, spots) { bool found = false; QMap::iterator spot = clusterSpots.find(s.dxcall); while (spot != clusterSpots.end() && spot.key() == s.dxcall && spot.value()->frequency == s.frequency) { spot.value()->current = !current; found = true; ++spot; } if (!found) { QCPRange xrange=spectrum->xAxis->range(); QCPRange yrange=spectrum->yAxis->range(); double left = s.frequency; double top = yrange.upper-10.0; bool conflict = true; while (conflict) { #if QCUSTOMPLOT_VERSION < 0x020000 QCPAbstractItem* absitem = spectrum->itemAt(QPointF(spectrum->xAxis->coordToPixel(left),spectrum->yAxis->coordToPixel(top)), true); #else QCPAbstractItem* absitem = spectrum->itemAt(QPointF(spectrum->xAxis->coordToPixel(left),spectrum->yAxis->coordToPixel(top)), true); #endif QCPItemText* item = dynamic_cast (absitem); if (item != nullptr) { top = top - 10.0; if (top < 10.0) { top = yrange.upper-10.0; left = left + (xrange.size()/20); } } else { conflict = false; } } spotData* sp = new spotData(s); //qDebug(logCluster()) << "ADD:" << sp->dxcall; sp->current = !current; sp->text = new QCPItemText(spectrum); sp->text->setAntialiased(true); sp->text->setColor(colors.clusterSpots); sp->text->setText(sp->dxcall); sp->text->setFont(QFont(font().family(), 10)); sp->text->setPositionAlignment(Qt::AlignVCenter | Qt::AlignHCenter); sp->text->position->setType(QCPItemPosition::ptPlotCoords); sp->text->setSelectable(true); QMargins margin; int width = (sp->text->right - sp->text->left) / 2; margin.setLeft(width); margin.setRight(width); sp->text->setPadding(margin); sp->text->position->setCoords(left, top); sp->text->setVisible(true); clusterSpots.insert(sp->dxcall, sp); } } QMap::iterator spot2 = clusterSpots.begin(); while (spot2 != clusterSpots.end()) { if (spot2.value()->current == current) { spectrum->removeItem(spot2.value()->text); //qDebug(logCluster()) << "REMOVE:" << spot2.value()->dxcall; delete spot2.value(); // Stop memory leak? spot2 = clusterSpots.erase(spot2); } else { ++spot2; } } //qDebug(logCluster()) << "Processing took" << timer.nsecsElapsed() / 1000 << "us"; } void spectrumScope::configPressed() { QDialog* configDialog = new QDialog(this); configDialog->setModal(true); QFormLayout* layout = new QFormLayout; //spotDialog->setFixedSize(240, 100); configDialog->setBaseSize(1, 1); configDialog->setWindowTitle(QString("Config %0 Scope").arg(this->sub?"Sub":"Main")); configDialog->setLayout(layout); QSlider* ref = new QSlider(Qt::Orientation::Horizontal); ref->setRange(-200,200); ref->setTickInterval(50); ref->setSingleStep(20); ref->setValue(0); ref->setAccessibleName("Scope display reference"); ref->setAccessibleDescription("Selects the display reference for the Scope display"); ref->setToolTip("Select display reference of scope"); layout->addRow("Ref",ref); QSlider* length = new QSlider(Qt::Orientation::Horizontal); length->setRange(100,1024); length->setValue(400); layout->addRow("Length",length); QSlider* top = new QSlider(Qt::Orientation::Horizontal); top->setRange(1,160); top->setValue(160); top->setAccessibleName("Scope display ceiling"); top->setAccessibleDescription("Selects the display ceiling for the Scope display"); top->setToolTip("Select display ceiling of scope"); layout->addRow("Ceiling",top); QSlider* bottom = new QSlider(Qt::Orientation::Horizontal); bottom->setRange(0,160); bottom->setValue(0); bottom->setAccessibleName("Scope display floor"); bottom->setAccessibleDescription("Selects the display floor for the Scope display"); bottom->setToolTip("Select display floor of scope"); layout->addRow("Floor",bottom); QComboBox* speed = new QComboBox(); speed->addItem("Speed Fast",QVariant::fromValue(uchar(0))); speed->addItem("Speed Mid",QVariant::fromValue(uchar(1))); speed->addItem("Speed Slow",QVariant::fromValue(uchar(2))); speed->setCurrentIndex(speed->findData(currentSpeed)); speed->setAccessibleName("Waterfall display speed"); speed->setAccessibleDescription("Selects the speed for the waterfall display"); speed->setToolTip("Waterfall Speed"); layout->addRow("Speed",speed); QComboBox* theme = new QComboBox(); theme->setAccessibleName("Waterfall display color theme"); theme->setAccessibleDescription("Selects the color theme for the waterfall display"); theme->setToolTip("Waterfall color theme"); theme->addItem("Theme Jet", QCPColorGradient::gpJet); theme->addItem("Theme Cold", QCPColorGradient::gpCold); theme->addItem("Theme Hot", QCPColorGradient::gpHot); theme->addItem("Theme Therm", QCPColorGradient::gpThermal); theme->addItem("Theme Night", QCPColorGradient::gpNight); theme->addItem("Theme Ion", QCPColorGradient::gpIon); theme->addItem("Theme Gray", QCPColorGradient::gpGrayscale); theme->addItem("Theme Geo", QCPColorGradient::gpGeography); theme->addItem("Theme Hues", QCPColorGradient::gpHues); theme->addItem("Theme Polar", QCPColorGradient::gpPolar); theme->addItem("Theme Spect", QCPColorGradient::gpSpectrum); theme->addItem("Theme Candy", QCPColorGradient::gpCandy); theme->setSizeAdjustPolicy(QComboBox::AdjustToContents); qInfo() << "Selecting theme" << currentTheme << theme->itemText(currentTheme); theme->setCurrentIndex(theme->findData(currentTheme)); layout->addRow("Theme",theme); QSlider* pbtInner = new QSlider(Qt::Orientation::Horizontal); pbtInner->setRange(0,255); double pbFreq = ((double)(this->PBTInner) / this->passbandWidth) * 127.0; qint16 newFreq = pbFreq + 128; if (newFreq >= 0 && newFreq <= 255) { pbtInner->setValue(newFreq); } layout->addRow("PBT Inner",pbtInner); QSlider* pbtOuter = new QSlider(Qt::Orientation::Horizontal); pbtOuter->setRange(0,255); pbFreq = ((double)(this->PBTOuter) / this->passbandWidth) * 127.0; newFreq = pbFreq + 128; if (newFreq >= 0 && newFreq <= 255) { pbtOuter->setValue(newFreq); } layout->addRow("PBT Outer",pbtOuter); QSlider* ifShift = new QSlider(Qt::Orientation::Horizontal); length->setRange(0,255); length->setValue(0); layout->addRow("IF Shift",ifShift); QSlider* filterWidth = new QSlider(Qt::Orientation::Horizontal); length->setRange(0,10000); length->setValue((this->passbandWidth*1E6)); layout->addRow("Fil Width",filterWidth); connect(length, &QSlider::valueChanged, configDialog, [=](const int &val) { prepareWf(val); }); connect(bottom, &QSlider::valueChanged, configDialog, [=](const int &val) { this->plotFloor = val; this->setRange(plotFloor,plotCeiling); }); connect(top, &QSlider::valueChanged, configDialog, [=](const int &val) { this->plotCeiling = val; this->setRange(plotFloor,plotCeiling); }); connect(ref, &QSlider::valueChanged, configDialog, [=](const int &val) { currentRef = (val/5) * 5; // rounded to "nearest 5" queue->add(priorityImmediate,queueItem(sub?funcScopeSubRef:funcScopeMainRef,QVariant::fromValue(currentRef),false,sub)); }); connect(speed, QOverload::of(&QComboBox::currentIndexChanged), configDialog, [=](const int &val) { queue->add(priorityImmediate,queueItem(sub?funcScopeSubSpeed:funcScopeMainSpeed,speed->itemData(val),false,sub)); }); connect(theme, QOverload::of(&QComboBox::currentIndexChanged), configDialog, [=](const int &val) { Q_UNUSED(val) currentTheme = theme->currentData().value(); colorMap->setGradient(currentTheme); emit updateTheme(sub,currentTheme); }); connect(pbtInner, &QSlider::valueChanged, configDialog, [=](const int &val) { queue->add(priorityImmediate,queueItem(funcPBTInner,QVariant::fromValue(val),false,sub)); }); connect(pbtOuter, &QSlider::valueChanged, configDialog, [=](const int &val) { queue->add(priorityImmediate,queueItem(funcPBTInner,QVariant::fromValue(val),false,sub)); }); connect(ifShift, &QSlider::valueChanged, configDialog, [=](const int &val) { queue->add(priorityImmediate,queueItem(funcIFShift,QVariant::fromValue(val),false,sub)); }); connect(filterWidth, &QSlider::valueChanged, configDialog, [=](const int &val) { queue->add(priorityImmediate,queueItem(funcFilterWidth,QVariant::fromValue(val),false,sub)); }); configDialog->show(); } void spectrumScope::wfTheme(int num) { currentTheme = QCPColorGradient::GradientPreset(num); colorMap->setGradient(static_cast(num)); }