From 455c709eeeb286dd1d2abac99b5d9b9195586473 Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Wed, 11 Oct 2023 13:08:54 -0400 Subject: [PATCH 01/11] Update to new single Pulse library --- src/PulseExplorerLib.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PulseExplorerLib.cmake b/src/PulseExplorerLib.cmake index 63e9da5..607b585 100644 --- a/src/PulseExplorerLib.cmake +++ b/src/PulseExplorerLib.cmake @@ -192,7 +192,7 @@ explorer_add_library(PulseExplorerWidgets QT_RESOURCES resources.qrc PUBLIC_LINK_LIBRARIES - Pulse::PulseEngine + Pulse::Pulse Qwt::Qwt ${QT_LIBRARIES} ) -- GitLab From c08afb3bd7f0ada0cf0f7c221f12a3c66c70a46d Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Wed, 11 Oct 2023 13:09:12 -0400 Subject: [PATCH 02/11] Update for new Dyspnea action --- src/controls/actions/DyspneaWidget.cxx | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/controls/actions/DyspneaWidget.cxx b/src/controls/actions/DyspneaWidget.cxx index 5fc92ba..09abdfb 100644 --- a/src/controls/actions/DyspneaWidget.cxx +++ b/src/controls/actions/DyspneaWidget.cxx @@ -14,14 +14,17 @@ public: Controls(QPulse& qp) : Pulse(qp) {} QPulse& Pulse; SEDyspnea Action; - QScalarWidget* Severity; + QScalarWidget* RespirationRateSeverity; + QScalarWidget* TidalVolumeSeverity; }; QDyspneaWidget::QDyspneaWidget(QPulse& qp, QWidget *parent, Qt::WindowFlags flags) : QActionWidget(qp, parent, flags) { m_Controls = new Controls(qp); - m_Controls->Severity = new QScalarWidget("Severity", 0, 1, 0.1, ScalarOptionWidget::None, this); - Properties()->layout()->addWidget(m_Controls->Severity); + m_Controls->RespirationRateSeverity = new QScalarWidget("RespirationRateSeverity", 0, 1, 0.1, ScalarOptionWidget::None, this); + Properties()->layout()->addWidget(m_Controls->RespirationRateSeverity); + m_Controls->TidalVolumeSeverity = new QScalarWidget("TidalVolumeSeverity", 0, 1, 0.1, ScalarOptionWidget::None, this); + Properties()->layout()->addWidget(m_Controls->TidalVolumeSeverity); Properties()->layout()->addWidget(GetProcessTimeCtrl()); Reset(); } @@ -35,7 +38,8 @@ void QDyspneaWidget::Reset() { QActionWidget::Reset(); m_Controls->Action.Clear(); - m_Controls->Severity->Reset(); + m_Controls->RespirationRateSeverity->Reset(); + m_Controls->TidalVolumeSeverity->Reset(); } SEAction& QDyspneaWidget::GetAction() @@ -50,13 +54,15 @@ const SEAction& QDyspneaWidget::GetAction() const void QDyspneaWidget::SetEnabled(bool b) { QActionWidget::SetEnabled(b); - m_Controls->Severity->EnableInput(b); + m_Controls->RespirationRateSeverity->EnableInput(b); + m_Controls->TidalVolumeSeverity->EnableInput(b); } void QDyspneaWidget::ControlsToAction() { QActionWidget::ControlsToAction(); - m_Controls->Severity->GetValue(m_Controls->Action.GetSeverity()); + m_Controls->RespirationRateSeverity->GetValue(m_Controls->Action.GetRespirationRateSeverity()); + m_Controls->TidalVolumeSeverity->GetValue(m_Controls->Action.GetTidalVolumeSeverity()); emit UpdateAction(m_Controls->Action, GetProcessTime()); } @@ -64,6 +70,8 @@ void QDyspneaWidget::ActionToControls(const SEDyspnea& action) { QActionWidget::ActionToControls(action); SEScalar data; - data.SetValue(action.GetSeverity()); - m_Controls->Severity->SetValue(data); + data.SetValue(action.GetRespirationRateSeverity()); + m_Controls->RespirationRateSeverity->SetValue(data); + data.SetValue(action.GetTidalVolumeSeverity()); + m_Controls->TidalVolumeSeverity->SetValue(data); } -- GitLab From da7203380532552cb14ada174232bdd1c310de6b Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Mon, 15 Jul 2024 10:19:38 -0400 Subject: [PATCH 03/11] Increment version (testing release candidates), and litle cmake clean up --- CMakeLists.txt | 4 ++-- cmake/external/External_Pulse.cmake | 1 + cmake/superbuild.cmake | 1 - src/Main.cxx | 2 +- src/ui/{Enviornment.ui => Environment.ui} | 22 +++++++++++----------- 5 files changed, 15 insertions(+), 15 deletions(-) rename src/ui/{Enviornment.ui => Environment.ui} (96%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 49b2a03..f829e17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.12) +cmake_minimum_required(VERSION 3.15) -project(PulseExplorer VERSION 3.1.0 LANGUAGES C CXX) +project(PulseExplorer VERSION 3.2.0 LANGUAGES C CXX) include(cmake/config.cmake) diff --git a/cmake/external/External_Pulse.cmake b/cmake/external/External_Pulse.cmake index 8669f74..f9b15ab 100644 --- a/cmake/external/External_Pulse.cmake +++ b/cmake/external/External_Pulse.cmake @@ -11,6 +11,7 @@ add_external_project_ex(Pulse -DPulse_DEPENDENT_BUILD:BOOL=ON -DPulse_JAVA_API:BOOL=ON -DPulse_PYTHON_API:BOOL=ON + -DPulse_MSVC_STATIC_RUNTIME:BOOL=OFF INSTALL_COMMAND ${SKIP_STEP_COMMAND} RELATIVE_INCLUDE_PATH "" DEPENDENCIES "" diff --git a/cmake/superbuild.cmake b/cmake/superbuild.cmake index 8da6637..d4ae2df 100644 --- a/cmake/superbuild.cmake +++ b/cmake/superbuild.cmake @@ -1,4 +1,3 @@ -include(${CMAKE_CURRENT_LIST_DIR}/config.cmake) function(define_dependency NAME) option(USE_SYSTEM_${NAME} diff --git a/src/Main.cxx b/src/Main.cxx index 653192d..dbf91f8 100644 --- a/src/Main.cxx +++ b/src/Main.cxx @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) QApplication::setApplicationName("Pulse Explorer"); QApplication::setOrganizationName("Kitware"); QApplication::setOrganizationDomain("kitware.com"); - QApplication::setApplicationVersion("3.0"); + QApplication::setApplicationVersion("3.2"); QApplication app(argc, argv); #ifdef Q_OS_MAC diff --git a/src/ui/Enviornment.ui b/src/ui/Environment.ui similarity index 96% rename from src/ui/Enviornment.ui rename to src/ui/Environment.ui index 0decaf5..b2f6f81 100644 --- a/src/ui/Enviornment.ui +++ b/src/ui/Environment.ui @@ -1,7 +1,7 @@ - EnviornmentWidget - + EnvironmentWidget + 0 @@ -18,8 +18,8 @@ - 757 - 337 + 787 + 352 @@ -37,7 +37,7 @@ DockWidget - + 0 @@ -102,7 +102,7 @@ 0 0 331 - 421 + 415 @@ -141,8 +141,8 @@ 0 0 - 304 - 197 + 294 + 193 @@ -175,8 +175,8 @@ 0 0 - 304 - 197 + 294 + 192 @@ -304,7 +304,7 @@ - + Save Environment File -- GitLab From 88da4bc1ad0f94635a857bf88eac81bb4eb89e0c Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Mon, 15 Jul 2024 10:25:31 -0400 Subject: [PATCH 04/11] Add initial modifiers menu and correct environment spelling --- src/DynamicControlsWidget.cxx | 56 ++- src/PulseExplorerLib.cmake | 9 +- src/controls/AddPopup.cxx | 6 +- ...rnmentWidget.cxx => EnvironmentWidget.cxx} | 70 +-- ...nviornmentWidget.h => EnvironmentWidget.h} | 10 +- src/controls/ModifiersWidget.cxx | 413 ++++++++++++++++++ src/controls/ModifiersWidget.h | 47 ++ src/ui/MainExplorerWindow.ui | 278 +++++++++++- src/ui/Modifiers.ui | 229 ++++++++++ src/ui/dark_tab.xml | 90 ++++ src/ui/default_tab.xml | 6 + 11 files changed, 1139 insertions(+), 75 deletions(-) rename src/controls/{EnviornmentWidget.cxx => EnvironmentWidget.cxx} (94%) rename src/controls/{EnviornmentWidget.h => EnvironmentWidget.h} (85%) create mode 100644 src/controls/ModifiersWidget.cxx create mode 100644 src/controls/ModifiersWidget.h create mode 100644 src/ui/Modifiers.ui create mode 100644 src/ui/dark_tab.xml create mode 100644 src/ui/default_tab.xml diff --git a/src/DynamicControlsWidget.cxx b/src/DynamicControlsWidget.cxx index 4ab036e..bff5f7f 100644 --- a/src/DynamicControlsWidget.cxx +++ b/src/DynamicControlsWidget.cxx @@ -12,7 +12,8 @@ See accompanying NOTICE file for details.*/ #include "controls/ActionsEditorWidget.h" #include "controls/DataRequestViewWidget.h" #include "controls/ScenarioActionsEditorWidget.h" -#include "controls/EnviornmentWidget.h" +#include "controls/EnvironmentWidget.h" +#include "controls/ModifiersWidget.h" //Showcases #include "showcases/AnaphylaxisShowcaseWidget.h" #include "showcases/MultiTraumaShowcaseWidget.h" @@ -40,7 +41,7 @@ public: delete ActionsEditor; delete DataRequestEditor; delete ScenarioActionsEditor; - delete EnviornmentEditor; + delete EnvironmentEditor; delete AnaphylaxisShowcaseWidget; delete MultiTraumaShowcaseWidget; } @@ -52,7 +53,8 @@ public: QActionsEditorWidget* ActionsEditor = nullptr; QScenarioActionsEditorWidget* ScenarioActionsEditor = nullptr; QDataRequestViewWidget* DataRequestEditor = nullptr; - QEnviornmentWidget* EnviornmentEditor = nullptr; + QEnvironmentWidget* EnvironmentEditor = nullptr; + QModifiersWidget* ModifiersEditor = nullptr; QAnaphylaxisShowcaseWidget* AnaphylaxisShowcaseWidget = nullptr; QMultiTraumaShowcaseWidget* MultiTraumaShowcaseWidget = nullptr; @@ -78,11 +80,14 @@ QDynamicControlsWidget::QDynamicControlsWidget(QPulse& qp, QWidget *parent, Qt:: m_Controls->ActionsEditor->setVisible(true); m_Controls->ActionsTab->layout()->addWidget(m_Controls->ActionsEditor); - m_Controls->DataRequestEditor = new QDataRequestViewWidget(m_Controls->Pulse, this); m_Controls->DataRequestEditor->setTitleBarWidget(new QWidget()); m_Controls->DataRequestEditor->setVisible(true); + m_Controls->ModifiersEditor = new QModifiersWidget(m_Controls->Pulse, this); + m_Controls->ModifiersEditor->setTitleBarWidget(new QWidget()); + m_Controls->ModifiersEditor->setVisible(true); + m_Controls->ScenarioActionsEditor = new QScenarioActionsEditorWidget(m_Controls->Pulse, this); m_Controls->ScenarioActionsEditor->setTitleBarWidget(new QWidget()); m_Controls->ScenarioActionsEditor->setVisible(true); @@ -91,9 +96,9 @@ QDynamicControlsWidget::QDynamicControlsWidget(QPulse& qp, QWidget *parent, Qt:: connect(m_Controls->ScenarioActionsEditor, SIGNAL(OpenAction(SEAction const&, SEScalarTime const&)), SLOT(OpenAction(SEAction const&, SEScalarTime const&))); connect(m_Controls->ActionsEditor, SIGNAL(UpdateAction(SEAction const&, SEScalarTime const&)), parentWidget(), SLOT(UpdateAction(SEAction const&, SEScalarTime const&))); - m_Controls->EnviornmentEditor = new QEnviornmentWidget(m_Controls->Pulse, this); - m_Controls->EnviornmentEditor->setTitleBarWidget(new QWidget()); - m_Controls->EnviornmentEditor->setVisible(true); + m_Controls->EnvironmentEditor = new QEnvironmentWidget(m_Controls->Pulse, this); + m_Controls->EnvironmentEditor->setTitleBarWidget(new QWidget()); + m_Controls->EnvironmentEditor->setVisible(true); QPixmap pic("resource/pulse_logo.png"); m_Controls->Icon->setPixmap(pic); @@ -123,7 +128,8 @@ QDynamicControlsWidget::~QDynamicControlsWidget() void QDynamicControlsWidget::AddTabWidgets(QTabWidget& tabWidget, int tabIdx) { tabWidget.widget(tabIdx++)->layout()->addWidget(m_Controls->DataRequestEditor); - tabWidget.widget(tabIdx++)->layout()->addWidget(m_Controls->EnviornmentEditor); + tabWidget.widget(tabIdx++)->layout()->addWidget(m_Controls->ModifiersEditor); + tabWidget.widget(tabIdx++)->layout()->addWidget(m_Controls->EnvironmentEditor); tabWidget.widget(tabIdx++)->layout()->addWidget(m_Controls->ScenarioActionsEditor); } @@ -135,7 +141,8 @@ void QDynamicControlsWidget::Clear() m_Controls->ActionsEditor->Clear(); m_Controls->DataRequestEditor->Clear(); m_Controls->ScenarioActionsEditor->Clear(); - m_Controls->EnviornmentEditor->Reset(); + m_Controls->EnvironmentEditor->Reset(); + m_Controls->ModifiersEditor->Reset(); m_Controls->ShowcaseWidget->setVisible(true); m_Controls->AnaphylaxisShowcaseWidget->setVisible(false); @@ -152,9 +159,11 @@ void QDynamicControlsWidget::Reset() m_Controls->ActionsEditor->Clear(); m_Controls->ActionsEditor->EnableInput(true); m_Controls->ActionsEditor->EnableEditControls(true); - m_Controls->EnviornmentEditor->Reset(); - m_Controls->EnviornmentEditor->EnableControls(true, false); + m_Controls->EnvironmentEditor->Reset(); + m_Controls->EnvironmentEditor->EnableControls(true, false); m_Controls->ScenarioActionsEditor->EnableControls(true); + m_Controls->ModifiersEditor->Reset(); + m_Controls->ModifiersEditor->EnableControls(false); m_Controls->DynamicControlsTab->setCurrentWidget(m_Controls->PatientTab); @@ -205,7 +214,8 @@ void QDynamicControlsWidget::SetupPulseEditor() m_Controls->ConditionsEditor->EnableInput(true); m_Controls->ActionsEditor->EnableInput(true); m_Controls->ActionsEditor->EnableEditControls(true); - m_Controls->EnviornmentEditor->EnableControls(true, false); + m_Controls->EnvironmentEditor->EnableControls(true, false); + m_Controls->ModifiersEditor->EnableControls(false); m_Controls->ScenarioActionsEditor->EnableControls(true); } @@ -384,6 +394,7 @@ void QDynamicControlsWidget::LoadScenario(SEScenario& scenario) // TODO Look for an Initial Environment Condition m_Controls->PatientEditor->EnableInput(m_Controls->ScenarioMode == ScenarioInput::Patient); m_Controls->ConditionsEditor->EnableInput(m_Controls->ScenarioMode == ScenarioInput::Patient); + // TODO Look for any active modifier actions } void QDynamicControlsWidget::SaveScenario(SEScenario& scenario) @@ -419,7 +430,8 @@ void QDynamicControlsWidget::StartEngine() m_Controls->ActionsEditor->EnableInput(false); m_Controls->ActionsEditor->EnableEditControls(false); - m_Controls->EnviornmentEditor->EnableControls(true, false); + m_Controls->EnvironmentEditor->EnableControls(true, false); + m_Controls->ModifiersEditor->EnableControls(false); m_Controls->ScenarioActionsEditor->EnableControls(false); @@ -436,7 +448,8 @@ bool QDynamicControlsWidget::SetupShowcase(QString name) m_Controls->ActionsEditor->EnableInput(false); m_Controls->ActionsEditor->EnableEditControls(false); m_Controls->ScenarioActionsEditor->EnableControls(false); - m_Controls->EnviornmentEditor->EnableControls(false, false); + m_Controls->EnvironmentEditor->EnableControls(false, false); + m_Controls->ModifiersEditor->EnableControls(false); if (name == "Anaphylaxis") { @@ -469,7 +482,8 @@ bool QDynamicControlsWidget::SetupShowcase(QString name) m_Controls->ActionsEditor->EnableInput(false); m_Controls->ActionsEditor->EnableEditControls(false); - m_Controls->EnviornmentEditor->EnableControls(true, false); + m_Controls->EnvironmentEditor->EnableControls(true, false); + m_Controls->ModifiersEditor->EnableControls(false); m_Controls->ScenarioActionsEditor->EnableControls(false); return true; @@ -481,7 +495,8 @@ void QDynamicControlsWidget::AtSteadyState(PhysiologyEngine& pulse) m_Controls->ConditionsEditor->AtSteadyState(pulse); m_Controls->ActionsEditor->AtSteadyState(pulse); m_Controls->DataRequestEditor->AtSteadyState(pulse); - m_Controls->EnviornmentEditor->AtSteadyState(pulse); + m_Controls->EnvironmentEditor->AtSteadyState(pulse); + m_Controls->ModifiersEditor->AtSteadyState(pulse); m_Controls->ScenarioActionsEditor->AtSteadyState(pulse); m_Controls->AnaphylaxisShowcaseWidget->AtSteadyState(pulse); @@ -493,7 +508,8 @@ void QDynamicControlsWidget::AtSteadyStateUpdateUI() m_Controls->ConditionsEditor->AtSteadyStateUpdateUI(); m_Controls->ActionsEditor->AtSteadyStateUpdateUI(); m_Controls->DataRequestEditor->AtSteadyStateUpdateUI(); - m_Controls->EnviornmentEditor->AtSteadyStateUpdateUI(); + m_Controls->EnvironmentEditor->AtSteadyStateUpdateUI(); + m_Controls->ModifiersEditor->AtSteadyStateUpdateUI(); m_Controls->ScenarioActionsEditor->AtSteadyStateUpdateUI(); m_Controls->AnaphylaxisShowcaseWidget->AtSteadyStateUpdateUI(); @@ -506,7 +522,8 @@ void QDynamicControlsWidget::ProcessPhysiology(PhysiologyEngine& pulse) m_Controls->ConditionsEditor->ProcessPhysiology(pulse); m_Controls->ActionsEditor->ProcessPhysiology(pulse); m_Controls->DataRequestEditor->ProcessPhysiology(pulse); - m_Controls->EnviornmentEditor->ProcessPhysiology(pulse); + m_Controls->EnvironmentEditor->ProcessPhysiology(pulse); + m_Controls->ModifiersEditor->ProcessPhysiology(pulse); m_Controls->ScenarioActionsEditor->ProcessPhysiology(pulse); m_Controls->AnaphylaxisShowcaseWidget->ProcessPhysiology(pulse); @@ -518,7 +535,8 @@ void QDynamicControlsWidget::PhysiologyUpdateUI(const std::vectorConditionsEditor->PhysiologyUpdateUI(actions); m_Controls->ActionsEditor->PhysiologyUpdateUI(actions); m_Controls->DataRequestEditor->PhysiologyUpdateUI(actions); - m_Controls->EnviornmentEditor->PhysiologyUpdateUI(actions); + m_Controls->EnvironmentEditor->PhysiologyUpdateUI(actions); + m_Controls->ModifiersEditor->PhysiologyUpdateUI(actions); m_Controls->ScenarioActionsEditor->PhysiologyUpdateUI(actions); m_Controls->AnaphylaxisShowcaseWidget->PhysiologyUpdateUI(actions); diff --git a/src/PulseExplorerLib.cmake b/src/PulseExplorerLib.cmake index 607b585..48000dc 100644 --- a/src/PulseExplorerLib.cmake +++ b/src/PulseExplorerLib.cmake @@ -21,10 +21,11 @@ explorer_add_library(PulseExplorerWidgets controls/ConditionsEditorWidget.h controls/DataRequestWidget.h controls/DataRequestViewWidget.h - controls/EnviornmentWidget.h + controls/EnvironmentWidget.h #controls/Icon.h controls/LabeledComboBox.h controls/LabeledDialWidget.h + controls/ModifiersWidget.h controls/NumberWidget.h #controls/Palette.h controls/PatientEditorWidget.h @@ -100,10 +101,11 @@ explorer_add_library(PulseExplorerWidgets controls/ConditionsEditorWidget.cxx controls/DataRequestViewWidget.cxx controls/DataRequestWidget.cxx - controls/EnviornmentWidget.cxx + controls/EnvironmentWidget.cxx #controls/Icon.cpp controls/LabeledComboBox.cxx controls/LabeledDialWidget.cxx + controls/ModifiersWidget.cxx controls/NumberWidget.cxx #controls/Palette.cpp controls/PatientEditorWidget.cxx @@ -178,8 +180,9 @@ explorer_add_library(PulseExplorerWidgets ui/Condition.ui ui/DataRequest.ui ui/DataRequestView.ui - ui/Enviornment.ui + ui/Environment.ui ui/LabeledDialWidget.ui + ui/Modifiers.ui ui/NumberWidget.ui ui/PatientEditor.ui ui/PlotSet.ui diff --git a/src/controls/AddPopup.cxx b/src/controls/AddPopup.cxx index 6d01076..b28a1bb 100644 --- a/src/controls/AddPopup.cxx +++ b/src/controls/AddPopup.cxx @@ -49,7 +49,7 @@ See accompanying NOTICE file for details.*/ #include "DataRequestsWidget.h" #include "VitalsMonitorWidget.h" #include "DynamicControlsWidget.h" -#include "EnviornmentWidget.h" +#include "EnvironmentWidget.h" #include "cdm/CommonDataModel.h" #include "PulsePhysiologyEngine.h" #include "cdm/engine/SEDataRequestManager.h" @@ -74,12 +74,12 @@ public: std::stringstream Status; double CurrentSimTime_s; InputMode Mode = InputMode::None; - QEnviornmentWidget* envir; + QEnvironmentWidget* envir; }; AddPopup::AddPopup(std::string name,QWidget *parent):QDialog(parent),Ui(new Ui::AddPopup) { - QEnviornmentWidget* envir = dynamic_cast (parent); + QEnvironmentWidget* envir = dynamic_cast (parent); m_Controls = new Controls(); m_Controls->setupUi(this); setWindowIcon(QIcon("resource/pulse.ico")); diff --git a/src/controls/EnviornmentWidget.cxx b/src/controls/EnvironmentWidget.cxx similarity index 94% rename from src/controls/EnviornmentWidget.cxx rename to src/controls/EnvironmentWidget.cxx index d86a08f..fd3759e 100644 --- a/src/controls/EnviornmentWidget.cxx +++ b/src/controls/EnvironmentWidget.cxx @@ -1,14 +1,14 @@ /* Distributed under the Apache License, Version 2.0. See accompanying NOTICE file for details.*/ -#include "EnviornmentWidget.h" -#include "ui_Enviornment.h" +#include "EnvironmentWidget.h" +#include "ui_Environment.h" #include #include #include #include #include "controls/AddPopup.h" -#include "controls/EnviornmentWidget.h" +#include "controls/EnvironmentWidget.h" #include "controls/ScalarWidget.h" #include "controls/ScalarQuantityWidget.h" @@ -42,13 +42,13 @@ See accompanying NOTICE file for details.*/ #include "pulse/cdm/properties/SEScalarPower.h" #include "pulse/cdm/utils/FileUtils.h" -class QEnviornmentWidget::Controls : public Ui::EnviornmentWidget +class QEnvironmentWidget::Controls : public Ui::EnvironmentWidget { public: Controls(QPulse& qp) : Pulse(qp) {} QPulse& Pulse; - std::string type = "Enviornment"; + std::string type = "Environment"; // Environmental Conditions QScalarQuantityWidget* AirDensity; QScalarQuantityWidget* AirVelocity; @@ -97,7 +97,7 @@ public: bool AppliedFracLast = false; }; -QEnviornmentWidget::QEnviornmentWidget(QPulse& qp, QWidget *parent, Qt::WindowFlags flags) : QDockWidget(parent,flags) +QEnvironmentWidget::QEnvironmentWidget(QPulse& qp, QWidget *parent, Qt::WindowFlags flags) : QDockWidget(parent,flags) { m_Controls = new Controls(qp); m_Controls->setupUi(this); @@ -261,18 +261,18 @@ QEnviornmentWidget::QEnviornmentWidget(QPulse& qp, QWidget *parent, Qt::WindowFl connect(m_Controls->ApplyAll, SIGNAL(clicked()), this, SLOT(ControlsToEnvironment())); connect(m_Controls->LoadEnvironment, SIGNAL(clicked()), this, SLOT(LoadEnvironmentFile())); - connect(m_Controls->SaveEnviornment, SIGNAL(clicked()), this, SLOT(SaveEnvironmentFile())); + connect(m_Controls->SaveEnvironment, SIGNAL(clicked()), this, SLOT(SaveEnvironmentFile())); Reset(); } -QEnviornmentWidget::~QEnviornmentWidget() +QEnvironmentWidget::~QEnvironmentWidget() { // TODO Clean up all the widgets - m_Controls->Enviornment->close(); + m_Controls->Environment->close(); delete m_Controls; } -void QEnviornmentWidget::Reset() +void QEnvironmentWidget::Reset() { LoadEnvironmentFile(QPulse::GetDataDir().toStdString()+"/environments/Standard.json"); m_Controls->sendEnvironment = false; @@ -294,7 +294,7 @@ void QEnviornmentWidget::Reset() EnableControls(true, false); } -void QEnviornmentWidget::EnableControls(bool conditions, bool actions) +void QEnvironmentWidget::EnableControls(bool conditions, bool actions) { m_Controls->AirDensity->EnableInput(conditions); m_Controls->AirVelocity->EnableInput(conditions); @@ -314,7 +314,7 @@ void QEnviornmentWidget::EnableControls(bool conditions, bool actions) m_Controls->AmbientSmoke->EnableInput(conditions); m_Controls->LoadEnvironment->setEnabled(conditions); - m_Controls->SaveEnviornment->setEnabled(conditions); + m_Controls->SaveEnvironment->setEnabled(conditions); m_Controls->ActiveCoolingCheck->setChecked(false); m_Controls->ActiveCoolingCheck->setEnabled(actions); @@ -330,7 +330,7 @@ void QEnviornmentWidget::EnableControls(bool conditions, bool actions) m_Controls->ApplyAll->setEnabled(actions); } -void QEnviornmentWidget::LoadEnvironmentFile() +void QEnvironmentWidget::LoadEnvironmentFile() { QString fileName = QFileDialog::getOpenFileName(this, "Open Environment", QPulse::GetDataDir()+"/environments", "JSON (*.json);;Protobuf Binary (*.pbb)"); @@ -340,42 +340,42 @@ void QEnviornmentWidget::LoadEnvironmentFile() std::string s = fileName.toStdString(); LoadEnvironmentFile(s); } -void QEnviornmentWidget::LoadEnvironmentFile(const std::string& fileName) +void QEnvironmentWidget::LoadEnvironmentFile(const std::string& fileName) { if(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().SerializeFromFile(fileName, *m_Controls->SubMgr)) EnvironmentToControls(); else { QMessageBox messageBox; - std::string message = "Unable to load Enviornment File"; + std::string message = "Unable to load Environment File"; messageBox.critical(0, "Error", QString::fromUtf8(message.c_str())); messageBox.setFixedSize(500, 200); } } -void QEnviornmentWidget::SaveEnvironmentFile() +void QEnvironmentWidget::SaveEnvironmentFile() { QString fileName = QFileDialog::getSaveFileName(this, - "Save Enviornment", QPulse::GetSaveEnvironmentsDir(), "JSON (*.json);;Protobuf Binary (*.pbb)"); + "Save Environment", QPulse::GetSaveEnvironmentsDir(), "JSON (*.json);;Protobuf Binary (*.pbb)"); if (fileName.isEmpty()) return; std::string s = QPulse::AttemptRelativePath(fileName).toStdString(); - SaveEnviornmentFile(s); + SaveEnvironmentFile(s); } -void QEnviornmentWidget::SaveEnviornmentFile(const std::string& fileName) +void QEnvironmentWidget::SaveEnvironmentFile(const std::string& fileName) { ControlsToEnvironment(); if (!m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().SerializeToFile(fileName) ) { QMessageBox messageBox; - std::string message = "Unable to save Enviornment File"; + std::string message = "Unable to save Environment File"; messageBox.critical(0, "Error", QString::fromUtf8(message.c_str())); messageBox.setFixedSize(500, 200); } } -void QEnviornmentWidget::ControlsToEnvironment() +void QEnvironmentWidget::ControlsToEnvironment() { m_Controls->AirDensity->GetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAirDensity()); m_Controls->AirVelocity->GetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAirVelocity()); @@ -481,7 +481,7 @@ void QEnviornmentWidget::ControlsToEnvironment() } } -void QEnviornmentWidget::EnvironmentToControls() +void QEnvironmentWidget::EnvironmentToControls() { m_Controls->AirDensity->SetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAirDensity()); m_Controls->AirVelocity->SetValue(m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().GetAirVelocity()); @@ -533,18 +533,18 @@ void QEnviornmentWidget::EnvironmentToControls() // No need to push actions to the UI } -void QEnviornmentWidget::AtSteadyState(PhysiologyEngine& pulse) +void QEnvironmentWidget::AtSteadyState(PhysiologyEngine& pulse) { m_Controls->ChangeEnvironmentalConditions->GetEnvironmentalConditions().Copy(*pulse.GetEnvironment()->GetEnvironmentalConditions(), *m_Controls->SubMgr); } -void QEnviornmentWidget::AtSteadyStateUpdateUI() +void QEnvironmentWidget::AtSteadyStateUpdateUI() { EnvironmentToControls(); bool show = (m_Controls->Pulse.GetMode() == ExplorerMode::Editor); EnableControls(show, show); } -void QEnviornmentWidget::ProcessPhysiology(PhysiologyEngine& pulse) +void QEnvironmentWidget::ProcessPhysiology(PhysiologyEngine& pulse) {// This is called from a thread, you should NOT update UI here // This is where we pull data from pulse, and push any actions to it @@ -560,13 +560,13 @@ void QEnviornmentWidget::ProcessPhysiology(PhysiologyEngine& pulse) } } -void QEnviornmentWidget::PhysiologyUpdateUI(const std::vector& actions) +void QEnvironmentWidget::PhysiologyUpdateUI(const std::vector& actions) {// This is called from a slot, you can update UI here // Nothing is expected to be in the environment } -void QEnviornmentWidget::EnableCooling() +void QEnvironmentWidget::EnableCooling() { bool b = m_Controls->ActiveCoolingCheck->isChecked(); if (b) @@ -595,20 +595,20 @@ void QEnviornmentWidget::EnableCooling() m_Controls->CoolingFraction->setDisabled(true); } } -void QEnviornmentWidget::EnableCoolingSurfaceArea() +void QEnvironmentWidget::EnableCoolingSurfaceArea() { bool b = m_Controls->CoolingArea->GetRadioButton()->isChecked(); m_Controls->CoolingArea->EnableInput(b); m_Controls->CoolingFraction->EnableInput(!b); } -void QEnviornmentWidget::EnableCoolingSurfaceAreaFraction() +void QEnvironmentWidget::EnableCoolingSurfaceAreaFraction() { bool b = m_Controls->CoolingFraction->GetRadioButton()->isChecked(); m_Controls->CoolingArea->EnableInput(!b); m_Controls->CoolingFraction->EnableInput(b); } -void QEnviornmentWidget::EnableHeating() +void QEnvironmentWidget::EnableHeating() { bool b = m_Controls->ActiveHeatingCheck->isChecked(); if (b) @@ -637,20 +637,20 @@ void QEnviornmentWidget::EnableHeating() m_Controls->HeatingFraction->setDisabled(true); } } -void QEnviornmentWidget::EnableHeatingSurfaceArea() +void QEnvironmentWidget::EnableHeatingSurfaceArea() { bool b = m_Controls->HeatingArea->GetRadioButton()->isChecked(); m_Controls->HeatingArea->EnableInput(b); m_Controls->HeatingFraction->EnableInput(!b); } -void QEnviornmentWidget::EnableHeatingSurfaceAreaFraction() +void QEnvironmentWidget::EnableHeatingSurfaceAreaFraction() { bool b = m_Controls->HeatingFraction->GetRadioButton()->isChecked(); m_Controls->HeatingArea->EnableInput(!b); m_Controls->HeatingFraction->EnableInput(b); } -void QEnviornmentWidget::EnableAppliedTemp() +void QEnvironmentWidget::EnableAppliedTemp() { bool b = m_Controls->AppliedTempCheck->isChecked(); if (b) @@ -680,14 +680,14 @@ void QEnviornmentWidget::EnableAppliedTemp() } } -void QEnviornmentWidget::EnableAppliedTempSurfaceArea() +void QEnvironmentWidget::EnableAppliedTempSurfaceArea() { bool b = m_Controls->AppliedArea->GetRadioButton()->isChecked(); m_Controls->AppliedArea->EnableInput(b); m_Controls->AppliedFraction->EnableInput(!b); } -void QEnviornmentWidget::EnableAppliedSurfaceAreaFraction() +void QEnvironmentWidget::EnableAppliedSurfaceAreaFraction() { bool b = m_Controls->AppliedFraction->GetRadioButton()->isChecked(); m_Controls->AppliedArea->EnableInput(!b); diff --git a/src/controls/EnviornmentWidget.h b/src/controls/EnvironmentWidget.h similarity index 85% rename from src/controls/EnviornmentWidget.h rename to src/controls/EnvironmentWidget.h index 65c7b95..edf0bb3 100644 --- a/src/controls/EnviornmentWidget.h +++ b/src/controls/EnvironmentWidget.h @@ -9,15 +9,15 @@ See accompanying NOTICE file for details.*/ class SEEnvironmentalConditions; namespace Ui { - class EnviornmentWidget; + class EnvironmentWidget; } -class QEnviornmentWidget : public QDockWidget, public PulseListener +class QEnvironmentWidget : public QDockWidget, public PulseListener { Q_OBJECT public: - QEnviornmentWidget(QPulse& qp, QWidget *parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags()); - virtual ~QEnviornmentWidget(); + QEnvironmentWidget(QPulse& qp, QWidget *parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags()); + virtual ~QEnvironmentWidget(); void Reset(); //SECondition& GetInitialEnvironmentConditions(); @@ -44,7 +44,7 @@ protected slots: void LoadEnvironmentFile(); void LoadEnvironmentFile(const std::string& fileName); void SaveEnvironmentFile(); - void SaveEnviornmentFile(const std::string& fileName); + void SaveEnvironmentFile(const std::string& fileName); void ControlsToEnvironment(); diff --git a/src/controls/ModifiersWidget.cxx b/src/controls/ModifiersWidget.cxx new file mode 100644 index 0000000..c39d654 --- /dev/null +++ b/src/controls/ModifiersWidget.cxx @@ -0,0 +1,413 @@ +/* Distributed under the Apache License, Version 2.0. +See accompanying NOTICE file for details.*/ +#include "ModifiersWidget.h" +#include "ui_Modifiers.h" +#include +#include +#include +#include + +#include "controls/AddPopup.h" +#include "controls/ModifiersWidget.h" +#include "controls/ScalarWidget.h" +#include "controls/ScalarQuantityWidget.h" + +#include "pulse/engine/PulseEngine.h" +#include "pulse/cdm/engine/SEActionManager.h" +#include "pulse/cdm/engine/SEPatientActionCollection.h" +#include "pulse/cdm/patient/actions/SECardiovascularMechanicsModification.h" +#include "pulse/cdm/system/physiology/SECardiovascularMechanicsModifiers.h" +#include "pulse/cdm/patient/actions/SERespiratoryMechanicsModification.h" +#include "pulse/cdm/system/physiology/SERespiratoryMechanicsModifiers.h" +#include "pulse/cdm/properties/SEScalarUnsigned.h" +#include "pulse/cdm/properties/SEScalarVolume.h" +#include "pulse/cdm/utils/FileUtils.h" + +class QModifiersWidget::Controls : public Ui::ModifiersWidget +{ +public: + Controls(QPulse& qp) : Pulse(qp) {} + + QPulse& Pulse; + std::string type = "Modifiers"; + // Cardiovascular Modifiers + QScalarWidget* ArterialComplianceMultiplier; + QScalarWidget* ArterialResistanceMultiplier; + QScalarWidget* PulmonaryComplianceMultiplier; + QScalarWidget* PulmonaryResistanceMultiplier; + QScalarWidget* SystemicResistanceMultiplier; + QScalarWidget* SystemicComplianceMultiplier; + QScalarWidget* VenousComplianceMultiplier; + QScalarWidget* VenousResistanceMultiplier; + QScalarWidget* HeartRateMultiplier; + QScalarWidget* StrokeVolumeMultiplier; + bool SendCardiovascularAction = false; + bool PullCardiovascularModifiers = false; + bool PushCardiovascularModifiersToControls = false; + SECardiovascularMechanicsModification* CardioModifiers; + + // Respiratory Modifiers + QScalarWidget* LeftComplianceMultiplier; + QScalarWidget* RightComplianceMultiplier; + QScalarWidget* LeftExpiratoryResistanceMultiplier; + QScalarWidget* LeftInspiratoryResistanceMultiplier; + QScalarWidget* RightExpiratoryResistanceMultiplier; + QScalarWidget* RightInspiratoryResistanceMultiplier; + QScalarWidget* UpperExpiratoryResistanceMultiplier; + QScalarWidget* UpperInspiratoryResistanceMultiplier; + QScalarWidget* RespirationRateMultiplier; + QScalarWidget* TidalVolumeMultiplier; + QScalarQuantityWidget* LeftLungVolumeIncrement; + QScalarQuantityWidget* RightLungVolumeIncrement; + bool SendRespiratoryAction = false; + bool PullRespiratoryModifiers = false; + bool PushRespiratoryModifiersToControls = false; + SERespiratoryMechanicsModification* RespModifiers; +}; + +QModifiersWidget::QModifiersWidget(QPulse& qp, QWidget *parent, Qt::WindowFlags flags) : QDockWidget(parent,flags) +{ + m_Controls = new Controls(qp); + m_Controls->setupUi(this); + + //////////////////////////////////// + // Setup Cardiovascular Modifiers // + //////////////////////////////////// + m_Controls->SendCardiovascularAction = false; + m_Controls->PullCardiovascularModifiers = false; + m_Controls->PushCardiovascularModifiersToControls = false; + m_Controls->CardioModifiers = new SECardiovascularMechanicsModification(); + + m_Controls->ArterialComplianceMultiplier = new QScalarWidget("Arterial Compliance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->ArterialComplianceMultiplier->EnableInput(false); + m_Controls->CardiovascularProperties->layout()->addWidget(m_Controls->ArterialComplianceMultiplier); + + m_Controls->ArterialResistanceMultiplier = new QScalarWidget("Arterial Resistance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->ArterialResistanceMultiplier->EnableInput(false); + m_Controls->CardiovascularProperties->layout()->addWidget(m_Controls->ArterialResistanceMultiplier); + + m_Controls->PulmonaryComplianceMultiplier = new QScalarWidget("Pulmonary Compliance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->PulmonaryComplianceMultiplier->EnableInput(false); + m_Controls->CardiovascularProperties->layout()->addWidget(m_Controls->PulmonaryComplianceMultiplier); + + m_Controls->PulmonaryResistanceMultiplier = new QScalarWidget("Pulmonary Resistance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->PulmonaryResistanceMultiplier->EnableInput(false); + m_Controls->CardiovascularProperties->layout()->addWidget(m_Controls->PulmonaryResistanceMultiplier); + + m_Controls->SystemicResistanceMultiplier = new QScalarWidget("Systemic Resistance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->SystemicResistanceMultiplier->EnableInput(false); + m_Controls->CardiovascularProperties->layout()->addWidget(m_Controls->SystemicResistanceMultiplier); + + m_Controls->SystemicComplianceMultiplier = new QScalarWidget("Systemic Compliance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->SystemicComplianceMultiplier->EnableInput(false); + m_Controls->CardiovascularProperties->layout()->addWidget(m_Controls->SystemicComplianceMultiplier); + + m_Controls->VenousComplianceMultiplier = new QScalarWidget("Venous Compliance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->VenousComplianceMultiplier->EnableInput(false); + m_Controls->CardiovascularProperties->layout()->addWidget(m_Controls->VenousComplianceMultiplier); + + m_Controls->VenousResistanceMultiplier = new QScalarWidget("Venous Resistance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->VenousResistanceMultiplier->EnableInput(false); + m_Controls->CardiovascularProperties->layout()->addWidget(m_Controls->VenousResistanceMultiplier); + + m_Controls->HeartRateMultiplier = new QScalarWidget("Heart Rate Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->HeartRateMultiplier->EnableInput(false); + m_Controls->CardiovascularProperties->layout()->addWidget(m_Controls->HeartRateMultiplier); + + m_Controls->StrokeVolumeMultiplier = new QScalarWidget("Stroke Volume Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->StrokeVolumeMultiplier->EnableInput(false); + m_Controls->CardiovascularProperties->layout()->addWidget(m_Controls->StrokeVolumeMultiplier); + + ///////////////////////////////// + // Setup Respiratory Modifiers // + ///////////////////////////////// + m_Controls->SendRespiratoryAction = false; + m_Controls->PullRespiratoryModifiers = false; + m_Controls->PushRespiratoryModifiersToControls = false; + m_Controls->RespModifiers = new SERespiratoryMechanicsModification(); + + m_Controls->LeftComplianceMultiplier = new QScalarWidget("Left Compliance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->LeftComplianceMultiplier->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->LeftComplianceMultiplier); + + m_Controls->RightComplianceMultiplier = new QScalarWidget("Right Compliance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->RightComplianceMultiplier->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->RightComplianceMultiplier); + + m_Controls->LeftExpiratoryResistanceMultiplier = new QScalarWidget("Left Expiratory Resistance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->LeftExpiratoryResistanceMultiplier->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->LeftExpiratoryResistanceMultiplier); + + m_Controls->LeftInspiratoryResistanceMultiplier = new QScalarWidget("Left Inspiratory Resistance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->LeftInspiratoryResistanceMultiplier->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->LeftInspiratoryResistanceMultiplier); + + m_Controls->RightExpiratoryResistanceMultiplier = new QScalarWidget("Right Expiratory Resistance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->RightExpiratoryResistanceMultiplier->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->RightExpiratoryResistanceMultiplier); + + m_Controls->RightInspiratoryResistanceMultiplier = new QScalarWidget("Right Inspiratory Resistance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->RightInspiratoryResistanceMultiplier->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->RightInspiratoryResistanceMultiplier); + + m_Controls->UpperExpiratoryResistanceMultiplier = new QScalarWidget("Upper Expiratory Resistance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->UpperExpiratoryResistanceMultiplier->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->UpperExpiratoryResistanceMultiplier); + + m_Controls->UpperInspiratoryResistanceMultiplier = new QScalarWidget("Upper Inspiratory Resistance Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->UpperInspiratoryResistanceMultiplier->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->UpperInspiratoryResistanceMultiplier); + + m_Controls->RespirationRateMultiplier = new QScalarWidget("Respiration Rate Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->RespirationRateMultiplier->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->RespirationRateMultiplier); + + m_Controls->TidalVolumeMultiplier = new QScalarWidget("Tidal Volume Multiplier", 1.0, 10.0, .1, ScalarOptionWidget::Check, this); + m_Controls->TidalVolumeMultiplier->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->TidalVolumeMultiplier); + + ///////////////////////////////// + // Setup Lung Volume Modifiers // + ///////////////////////////////// + + m_Controls->LeftLungVolumeIncrement = new QScalarQuantityWidget("Left Lung Volume Increment", 0.0, 100.0, 1.0, VolumeUnit::mL, ScalarOptionWidget::Check, this); + m_Controls->LeftLungVolumeIncrement->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->LeftLungVolumeIncrement); + + m_Controls->RightLungVolumeIncrement = new QScalarQuantityWidget("Right Lung Volume Increment", 0.0, 100.0, 1.0, VolumeUnit::mL, ScalarOptionWidget::Check, this); + m_Controls->RightLungVolumeIncrement->EnableInput(false); + m_Controls->RespiratoryProperties->layout()->addWidget(m_Controls->RightLungVolumeIncrement); + + + connect(m_Controls->ApplyCardiovascular, SIGNAL(clicked()), this, SLOT(CardiovascularControlsToPulse())); + connect(m_Controls->ResetCardiovascular, SIGNAL(clicked()), this, SLOT(PulseToCardiovascularControls())); + connect(m_Controls->ApplyRespiratory, SIGNAL(clicked()), this, SLOT(RespiratoryControlsToPulse())); + connect(m_Controls->ResetRespiratory, SIGNAL(clicked()), this, SLOT(PulseToRespiratoryControls())); + Reset(); +} + +QModifiersWidget::~QModifiersWidget() +{ + // TODO Clean up all the widgets + m_Controls->Modifiers->close(); + delete m_Controls; +} + +void QModifiersWidget::Reset() +{ + EnableControls(false); + PulseToCardiovascularControls(); + PulseToRespiratoryControls(); +} + +void QModifiersWidget::EnableControls(bool b) +{ + m_Controls->ArterialComplianceMultiplier->EnableInput(b,false); + m_Controls->ArterialResistanceMultiplier->EnableInput(b, false); + m_Controls->PulmonaryComplianceMultiplier->EnableInput(b, false); + m_Controls->PulmonaryResistanceMultiplier->EnableInput(b, false); + m_Controls->SystemicResistanceMultiplier->EnableInput(b, false); + m_Controls->SystemicComplianceMultiplier->EnableInput(b, false); + m_Controls->VenousComplianceMultiplier->EnableInput(b, false); + m_Controls->VenousResistanceMultiplier->EnableInput(b, false); + m_Controls->HeartRateMultiplier->EnableInput(b, false); + m_Controls->StrokeVolumeMultiplier->EnableInput(b, false); + m_Controls->ApplyCardiovascular->setEnabled(b); + m_Controls->ResetCardiovascular->setEnabled(b); + + m_Controls->LeftComplianceMultiplier->EnableInput(b, false); + m_Controls->RightComplianceMultiplier->EnableInput(b, false); + m_Controls->LeftExpiratoryResistanceMultiplier->EnableInput(b, false); + m_Controls->LeftInspiratoryResistanceMultiplier->EnableInput(b, false); + m_Controls->RightExpiratoryResistanceMultiplier->EnableInput(b, false); + m_Controls->RightInspiratoryResistanceMultiplier->EnableInput(b, false); + m_Controls->UpperExpiratoryResistanceMultiplier->EnableInput(b, false); + m_Controls->UpperInspiratoryResistanceMultiplier->EnableInput(b, false); + m_Controls->RespirationRateMultiplier->EnableInput(b, false); + m_Controls->TidalVolumeMultiplier->EnableInput(b, false); + m_Controls->LeftLungVolumeIncrement->EnableInput(b, false); + m_Controls->RightLungVolumeIncrement->EnableInput(b, false); + m_Controls->ApplyRespiratory->setEnabled(b); + m_Controls->ResetRespiratory->setEnabled(b); +} + +void QModifiersWidget::ResetControls() +{ + m_Controls->ArterialComplianceMultiplier->Reset(); + m_Controls->ArterialResistanceMultiplier->Reset(); + m_Controls->PulmonaryComplianceMultiplier->Reset(); + m_Controls->PulmonaryResistanceMultiplier->Reset(); + m_Controls->SystemicResistanceMultiplier->Reset(); + m_Controls->SystemicComplianceMultiplier->Reset(); + m_Controls->VenousComplianceMultiplier->Reset(); + m_Controls->VenousResistanceMultiplier->Reset(); + m_Controls->HeartRateMultiplier->Reset(); + m_Controls->StrokeVolumeMultiplier->Reset(); + + m_Controls->LeftComplianceMultiplier->Reset(); + m_Controls->RightComplianceMultiplier->Reset(); + m_Controls->LeftExpiratoryResistanceMultiplier->Reset(); + m_Controls->LeftInspiratoryResistanceMultiplier->Reset(); + m_Controls->RightExpiratoryResistanceMultiplier->Reset(); + m_Controls->RightInspiratoryResistanceMultiplier->Reset(); + m_Controls->UpperExpiratoryResistanceMultiplier->Reset(); + m_Controls->UpperInspiratoryResistanceMultiplier->Reset(); + m_Controls->RespirationRateMultiplier->Reset(); + m_Controls->TidalVolumeMultiplier->Reset(); + m_Controls->LeftLungVolumeIncrement->Reset(); + m_Controls->RightLungVolumeIncrement->Reset(); +} + +void QModifiersWidget::CardiovascularControlsToPulse() +{ + m_Controls->CardioModifiers->Clear(); + auto& m = m_Controls->CardioModifiers->GetModifiers(); + if (m_Controls->ArterialComplianceMultiplier->IsChecked()) + m_Controls->ArterialComplianceMultiplier->GetValue(m.GetArterialComplianceMultiplier()); + if (m_Controls->ArterialResistanceMultiplier->IsChecked()) + m_Controls->ArterialResistanceMultiplier->GetValue(m.GetArterialResistanceMultiplier()); + if (m_Controls->PulmonaryComplianceMultiplier->IsChecked()) + m_Controls->PulmonaryComplianceMultiplier->GetValue(m.GetPulmonaryComplianceMultiplier()); + if (m_Controls->PulmonaryResistanceMultiplier->IsChecked()) + m_Controls->PulmonaryResistanceMultiplier->GetValue(m.GetPulmonaryResistanceMultiplier()); + if (m_Controls->SystemicResistanceMultiplier->IsChecked()) + m_Controls->SystemicResistanceMultiplier->GetValue(m.GetSystemicResistanceMultiplier()); + if (m_Controls->SystemicComplianceMultiplier->IsChecked()) + m_Controls->SystemicComplianceMultiplier->GetValue(m.GetSystemicComplianceMultiplier()); + if (m_Controls->VenousComplianceMultiplier->IsChecked()) + m_Controls->VenousComplianceMultiplier->GetValue(m.GetVenousComplianceMultiplier()); + if (m_Controls->VenousResistanceMultiplier->IsChecked()) + m_Controls->VenousResistanceMultiplier->GetValue(m.GetVenousResistanceMultiplier()); + if (m_Controls->HeartRateMultiplier->IsChecked()) + m_Controls->HeartRateMultiplier->GetValue(m.GetHeartRateMultiplier()); + if (m_Controls->StrokeVolumeMultiplier->IsChecked()) + m_Controls->StrokeVolumeMultiplier->GetValue(m.GetStrokeVolumeMultiplier()); + + m_Controls->SendCardiovascularAction = true; +} + +void QModifiersWidget::UpdateControls(SECardiovascularMechanicsModifiers const& m) +{ + +} + +void QModifiersWidget::PulseToCardiovascularControls() +{ + m_Controls->PullCardiovascularModifiers = true; +} + +void QModifiersWidget::RespiratoryControlsToPulse() +{ + m_Controls->RespModifiers->Clear(); + auto& m = m_Controls->RespModifiers->GetModifiers(); + if (m_Controls->LeftComplianceMultiplier->IsChecked()) + m_Controls->LeftComplianceMultiplier->GetValue(m.GetLeftComplianceMultiplier()); + if (m_Controls->RightComplianceMultiplier->IsChecked()) + m_Controls->RightComplianceMultiplier->GetValue(m.GetRightComplianceMultiplier()); + if (m_Controls->LeftExpiratoryResistanceMultiplier->IsChecked()) + m_Controls->LeftExpiratoryResistanceMultiplier->GetValue(m.GetLeftExpiratoryResistanceMultiplier()); + if (m_Controls->LeftInspiratoryResistanceMultiplier->IsChecked()) + m_Controls->LeftInspiratoryResistanceMultiplier->GetValue(m.GetLeftInspiratoryResistanceMultiplier()); + if (m_Controls->RightExpiratoryResistanceMultiplier->IsChecked()) + m_Controls->RightExpiratoryResistanceMultiplier->GetValue(m.GetRightExpiratoryResistanceMultiplier()); + if (m_Controls->RightInspiratoryResistanceMultiplier->IsChecked()) + m_Controls->RightInspiratoryResistanceMultiplier->GetValue(m.GetRightInspiratoryResistanceMultiplier()); + if (m_Controls->UpperExpiratoryResistanceMultiplier->IsChecked()) + m_Controls->UpperExpiratoryResistanceMultiplier->GetValue(m.GetUpperExpiratoryResistanceMultiplier()); + if (m_Controls->UpperInspiratoryResistanceMultiplier->IsChecked()) + m_Controls->UpperInspiratoryResistanceMultiplier->GetValue(m.GetUpperInspiratoryResistanceMultiplier()); + if (m_Controls->RespirationRateMultiplier->IsChecked()) + m_Controls->RespirationRateMultiplier->GetValue(m.GetRespirationRateMultiplier()); + if (m_Controls->TidalVolumeMultiplier->IsChecked()) + m_Controls->TidalVolumeMultiplier->GetValue(m.GetTidalVolumeMultiplier()); + + if (m_Controls->LeftLungVolumeIncrement->IsChecked()) + m_Controls->LeftLungVolumeIncrement->GetValue(m.GetLungVolumeIncrement(eLungCompartment::LeftLung)); + if (m_Controls->RightLungVolumeIncrement->IsChecked()) + m_Controls->RightLungVolumeIncrement->GetValue(m.GetLungVolumeIncrement(eLungCompartment::RightLung)); + + m_Controls->SendRespiratoryAction = true; +} + +void QModifiersWidget::UpdateControls(SERespiratoryMechanicsModifiers const& m) +{ + +} + +void QModifiersWidget::PulseToRespiratoryControls() +{ + m_Controls->PullRespiratoryModifiers = true; +} + +void QModifiersWidget::AtSteadyState(PhysiologyEngine& pulse) +{ + +} +void QModifiersWidget::AtSteadyStateUpdateUI() +{ + bool show = (m_Controls->Pulse.GetMode() == ExplorerMode::Editor); + EnableControls(show); +} + +void QModifiersWidget::ProcessPhysiology(PhysiologyEngine& pulse) +{// This is called from a thread, you should NOT update UI here + // This is where we pull data from pulse, and push any actions to it + + if (m_Controls->SendCardiovascularAction) + { + m_Controls->CardioModifiers->SetIncremental(true); + pulse.ProcessAction(*m_Controls->CardioModifiers); + m_Controls->SendCardiovascularAction = false; + } + + if (m_Controls->PullCardiovascularModifiers) + { + if (pulse.GetActionManager().GetPatientActions().HasCardiovascularMechanicsModification()) + { + m_Controls->CardioModifiers->Copy( + *pulse.GetActionManager().GetPatientActions().GetCardiovascularMechanicsModification()); + } + else + { + m_Controls->CardioModifiers->Clear(); + } + m_Controls->PullCardiovascularModifiers = false; + m_Controls->PushCardiovascularModifiersToControls = true; + } + + if (m_Controls->SendRespiratoryAction) + { + m_Controls->RespModifiers->SetIncremental(true); + pulse.ProcessAction(*m_Controls->RespModifiers); + m_Controls->SendRespiratoryAction = false; + } + + if (m_Controls->PullRespiratoryModifiers) + { + if (pulse.GetActionManager().GetPatientActions().HasRespiratoryMechanicsModification()) + { + m_Controls->RespModifiers->Copy( + *pulse.GetActionManager().GetPatientActions().GetRespiratoryMechanicsModification()); + } + else + { + m_Controls->RespModifiers->Clear(); + } + m_Controls->PullRespiratoryModifiers = false; + m_Controls->PushRespiratoryModifiersToControls = true; + } +} +void QModifiersWidget::PhysiologyUpdateUI(const std::vector& actions) +{// This is called from a slot, you can update UI here + if (m_Controls->PushCardiovascularModifiersToControls) + { + UpdateControls(m_Controls->CardioModifiers->GetModifiers()); + m_Controls->PushCardiovascularModifiersToControls = false; + } + + if (m_Controls->PushRespiratoryModifiersToControls) + { + UpdateControls(m_Controls->RespModifiers->GetModifiers()); + m_Controls->PushRespiratoryModifiersToControls = false; + } +} diff --git a/src/controls/ModifiersWidget.h b/src/controls/ModifiersWidget.h new file mode 100644 index 0000000..a4cac5b --- /dev/null +++ b/src/controls/ModifiersWidget.h @@ -0,0 +1,47 @@ +/* Distributed under the Apache License, Version 2.0. +See accompanying NOTICE file for details.*/ +#pragma once + +#include +#include +#include "QPulse.h" + +namespace Ui { + class ModifiersWidget; +} + +class SECardiovascularMechanicsModifiers; +class SERespiratoryMechanicsModifiers; + +class QModifiersWidget : public QDockWidget, public PulseListener +{ + Q_OBJECT +public: + QModifiersWidget(QPulse& qp, QWidget *parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags()); + virtual ~QModifiersWidget(); + + void Reset(); + + void EnableControls(bool b); + + void UpdateControls(SECardiovascularMechanicsModifiers const& m); + void UpdateControls(SERespiratoryMechanicsModifiers const& m); + + void AtSteadyState(PhysiologyEngine& pulse) override; + void AtSteadyStateUpdateUI() override;// Main Window will call this to update UI Components + void ProcessPhysiology(PhysiologyEngine& pulse) override; + void PhysiologyUpdateUI(const std::vector& actions) override;// Main Window will call this to update UI Components + void EngineErrorUI() override {};// Main Window will call this to update UI Components + +//signals: +protected slots: + void ResetControls(); + void CardiovascularControlsToPulse(); + void PulseToCardiovascularControls(); + void RespiratoryControlsToPulse(); + void PulseToRespiratoryControls(); + +private: + class Controls; + Controls* m_Controls; +}; \ No newline at end of file diff --git a/src/ui/MainExplorerWindow.ui b/src/ui/MainExplorerWindow.ui index 99f0316..c315a38 100644 --- a/src/ui/MainExplorerWindow.ui +++ b/src/ui/MainExplorerWindow.ui @@ -14,7 +14,7 @@ Pulse Explorer - + @@ -144,7 +144,7 @@ - 5 + 3 @@ -185,8 +185,126 @@ 0 + + + + + + + 211 + 211 + 211 + + + + + + + 170 + 255 + 0 + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + + + + + 211 + 211 + 211 + + + + + + + 170 + 255 + 0 + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + + + + + 211 + 211 + 211 + + + + + + + 170 + 255 + 0 + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + + - #DataRequestsTab { background: lightgrey } + QWidget#DataRequestsTab { background: lightgrey } Data Requests @@ -197,7 +315,144 @@ - + + + + 0 + 0 + + + + + + + + + 211 + 211 + 211 + + + + + + + 240 + 240 + 240 + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + + + + + 211 + 211 + 211 + + + + + + + 240 + 240 + 240 + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + + + + + 211 + 211 + 211 + + + + + + + 240 + 240 + 240 + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + + + + QWidget#ModifierTab { background: lightgrey } + + + Modifiers + + + + + + + + 0 @@ -205,7 +460,7 @@ - true + false QWidget#EnvironmentTab { background: lightgrey } @@ -215,7 +470,7 @@ - + @@ -311,10 +566,13 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><br /></p></body></html> +hr { height: 1px; border-width: 0; } +li.unchecked::marker { content: "\2610"; } +li.checked::marker { content: "\2612"; } +</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:12pt;"><br /></p></body></html> @@ -330,7 +588,7 @@ p, li { white-space: pre-wrap; } 0 0 1440 - 21 + 22 diff --git a/src/ui/Modifiers.ui b/src/ui/Modifiers.ui new file mode 100644 index 0000000..ca30660 --- /dev/null +++ b/src/ui/Modifiers.ui @@ -0,0 +1,229 @@ + + + ModifiersWidget + + + + 0 + 0 + 915 + 747 + + + + + 0 + 0 + + + + + 787 + 747 + + + + + 524287 + 524287 + + + + true + + + QDockWidget::NoDockWidgetFeatures + + + DockWidget + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + + + Cardiovascular Modifiers + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + true + + + + + 0 + 0 + 380 + 599 + + + + + + + + + + + + Reset + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Apply + + + + + + + + + + + + + + + + + + Respiratory Modifiers + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + true + + + + + 0 + 0 + 379 + 599 + + + + + + + + + + + + Reset + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Apply + + + + + + + + + + + + + + + + + + + + diff --git a/src/ui/dark_tab.xml b/src/ui/dark_tab.xml new file mode 100644 index 0000000..3ac3551 --- /dev/null +++ b/src/ui/dark_tab.xml @@ -0,0 +1,90 @@ + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + + + 211 + 211 + 211 + + + + + diff --git a/src/ui/default_tab.xml b/src/ui/default_tab.xml new file mode 100644 index 0000000..b8fafb2 --- /dev/null +++ b/src/ui/default_tab.xml @@ -0,0 +1,6 @@ + + + + + + -- GitLab From 1dbc1af394866cf921c877d9143b5bc9316fe5a9 Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Mon, 15 Jul 2024 10:26:36 -0400 Subject: [PATCH 05/11] Support a ratio display for a number widet --- src/controls/NumberWidget.cxx | 16 ++++++++++++++-- src/controls/NumberWidget.h | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/controls/NumberWidget.cxx b/src/controls/NumberWidget.cxx index 56181f4..1929da0 100644 --- a/src/controls/NumberWidget.cxx +++ b/src/controls/NumberWidget.cxx @@ -17,6 +17,7 @@ struct NumberWidget::Private : public Ui::NumberWidget double actualValue = 0.0; QString name; QString unit; + bool isRatio = false; SEDataRequest* request; }; @@ -33,11 +34,12 @@ NumberWidget::~NumberWidget() delete d; } -void NumberWidget::setup(QString name, QString unit, int precision /*= 0*/) +void NumberWidget::setup(QString name, QString unit, int precision /*= 0*/, bool isRatio /*=false*/) { setName(name); setUnit(unit); setPrecision(precision); + d->isRatio = isRatio; } QString NumberWidget::getName() const @@ -69,7 +71,17 @@ double NumberWidget::getValue() const void NumberWidget::setValue(double val) { - d->value->setText(QString::number( (std::round(val * d->factor)) / d->factor , 'f', d->precision)); + if (d->isRatio) + { + val = 1 / val; + d->value->setText("1:"+QString::number((std::round(val * d->factor)) / d->factor, 'f', d->precision)); + } + else + { + d->value->setText(QString::number((std::round(val * d->factor)) / d->factor, 'f', d->precision)); + } + + d->actualValue = val; } diff --git a/src/controls/NumberWidget.h b/src/controls/NumberWidget.h index 8000508..861a9db 100644 --- a/src/controls/NumberWidget.h +++ b/src/controls/NumberWidget.h @@ -24,7 +24,7 @@ public: Q_PROPERTY(double value READ getValue WRITE setValue) Q_PROPERTY(int precision READ getPrecision WRITE setPrecision) - void setup(QString name, QString unit, int precision = 0); + void setup(QString name, QString unit, int precision = 0, bool isRatio=false); QString getName() const; void setName(QString name); -- GitLab From f0040386ec9a2a43e706f22ace5b3b484d0b0895 Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Mon, 15 Jul 2024 10:32:34 -0400 Subject: [PATCH 06/11] Update ventilator with latest Pulse API and update monitor display - Display I:E ratio as a ratio - Change cStatic to cDynamic Properly update ventilator UI when loading a state with the ventilator on - Note, Pulse needed to be updated for this to happen --- src/controls/VentilatorWidget.cxx | 140 ++++++++++++------ src/controls/VentilatorWidget.h | 13 +- ...ContinuousPositiveAirwayPressureWidget.cxx | 6 +- ...hanicalVentilatorPressureControlWidget.cxx | 6 +- ...echanicalVentilatorVolumeControlWidget.cxx | 6 +- 5 files changed, 101 insertions(+), 70 deletions(-) diff --git a/src/controls/VentilatorWidget.cxx b/src/controls/VentilatorWidget.cxx index 05e867f..6a65fea 100644 --- a/src/controls/VentilatorWidget.cxx +++ b/src/controls/VentilatorWidget.cxx @@ -1,13 +1,16 @@ /* Distributed under the Apache License, Version 2.0. See accompanying NOTICE file for details.*/ + #include "VentilatorWidget.h" #include "ui_Ventilator.h" #include #include +#include "pulse/cdm/engine/SEActionManager.h" #include "pulse/cdm/engine/SEDataRequestManager.h" #include "pulse/cdm/engine/SEEngineTracker.h" +#include "pulse/cdm/engine/SEEquipmentActionCollection.h" #include "pulse/cdm/properties/SEScalar0To1.h" #include "pulse/cdm/properties/SEScalarFrequency.h" #include "pulse/cdm/properties/SEScalarPressure.h" @@ -25,15 +28,12 @@ #include "pulse/cdm/system/physiology/SERespiratorySystem.h" #include "pulse/engine/PulseEngine.h" - #include "QwtPulsePlot.h" #include "LabeledComboBox.h" #include "NumberWidget.h" #include "QMutex" #include "VentilatorHysteresisWidget.h" - - struct QVentilatorWidget::Private : public Ui::VentilatorWidget { Private(QVentilatorWidget* parent) : parent(parent) @@ -69,6 +69,8 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget ActionSet initialValues; ActionSet currentValues; + const SEMechanicalVentilatorMode* stateMode = nullptr; + const SEMechanicalVentilatorHold* stateHold = nullptr; std::vector> actions; int modeFromAction = -1; @@ -100,7 +102,7 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget action.GetInspiratoryPressure().SetValue(13.0, PressureUnit::cmH2O); action.GetInspiratoryPeriod().SetValue(1.0, TimeUnit::s); action.GetRespirationRate().SetValue(12, FrequencyUnit::Per_min); - action.GetPositiveEndExpiredPressure().SetValue(5.0, PressureUnit::cmH2O); + action.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); action.GetSlope().SetValue(0.2, TimeUnit::s); } { @@ -110,14 +112,14 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget action.GetTidalVolume().SetValue(600, VolumeUnit::mL); action.GetInspiratoryPeriod().SetValue(1.0, TimeUnit::s); action.GetRespirationRate().SetValue(12, FrequencyUnit::Per_min); - action.GetPositiveEndExpiredPressure().SetValue(5.0, PressureUnit::cmH2O); + action.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); action.GetFlow().SetValue(50, VolumePerTimeUnit::L_Per_min); } { auto& action = initialValues.cpap; action.SetConnection(eSwitch::On); action.GetFractionInspiredOxygen().SetValue(0.21); - action.GetPositiveEndExpiredPressure().SetValue(5.0, PressureUnit::cmH2O); + action.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); action.GetDeltaPressureSupport().SetValue(8, PressureUnit::cmH2O); action.GetSlope().SetValue(0.2, TimeUnit::s); } @@ -141,6 +143,7 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget slopeWidget = nullptr; } + // The range of the slope is dependent on another widgets range, set up and connect the two void setupSlope(LabeledDialWidget* ti, LabeledDialWidget* slope) { clearSlope(); @@ -149,6 +152,7 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget connect(tiWidget, &LabeledDialWidget::valueChanged, parent, &QVentilatorWidget::updateSlope); } + // maxIndex the index of the last dial to show, dials with index higher will be hidden in the UI void showDials(int maxIndex) { for (int i = 0; i < maxIndex && i < dials.size(); ++i) @@ -157,7 +161,6 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget } } - void setMode(QString mode, bool resetValues = false) { clearSlope(); @@ -180,7 +183,7 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget dial_1->setup("Pinsp", "cmH2O", 1, 100, 1, 1, &action.GetInspiratoryPressure()); dial_2->setup("Ti", "s", 0.1, 60, 10, 0.1, &action.GetInspiratoryPeriod()); dial_3->setup("RR", "bpm", 10, 60, 1, 1.0, &action.GetRespirationRate()); - dial_4->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, &action.GetPositiveEndExpiredPressure()); + dial_4->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, &action.GetPositiveEndExpiratoryPressure()); dial_5->setup("Slope", "s", 0, dial_2->getValue(), 10, 0.1, &action.GetSlope()); setupSlope(dial_2, dial_5); showDials(6); @@ -193,7 +196,7 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget dial_1->setup("VT", "mL", 100, 2000, 1, 1.0, &action.GetTidalVolume()); dial_2->setup("Ti", "s", 0.1, 60, 10, 0.1, &action.GetInspiratoryPeriod()); dial_3->setup("RR", "bpm", 10, 60, 1, 1.0, &action.GetRespirationRate()); - dial_4->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, &action.GetPositiveEndExpiredPressure()); + dial_4->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, &action.GetPositiveEndExpiratoryPressure()); dial_5->setup("Flow", "L/min", 1, 100, 1, 1.0, &action.GetFlow()); showDials(6); } @@ -202,7 +205,7 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget if (resetValues) currentValues.cpap.Copy(initialValues.cpap); auto& action = currentValues.cpap; dial_0->setup("FiO2", "", 0.21, 1.0, 100, 0.1, &action.GetFractionInspiredOxygen()); - dial_1->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, &action.GetPositiveEndExpiredPressure()); + dial_1->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, &action.GetPositiveEndExpiratoryPressure()); dial_2->setup("deltaPsupp", "cmH2O", 1, 100, 1, 1.0, &action.GetDeltaPressureSupport()); dial_3->setup("Slope", "s", 0, 1, 100, 0.1, &action.GetSlope()); showDials(4); @@ -345,41 +348,81 @@ void QVentilatorWidget::Reset() void QVentilatorWidget::AtSteadyState(PhysiologyEngine& pulse) { - // Create Data Requests here ... - - auto& dm = pulse.GetEngineTracker()->GetDataRequestManager(); - - // PulsePhysiology Name, Unit, UI Abbreviation - // HS would like to set up things this way but that still has a few issues -// static std::vector> items = -// { -// {"PeakInspiratoryPressure", PressureUnit::cmH2O, "PIP"}, -// {"MeanAirwayPressure", PressureUnit::cmH2O, "Pmean"}, -// {"RespirationRate", FrequencyUnit::Per_min, "RR"}, -// {"TidalVolume", VolumeUnit::mL, "VT"}, -// {"TotalPulmonaryVentilation", VolumePerTimeUnit::L_Per_min, "MVe"}, -// {"EndTidalCarbonDioxidePressure", PressureUnit::mmHg, "etCO2"}, -// {"PulmonaryCompliance", {}, "cDyn"}, -// }; + // Called when we load a state too, so copy any of our actions + + + if (pulse.GetActionManager().GetEquipmentActions().HasMechanicalVentilatorContinuousPositiveAirwayPressure()) + { + d->stateMode = pulse.GetActionManager().GetEquipmentActions().GetMechanicalVentilatorContinuousPositiveAirwayPressure(); + } + else if (pulse.GetActionManager().GetEquipmentActions().HasMechanicalVentilatorPressureControl()) + { + d->stateMode = pulse.GetActionManager().GetEquipmentActions().GetMechanicalVentilatorPressureControl(); + } + else if (pulse.GetActionManager().GetEquipmentActions().HasMechanicalVentilatorVolumeControl()) + { + d->stateMode = pulse.GetActionManager().GetEquipmentActions().GetMechanicalVentilatorVolumeControl(); + } + + if (pulse.GetActionManager().GetEquipmentActions().HasMechanicalVentilatorHold()) + { + d->stateHold = pulse.GetActionManager().GetEquipmentActions().GetMechanicalVentilatorHold(); + // TODO Log("Removing the hold from the loaded state"); + } + +// PulsePhysiology Name, Unit, UI Abbreviation +// HS would like to set up things this way but that still has a few issues +// auto& dm = pulse.GetEngineTracker()->GetDataRequestManager(); +// static std::vector> items = +// { +// {"PeakInspiratoryPressure", PressureUnit::cmH2O, "PIP"}, +// {"MeanAirwayPressure", PressureUnit::cmH2O, "Pmean"}, +// {"RespirationRate", FrequencyUnit::Per_min, "RR"}, +// {"TidalVolume", VolumeUnit::mL, "VT"}, +// {"TotalPulmonaryVentilation", VolumePerTimeUnit::L_Per_min, "MVe"}, +// {"EndTidalCarbonDioxidePressure", PressureUnit::mmHg, "etCO2"}, +// {"PulmonaryCompliance", {}, "cDyn"}, +// }; // -// int i = 0; -// for (auto& item : items) -// { -// const std::string& physName = std::get<0>(item); -// const CCompoundUnit& unit = std::get<1>(item); -// const QString& label = std::get<2>(item); +// int i = 0; +// for (auto& item : items) +// { +// const std::string& physName = std::get<0>(item); +// const CCompoundUnit& unit = std::get<1>(item); +// const QString& label = std::get<2>(item); // -// if (physName.empty()) continue; +// if (physName.empty()) continue; // -// d->numbers[i]->setDataRequest(&dm.CreatePhysiologyDataRequest(physName, unit)); +// d->numbers[i]->setDataRequest(&dm.CreatePhysiologyDataRequest(physName, unit)); // -// d->numbers[i]->setName(label); -// d->numbers[i]->setUnit(QString(unit.GetString().c_str())); -// ++i; -// } +// d->numbers[i]->setName(label); +// d->numbers[i]->setUnit(QString(unit.GetString().c_str())); +// ++i; +// } + d->hysteresis->AtSteadyState(pulse); } +void QVentilatorWidget::AtSteadyStateUpdateUI() +{ + if (d->stateMode) + { + std::vector actions {d->stateMode}; + UpdateUI(actions); + d->stateMode = nullptr; + d->setUIState(Private::Connected); + } + + if (d->stateHold) + {// Just force the hold release, this would be a wierd edge case to support + // The use can just enable the hold manually + removeHold(); + d->stateHold = nullptr; + } + + d->hysteresis->AtSteadyStateUpdateUI(); +} + void QVentilatorWidget::ProcessPhysiology(PhysiologyEngine& pulse) { // This is called from a thread, you should NOT update UI here @@ -395,7 +438,7 @@ void QVentilatorWidget::ProcessPhysiology(PhysiologyEngine& pulse) d->number_3->setWithoutUpdate(ventilator->GetTotalPulmonaryVentilation(VolumePerTimeUnit::L_Per_min)); d->number_4->setWithoutUpdate(ventilator->GetRespirationRate(FrequencyUnit::Per_min)); d->number_5->setWithoutUpdate(ventilator->GetEndTidalCarbonDioxidePressure(PressureUnit::mmHg)); - d->number_6->setWithoutUpdate(ventilator->GetDynamicPulmonaryCompliance(VolumePerPressureUnit::L_Per_cmH2O)); + d->number_6->setWithoutUpdate(ventilator->GetStaticRespiratoryCompliance(VolumePerPressureUnit::mL_Per_cmH2O)); d->number_7->setWithoutUpdate(ventilator->GetInspiratoryExpiratoryRatio()); double time_s = pulse.GetSimulationTime(TimeUnit::s); @@ -406,13 +449,12 @@ void QVentilatorWidget::ProcessPhysiology(PhysiologyEngine& pulse) d->applyActions(pulse); } -void QVentilatorWidget::AtSteadyStateUpdateUI() +void QVentilatorWidget::PhysiologyUpdateUI(const std::vector& actions) { - d->hysteresis->AtSteadyStateUpdateUI(); - + UpdateUI(actions); } -void QVentilatorWidget::PhysiologyUpdateUI(const std::vector& actions) +void QVentilatorWidget::UpdateUI(const std::vector& actions) { // This is called from a slot, you can update UI here // This is where we take the pulse data we pulled and push it to a UI widget @@ -430,7 +472,7 @@ void QVentilatorWidget::PhysiologyUpdateUI(const std::vector& a { d->currentValues.pc.Copy(*typedAction); QString currentText = (typedAction->GetMode() == eMechanicalVentilator_PressureControlMode::AssistedControl) ? - "PC-AC" : "PC-CMV"; + "PC-AC" : "PC-CMV"; d->modeBox->setCurrentText(currentText); break; } @@ -438,8 +480,8 @@ void QVentilatorWidget::PhysiologyUpdateUI(const std::vector& a { d->currentValues.vc.Copy(*typedAction); QString currentText = (typedAction->GetMode() == eMechanicalVentilator_VolumeControlMode::AssistedControl) ? - "VC-AC" : "VC-CMV"; - d->modeBox->setCurrentText("VC-CMV"); + "VC-AC" : "VC-CMV"; + d->modeBox->setCurrentText(currentText); break; } if (auto typedAction = dynamic_cast(*it)) @@ -600,9 +642,9 @@ void QVentilatorWidget::setupNumbers() d->number_2->setup("Pmean", "cmH20"); d->number_3->setup("MVe", "L/min"); d->number_4->setup("RR", "/min"); - d->number_5->setup("etCO2", "mmHg"); // , 2 - d->number_6->setup("cDyn", "L/cmH2O", 2); - d->number_7->setup("I:E", "", 2); + d->number_5->setup("etCO2", "mmHg"); + d->number_6->setup("cStat", "mL/cmH2O"); + d->number_7->setup("I:E", "", 1, true); } void QVentilatorWidget::lockForHold() diff --git a/src/controls/VentilatorWidget.h b/src/controls/VentilatorWidget.h index d487ef1..7673795 100644 --- a/src/controls/VentilatorWidget.h +++ b/src/controls/VentilatorWidget.h @@ -53,19 +53,8 @@ protected slots: void resetDials(); protected: - ///@{ - /// The range of the slope is dependent on another widgets range, set up and connect - /// the two - void setupSlope(LabeledDialWidget* tiWidget, LabeledDialWidget* slopeWidget); - void clearSlope(); - ///@} - - /// Display a number of dials - /// \param maxIndex the index of the last dial to show, dials with index higher - /// will be hidden in the UI - void showDials(int maxIndex); - void setupNumbers(); + void UpdateUI(const std::vector& actions); ///@{ /// When hold is clicked, the UI should be locked for input diff --git a/src/controls/actions/MechanicalVentilatorContinuousPositiveAirwayPressureWidget.cxx b/src/controls/actions/MechanicalVentilatorContinuousPositiveAirwayPressureWidget.cxx index 381de49..517c04c 100644 --- a/src/controls/actions/MechanicalVentilatorContinuousPositiveAirwayPressureWidget.cxx +++ b/src/controls/actions/MechanicalVentilatorContinuousPositiveAirwayPressureWidget.cxx @@ -57,7 +57,7 @@ QMechanicalVentilatorContinuousPositiveAirwayPressureWidget::QMechanicalVentilat m_Controls->DefaultAction.SetConnection(eSwitch::On); m_Controls->DefaultAction.GetFractionInspiredOxygen().SetValue(0.21); - m_Controls->DefaultAction.GetPositiveEndExpiredPressure().SetValue(5.0, PressureUnit::cmH2O); + m_Controls->DefaultAction.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); m_Controls->DefaultAction.GetDeltaPressureSupport().SetValue(8, PressureUnit::cmH2O); m_Controls->DefaultAction.GetSlope().SetValue(0.2, TimeUnit::s); @@ -105,7 +105,7 @@ void QMechanicalVentilatorContinuousPositiveAirwayPressureWidget::ControlsToActi m_Controls->Action.SetConnection((m_Controls->State->GetIndex() == 0) ? eSwitch::On : eSwitch::Off); m_Controls->FractionInspiredOxygen->GetValue(m_Controls->Action.GetFractionInspiredOxygen()); m_Controls->DeltaPressureSupport->GetValue(m_Controls->Action.GetDeltaPressureSupport()); - m_Controls->PositiveEndExpiredPressure->GetValue(m_Controls->Action.GetPositiveEndExpiredPressure()); + m_Controls->PositiveEndExpiredPressure->GetValue(m_Controls->Action.GetPositiveEndExpiratoryPressure()); m_Controls->Slope->GetValue(m_Controls->Action.GetSlope()); emit UpdateAction(m_Controls->Action, GetProcessTime()); @@ -118,6 +118,6 @@ void QMechanicalVentilatorContinuousPositiveAirwayPressureWidget::ActionToContro m_Controls->State->SetCurrentIndex((action.GetConnection() == eSwitch::On) ? 0 : 1); m_Controls->FractionInspiredOxygen->SetValue(m_Controls->Action.GetFractionInspiredOxygen()); m_Controls->DeltaPressureSupport->SetValue(m_Controls->Action.GetDeltaPressureSupport()); - m_Controls->PositiveEndExpiredPressure->SetValue(m_Controls->Action.GetPositiveEndExpiredPressure()); + m_Controls->PositiveEndExpiredPressure->SetValue(m_Controls->Action.GetPositiveEndExpiratoryPressure()); m_Controls->Slope->SetValue(m_Controls->Action.GetSlope()); } diff --git a/src/controls/actions/MechanicalVentilatorPressureControlWidget.cxx b/src/controls/actions/MechanicalVentilatorPressureControlWidget.cxx index 99eaad4..5b274f5 100644 --- a/src/controls/actions/MechanicalVentilatorPressureControlWidget.cxx +++ b/src/controls/actions/MechanicalVentilatorPressureControlWidget.cxx @@ -74,7 +74,7 @@ QMechanicalVentilatorPressureControlWidget::QMechanicalVentilatorPressureControl m_Controls->DefaultAction.GetInspiratoryPressure().SetValue(13.0, PressureUnit::cmH2O); m_Controls->DefaultAction.GetInspiratoryPeriod().SetValue(1.0, TimeUnit::s); m_Controls->DefaultAction.GetRespirationRate().SetValue(12, FrequencyUnit::Per_min); - m_Controls->DefaultAction.GetPositiveEndExpiredPressure().SetValue(5.0, PressureUnit::cmH2O); + m_Controls->DefaultAction.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); m_Controls->DefaultAction.GetSlope().SetValue(0.2, TimeUnit::s); Reset(); @@ -127,7 +127,7 @@ void QMechanicalVentilatorPressureControlWidget::ControlsToAction() m_Controls->InspiratoryPressure->GetValue(m_Controls->Action.GetInspiratoryPressure()); m_Controls->InspiratoryPeriod->GetValue(m_Controls->Action.GetInspiratoryPeriod()); m_Controls->RespirationRate->GetValue(m_Controls->Action.GetRespirationRate()); - m_Controls->PositiveEndExpiredPressure->GetValue(m_Controls->Action.GetPositiveEndExpiredPressure()); + m_Controls->PositiveEndExpiredPressure->GetValue(m_Controls->Action.GetPositiveEndExpiratoryPressure()); m_Controls->Slope->GetValue(m_Controls->Action.GetSlope()); emit UpdateAction(m_Controls->Action, GetProcessTime()); @@ -142,6 +142,6 @@ void QMechanicalVentilatorPressureControlWidget::ActionToControls(const SEMechan m_Controls->InspiratoryPressure->SetValue(m_Controls->Action.GetInspiratoryPressure()); m_Controls->InspiratoryPeriod->SetValue(m_Controls->Action.GetInspiratoryPeriod()); m_Controls->RespirationRate->SetValue(m_Controls->Action.GetRespirationRate()); - m_Controls->PositiveEndExpiredPressure->SetValue(m_Controls->Action.GetPositiveEndExpiredPressure()); + m_Controls->PositiveEndExpiredPressure->SetValue(m_Controls->Action.GetPositiveEndExpiratoryPressure()); m_Controls->Slope->SetValue(m_Controls->Action.GetSlope()); } diff --git a/src/controls/actions/MechanicalVentilatorVolumeControlWidget.cxx b/src/controls/actions/MechanicalVentilatorVolumeControlWidget.cxx index 13ca01e..4b838fd 100644 --- a/src/controls/actions/MechanicalVentilatorVolumeControlWidget.cxx +++ b/src/controls/actions/MechanicalVentilatorVolumeControlWidget.cxx @@ -66,7 +66,7 @@ QMechanicalVentilatorVolumeControlWidget::QMechanicalVentilatorVolumeControlWidg m_Controls->DefaultAction.GetTidalVolume().SetValue(600, VolumeUnit::mL); m_Controls->DefaultAction.GetInspiratoryPeriod().SetValue(1.0, TimeUnit::s); m_Controls->DefaultAction.GetRespirationRate().SetValue(12, FrequencyUnit::Per_min); - m_Controls->DefaultAction.GetPositiveEndExpiredPressure().SetValue(5.0, PressureUnit::cmH2O); + m_Controls->DefaultAction.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); m_Controls->DefaultAction.GetFlow().SetValue(50, VolumePerTimeUnit::L_Per_min); Properties()->layout()->addWidget(GetProcessTimeCtrl()); @@ -117,7 +117,7 @@ void QMechanicalVentilatorVolumeControlWidget::ControlsToAction() m_Controls->TidalVolume->GetValue(m_Controls->Action.GetTidalVolume()); m_Controls->InspiratoryPeriod->GetValue(m_Controls->Action.GetInspiratoryPeriod()); m_Controls->RespirationRate->GetValue(m_Controls->Action.GetRespirationRate()); - m_Controls->PositiveEndExpiredPressure->GetValue(m_Controls->Action.GetPositiveEndExpiredPressure()); + m_Controls->PositiveEndExpiredPressure->GetValue(m_Controls->Action.GetPositiveEndExpiratoryPressure()); m_Controls->Flow->GetValue(m_Controls->Action.GetFlow()); emit UpdateAction(m_Controls->Action, GetProcessTime()); @@ -131,6 +131,6 @@ void QMechanicalVentilatorVolumeControlWidget::ActionToControls(const SEMechanic m_Controls->TidalVolume->SetValue(m_Controls->Action.GetTidalVolume()); m_Controls->InspiratoryPeriod->SetValue(m_Controls->Action.GetInspiratoryPeriod()); m_Controls->RespirationRate->SetValue(m_Controls->Action.GetRespirationRate()); - m_Controls->PositiveEndExpiredPressure->SetValue(m_Controls->Action.GetPositiveEndExpiredPressure()); + m_Controls->PositiveEndExpiredPressure->SetValue(m_Controls->Action.GetPositiveEndExpiratoryPressure()); m_Controls->Flow->SetValue(m_Controls->Action.GetFlow()); } -- GitLab From 38282bf7bddf1f6e137f64e2e1f30779fa3cdefc Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Mon, 15 Jul 2024 10:33:51 -0400 Subject: [PATCH 07/11] Minor correction of text display --- src/controls/actions/PneumoniaExacerbationWidget.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controls/actions/PneumoniaExacerbationWidget.cxx b/src/controls/actions/PneumoniaExacerbationWidget.cxx index 62d6ac0..177d330 100644 --- a/src/controls/actions/PneumoniaExacerbationWidget.cxx +++ b/src/controls/actions/PneumoniaExacerbationWidget.cxx @@ -22,7 +22,7 @@ QPneumoniaExacerbationWidget::QPneumoniaExacerbationWidget(QPulse& qp, QWidget * { m_Controls = new Controls(qp); m_Controls->LeftLungSeverity = new QScalarWidget("Left Lung Severity", 0, 1, 0.1, ScalarOptionWidget::None, this); - m_Controls->RightLungSeverity = new QScalarWidget("Right LungA ffected", 0, 1, 0.1, ScalarOptionWidget::None, this); + m_Controls->RightLungSeverity = new QScalarWidget("Right Lung Severity", 0, 1, 0.1, ScalarOptionWidget::None, this); Properties()->layout()->addWidget(m_Controls->LeftLungSeverity); Properties()->layout()->addWidget(m_Controls->RightLungSeverity); Properties()->layout()->addWidget(GetProcessTimeCtrl()); -- GitLab From 29bac6d67743f953af891141db73c6af40dde5ee Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Mon, 15 Jul 2024 10:34:39 -0400 Subject: [PATCH 08/11] We don't need to run the patient checker when loading a state --- src/controls/PatientEditorWidget.cxx | 29 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/controls/PatientEditorWidget.cxx b/src/controls/PatientEditorWidget.cxx index 9fd7f34..8af212e 100644 --- a/src/controls/PatientEditorWidget.cxx +++ b/src/controls/PatientEditorWidget.cxx @@ -249,21 +249,25 @@ bool QPatientEditorWidget::ValidPatient() msgBox.exec(); return false; } - SEPatient p(m_Controls->Pulse.GetEngine().GetLogger()); - ControlsToPatient(p); - if (!pulse::human_adult_whole_body::SetupPatient(p)) + // Trust the state file patient + if (m_Controls->StateFilename->text().isEmpty()) { - QMessageBox msgBox(this); - msgBox.setWindowTitle("Error!"); - QString err = "Invalid Patient, check log window for more details"; - msgBox.setText(err); - msgBox.exec(); + SEPatient p(m_Controls->Pulse.GetEngine().GetLogger()); + ControlsToPatient(p); + if (!pulse::human_adult_whole_body::SetupPatient(p)) + { + QMessageBox msgBox(this); + msgBox.setWindowTitle("Error!"); + QString err = "Invalid Patient, check log window for more details"; + msgBox.setText(err); + msgBox.exec(); - // This will push all log messages to the LogBox UI - std::vector actions; - emit m_Controls->Pulse.Advanced(actions); + // This will push all log messages to the LogBox UI + std::vector actions; + emit m_Controls->Pulse.Advanced(actions); - return false; + return false; + } } return true; @@ -516,6 +520,7 @@ void QPatientEditorWidget::LoadPatientFile() msgBox.exec(); return; } + m_Controls->StateFilename->setText(""); m_Controls->Pulse.SetPatientFilename(s); PatientToControls(m_Controls->Pulse.GetPatientConfiguration().GetPatient()); } -- GitLab From 85c922b2b757a27b0e9a71ca04460d2f86872f67 Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Tue, 1 Oct 2024 11:49:58 -0400 Subject: [PATCH 09/11] Add UI for setting triggers and drugs to the ventilator Add Units to the data request plots --- src/controls/PlotSetWidget.cxx | 73 +++-- src/controls/QwtPulsePlot.cxx | 10 + src/controls/QwtPulsePlot.h | 4 + src/controls/ScalarQuantityWidget.h | 3 + src/controls/ScalarQuantityWidget.inl | 20 +- src/controls/VentilatorWidget.cxx | 404 +++++++++++++++++++++----- src/controls/VentilatorWidget.h | 7 + src/ui/MainExplorerWindow.ui | 134 ++++++++- src/ui/Ventilator.ui | 398 ++++++++++++++++++------- 9 files changed, 862 insertions(+), 191 deletions(-) diff --git a/src/controls/PlotSetWidget.cxx b/src/controls/PlotSetWidget.cxx index bfae40c..0485192 100644 --- a/src/controls/PlotSetWidget.cxx +++ b/src/controls/PlotSetWidget.cxx @@ -13,26 +13,33 @@ See accompanying NOTICE file for details.*/ #include "pulse/cdm/engine/SEDataRequestManager.h" #include "pulse/cdm/properties/SEScalarTime.h" -// TODO -// I took this from SEEngineTrack, this method should go in there -// (I did change the delimeter from "-" to " ") -std::string GetTitle(SEDataRequest& dr) +// The method is used to set a plot name as well as its title +// When getting the name, we don't want the unit in the name, so includeUnit=false +// When getting the title,we want the unit, so includeUnit=true +// The Explorer DataRequest creation UI does not provide a way for the user to select a unit +// So the unit shown will be in whatever unit the engine uses for the requested property +// If we ever do provide a way for the user to select the DR unit, we will need to revisit this logic + +// TODO When we load a scenario, with data requests, do they have a unit? Are we honoring it? +std::string ToString(SEDataRequest& dr, bool includeUnit=false) { std::stringstream ss; switch (dr.GetCategory()) { case eDataRequest_Category::Patient: - ss << "Patient"; + ss << "Patient "; case eDataRequest_Category::Physiology: case eDataRequest_Category::Environment: case eDataRequest_Category::AnesthesiaMachine: case eDataRequest_Category::ECG: case eDataRequest_Category::Inhaler: { - if (!dr.GetUnit()) + if (!includeUnit) ss << dr.GetPropertyName(); - else + else if (dr.GetUnit()) ss << dr.GetPropertyName() << "(" << dr.GetUnit() << ")"; + else + ss << dr.GetPropertyName(); break; } case eDataRequest_Category::GasCompartment: @@ -42,17 +49,22 @@ std::string GetTitle(SEDataRequest& dr) { if (dr.HasSubstanceName()) { - if (!dr.GetUnit()) + if (!includeUnit) ss << dr.GetCompartmentName() << " " << dr.GetSubstanceName() << " " << dr.GetPropertyName(); + else if (dr.GetUnit()) + ss << dr.GetCompartmentName() << " " << dr.GetSubstanceName() << " " << dr.GetPropertyName() << " (" << dr.GetUnit() << ")"; else - ss << dr.GetCompartmentName() << " " << dr.GetSubstanceName() << " " << dr.GetPropertyName() << "(" << dr.GetUnit() << ")"; + ss << dr.GetCompartmentName() << " " << dr.GetSubstanceName() << " " << dr.GetPropertyName(); + } else { - if (!dr.GetUnit()) + if (!includeUnit) ss << dr.GetCompartmentName() << " " << dr.GetPropertyName(); + else if (dr.GetUnit()) + ss << dr.GetCompartmentName() << " " << dr.GetPropertyName() << " (" << dr.GetUnit() << ")"; else - ss << dr.GetCompartmentName() << " " << dr.GetPropertyName() << "(" << dr.GetUnit() << ")"; + ss << dr.GetCompartmentName() << " " << dr.GetPropertyName(); } break; } @@ -60,17 +72,21 @@ std::string GetTitle(SEDataRequest& dr) { if (dr.HasCompartmentName()) { - if (!dr.GetUnit()) + if (!includeUnit) ss << dr.GetSubstanceName() << " " << dr.GetCompartmentName() << " " << dr.GetPropertyName(); + else if (dr.GetUnit()) + ss << dr.GetSubstanceName() << " " << dr.GetCompartmentName() << " " << dr.GetPropertyName() << " (" << dr.GetUnit() << ")"; else - ss << dr.GetSubstanceName() << " " << dr.GetCompartmentName() << " " << dr.GetPropertyName() << "(" << dr.GetUnit() << ")"; + ss << dr.GetSubstanceName() << " " << dr.GetCompartmentName() << " " << dr.GetPropertyName(); } else { - if (!dr.GetUnit()) + if (!includeUnit) ss << dr.GetSubstanceName() << " " << dr.GetPropertyName(); + else if (dr.GetUnit()) + ss << dr.GetSubstanceName() << " " << dr.GetPropertyName() << " (" << dr.GetUnit() << ")"; else - ss << dr.GetSubstanceName() << " " << dr.GetPropertyName() << "(" << dr.GetUnit() << ")"; + ss << dr.GetSubstanceName() << " " << dr.GetPropertyName(); } break; } @@ -129,10 +145,10 @@ void QPlotSetWidget::Clear() void QPlotSetWidget::AddDataRequest(SEDataRequest& dr) { - QString title = GetTitle(dr).c_str(); + std::string name = ToString(dr); int idx=-1; for(; idxPlots.size(); idx++) - if (m_Controls->Plots[idx]->GetPlot().title() == title) + if (m_Controls->Plots[idx]->GetName() == name) break; if (idx == -1) { @@ -148,8 +164,10 @@ void QPlotSetWidget::AddDataRequest(SEDataRequest& dr) newPlot->GetGrid().enableY(true); m_Controls->Plots.push_back(newPlot); m_Controls->DataRequests.push_back(&dr); + newPlot->SetName(name); + // For now, use the name as the title, we'll update it with a unit later newPlot->GetPlot().setTitle(dr.GetPropertyName().c_str()); - m_Controls->PlotComboBox->addItem(title); + m_Controls->PlotComboBox->addItem(name.c_str()); m_Controls->PlotContainer->layout()->addWidget(newPlot); } // Update Controls @@ -229,7 +247,24 @@ void QPlotSetWidget::ProcessPhysiology(PhysiologyEngine& pulse) if (i+1 > m_Controls->EngineDataRequests.size()) { SEDataRequest const* dr = m_Controls->DataRequests[i]; - m_Controls->EngineDataRequests.push_back(&pulse.GetEngineTracker()->GetDataRequestManager().CopyDataRequest(*dr)); + SEDataRequest* pulseDr = &pulse.GetEngineTracker()->GetDataRequestManager().CopyDataRequest(*dr); + m_Controls->EngineDataRequests.push_back(pulseDr); + // Update the plot title to include the unit + // TrackRequest will hook up the request to the engine, + // which includes setting the unit to the engine unit if none was requested + pulse.GetEngineTracker()->TrackRequest(*pulseDr); + std::string unit = pulse.GetEngineTracker()->GetUnit(*pulseDr); + if (!unit.empty()) + { + // The name is the original string used when creating the plot + // We don't include the unit in the original name + std::string name = ToString(*pulseDr, false); + std::string title = ToString(*pulseDr, true); + for (int idx = 0; idx < m_Controls->Plots.size(); idx++) + if (m_Controls->Plots[idx]->GetName() == name) + m_Controls->Plots[idx]->GetPlot().setTitle(title.c_str()); + } + } } } diff --git a/src/controls/QwtPulsePlot.cxx b/src/controls/QwtPulsePlot.cxx index 2c9162f..fd954b5 100644 --- a/src/controls/QwtPulsePlot.cxx +++ b/src/controls/QwtPulsePlot.cxx @@ -25,6 +25,7 @@ public: double MinY; size_t MaxSize; QMutex Mutex; + std::string Name; }; QwtPulsePlot::QwtPulsePlot(QWidget* parent, size_t max_points) @@ -67,6 +68,15 @@ void QwtPulsePlot::Clear() m_Data->Values.clear(); } +std::string QwtPulsePlot::GetName() const +{ + return m_Data->Name; +} +void QwtPulsePlot::SetName(const std::string& name) +{ + m_Data->Name = name; +} + QwtPlot& QwtPulsePlot::GetPlot() { return *m_Data->Plot; } QwtPlotCurve& QwtPulsePlot::GetCurve() { return *m_Data->Curve; } QwtPlotGrid& QwtPulsePlot::GetGrid() { return *m_Data->Grid; } diff --git a/src/controls/QwtPulsePlot.h b/src/controls/QwtPulsePlot.h index bb43901..c1c0d0e 100644 --- a/src/controls/QwtPulsePlot.h +++ b/src/controls/QwtPulsePlot.h @@ -22,6 +22,10 @@ public: QwtPlotCurve& GetCurve(); QwtPlotGrid& GetGrid(); + + std::string GetName() const; + void SetName(const std::string& name); + void SetDataRange(double min, double max); void Append(double time, double value); void UpdateUI(bool pad=true); diff --git a/src/controls/ScalarQuantityWidget.h b/src/controls/ScalarQuantityWidget.h index 62a9dd2..d3c514d 100644 --- a/src/controls/ScalarQuantityWidget.h +++ b/src/controls/ScalarQuantityWidget.h @@ -30,11 +30,13 @@ public: void AddUnit(const Unit& unit); void SetValue(const SEScalarQuantity& s); void GetValue(SEScalarQuantity& s); + bool SetDefault(double d);// Assumed to be in default units, must be in range void EnableInput(bool b); void EnableInput(bool check, bool value); void EnableConverter(bool b); void FullDisable(); void FullEnable(); + bool IsZero() const; const QRadioButton* GetRadioButton() { return m_Radio; } @@ -57,6 +59,7 @@ protected slots: double m_Max; double m_Step; double m_LastValue; + double m_Default; int m_LastUnitIndex; const Unit& m_DefaultUnit; std::vector m_Units; diff --git a/src/controls/ScalarQuantityWidget.inl b/src/controls/ScalarQuantityWidget.inl index f97f73e..5c276b0 100644 --- a/src/controls/ScalarQuantityWidget.inl +++ b/src/controls/ScalarQuantityWidget.inl @@ -70,6 +70,7 @@ QScalarQuantityWidget::QScalarQuantityWidget(const QString& name, double m m_Value->setMaximumSize(QSize(70, 22)); m_Value->setDecimals(2); m_Layout->addWidget(m_Value); + m_Default = min; m_Unit = new QComboBox(this); QSizePolicy sizePolicyU(QSizePolicy::Fixed, QSizePolicy::Maximum); @@ -109,7 +110,7 @@ void QScalarQuantityWidget::Reset() m_Radio->setChecked(false); EnableInput(true, false); m_LastUnitIndex = 0; - m_LastValue = m_Value->minimum(); + m_LastValue = m_Default; m_Unit->setCurrentIndex(m_LastUnitIndex); m_Value->setValue(m_LastValue); } @@ -140,6 +141,17 @@ void QScalarQuantityWidget::AddUnit(const Unit& unit) m_Unit->addItem(QString::fromStdString(unit.GetString())); } +template +bool QScalarQuantityWidget::SetDefault(double d) // Assumed to be in default units +{ + if (d >= m_Value->minimum() && d <= m_Value->maximum()) + { + m_Default = d; + return true; + } + return false; +} + template void QScalarQuantityWidget::SetValue(const SEScalarQuantity& s) { @@ -175,6 +187,12 @@ void QScalarQuantityWidget::GetValue(SEScalarQuantity& s) s.SetValue(m_Value->value(),*m_Units[m_Unit->currentIndex()]); } +template +bool QScalarQuantityWidget::IsZero() const +{ + return SEScalar::IsZero(m_Value->value(), ZERO_APPROX); +} + template void QScalarQuantityWidget::EnableInput(bool b) { diff --git a/src/controls/VentilatorWidget.cxx b/src/controls/VentilatorWidget.cxx index 6a65fea..30bea09 100644 --- a/src/controls/VentilatorWidget.cxx +++ b/src/controls/VentilatorWidget.cxx @@ -14,6 +14,7 @@ #include "pulse/cdm/properties/SEScalar0To1.h" #include "pulse/cdm/properties/SEScalarFrequency.h" #include "pulse/cdm/properties/SEScalarPressure.h" +#include "pulse/cdm/properties/SEScalarMassPerVolume.h" #include "pulse/cdm/properties/SEScalarTime.h" #include "pulse/cdm/properties/SEScalarVolume.h" #include "pulse/cdm/properties/SEScalarVolumePerPressure.h" @@ -33,6 +34,8 @@ #include "NumberWidget.h" #include "QMutex" #include "VentilatorHysteresisWidget.h" +#include "controls/ScalarWidget.h" +#include "controls/ScalarQuantityWidget.h" struct QVentilatorWidget::Private : public Ui::VentilatorWidget { @@ -49,12 +52,27 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget }); } + // Mode QVector dials; QVector numbers; LabeledDialWidget* slopeWidget = nullptr; LabeledDialWidget* tiWidget = nullptr; QVentilatorWidget* parent = nullptr; QVentilatorHysteresisWidget* hysteresis = nullptr; + // Triggers + QScalarQuantityWidget* inspirationPatientTriggerFlow; + QScalarQuantityWidget* inspirationPatientTriggerPressure; + QWidget* modelTrigger; + QRadioButton* modelRadio; + QLabel* modelTriggerLabel; + QSpacerItem* modelTriggerSpacer; + QLabel* modelTriggerValue; + QHBoxLayout* modelTriggerLayout; + // Drugs + QScalarQuantityWidget* albuterolConcentration; + const SESubstance* albuterol = nullptr; + QScalarWidget* desfluraneVolumeFraction; + const SESubstance* desflurane = nullptr; static const int PC = 0; static const int VC = 1; @@ -71,6 +89,7 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget const SEMechanicalVentilatorMode* stateMode = nullptr; const SEMechanicalVentilatorHold* stateHold = nullptr; + SEMechanicalVentilatorSettings* stateConfig = nullptr; std::vector> actions; int modeFromAction = -1; @@ -175,7 +194,7 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget setUIState(VentilatorNone); return; } - else if (mode == "PC" || mode == "PC-CMV" || mode == "PC-AC") + else if (mode == "PC-CMV" || mode == "PC-AC") { if (resetValues) currentValues.pc.Copy(initialValues.pc); auto& action = currentValues.pc; @@ -188,7 +207,7 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget setupSlope(dial_2, dial_5); showDials(6); } - else if (mode == "VC" || mode == "VC-CMV" || mode == "VC-AC") + else if (mode == "VC-CMV" || mode == "VC-AC") { if (resetValues) currentValues.vc.Copy(initialValues.vc); auto& action = currentValues.vc; @@ -214,47 +233,12 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget qWarning() << "Mode " << mode << " not found."; } + applyButton->setEnabled(true); setUIState((applyButton->text() == "Connect") ? Disconnected : Connected); + // Reset Triggers and Drugs when changing modes + resetDrugs(); } - void setUIState(UIState state) - { - switch (state) - { - case Default: - reset(); - setUIState(Off); - break; - case Off: - modeBox->setEnabled(false); - applyButton->setEnabled(false); - holdButton->setEnabled(false); - disconnectButton->setEnabled(false); - break; - case Enabled: - modeBox->setEnabled(true); - setUIState((applyButton->text() == "Connect") ? Disconnected : Connected); - break; - case VentilatorNone: - modeBox->setEnabled(true); - applyButton->setEnabled(false); - holdButton->setEnabled(false); - disconnectButton->setEnabled(false); - break; - case Connected: - applyButton->setText("Apply"); - applyButton->setEnabled(true); - holdButton->setEnabled(true); - disconnectButton->setEnabled(true); - break; - case Disconnected: - applyButton->setText("Connect"); - applyButton->setEnabled(true); - holdButton->setDisabled(true); - disconnectButton->setDisabled(true); - break; - } - } void reset() { @@ -297,12 +281,119 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget currentValues.pc.Copy(initialValues.pc); currentValues.vc.Copy(initialValues.vc); currentValues.cpap.Copy(initialValues.cpap); + + resetTriggers(); + resetDrugs(); } void resetDials() { setMode(modeBox->currentText(), true); } + + void setUIState(UIState state) + { + switch (state) + { + case Default: + reset(); + setUIState(Off); + applyButton->setEnabled(false); + break; + case Enabled: + modeBox->setEnabled(true); + resetButton->setEnabled(true); + setUIState((applyButton->text() == "Connect") ? Disconnected : Connected); + break; + case Off: + case VentilatorNone: + if (state == Off) + { + modeBox->setEnabled(false); + applyButton->setEnabled(false); + } + else if (state == VentilatorNone) + { + modeBox->setEnabled(true); + } + resetButton->setEnabled(true); + holdButton->setEnabled(false); + disconnectButton->setEnabled(false); + resetButton->setEnabled(false); + hysteresisButton->setEnabled(false); + // Triggers + enableTriggers(false); + // Drugs + albuterolConcentration->setEnabled(false); + desfluraneVolumeFraction->setEnabled(false); + apply_drugs->setEnabled(false); + break; + case Connected: + case Disconnected: + if (state == Connected) + { + applyButton->setText("Apply"); + disconnectButton->setEnabled(true); + } + else if (state == Disconnected) + { + applyButton->setText("Connect"); + disconnectButton->setEnabled(false); + } + resetButton->setEnabled(true); + holdButton->setEnabled(true); + hysteresisButton->setEnabled(true); + // Drugs + albuterolConcentration->setEnabled(true); + desfluraneVolumeFraction->setEnabled(true); + apply_drugs->setEnabled(true); + break; + } + } + + void enableTriggers(bool b) + { + if (b && modelTrigger->isEnabled()) + return; // We are already enabled + if (!b && !modelTrigger->isEnabled()) + return // We are already disabled + + inspirationPatientTriggerFlow->Reset(); + inspirationPatientTriggerPressure->Reset(); + inspirationPatientTriggerFlow->EnableInput(false, false); + inspirationPatientTriggerPressure->EnableInput(false, false); + + if (!b) + { + inspirationPatientTriggerFlow->FullDisable(); + inspirationPatientTriggerPressure->FullDisable(); + modelTrigger->setEnabled(false); + apply_triggers->setEnabled(false); + modelRadio->setChecked(false); + modelTriggerValue->setText("N/A"); + } + else + { + inspirationPatientTriggerFlow->FullEnable(); + inspirationPatientTriggerFlow->EnableInput(false); + inspirationPatientTriggerPressure->FullEnable(); + inspirationPatientTriggerPressure->EnableInput(false); + modelTrigger->setEnabled(true); + modelRadio->setChecked(true); + modelTriggerValue->setText("On"); + apply_triggers->setEnabled(true); + } + } + + void resetTriggers() + { + } + + void resetDrugs() + { + albuterolConcentration->Reset(); + desfluraneVolumeFraction->Reset(); + } }; QVentilatorWidget::QVentilatorWidget(QWidget *parent, Qt::WindowFlags flags) : @@ -325,13 +416,63 @@ QVentilatorWidget::QVentilatorWidget(QWidget *parent, Qt::WindowFlags flags) : setupNumbers(); + // Mode Controls connect(d->modeBox, &QComboBox::currentTextChanged, this, &QVentilatorWidget::setMode); - connect(d->applyButton, &QPushButton::clicked, this, &QVentilatorWidget::applyAction); connect(d->disconnectButton, &QPushButton::clicked, this, &QVentilatorWidget::disconnectAction); connect(d->holdButton, &QPushButton::pressed, this, &QVentilatorWidget::addHold); connect(d->holdButton, &QPushButton::released, this, &QVentilatorWidget::removeHold); connect(d->resetButton, &QPushButton::released, this, &QVentilatorWidget::resetDials); + // Triggers + d->inspirationPatientTriggerFlow = new QScalarQuantityWidget("Flow", 0, 10000, 1, VolumePerTimeUnit::L_Per_min, ScalarOptionWidget::Radio, this); + d->inspirationPatientTriggerFlow->AddUnit(VolumePerTimeUnit::L_Per_s); + d->inspirationPatientTriggerFlow->AddUnit(VolumePerTimeUnit::mL_Per_s); + d->inspirationPatientTriggerFlow->AddUnit(VolumePerTimeUnit::mL_Per_min); + d->inspirationPatientTriggerFlow->EnableInput(false, false); + d->trigger_layout->layout()->addWidget(d->inspirationPatientTriggerFlow); + d->inspirationPatientTriggerPressure = new QScalarQuantityWidget("Pressure", -10000, 10000, 1, PressureUnit::cmH2O, ScalarOptionWidget::Radio, this); + d->inspirationPatientTriggerPressure->AddUnit(PressureUnit::mmHg); + d->inspirationPatientTriggerPressure->AddUnit(PressureUnit::Pa); + d->inspirationPatientTriggerPressure->AddUnit(PressureUnit::psi); + d->inspirationPatientTriggerPressure->SetDefault(0); + d->inspirationPatientTriggerPressure->EnableInput(false, false); + d->trigger_layout->layout()->addWidget(d->inspirationPatientTriggerPressure); + d->modelTriggerLayout = new QHBoxLayout(); + d->modelTriggerLayout->setSpacing(6); + d->modelTriggerLayout->setContentsMargins(-1, 3, -1, 3); + QSizePolicy SsizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + SsizePolicy.setHorizontalStretch(0); + SsizePolicy.setVerticalStretch(0); + d->modelRadio = new QRadioButton(this); + d->modelTriggerLayout->addWidget(d->modelRadio); + d->modelTriggerLabel = new QLabel("Respiratory Model", this); + SsizePolicy.setHeightForWidth(d->modelTriggerLabel->sizePolicy().hasHeightForWidth()); + d->modelTriggerLabel->setSizePolicy(SsizePolicy); + d->modelTriggerLayout->addWidget(d->modelTriggerLabel); + d->modelTriggerSpacer = new QSpacerItem(40, 30, QSizePolicy::Expanding, QSizePolicy::Maximum); + d->modelTriggerLayout->addItem(d->modelTriggerSpacer); + d->modelTriggerValue = new QLabel("On", this); + d->modelTriggerLayout->addWidget(d->modelTriggerValue); + d->modelTrigger = new QWidget(this); + d->modelTrigger->setLayout(d->modelTriggerLayout); + d->trigger_layout->layout()->addWidget(d->modelTrigger); + connect(d->inspirationPatientTriggerFlow->GetRadioButton(), SIGNAL(clicked()), this, SLOT(enableFlowTrigger())); + connect(d->inspirationPatientTriggerPressure->GetRadioButton(), SIGNAL(clicked()), this, SLOT(enablePressureTrigger())); + connect(d->modelRadio, SIGNAL(clicked()), this, SLOT(enableModelTrigger())); + connect(d->apply_triggers, &QPushButton::clicked, this, &QVentilatorWidget::applyTriggers); + // Drugs + d->albuterolConcentration = new QScalarQuantityWidget("Albuterol\nConcentration", 0, 10000, 1, MassPerVolumeUnit::g_Per_L, ScalarOptionWidget::Check, this); + d->albuterolConcentration->AddUnit(MassPerVolumeUnit::g_Per_dL); + d->albuterolConcentration->AddUnit(MassPerVolumeUnit::g_Per_mL); + d->albuterolConcentration->AddUnit(MassPerVolumeUnit::mg_Per_L); + d->albuterolConcentration->AddUnit(MassPerVolumeUnit::mg_Per_dL); + d->albuterolConcentration->AddUnit(MassPerVolumeUnit::mg_Per_mL); + d->albuterolConcentration->AddUnit(MassPerVolumeUnit::ug_Per_L); + d->albuterolConcentration->AddUnit(MassPerVolumeUnit::ug_Per_mL); + d->drugs_layout->layout()->addWidget(d->albuterolConcentration); + d->desfluraneVolumeFraction = new QScalarWidget("Desflurane\nVolume Fraction", 0, 1, 0.05, ScalarOptionWidget::Check, this); + d->drugs_layout->layout()->addWidget(d->desfluraneVolumeFraction); + connect(d->apply_drugs, &QPushButton::clicked, this, &QVentilatorWidget::applyDrugs); Reset(); } @@ -344,10 +485,14 @@ QVentilatorWidget::~QVentilatorWidget() void QVentilatorWidget::Reset() { d->setUIState(QVentilatorWidget::Private::Default); + d->enableTriggers(false); + d->resetDrugs(); } void QVentilatorWidget::AtSteadyState(PhysiologyEngine& pulse) { + d->albuterol = pulse.GetSubstanceManager().GetSubstance("Albuterol"); + d->desflurane = pulse.GetSubstanceManager().GetSubstance("Desflurane"); // Called when we load a state too, so copy any of our actions @@ -370,6 +515,16 @@ void QVentilatorWidget::AtSteadyState(PhysiologyEngine& pulse) // TODO Log("Removing the hold from the loaded state"); } + if (pulse.GetMechanicalVentilator()->GetSettings()->GetConnection() == eSwitch::On) + { + if (d->stateConfig == nullptr) + d->stateConfig = new SEMechanicalVentilatorSettings(pulse.GetLogger()); + d->stateConfig->Copy(*pulse.GetMechanicalVentilator()->GetSettings(), pulse.GetSubstanceManager()); + } + + + d->hysteresis->AtSteadyState(pulse); + // PulsePhysiology Name, Unit, UI Abbreviation // HS would like to set up things this way but that still has a few issues // auto& dm = pulse.GetEngineTracker()->GetDataRequestManager(); @@ -400,7 +555,6 @@ void QVentilatorWidget::AtSteadyState(PhysiologyEngine& pulse) // ++i; // } - d->hysteresis->AtSteadyState(pulse); } void QVentilatorWidget::AtSteadyStateUpdateUI() @@ -420,33 +574,37 @@ void QVentilatorWidget::AtSteadyStateUpdateUI() d->stateHold = nullptr; } - d->hysteresis->AtSteadyStateUpdateUI(); -} - -void QVentilatorWidget::ProcessPhysiology(PhysiologyEngine& pulse) -{ - // This is called from a thread, you should NOT update UI here - // This is where we pull data from pulse, and push any actions to it - - d->hysteresis->ProcessPhysiology(pulse); - - auto ventilator = pulse.GetMechanicalVentilator(); + if (d->stateConfig && d->stateConfig->GetConnection() == eSwitch::On) + { + d->modelTriggerValue->setText("On"); + // Update Trigger + if (d->stateConfig->HasInspirationPatientTriggerFlow()) + { + enableFlowTrigger(); + d->inspirationPatientTriggerFlow->SetValue(d->stateConfig->GetInspirationPatientTriggerFlow()); + } + else if (d->stateConfig->HasInspirationPatientTriggerPressure()) + { + enablePressureTrigger(); + d->inspirationPatientTriggerPressure->SetValue(d->stateConfig->GetInspirationPatientTriggerPressure()); + } + else if (d->stateConfig->HasInspirationPatientTriggerRespiratoryModel() && + d->stateConfig->GetInspirationPatientTriggerRespiratoryModel() == eSwitch::On) + { + enableModelTrigger(); + d->modelTriggerValue->setText("On"); + } - d->number_0->setWithoutUpdate(ventilator->GetPeakInspiratoryPressure(PressureUnit::cmH2O)); - d->number_1->setWithoutUpdate(ventilator->GetTidalVolume(VolumeUnit::mL)); - d->number_2->setWithoutUpdate(ventilator->GetMeanAirwayPressure(PressureUnit::cmH2O)); - d->number_3->setWithoutUpdate(ventilator->GetTotalPulmonaryVentilation(VolumePerTimeUnit::L_Per_min)); - d->number_4->setWithoutUpdate(ventilator->GetRespirationRate(FrequencyUnit::Per_min)); - d->number_5->setWithoutUpdate(ventilator->GetEndTidalCarbonDioxidePressure(PressureUnit::mmHg)); - d->number_6->setWithoutUpdate(ventilator->GetStaticRespiratoryCompliance(VolumePerPressureUnit::mL_Per_cmH2O)); - d->number_7->setWithoutUpdate(ventilator->GetInspiratoryExpiratoryRatio()); + // Update Drugs + if (d->stateConfig->HasConcentrationInspiredAerosol(*d->albuterol)) + d->albuterolConcentration->SetValue(d->stateConfig->GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration()); + if (d->stateConfig->HasFractionInspiredGas(*d->desflurane)) + d->desfluraneVolumeFraction->SetValue(d->stateConfig->GetFractionInspiredGas(*d->desflurane).GetFractionAmount()); - double time_s = pulse.GetSimulationTime(TimeUnit::s); - d->plot_0->append(time_s, ventilator->GetAirwayPressure(PressureUnit::cmH2O)); - d->plot_1->append(time_s, ventilator->GetInspiratoryFlow(VolumePerTimeUnit::L_Per_min)); - d->plot_2->append(time_s, ventilator->GetTotalLungVolume(VolumeUnit::mL)); + d->stateConfig->Clear(); + } - d->applyActions(pulse); + d->hysteresis->AtSteadyStateUpdateUI(); } void QVentilatorWidget::PhysiologyUpdateUI(const std::vector& actions) @@ -513,6 +671,33 @@ void QVentilatorWidget::UpdateUI(const std::vector& actions) d->hysteresis->PhysiologyUpdateUI(actions); } +void QVentilatorWidget::ProcessPhysiology(PhysiologyEngine& pulse) +{ + // This is called from a thread, you should NOT update UI here + // This is where we pull data from pulse, and push any actions to it + + d->hysteresis->ProcessPhysiology(pulse); + + auto ventilator = pulse.GetMechanicalVentilator(); + + d->number_0->setWithoutUpdate(ventilator->GetPeakInspiratoryPressure(PressureUnit::cmH2O)); + d->number_1->setWithoutUpdate(ventilator->GetTidalVolume(VolumeUnit::mL)); + d->number_2->setWithoutUpdate(ventilator->GetMeanAirwayPressure(PressureUnit::cmH2O)); + d->number_3->setWithoutUpdate(ventilator->GetTotalPulmonaryVentilation(VolumePerTimeUnit::L_Per_min)); + d->number_4->setWithoutUpdate(ventilator->GetRespirationRate(FrequencyUnit::Per_min)); + d->number_5->setWithoutUpdate(ventilator->GetEndTidalCarbonDioxidePressure(PressureUnit::mmHg)); + d->number_6->setWithoutUpdate(ventilator->GetStaticRespiratoryCompliance(VolumePerPressureUnit::mL_Per_cmH2O)); + d->number_7->setWithoutUpdate(ventilator->GetInspiratoryExpiratoryRatio()); + + double time_s = pulse.GetSimulationTime(TimeUnit::s); + d->plot_0->append(time_s, ventilator->GetAirwayPressure(PressureUnit::cmH2O)); + d->plot_1->append(time_s, ventilator->GetInspiratoryFlow(VolumePerTimeUnit::L_Per_min)); + d->plot_2->append(time_s, ventilator->GetTotalLungVolume(VolumeUnit::mL)); + + d->applyActions(pulse); +} + + void QVentilatorWidget::EngineErrorUI() { @@ -536,6 +721,7 @@ void QVentilatorWidget::applyAction() if (mode == "NONE") { + disconnectAction(); return; } else if (mode == "PC-CMV" || mode == "PC-AC") @@ -545,10 +731,12 @@ void QVentilatorWidget::applyAction() action->SetConnection(eSwitch::On); if (mode == "PC-AC") { + d->enableTriggers(true); action->SetMode(eMechanicalVentilator_PressureControlMode::AssistedControl); } else { + d->enableTriggers(false); action->SetMode(eMechanicalVentilator_PressureControlMode::ContinuousMandatoryVentilation); } emit(UpdateAction(*action, t)); @@ -562,10 +750,12 @@ void QVentilatorWidget::applyAction() // See setMode for dial assignments if (mode == "VC-AC") { + d->enableTriggers(true); action->SetMode(eMechanicalVentilator_VolumeControlMode::AssistedControl); } else { + d->enableTriggers(false); action->SetMode(eMechanicalVentilator_VolumeControlMode::ContinuousMandatoryVentilation); } emit(UpdateAction(*action, t)); @@ -574,6 +764,7 @@ void QVentilatorWidget::applyAction() } else if (mode == "CPAP") { + d->enableTriggers(false); auto action = std::make_unique(); action->SetConnection(eSwitch::On); action->Copy(d->currentValues.cpap); @@ -656,3 +847,84 @@ void QVentilatorWidget::unlock() { d->applyButton->setDisabled(false); } + +void QVentilatorWidget::enableFlowTrigger() +{ + d->inspirationPatientTriggerFlow->EnableInput(true); + d->inspirationPatientTriggerPressure->EnableInput(false); + d->modelRadio->setChecked(false); + d->modelTriggerValue->setEnabled(false); + d->modelTriggerValue->setText("Off"); + +} +void QVentilatorWidget::enablePressureTrigger() +{ + d->inspirationPatientTriggerFlow->EnableInput(false); + d->inspirationPatientTriggerPressure->EnableInput(true); + d->modelRadio->setChecked(false); + d->modelTriggerValue->setEnabled(false); + d->modelTriggerValue->setText("Off"); +} +void QVentilatorWidget::enableModelTrigger() +{ + d->inspirationPatientTriggerFlow->EnableInput(false); + d->inspirationPatientTriggerPressure->EnableInput(false); + d->modelRadio->setChecked(true); + d->modelTriggerValue->setEnabled(true); + d->modelTriggerValue->setText("On"); +} + +void QVentilatorWidget::applyTriggers() +{ + auto action = std::make_unique(); + action->SetMergeType(eMergeType::Append); + + if (d->inspirationPatientTriggerFlow->IsChecked() && !d->inspirationPatientTriggerFlow->IsZero()) + { + d->inspirationPatientTriggerFlow->GetValue( + action->GetSettings().GetInspirationPatientTriggerFlow()); + } + + else if (d->inspirationPatientTriggerPressure->IsChecked() && !d->inspirationPatientTriggerPressure->IsZero()) + d->inspirationPatientTriggerPressure->GetValue( + action->GetSettings().GetInspirationPatientTriggerPressure()); + else + { + enableModelTrigger(); + action->GetSettings().SetInspirationPatientTriggerRespiratoryModel(eSwitch::On); + } + SEScalarTime t; + t.Invalidate(); + emit(UpdateAction(*action, t)); + d->addAction(std::move(action)); +} + +void QVentilatorWidget::applyDrugs() +{ + auto action = std::make_unique(); + action->SetMergeType(eMergeType::Append); + if (d->albuterolConcentration->IsChecked()) + { + d->albuterolConcentration->GetValue( + action->GetSettings().GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration() + ); + } + else + { + action->GetSettings().GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration().SetValue(0, MassPerVolumeUnit::g_Per_L); + } + if (d->desfluraneVolumeFraction->IsChecked()) + { + d->desfluraneVolumeFraction->GetValue( + action->GetSettings().GetFractionInspiredGas(*d->desflurane).GetFractionAmount() + ); + } + else + { + action->GetSettings().GetFractionInspiredGas(*d->desflurane).GetFractionAmount().SetValue(0); + } + SEScalarTime t; + t.Invalidate(); + emit(UpdateAction(*action, t)); + d->addAction(std::move(action)); +} diff --git a/src/controls/VentilatorWidget.h b/src/controls/VentilatorWidget.h index 7673795..a86649f 100644 --- a/src/controls/VentilatorWidget.h +++ b/src/controls/VentilatorWidget.h @@ -52,6 +52,13 @@ protected slots: void setMode(QString val); void resetDials(); + void enableFlowTrigger(); + void enablePressureTrigger(); + void enableModelTrigger(); + void applyTriggers(); + + void applyDrugs(); + protected: void setupNumbers(); void UpdateUI(const std::vector& actions); diff --git a/src/ui/MainExplorerWindow.ui b/src/ui/MainExplorerWindow.ui index c315a38..29d0e35 100644 --- a/src/ui/MainExplorerWindow.ui +++ b/src/ui/MainExplorerWindow.ui @@ -138,13 +138,28 @@ + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - 3 + 6 @@ -157,6 +172,21 @@ ParaView + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -173,6 +203,21 @@ Vitals Monitor + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -310,6 +355,21 @@ Data Requests + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -447,6 +507,21 @@ Modifiers + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -469,6 +544,21 @@ Environment + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -491,6 +581,21 @@ Scenario + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -510,6 +615,21 @@ Ventilator + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -547,6 +667,18 @@ + + 0 + + + 0 + + + 0 + + + 0 + diff --git a/src/ui/Ventilator.ui b/src/ui/Ventilator.ui index 2fb54db..239f7a5 100644 --- a/src/ui/Ventilator.ui +++ b/src/ui/Ventilator.ui @@ -26,6 +26,9 @@ 0 + + 6 + @@ -50,6 +53,21 @@ QFrame::Raised + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -75,116 +93,285 @@ - 40 + 60 20 - + + + + 0 + 0 + + - 150 + 300 0 - - QFrame::StyledPanel + + + 300 + 16777215 + - - QFrame::Raised + + 0 - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - false - - - Hold - - - - - - - false - - - Disconnect - - - - - - - Connect - - - - - - - - NONE - - - - - PC-CMV - - - - - PC-AC - - - - - VC-CMV - - - - - VC-AC - - - + + false + + + + QWidget#ModeTab { background: #F0F0F0 } + + + Mode + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Qt::Horizontal + + + + 15 + 20 + + + + + + + + + 132 + 0 + + + + + NONE + + + + + PC-CMV + + + + + PC-AC + + + + + VC-CMV + + + + + VC-AC + + + + + CPAP + + + + + + + + + + + + Connect + + + + + + + false + + + Disconnect + + + + + + + + + + + false + + + Hold + + + + + + + Reset + + + + + + + - CPAP + Show Loops - - - - - - - Loops - - - - - - - Reset - - - - + + + + + + + QWidget#TriggerTab { background: #F0F0F0 } + + + Triggers + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 80 + 0 + + + + Apply + + + + + + + + + + QWidget#DrugTab { background: #F0F0F0 } + + + Drugs + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 80 + 0 + + + + Apply + + + + + + + @@ -266,6 +453,18 @@ QFrame::Sunken + + 0 + + + 0 + + + 0 + + + 0 + @@ -327,7 +526,6 @@ - 75 true @@ -356,7 +554,6 @@ - 75 true @@ -390,7 +587,6 @@ - 75 true @@ -416,7 +612,6 @@ - 75 true @@ -433,7 +628,6 @@ 12 - 75 true @@ -457,7 +651,6 @@ 12 - 75 true @@ -488,7 +681,6 @@ - 75 true @@ -517,7 +709,6 @@ - 75 true @@ -537,7 +728,6 @@ 12 - 75 true -- GitLab From cb6a2be54d5818e9234fd01620e087fdb18f41d3 Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Mon, 20 Jan 2025 09:43:10 -0500 Subject: [PATCH 10/11] Sync data requests with CDM names Update ventilator trigger/drug logic --- src/MainExplorerWindow.cxx | 1 - src/controls/DataRequestWidget.cxx | 23 +- src/controls/ScalarQuantityWidget.inl | 4 + src/controls/ScalarWidget.cxx | 4 + src/controls/VentilatorWidget.cxx | 851 +++++++++++------- src/controls/VentilatorWidget.h | 36 +- ...ContinuousPositiveAirwayPressureWidget.cxx | 2 +- ...hanicalVentilatorPressureControlWidget.cxx | 2 +- ...echanicalVentilatorVolumeControlWidget.cxx | 2 +- 9 files changed, 549 insertions(+), 376 deletions(-) diff --git a/src/MainExplorerWindow.cxx b/src/MainExplorerWindow.cxx index ed4ce96..77a60dd 100644 --- a/src/MainExplorerWindow.cxx +++ b/src/MainExplorerWindow.cxx @@ -118,7 +118,6 @@ MainExplorerWindow::MainExplorerWindow() // is subclassed from the UI class // i.e. m_Controls->VentilatorWidget // Hack move the ventilator widget to #2 - connect(m_Controls->VentilatorWidget, SIGNAL(UpdateAction(SEAction const&, SEScalarTime const&)), m_Controls->DynamicControls, SLOT(UpdateAction(SEAction const&, SEScalarTime const&))); int ventTab = findTab(m_Controls->TabWidget, "Ventilator"); diff --git a/src/controls/DataRequestWidget.cxx b/src/controls/DataRequestWidget.cxx index b633999..5c84ebe 100644 --- a/src/controls/DataRequestWidget.cxx +++ b/src/controls/DataRequestWidget.cxx @@ -61,6 +61,7 @@ public: //Physiology Properties std::set BloodChemistry { + "BaseExcess", "BloodDensity", "BloodPH", "BloodSpecificHeat", @@ -71,6 +72,8 @@ public: "HemoglobinContent", "OxygenSaturation", "Phosphate", + "PlasmaOsmolality", + "PlasmaOsmolarity", "PlasmaVolume", "PulseOximetry", "RedBloodCellCount", @@ -113,6 +116,7 @@ public: "MeanArterialCarbonDioxidePartialPressureDelta", "MeanCentralVenousPressure", "MeanSkinFlow", + "PeripheralPerfusionIndex", "PulmonaryArterialPressure", "PulmonaryCapillariesCoverageFraction", "PulmonaryCapillariesWedgePressure", @@ -139,6 +143,7 @@ public: "MeanBloodPressureChange", "NeuromuscularBlockLevel", "PulsePressureChange", + //"PupillaryResponse", "RespirationRateChange", "SedationLevel", "TidalVolumeChange", @@ -250,19 +255,20 @@ public: "EndTidalOxygenFraction", "EndTidalOxygenPressure", "ExpiratoryFlow", - "ExpiratoryPulmonaryResistance", + "ExpiratoryRespiratoryResistance", "ExpiratoryTidalVolume", - "FractionOfInsipredOxygen", + "ExtrinsicPositiveEndExpiratoryPressure", + "FractionOfInspiredOxygen", "HorowitzIndex", "ImposedPowerOfBreathing", "ImposedWorkOfBreathing", "InspiratoryExpiratoryRatio", "InspiratoryFlow", - "InspiratoryPulmonaryResistance", + "InspiratoryRespiratoryResistance", "InspiratoryTidalVolume", "IntrapleuralPressure", "IntrapulmonaryPressure", - "IntrinsicPositiveEndExpiredPressure", + "IntrinsicPositiveEndExpiratoryPressure", "LungCompliance", "MaximalInspiratoryPressure", "MeanAirwayPressure", @@ -273,9 +279,8 @@ public: "PeakInspiratoryPressure", "PhysiologicDeadSpace", "PhysiologicDeadSpaceTidalVolumeRatio", - "PositiveEndExpiratoryPressure", - "PulmonaryCompliance", - "PulmonaryElastance", + "RespiratoryCompliance", + "RespiratoryElastance", "RelativeTotalLungVolume", "ResistiveExpiratoryWorkOfBreathing", "ResistiveInspiratoryWorkOfBreathing", @@ -288,6 +293,7 @@ public: "TotalAlveolarVentilation", "TotalDeadSpaceVentilation", "TotalLungVolume", + "TotalPositiveEndExpiratoryPressure", "TotalPowerOfBreathing", "TotalPulmonaryVentilation", "TotalWorkOfBreathing", @@ -308,7 +314,8 @@ public: "IntracellularFluidPH", "IntracellularFluidVolume", "OxygenConsumptionRate", - "RespiratoryExchangeRatio" + "RespiratoryExchangeRatio", + "TotalFluidVolume" }; }; diff --git a/src/controls/ScalarQuantityWidget.inl b/src/controls/ScalarQuantityWidget.inl index 5c276b0..3c0df22 100644 --- a/src/controls/ScalarQuantityWidget.inl +++ b/src/controls/ScalarQuantityWidget.inl @@ -202,7 +202,11 @@ template void QScalarQuantityWidget::EnableInput(bool check, bool value) { if (m_Check != nullptr) + { m_Check->setEnabled(check); + if (!value) + m_Check->setChecked(false); + } if (m_Radio != nullptr) m_Radio->setChecked(check); m_Value->setEnabled(value); diff --git a/src/controls/ScalarWidget.cxx b/src/controls/ScalarWidget.cxx index bd613e1..54ea03c 100644 --- a/src/controls/ScalarWidget.cxx +++ b/src/controls/ScalarWidget.cxx @@ -145,7 +145,11 @@ void QScalarWidget::EnableInput(bool b) void QScalarWidget::EnableInput(bool check, bool value) { if (m_Check != nullptr) + { m_Check->setEnabled(check); + if (!value) + m_Check->setChecked(false); + } if (m_Radio != nullptr) m_Radio->setChecked(check); m_Value->setEnabled(value); diff --git a/src/controls/VentilatorWidget.cxx b/src/controls/VentilatorWidget.cxx index 30bea09..46b1323 100644 --- a/src/controls/VentilatorWidget.cxx +++ b/src/controls/VentilatorWidget.cxx @@ -42,7 +42,7 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget Private(QVentilatorWidget* parent) : parent(parent) { setupUi(parent); - setupInitialValues(); + SetupInitialValues(); hysteresis = new QVentilatorHysteresisWidget(parent, Qt::WindowType::Window); hysteresis->hide(); connect(hysteresisButton, &QPushButton::released, [this]() @@ -52,6 +52,7 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget }); } + const SESubstanceManager* subMgr; // Mode QVector dials; QVector numbers; @@ -79,68 +80,132 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget static const int CPAP = 2; struct ActionSet { - SEMechanicalVentilatorPressureControl pc; - SEMechanicalVentilatorVolumeControl vc; + SEMechanicalVentilatorPressureControl pc_ac; + SEMechanicalVentilatorPressureControl pc_cmv; + SEMechanicalVentilatorVolumeControl vc_ac; + SEMechanicalVentilatorVolumeControl vc_cmv; SEMechanicalVentilatorContinuousPositiveAirwayPressure cpap; }; ActionSet initialValues; ActionSet currentValues; + // These are used when loading a state and updating the UI at steady state const SEMechanicalVentilatorMode* stateMode = nullptr; const SEMechanicalVentilatorHold* stateHold = nullptr; - SEMechanicalVentilatorSettings* stateConfig = nullptr; - std::vector> actions; + SEMechanicalVentilatorSettings* stateSettings = nullptr; + // For passing setting updates over to the engine as we run + std::vector> unique_ptr_actions; + // More detailed configuration properties to append to the selected mode int modeFromAction = -1; QMutex actionMutex; - void addAction(std::unique_ptr p) + void Reset() + { + for (auto number : numbers) + { + number->setValue(0); + } + + modeBox->setCurrentIndex(0); + + for (auto dial : dials) + { + dial->hide(); + } + + plot_0->clear(); + plot_0->setYRange(-0.1, 20.); + min_0->setText("0"); + max_0->setText("20"); + plot_0->setMaxPoints(50 * 15); // 15 Seconds + plot_0->setScaleMode(PulsePainterPlot::ScaleMode::Expanding); + plot_0->setUpdateMode(PulsePainterPlot::UpdateMode::InPlace); + plot_1->clear(); + plot_1->setYRange(-30, 30); + min_1->setText("-30"); + max_1->setText("30"); + plot_1->setMaxPoints(50 * 15); // 15 Seconds + plot_1->setScaleMode(PulsePainterPlot::ScaleMode::Expanding); + plot_1->setUpdateMode(PulsePainterPlot::UpdateMode::InPlace); + plot_2->clear(); + plot_2->setYRange(-100.0, 500); + plot_2->setMaxPoints(50 * 15); // 15 Seconds + plot_2->setScaleMode(PulsePainterPlot::ScaleMode::Expanding); + plot_2->setUpdateMode(PulsePainterPlot::UpdateMode::InPlace); + min_2->setText("-100"); + max_2->setText("500"); + + currentValues.pc_ac.Copy(initialValues.pc_ac, *subMgr); + currentValues.pc_cmv.Copy(initialValues.pc_cmv, *subMgr); + currentValues.vc_ac.Copy(initialValues.vc_ac, *subMgr); + currentValues.vc_cmv.Copy(initialValues.vc_cmv, *subMgr); + currentValues.cpap.Copy(initialValues.cpap, *subMgr); + + EnableTriggers(false); + EnableDrugs(false); + } + + void ResetDials() + { + SetMode(modeBox->currentText(), true); + } + + void AddAction(std::unique_ptr p) { QMutexLocker lock(&actionMutex); - actions.push_back(std::move(p)); + unique_ptr_actions.push_back(std::move(p)); } - void applyActions(PhysiologyEngine& pulse) + void ApplyActions(PhysiologyEngine& pulse) { QMutexLocker lock(&actionMutex); - for (auto& action : actions) + for (auto& action : unique_ptr_actions) { pulse.ProcessAction(*action); } - actions.clear(); + unique_ptr_actions.clear(); } - void setupInitialValues() - { + void SetupInitialValues() + { // Try to keep this in sync with whats in the Pulse HowTo_MechanicalVentilator.cpp { - auto& action = initialValues.pc; - action.SetConnection(eSwitch::On); - action.GetFractionInspiredOxygen().SetValue(.21); - action.GetInspiratoryPressure().SetValue(13.0, PressureUnit::cmH2O); - action.GetInspiratoryPeriod().SetValue(1.0, TimeUnit::s); - action.GetRespirationRate().SetValue(12, FrequencyUnit::Per_min); - action.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); - action.GetSlope().SetValue(0.2, TimeUnit::s); + auto& pc_cmv = initialValues.pc_cmv; + pc_cmv.SetConnection(eSwitch::On); + pc_cmv.GetFractionInspiredOxygen().SetValue(.21); + pc_cmv.GetInspiratoryPressure().SetValue(23.0, PressureUnit::cmH2O); + pc_cmv.GetInspiratoryPeriod().SetValue(1.1, TimeUnit::s); + pc_cmv.GetRespirationRate().SetValue(12, FrequencyUnit::Per_min); + pc_cmv.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); + pc_cmv.GetSlope().SetValue(0.2, TimeUnit::s); + auto& pc_ac = initialValues.pc_ac; + pc_ac.Copy(pc_cmv, *subMgr); + pc_ac.SetMode(eMechanicalVentilator_PressureControlMode::AssistedControl); + pc_cmv.SetMode(eMechanicalVentilator_PressureControlMode::ContinuousMandatoryVentilation); } { - auto& action = initialValues.vc; - action.SetConnection(eSwitch::On); - action.GetFractionInspiredOxygen().SetValue(0.21); - action.GetTidalVolume().SetValue(600, VolumeUnit::mL); - action.GetInspiratoryPeriod().SetValue(1.0, TimeUnit::s); - action.GetRespirationRate().SetValue(12, FrequencyUnit::Per_min); - action.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); - action.GetFlow().SetValue(50, VolumePerTimeUnit::L_Per_min); + auto& vc_cmv = initialValues.vc_cmv; + vc_cmv.SetConnection(eSwitch::On); + vc_cmv.GetFractionInspiredOxygen().SetValue(0.21); + vc_cmv.GetTidalVolume().SetValue(540, VolumeUnit::mL); + vc_cmv.GetInspiratoryPeriod().SetValue(1.0, TimeUnit::s); + vc_cmv.GetRespirationRate().SetValue(12, FrequencyUnit::Per_min); + vc_cmv.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); + vc_cmv.GetFlow().SetValue(60, VolumePerTimeUnit::L_Per_min); auto& pc_ac = initialValues.pc_ac; + auto& vc_ac = initialValues.vc_ac; + vc_ac.Copy(vc_cmv, *subMgr); + vc_ac.SetMode(eMechanicalVentilator_VolumeControlMode::AssistedControl); + vc_cmv.SetMode(eMechanicalVentilator_VolumeControlMode::ContinuousMandatoryVentilation); } { - auto& action = initialValues.cpap; - action.SetConnection(eSwitch::On); - action.GetFractionInspiredOxygen().SetValue(0.21); - action.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); - action.GetDeltaPressureSupport().SetValue(8, PressureUnit::cmH2O); - action.GetSlope().SetValue(0.2, TimeUnit::s); + auto& cpap = initialValues.cpap; + cpap.SetConnection(eSwitch::On); + cpap.GetFractionInspiredOxygen().SetValue(0.21); + cpap.GetPositiveEndExpiratoryPressure().SetValue(5.0, PressureUnit::cmH2O); + cpap.GetDeltaPressureSupport().SetValue(10, PressureUnit::cmH2O); + cpap.GetSlope().SetValue(0.2, TimeUnit::s); } } @@ -154,25 +219,25 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget Hold }; - void clearSlope() + void ClearSlope() { if (tiWidget == nullptr) return; - disconnect(tiWidget, &LabeledDialWidget::valueChanged, parent, &QVentilatorWidget::updateSlope); + disconnect(tiWidget, &LabeledDialWidget::valueChanged, parent, &QVentilatorWidget::UpdateSlope); tiWidget = nullptr; slopeWidget = nullptr; } // The range of the slope is dependent on another widgets range, set up and connect the two - void setupSlope(LabeledDialWidget* ti, LabeledDialWidget* slope) + void SetupSlope(LabeledDialWidget* ti, LabeledDialWidget* slope) { - clearSlope(); + ClearSlope(); slopeWidget = slope; tiWidget = ti; - connect(tiWidget, &LabeledDialWidget::valueChanged, parent, &QVentilatorWidget::updateSlope); + connect(tiWidget, &LabeledDialWidget::valueChanged, parent, &QVentilatorWidget::UpdateSlope); } // maxIndex the index of the last dial to show, dials with index higher will be hidden in the UI - void showDials(int maxIndex) + void ShowDials(int maxIndex) { for (int i = 0; i < maxIndex && i < dials.size(); ++i) { @@ -180,9 +245,9 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget } } - void setMode(QString mode, bool resetValues = false) + void SetMode(QString mode, bool resetValues = false) { - clearSlope(); + ClearSlope(); for (auto dial : dials) { @@ -191,119 +256,146 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget if (mode == "NONE") { - setUIState(VentilatorNone); + SetUIState(VentilatorNone); return; } else if (mode == "PC-CMV" || mode == "PC-AC") { - if (resetValues) currentValues.pc.Copy(initialValues.pc); - auto& action = currentValues.pc; - dial_0->setup("FiO2", "",0.21, 1.0, 100, 0.1, &action.GetFractionInspiredOxygen()); - dial_1->setup("Pinsp", "cmH2O", 1, 100, 1, 1, &action.GetInspiratoryPressure()); - dial_2->setup("Ti", "s", 0.1, 60, 10, 0.1, &action.GetInspiratoryPeriod()); - dial_3->setup("RR", "bpm", 10, 60, 1, 1.0, &action.GetRespirationRate()); - dial_4->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, &action.GetPositiveEndExpiratoryPressure()); - dial_5->setup("Slope", "s", 0, dial_2->getValue(), 10, 0.1, &action.GetSlope()); - setupSlope(dial_2, dial_5); - showDials(6); + SEMechanicalVentilatorPressureControl* initial; + SEMechanicalVentilatorPressureControl* current; + if (mode == "PC-AC") + { + EnableTriggers(true); + initial = &initialValues.pc_ac; + current = ¤tValues.pc_ac; + } + else + { + EnableTriggers(false); + initial = &initialValues.pc_cmv; + current = ¤tValues.pc_cmv; + } + if (resetValues) + current->Copy(*initial, *subMgr); + + dial_0->setup("FiO2", "",0.21, 1.0, 100, 0.01, ¤t->GetFractionInspiredOxygen()); + dial_1->setup("Pinsp", "cmH2O", 1, 100, 1, 1, ¤t->GetInspiratoryPressure()); + dial_2->setup("Ti", "s", 0.1, 60, 10, 0.1, ¤t->GetInspiratoryPeriod()); + dial_3->setup("RR", "bpm", 10, 60, 1, 1.0, ¤t->GetRespirationRate()); + dial_4->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, ¤t->GetPositiveEndExpiratoryPressure()); + dial_5->setup("Slope", "s", 0, dial_2->getValue(), 10, 0.1, ¤t->GetSlope()); + SetupSlope(dial_2, dial_5); + ShowDials(6); + if (mode == "PC-AC") + { + // Update Trigger + if (current->HasInspirationPatientTriggerFlow()) + { + EnableFlowTrigger(); + inspirationPatientTriggerFlow->SetValue(current->GetInspirationPatientTriggerFlow()); + } + else if (current->HasInspirationPatientTriggerPressure()) + { + EnablePressureTrigger(); + inspirationPatientTriggerPressure->SetValue(current->GetInspirationPatientTriggerPressure()); + } + else + { + EnableModelTrigger(); + } + } } else if (mode == "VC-CMV" || mode == "VC-AC") { - if (resetValues) currentValues.vc.Copy(initialValues.vc); - auto& action = currentValues.vc; - dial_0->setup("FiO2", "", 0.21, 1.0, 100, 0.1, &action.GetFractionInspiredOxygen()); - dial_1->setup("VT", "mL", 100, 2000, 1, 1.0, &action.GetTidalVolume()); - dial_2->setup("Ti", "s", 0.1, 60, 10, 0.1, &action.GetInspiratoryPeriod()); - dial_3->setup("RR", "bpm", 10, 60, 1, 1.0, &action.GetRespirationRate()); - dial_4->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, &action.GetPositiveEndExpiratoryPressure()); - dial_5->setup("Flow", "L/min", 1, 100, 1, 1.0, &action.GetFlow()); - showDials(6); + SEMechanicalVentilatorVolumeControl* initial; + SEMechanicalVentilatorVolumeControl* current; + if (mode == "VC-AC") + { + EnableTriggers(true); + initial = &initialValues.vc_ac; + current = ¤tValues.vc_ac; + } + else + { + EnableTriggers(false); + initial = &initialValues.vc_cmv; + current = ¤tValues.vc_cmv; + } + if (resetValues) + current->Copy(*initial, *subMgr); + dial_0->setup("FiO2", "", 0.21, 1.0, 100, 0.01, ¤t->GetFractionInspiredOxygen()); + dial_1->setup("VT", "mL", 100, 2000, 1, 10.0, ¤t->GetTidalVolume()); + dial_2->setup("Ti", "s", 0.1, 60, 10, 0.1, ¤t->GetInspiratoryPeriod()); + dial_3->setup("RR", "bpm", 10, 60, 1, 1.0, ¤t->GetRespirationRate()); + dial_4->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, ¤t->GetPositiveEndExpiratoryPressure()); + dial_5->setup("Flow", "L/min", 1, 100, 1, 1.0, ¤t->GetFlow()); + ShowDials(6); + if (mode == "VC-AC") + { + // Update Trigger + if (current->HasInspirationPatientTriggerFlow()) + { + EnableFlowTrigger(); + inspirationPatientTriggerFlow->SetValue(current->GetInspirationPatientTriggerFlow()); + } + else if (current->HasInspirationPatientTriggerPressure()) + { + EnablePressureTrigger(); + inspirationPatientTriggerPressure->SetValue(current->GetInspirationPatientTriggerPressure()); + } + else + { + EnableModelTrigger(); + } + } } else if (mode == "CPAP") { - if (resetValues) currentValues.cpap.Copy(initialValues.cpap); - auto& action = currentValues.cpap; - dial_0->setup("FiO2", "", 0.21, 1.0, 100, 0.1, &action.GetFractionInspiredOxygen()); - dial_1->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, &action.GetPositiveEndExpiratoryPressure()); - dial_2->setup("deltaPsupp", "cmH2O", 1, 100, 1, 1.0, &action.GetDeltaPressureSupport()); - dial_3->setup("Slope", "s", 0, 1, 100, 0.1, &action.GetSlope()); - showDials(4); + EnableTriggers(true); + if (resetValues) currentValues.cpap.Copy(initialValues.cpap, *subMgr); + auto& cpap = currentValues.cpap; + dial_0->setup("FiO2", "", 0.21, 1.0, 100, 0.01, &cpap.GetFractionInspiredOxygen()); + dial_1->setup("PEEP", "cmH2O", 0, 50, 1, 1.0, &cpap.GetPositiveEndExpiratoryPressure()); + dial_2->setup("deltaPsupp", "cmH2O", 1, 100, 1, 1.0, &cpap.GetDeltaPressureSupport()); + dial_3->setup("Slope", "s", 0, 1, 100, 0.1, &cpap.GetSlope()); + ShowDials(4); + // Update Trigger + if (cpap.HasInspirationPatientTriggerFlow()) + { + EnableFlowTrigger(); + inspirationPatientTriggerFlow->SetValue(cpap.GetInspirationPatientTriggerFlow()); + } + else if (cpap.HasInspirationPatientTriggerPressure()) + { + EnablePressureTrigger(); + inspirationPatientTriggerPressure->SetValue(cpap.GetInspirationPatientTriggerPressure()); + } + else + { + EnableModelTrigger(); + } } else { qWarning() << "Mode " << mode << " not found."; } applyButton->setEnabled(true); - setUIState((applyButton->text() == "Connect") ? Disconnected : Connected); - // Reset Triggers and Drugs when changing modes - resetDrugs(); - } - - - void reset() - { - for (auto number : numbers) - { - number->setValue(0); - } - - - modeBox->setCurrentIndex(0); - - - for (auto dial : dials) - { - dial->hide(); - } - - plot_0->clear(); - plot_0->setYRange(-0.1, 20.); - min_0->setText("0"); - max_0->setText("20"); - plot_0->setMaxPoints(50 * 15); // 15 Seconds - plot_0->setScaleMode(PulsePainterPlot::ScaleMode::Expanding); - plot_0->setUpdateMode(PulsePainterPlot::UpdateMode::InPlace); - plot_1->clear(); - plot_1->setYRange(-30, 30); - min_1->setText("-30"); - max_1->setText("30"); - plot_1->setMaxPoints(50 * 15); // 15 Seconds - plot_1->setScaleMode(PulsePainterPlot::ScaleMode::Expanding); - plot_1->setUpdateMode(PulsePainterPlot::UpdateMode::InPlace); - plot_2->clear(); - plot_2->setYRange(-100.0, 500); - plot_2->setMaxPoints(50 * 15); // 15 Seconds - plot_2->setScaleMode(PulsePainterPlot::ScaleMode::Expanding); - plot_2->setUpdateMode(PulsePainterPlot::UpdateMode::InPlace); - min_2->setText("-100"); - max_2->setText("500"); - - currentValues.pc.Copy(initialValues.pc); - currentValues.vc.Copy(initialValues.vc); - currentValues.cpap.Copy(initialValues.cpap); - - resetTriggers(); - resetDrugs(); - } - - void resetDials() - { - setMode(modeBox->currentText(), true); + SetUIState((applyButton->text() == "Connect") ? Disconnected : Connected); } - void setUIState(UIState state) + void SetUIState(UIState state) { switch (state) { case Default: - reset(); - setUIState(Off); + Reset(); + SetUIState(Off); applyButton->setEnabled(false); break; case Enabled: modeBox->setEnabled(true); resetButton->setEnabled(true); - setUIState((applyButton->text() == "Connect") ? Disconnected : Connected); + SetUIState((applyButton->text() == "Connect") ? Disconnected : Connected); break; case Off: case VentilatorNone: @@ -322,11 +414,9 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget resetButton->setEnabled(false); hysteresisButton->setEnabled(false); // Triggers - enableTriggers(false); + EnableTriggers(false); // Drugs - albuterolConcentration->setEnabled(false); - desfluraneVolumeFraction->setEnabled(false); - apply_drugs->setEnabled(false); + EnableDrugs(false); break; case Connected: case Disconnected: @@ -334,24 +424,22 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget { applyButton->setText("Apply"); disconnectButton->setEnabled(true); + EnableDrugs(true); } else if (state == Disconnected) { applyButton->setText("Connect"); disconnectButton->setEnabled(false); + EnableDrugs(false); } resetButton->setEnabled(true); holdButton->setEnabled(true); hysteresisButton->setEnabled(true); - // Drugs - albuterolConcentration->setEnabled(true); - desfluraneVolumeFraction->setEnabled(true); - apply_drugs->setEnabled(true); break; } } - void enableTriggers(bool b) + void EnableTriggers(bool b) { if (b && modelTrigger->isEnabled()) return; // We are already enabled @@ -380,19 +468,79 @@ struct QVentilatorWidget::Private : public Ui::VentilatorWidget inspirationPatientTriggerPressure->EnableInput(false); modelTrigger->setEnabled(true); modelRadio->setChecked(true); - modelTriggerValue->setText("On"); apply_triggers->setEnabled(true); + modelTriggerValue->setText("On"); } } - void resetTriggers() + void EnableFlowTrigger() + { + inspirationPatientTriggerFlow->EnableInput(true); + inspirationPatientTriggerPressure->EnableInput(false); + modelRadio->setChecked(false); + modelTriggerValue->setEnabled(false); + + } + void EnablePressureTrigger() + { + inspirationPatientTriggerFlow->EnableInput(false); + inspirationPatientTriggerPressure->EnableInput(true); + modelRadio->setChecked(false); + modelTriggerValue->setEnabled(false); + } + void EnableModelTrigger() + { + inspirationPatientTriggerFlow->EnableInput(false); + inspirationPatientTriggerPressure->EnableInput(false); + modelRadio->setChecked(true); + modelTriggerValue->setEnabled(true); + } + + void PullTrigger(SEScalarVolumePerTime& flowTrigger, SEScalarPressure& pressureTrigger) { + // Pull from Triggers Tab + if (apply_triggers->isEnabled()) + { + if (inspirationPatientTriggerFlow->IsChecked()) + { + pressureTrigger.Invalidate(); + inspirationPatientTriggerFlow->GetValue(flowTrigger); + if (flowTrigger.IsZero()) + flowTrigger.Invalidate(); + if (!flowTrigger.IsValid()) + { + // Default back to model trigger + inspirationPatientTriggerFlow->EnableInput(true, false); + EnableModelTrigger(); + } + } + else if (inspirationPatientTriggerPressure->IsChecked()) + { + flowTrigger.Invalidate(); + inspirationPatientTriggerPressure->GetValue(pressureTrigger); + if (pressureTrigger.IsZero()) + pressureTrigger.Invalidate(); + if (!pressureTrigger.IsValid()) + { + // Default back to model trigger + inspirationPatientTriggerPressure->EnableInput(true, false); + EnableModelTrigger(); + } + } + else + { + flowTrigger.Invalidate(); + pressureTrigger.Invalidate(); + EnableModelTrigger(); + } + } } - void resetDrugs() + void EnableDrugs(bool b) { - albuterolConcentration->Reset(); - desfluraneVolumeFraction->Reset(); + albuterolConcentration->setEnabled(b); + desfluraneVolumeFraction->setEnabled(b); + apply_drugs->setEnabled(b); } }; @@ -414,27 +562,28 @@ QVentilatorWidget::QVentilatorWidget(QWidget *parent, Qt::WindowFlags flags) : d->number_5, d->number_6, d->number_7 }; - setupNumbers(); + SetupNumbers(); // Mode Controls - connect(d->modeBox, &QComboBox::currentTextChanged, this, &QVentilatorWidget::setMode); - connect(d->applyButton, &QPushButton::clicked, this, &QVentilatorWidget::applyAction); - connect(d->disconnectButton, &QPushButton::clicked, this, &QVentilatorWidget::disconnectAction); - connect(d->holdButton, &QPushButton::pressed, this, &QVentilatorWidget::addHold); - connect(d->holdButton, &QPushButton::released, this, &QVentilatorWidget::removeHold); - connect(d->resetButton, &QPushButton::released, this, &QVentilatorWidget::resetDials); + connect(d->modeBox, &QComboBox::currentTextChanged, this, &QVentilatorWidget::SetMode); + connect(d->applyButton, &QPushButton::clicked, this, &QVentilatorWidget::ApplyAction); + connect(d->disconnectButton, &QPushButton::clicked, this, &QVentilatorWidget::DisconnectAction); + connect(d->holdButton, &QPushButton::pressed, this, &QVentilatorWidget::AddHold); + connect(d->holdButton, &QPushButton::released, this, &QVentilatorWidget::RemoveHold); + connect(d->resetButton, &QPushButton::released, this, &QVentilatorWidget::ResetDials); // Triggers d->inspirationPatientTriggerFlow = new QScalarQuantityWidget("Flow", 0, 10000, 1, VolumePerTimeUnit::L_Per_min, ScalarOptionWidget::Radio, this); d->inspirationPatientTriggerFlow->AddUnit(VolumePerTimeUnit::L_Per_s); d->inspirationPatientTriggerFlow->AddUnit(VolumePerTimeUnit::mL_Per_s); d->inspirationPatientTriggerFlow->AddUnit(VolumePerTimeUnit::mL_Per_min); + d->inspirationPatientTriggerFlow->SetDefault(2); d->inspirationPatientTriggerFlow->EnableInput(false, false); d->trigger_layout->layout()->addWidget(d->inspirationPatientTriggerFlow); d->inspirationPatientTriggerPressure = new QScalarQuantityWidget("Pressure", -10000, 10000, 1, PressureUnit::cmH2O, ScalarOptionWidget::Radio, this); d->inspirationPatientTriggerPressure->AddUnit(PressureUnit::mmHg); d->inspirationPatientTriggerPressure->AddUnit(PressureUnit::Pa); d->inspirationPatientTriggerPressure->AddUnit(PressureUnit::psi); - d->inspirationPatientTriggerPressure->SetDefault(0); + d->inspirationPatientTriggerPressure->SetDefault(1); d->inspirationPatientTriggerPressure->EnableInput(false, false); d->trigger_layout->layout()->addWidget(d->inspirationPatientTriggerPressure); d->modelTriggerLayout = new QHBoxLayout(); @@ -456,10 +605,10 @@ QVentilatorWidget::QVentilatorWidget(QWidget *parent, Qt::WindowFlags flags) : d->modelTrigger = new QWidget(this); d->modelTrigger->setLayout(d->modelTriggerLayout); d->trigger_layout->layout()->addWidget(d->modelTrigger); - connect(d->inspirationPatientTriggerFlow->GetRadioButton(), SIGNAL(clicked()), this, SLOT(enableFlowTrigger())); - connect(d->inspirationPatientTriggerPressure->GetRadioButton(), SIGNAL(clicked()), this, SLOT(enablePressureTrigger())); - connect(d->modelRadio, SIGNAL(clicked()), this, SLOT(enableModelTrigger())); - connect(d->apply_triggers, &QPushButton::clicked, this, &QVentilatorWidget::applyTriggers); + connect(d->inspirationPatientTriggerFlow->GetRadioButton(), SIGNAL(clicked()), this, SLOT(EnableFlowTrigger())); + connect(d->inspirationPatientTriggerPressure->GetRadioButton(), SIGNAL(clicked()), this, SLOT(EnablePressureTrigger())); + connect(d->modelRadio, SIGNAL(clicked()), this, SLOT(EnableModelTrigger())); + connect(d->apply_triggers, &QPushButton::clicked, this, &QVentilatorWidget::ApplyTriggers); // Drugs d->albuterolConcentration = new QScalarQuantityWidget("Albuterol\nConcentration", 0, 10000, 1, MassPerVolumeUnit::g_Per_L, ScalarOptionWidget::Check, this); d->albuterolConcentration->AddUnit(MassPerVolumeUnit::g_Per_dL); @@ -472,7 +621,7 @@ QVentilatorWidget::QVentilatorWidget(QWidget *parent, Qt::WindowFlags flags) : d->drugs_layout->layout()->addWidget(d->albuterolConcentration); d->desfluraneVolumeFraction = new QScalarWidget("Desflurane\nVolume Fraction", 0, 1, 0.05, ScalarOptionWidget::Check, this); d->drugs_layout->layout()->addWidget(d->desfluraneVolumeFraction); - connect(d->apply_drugs, &QPushButton::clicked, this, &QVentilatorWidget::applyDrugs); + connect(d->apply_drugs, &QPushButton::clicked, this, &QVentilatorWidget::ApplyDrugs); Reset(); } @@ -484,17 +633,17 @@ QVentilatorWidget::~QVentilatorWidget() void QVentilatorWidget::Reset() { - d->setUIState(QVentilatorWidget::Private::Default); - d->enableTriggers(false); - d->resetDrugs(); + d->SetUIState(QVentilatorWidget::Private::Default); + d->EnableTriggers(false); + d->EnableDrugs(false); } void QVentilatorWidget::AtSteadyState(PhysiologyEngine& pulse) { - d->albuterol = pulse.GetSubstanceManager().GetSubstance("Albuterol"); - d->desflurane = pulse.GetSubstanceManager().GetSubstance("Desflurane"); - // Called when we load a state too, so copy any of our actions - + // Called when we load a state too, so copy any data or actions + d->subMgr = &pulse.GetSubstanceManager(); + d->albuterol = d->subMgr->GetSubstance("Albuterol"); + d->desflurane = d->subMgr->GetSubstance("Desflurane"); if (pulse.GetActionManager().GetEquipmentActions().HasMechanicalVentilatorContinuousPositiveAirwayPressure()) { @@ -515,13 +664,7 @@ void QVentilatorWidget::AtSteadyState(PhysiologyEngine& pulse) // TODO Log("Removing the hold from the loaded state"); } - if (pulse.GetMechanicalVentilator()->GetSettings()->GetConnection() == eSwitch::On) - { - if (d->stateConfig == nullptr) - d->stateConfig = new SEMechanicalVentilatorSettings(pulse.GetLogger()); - d->stateConfig->Copy(*pulse.GetMechanicalVentilator()->GetSettings(), pulse.GetSubstanceManager()); - } - + d->stateSettings = const_cast(pulse.GetMechanicalVentilator()->GetSettings()); d->hysteresis->AtSteadyState(pulse); @@ -561,95 +704,68 @@ void QVentilatorWidget::AtSteadyStateUpdateUI() { if (d->stateMode) { - std::vector actions {d->stateMode}; - UpdateUI(actions); - d->stateMode = nullptr; - d->setUIState(Private::Connected); + d->SetUIState(Private::Connected); + UpdateModeUI(); } - if (d->stateHold) {// Just force the hold release, this would be a wierd edge case to support // The use can just enable the hold manually - removeHold(); - d->stateHold = nullptr; + RemoveHold(); } + d->hysteresis->AtSteadyStateUpdateUI(); + if (d->stateSettings) + UpdateSettingsUI(); +} - if (d->stateConfig && d->stateConfig->GetConnection() == eSwitch::On) - { - d->modelTriggerValue->setText("On"); - // Update Trigger - if (d->stateConfig->HasInspirationPatientTriggerFlow()) - { - enableFlowTrigger(); - d->inspirationPatientTriggerFlow->SetValue(d->stateConfig->GetInspirationPatientTriggerFlow()); - } - else if (d->stateConfig->HasInspirationPatientTriggerPressure()) - { - enablePressureTrigger(); - d->inspirationPatientTriggerPressure->SetValue(d->stateConfig->GetInspirationPatientTriggerPressure()); - } - else if (d->stateConfig->HasInspirationPatientTriggerRespiratoryModel() && - d->stateConfig->GetInspirationPatientTriggerRespiratoryModel() == eSwitch::On) - { - enableModelTrigger(); - d->modelTriggerValue->setText("On"); - } - // Update Drugs - if (d->stateConfig->HasConcentrationInspiredAerosol(*d->albuterol)) - d->albuterolConcentration->SetValue(d->stateConfig->GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration()); - if (d->stateConfig->HasFractionInspiredGas(*d->desflurane)) - d->desfluraneVolumeFraction->SetValue(d->stateConfig->GetFractionInspiredGas(*d->desflurane).GetFractionAmount()); +void QVentilatorWidget::ProcessPhysiology(PhysiologyEngine& pulse) +{ + // This is called from a thread, you should NOT update UI here + // This is where we pull data from pulse, and push any actions to it - d->stateConfig->Clear(); - } + d->hysteresis->ProcessPhysiology(pulse); - d->hysteresis->AtSteadyStateUpdateUI(); -} + auto ventilator = pulse.GetMechanicalVentilator(); -void QVentilatorWidget::PhysiologyUpdateUI(const std::vector& actions) -{ - UpdateUI(actions); + d->number_0->setWithoutUpdate(ventilator->GetPeakInspiratoryPressure(PressureUnit::cmH2O)); + d->number_1->setWithoutUpdate(ventilator->GetTidalVolume(VolumeUnit::mL)); + d->number_2->setWithoutUpdate(ventilator->GetMeanAirwayPressure(PressureUnit::cmH2O)); + d->number_3->setWithoutUpdate(ventilator->GetTotalPulmonaryVentilation(VolumePerTimeUnit::L_Per_min)); + d->number_4->setWithoutUpdate(ventilator->GetRespirationRate(FrequencyUnit::Per_min)); + d->number_5->setWithoutUpdate(ventilator->GetEndTidalCarbonDioxidePressure(PressureUnit::mmHg)); + d->number_6->setWithoutUpdate(ventilator->GetStaticRespiratoryCompliance(VolumePerPressureUnit::mL_Per_cmH2O)); + d->number_7->setWithoutUpdate(ventilator->GetInspiratoryExpiratoryRatio()); + + double time_s = pulse.GetSimulationTime(TimeUnit::s); + d->plot_0->append(time_s, ventilator->GetAirwayPressure(PressureUnit::cmH2O)); + d->plot_1->append(time_s, ventilator->GetInspiratoryFlow(VolumePerTimeUnit::L_Per_min)); + d->plot_2->append(time_s, ventilator->GetTotalLungVolume(VolumeUnit::mL)); + + d->ApplyActions(pulse); } -void QVentilatorWidget::UpdateUI(const std::vector& actions) +void QVentilatorWidget::PhysiologyUpdateUI(const std::vector& actions) { - // This is called from a slot, you can update UI here - // This is where we take the pulse data we pulled and push it to a UI widget for (auto number : d->numbers) { number->updateValue(); } - - // Only the last/newest action in the set is relevant - auto itEnd = actions.crend(); - auto it = actions.crbegin(); - while (it != itEnd) + // This is where we take the pulse data we pulled and push it to a UI widget + for (const SEAction* a : actions) { - if (auto typedAction = dynamic_cast(*it)) - { - d->currentValues.pc.Copy(*typedAction); - QString currentText = (typedAction->GetMode() == eMechanicalVentilator_PressureControlMode::AssistedControl) ? - "PC-AC" : "PC-CMV"; - d->modeBox->setCurrentText(currentText); - break; - } - if (auto typedAction = dynamic_cast(*it)) + if (auto mode = dynamic_cast(a)) { - d->currentValues.vc.Copy(*typedAction); - QString currentText = (typedAction->GetMode() == eMechanicalVentilator_VolumeControlMode::AssistedControl) ? - "VC-AC" : "VC-CMV"; - d->modeBox->setCurrentText(currentText); - break; + d->stateMode = mode; + UpdateModeUI(); } - if (auto typedAction = dynamic_cast(*it)) + else if (auto cfg = dynamic_cast(a)) { - d->currentValues.cpap.Copy(*typedAction); - d->modeBox->setCurrentText("CPAP"); - break; + // TODO NO SUPPORT FOR FILE BASED SETTINGS YET + d->stateSettings = const_cast(cfg->GetSettings()); + UpdateSettingsUI(); } - ++it; } + d->hysteresis->PhysiologyUpdateUI(actions); // update plot axis labels { @@ -667,37 +783,97 @@ void QVentilatorWidget::UpdateUI(const std::vector& actions) d->min_2->setText(QString::number(range.first, 'f', 0)); d->max_2->setText(QString::number(range.second, 'f', 0)); } - - d->hysteresis->PhysiologyUpdateUI(actions); } -void QVentilatorWidget::ProcessPhysiology(PhysiologyEngine& pulse) +void QVentilatorWidget::UpdateModeUI() { - // This is called from a thread, you should NOT update UI here - // This is where we pull data from pulse, and push any actions to it + if (!d->stateMode) + return; - d->hysteresis->ProcessPhysiology(pulse); + if (auto typedAction = dynamic_cast(d->stateMode)) + { + if (typedAction->GetMode() == eMechanicalVentilator_PressureControlMode::AssistedControl) + { + d->currentValues.pc_ac.Copy(*typedAction, *d->subMgr); + d->modeBox->setCurrentText("PC-AC");// Triggers SetMode (which updates dial values) + } + else + { + d->currentValues.pc_cmv.Copy(*typedAction, *d->subMgr); + d->modeBox->setCurrentText("PC-CMV");// Triggers SetMode (which updates dial values) + } + } + else if (auto typedAction = dynamic_cast(d->stateMode)) + { + if (typedAction->GetMode() == eMechanicalVentilator_VolumeControlMode::AssistedControl) + { + d->currentValues.vc_ac.Copy(*typedAction, *d->subMgr); + d->modeBox->setCurrentText("VC-AC");// Triggers SetMode (which updates dial values) + } + else + { + d->currentValues.vc_cmv.Copy(*typedAction, *d->subMgr); + d->modeBox->setCurrentText("VC-CMV");// Triggers SetMode (which updates dial values) + } + } + else if (auto typedAction = dynamic_cast(d->stateMode)) + { + d->currentValues.cpap.Copy(*typedAction, *d->subMgr); + d->modeBox->setCurrentText("CPAP");// Triggers SetMode (which updates dial values) + } + d->stateMode = nullptr; +} - auto ventilator = pulse.GetMechanicalVentilator(); +void QVentilatorWidget::UpdateSettingsUI() +{ + std::string mode = d->modeBox->currentText().toStdString(); - d->number_0->setWithoutUpdate(ventilator->GetPeakInspiratoryPressure(PressureUnit::cmH2O)); - d->number_1->setWithoutUpdate(ventilator->GetTidalVolume(VolumeUnit::mL)); - d->number_2->setWithoutUpdate(ventilator->GetMeanAirwayPressure(PressureUnit::cmH2O)); - d->number_3->setWithoutUpdate(ventilator->GetTotalPulmonaryVentilation(VolumePerTimeUnit::L_Per_min)); - d->number_4->setWithoutUpdate(ventilator->GetRespirationRate(FrequencyUnit::Per_min)); - d->number_5->setWithoutUpdate(ventilator->GetEndTidalCarbonDioxidePressure(PressureUnit::mmHg)); - d->number_6->setWithoutUpdate(ventilator->GetStaticRespiratoryCompliance(VolumePerPressureUnit::mL_Per_cmH2O)); - d->number_7->setWithoutUpdate(ventilator->GetInspiratoryExpiratoryRatio()); + if (mode == "NONE") + { + d->EnableDrugs(false); + return; + } - double time_s = pulse.GetSimulationTime(TimeUnit::s); - d->plot_0->append(time_s, ventilator->GetAirwayPressure(PressureUnit::cmH2O)); - d->plot_1->append(time_s, ventilator->GetInspiratoryFlow(VolumePerTimeUnit::L_Per_min)); - d->plot_2->append(time_s, ventilator->GetTotalLungVolume(VolumeUnit::mL)); + // Update Drugs + d->EnableDrugs(true); + if (d->stateSettings->HasConcentrationInspiredAerosol(*d->albuterol)) + { + SEScalarMassPerVolume& c = d->stateSettings->GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration(); + if (c.IsZero()) + { + d->albuterolConcentration->EnableInput(true, false); + } + else + { + d->albuterolConcentration->SetValue(c); + } + } + else + { + d->albuterolConcentration->EnableInput(true, false); + } - d->applyActions(pulse); + if (d->stateSettings->HasFractionInspiredGas(*d->desflurane)) + { + SEScalar0To1& a = d->stateSettings->GetFractionInspiredGas(*d->desflurane).GetFractionAmount(); + if (a.IsZero()) + { + d->desfluraneVolumeFraction->EnableInput(true, false); + } + else + { + d->desfluraneVolumeFraction->SetValue(a); + } + } + else + { + d->desfluraneVolumeFraction->EnableInput(true, false); + } + d->stateSettings = nullptr; } + void QVentilatorWidget::EngineErrorUI() { @@ -705,15 +881,15 @@ void QVentilatorWidget::EngineErrorUI() void QVentilatorWidget::StartEngine() { - d->setUIState(QVentilatorWidget::Private::VentilatorNone); + d->SetUIState(QVentilatorWidget::Private::VentilatorNone); } -void QVentilatorWidget::updateSlope(double value) +void QVentilatorWidget::UpdateSlope(double value) { d->slopeWidget->setMaximumValue(value); } -void QVentilatorWidget::applyAction() +void QVentilatorWidget::ApplyAction() { QString mode = d->modeBox->currentText(); SEScalarTime t; @@ -721,78 +897,76 @@ void QVentilatorWidget::applyAction() if (mode == "NONE") { - disconnectAction(); + DisconnectAction(); return; } else if (mode == "PC-CMV" || mode == "PC-AC") { auto action = std::make_unique(); - action->Copy(d->currentValues.pc); - action->SetConnection(eSwitch::On); if (mode == "PC-AC") { - d->enableTriggers(true); - action->SetMode(eMechanicalVentilator_PressureControlMode::AssistedControl); + d->PullTrigger(d->currentValues.pc_ac.GetInspirationPatientTriggerFlow(), + d->currentValues.pc_ac.GetInspirationPatientTriggerPressure()); + PullSupplementalSettings(d->currentValues.pc_ac.GetSupplementalSettings()); + action->Copy(d->currentValues.pc_ac, *d->subMgr); } else { - d->enableTriggers(false); - action->SetMode(eMechanicalVentilator_PressureControlMode::ContinuousMandatoryVentilation); + PullSupplementalSettings(d->currentValues.pc_cmv.GetSupplementalSettings()); + action->Copy(d->currentValues.pc_cmv, *d->subMgr); } emit(UpdateAction(*action, t)); - d->addAction(std::move(action)); + d->AddAction(std::move(action)); } else if (mode == "VC-CMV" || mode == "VC-AC") { auto action = std::make_unique(); - action->Copy(d->currentValues.vc); - action->SetConnection(eSwitch::On); - // See setMode for dial assignments + + // See SetMode for dial assignments if (mode == "VC-AC") { - d->enableTriggers(true); - action->SetMode(eMechanicalVentilator_VolumeControlMode::AssistedControl); + d->PullTrigger(d->currentValues.vc_ac.GetInspirationPatientTriggerFlow(), + d->currentValues.vc_ac.GetInspirationPatientTriggerPressure()); + PullSupplementalSettings(d->currentValues.vc_ac.GetSupplementalSettings()); + action->Copy(d->currentValues.vc_ac, *d->subMgr); } else { - d->enableTriggers(false); - action->SetMode(eMechanicalVentilator_VolumeControlMode::ContinuousMandatoryVentilation); + PullSupplementalSettings(d->currentValues.vc_cmv.GetSupplementalSettings()); + action->Copy(d->currentValues.vc_cmv, *d->subMgr); } emit(UpdateAction(*action, t)); - - d->addAction(std::move(action)); + d->AddAction(std::move(action)); } else if (mode == "CPAP") { - d->enableTriggers(false); auto action = std::make_unique(); - action->SetConnection(eSwitch::On); - action->Copy(d->currentValues.cpap); + d->PullTrigger(d->currentValues.cpap.GetInspirationPatientTriggerFlow(), + d->currentValues.cpap.GetInspirationPatientTriggerPressure()); + PullSupplementalSettings(d->currentValues.cpap.GetSupplementalSettings()); + action->Copy(d->currentValues.cpap, *d->subMgr); emit(UpdateAction(*action, t)); - - d->addAction(std::move(action)); + d->AddAction(std::move(action)); } else { qWarning() << "Mode " << mode << " not found."; } - - d->setUIState(Private::Connected); - + d->SetUIState(Private::Connected); } -void QVentilatorWidget::disconnectAction() +void QVentilatorWidget::DisconnectAction() { auto action = std::make_unique(); action->GetSettings().SetConnection(eSwitch::Off); SEScalarTime t; t.Invalidate(); emit(UpdateAction(*action, t)); - d->addAction(std::move(action)); + d->AddAction(std::move(action)); - d->setUIState(Private::Disconnected); + d->SetUIState(Private::Disconnected); } -void QVentilatorWidget::addHold() +void QVentilatorWidget::AddHold() { /// If the hold button is enabled /// both of these other buttons are enabled as well, therefore @@ -802,31 +976,32 @@ void QVentilatorWidget::addHold() auto action = std::make_unique(); action->SetState(eSwitch::On); - d->addAction(std::move(action)); + d->AddAction(std::move(action)); } -void QVentilatorWidget::removeHold() +void QVentilatorWidget::RemoveHold() { d->applyButton->setDisabled(false); d->disconnectButton->setDisabled(false); auto action = std::make_unique(); action->SetState(eSwitch::Off); - d->addAction(std::move(action)); + d->AddAction(std::move(action)); + d->stateHold = nullptr; } -void QVentilatorWidget::setMode(QString val) +void QVentilatorWidget::SetMode(QString val) { - d->setMode(val); + d->SetMode(val); } -void QVentilatorWidget::resetDials() +void QVentilatorWidget::ResetDials() { - d->resetDials(); + d->ResetDials(); } -void QVentilatorWidget::setupNumbers() +void QVentilatorWidget::SetupNumbers() { d->number_0->setup("PIP", "cmH20"); d->number_1->setup("VT", "mL"); @@ -838,93 +1013,75 @@ void QVentilatorWidget::setupNumbers() d->number_7->setup("I:E", "", 1, true); } -void QVentilatorWidget::lockForHold() +void QVentilatorWidget::LockForHold() { d->applyButton->setDisabled(true); } -void QVentilatorWidget::unlock() +void QVentilatorWidget::Unlock() { d->applyButton->setDisabled(false); } -void QVentilatorWidget::enableFlowTrigger() +void QVentilatorWidget::EnableFlowTrigger() { - d->inspirationPatientTriggerFlow->EnableInput(true); - d->inspirationPatientTriggerPressure->EnableInput(false); - d->modelRadio->setChecked(false); - d->modelTriggerValue->setEnabled(false); - d->modelTriggerValue->setText("Off"); + d->EnableFlowTrigger(); } -void QVentilatorWidget::enablePressureTrigger() +void QVentilatorWidget::EnablePressureTrigger() { - d->inspirationPatientTriggerFlow->EnableInput(false); - d->inspirationPatientTriggerPressure->EnableInput(true); - d->modelRadio->setChecked(false); - d->modelTriggerValue->setEnabled(false); - d->modelTriggerValue->setText("Off"); + d->EnablePressureTrigger(); } -void QVentilatorWidget::enableModelTrigger() +void QVentilatorWidget::EnableModelTrigger() { - d->inspirationPatientTriggerFlow->EnableInput(false); - d->inspirationPatientTriggerPressure->EnableInput(false); - d->modelRadio->setChecked(true); - d->modelTriggerValue->setEnabled(true); - d->modelTriggerValue->setText("On"); + d->EnableModelTrigger(); } -void QVentilatorWidget::applyTriggers() +void QVentilatorWidget::ApplyTriggers() { - auto action = std::make_unique(); - action->SetMergeType(eMergeType::Append); - - if (d->inspirationPatientTriggerFlow->IsChecked() && !d->inspirationPatientTriggerFlow->IsZero()) - { - d->inspirationPatientTriggerFlow->GetValue( - action->GetSettings().GetInspirationPatientTriggerFlow()); - } + ApplyAction(); +} - else if (d->inspirationPatientTriggerPressure->IsChecked() && !d->inspirationPatientTriggerPressure->IsZero()) - d->inspirationPatientTriggerPressure->GetValue( - action->GetSettings().GetInspirationPatientTriggerPressure()); - else - { - enableModelTrigger(); - action->GetSettings().SetInspirationPatientTriggerRespiratoryModel(eSwitch::On); - } - SEScalarTime t; - t.Invalidate(); - emit(UpdateAction(*action, t)); - d->addAction(std::move(action)); +void QVentilatorWidget::ApplyDrugs() +{ + ApplyAction(); } -void QVentilatorWidget::applyDrugs() +void QVentilatorWidget::PullSupplementalSettings(SEMechanicalVentilatorSettings& settings) { - auto action = std::make_unique(); - action->SetMergeType(eMergeType::Append); + settings.Clear(); + // Pull from Drugs Tab if (d->albuterolConcentration->IsChecked()) { d->albuterolConcentration->GetValue( - action->GetSettings().GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration() + settings.GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration() ); + if (!settings.GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration().IsValid()) + settings.GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration().SetValue(0, MassPerVolumeUnit::g_Per_L); + if (settings.GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration().IsZero()) + { + d->albuterolConcentration->EnableInput(true, false); + } } else { - action->GetSettings().GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration().SetValue(0, MassPerVolumeUnit::g_Per_L); + settings.GetConcentrationInspiredAerosol(*d->albuterol).GetConcentration().SetValue(0, MassPerVolumeUnit::g_Per_L); } + if (d->desfluraneVolumeFraction->IsChecked()) { d->desfluraneVolumeFraction->GetValue( - action->GetSettings().GetFractionInspiredGas(*d->desflurane).GetFractionAmount() + settings.GetFractionInspiredGas(*d->desflurane).GetFractionAmount() ); + if (!settings.GetFractionInspiredGas(*d->desflurane).GetFractionAmount().IsValid()) + settings.GetFractionInspiredGas(*d->desflurane).GetFractionAmount().SetValue(0); + if (settings.GetFractionInspiredGas(*d->desflurane).GetFractionAmount().IsZero()) + { + d->desfluraneVolumeFraction->EnableInput(true, false); + } } else { - action->GetSettings().GetFractionInspiredGas(*d->desflurane).GetFractionAmount().SetValue(0); + settings.GetFractionInspiredGas(*d->desflurane).GetFractionAmount().SetValue(0); } - SEScalarTime t; - t.Invalidate(); - emit(UpdateAction(*action, t)); - d->addAction(std::move(action)); } diff --git a/src/controls/VentilatorWidget.h b/src/controls/VentilatorWidget.h index a86649f..ca63c20 100644 --- a/src/controls/VentilatorWidget.h +++ b/src/controls/VentilatorWidget.h @@ -4,6 +4,7 @@ #include #include "QPulse.h" +class SEMechanicalVentilatorSettings; namespace Ui { class VentilatorWidget; @@ -34,39 +35,40 @@ signals: protected slots: /// Used to update the slope widget with a new range - void updateSlope(double value); + void UpdateSlope(double value); /// On apply take the current mode and input parameters and /// apply an action to pulse - void applyAction(); + void ApplyAction(); /// Disconnect the ventilator - void disconnectAction(); + void DisconnectAction(); ///@{ /// Handle holds - void addHold(); - void removeHold(); + void AddHold(); + void RemoveHold(); ///@} - void setMode(QString val); - void resetDials(); + void SetMode(QString val); + void ResetDials(); - void enableFlowTrigger(); - void enablePressureTrigger(); - void enableModelTrigger(); - void applyTriggers(); - - void applyDrugs(); + void EnableFlowTrigger(); + void EnablePressureTrigger(); + void EnableModelTrigger(); + void ApplyTriggers(); + void ApplyDrugs(); protected: - void setupNumbers(); - void UpdateUI(const std::vector& actions); + void SetupNumbers(); + void UpdateModeUI(); + void UpdateSettingsUI(); + void PullSupplementalSettings(SEMechanicalVentilatorSettings& ss); ///@{ /// When hold is clicked, the UI should be locked for input - void lockForHold(); - void unlock(); + void LockForHold(); + void Unlock(); private: struct Private; diff --git a/src/controls/actions/MechanicalVentilatorContinuousPositiveAirwayPressureWidget.cxx b/src/controls/actions/MechanicalVentilatorContinuousPositiveAirwayPressureWidget.cxx index 517c04c..e3e339e 100644 --- a/src/controls/actions/MechanicalVentilatorContinuousPositiveAirwayPressureWidget.cxx +++ b/src/controls/actions/MechanicalVentilatorContinuousPositiveAirwayPressureWidget.cxx @@ -114,7 +114,7 @@ void QMechanicalVentilatorContinuousPositiveAirwayPressureWidget::ActionToContro const SEMechanicalVentilatorContinuousPositiveAirwayPressure& action) { QActionWidget::ActionToControls(action); - m_Controls->Action.Copy(action); + m_Controls->Action.Copy(action, m_Controls->Pulse.GetScenario().GetSubstanceManager()); m_Controls->State->SetCurrentIndex((action.GetConnection() == eSwitch::On) ? 0 : 1); m_Controls->FractionInspiredOxygen->SetValue(m_Controls->Action.GetFractionInspiredOxygen()); m_Controls->DeltaPressureSupport->SetValue(m_Controls->Action.GetDeltaPressureSupport()); diff --git a/src/controls/actions/MechanicalVentilatorPressureControlWidget.cxx b/src/controls/actions/MechanicalVentilatorPressureControlWidget.cxx index 5b274f5..621215c 100644 --- a/src/controls/actions/MechanicalVentilatorPressureControlWidget.cxx +++ b/src/controls/actions/MechanicalVentilatorPressureControlWidget.cxx @@ -135,7 +135,7 @@ void QMechanicalVentilatorPressureControlWidget::ControlsToAction() void QMechanicalVentilatorPressureControlWidget::ActionToControls(const SEMechanicalVentilatorPressureControl& action) { QActionWidget::ActionToControls(action); - m_Controls->Action.Copy(action); + m_Controls->Action.Copy(action, m_Controls->Pulse.GetScenario().GetSubstanceManager()); m_Controls->State->SetCurrentIndex((action.GetConnection() == eSwitch::On) ? 0 : 1); m_Controls->Mode->SetCurrentIndex((action.GetMode() == eMechanicalVentilator_PressureControlMode::AssistedControl) ? 0 : 1); m_Controls->FractionInspiredOxygen->SetValue(m_Controls->Action.GetFractionInspiredOxygen()); diff --git a/src/controls/actions/MechanicalVentilatorVolumeControlWidget.cxx b/src/controls/actions/MechanicalVentilatorVolumeControlWidget.cxx index 4b838fd..f1b16b7 100644 --- a/src/controls/actions/MechanicalVentilatorVolumeControlWidget.cxx +++ b/src/controls/actions/MechanicalVentilatorVolumeControlWidget.cxx @@ -125,7 +125,7 @@ void QMechanicalVentilatorVolumeControlWidget::ControlsToAction() void QMechanicalVentilatorVolumeControlWidget::ActionToControls(const SEMechanicalVentilatorVolumeControl& action) { QActionWidget::ActionToControls(action); - m_Controls->Action.Copy(action); + m_Controls->Action.Copy(action, m_Controls->Pulse.GetScenario().GetSubstanceManager()); m_Controls->State->SetCurrentIndex((action.GetConnection() == eSwitch::On) ? 0 : 1); m_Controls->FractionInspiredOxygen->SetValue(m_Controls->Action.GetFractionInspiredOxygen()); m_Controls->TidalVolume->SetValue(m_Controls->Action.GetTidalVolume()); -- GitLab From 06371992157b7f85255be4c4be59ae6296de7904 Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Fri, 24 Jan 2025 09:10:01 -0500 Subject: [PATCH 11/11] Sync with Pulse 4.3.1 --- cmake/external/External_Pulse.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/external/External_Pulse.cmake b/cmake/external/External_Pulse.cmake index f9b15ab..934dd67 100644 --- a/cmake/external/External_Pulse.cmake +++ b/cmake/external/External_Pulse.cmake @@ -5,7 +5,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/AddExternalProject.cmake) define_external_dirs_ex(Pulse) add_external_project_ex(Pulse GIT_REPOSITORY https://gitlab.kitware.com/physiology/engine.git - GIT_TAG REL_4_2_0 + GIT_TAG REL_4_3_1 CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX} -DPulse_DEPENDENT_BUILD:BOOL=ON -- GitLab