mirror of
https://github.com/jankae/LibreVNA.git
synced 2026-04-06 23:13:43 +00:00
Compound device edit dialog
This commit is contained in:
parent
90ac9c57e1
commit
74e6a439af
27 changed files with 4439 additions and 8 deletions
77
Software/PC_Application/Device/compounddevice.cpp
Normal file
77
Software/PC_Application/Device/compounddevice.cpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#include "compounddevice.h"
|
||||
|
||||
CompoundDevice::CompoundDevice()
|
||||
{
|
||||
name = "";
|
||||
sync = Synchronization::USB;
|
||||
}
|
||||
|
||||
nlohmann::json CompoundDevice::toJSON()
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["name"] = name.toStdString();
|
||||
j["synchronization"] = SyncToString(sync).toStdString();
|
||||
nlohmann::json jserials;
|
||||
for(auto d : deviceSerials) {
|
||||
jserials.push_back(d.toStdString());
|
||||
}
|
||||
j["devices"] = jserials;
|
||||
nlohmann::json jmappings;
|
||||
for(auto m : portMapping) {
|
||||
nlohmann::json jmapping;
|
||||
jmapping["device"] = m.device;
|
||||
jmapping["port"] = m.port;
|
||||
jmappings.push_back(jmapping);
|
||||
}
|
||||
j["mapping"] = jmappings;
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
void CompoundDevice::fromJSON(nlohmann::json j)
|
||||
{
|
||||
name = QString::fromStdString(j.value("name", "CompoundDevice"));
|
||||
sync = SyncFromString(QString::fromStdString(j.value("synchronization", "USB")));
|
||||
deviceSerials.clear();
|
||||
if(j.contains("devices")) {
|
||||
for(auto js : j["devices"]) {
|
||||
deviceSerials.push_back(QString::fromStdString(js));
|
||||
}
|
||||
}
|
||||
portMapping.clear();
|
||||
if(j.contains("mapping")) {
|
||||
for(auto jm : j["mapping"]) {
|
||||
PortMapping mapping;
|
||||
mapping.device = jm.value("device", 0);
|
||||
mapping.port = jm.value("port", 0);
|
||||
portMapping.push_back(mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString CompoundDevice::SyncToString(CompoundDevice::Synchronization sync)
|
||||
{
|
||||
switch(sync) {
|
||||
case Synchronization::USB: return "USB";
|
||||
case Synchronization::ExtRef: return "Ext. Ref.";
|
||||
case Synchronization::Trigger: return "Trigger";
|
||||
default:
|
||||
case Synchronization::Last: return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
CompoundDevice::Synchronization CompoundDevice::SyncFromString(QString s)
|
||||
{
|
||||
for(int i=0;i<(int) Synchronization::Last;i++) {
|
||||
if(SyncToString((Synchronization)i) == s) {
|
||||
return (Synchronization) i;
|
||||
}
|
||||
}
|
||||
// default to USB
|
||||
return Synchronization::USB;
|
||||
}
|
||||
|
||||
QString CompoundDevice::getDesription()
|
||||
{
|
||||
return name + ", "+QString::number(deviceSerials.size())+" devices, "+QString::number(portMapping.size())+" ports in total";
|
||||
}
|
||||
43
Software/PC_Application/Device/compounddevice.h
Normal file
43
Software/PC_Application/Device/compounddevice.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef COMPOUNDDEVICE_H
|
||||
#define COMPOUNDDEVICE_H
|
||||
|
||||
#include "savable.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QString>
|
||||
|
||||
class CompoundDevice : public Savable
|
||||
{
|
||||
friend class CompoundDeviceEditDialog;
|
||||
public:
|
||||
CompoundDevice();
|
||||
|
||||
virtual nlohmann::json toJSON();
|
||||
virtual void fromJSON(nlohmann::json j);
|
||||
|
||||
class PortMapping {
|
||||
public:
|
||||
unsigned int device;
|
||||
unsigned int port;
|
||||
};
|
||||
|
||||
enum class Synchronization {
|
||||
USB,
|
||||
ExtRef,
|
||||
Trigger,
|
||||
Last
|
||||
};
|
||||
|
||||
static QString SyncToString(Synchronization sync);
|
||||
static Synchronization SyncFromString(QString s);
|
||||
|
||||
QString getDesription();
|
||||
|
||||
QString name;
|
||||
Synchronization sync;
|
||||
std::vector<QString> deviceSerials;
|
||||
std::vector<PortMapping> portMapping;
|
||||
};
|
||||
|
||||
#endif // COMPOUNDDEVICE_H
|
||||
548
Software/PC_Application/Device/compounddeviceeditdialog.cpp
Normal file
548
Software/PC_Application/Device/compounddeviceeditdialog.cpp
Normal file
|
|
@ -0,0 +1,548 @@
|
|||
#include "compounddeviceeditdialog.h"
|
||||
#include "ui_compounddeviceeditdialog.h"
|
||||
|
||||
#include "device.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QDrag>
|
||||
#include <QMimeData>
|
||||
#include <QMouseEvent>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
using namespace std;
|
||||
|
||||
CompoundDeviceEditDialog::CompoundDeviceEditDialog(CompoundDevice *cdev, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::CompoundDeviceEditDialog)
|
||||
{
|
||||
ldev = *cdev;
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->name, &QLineEdit::editingFinished, [=](){
|
||||
ldev.name = ui->name->text();
|
||||
checkIfOkay();
|
||||
});
|
||||
for(int i=0;i<(int)CompoundDevice::Synchronization::Last;i++) {
|
||||
ui->sync->addItem(CompoundDevice::SyncToString((CompoundDevice::Synchronization) i));
|
||||
if((CompoundDevice::Synchronization) i == CompoundDevice::Synchronization::Trigger) {
|
||||
// Disable for now
|
||||
auto *model = qobject_cast<QStandardItemModel *>(ui->sync->model());
|
||||
Q_ASSERT(model != nullptr);
|
||||
bool disabled = true;
|
||||
auto *item = model->item(i);
|
||||
item->setFlags(disabled ? item->flags() & ~Qt::ItemIsEnabled
|
||||
: item->flags() | Qt::ItemIsEnabled);
|
||||
}
|
||||
}
|
||||
connect(ui->sync, &QComboBox::currentTextChanged, [=](){
|
||||
ldev.sync = CompoundDevice::SyncFromString(ui->sync->currentText());
|
||||
updateDeviceFrames();
|
||||
});
|
||||
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, [=](){
|
||||
*cdev = ldev;
|
||||
accept();
|
||||
});
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &QDialog::reject);
|
||||
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Save), &QPushButton::clicked, [=](){
|
||||
ldev.saveToFileDialog("Save compound device", "Compound device file (*.cdev)", ".cdev");
|
||||
});
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Open), &QPushButton::clicked, [=](){
|
||||
if(ldev.openFromFileDialog("Load compound device", "Compound device file (*.cdev)")) {
|
||||
setInitialGUI();
|
||||
}
|
||||
});
|
||||
|
||||
ui->status->setStyleSheet("QLabel { color : red; }");
|
||||
|
||||
graph = new QWidget();
|
||||
ui->scrollArea->setWidget(graph);
|
||||
auto layout = new QHBoxLayout();
|
||||
graph->setLayout(layout);
|
||||
graph->setAcceptDrops(true);
|
||||
graph->setObjectName("Graph");
|
||||
graph->installEventFilter(this);
|
||||
ui->lLibreVNA1->installEventFilter(this);
|
||||
layout->setContentsMargins(0,0,0,0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
setInitialGUI();
|
||||
}
|
||||
|
||||
CompoundDeviceEditDialog::~CompoundDeviceEditDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void CompoundDeviceEditDialog::checkIfOkay()
|
||||
{
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(false);
|
||||
|
||||
if(deviceFrames.size() != ldev.deviceSerials.size()) {
|
||||
// probably still populating the GUI, skip check
|
||||
return;
|
||||
}
|
||||
|
||||
if(ldev.name.isEmpty()) {
|
||||
ui->status->setText("Name must not be empty");
|
||||
return;
|
||||
}
|
||||
if(ldev.deviceSerials.size() < 2) {
|
||||
ui->status->setText("At least two devices are required");
|
||||
return;
|
||||
}
|
||||
if(ldev.deviceSerials.size() > 4) {
|
||||
ui->status->setText("Only up to four devices supported");
|
||||
return;
|
||||
}
|
||||
// Check serials
|
||||
for(int i=0;i<ldev.deviceSerials.size();i++) {
|
||||
ldev.deviceSerials[i] = deviceFrames[i]->getSerial();
|
||||
if(ldev.deviceSerials[i].isEmpty()) {
|
||||
ui->status->setText("Device "+QString::number(i+1)+" has no serial number");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Check serials for duplicates
|
||||
for(int i=0;i<ldev.deviceSerials.size();i++) {
|
||||
for(int j=i+1;j<ldev.deviceSerials.size();j++) {
|
||||
if(ldev.deviceSerials[i] == ldev.deviceSerials[j]) {
|
||||
ui->status->setText("Duplicate serial number ("+ldev.deviceSerials[i]+") in devices "+QString::number(i+1)+" and "+QString::number(j+1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check port mapping
|
||||
// Looking for duplicate and missing ports
|
||||
bool highestPortFound = false;
|
||||
int highestPort;
|
||||
for(int port=0;port<2*ldev.deviceSerials.size();port++) {
|
||||
int num = 0;
|
||||
for(int i=0;i<deviceFrames.size();i++) {
|
||||
if(deviceFrames[i]->getPort1() == port) {
|
||||
num++;
|
||||
}
|
||||
if(deviceFrames[i]->getPort2() == port) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
if(num > 1) {
|
||||
ui->status->setText("Duplicate port "+QString::number(port+1));
|
||||
return;
|
||||
} else if(num == 0) {
|
||||
if(port == 0) {
|
||||
ui->status->setText("Port 1 must be present");
|
||||
return;
|
||||
}
|
||||
if(!highestPortFound) {
|
||||
highestPort = port;
|
||||
}
|
||||
highestPortFound = true;
|
||||
} else if(highestPortFound) {
|
||||
// port is present, but earlier port was missing
|
||||
ui->status->setText("Missing port: "+QString::number(port+1)+" is selected, but port "+QString::number(port)+" is not present.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!highestPortFound) {
|
||||
highestPort = 2*ldev.deviceSerials.size();
|
||||
}
|
||||
|
||||
// All good, actually create the port mapping
|
||||
ldev.portMapping.clear();
|
||||
for(int port=0;port<highestPort;port++) {
|
||||
CompoundDevice::PortMapping map;
|
||||
bool found = false;
|
||||
for(int i=0;i<deviceFrames.size();i++) {
|
||||
if(deviceFrames[i]->getPort1() == port) {
|
||||
found = true;
|
||||
map.device = i;
|
||||
map.port = 0;
|
||||
break;
|
||||
}
|
||||
if(deviceFrames[i]->getPort2() == port) {
|
||||
found = true;
|
||||
map.device = i;
|
||||
map.port = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
ui->status->setText("Failed to find port "+QString::number(port+1)+" (likely a bug)");
|
||||
return;
|
||||
}
|
||||
ldev.portMapping.push_back(map);
|
||||
}
|
||||
|
||||
ui->status->clear();
|
||||
|
||||
ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(true);
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
|
||||
}
|
||||
|
||||
void CompoundDeviceEditDialog::setInitialGUI()
|
||||
{
|
||||
ui->name->setText(ldev.name);
|
||||
ui->sync->setCurrentText(CompoundDevice::SyncToString(ldev.sync));
|
||||
|
||||
// Removing the old frames actually modifies the state of ldev as well. Block signals to prevent this from happening
|
||||
for(auto f : deviceFrames) {
|
||||
f->blockSignals(true);
|
||||
}
|
||||
|
||||
QHBoxLayout* layout = (QHBoxLayout*) graph->layout();
|
||||
// remove all widgets from the layout
|
||||
if (layout != NULL ) {
|
||||
QLayoutItem* item;
|
||||
while ((item = layout->takeAt(0)) != NULL ) {
|
||||
delete item->widget();
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
deviceFrames.clear();
|
||||
layout->addStretch(1);
|
||||
for(int i=0;i<ldev.deviceSerials.size();i++) {
|
||||
auto frame = new DeviceFrame(&ldev, i);
|
||||
connect(frame, &DeviceFrame::settingChanged, this, &CompoundDeviceEditDialog::checkIfOkay);
|
||||
addFrame(i, frame);
|
||||
}
|
||||
layout->addStretch(1);
|
||||
|
||||
checkIfOkay();
|
||||
}
|
||||
|
||||
DeviceFrame *CompoundDeviceEditDialog::frameAtPosition(int pos)
|
||||
{
|
||||
pos -= graph->layout()->itemAt(0)->geometry().width();
|
||||
if(pos > 0 && pos <= (int) deviceFrames.size() * frameSize) {
|
||||
return deviceFrames[pos / frameSize];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int CompoundDeviceEditDialog::findInsertPosition(int xcoord)
|
||||
{
|
||||
xcoord -= graph->layout()->itemAt(0)->geometry().width();
|
||||
// added in port 1 network
|
||||
int index = (xcoord + frameSize / 2) / frameSize;
|
||||
if(index < 0) {
|
||||
index = 0;
|
||||
} else if(index > (int) deviceFrames.size()) {
|
||||
index = deviceFrames.size();
|
||||
}
|
||||
// add 1 (first widget is always the stretch)
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
void CompoundDeviceEditDialog::addFrameAtPosition(int pos, DeviceFrame *c)
|
||||
{
|
||||
auto index = findInsertPosition(pos);
|
||||
|
||||
// add component to the deviceFrame vector
|
||||
index -= 1; // first widget is fixed
|
||||
if(index <= deviceFrames.size()) {
|
||||
addFrame(index, c);
|
||||
}
|
||||
}
|
||||
|
||||
void CompoundDeviceEditDialog::addFrame(int index, DeviceFrame *c)
|
||||
{
|
||||
if(deviceFrames.size() == ldev.deviceSerials.size()) {
|
||||
ldev.deviceSerials.insert(ldev.deviceSerials.begin() + index, "");
|
||||
}
|
||||
deviceFrames.insert(deviceFrames.begin() + index, c);
|
||||
deviceFrames[index]->setPosition(index);
|
||||
// remove from list when the component deletes itself
|
||||
connect(c, &DeviceFrame::deleted, [=](){
|
||||
removeDeviceFrame(c);
|
||||
});
|
||||
QHBoxLayout *l = static_cast<QHBoxLayout*>(graph->layout());
|
||||
l->insertWidget(index + 1, c);
|
||||
c->show();
|
||||
updateDeviceFrames();
|
||||
}
|
||||
|
||||
void CompoundDeviceEditDialog::createDragFrame(DeviceFrame *c)
|
||||
{
|
||||
QDrag *drag = new QDrag(this);
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
|
||||
QByteArray encodedPointer;
|
||||
QDataStream stream(&encodedPointer, QIODevice::WriteOnly);
|
||||
stream << quintptr(c);
|
||||
|
||||
mimeData->setData("compoundDeviceFrame/pointer", encodedPointer);
|
||||
drag->setMimeData(mimeData);
|
||||
|
||||
drag->exec(Qt::MoveAction);
|
||||
}
|
||||
|
||||
void CompoundDeviceEditDialog::updateInsertIndicator(int xcoord)
|
||||
{
|
||||
auto index = findInsertPosition(xcoord);
|
||||
QHBoxLayout *l = static_cast<QHBoxLayout*>(graph->layout());
|
||||
l->removeWidget(insertIndicator);
|
||||
l->insertWidget(index, insertIndicator);
|
||||
}
|
||||
|
||||
bool CompoundDeviceEditDialog::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
if(object->objectName() == "Graph") {
|
||||
if(event->type() == QEvent::MouseButtonPress) {
|
||||
auto mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if (mouseEvent->button() == Qt::LeftButton) {
|
||||
dragFrame = frameAtPosition(mouseEvent->pos().x());
|
||||
if(dragFrame) {
|
||||
dragStartPosition = mouseEvent->pos();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if(event->type() == QEvent::MouseMove) {
|
||||
auto mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if (!(mouseEvent->buttons() & Qt::LeftButton)) {
|
||||
return false;
|
||||
}
|
||||
if (!dragFrame) {
|
||||
return false;
|
||||
}
|
||||
if ((mouseEvent->pos() - dragStartPosition).manhattanLength()
|
||||
< QApplication::startDragDistance()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove and hide component while it is being dragged
|
||||
graph->layout()->removeWidget(dragFrame);
|
||||
dragFrame->hide();
|
||||
removeDeviceFrame(dragFrame);
|
||||
graph->update();
|
||||
|
||||
createDragFrame(dragFrame);
|
||||
return true;
|
||||
} else if(event->type() == QEvent::DragEnter) {
|
||||
auto dragEvent = static_cast<QDragEnterEvent*>(event);
|
||||
if(dragEvent->mimeData()->hasFormat("compoundDeviceFrame/pointer")) {
|
||||
dropPending = true;
|
||||
auto data = dragEvent->mimeData()->data("compoundDeviceFrame/pointer");
|
||||
QDataStream stream(&data, QIODevice::ReadOnly);
|
||||
quintptr dropPtr;
|
||||
stream >> dropPtr;
|
||||
dropFrame = (DeviceFrame*) dropPtr;
|
||||
dragEvent->acceptProposedAction();
|
||||
insertIndicator = new QWidget();
|
||||
insertIndicator->setMinimumSize(2, frameSize);
|
||||
insertIndicator->setMaximumSize(2, frameSize);
|
||||
insertIndicator->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
insertIndicator->setStyleSheet("background-color:red;");
|
||||
updateInsertIndicator(dragEvent->pos().x());
|
||||
return true;
|
||||
}
|
||||
} else if(event->type() == QEvent::DragMove) {
|
||||
auto dragEvent = static_cast<QDragMoveEvent*>(event);
|
||||
updateInsertIndicator(dragEvent->pos().x());
|
||||
return true;
|
||||
} else if(event->type() == QEvent::Drop) {
|
||||
auto dragEvent = static_cast<QDropEvent*>(event);
|
||||
delete insertIndicator;
|
||||
addFrameAtPosition(dragEvent->pos().x(), dropFrame);
|
||||
return true;
|
||||
} else if(event->type() == QEvent::DragLeave) {
|
||||
dropPending = false;
|
||||
dropFrame = nullptr;
|
||||
delete insertIndicator;
|
||||
}
|
||||
} else {
|
||||
// clicked/dragged one of the components outside of the graph
|
||||
if(event->type() == QEvent::MouseButtonPress) {
|
||||
auto mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if (mouseEvent->button() == Qt::LeftButton) {
|
||||
dragStartPosition = mouseEvent->pos();
|
||||
if(object->objectName() == "lLibreVNA1") {
|
||||
dragFrame = new DeviceFrame(&ldev, 0);
|
||||
connect(dragFrame, &DeviceFrame::settingChanged, this, &CompoundDeviceEditDialog::checkIfOkay);
|
||||
} else {
|
||||
dragFrame = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if(event->type() == QEvent::MouseMove) {
|
||||
auto mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if (!(mouseEvent->buttons() & Qt::LeftButton)) {
|
||||
return false;
|
||||
}
|
||||
if (!dragFrame) {
|
||||
return false;
|
||||
}
|
||||
if ((mouseEvent->pos() - dragStartPosition).manhattanLength()
|
||||
< QApplication::startDragDistance()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
createDragFrame(dragFrame);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CompoundDeviceEditDialog::removeDeviceFrame(DeviceFrame *dev)
|
||||
{
|
||||
auto it = std::find(deviceFrames.begin(), deviceFrames.end(), dev);
|
||||
if(it == deviceFrames.end()) {
|
||||
// not found, shouldn't happen
|
||||
return;
|
||||
}
|
||||
auto pos = it - deviceFrames.begin();
|
||||
deviceFrames.erase(it);
|
||||
ldev.deviceSerials.erase(ldev.deviceSerials.begin() + pos);
|
||||
// remove all port mappings from the removed device
|
||||
bool mappingFound;
|
||||
do {
|
||||
mappingFound = false;
|
||||
for(int i=0;i<ldev.portMapping.size();i++) {
|
||||
if(ldev.portMapping[i].device == pos) {
|
||||
mappingFound = true;
|
||||
ldev.portMapping.erase(ldev.portMapping.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(mappingFound);
|
||||
updateDeviceFrames();
|
||||
}
|
||||
|
||||
void CompoundDeviceEditDialog::updateDeviceFrames()
|
||||
{
|
||||
int i=0;
|
||||
for(auto df : deviceFrames) {
|
||||
df->setPosition(i++);
|
||||
}
|
||||
}
|
||||
|
||||
DeviceFrame::DeviceFrame(CompoundDevice *dev, int position) :
|
||||
dev(dev),
|
||||
position(position)
|
||||
{
|
||||
setMinimumSize(frameSize, frameSize);
|
||||
setMaximumSize(frameSize, frameSize);
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
setFocusPolicy(Qt::FocusPolicy::ClickFocus);
|
||||
|
||||
serial = new QComboBox();
|
||||
serial->setEditable(true);
|
||||
port1 = new QComboBox();
|
||||
port2 = new QComboBox();
|
||||
|
||||
connect(serial, &QComboBox::currentTextChanged, this, &DeviceFrame::settingChanged);
|
||||
connect(port1, &QComboBox::currentTextChanged, this, &DeviceFrame::settingChanged);
|
||||
connect(port2, &QComboBox::currentTextChanged, this, &DeviceFrame::settingChanged);
|
||||
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->addStretch(1);
|
||||
auto l1 = new QHBoxLayout;
|
||||
l1->addStretch(1);
|
||||
l1->addWidget(serial);
|
||||
l1->addStretch(1);
|
||||
layout->addLayout(l1);
|
||||
layout->addStretch(1);
|
||||
auto l2 = new QHBoxLayout;
|
||||
l2->addWidget(port1);
|
||||
l2->addStretch(1);
|
||||
l2->addWidget(port2);
|
||||
layout->addLayout(l2);
|
||||
setLayout(layout);
|
||||
|
||||
update();
|
||||
|
||||
// Set initial state
|
||||
if(position < dev->deviceSerials.size()) {
|
||||
serial->setCurrentText(dev->deviceSerials[position]);
|
||||
for(int i=0;i<dev->portMapping.size();i++) {
|
||||
if(dev->portMapping[i].device == position) {
|
||||
if(dev->portMapping[i].port == 0) {
|
||||
port1->setCurrentIndex(i + 1);
|
||||
} else if(dev->portMapping[i].port == 1) {
|
||||
port2->setCurrentIndex(i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeviceFrame::~DeviceFrame()
|
||||
{
|
||||
emit deleted();
|
||||
}
|
||||
|
||||
void DeviceFrame::setPosition(int pos)
|
||||
{
|
||||
position = pos;
|
||||
update();
|
||||
}
|
||||
|
||||
void DeviceFrame::update()
|
||||
{
|
||||
auto p1 = port1->currentText();
|
||||
auto p2 = port2->currentText();
|
||||
auto s = serial->currentText();
|
||||
port1->clear();
|
||||
port2->clear();
|
||||
serial->clear();
|
||||
|
||||
port1->addItem("Unused");
|
||||
port2->addItem("Unused");
|
||||
for(int i=0;i<dev->deviceSerials.size();i++) {
|
||||
port1->addItem("Port "+QString::number(i*2+1));
|
||||
port2->addItem("Port "+QString::number(i*2+1));
|
||||
port1->addItem("Port "+QString::number(i*2+2));
|
||||
port2->addItem("Port "+QString::number(i*2+2));
|
||||
}
|
||||
if(port1->findText(p1) >= 0) {
|
||||
port1->setCurrentText(p1);
|
||||
} else {
|
||||
port1->setCurrentIndex(0);
|
||||
}
|
||||
if(port2->findText(p2) >= 0) {
|
||||
port2->setCurrentText(p2);
|
||||
} else {
|
||||
port2->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
auto devices = Device::GetDevices();
|
||||
for(auto d : devices) {
|
||||
serial->addItem(d);
|
||||
}
|
||||
// if(!serial->findText(s) >= 0) {
|
||||
// serial->addItem(s);
|
||||
// }
|
||||
serial->setCurrentText(s);
|
||||
|
||||
if(dev->sync == CompoundDevice::Synchronization::USB) {
|
||||
setStyleSheet("image: url(:/icons/compound_V1_USB.png);");
|
||||
} else if(dev->sync == CompoundDevice::Synchronization::ExtRef) {
|
||||
if(position == 0) {
|
||||
setStyleSheet("image: url(:/icons/compound_V1_Ref_Left.png);");
|
||||
} else if(position == dev->deviceSerials.size() - 1) {
|
||||
setStyleSheet("image: url(:/icons/compound_V1_Ref_Right.png);");
|
||||
} else {
|
||||
setStyleSheet("image: url(:/icons/compound_V1_Ref_Middle.png);");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString DeviceFrame::getSerial()
|
||||
{
|
||||
return serial->currentText();
|
||||
}
|
||||
|
||||
int DeviceFrame::getPort1()
|
||||
{
|
||||
return port1->currentIndex() - 1;
|
||||
}
|
||||
|
||||
int DeviceFrame::getPort2()
|
||||
{
|
||||
return port2->currentIndex() - 1;
|
||||
}
|
||||
74
Software/PC_Application/Device/compounddeviceeditdialog.h
Normal file
74
Software/PC_Application/Device/compounddeviceeditdialog.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#ifndef COMPOUNDDEVICEEDITDIALOG_H
|
||||
#define COMPOUNDDEVICEEDITDIALOG_H
|
||||
|
||||
#include "compounddevice.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QComboBox>
|
||||
|
||||
namespace Ui {
|
||||
class CompoundDeviceEditDialog;
|
||||
}
|
||||
|
||||
class DeviceFrame : public QFrame {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DeviceFrame(CompoundDevice *dev, int position);
|
||||
~DeviceFrame();
|
||||
void setPosition(int pos);
|
||||
void update();
|
||||
QString getSerial();
|
||||
int getPort1();
|
||||
int getPort2();
|
||||
signals:
|
||||
void deleted();
|
||||
void settingChanged();
|
||||
private:
|
||||
static constexpr int frameSize = 350;
|
||||
QComboBox *serial;
|
||||
QComboBox *port1, *port2;
|
||||
QLabel *image;
|
||||
|
||||
int position;
|
||||
CompoundDevice *dev;
|
||||
};
|
||||
|
||||
class CompoundDeviceEditDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CompoundDeviceEditDialog(CompoundDevice *cdev, QWidget *parent = nullptr);
|
||||
~CompoundDeviceEditDialog();
|
||||
|
||||
private slots:
|
||||
void checkIfOkay();
|
||||
private:
|
||||
static constexpr int frameSize = 350;
|
||||
void setInitialGUI();
|
||||
DeviceFrame *frameAtPosition(int pos);
|
||||
unsigned int findInsertPosition(int xcoord);
|
||||
void addFrameAtPosition(int pos, DeviceFrame *c);
|
||||
void addFrame(int index, DeviceFrame *c);
|
||||
void createDragFrame(DeviceFrame *c);
|
||||
void updateInsertIndicator(int xcoord);
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
|
||||
void removeDeviceFrame(DeviceFrame *dev);
|
||||
|
||||
void updateDeviceFrames();
|
||||
|
||||
Ui::CompoundDeviceEditDialog *ui;
|
||||
CompoundDevice ldev;
|
||||
|
||||
QWidget *graph, *insertIndicator;
|
||||
QPoint dragStartPosition;
|
||||
bool dropPending;
|
||||
DeviceFrame *dragFrame;
|
||||
DeviceFrame *dropFrame;
|
||||
|
||||
std::vector<DeviceFrame*> deviceFrames;
|
||||
};
|
||||
|
||||
#endif // COMPOUNDDEVICEEDITDIALOG_H
|
||||
183
Software/PC_Application/Device/compounddeviceeditdialog.ui
Normal file
183
Software/PC_Application/Device/compounddeviceeditdialog.ui
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CompoundDeviceEditDialog</class>
|
||||
<widget class="QDialog" name="CompoundDeviceEditDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1097</width>
|
||||
<height>598</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Compound Device Edit</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="name"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Synchronization:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="sync"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Standalone Devices</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Drag/drop into compound device</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lLibreVNA1">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-image: url(:/icons/LibreVNAV1.svg);</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>LibreVNA V1</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1077</width>
|
||||
<height>372</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="status">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Open|QDialogButtonBox::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -136,6 +136,7 @@ VirtualDevice::VirtualDevice(QString serial)
|
|||
info{},
|
||||
status{}
|
||||
{
|
||||
cdev = nullptr;
|
||||
isCompound = false;
|
||||
zerospan = false;
|
||||
auto dev = new Device(serial);
|
||||
|
|
@ -243,6 +244,11 @@ Device *VirtualDevice::getDevice()
|
|||
}
|
||||
}
|
||||
|
||||
CompoundDevice *VirtualDevice::getCompoundDevice()
|
||||
{
|
||||
return cdev;
|
||||
}
|
||||
|
||||
std::vector<Device *> VirtualDevice::getDevices()
|
||||
{
|
||||
return devices;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "device.h"
|
||||
#include "Tools/parameters.h"
|
||||
#include "compounddevice.h"
|
||||
|
||||
#include <set>
|
||||
#include <complex>
|
||||
|
|
@ -52,6 +53,7 @@ public:
|
|||
|
||||
bool isCompoundDevice() const;
|
||||
Device *getDevice();
|
||||
CompoundDevice *getCompoundDevice();
|
||||
std::vector<Device*> getDevices();
|
||||
const Info& getInfo() const;
|
||||
static const VirtualDevice::Info &getInfo(VirtualDevice *vdev);
|
||||
|
|
@ -179,6 +181,8 @@ private:
|
|||
bool zerospan;
|
||||
|
||||
std::map<Device*, Device::TransmissionResult> results;
|
||||
|
||||
CompoundDevice *cdev;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(VirtualDevice::Status)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue