diff --git a/Software/PC_Application/Calibration/amplitudecaldialog.cpp b/Software/PC_Application/Calibration/amplitudecaldialog.cpp index 3c4c3dc..9425aa3 100644 --- a/Software/PC_Application/Calibration/amplitudecaldialog.cpp +++ b/Software/PC_Application/Calibration/amplitudecaldialog.cpp @@ -17,15 +17,16 @@ using namespace std; using namespace nlohmann; -AmplitudeCalDialog::AmplitudeCalDialog(Device *dev, QWidget *parent) : +AmplitudeCalDialog::AmplitudeCalDialog(Device *dev, ModeHandler *handler, QWidget *parent) : QDialog(parent), ui(new Ui::AmplitudeCalDialog), dev(dev), + modeHandler(handler), model(this), mode(CalibrationMode::BothPorts) { - activeMode = Mode::getActiveMode(); - activeMode->deactivate(); + auto activeMode = modeHandler->getActiveMode(); + modeHandler->deactivate(activeMode); dev->SetIdle(); ui->setupUi(this); ui->view->setModel(&model); @@ -137,7 +138,8 @@ AmplitudeCalDialog::AmplitudeCalDialog(Device *dev, QWidget *parent) : AmplitudeCalDialog::~AmplitudeCalDialog() { delete ui; - activeMode->activate(); + auto activeMode = modeHandler->getActiveMode(); + modeHandler->activate(activeMode); } void AmplitudeCalDialog::reject() diff --git a/Software/PC_Application/Calibration/amplitudecaldialog.h b/Software/PC_Application/Calibration/amplitudecaldialog.h index 0abcbd8..d36516d 100644 --- a/Software/PC_Application/Calibration/amplitudecaldialog.h +++ b/Software/PC_Application/Calibration/amplitudecaldialog.h @@ -2,6 +2,7 @@ #define AMPLITUDECALDIALOG_H #include "mode.h" +#include "modehandler.h" #include "Device/device.h" #include @@ -42,7 +43,7 @@ class AmplitudeCalDialog : public QDialog Q_OBJECT public: - explicit AmplitudeCalDialog(Device *dev, QWidget *parent = nullptr); + explicit AmplitudeCalDialog(Device *dev, ModeHandler *handler, QWidget *parent = nullptr); ~AmplitudeCalDialog(); void reject() override; @@ -100,7 +101,7 @@ protected: std::vector points; Ui::AmplitudeCalDialog *ui; Device *dev; - Mode *activeMode; + ModeHandler *modeHandler; AmplitudeModel model; bool edited; CalibrationMode mode; diff --git a/Software/PC_Application/Calibration/frequencycaldialog.cpp b/Software/PC_Application/Calibration/frequencycaldialog.cpp index df2d403..abd04f8 100644 --- a/Software/PC_Application/Calibration/frequencycaldialog.cpp +++ b/Software/PC_Application/Calibration/frequencycaldialog.cpp @@ -2,7 +2,7 @@ #include "ui_frequencycaldialog.h" -FrequencyCalDialog::FrequencyCalDialog(Device *dev, QWidget *parent) : +FrequencyCalDialog::FrequencyCalDialog(Device *dev, ModeHandler *handler, QWidget *parent) : QDialog(parent), ui(new Ui::FrequencyCalDialog), dev(dev) @@ -22,9 +22,9 @@ FrequencyCalDialog::FrequencyCalDialog(Device *dev, QWidget *parent) : p.frequencyCorrection.ppm = ui->ppm->value(); dev->SendPacket(p); // force restart of current mode for setting to take effect - auto activeMode = Mode::getActiveMode(); - activeMode->deactivate(); - activeMode->activate(); + auto activeMode = handler->getActiveMode(); + handler->deactivate(activeMode); + handler->activate(activeMode); accept(); delete this; }); diff --git a/Software/PC_Application/Calibration/frequencycaldialog.h b/Software/PC_Application/Calibration/frequencycaldialog.h index 7358407..9ddf4e9 100644 --- a/Software/PC_Application/Calibration/frequencycaldialog.h +++ b/Software/PC_Application/Calibration/frequencycaldialog.h @@ -2,6 +2,7 @@ #define FREQUENCYCALDIALOG_H #include "Device/device.h" +#include "modehandler.h" #include "mode.h" #include @@ -15,7 +16,7 @@ class FrequencyCalDialog : public QDialog Q_OBJECT public: - explicit FrequencyCalDialog(Device *dev, QWidget *parent = nullptr); + explicit FrequencyCalDialog(Device *dev, ModeHandler *handler, QWidget *parent = nullptr); ~FrequencyCalDialog(); private: diff --git a/Software/PC_Application/Calibration/receivercaldialog.cpp b/Software/PC_Application/Calibration/receivercaldialog.cpp index 1b74176..bd64cfe 100644 --- a/Software/PC_Application/Calibration/receivercaldialog.cpp +++ b/Software/PC_Application/Calibration/receivercaldialog.cpp @@ -1,7 +1,7 @@ #include "receivercaldialog.h" -ReceiverCalDialog::ReceiverCalDialog(Device *dev) - : AmplitudeCalDialog(dev) +ReceiverCalDialog::ReceiverCalDialog(Device *dev, ModeHandler *handler) + : AmplitudeCalDialog(dev, handler) { setWindowTitle("Receiver Calibration Dialog"); LoadFromDevice(); diff --git a/Software/PC_Application/Calibration/receivercaldialog.h b/Software/PC_Application/Calibration/receivercaldialog.h index 1032c73..28fecf4 100644 --- a/Software/PC_Application/Calibration/receivercaldialog.h +++ b/Software/PC_Application/Calibration/receivercaldialog.h @@ -2,12 +2,13 @@ #define RECEIVERCALDIALOG_H #include "amplitudecaldialog.h" +#include "modehandler.h" class ReceiverCalDialog : public AmplitudeCalDialog { Q_OBJECT public: - ReceiverCalDialog(Device *dev); + ReceiverCalDialog(Device *dev, ModeHandler *handler); protected: Protocol::PacketType requestCommand() override { return Protocol::PacketType::RequestReceiverCal; } Protocol::PacketType pointType() override { return Protocol::PacketType::ReceiverCalPoint; } diff --git a/Software/PC_Application/Calibration/sourcecaldialog.cpp b/Software/PC_Application/Calibration/sourcecaldialog.cpp index 9d047b1..c511920 100644 --- a/Software/PC_Application/Calibration/sourcecaldialog.cpp +++ b/Software/PC_Application/Calibration/sourcecaldialog.cpp @@ -2,8 +2,8 @@ #include -SourceCalDialog::SourceCalDialog(Device *dev) - : AmplitudeCalDialog(dev) +SourceCalDialog::SourceCalDialog(Device *dev, ModeHandler *handler) + : AmplitudeCalDialog(dev, handler) { setWindowTitle("Source Calibration Dialog"); LoadFromDevice(); diff --git a/Software/PC_Application/Calibration/sourcecaldialog.h b/Software/PC_Application/Calibration/sourcecaldialog.h index 7bd691c..f343e3b 100644 --- a/Software/PC_Application/Calibration/sourcecaldialog.h +++ b/Software/PC_Application/Calibration/sourcecaldialog.h @@ -2,6 +2,7 @@ #define SOURCECALDIALOG_H #include "amplitudecaldialog.h" +#include "modehandler.h" #include @@ -9,7 +10,7 @@ class SourceCalDialog : public AmplitudeCalDialog { Q_OBJECT public: - SourceCalDialog(Device *dev); + SourceCalDialog(Device *dev, ModeHandler *handler); protected: Protocol::PacketType requestCommand() override { return Protocol::PacketType::RequestSourceCal; } Protocol::PacketType pointType() override { return Protocol::PacketType::SourceCalPoint; } diff --git a/Software/PC_Application/Generator/generator.cpp b/Software/PC_Application/Generator/generator.cpp index 94d4d0f..6a52878 100644 --- a/Software/PC_Application/Generator/generator.cpp +++ b/Software/PC_Application/Generator/generator.cpp @@ -55,7 +55,7 @@ void Generator::fromJSON(nlohmann::json j) void Generator::updateDevice() { - if(!window->getDevice() || Mode::getActiveMode() != this) { + if(!window->getDevice() || isActive != true) { // can't update if not connected return; } diff --git a/Software/PC_Application/Generator/generator.h b/Software/PC_Application/Generator/generator.h index 41f4bb5..5d97585 100644 --- a/Software/PC_Application/Generator/generator.h +++ b/Software/PC_Application/Generator/generator.h @@ -18,6 +18,8 @@ public: virtual nlohmann::json toJSON() override; virtual void fromJSON(nlohmann::json j) override; + void setAveragingMode(Averaging::Mode mode) override {Q_UNUSED(mode)}; + private slots: void updateDevice(); diff --git a/Software/PC_Application/LibreVNA-GUI.pro b/Software/PC_Application/LibreVNA-GUI.pro index bd60738..b12ef96 100644 --- a/Software/PC_Application/LibreVNA-GUI.pro +++ b/Software/PC_Application/LibreVNA-GUI.pro @@ -123,7 +123,9 @@ HEADERS += \ averaging.h \ csv.h \ json.hpp \ + modehandler.h \ mode.h \ + modewindow.h \ preferences.h \ savable.h \ scpi.h \ @@ -242,7 +244,9 @@ SOURCES += \ averaging.cpp \ csv.cpp \ main.cpp \ + modehandler.cpp \ mode.cpp \ + modewindow.cpp \ preferences.cpp \ scpi.cpp \ tcpserver.cpp \ diff --git a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp index de035c7..12d8d94 100644 --- a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp +++ b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp @@ -433,7 +433,7 @@ using namespace std; void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d) { - if(Mode::getActiveMode() != this) { + if(isActive != true) { return; } @@ -570,7 +570,7 @@ void SpectrumAnalyzer::SettingsChanged() } } - if(window->getDevice() && Mode::getActiveMode() == this) { + if(window->getDevice() && isActive) { window->getDevice()->Configure(settings, [=](Device::TransmissionResult res){ // device received command changingSettings = false; diff --git a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.h b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.h index d247d25..fcec0da 100644 --- a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.h +++ b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.h @@ -28,7 +28,7 @@ public: virtual void fromJSON(nlohmann::json j) override; void updateGraphColors(); - void setAveragingMode(Averaging::Mode mode); + void setAveragingMode(Averaging::Mode mode) override; private: diff --git a/Software/PC_Application/VNA/vna.cpp b/Software/PC_Application/VNA/vna.cpp index fc0cd22..aa65a67 100644 --- a/Software/PC_Application/VNA/vna.cpp +++ b/Software/PC_Application/VNA/vna.cpp @@ -801,7 +801,7 @@ using namespace std; void VNA::NewDatapoint(Protocol::Datapoint d) { - if(Mode::getActiveMode() != this) { + if(isActive != true) { // ignore return; } @@ -972,7 +972,7 @@ void VNA::SettingsChanged(bool resetTraces, std::functiongetDevice() && Mode::getActiveMode() == this) { + if(window->getDevice() && isActive) { if(s.excitePort1 == 0 && s.excitePort2 == 0) { // no signal at either port, just set the device to idle window->getDevice()->SetIdle(); @@ -1486,7 +1486,7 @@ void VNA::SetupSCPI() return ret; })); scpi_cal->add(new SCPICommand("MEASure", [=](QStringList params) -> QString { - if(params.size() != 1 || CalibrationMeasurementActive() || !window->getDevice() || Mode::getActiveMode() != this) { + if(params.size() != 1 || CalibrationMeasurementActive() || !window->getDevice() || isActive != true) { // no measurement specified, still busy or invalid mode return SCPI::getResultName(SCPI::Result::Error); } else { diff --git a/Software/PC_Application/VNA/vna.h b/Software/PC_Application/VNA/vna.h index 77068b2..2702af1 100644 --- a/Software/PC_Application/VNA/vna.h +++ b/Software/PC_Application/VNA/vna.h @@ -31,7 +31,7 @@ public: virtual void fromJSON(nlohmann::json j) override; void updateGraphColors(); - void setAveragingMode(Averaging::Mode mode); + void setAveragingMode(Averaging::Mode mode) override; enum class SweepType { Frequency = 0, diff --git a/Software/PC_Application/appwindow.cpp b/Software/PC_Application/appwindow.cpp index e964080..907e3a1 100644 --- a/Software/PC_Application/appwindow.cpp +++ b/Software/PC_Application/appwindow.cpp @@ -27,12 +27,14 @@ #include "CustomWidgets/informationbox.h" #include "Util/app_common.h" #include "about.h" +#include "mode.h" +#include "modehandler.h" +#include "modewindow.h" #include #include #include #include -#include #include #include #include @@ -168,6 +170,7 @@ AppWindow::AppWindow(QWidget *parent) , appVersion(APP_VERSION) , appGitHash(APP_GIT_HASH) { + // qDebug().setVerbosity(0); qDebug() << "Application start"; @@ -191,6 +194,7 @@ AppWindow::AppWindow(QWidget *parent) Preferences::getInstance().load(); } device = nullptr; + modeHandler = nullptr; if(parser.isSet("port")) { bool OK; @@ -227,12 +231,22 @@ AppWindow::AppWindow(QWidget *parent) ui->menuToolbars->addAction(t->toggleViewAction()); } - // Create GUI modes + modeHandler = new ModeHandler(this); + new ModeWindow(modeHandler, this); + central = new QStackedWidget; setCentralWidget(central); - auto vna = new VNA(this); - auto generator = new Generator(this); - auto spectrumAnalyzer = new SpectrumAnalyzer(this); + + auto vnaIndex = modeHandler->createMode("Vector Network Analyzer", Mode::Type::VNA); + modeHandler->createMode("Spectrum Analyzer", Mode::Type::SA); + modeHandler->createMode("Signal Generator", Mode::Type::SG); + modeHandler->setCurrentIndex(vnaIndex); + + auto setModeStatusbar = [=](const QString &msg) { + lModeInfo.setText(msg); + }; + + connect(modeHandler, &ModeHandler::StatusBarMessageChanged, setModeStatusbar); // UI connections connect(ui->actionUpdate_Device_List, &QAction::triggered, this, &AppWindow::UpdateDeviceList); @@ -255,7 +269,7 @@ AppWindow::AppWindow(QWidget *parent) LoadSetup(filename); }); connect(ui->actionSave_image, &QAction::triggered, [=](){ - Mode::getActiveMode()->saveSreenshot(); + modeHandler->getActiveMode()->saveSreenshot(); }); connect(ui->actionManual_Control, &QAction::triggered, this, &AppWindow::StartManualControl); @@ -275,26 +289,18 @@ AppWindow::AppWindow(QWidget *parent) StartTCPServer(p.SCPIServer.port); } } - // averaging mode may have changed, update for all relevant modes - for (auto m : Mode::getModes()) + for (auto m : modeHandler->getModes()) { switch (m->getType()) { case Mode::Type::VNA: - if(p.Acquisition.useMedianAveraging) { - static_cast(m)->setAveragingMode(Averaging::Mode::Median); - } - else { - static_cast(m)->setAveragingMode(Averaging::Mode::Mean); - } - break; case Mode::Type::SA: if(p.Acquisition.useMedianAveraging) { - static_cast(m)->setAveragingMode(Averaging::Mode::Median); + m->setAveragingMode(Averaging::Mode::Median); } else { - static_cast(m)->setAveragingMode(Averaging::Mode::Mean); + m->setAveragingMode(Averaging::Mode::Mean); } break; case Mode::Type::SG: @@ -307,7 +313,7 @@ AppWindow::AppWindow(QWidget *parent) // acquisition frequencies may have changed, update UpdateAcquisitionFrequencies(); - auto active = Mode::getActiveMode(); + auto active = modeHandler->getActiveMode(); if (active) { active->updateGraphColors(); @@ -338,9 +344,6 @@ AppWindow::AppWindow(QWidget *parent) SetupSCPI(); - // Set default mode - vna->activate(); - auto pref = Preferences::getInstance(); if(pref.Startup.UseSetupFile) { LoadSetup(pref.Startup.SetupFile); @@ -356,7 +359,8 @@ AppWindow::AppWindow(QWidget *parent) LoadSetup(parser.value("setup")); } if(parser.isSet("cal")) { - vna->LoadCalibration(parser.value("cal")); + VNA* mode = static_cast(modeHandler->findFirstOfType(Mode::Type::VNA)); + mode->LoadCalibration(parser.value("cal")); } if(!parser.isSet("no-gui")) { InformationBox::setGUI(true); @@ -380,16 +384,16 @@ void AppWindow::closeEvent(QCloseEvent *event) if(pref.Startup.UseSetupFile && pref.Startup.AutosaveSetupFile) { SaveSetup(pref.Startup.SetupFile); } - for(auto m : Mode::getModes()) { - m->shutdown(); - } + modeHandler->shutdown(); QSettings settings; settings.setValue("geometry", saveGeometry()); // deactivate currently used mode (stores mode state in settings) - if(Mode::getActiveMode()) { - Mode::getActiveMode()->deactivate(); + if(modeHandler->getActiveMode()) { + modeHandler->deactivate(modeHandler->getActiveMode()); } delete device; + delete modeHandler; + modeHandler = nullptr; pref.store(); QMainWindow::closeEvent(event); } @@ -421,8 +425,8 @@ bool AppWindow::ConnectToDevice(QString serial) ui->actionFrequency_Calibration->setEnabled(true); UpdateAcquisitionFrequencies(); - if (Mode::getActiveMode()) { - Mode::getActiveMode()->initializeDevice(); + if (modeHandler->getActiveMode()) { + modeHandler->getActiveMode()->initializeDevice(); } UpdateReference(); @@ -460,8 +464,8 @@ void AppWindow::DisconnectDevice() deviceActionGroup->checkedAction()->setChecked(false); } UpdateStatusBar(DeviceStatusBar::Disconnected); - if(Mode::getActiveMode()) { - Mode::getActiveMode()->deviceDisconnected(); + if(modeHandler->getActiveMode()) { + modeHandler->getActiveMode()->deviceDisconnected(); } qDebug() << "Disconnected device"; } @@ -591,22 +595,23 @@ void AppWindow::SetupSCPI() } Mode *mode = nullptr; if (params[0] == "VNA") { - mode = Mode::findFirstOfType(Mode::Type::VNA); + mode = modeHandler->findFirstOfType(Mode::Type::VNA); } else if(params[0] == "GEN") { - mode = Mode::findFirstOfType(Mode::Type::SG); + mode = modeHandler->findFirstOfType(Mode::Type::SG); } else if(params[0] == "SA") { - mode = Mode::findFirstOfType(Mode::Type::SA); + mode = modeHandler->findFirstOfType(Mode::Type::SA); } else { return "INVALID MDOE"; } if(mode) { - mode->activate(); + int index = modeHandler->findIndex(mode); + modeHandler->setCurrentIndex(index); return SCPI::getResultName(SCPI::Result::Empty); } else { return SCPI::getResultName(SCPI::Result::Error); } }, [=](QStringList) -> QString { - auto active = Mode::getActiveMode(); + auto active = modeHandler->getActiveMode(); if(active) { switch(active->getType()) { case Mode::Type::VNA: return "VNA"; @@ -968,7 +973,7 @@ void AppWindow::StartManualControl() connect(manual, &QDialog::finished, [=](){ manual = nullptr; if(device) { - Mode::getActiveMode()->initializeDevice(); + modeHandler->getActiveMode()->initializeDevice(); } }); if(AppWindow::showGUI()) { @@ -1048,7 +1053,7 @@ void AppWindow::DeviceStatusUpdated() void AppWindow::SourceCalibrationDialog() { - auto d = new SourceCalDialog(device); + auto d = new SourceCalDialog(device, modeHandler); if(AppWindow::showGUI()) { d->exec(); } @@ -1056,7 +1061,7 @@ void AppWindow::SourceCalibrationDialog() void AppWindow::ReceiverCalibrationDialog() { - auto d = new ReceiverCalDialog(device); + auto d = new ReceiverCalDialog(device, modeHandler); if(AppWindow::showGUI()) { d->exec(); } @@ -1064,7 +1069,7 @@ void AppWindow::ReceiverCalibrationDialog() void AppWindow::FrequencyCalibrationDialog() { - auto d = new FrequencyCalDialog(device); + auto d = new FrequencyCalDialog(device, modeHandler); if(AppWindow::showGUI()) { d->exec(); } @@ -1087,7 +1092,7 @@ nlohmann::json AppWindow::SaveSetup() { nlohmann::json j; nlohmann::json jm; - for(auto m : Mode::getModes()) { + for(auto m : modeHandler->getModes()) { nlohmann::json jmode; jmode["type"] = Mode::TypeToName(m->getType()).toStdString(); jmode["name"] = m->getName().toStdString(); @@ -1095,8 +1100,8 @@ nlohmann::json AppWindow::SaveSetup() jm.push_back(jmode); } j["Modes"] = jm; - if(Mode::getActiveMode()) { - j["activeMode"] = Mode::getActiveMode()->getName().toStdString(); + if(modeHandler->getActiveMode()) { + j["activeMode"] = modeHandler->getActiveMode()->getName().toStdString(); } nlohmann::json ref; @@ -1143,28 +1148,32 @@ void AppWindow::LoadSetup(nlohmann::json j) toolbars.reference.type->setCurrentIndex(index); toolbars.reference.outFreq->setCurrentText(QString::fromStdString(j["Reference"].value("Output", "Off"))); } - while(Mode::getModes().size() > 0) { - delete Mode::getModes()[0]; - } - // old style VNA/Generator/Spectrum Analyzer settings + modeHandler->closeModes(); + + /* old style VNA/Generator/Spectrum Analyzer settings, + * no more than one instance in each mode running */ if(j.contains("VNA")) { - auto vna = new VNA(this); + auto vnaIndex = modeHandler->createMode("Vector Network Analyzer", Mode::Type::VNA); + auto *vna = static_cast(modeHandler->getMode(vnaIndex)); vna->fromJSON(j["VNA"]); } if(j.contains("Generator")) { - auto generator = new Generator(this); + auto sgIndex = modeHandler->createMode("Generator", Mode::Type::SG); + auto *generator = static_cast(modeHandler->getMode(sgIndex)); generator->fromJSON(j["Generator"]); } if(j.contains("SpectrumAnalyzer")) { - auto spectrumAnalyzer = new SpectrumAnalyzer(this); + auto saIndex = modeHandler->createMode("Spectrum Analyzer", Mode::Type::SA); + auto *spectrumAnalyzer = static_cast(modeHandler->getMode(saIndex)); spectrumAnalyzer->fromJSON(j["SpectrumAnalyzer"]); } if(j.contains("Modes")) { for(auto jm : j["Modes"]) { auto type = Mode::TypeFromName(QString::fromStdString(jm.value("type", "Invalid"))); if(type != Mode::Type::Last && jm.contains("settings")) { - auto m = Mode::createNew(this, QString::fromStdString(jm.value("name", "")), type); + auto index = modeHandler->createMode(QString::fromStdString(jm.value("name", "")), type); + auto m = modeHandler->getMode(index); m->fromJSON(jm["settings"]); } } @@ -1172,15 +1181,16 @@ void AppWindow::LoadSetup(nlohmann::json j) // activate the correct mode QString modeName = QString::fromStdString(j.value("activeMode", "")); - for(auto m : Mode::getModes()) { + for(auto m : modeHandler->getModes()) { if(m->getName() == modeName) { - m->activate(); + auto index = modeHandler->findIndex(m); + modeHandler->setCurrentIndex(index); break; } } // if no mode is activated, there might have been a problem with the setup file. Activate the first mode anyway, to prevent invalid GUI state - if(!Mode::getActiveMode() && Mode::getModes().size() > 0) { - Mode::getModes()[0]->activate(); + if(!modeHandler->getActiveMode() && modeHandler->getModes().size() > 0) { + modeHandler->activate(modeHandler->getModes()[0]); } } @@ -1194,6 +1204,12 @@ QStackedWidget *AppWindow::getCentral() const return central; } +ModeHandler* AppWindow::getModeHandler() const +{ + return modeHandler; +} + + Ui::MainWindow *AppWindow::getUi() const { return ui; @@ -1273,3 +1289,4 @@ void AppWindow::UpdateStatusBar(DeviceStatusBar status) break; } } + diff --git a/Software/PC_Application/appwindow.h b/Software/PC_Application/appwindow.h index 90b18f2..3fcc8b9 100644 --- a/Software/PC_Application/appwindow.h +++ b/Software/PC_Application/appwindow.h @@ -31,6 +31,7 @@ class MainWindow; class VNA; class Generator; class SpectrumAnalyzer; +class ModeHandler; class AppWindow : public QMainWindow { @@ -41,6 +42,7 @@ public: Ui::MainWindow *getUi() const; QStackedWidget *getCentral() const; + ModeHandler* getModeHandler() const; Device*&getDevice(); const QString& getAppVersion() const; @@ -98,6 +100,7 @@ private: } reference; } toolbars; + ModeHandler *modeHandler; Device *device; DeviceLog deviceLog; QString deviceSerial; diff --git a/Software/PC_Application/mode.cpp b/Software/PC_Application/mode.cpp index 163f203..ec31fb1 100644 --- a/Software/PC_Application/mode.cpp +++ b/Software/PC_Application/mode.cpp @@ -13,110 +13,22 @@ #include #include -std::vector Mode::modes; -Mode* Mode::activeMode = nullptr; -QTabBar* Mode::tabbar = nullptr; -QWidget* Mode::cornerWidget = nullptr; //QButtonGroup* Mode::modeButtonGroup = nullptr; Mode::Mode(AppWindow *window, QString name, QString SCPIname) : QObject(window), SCPINode(SCPIname), window(window), + isActive(false), name(name), central(nullptr) { - if(!nameAllowed(name)) { - throw std::runtime_error("Unable to create mode, name already taken"); - } - // Create mode switch button - if(!cornerWidget) { - // this is the first created mode, initialize corner widget and set this mode as active - cornerWidget = new QWidget(); - cornerWidget->setLayout(new QHBoxLayout); - cornerWidget->layout()->setSpacing(0); - cornerWidget->layout()->setMargin(0); - cornerWidget->layout()->setContentsMargins(0,0,0,0); - cornerWidget->setMaximumHeight(window->menuBar()->height()); - - tabbar = new QTabBar; - tabbar->setTabsClosable(true); - tabbar->setStyleSheet("QTabBar::tab { height: "+QString::number(window->menuBar()->height())+"px;}"); - cornerWidget->layout()->addWidget(tabbar); - - auto bAdd = new QPushButton(); - QIcon icon; - QString iconThemeName = QString::fromUtf8("list-add"); - if (QIcon::hasThemeIcon(iconThemeName)) { - icon = QIcon::fromTheme(iconThemeName); - } else { - icon.addFile(QString::fromUtf8(":/icons/add.png"), QSize(), QIcon::Normal, QIcon::Off); - } - bAdd->setIcon(icon); - - auto mAdd = new QMenu(); - for(unsigned int i=0;i<(int) Type::Last;i++) { - auto type = (Type) i; - auto action = new QAction(TypeToName(type)); - mAdd->addAction(action); - connect(action, &QAction::triggered, [=](){ - bool ok; - QString text = QInputDialog::getText(window, "Create new "+TypeToName(type)+" tab", - "Name:", QLineEdit::Normal, - TypeToName(type), &ok); - if(ok) { - if(!nameAllowed(text)) { - InformationBox::ShowError("Name collision", "Unable to create tab, no duplicate names allowed"); - } else { - auto mode = Mode::createNew(window, text, type); - mode->activate(); - } - } - }); - } - bAdd->setMenu(mAdd); - bAdd->setMaximumHeight(window->menuBar()->height()); - bAdd->setMaximumWidth(40); - cornerWidget->layout()->addWidget(bAdd); - - window->menuBar()->setCornerWidget(cornerWidget); - - connect(tabbar, &QTabBar::currentChanged, [=](int index){ - modes[index]->activate(); - }); - connect(tabbar, &QTabBar::tabCloseRequested, [=](int index){ - delete modes[index]; - }); - connect(tabbar, &QTabBar::tabMoved, [=](int from, int to){ - auto modeFrom = modes.at(from); - auto modeTo = modes.at(to); - modes[from] = modeTo; - modes[to] = modeFrom; - }); - } - connect(this, &Mode::statusbarMessage, window, &AppWindow::setModeStatus); - modes.push_back(this); - tabbar->blockSignals(true); - tabbar->insertTab(tabbar->count(), name); - tabbar->blockSignals(false); - tabbar->setMovable(true); window->getSCPI()->add(this); } Mode::~Mode() { window->getSCPI()->remove(this); - if(activeMode == this) { - deactivate(); - } - auto index = findTabIndex(); - tabbar->blockSignals(true); - tabbar->removeTab(index); - tabbar->blockSignals(false); - modes.erase(modes.begin() + index); - if(modes.size() > 0) { - modes[tabbar->currentIndex()]->activate(); - } window->getCentral()->removeWidget(central); delete central; for(auto d : docks) { @@ -129,13 +41,7 @@ Mode::~Mode() void Mode::activate() { - if(activeMode == this) { - // already active; - return; - } else if(activeMode) { - activeMode->deactivate(); - } - + isActive = true; qDebug() << "Activating mode" << name; // show all mode specific GUI elements for(auto t : toolbars) { @@ -152,7 +58,6 @@ void Mode::activate() QSettings settings; window->getCentral()->setCurrentWidget(central); - // restore dock and toolbar positions window->restoreState(settings.value("windowState_"+name).toByteArray()); @@ -174,12 +79,6 @@ void Mode::activate() } } - activeMode = this; - // force activation of correct tab in case the mode switch was done via script/setup load. - // This will trigger a second activation of this mode in the signal of the tab bar, but since it is - // already the active mode, this function will just return -> no recursion - tabbar->setCurrentIndex(findTabIndex()); - if(window->getDevice()) { initializeDevice(); } @@ -189,6 +88,7 @@ void Mode::activate() void Mode::deactivate() { + isActive = false; QSettings settings; // save dock/toolbar visibility for(auto d : docks) { @@ -213,15 +113,10 @@ void Mode::deactivate() } qDebug() << "Deactivated mode" << name; + if(window->getDevice()) { window->getDevice()->SetIdle(); } - activeMode = nullptr; -} - -Mode *Mode::getActiveMode() -{ - return activeMode; } QString Mode::TypeToName(Mode::Type t) @@ -258,27 +153,6 @@ void Mode::saveSreenshot() central->grab().save(filename); } -Mode *Mode::createNew(AppWindow *window, QString name, Mode::Type t) -{ - switch(t) { - case Type::VNA: return new VNA(window, name); - case Type::SG: return new Generator(window, name); - case Type::SA: return new SpectrumAnalyzer(window, name); - default: return nullptr; - } -} - -bool Mode::nameAllowed(QString name) -{ - for(auto m : modes) { - if(m->getName() == name) { - // name already taken, no duplicates allowed - return false; - } - } - return true; -} - void Mode::finalize(QWidget *centralWidget) { central = centralWidget; @@ -302,33 +176,10 @@ void Mode::finalize(QWidget *centralWidget) } } -int Mode::findTabIndex() -{ - auto it = std::find(modes.begin(), modes.end(), this); - return it - modes.begin(); -} - -std::vector Mode::getModes() -{ - return modes; -} - -Mode *Mode::findFirstOfType(Mode::Type t) -{ - for(auto m : modes) { - if(m->getType() == t) { - return m; - } - } - return nullptr; -} - void Mode::setStatusbarMessage(QString msg) { statusbarMsg = msg; - if(this == activeMode) { - emit statusbarMessage(msg); - } + emit statusbarMessage(msg); } QString Mode::getName() const @@ -338,12 +189,7 @@ QString Mode::getName() const void Mode::setName(const QString &value) { - if(!nameAllowed(value)) { - // unable to use this name - return; - } name = value; - tabbar->setTabText(findTabIndex(), name); } void Mode::updateGraphColors() diff --git a/Software/PC_Application/mode.h b/Software/PC_Application/mode.h index 038cc53..1784a5e 100644 --- a/Software/PC_Application/mode.h +++ b/Software/PC_Application/mode.h @@ -16,6 +16,7 @@ class Mode : public QObject, public Savable, public SCPINode { Q_OBJECT + friend class ModeHandler; public: enum class Type { VNA, @@ -27,13 +28,10 @@ public: Mode(AppWindow *window, QString name, QString SCPIname); ~Mode(); - virtual void activate(); // derived classes must call Mode::activate before doing anything - virtual void deactivate(); // derived classes must call Mode::deactivate before returning virtual void shutdown(){}; // called when the application is about to exit QString getName() const; void setName(const QString &value); void updateGraphColors(); - static Mode *getActiveMode(); static QString TypeToName(Type t); static Type TypeFromName(QString s); virtual Type getType() = 0; @@ -43,14 +41,16 @@ public: virtual void saveSreenshot(); - static Mode *createNew(AppWindow *window, QString name, Type t); - static bool nameAllowed(QString name); - static std::vector getModes(); - static Mode* findFirstOfType(Type t); + virtual void setAveragingMode(Averaging::Mode mode) = 0; signals: void statusbarMessage(QString msg); protected: + + virtual void activate(); // derived classes must call Mode::activate before doing anything + virtual void deactivate(); // derived classes must call Mode::deactivate before returning + bool isActive; + void setStatusbarMessage(QString msg); // call once the derived class is fully initialized void finalize(QWidget *centralWidget); @@ -60,14 +60,10 @@ protected: std::set docks; private: - int findTabIndex(); - static std::vector modes; - static Mode *activeMode; - static QTabBar *tabbar; - static QWidget *cornerWidget; // static QButtonGroup *modeButtonGroup; QString name; QString statusbarMsg; + QWidget *central; }; diff --git a/Software/PC_Application/modehandler.cpp b/Software/PC_Application/modehandler.cpp new file mode 100644 index 0000000..b42a79e --- /dev/null +++ b/Software/PC_Application/modehandler.cpp @@ -0,0 +1,204 @@ +#include "modehandler.h" + +#include "VNA/vna.h" +#include "SpectrumAnalyzer/spectrumanalyzer.h" +#include "Generator/generator.h" +#include "mode.h" +#include "averaging.h" + +ModeHandler::ModeHandler(AppWindow *aw): + QObject(), + aw(aw) +{} + +void ModeHandler::shutdown() +{ + for(auto m : modes) { + m->shutdown(); + } +} + +int ModeHandler::createMode(QString name, Mode::Type t) +{ + auto mode = createNew(aw, name, t); + return createMode(mode); +} + +int ModeHandler::createMode(Mode *mode) +{ + modes.push_back(mode); + currentModeIndex = int(modes.size()) - 1; + connect(mode, &Mode::statusbarMessage, this, &ModeHandler::setStatusBarMessageChanged); + + auto m = getMode(currentModeIndex); + activate(m); + + emit ModeCreated(currentModeIndex); + return (currentModeIndex); +} + +Mode *ModeHandler::createNew(AppWindow *aw, QString name, Mode::Type t) +{ + switch(t) { + case Mode::Type::VNA: return new VNA(aw, name); + case Mode::Type::SG: return new Generator(aw, name); + case Mode::Type::SA: return new SpectrumAnalyzer(aw, name); + default: return nullptr; + } +} + +Mode* ModeHandler::getActiveMode() +{ + return activeMode; +} + +Mode* ModeHandler::getMode(int index) +{ + return modes.at(index); +} + +void ModeHandler::activate(Mode * mode) +{ + if (getActiveMode() == mode) { + // Already active + return; + } + else if (getActiveMode()) { + deactivate(getActiveMode()); + } + activeMode = mode; + mode->activate(); +} + +void ModeHandler::deactivate(Mode* mode) +{ + mode->deactivate(); + activeMode = nullptr; +} + +std::vector ModeHandler::getModes() +{ + return modes; +} + +void ModeHandler::setCurrentIndex(int index) +{ + if (index >= 0) { + currentModeIndex = index; + auto m = getMode(getCurrentIndex()); + activate(m); + emit CurrentModeChanged(getCurrentIndex()); + } +} + +void ModeHandler::currentModeMoved(int from, int to) +{ + auto modeFrom = modes.at(from); + auto modeTo = modes.at(to); + modes[from] = modeTo; + modes[to] = modeFrom; +} + +int ModeHandler::getCurrentIndex() +{ + return currentModeIndex; +} + +void ModeHandler::closeMode(int index) +{ + disconnect(modes.at(index), &Mode::statusbarMessage, this, &ModeHandler::setStatusBarMessageChanged); + + std::vector idx; + for(int i=0; i < int(modes.size()); i++) + { + idx.push_back(i); + } + + auto left = std::find(idx.begin(), idx.end(), getCurrentIndex()-1); + auto right = std::find(idx.begin(), idx.end(), getCurrentIndex()+1); + auto foundLeft = false; + auto foundRight = false; + + if ( left != idx.end() ) + { + foundLeft = true; + } + + if ( right != idx.end() ) + { + foundRight = true; + } + + auto lastIndex = getCurrentIndex(); + + if (int(modes.size()) > 0) { + if (getCurrentIndex() == index) + { + if (foundLeft) + { + setCurrentIndex(getCurrentIndex()-1); + } + else if (foundRight) + { + setCurrentIndex(getCurrentIndex()+1); + } + } + } + + if (getActiveMode() == modes.at(index)) { + deactivate(getActiveMode()); + } + + delete modes.at(index); + modes.erase(modes.begin() + index); + + if (getCurrentIndex() == 1 && lastIndex == 0) { + setCurrentIndex(0); + } + + emit ModeClosed(index); +} + +void ModeHandler::closeModes() +{ + while(modes.size() > 0) { + closeMode(0); + } +} + +void ModeHandler::setStatusBarMessageChanged(const QString &msg) +{ + QObject* mode = sender(); + if ( getActiveMode() == mode) { + emit StatusBarMessageChanged(msg); + } +} + +bool ModeHandler::nameAllowed(const QString &name) +{ + for(auto m : modes) { + if(m->getName() == name) { + /* name already taken, no duplicates allowed + * when importing, name is used as value + */ + return false; + } + } + return true; +} + +int ModeHandler::findIndex(Mode *targetMode) +{ + auto it = std::find(modes.begin(), modes.end(), targetMode); + return it - modes.begin(); +} + +Mode* ModeHandler::findFirstOfType(Mode::Type t) +{ + for(auto m : modes) { + if(m->getType() == t) { + return m; + } + } + return nullptr; +} diff --git a/Software/PC_Application/modehandler.h b/Software/PC_Application/modehandler.h new file mode 100644 index 0000000..e34e662 --- /dev/null +++ b/Software/PC_Application/modehandler.h @@ -0,0 +1,58 @@ +#ifndef MODEHANDLER_H +#define MODEHANDLER_H + +#include "mode.h" +#include "appwindow.h" + +#include +#include + +class ModeHandler: public QObject +{ + Q_OBJECT +public: + ModeHandler(AppWindow *window); + ~ModeHandler() = default; + + void shutdown(); + int createMode(QString name, Mode::Type t); + void closeMode(int index); + void currentModeMoved(int from, int to); + void closeModes(); + int getCurrentIndex(); + + Mode* getActiveMode(); + + void activate(Mode * mode); + void deactivate(Mode* mode); + + Mode* getMode(int index); + std::vector getModes(); + + bool nameAllowed(const QString &name); + int findIndex(Mode *targetMode); + Mode* findFirstOfType(Mode::Type t); + +signals: + void StatusBarMessageChanged(const QString &msg); + + void ModeCreated(int modeIndex); + void ModeClosed(int modeIndex); + void CurrentModeChanged(int modeIndex); + +public slots: + void setCurrentIndex(int modeIndex); + +private: + std::vector modes; + int currentModeIndex; + int createMode(Mode *mode); + Mode *createNew(AppWindow *window, QString name, Mode::Type t); + AppWindow *aw; + Mode *activeMode = nullptr; + +private slots: + void setStatusBarMessageChanged(const QString &msg); +}; + +#endif // MODEHANDLER_H diff --git a/Software/PC_Application/modewindow.cpp b/Software/PC_Application/modewindow.cpp new file mode 100644 index 0000000..1fe89d4 --- /dev/null +++ b/Software/PC_Application/modewindow.cpp @@ -0,0 +1,117 @@ +#include "modewindow.h" + +#include "mode.h" +#include "appwindow.h" +#include "CustomWidgets/informationbox.h" + +#include +#include +#include + +ModeWindow::ModeWindow(ModeHandler* handler, AppWindow* aw, QWidget* parent): + QWidget(parent), + handler(handler), + aw(aw) +{ + + SetupUi(); + + connect(handler, &ModeHandler::ModeCreated, this, &ModeWindow::ModeCreated); + connect(handler, &ModeHandler::ModeClosed, this, &ModeWindow::ModeClosed); + connect(handler, &ModeHandler::CurrentModeChanged, this, &ModeWindow::CurrentModeChanged); + + connect(tabBar, &QTabBar::currentChanged, handler, &ModeHandler::setCurrentIndex); + connect(tabBar, &QTabBar::tabCloseRequested, handler, &ModeHandler::closeMode); + connect(tabBar, &QTabBar::tabMoved, handler, &ModeHandler::currentModeMoved); +} + +ModeWindow::~ModeWindow() +{ +} + +void ModeWindow::SetupUi() +{ + auto cornerWidget = new QWidget(); + cornerWidget->setLayout(new QHBoxLayout); + cornerWidget->layout()->setSpacing(0); + cornerWidget->layout()->setMargin(0); + cornerWidget->layout()->setContentsMargins(0,0,0,0); + cornerWidget->setMaximumHeight(aw->menuBar()->height()); + + tabBar = new QTabBar; + tabBar->setStyleSheet("QTabBar::tab { height: " + QString::number(aw->menuBar()->height()) + "px;}"); + tabBar->setTabsClosable(true); + cornerWidget->layout()->addWidget(tabBar); + + auto bAdd = new QPushButton(); + QIcon icon; + QString iconThemeName = QString::fromUtf8("list-add"); + + if (QIcon::hasThemeIcon(iconThemeName)) + icon = QIcon::fromTheme(iconThemeName); + else + icon.addFile(QString::fromUtf8(":/icons/add.png"), QSize(), QIcon::Normal, QIcon::Off); + + bAdd->setIcon(icon); + bAdd->setMaximumHeight(aw->menuBar()->height()); + bAdd->setMaximumWidth(40); + + auto mAdd = new QMenu(); + for(unsigned int i=0;i<(int) Mode::Type::Last;i++) { + auto type = (Mode::Type) i; + auto action = new QAction(Mode::TypeToName(type)); + mAdd->addAction(action); + connect(action, &QAction::triggered, [=](){ + bool ok; + QString text = QInputDialog::getText(this, + "Create new "+Mode::TypeToName(type)+" tab", + "Name:", QLineEdit::Normal, + Mode::TypeToName(type), &ok); + if(ok) { + if(!handler->nameAllowed(text)) { + InformationBox::ShowError("Name collision", "Unable to create tab, " \ + "no duplicate names allowed"); + } else { + handler->createMode(text, type); + } + } + }); + } + bAdd->setMenu(mAdd); + + cornerWidget->layout()->addWidget(bAdd); + + aw->menuBar()->setCornerWidget(cornerWidget); +} + +void ModeWindow::ModeCreated(int modeIndex) +{ + auto mode = handler->getMode(modeIndex); + + if (mode) + { + const auto name = mode->getName(); + + tabBar->blockSignals(true); + tabBar->insertTab(modeIndex, name); + tabBar->blockSignals(false); + tabBar->setMovable(true); + tabBar->setCurrentIndex(modeIndex); + } +} + +void ModeWindow::ModeClosed(int modeIndex) +{ + tabBar->blockSignals(true); + tabBar->removeTab(modeIndex); + tabBar->blockSignals(false); +} + + +void ModeWindow::CurrentModeChanged(int modeIndex) +{ + if (modeIndex != tabBar->currentIndex()) + { + tabBar->setCurrentIndex(modeIndex); + } +} diff --git a/Software/PC_Application/modewindow.h b/Software/PC_Application/modewindow.h new file mode 100644 index 0000000..c4a8139 --- /dev/null +++ b/Software/PC_Application/modewindow.h @@ -0,0 +1,25 @@ +#ifndef MODEWINDOW_H +#define MODEWINDOW_H + +#include "modehandler.h" + +class ModeWindow: public QWidget +{ + Q_OBJECT +public: + explicit ModeWindow(ModeHandler* handler, AppWindow* aw, QWidget *parent = nullptr); + ~ModeWindow(); + +private: + ModeHandler* handler; + void SetupUi(); + AppWindow* aw; + QTabBar* tabBar; + +private slots: + void ModeCreated(int modeIndex); + void ModeClosed(int modeIndex); + void CurrentModeChanged(int modeIndex); +}; + +#endif // MODEWINDOW_H