LibreVNA/Software/PC_Application/LibreVNA-GUI/CustomWidgets/tracesetselector.cpp
2022-11-09 12:33:14 +01:00

219 lines
6.4 KiB
C++

#include "tracesetselector.h"
#include <QGridLayout>
#include <QLabel>
TraceSetSelector::TraceSetSelector(QWidget *parent) :
QWidget(parent),
model(nullptr)
{
points = 0;
ports = 0;
lowerFreq = upperFreq = 0;
referenceImpedance = 50.0;
freqsSet = false;
partialSelectionAllowed = false;
setLayout(new QGridLayout);
setPorts(2);
}
TraceSetSelector::~TraceSetSelector()
{
blockSignals(true);
// this will free all created widgets
setPorts(0);
blockSignals(false);
}
unsigned int TraceSetSelector::getPorts() const
{
return ports;
}
void TraceSetSelector::setPorts(unsigned int newPorts)
{
if(!model) {
return;
}
QGridLayout *layout = static_cast<QGridLayout*>(this->layout());
if(newPorts != ports) {
ports = newPorts;
// remove the previous widgets
QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
delete child->widget();
delete child;
}
cTraces.clear();
for(unsigned int i=0;i<ports;i++) {
cTraces.push_back(std::vector<QComboBox*>());
for(unsigned int j=0;j<ports;j++) {
auto l = new QLabel("S"+QString::number(i+1)+QString::number(j+1)+":");
auto c = new QComboBox();
cTraces[i].push_back(c);
connect(c, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) {
selectionChanged(c);
});
layout->addWidget(l, i, j*2);
layout->addWidget(c, i, j*2 + 1);
}
}
}
auto availableTraces = model->getTraces();
for(unsigned int i=0;i<ports;i++) {
for(unsigned int j=0;j<ports;j++) {
auto c = cTraces[i][j];
c->blockSignals(true);
c->clear();
// create possible trace selections
c->addItem("None");
for(auto t : availableTraces) {
if(t->getDataType() != Trace::DataType::Frequency) {
// can only add frequency traces
continue;
}
if(i == j && !t->isReflection()) {
// can not add through measurement at reflection port
continue;
} else if(i != j && t->isReflection()) {
// can not add reflection measurement at through port
continue;
}
c->addItem(t->name(), QVariant::fromValue<Trace*>(t));
}
c->blockSignals(false);
}
}
emit selectionChanged();
}
bool TraceSetSelector::setTrace(unsigned int destPort, unsigned int srcPort, Trace *t)
{
if(destPort < 1 || destPort > ports || srcPort < 1 || srcPort > ports) {
// invalid port selection
return false;
}
auto c = cTraces[destPort-1][srcPort-1];
// find required trace
for(unsigned int i=1;i<(unsigned int) c->count();i++) {
if(qvariant_cast<Trace*>(c->itemData(i)) == t) {
c->setCurrentIndex(i);
return true;
}
}
// requested trace not found, unable to set
return false;
}
Trace *TraceSetSelector::getTrace(unsigned int destPort, unsigned int srcPort)
{
if(destPort < 1 || destPort > ports || srcPort < 1 || srcPort > ports) {
// invalid port selection
return nullptr;
}
auto c = cTraces[destPort-1][srcPort-1];
if(c->currentIndex() == 0) {
// no trace selected
return nullptr;
} else {
return qvariant_cast<Trace*>(c->itemData(c->currentIndex()));
}
}
bool TraceSetSelector::selectionValid()
{
for(unsigned int i=1;i<=ports;i++) {
for(unsigned int j=1;j<=ports;j++) {
auto t = getTrace(i, j);
if(!t && !partialSelectionAllowed) {
// at least one trace is missing
return false;
}
if(t && partialSelectionAllowed) {
// at least one trace is present
return true;
}
}
}
// if we get here, either:
// - all traces are valid and partial selection is not allowed -> whole selection valid
// or:
// - all traces are invalid and partial selection is allowed -> whole selection invalid
return !partialSelectionAllowed;
}
void TraceSetSelector::selectionChanged(QComboBox *c)
{
if(c->currentIndex() != 0 && !freqsSet) {
// the first trace has been selected, extract frequency info
Trace *t = qvariant_cast<Trace*>(c->itemData(c->currentIndex()));
points = t->size();
referenceImpedance = t->getReferenceImpedance();
if(points > 0) {
lowerFreq = t->minX();
upperFreq = t->maxX();
}
freqsSet = true;
// remove all trace options with incompatible frequencies
for(auto v1 : cTraces) {
for(auto c : v1) {
for(int i=1;i<c->count();i++) {
Trace *t = qvariant_cast<Trace*>(c->itemData(i));
if(t->getReferenceImpedance() != referenceImpedance || t->size() != points || (points > 0 && (t->minX() != lowerFreq || t->maxX() != upperFreq))) {
// this trace is not available anymore
c->removeItem(i);
// decrement to check the next index in the next loop iteration
i--;
}
}
}
}
} else if(c->currentIndex() == 0 && freqsSet) {
// Check if all trace selections are set for none
for(auto v1 : cTraces) {
for(auto c : v1) {
if(c->currentIndex() != 0) {
// some trace is still selected, abort
emit selectionChanged();
return;
}
}
}
// all traces set for none
freqsSet = false;
setPorts(ports);
}
emit selectionChanged();
}
double TraceSetSelector::getReferenceImpedance() const
{
return referenceImpedance;
}
double TraceSetSelector::getUpperFreq() const
{
return upperFreq;
}
double TraceSetSelector::getLowerFreq() const
{
return lowerFreq;
}
unsigned int TraceSetSelector::getPoints() const
{
return points;
}
void TraceSetSelector::setModel(TraceModel *newModel)
{
model = newModel;
}
void TraceSetSelector::setPartialSelectionAllowed(bool newPartialSelectionAllowed)
{
partialSelectionAllowed = newPartialSelectionAllowed;
}