wfview/spectrumscope.cpp

1396 wiersze
50 KiB
C++

#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);
speedCombo = new QComboBox();
speedCombo->addItem("Speed Fast",QVariant::fromValue(uchar(0)));
speedCombo->addItem("Speed Mid",QVariant::fromValue(uchar(1)));
speedCombo->addItem("Speed Slow",QVariant::fromValue(uchar(2)));
controlSpacer = new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Fixed);
midSpacer = new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Fixed);
clearPeaksButton = new QPushButton("Clear Peaks");
themeCombo = new QComboBox();
themeCombo->setAccessibleName("Waterfall display color themey");
themeCombo->setAccessibleDescription("Selects the theme for the color waterfall display");
themeCombo->setToolTip("Waterfall color theme");
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->addWidget(speedCombo);
controlLayout->addSpacerItem(controlSpacer);
controlLayout->addWidget(modeCombo);
controlLayout->addWidget(dataCombo);
controlLayout->addWidget(filterCombo);
controlLayout->addSpacerItem(midSpacer);
controlLayout->addWidget(clearPeaksButton);
controlLayout->addWidget(themeCombo);
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);
themeCombo->addItem("Theme Jet", QCPColorGradient::gpJet);
themeCombo->addItem("Theme Cold", QCPColorGradient::gpCold);
themeCombo->addItem("Theme Hot", QCPColorGradient::gpHot);
themeCombo->addItem("Theme Therm", QCPColorGradient::gpThermal);
themeCombo->addItem("Theme Night", QCPColorGradient::gpNight);
themeCombo->addItem("Theme Ion", QCPColorGradient::gpIon);
themeCombo->addItem("Theme Gray", QCPColorGradient::gpGrayscale);
themeCombo->addItem("Theme Geo", QCPColorGradient::gpGeography);
themeCombo->addItem("Theme Hues", QCPColorGradient::gpHues);
themeCombo->addItem("Theme Polar", QCPColorGradient::gpPolar);
themeCombo->addItem("Theme Spect", QCPColorGradient::gpSpectrum);
themeCombo->addItem("Theme Candy", QCPColorGradient::gpCandy);
themeCombo->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(themeCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedTheme(int)));
connect(toFixedButton,SIGNAL(pressed()), this, SLOT(toFixedPressed()));
connect(edgeCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedEdge(int)));
connect(edgeButton,SIGNAL(pressed()), this, SLOT(customSpanPressed()));
connect(speedCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedSpeed(int)));
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' );
if((unsigned int)wfimage.size() < wfLengthMax)
{
unsigned int i=0;
unsigned int oldSize = wfimage.size();
for(i=oldSize; i<(wfLengthMax); i++)
{
wfimage.append(empty);
}
}
wfimage.squeeze();
//colorMap->clearData();
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<QCPColorGradient::GradientPreset>(currentTheme));
if(colorMapData != Q_NULLPTR)
{
delete colorMapData;
}
colorMapData = new QCPColorMapData(spectWidth, wfLength, QCPRange(0, spectWidth-1), QCPRange(0, wfLength-1));
colorMap->setData(colorMapData);
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 <double> 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->themeCombo->setVisible(en);
this->clearPeaksButton->setVisible(en);
this->speedCombo->setVisible(en);
this->holdButton->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<spectrumMode_t>(scopeModeCombo->itemData(index).toInt());
spectrumMode_t s = scopeModeCombo->itemData(index).value<spectrumMode_t>();
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<modeInfo>();
mi.filter = filterCombo->currentData().toInt();
mi.data = dataCombo->currentIndex();
queue->add(priorityImmediate,queueItem((sub?funcUnselectedMode:funcSelectedMode),QVariant::fromValue(mi),false,sub));
}
void spectrumScope::updatedTheme(int index)
{
currentTheme = themeCombo->itemData(index).toInt();
colorMap->setGradient(static_cast<QCPColorGradient::GradientPreset>(currentTheme));
}
void spectrumScope::updatedEdge(int index)
{
queue->add(priorityImmediate,queueItem((sub?funcScopeSubEdge:funcScopeMainEdge),QVariant::fromValue<uchar>(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<uchar>(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.\
<br/>Please make sure to place a comma between the frequencies.\
<br/>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<freqt>(freqGo),false,sub));
}
}
else if (me->button() == Qt::RightButton)
{
QCPAbstractItem* item = spectrum->itemAt(me->pos(), true);
QCPItemRect* rectItem = dynamic_cast<QCPItemRect*> (item);
if (rectItem != nullptr)
{
double pbFreq = (pbtDefault / passbandWidth) * 127.0;
qint16 newFreq = pbFreq + 128;
queue->add(priorityImmediate,queueItem(funcPBTInner,QVariant::fromValue<ushort>(newFreq),false,sub));
queue->add(priorityImmediate,queueItem(funcPBTOuter,QVariant::fromValue<ushort>(newFreq),false,sub));
}
}
}
void spectrumScope::scopeClick(QMouseEvent* me)
{
QCPAbstractItem* item = spectrum->itemAt(me->pos(), true);
QCPItemText* textItem = dynamic_cast<QCPItemText*> (item);
QCPItemRect* rectItem = dynamic_cast<QCPItemRect*> (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<QString, spotData*>::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<freqt>(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<QString, spotData*>::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<QCPItemText*> (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<QCPItemText*> (item);
QCPItemRect* rectItem = dynamic_cast<QCPItemRect*> (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<ushort>(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<ushort>(newInFreq),false,sub));
queue->add(priorityImmediate,queueItem(funcPBTOuter,QVariant::fromValue<ushort>(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<ushort>(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<ushort>(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<freqt>(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<freqt>(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;i<modeCombo->count();i++)
{
modeInfo mi = modeCombo->itemData(i).value<modeInfo>();
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;
switch (m.mk) {
case modeLSB:
case modeUSB:
passbandCenterFrequency = 0.0015;
queue->addUnique(priorityHigh,funcPBTInner,true,sub);
queue->addUnique(priorityHigh,funcPBTOuter,true,sub);
queue->addUnique(priorityHigh,funcFilterWidth,true,sub);
queue->del(funcCwPitch,sub);
queue->del(funcDashRatio,sub);
queue->del(funcKeySpeed,sub);
break;
case modeRTTY:
case modeRTTY_R:
case modePSK:
case modePSK_R:
queue->addUnique(priorityHigh,funcPBTInner,true,sub);
queue->addUnique(priorityHigh,funcPBTOuter,true,sub);
queue->addUnique(priorityHigh,funcFilterWidth,true,sub);
queue->del(funcCwPitch,sub);
queue->del(funcDashRatio,sub);
queue->del(funcKeySpeed,sub);
break;
case modeCW:
case modeCW_R:
queue->addUnique(priorityHigh,funcPBTInner,true,sub);
queue->addUnique(priorityHigh,funcPBTOuter,true,sub);
queue->addUnique(priorityHigh,funcFilterWidth,true,sub);
queue->addUnique(priorityLow,funcCwPitch,true,sub);
queue->addUnique(priorityLow,funcDashRatio,true,sub);
queue->addUnique(priorityLow,funcKeySpeed,true,sub);
break;
case modeAM:
queue->addUnique(priorityHigh,funcPBTInner,true,sub);
queue->addUnique(priorityHigh,funcPBTOuter,true,sub);
queue->addUnique(priorityHigh,funcFilterWidth,true,sub);
queue->del(funcCwPitch,sub);
queue->del(funcDashRatio,sub);
queue->del(funcKeySpeed,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);
queue->del(funcPBTInner,sub);
queue->del(funcPBTOuter,sub);
queue->del(funcFilterWidth,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::updatedSpeed(int index)
{
queue->add(priorityImmediate,queueItem(sub?funcScopeSubSpeed:funcScopeMainSpeed,this->speedCombo->itemData(index),false,sub));
}
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->speedCombo->blockSignals(true);
this->speedCombo->setCurrentIndex(this->speedCombo->findData(s));
this->speedCombo->blockSignals(false);
}
void spectrumScope::receiveSpots(QList<spotData> 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<QString, spotData*>::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
QCPItemText* item = spectrum->itemAt<QCPItemText>(QPointF(spectrum->xAxis->coordToPixel(left),spectrum->yAxis->coordToPixel(top)), true);
#else
QCPItemText* item = spectrum->itemAt<QCPItemText>(QPointF(spectrum->xAxis->coordToPixel(left),spectrum->yAxis->coordToPixel(top)), true);
#endif
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<QString, spotData*>::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";
}