├── .clang-format ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .gitmodules ├── .vscode ├── c_cpp_properties.json └── settings.json ├── CMakeLists.txt ├── README.md ├── bg-ui.sublime-project ├── cmake ├── BioGearsUIConfig.cmake.in ├── cmake-commonConfig.cmake.in ├── cmake-common_logic.cmake ├── common │ ├── FindLog4cpp.cmake │ ├── FindProtobuf.cmake │ └── FindTbb.cmake ├── packaging │ ├── BioGearsLogo.bmp │ ├── BioGearsLogo.png │ ├── CMakeLists.txt │ ├── COPYRIGHT.txt │ ├── LICENSE.txt │ ├── README.txt │ ├── WIX_UI_BANNER.bmp │ ├── WIX_UI_BANNER.png │ ├── WIX_UI_DIALOG.bmp │ ├── WIX_UI_DIALOG.png │ ├── biogearslogo_XoQ_icon.ico │ └── biogearslogo_kvO_icon.ico └── toolchains │ └── linux-gcc9-amd64 ├── projects ├── CMakeLists.txt └── ui │ ├── BioGearsUI.ico │ ├── BioGearsUI.rc │ ├── CMakeLists.txt │ ├── cpp │ ├── biogears │ │ ├── BioGearsData.cpp │ │ ├── BioGearsData.h │ │ ├── BloodPanel.h │ │ ├── EventTree.cpp │ │ ├── EventTree.h │ │ ├── Gadgets.h │ │ ├── Logger.cpp │ │ ├── Logger.h │ │ ├── Models │ │ │ ├── DataRequestNode.cpp │ │ │ ├── DataRequestNode.h │ │ │ ├── DataRequestTree.cpp │ │ │ ├── DataRequestTree.h │ │ │ ├── PhysiologyRequest.cpp │ │ │ └── PhysiologyRequest.h │ │ ├── PatientConditions.h │ │ ├── PatientMetrics.h │ │ ├── PatientState.h │ │ ├── Scenario.cpp │ │ ├── Scenario.h │ │ ├── Urinalysis.cpp │ │ └── Urinalysis.h │ ├── main.cpp │ ├── version.cpp.in │ └── version.h │ ├── lua │ └── main.lua │ └── qml │ ├── ActionDrawer.qml │ ├── ActionDrawerForm.ui.qml │ ├── Controls.qml │ ├── ControlsForm.ui.qml │ ├── CustomPlots.qml │ ├── CustomPlotsForm.ui.qml │ ├── GraphArea.qml │ ├── GraphAreaForm.ui.qml │ ├── LuaConsole.qml │ ├── LuaConsoleForm.ui.qml │ ├── Main.qml │ ├── MainForm.ui.qml │ ├── MenuArea.qml │ ├── MenuAreaForm.ui.qml │ ├── PatientMenu.qml │ ├── PatientMenuForm.ui.qml │ ├── WizardDialog.qml │ ├── WizardDialogForm.ui.qml │ ├── actions │ ├── ActionModel.qml │ ├── UIActionForm.ui.qml │ ├── UIAcuteRespiratoryDistress.qml │ ├── UIAcuteStress.qml │ ├── UIAirwayObstruction.qml │ ├── UIAnesthesiaMachine.qml │ ├── UIApnea.qml │ ├── UIAsthmaAttack.qml │ ├── UIBronchoconstriction.qml │ ├── UIBurnWound.qml │ ├── UICardiacArrest.qml │ ├── UICompoundInfusion.qml │ ├── UIConsumeMeal.qml │ ├── UIDrugAdministration.qml │ ├── UIExercise.qml │ ├── UIHemorrhage.qml │ ├── UIInfection.qml │ ├── UIInhaler.qml │ ├── UINeedleDecompression.qml │ ├── UIPainStimulus.qml │ ├── UIPatientAssessment.qml │ ├── UISerialize.qml │ ├── UITensionPneumothorax.qml │ ├── UITourniquet.qml │ ├── UITransfusion.qml │ ├── UITraumaticBrainInjury.qml │ └── UIUpdateEnvironment.qml │ ├── dashboards │ ├── EnergyPanel.qml │ ├── RenalPanel.qml │ └── VitalsPanel.qml │ ├── elements │ ├── UIActionDialog.qml │ ├── UIActionDialogForm.ui.qml │ ├── UIActionSwitch.qml │ ├── UIActionSwitchForm.qml │ ├── UIBioGearsButtonForm.ui.qml │ ├── UIComboBox.qml │ ├── UIComboBoxForm.ui.qml │ ├── UICompoundWizard.qml │ ├── UICompoundWizardForm.ui.qml │ ├── UIControlPhysiology.ui.qml │ ├── UIDataRequest.qml │ ├── UIDataRequestForm.ui.qml │ ├── UIEnvironmentWizard.qml │ ├── UIEnvironmentWizardForm.ui.qml │ ├── UINutritionWizard.qml │ ├── UINutritionWizardForm.ui.qml │ ├── UIPatientWizard.qml │ ├── UIPatientWizardForm.ui.qml │ ├── UIPlaybackForm.ui.qml │ ├── UIPlotSeries.qml │ ├── UIPlotSeriesForm.ui.qml │ ├── UIRadioButton.qml │ ├── UIRadioButtonForm.ui.qml │ ├── UIScalarForm.ui.qml │ ├── UIScenarioBuilder.qml │ ├── UIScenarioBuilderForm.ui.qml │ ├── UIScenarioTimelineForm.ui.qml │ ├── UISpinBox.qml │ ├── UISpinBoxForm.ui.qml │ ├── UISubstanceEntry.qml │ ├── UISubstanceEntryForm.ui.qml │ ├── UISubstanceWizard.qml │ ├── UISubstanceWizardForm.ui.qml │ ├── UITabButtonForm.ui.qml │ ├── UITextField.qml │ ├── UITextFieldForm.ui.qml │ ├── UITextInputForm.ui.qml │ ├── UIUnitScalarEntry.qml │ └── UIUnitScalarEntryForm.ui.qml │ ├── img │ ├── DownArrow.png │ ├── HospitalRoom.jpg │ ├── PlotsSelectionIcon.png │ ├── UpArrow.png │ ├── add.png │ ├── add_plain.png │ ├── administer_icon.png │ ├── backwards.png │ ├── biogears_logo_400_400.ico │ ├── biogears_logo_400_400.png │ ├── biogears_noBackground.png │ ├── burn.svg │ ├── clock-2X.png │ ├── clock-max.png │ ├── clock-realtime(white_background).png │ ├── clock-realtime.png │ ├── collapsedOption.png │ ├── comboIndicatorWhite.png │ ├── exercise_icon.png │ ├── expandedOption.png │ ├── foward.png │ ├── icon-round-question_mark.svg │ ├── insult_icon.png │ ├── menu.png │ ├── menu.svg │ ├── menu_transparent.png │ ├── next.png │ ├── next.svg │ ├── next1.png │ ├── next_transparent.png │ ├── nursing.svg │ ├── openIndicatorBlue.png │ ├── openIndicatorWhite.png │ ├── patient.svg │ ├── pause(white_background).png │ ├── pause.png │ ├── play(white_background).png │ ├── play.png │ ├── play.svg │ ├── playback.png │ ├── prev.png │ ├── prev.svg │ ├── prev1.png │ ├── prev_transparent.png │ ├── question.png │ ├── remove.png │ ├── renalPanelNephron.png │ ├── renalPanelNephronWhite.png │ ├── reset.png │ ├── reverse.png │ ├── reverse.svg │ ├── speedup.svg │ └── stop.png │ ├── qtquickcontrols2.conf │ └── visualizer.qrc ├── visualizer.DotSettings └── visualizer.code-workspace /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: WebKit 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: DontAlign 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: false 10 | AlignTrailingComments: false 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: false 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: true 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | BeforeCatch: false 33 | BeforeElse: false 34 | IndentBraces: false 35 | SplitEmptyFunction: true 36 | SplitEmptyRecord: true 37 | SplitEmptyNamespace: true 38 | BreakBeforeBinaryOperators: All 39 | BreakBeforeBraces: WebKit 40 | BreakBeforeInheritanceComma: false 41 | BreakBeforeTernaryOperators: true 42 | BreakConstructorInitializersBeforeComma: false 43 | BreakConstructorInitializers: BeforeComma 44 | BreakAfterJavaFieldAnnotations: false 45 | BreakStringLiterals: true 46 | ColumnLimit: 0 47 | CommentPragmas: '^ IWYU pragma:' 48 | CompactNamespaces: false 49 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 50 | ConstructorInitializerIndentWidth: 2 51 | ContinuationIndentWidth: 2 52 | Cpp11BracedListStyle: false 53 | DerivePointerAlignment: false 54 | DisableFormat: false 55 | ExperimentalAutoDetectBinPacking: false 56 | FixNamespaceComments: false 57 | ForEachMacros: 58 | - foreach 59 | - Q_FOREACH 60 | - BOOST_FOREACH 61 | IncludeCategories: 62 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 63 | Priority: 2 64 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 65 | Priority: 3 66 | - Regex: '.*' 67 | Priority: 1 68 | IncludeIsMainRegex: '(Test)?$' 69 | IndentCaseLabels: false 70 | IndentWidth: 2 71 | IndentWrappedFunctionNames: false 72 | JavaScriptQuotes: Leave 73 | JavaScriptWrapImports: true 74 | KeepEmptyLinesAtTheStartOfBlocks: true 75 | MacroBlockBegin: '' 76 | MacroBlockEnd: '' 77 | MaxEmptyLinesToKeep: 1 78 | NamespaceIndentation: Inner 79 | ObjCBlockIndentWidth: 2 80 | ObjCSpaceAfterProperty: true 81 | ObjCSpaceBeforeProtocolList: true 82 | PenaltyBreakAssignment: 2 83 | PenaltyBreakBeforeFirstCallParameter: 19 84 | PenaltyBreakComment: 300 85 | PenaltyBreakFirstLessLess: 120 86 | PenaltyBreakString: 1000 87 | PenaltyExcessCharacter: 1000000 88 | PenaltyReturnTypeOnItsOwnLine: 60 89 | PointerAlignment: Left 90 | ReflowComments: true 91 | SortIncludes: true 92 | SortUsingDeclarations: true 93 | SpaceAfterCStyleCast: false 94 | SpaceAfterTemplateKeyword: true 95 | SpaceBeforeAssignmentOperators: true 96 | SpaceBeforeParens: ControlStatements 97 | SpaceInEmptyParentheses: false 98 | SpacesBeforeTrailingComments: 1 99 | SpacesInAngles: false 100 | SpacesInContainerLiterals: true 101 | SpacesInCStyleCastParentheses: false 102 | SpacesInParentheses: false 103 | SpacesInSquareBrackets: false 104 | Standard: Cpp11 105 | TabWidth: 2 106 | UseTab: Never 107 | ... 108 | 109 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | 4 | [*.py] 5 | indent_style = space 6 | indent_size = 2 7 | 8 | [*.java] 9 | indent_style = space 10 | indent_size = 2 11 | 12 | [*.cpp] 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.qml] 17 | indent_style = space 18 | indent_size = 2 19 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | #*.pdf filter=lfs diff=lfs merge=lfs -text 2 | #*.xlsx filter=lfs diff=lfs merge=lfs -text 3 | #*.xls filter=lfs diff=lfs merge=lfs -text 4 | #*.docx filter=lfs diff=lfs merge=lfs -text 5 | #*.doc filter=lfs diff=lfs merge=lfs -text 6 | #*.png filter=lfs diff=lfs merge=lfs -text 7 | #*.jpg filter=lfs diff=lfs merge=lfs -text 8 | #*.bmp filter=lfs diff=lfs merge=lfs -text 9 | #*.tiff filter=lfs diff=lfs merge=lfs -text 10 | #*.svg filter=lfs diff=lfs merge=lfs -text 11 | #*.pptx filter=lfs diff=lfs merge=lfs -text 12 | #*.ppt filter=lfs diff=lfs merge=lfs -text 13 | #*.dsn filter=lfs diff=lfs merge=lfs -text 14 | #*.jar filter=lfs diff=lfs merge=lfs -text 15 | 16 | # Set the default behavior, in case people don't have core.autocrlf set. 17 | * text=auto eol=lf 18 | 19 | 20 | # Normalize line endings. 21 | 22 | *.c text eol=lf 23 | *.h text eol=lf 24 | *.xsd text eol=lf 25 | *.txt text eol=lf 26 | *.xml text eol=lf 27 | *.cmake text eol=lf 28 | # Declare files that will always have CRLF line endings on checkout. 29 | *.sln text eol=lf 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build-*/ 2 | build*/ 3 | worktrees/ 4 | 5 | #Sublime 6 | *.sublime-workspace 7 | *.swp 8 | *.autosave 9 | ~* 10 | CMakeLists.txt.user 11 | 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libbiogears"] 2 | path = extern/biogears 3 | url = https://github.com/BioGearsEngine/core.git 4 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "D:/remotes/sed-stash/biogears/external/windows-vc16-amd64/include/", 8 | "C:/Qt/5.12.2/msvc2017_64/include/**", 9 | "${workspaceFolder}/extern/biogears/projects/biogears/libBiogears/include", 10 | "${workspaceFolder}/extern/biogears/projects/biogears/libCDM/include", 11 | "${workspaceFolder}/extern/biogears/projects/biogears/libCircuitTest/include", 12 | "${workspaceFolder}/extern/biogears/projects/biogears-common/include", 13 | "${workspaceFolder}/build-msvc16/projects/libbiogears/projects/biogears" 14 | ], 15 | "defines": [ 16 | "_DEBUG", 17 | "UNICODE", 18 | "_UNICODE" 19 | ], 20 | "windowsSdkVersion": "10.0.18362.0", 21 | "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.23.28105/bin/Hostx64/x64/cl.exe", 22 | "cStandard": "c11", 23 | "cppStandard": "c++17", 24 | "intelliSenseMode": "msvc-x64" 25 | } 26 | ], 27 | "version": 4 28 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "**/.svn": true, 5 | "**/.hg": true, 6 | "**/CVS": true, 7 | "**/.DS_Store": true, 8 | "build-*" : true 9 | 10 | } 11 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # CMAKE DEFINITIONS AND setTINGS 3 | # 4 | # Requires the following environmental variables: 5 | # 6 | # BUILD TYPE ENV VARIABLE Description 7 | # ANDROID ANDROID_NDK Android NDK root folder location 8 | # (also required for toolchain file) 9 | # ANDROID GRADLE_EXECUTABLE Location of the Gradle executable 10 | ############################################################################### 11 | set(ROOT_PROJECT_NAME BiogearsUI) 12 | set(${ROOT_PROJECT_NAME}_CMAKE_MIN_VERSION 3.11.0) 13 | set(${ROOT_PROJECT_NAME}_CMAKE_POLICY 3.11.0) 14 | 15 | cmake_minimum_required(VERSION ${${ROOT_PROJECT_NAME}_CMAKE_MIN_VERSION}) 16 | 17 | set(${ROOT_PROJECT_NAME}_VERSION_MAJOR 0) 18 | set(${ROOT_PROJECT_NAME}_VERSION_MINOR 1) 19 | set(${ROOT_PROJECT_NAME}_VERSION_PATCH 0) 20 | set(${ROOT_PROJECT_NAME}_VERSION_TAG "-beta") 21 | 22 | include(cmake/cmake-common_logic.cmake) 23 | ################################################################################ 24 | # STEP 1: 25 | # Change this to custimize your project 26 | ################################################################################ 27 | project( ${ROOT_PROJECT_NAME} LANGUAGES CXX C) 28 | generate_project_suffix() 29 | 30 | 31 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ${PROJECT_SOURCE_DIR}/cmake/common) 32 | list(APPEND CMAKE_PREFIX_PATH ) 33 | list(APPEND CMAKE_LIBRARY_PATH ) 34 | list(APPEND CMAKE_INCLUDE_PATH ) 35 | list(APPEND CMAKE_FIND_ROOT_PATH ${PROJECT_SOURCE_DIR}/cmake/common) 36 | 37 | message(STATUS " 38 | Using the following search paths 39 | CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH} 40 | CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH} 41 | CMAKE_LIBRARY_PATH = ${CMAKE_LIBRARY_PATH} 42 | CMAKE_INCLUDE_PATH = ${CMAKE_INCLUDE_PATH} 43 | CMAKE_FIND_ROOT_PATH = ${CMAKE_FIND_ROOT_PATH} 44 | ") 45 | 46 | find_package(Git) 47 | if(Git_FOUND) 48 | configure_version_information(GIT_SUCESS) 49 | endif() 50 | if(NOT GIT_SUCESS) 51 | # Update these variables to ensure out of source build have some sane tags 52 | message(WARNING "GIT_EXECUTABLE was not found or no corrisponding GIT_REPO is avaliable.\n" 53 | "If you are building with in a git repo you should ensure GIT is in your current path. " 54 | "If you are building outside of a repo ignore this message.") 55 | set(${ROOT_PROJECT_NAME}_VERSION_MAJOR 0) 56 | set(${ROOT_PROJECT_NAME}_VERSION_MINOR 0) 57 | set(${ROOT_PROJECT_NAME}_VERSION_PATCH 2) 58 | set(${ROOT_PROJECT_NAME}_VERSION_TWEAK 0) 59 | set(${ROOT_PROJECT_NAME}_LIB_VERSION ${${ROOT_PROJECT_NAME}_VERSION_MAJOR}.${${ROOT_PROJECT_NAME}_VERSION_MINOR} ) 60 | set(${ROOT_PROJECT_NAME}_VERSION_TAG "Beta") 61 | set(${ROOT_PROJECT_NAME}_DIRTY_BUILD true) 62 | 63 | string(TIMESTAMP ${ROOT_PROJECT_NAME}_COMMIT_DATE "%Y-%m-%d %H:%M") 64 | endif() 65 | ############################# ################################################## 66 | # Add Repository Subdirectories 67 | ############################################################################### 68 | add_subdirectory(projects) 69 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT BioGearsUI) 70 | ############################################################################### 71 | # Step 2: 72 | # You likely need to add on project to stage for every executable you would like 73 | # to stage (AKA move dep DLLs to the run folder for debugging. 74 | ################################################################################ 75 | if(${ROOT_PROJECT_NAME}_BUILD_${ROOT_PROJECT_NAME}) 76 | add_dependencies(STAGE ${ROOT_PROJECT_NAME}) 77 | endif() 78 | 79 | ############################################################################### 80 | # Step 3: 81 | # Infrastructure Installation for each library 82 | # your project outputs create a Find${lib}.cmake file 83 | # list them here. This will install them in your sysroot 84 | # so other projects can build off those libraries 85 | ############################################################################### 86 | if( PROJECT_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) 87 | message(STATUS "Preparing Installer Packages") 88 | add_subdirectory(cmake/packaging) 89 | endif() 90 | 91 | generate_project_suffix() 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tage Overview 2 | 3 | ## BioGears Simulation UI 4 | BioGears® simulation UI source code is hosted here. Our latest deployment is still in a beta phase, and is intended to be an intermediate release to showcase the capabilities of the BioGears® simulation UI. This version of the software is meant to elicit feedback and enhance community involvement in establishing end product expectations. 5 | 6 | 7 | Build Status 8 | ----------------- 9 | | Platform | Compiler | Architecture | Status | 10 | |----------|----------|--------------|--------| 11 | | Windows | msvc15 | amd64 | ![Windows msvc15 Build Status](https://biogearsengine.com/content/badges/nightly_biogears-ui_windows_msvc15.png) | 12 | | Windows | msvc16 | amd64 | ![Windows msvc16 Build Status](https://biogearsengine.com/content/badges/nightly_biogears-ui_windows_msvc16.png) | 13 | | Linux | gcc9 | amd64 | ![Linux-gcc9-amd64 Build Status](https://biogearsengine.com/content/badges/nightly_biogears-ui_linux_gcc9-amd64.png) | 14 | | MacOS Yosemite | clang10 | amd64 | ![MacOS Yosemite clang11 Build Status](https://biogearsengine.com/content/badges/nightly_biogears-ui_macos-yosemite.png) | 15 | | MacOS Catalina| clang11 | amd64 | ![MacOS Catalina clang11 Build Status](https://biogearsengine.com/content/badges/nightly_biogears-ui_macos-catalina.png) | 16 | 17 | ## Objectives 18 | 19 | * To allow users to visually compose and execute BioGears® simulation scenarios 20 | * To allow users to visualize BioGears® scenario actions and outputs in an intuitive timeline format 21 | 22 | # Building from Source 23 | 24 | BioGears® simulation UI requires the following dependencies: 25 | * BioGears Physiology Engine - build requirements can be found [here](https://github.com/BioGearsEngine/core/wiki). 26 | * Boost - build requirements can be found [here](https://www.boost.org/doc/libs/1_68_0/more/getting_started/index.html). 27 | * QT 5 - build requirements can be found [here](https://wiki.qt.io/Building_Qt_5_from_Git). 28 | 29 | ## Building the Visualizer with the CMake CLI 30 | 31 | A submodule for BioGears is located in projects/libbiogears. It can be initialized using the git submodule commands from the root level. 32 | 33 | `git submodule init projects/libbiogears` 34 | `git submodule update` 35 | 36 | BioGears should then be built either inside the submodule or at the root level in its own build folder for example 37 | 38 | ``` 39 | mkdir build-biogears 40 | cd build-biogears 41 | cmake ../projectslibbiogears -DCMAKE_INSTALL_PREFIX=${PWD}../build-gui/usr 42 | cmake --build . -config Release -target install 43 | ``` 44 | 45 | If you are going to build BioGears only once it is fine to place BioGears inside the same folder structure as its deps, but if you are planning on building BioGears multiple times and testing the different versions of BioGears against the GUI then the example above places the BioGears libraries in its own external tree so that the build system for biogears will never see the headers for a previously installed version. 46 | 47 | You can follow the instructions for building biogears from its github page for more information, just remember to account of the unique structure layout 48 | 49 | ## Building the Visualizer with the CMake GUI 50 | 51 | ``` 52 | #Pulling Code 53 | git clone https://github.com/BioGearsEngine/ui.git visualizer 54 | cd visualizer 55 | git submodule init 56 | git submodule update --progress 57 | 58 | 59 | #Building the Visualizer code against biogears 60 | cd .. 61 | mkdir build-ui 62 | cd build-ui 63 | cmake .. -G Ninja -DCMAKE_PREFIX_PATH="/opt/biogears/external/" 64 | cmake -DCMAKE_BUILD_TYPE=Release . 65 | cmake --build . --config Release --target install 66 | cmake --build . --config Release --target gather_runtime_dependencies 67 | ``` 68 | 69 | Further instructions can be found in our WIKI at our github page 70 | # Running the Visualizer 71 | 72 | ## Initial Setup 73 | Once open in Microsoft Visual Studios (MVS), right-click on BioGearsUI on the lefthand side of the screen in the Solution Explorer. Switch the configuration in the top left corner of the property page to be "All Configurations." On the left hand side of the screen, navigate to Configuration Properties→Debugging, and fill in the Environment box with the QT Path: 74 | 75 | * QT_PLUGIN_PATH=D:\remotes\sed-stash\biogears\external\windows-vc15-amd64\plugins 76 | 77 | **Note**: The above path is an example. Be sure to switch the path to your specific plugin folder of the windows build based on your folder configuration. 78 | 79 | Specify the configuration (release or debug) you wish to build in at the top of the MVS screen. Click the F7 key or navigate to the Build→Build Solution tab at the top of the screen. Make sure the build is successful. Then, navigate in the solution explorer to CMakePredefinedTargets→gather_runtime_dependencies, right-clock on stage, and select build. Make sure this build is also successful. 80 | 81 | Click F5 or click the play button to run the solution. The viualizer/UI should pop up and prompt you with further directions. 82 | 83 | **Note**: For full details, visit our wiki [here]( https://github.com/BioGearsEngine/ui/wiki/Running-the-Visualizer). 84 | 85 | ## QT Creator Support 86 | QT Creator supports CMake project imports. The following is a short guide on how to setup a project with QT Creator 87 | 88 | # Additional Information 89 | 90 | 91 | ##Code of Conduct 92 | 93 | We support the [contributor covenant](https://github.com/BioGearsEngine/Engine/blob/master/CODE_OF_CONDUCT.md) and the scope and enforcement it details. We reserve the right of enforcement that we feel is appropriate given the nature of the offense up to and including a permanent ban from the project. 94 | 95 | ##Contributing 96 | 97 | Details will be filled in shortly. In the meantime if you have a contribution or issue to post/push feel free to contact biogears@ara.com with the details. 98 | 99 | ##Additional Documentation 100 | 101 | For more detailed documentation including model discussions and implementation details can be found at www.BioGearsEngine.com 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /bg-ui.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": 3 | [ 4 | { 5 | "path": "projects/ui" 6 | }, 7 | { 8 | "path": "projects/biogears-common" 9 | }, 10 | { 11 | "path": "cmake" 12 | }, 13 | { 14 | "path": "share" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /cmake/BioGearsUIConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include(CMakeFindDependencyMacro) 4 | 5 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) 6 | set(Biogears_XSD_SCHEMA_DIR ${PACKAGE_PREFIX_DIR}/share/biogears/xsd/ CACHE PATH "Directory containing all of the CDM XSD Schema files") 7 | file(GLOB_RECURSE Biogears_XSD_SCHEMA_LIST ${PACKAGE_PREFIX_DIR}/share/biogears/xsd/*.xsd "Exsact list of XSD files for the current Biogears Release") 8 | set(Biogears_XML_DATA_DIR ${PACKAGE_PREFIX_DIR}/share/biogears/data CACHE PATH "Directory containing all of the data files Biogears needs to run") 9 | file(GLOB_RECURSE Biogears_XSD_DATA_LIST ${PACKAGE_PREFIX_DIR}/share/biogears/data/*.xml "Exsact list of XML files for the current Biogears Release") 10 | 11 | include ( "${CMAKE_CURRENT_LIST_DIR}/@ROOT_PROJECT_NAME@.cmake" ) 12 | 13 | find_dependency(Eigen3) 14 | find_dependency(Log4cpp) 15 | find_dependency(CodeSynthesis) 16 | 17 | # 18 | # Function Stage_BioGears_Schema 19 | # Param: DESTINATION - Directory to stage the contents of Biogears_XSD_SCHEMA_DIR 20 | # Param: RESULTS_VAR - Variable to store the results in 21 | # 22 | # Places the value of Biogears_XSD_SCHEMA_LIST in to DIR 23 | # Each file will become its on custom_target and will be staged before by runtime 24 | function(stage_biogears_schema ) 25 | cmake_parse_arguments(_ 26 | "" 27 | "DESTINATION;RESULTS_VAR" 28 | "" ${ARGN}) 29 | if(NOT __DESTINATION) 30 | message(FATAL_ERROR "DESTINATION required but not given") 31 | endif() 32 | if(NOT __RESULTS_VAR) 33 | set(__RESULTS_VAR _stage_biogears_schema_results) 34 | endif() 35 | foreach( file IN LISTS Biogears_XSD_SCHEMA_LIST ) 36 | string(REPLACE "${Biogears_XSD_SCHEMA_DIR}" "${__DESTINATION}/xsd" destination_file "${file}" ) 37 | list(APPEND ${__RESULTS_VAR} ${destination_file} ) 38 | add_custom_command( 39 | OUTPUT ${destination_file} 40 | DEPENDS ${file} 41 | COMMAND ${CMAKE_COMMAND} -E copy ${file} ${destination_file} 42 | ) 43 | endforeach() 44 | add_custom_target( stage_biogears_schema 45 | DEPENDS 46 | ${${__RESULTS_VAR}} 47 | COMMENT "Scanning for need to stage runtime dir" 48 | ) 49 | set(${__RESULTS_VAR} ${${__RESULTS_VAR}} PARENT_SCOPE) 50 | endfunction() 51 | 52 | # 53 | # Function Stage_BioGears_Data 54 | # Param: DESTINATION - Directory to stage the contents of Biogears_XSD_SCHEMA_DIR 55 | # Param: RESULTS_VAR - Variable to store the results in 56 | # 57 | # Places the value of Biogears_XSD_DATA_LIST in to DIR 58 | # Each file will become its on custom_target and will be staged before by runtime 59 | function(stage_biogears_data) 60 | cmake_parse_arguments(_ 61 | "" 62 | "DESTINATION;RESULTS_VAR" 63 | "" ${ARGN}) 64 | if(NOT __DESTINATION) 65 | message(FATAL_ERROR "DESTINATION required but not given") 66 | endif() 67 | if(NOT __RESULTS_VAR) 68 | set(__RESULTS_VAR _stage_biogears_data_results) 69 | endif() 70 | foreach( file IN LISTS Biogears_XSD_DATA_LIST ) 71 | string(REPLACE "${Biogears_XML_DATA_DIR}" "${__DESTINATION}" destination_file "${file}" ) 72 | list(APPEND ${__RESULTS_VAR} ${destination_file} ) 73 | add_custom_command( 74 | OUTPUT ${destination_file} 75 | DEPENDS ${file} 76 | COMMAND ${CMAKE_COMMAND} -E copy ${file} ${destination_file} 77 | ) 78 | endforeach() 79 | add_custom_target(stage_biogears_data 80 | DEPENDS 81 | ${${__RESULTS_VAR}} 82 | COMMENT "Scanning for need to stage runtime dir" 83 | ) 84 | set(${__RESULTS_VAR} ${${__RESULTS_VAR}} PARENT_SCOPE) 85 | endfunction() 86 | -------------------------------------------------------------------------------- /cmake/cmake-commonConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include ( "${CMAKE_CURRENT_LIST_DIR}/${ROOT_PROJECT_NAME}.cmake" ) -------------------------------------------------------------------------------- /cmake/common/FindLog4cpp.cmake: -------------------------------------------------------------------------------- 1 | #.rst: 2 | # FindLog4cpp 3 | # -------- 4 | # 5 | # Find Log4cpp 6 | # 7 | # Find the native Log4cpp headers and libraries. 8 | # 9 | # :: 10 | # 11 | # Log4cpp_INCLUDE_DIRS - where to find Log4cpp/Log4cpp.h, etc. 12 | # Log4cpp_LIBRARIES - List of libraries when using Log4cpp. 13 | # Log4cpp_FOUND - True if Log4cpp found. 14 | # Log4cpp_VERSION_STRING - the version of Log4cpp found (since CMake 2.8.8) 15 | 16 | if(NOT Log4cpp_FOUND) 17 | # Look for the header file. 18 | find_path(Log4cpp_INCLUDE_DIR 19 | NAMES log4cpp/Category.hh 20 | PATH_SUFFIXES 21 | log4cpp 22 | include/log4cpp 23 | DOC "Log4cpp Include Path" 24 | ) 25 | # Look for the library (sorted from most current/relevant entry to least). 26 | find_library(Log4cpp_LIBRARY_RELEASE NAMES 27 | log4cpp 28 | liblog4cpp 29 | 30 | PATH_SUFFIX release 31 | DOC "Log4cpp Release Library. Prefered over DLL" 32 | ) 33 | # Look for the library (sorted from most current/relevant entry to least). 34 | find_library(Log4cpp_LIBRARY_DEBUG NAMES 35 | log4cpp_d 36 | liblog4cpp_d 37 | log4cpp 38 | liblog4cpp 39 | PATH_SUFFIX debug 40 | DOC "Log4cpp Debug Library. Prefered over DLL" 41 | ) 42 | 43 | 44 | # handle the QUIETLY and REQUIRED arguments and set Log4cpp_FOUND to TRUE if 45 | # all listed variables are TRUE 46 | include(FindPackageHandleStandardArgs) 47 | 48 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Log4cpp 49 | REQUIRED_VARS Log4cpp_LIBRARY_DEBUG 50 | Log4cpp_LIBRARY_RELEASE 51 | Log4cpp_INCLUDE_DIR 52 | ) 53 | 54 | if(Log4cpp_FOUND) 55 | add_library(Log4cpp::Log4cpp SHARED IMPORTED GLOBAL) 56 | set_target_properties(Log4cpp::Log4cpp 57 | PROPERTIES 58 | IMPORTED_LOCATION ${Log4cpp_LIBRARY_RELEASE} 59 | IMPORTED_LOCATION_DEBUG ${Log4cpp_LIBRARY_DEBUG} 60 | IMPORTED_IMPLIB_DEBUG ${Log4cpp_LIBRARY_DEBUG} 61 | IMPORTED_IMPLIB ${Log4cpp_LIBRARY_RELEASE} 62 | INTERFACE_INCLUDE_DIRECTORIES 63 | ${Log4cpp_INCLUDE_DIR} 64 | ) 65 | 66 | mark_as_advanced(Log4cpp_LIBRARY_DEBUG) 67 | mark_as_advanced(Log4cpp_LIBRARY_RELEASE) 68 | mark_as_advanced(Log4cpp_INCLUDE_DIR) 69 | endif() 70 | endif() 71 | -------------------------------------------------------------------------------- /cmake/common/FindTbb.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Steven A Whtie 2 | # This file is MIT licensed. 3 | # See http://opensource.org/licenses/MIT 4 | 5 | # Tbb_FOUND 6 | # Tbb_INCLUDE_DIR 7 | # Tbb_LIBRARIES 8 | 9 | ################################################################################# 10 | # Includes 11 | ################################################################################# 12 | find_path(Tbb_INCLUDE_DIR 13 | NAMES tbb_stddef.h 14 | PATH tbb 15 | ) 16 | ################################################################################# 17 | # Libraries 18 | ################################################################################# 19 | find_library(Tbb_MALLOC_LIBRARY_DEBUG 20 | NAMES tbbmalloc_debug tbbmalloc 21 | PATH_SUFFIXES debug 22 | ) 23 | find_library(Tbb_MALLOC_LIBRARY 24 | NAMES tbbmalloc 25 | PATH_SUFFIXES release 26 | ) 27 | find_library(Tbb_LIBRARY_DEBUG 28 | NAMES tbb_debug tbb 29 | PATH_SUFFIXES debug 30 | ) 31 | find_library(Tbb_LIBRARY 32 | NAMES tbb 33 | PATH_SUFFIXES release 34 | ) 35 | 36 | include(FindPackageHandleStandardArgs) 37 | find_package_handle_standard_args(Tbb 38 | REQUIRED_VARS 39 | Tbb_INCLUDE_DIR 40 | Tbb_MALLOC_LIBRARY_DEBUG 41 | Tbb_MALLOC_LIBRARY 42 | Tbb_LIBRARY_DEBUG 43 | Tbb_LIBRARY 44 | ) 45 | 46 | if(Tbb_FOUND) 47 | mark_as_advanced(Tbb_INCLUDE_DIR) 48 | mark_as_advanced(Tbb_MALLOC_LIBRARY_DEBUG) 49 | mark_as_advanced(Tbb_MALLOC_LIBRARY) 50 | mark_as_advanced(Tbb_LIBRARY_DEBUG) 51 | mark_as_advanced(Tbb_LIBRARY) 52 | 53 | add_library(Tbb::malloc IMPORTED GLOBAL) 54 | set_target_properties(Tbb::malloc 55 | PROPERTIES 56 | IMPORTED_IMPLIB_DEBUG ${Tbb_MALLOC_LIBRARY_DEBUG} 57 | IMPORTED_IMPLIB ${Tbb_MALLOC_LIBRARY} 58 | INTERFACE_SYSTEM_INCLUDE_DIRECTORIES 59 | ${Tbb_INCLUDE_DIR} 60 | ) 61 | 62 | add_library(Tbb::Tbb IMPORTED GLOBAL) 63 | set_target_properties(Tbb::Tbb 64 | PROPERTIES 65 | IMPORTED_IMPLIB_DEBUG ${Tbb_LIBRARY_DEBUG} 66 | IMPORTED_IMPLIB ${Tbb_LIBRARY_RELEASE} 67 | 68 | INTERFACE_SYSTEM_INCLUDE_DIRECTORIES 69 | ${Tbb_INCLUDE_DIR} 70 | ) 71 | 72 | endif(Tbb_FOUND) 73 | -------------------------------------------------------------------------------- /cmake/packaging/BioGearsLogo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/cmake/packaging/BioGearsLogo.bmp -------------------------------------------------------------------------------- /cmake/packaging/BioGearsLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/cmake/packaging/BioGearsLogo.png -------------------------------------------------------------------------------- /cmake/packaging/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_policy(SET CMP0087 NEW) 2 | 3 | include(InstallRequiredSystemLibraries) 4 | set(CPACK_PACKAGE_NAME "BioGears Explorer") 5 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "BioGears User Interface") 6 | set(CPACK_PACKAGE_VENDOR "Applied Resaerch Associates") 7 | set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.txt") 8 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt") 9 | set(CPACK_PACKAGE_HOMEPAGE_URL "http://biogearsengine.com") 10 | set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/biogearslogo_XoQ_icon.ico") 11 | set(VERSION_NUMBER "${${ROOT_PROJECT_NAME}_VERSION_MAJOR}.${${ROOT_PROJECT_NAME}_VERSION_MINOR}.${${ROOT_PROJECT_NAME}_VERSION_PATCH}") 12 | set(CPACK_PACKAGE_INSTALL_DIRECTORY "BioGears/${VERSION_NUMBER}") 13 | set(CPACK_PACKAGE_VERSION_MAJOR ${${ROOT_PROJECT_NAME}_VERSION_MAJOR} ) 14 | set(CPACK_PACKAGE_VERSION_MINOR ${${ROOT_PROJECT_NAME}_VERSION_MINOR} ) 15 | set(CPACK_PACKAGE_VERSION_PATCH ${${ROOT_PROJECT_NAME}_VERSION_PATCH} ) 16 | set(CPACK_PACKAGE_VERSION_TWEAK ${${ROOT_PROJECT_NAME}_VERSION_TWEAK} ) 17 | 18 | 19 | if(WIN32 AND NOT UNIX) 20 | # There is a bug in NSI that does not handle full UNIX paths properly. 21 | # Make sure there is at least one set of four backlashes. 22 | 23 | set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}\\\\BioGearsLogo.bmp") 24 | set(CPACK_NSIS_INSTALLED_ICON_NAME "${CMAKE_CURRENT_SOURCE_DIR}/biogearslogo_XoQ_icon.ico") 25 | set(CPACK_NSIS_DISPLAY_NAME "BioGears Explorer") 26 | set(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.biogearsengine.com") 27 | set(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.biogearsengine.com") 28 | set(CPACK_NSIS_CONTACT "admin@biogearsengine.com") 29 | set(CPACK_NSIS_MODIFY_PATH ON) 30 | set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON) 31 | 32 | set(CPACK_WIX_UPGRADE_GUID "5b30e5cf-134b-4e38-9883-111f3c6d7faf") 33 | set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/biogearslogo_XoQ_icon.ico") 34 | set(CPACK_WIX_PROGRAM_MENU_FOLDER "BioGears") 35 | set(CPACK_WIX_UI_BANNER "${CMAKE_CURRENT_SOURCE_DIR}/WIX_UI_BANNER.png") 36 | set(CPACK_WIX_UI_DIALOG "${CMAKE_CURRENT_SOURCE_DIR}/WIX_UI_DIALOG.png") 37 | set(CPACK_WIX_PROPERTY_ARPCOMMENTS "Graphical interface for using BioGears ${${ROOT_PROJECT_NAME}_VERSION_TAG}") 38 | set(CPACK_WIX_PROPERTY_ARPHELPLINK "https://biogearsengine.com") 39 | set(ARPURLINFOABOUT "https://biogearsengine.com") 40 | 41 | get_filename_component(Qt5_ROOT_DIR "${Qt5_DIR}/../../../" ABSOLUTE ) 42 | 43 | install(CODE " 44 | include(BundleUtilities) 45 | 46 | string(TOUPPER \${CMAKE_INSTALL_CONFIG_NAME} CONFIG) 47 | if( NOT UNIX ) 48 | set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY \${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_\${CONFIG}} ) 49 | set( CMAKE_LIBRARY_OUTPUT_DIRECTORY \${CMAKE_LIBRARY_OUTPUT_DIRECTORY_\${CONFIG}} ) 50 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY \${CMAKE_RUNTIME_OUTPUT_DIRECTORY_\${CONFIG}} ) 51 | endif() 52 | 53 | 54 | set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH}) 55 | 56 | foreach(_dir IN LISTS CMAKE_PREFIX_PATH) 57 | list(APPEND THIRD_PARTY \"\${_dir}\") 58 | list(APPEND THIRD_PARTY_LIB \"\${_dir}/lib\") 59 | list(APPEND THIRD_PARTY_BIN \"\${_dir}/bin\") 60 | endforeach() 61 | 62 | message(\" Generating Bundle for \${CMAKE_INSTALL_PREFIX}/bin/BioGearsUI.exe\") 63 | fixup_bundle(\${CMAKE_INSTALL_PREFIX}/bin/$ 64 | \"\" 65 | \"\${THIRD_PARTY_LIB};\${THIRD_PARTY_BIN}\" 66 | ) 67 | if(WIN32) 68 | message(\" Running windeployqt for \${CMAKE_INSTALL_PREFIX}/bin/BioGearsUI.exe\") 69 | execute_process( 70 | COMMAND ${CMAKE_COMMAND} -E env \"${Qt5_ROOT_DIR}/bin/windeployqt\" --no-compiler-runtime --list mapping \"\${CMAKE_INSTALL_PREFIX}/bin/$\" 71 | WORKING_DIRECTORY \"\${CMAKE_INSTALL_PREFIX}/bin/\" 72 | OUTPUT_VARIABLE _output 73 | ERROR_VARIABLE _error 74 | OUTPUT_STRIP_TRAILING_WHITESPACE 75 | ) 76 | if(_output) 77 | message(\"windeployqt OUTPUT : \${_output}\") 78 | endif() 79 | if( _error ) 80 | message(\"windeployqt ERROR : \${_error}\") 81 | endif() 82 | endif() 83 | 84 | ") 85 | 86 | install(DIRECTORY 87 | ${PROJECT_SOURCE_DIR}/extern/biogears/share/xsd 88 | DESTINATION runtime/${VERSION_NUMBER} 89 | FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ 90 | ) 91 | 92 | install(DIRECTORY 93 | ${PROJECT_SOURCE_DIR}/extern/biogears/share/data/ 94 | DESTINATION runtime/${VERSION_NUMBER} 95 | FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ 96 | FILES_MATCHING 97 | PATTERN "*.xml" 98 | PATTERN "*.config" 99 | PATTERN "*.csv" 100 | ) 101 | install(DIRECTORY 102 | ${PROJECT_SOURCE_DIR}/extern/biogears/share/Scenarios 103 | DESTINATION runtime/${VERSION_NUMBER} 104 | FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ 105 | FILES_MATCHING 106 | PATTERN "*.xml" 107 | ) 108 | 109 | install(DIRECTORY 110 | ${Qt5_ROOT_DIR}/plugins/ 111 | DESTINATION bin/ 112 | FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ 113 | FILES_MATCHING 114 | PATTERN "*.dll" 115 | ) 116 | install(DIRECTORY 117 | ${Qt5_ROOT_DIR}/qml/Qt 118 | ${Qt5_ROOT_DIR}/qml/QtCanvas3D 119 | ${Qt5_ROOT_DIR}/qml/QtCharts 120 | ${Qt5_ROOT_DIR}/qml/QtDataVisualization 121 | ${Qt5_ROOT_DIR}/qml/QtGraphicalEffects 122 | ${Qt5_ROOT_DIR}/qml/QtQuick 123 | ${Qt5_ROOT_DIR}/qml/QtQuick.2 124 | ${Qt5_ROOT_DIR}/qml/QtQMl 125 | DESTINATION bin/ 126 | FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ 127 | ) 128 | # install(DIRECTORY 129 | # ${Qt5_ROOT_DIR}/translations 130 | # DESTINATION bin/ 131 | # FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ 132 | # FILES_MATCHING 133 | # PATTERN "*.qm" 134 | # ) 135 | 136 | else() 137 | set(CPACK_STRIP_FILES "") 138 | set(CPACK_SOURCE_STRIP_FILES "") 139 | endif() 140 | set(CPACK_PACKAGE_EXECUTABLES "BioGearsUI" "BioGears Explorer") 141 | 142 | include(CPack) 143 | -------------------------------------------------------------------------------- /cmake/packaging/COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | //********************************************************************************** 2 | //Copyright 2015 Applied Research Associates, Inc. 3 | //Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | //this file except in compliance with the License.You may obtain a copy of the License 5 | //at : 6 | //http://www.apache.org/licenses/LICENSE-2.0 7 | //Unless required by applicable law or agreed to in writing, software distributed under 8 | //the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | //CONDITIONS OF ANY KIND, either express or implied.See the License for the 10 | //specific language governing permissions and limitations under the License. 11 | //************************************************************************************** 12 | -------------------------------------------------------------------------------- /cmake/packaging/README.txt: -------------------------------------------------------------------------------- 1 | BioGears® is a C++ based, open source, multi-platform (Windows, Mac, and Linux), comprehensive human 2 | physiology engine that will drive medical education, research, and training technologies. BioGears enables 3 | accurate and consistent physiology simulation across the medical community. The engine can be used as a 4 | standalone application or integrated with simulators, sensor interfaces, and models of all fidelities. -------------------------------------------------------------------------------- /cmake/packaging/WIX_UI_BANNER.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/cmake/packaging/WIX_UI_BANNER.bmp -------------------------------------------------------------------------------- /cmake/packaging/WIX_UI_BANNER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/cmake/packaging/WIX_UI_BANNER.png -------------------------------------------------------------------------------- /cmake/packaging/WIX_UI_DIALOG.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/cmake/packaging/WIX_UI_DIALOG.bmp -------------------------------------------------------------------------------- /cmake/packaging/WIX_UI_DIALOG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/cmake/packaging/WIX_UI_DIALOG.png -------------------------------------------------------------------------------- /cmake/packaging/biogearslogo_XoQ_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/cmake/packaging/biogearslogo_XoQ_icon.ico -------------------------------------------------------------------------------- /cmake/packaging/biogearslogo_kvO_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/cmake/packaging/biogearslogo_kvO_icon.ico -------------------------------------------------------------------------------- /cmake/toolchains/linux-gcc9-amd64: -------------------------------------------------------------------------------- 1 | # the name of the target operating system 2 | set(CMAKE_SYSTEM_NAME Linux) 3 | set(CMAKE_GENERATOR "GNU Makefiles") 4 | set(CMAKE_SYSTEM_PROCESSOR "x86_64") 5 | # which compilers to use for C and C++ 6 | set(CMAKE_C_COMPILER gcc-9) 7 | set(CMAKE_C_FLAGS "-mtune=core2 -std=c11 -fPIC") 8 | set(CMAKE_CXX_COMPILER g++-9) 9 | set(CMAKE_CXX_FLAGS "-mtune=core2 -std=c++11 -fPIC") 10 | 11 | -------------------------------------------------------------------------------- /projects/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Step 1: Some packages need to be configured globally to ensure they find the 3 | # right library all others should be called in the respective projects 4 | # to promote some independence 5 | ############################################################################### 6 | 7 | if(WIN32) 8 | set(LIBRARY_INSTALL_DIR bin) 9 | else() 10 | set(LIBRARY_INSTALL_DIR lib) 11 | endif() 12 | 13 | set(CMAKE_STATIC_LIBRARY_PREFIX "lib") 14 | set(CMAKE_STATIC_LIBRARY_SUFFIX "_st${CMAKE_STATIC_LIBRARY_SUFFIX}") 15 | set(CMAKE_SHARED_LIBRARY_PREFIX "lib") 16 | 17 | setup_unified_output_directory() 18 | ############################################################################### 19 | # Step 2: Project Includes are generally order dependent. So manually maintain 20 | # this list 21 | ############################################################################### 22 | #option (Boost_USE_STATIC_LIBS "Toggle this option to allow static libraries" OFF) 23 | #if(WIN32) 24 | # if(NOT DEFINED Boost_USE_MULTITHREADED) 25 | # set(Boost_USE_MULTITHREADED ON) 26 | # endif() 27 | # if (Boost_USE_STATIC_LIBS AND NOT DEFINED Boost_USE_STATIC_RUNTIME) 28 | # set(Boost_USE_STATIC_RUNTIME ON) 29 | # else() 30 | # set(Boost_USE_STATIC_RUNTIME OFF) 31 | # endif() 32 | # set(BOOST_ALL_NO_LIB ON) 33 | #endif() 34 | #find_package(Boost COMPONENTS system filesystem program_options REQUIRED) 35 | 36 | add_subdirectory(ui) 37 | 38 | find_package(Git QUIET) 39 | option(BUILD_Biogears "Build Biogears using provided submodule" ON) 40 | # Update submodules as needed 41 | if(BUILD_Biogears) 42 | if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git" AND NOT Biogears_SUBMODULE_PULLED ) 43 | message(STATUS "Updating Biogears Submodule") 44 | execute_process( 45 | COMMAND ${CMAKE_COMMAND} -E echo ${GIT_EXECUTABLE} submodule init extern/biogears 46 | COMMAND ${GIT_EXECUTABLE} submodule init extern/biogears 47 | COMMAND ${CMAKE_COMMAND} -E echo ${GIT_EXECUTABLE} submodule update --progress --init extern/biogears/ 48 | COMMAND ${GIT_EXECUTABLE} submodule update --progress --init :/extern/biogears/ 49 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 50 | RESULT_VARIABLE GIT_SUBMOD_RESULT 51 | ERROR_VARIABLE GIT_ERROR 52 | OUTPUT_VARIABLE GIT_LOG 53 | ) 54 | if(NOT GIT_SUBMOD_RESULT EQUAL "0") 55 | message(FATAL_ERROR "Git operation failed with ${GIT_ERROR}, please checkout submodules") 56 | else () 57 | set (Biogears_SUBMODULE_PULLED "The Cmake Build Machine has Initialized the Build System" CACHE BOOL ON) 58 | endif() 59 | endif() 60 | if(NOT EXISTS "${PROJECT_SOURCE_DIR}/extern/biogears/CMakeLists.txt") 61 | message(FATAL_ERROR "The submodules were not downloaded! GIT_SUBMODULE was turned off or failed. Please update submodules and try again.") 62 | endif() 63 | endif() 64 | 65 | 66 | 67 | set(Biogears_BUILD_CIRCUIT_PROFILER CACHE BOOL OFF) 68 | set(Biogears_BUILD_CIRCUIT_TESTS CACHE BOOL OFF) 69 | set(Biogears_BUILD_CMD_TOOLS CACHE BOOL OFF) 70 | set(Biogears_BUILD_DOCUMENTATION CACHE BOOL OFF) 71 | set(Biogears_BUILD_HOWTOS CACHE BOOL OFF) 72 | set(Biogears_BUILD_TEST CACHE BOOL OFF) 73 | set(Biogears_BUILD_TEST_DRIVER CACHE BOOL OFF) 74 | set(Biogears_BUILD_SCENARIO_DRIVER CACHE BOOL OFF) 75 | set(Biogears_RUNTIME_DIR ${PROJECT_BINARY_DIR}/runtime) 76 | set(XSD_USE_SHORT_TARGET_NAMES ON) 77 | set(Biogears_IO_USE_SHORT_TARGET_NAMES ON) 78 | if(BUILD_Biogears AND EXISTS "${PROJECT_SOURCE_DIR}/extern/biogears/CMakeLists.txt") 79 | add_subdirectory(${PROJECT_SOURCE_DIR}/extern/biogears libbiogears) 80 | else() 81 | find_package(Biogears QUIET) 82 | if(NOT Biogears_FOUND) 83 | message(FATAL_ERROR "Unable to find Biogears. Biogears must match the requested revision for this code base. 84 | Eitehr turn on BUILD_Biogears or provide it using CMAKE_PREFIX_PATH") 85 | endif() 86 | endif() 87 | -------------------------------------------------------------------------------- /projects/ui/BioGearsUI.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/BioGearsUI.ico -------------------------------------------------------------------------------- /projects/ui/BioGearsUI.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON BioGearsUI.ico -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/BioGearsData.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "Models/PhysiologyRequest.h" 11 | #include "biogears/engine/Controller/BioGearsSubstances.h" 12 | #include "biogears/cdm/scenario/requests/SEDataRequestManager.h" 13 | 14 | class BioGearsData : public QAbstractItemModel { 15 | Q_OBJECT 16 | 17 | Q_PROPERTY(double simulation_time READ getSimulationTime NOTIFY timeAdvanced) 18 | public: 19 | enum Categories { 20 | VITALS = 0, 21 | CARDIOVASCULAR, 22 | RESPIRATORY, 23 | BLOOD_CHEMISTRY, 24 | ENERGY_AND_METABOLISM, 25 | RENAL, 26 | SUBSTANCES, 27 | CUSTOM, 28 | TOTAL_CATEGORIES 29 | }; 30 | Q_ENUMS(Categories) 31 | enum PhysiologyRequestRoles { 32 | PrefixRole = Qt::UserRole + 1, 33 | RequestRole, 34 | ValueRole, 35 | UnitRole, 36 | FullNameRole, 37 | UsableRole, 38 | EnabledRole, 39 | CustomRole, 40 | RateRole, 41 | RowRole, 42 | NestedRole, 43 | ChildrenRole, 44 | ColumnRole, 45 | AutoScaleRole, 46 | YMaxRole, 47 | YMinRole, 48 | XIntervalRole, 49 | }; 50 | Q_ENUMS(PhysiologyRequestRoles) 51 | 52 | explicit BioGearsData(); 53 | explicit BioGearsData(QString name, QObject* parent); 54 | explicit BioGearsData(QString name, BioGearsData* parent); 55 | ~BioGearsData() override; 56 | 57 | void initialize(const biogears::BioGearsSubstances& bgSubstances); 58 | 59 | Q_INVOKABLE int categories(); 60 | Q_INVOKABLE BioGearsData* category(int category); 61 | 62 | Q_INVOKABLE QVariant data(int role) const; 63 | Q_INVOKABLE QVariant data(const QModelIndex& index, int role) const override; 64 | bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); 65 | Qt::ItemFlags flags(const QModelIndex& index) const override; 66 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; 67 | QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; 68 | QModelIndex parent(const QModelIndex& index) const override; 69 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; 70 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; 71 | 72 | QModelIndex index(QAbstractItemModel const* model) const; 73 | 74 | double getSimulationTime(); 75 | void setSimulationTime(double time_s); 76 | void enableFromScenario(CDM::ScenarioData* scenario); 77 | 78 | QHash roleNames() const 79 | { 80 | QHash roles; 81 | roles[Qt::DisplayRole] = "name"; 82 | roles[PrefixRole] = "prefix"; 83 | roles[RequestRole] = "request"; 84 | roles[ValueRole] = "value"; 85 | roles[UnitRole] = "unit"; 86 | roles[FullNameRole] = "fullname"; 87 | roles[UsableRole] = "usable"; 88 | roles[EnabledRole] = "enabled"; 89 | roles[CustomRole] = "custom"; 90 | roles[RateRole] = "rate"; 91 | roles[RowRole] = "rows"; 92 | roles[NestedRole] = "nested"; 93 | roles[ChildrenRole] = "rows"; 94 | roles[ColumnRole] = "columns"; 95 | roles[AutoScaleRole] = "autoscale"; 96 | roles[YMaxRole] = "ymax"; 97 | roles[YMinRole] = "ymin"; 98 | roles[XIntervalRole] = "xinterval"; 99 | return roles; 100 | } 101 | 102 | void clear(); //Remove all Children; 103 | PhysiologyRequest* append(QString prefix, QString name, QString display = ""); 104 | PhysiologyRequest const* child(int row) const; 105 | PhysiologyRequest* child(int row); 106 | 107 | signals: 108 | void timeAdvanced(double time_s); 109 | 110 | private: 111 | QString _name; 112 | 113 | double _simulation_time_s = 0.; 114 | 115 | BioGearsData* _rootModel = nullptr; 116 | PhysiologyRequest _rootRequest; 117 | 118 | BioGearsData* _vitals = nullptr; 119 | BioGearsData* _cardiovascular = nullptr; 120 | BioGearsData* _respiratory = nullptr; 121 | BioGearsData* _blood_chemistry = nullptr; 122 | BioGearsData* _energy_and_metabolism = nullptr; 123 | BioGearsData* _renal = nullptr; 124 | BioGearsData* _substances = nullptr; 125 | BioGearsData* _customs = nullptr; 126 | 127 | Q_PROPERTY(QString name MEMBER _name CONSTANT) 128 | }; 129 | -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/BloodPanel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct PatientAssessments { 6 | bool urinalysis = false; 7 | 8 | bool operator==(const PatientAssessments& ua) const { return urinalysis == ua.urinalysis; } 9 | bool operator!=(const PatientAssessments& ua) const { return !(*this == ua); } 10 | 11 | private: 12 | Q_GADGET 13 | Q_PROPERTY(bool urinalysis MEMBER urinalysis) 14 | }; 15 | Q_DECLARE_METATYPE(PatientAssessments) 16 | -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/Gadgets.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PatientState.h" 4 | #include "PatientMerics.h" 5 | #include "PatientConditions.h" -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "Logger.h" 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void QtLogForward::Debug(char const* msg) const 9 | { 10 | messageReceived(QString("%1\n").arg(msg)); 11 | } 12 | //------------------------------------------------------------------------------- 13 | void QtLogForward::Info(char const* msg) const 14 | { 15 | messageReceived(QString("%1\n").arg(msg)); 16 | } 17 | //------------------------------------------------------------------------------- 18 | void QtLogForward::Warning(char const* msg) const 19 | { 20 | messageReceived(QString("%1\n").arg(msg)); 21 | } 22 | //------------------------------------------------------------------------------- 23 | void QtLogForward::Error(char const* msg) const 24 | { 25 | 26 | messageReceived(QString("%1\n").arg(msg)); 27 | } 28 | //------------------------------------------------------------------------------- 29 | void QtLogForward::Fatal(char const* msg) const 30 | { 31 | messageReceived(QString("%1\n").arg(msg)); 32 | } 33 | //------------------------------------------------------------------------------- 34 | //------------------------------------------------------------------------------- 35 | QtLogForward::QtLogForward(QObject* parent) 36 | : QObject(parent) 37 | , _buffer() 38 | , _channel(&_buffer) 39 | { 40 | } 41 | 42 | //------------------------------------------------------------------------------- 43 | struct QtLogger::Implementation { 44 | QtLogForward Qt5LogStream; 45 | }; 46 | //------------------------------------------------------------------------------- 47 | 48 | QtLogger::QtLogger(const QString& logFilename, biogears::IOManager iomanager) 49 | : biogears::Logger(logFilename.toStdString(), iomanager) 50 | , _pimpl(std::make_unique()) 51 | { 52 | biogears::Logger::SetForward(&_pimpl->Qt5LogStream); 53 | } 54 | //------------------------------------------------------------------------------- 55 | QtLogger::~QtLogger() 56 | { 57 | _pimpl = nullptr; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/Logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WINDOWS_LEAN_AND_MEAN 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #ifdef ERROR 12 | #undef ERROR 13 | #endif 14 | 15 | #include 16 | class QtLogForward : public QObject, public biogears::LoggerForward { 17 | Q_OBJECT 18 | 19 | public: 20 | 21 | QtLogForward(QObject* parent = nullptr); 22 | ~QtLogForward() = default; 23 | void Debug(const char* msg) const final; 24 | void Info(const char* msg) const final; 25 | void Warning(const char* msg) const final; 26 | void Error(const char* msg) const final; 27 | void Fatal(const char* msg) const final; 28 | 29 | signals: 30 | void messageReceived(QString message) const; 31 | 32 | 33 | private: 34 | QString _buffer; 35 | QTextStream _channel; 36 | }; 37 | 38 | class QtLogger : public biogears::Logger { 39 | friend biogears::Loggable; 40 | 41 | public: 42 | QtLogger(const QString& logFilename, biogears::IOManager iomanager); 43 | virtual ~QtLogger(); 44 | 45 | protected: 46 | using biogears::Logger::HasForward; 47 | using biogears::Logger::SetForward; 48 | 49 | using biogears::Logger::Debug; 50 | using biogears::Logger::Error; 51 | using biogears::Logger::Fatal; 52 | using biogears::Logger::Info; 53 | using biogears::Logger::Warning; 54 | 55 | private: 56 | struct Implementation; 57 | std::unique_ptr _pimpl; 58 | }; 59 | -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/Models/DataRequestNode.cpp: -------------------------------------------------------------------------------- 1 | #include "DataRequestNode.h" 2 | 3 | #include "DataRequestTree.h" 4 | 5 | #include 6 | #include 7 | 8 | DataRequestNode::DataRequestNode() 9 | { 10 | } 11 | //------------------------------------------------------------------------------------ 12 | DataRequestNode::DataRequestNode(QString name, int checked, bool collapsed, QString type, DataRequestNode* parent) 13 | : _parent(parent) 14 | , _name(name) 15 | , _checked(checked) 16 | , _collapsed(collapsed) 17 | , _type(type) 18 | { 19 | } 20 | //------------------------------------------------------------------------------------ 21 | DataRequestNode::~DataRequestNode() 22 | { 23 | _children.clear(); 24 | } 25 | //------------------------------------------------------------------------------------ 26 | QString DataRequestNode::name() const 27 | { 28 | return _name; 29 | } 30 | //------------------------------------------------------------------------------------ 31 | void DataRequestNode::name(const QString& value) 32 | { 33 | _name = value; 34 | } 35 | //------------------------------------------------------------------------------------ 36 | int DataRequestNode::checked() const 37 | { 38 | return _checked; 39 | } 40 | //------------------------------------------------------------------------------------ 41 | void DataRequestNode::checked(int value) 42 | { 43 | _checked = value; 44 | } 45 | //------------------------------------------------------------------------------------ 46 | bool DataRequestNode::collapsed() const 47 | { 48 | return _collapsed; 49 | } 50 | //------------------------------------------------------------------------------------ 51 | void DataRequestNode::collapsed(bool value) 52 | { 53 | _collapsed = value; 54 | } 55 | //------------------------------------------------------------------------------------ 56 | QString DataRequestNode::type() const 57 | { 58 | return _type; 59 | } 60 | //------------------------------------------------------------------------------------ 61 | void DataRequestNode::type(QString& value) 62 | { 63 | _type = value; 64 | } 65 | //------------------------------------------------------------------------------------ 66 | int DataRequestNode::rows() const 67 | { 68 | return _children.size(); 69 | } 70 | //------------------------------------------------------------------------------------ 71 | int DataRequestNode::rowInParent() const 72 | { 73 | if (_parent != nullptr) { 74 | return _parent->children().indexOf(const_cast(this)); 75 | } else { 76 | return 0; 77 | } 78 | } 79 | //------------------------------------------------------------------------------------ 80 | DataRequestNode const* DataRequestNode::parent() const 81 | { 82 | return _parent; 83 | } 84 | //------------------------------------------------------------------------------------ 85 | DataRequestNode* DataRequestNode::parent() 86 | { 87 | return _parent; 88 | } 89 | //------------------------------------------------------------------------------------ 90 | DataRequestNode* DataRequestNode::child(int index) 91 | { 92 | if (0 <= index && index < _children.size()) { 93 | return _children[index]; 94 | } 95 | return nullptr; 96 | } 97 | //------------------------------------------------------------------------------------ 98 | DataRequestNode const* DataRequestNode::child(int index) const 99 | { 100 | if (0 <= index && index <= _children.size()) { 101 | return _children[index]; 102 | } 103 | return nullptr; 104 | } 105 | //------------------------------------------------------------------------------------ 106 | QVector DataRequestNode::children() const 107 | { 108 | return _children; 109 | } 110 | //------------------------------------------------------------------------------------ 111 | QVariant DataRequestNode::data(int role) const 112 | { 113 | switch (role) { 114 | case Qt::DisplayRole: 115 | return QVariant(_name); 116 | case Qt::CheckStateRole: 117 | return QVariant(_checked); 118 | case DataRequestTree::CollapsedRole: 119 | return QVariant(_collapsed); 120 | case DataRequestTree::TypeRole: 121 | return QVariant(_type); 122 | default: 123 | return QVariant(); 124 | } 125 | } 126 | //------------------------------------------------------------------------------------ 127 | DataRequestNode* DataRequestNode::appendChild(QString name, QString type) 128 | { 129 | DataRequestNode* newNode = new DataRequestNode(); 130 | newNode->_name = name; 131 | newNode->_checked = 0; 132 | newNode->_collapsed = true; 133 | newNode->_type = type; 134 | newNode->_parent = this; 135 | _children.append(newNode); 136 | return _children.back(); 137 | } 138 | //------------------------------------------------------------------------------------ 139 | DataRequestNode* DataRequestNode::appendChildren(QList> nameTypePairs) 140 | { 141 | QList>::const_iterator nodeIt; 142 | for (nodeIt = nameTypePairs.constBegin(); nodeIt != nameTypePairs.constEnd(); ++nodeIt) { 143 | DataRequestNode* childNode = new DataRequestNode((*nodeIt).first, 0, true, (*nodeIt).second, this); 144 | _children.append(childNode); 145 | } 146 | return _children.back(); 147 | } 148 | //------------------------------------------------------------------------------------ 149 | void DataRequestNode::reset() 150 | { 151 | collapsed(true); 152 | checked(0); 153 | if (_children.size() > 0) { 154 | for (auto child : _children) { 155 | child->reset(); 156 | } 157 | } 158 | } -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/Models/DataRequestNode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | class DataRequestNode { 12 | public: 13 | DataRequestNode(); 14 | DataRequestNode(QString name, int checked = 0, bool collapsed = true, QString type = "", DataRequestNode* parent = nullptr); 15 | ~DataRequestNode(); 16 | 17 | struct NodeInput { 18 | QString name; 19 | QString type; 20 | }; 21 | 22 | QString name() const; 23 | void name(const QString& value); 24 | 25 | int checked() const; 26 | void checked(int value); 27 | 28 | bool collapsed() const; 29 | void collapsed(bool value); 30 | 31 | QString type() const; 32 | void type(QString& value); 33 | 34 | int rows() const; 35 | int rowInParent() const; 36 | 37 | QVariant data(int role) const; 38 | 39 | DataRequestNode const* parent() const; 40 | DataRequestNode* parent(); 41 | DataRequestNode* child(int row); 42 | DataRequestNode const* child(int row) const; 43 | QVector children() const; 44 | DataRequestNode* appendChild(QString name, QString type = ""); 45 | DataRequestNode* appendChildren(QList> nameTypePairs); 46 | void reset(); 47 | 48 | private: 49 | DataRequestNode* _parent = nullptr; 50 | 51 | QVector _children; 52 | QString _name; 53 | int _checked = 0; 54 | bool _collapsed = true; 55 | QString _type = ""; 56 | }; 57 | -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/Models/DataRequestTree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "DataRequestNode.h" 11 | #include "biogears/cdm/compartment/SECompartmentManager.h" 12 | #include "biogears/cdm/scenario/requests/SEDataRequestManager.h" 13 | #include "biogears/cdm/substance/SESubstanceManager.h" 14 | #include 15 | 16 | class DataRequestTree : public QAbstractItemModel { 17 | Q_OBJECT 18 | 19 | public: 20 | enum DataRequestRoles { 21 | CollapsedRole = Qt::UserRole + 1, 22 | TypeRole 23 | }; 24 | Q_ENUMS(DataRequestRoles) 25 | 26 | explicit DataRequestTree(QObject* parent = nullptr); 27 | ~DataRequestTree() override; 28 | 29 | Q_INVOKABLE QVariant data(const QModelIndex& index, int role) const override; 30 | Q_INVOKABLE QString dataPath(const QModelIndex& index); 31 | Q_INVOKABLE void resetData(); 32 | bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; 33 | Qt::ItemFlags flags(const QModelIndex& index) const override; 34 | QModelIndex parent(const QModelIndex& index) const override; 35 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; 36 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; 37 | QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; 38 | DataRequestNode* appendChild(QString name, QString type = ""); 39 | DataRequestNode* appendChildren(QList> nameUnitPairs); 40 | CDM::DataRequestData* decode_request(QString request); 41 | QVariantList encode_requests(CDM::ScenarioData* scenario); 42 | void initialize(biogears::SECompartmentManager* comps, biogears::SESubstanceManager* subs); 43 | 44 | QHash roleNames() const override 45 | { 46 | QHash roles; 47 | roles[Qt::DisplayRole] = "name"; 48 | roles[Qt::CheckStateRole] = "checked"; 49 | roles[CollapsedRole] = "collapsed"; 50 | roles[TypeRole] = "type"; 51 | return roles; 52 | } 53 | 54 | signals: 55 | void requestModelUpdate(DataRequestTree* model); 56 | 57 | private: 58 | QString encode_gas_compartment_request(CDM::GasCompartmentDataRequestData* req); 59 | QString encode_liquid_compartment_request(CDM::LiquidCompartmentDataRequestData* req); 60 | QString encode_thermal_compartment_request(CDM::ThermalCompartmentDataRequestData* req); 61 | QString encode_tissue_compartment_request(CDM::TissueCompartmentDataRequestData* req); 62 | QString encode_environment_request(CDM::EnvironmentDataRequestData* req); 63 | QString encode_patient_request(CDM::PatientDataRequestData* req); 64 | QString encode_physiology_request(CDM::PhysiologyDataRequestData* req); 65 | QString encode_substance_request(CDM::SubstanceDataRequestData* req); 66 | 67 | CDM::CompartmentDataRequestData* decode_compartment_request(int type, std::vector& args); 68 | CDM::EnvironmentDataRequestData* decode_environment_request(std::vector& args); 69 | CDM::PatientDataRequestData* decode_patient_request(std::vector& args); 70 | CDM::PhysiologyDataRequestData* decode_physiology_request(std::vector& args); 71 | CDM::SubstanceDataRequestData* decode_substance_request(std::vector& args); 72 | 73 | DataRequestNode* _root; 74 | }; 75 | -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/Models/PhysiologyRequest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | class PhysiologyRequest { 12 | public: 13 | PhysiologyRequest(); 14 | PhysiologyRequest(QString prefix, QString name, bool enabled = false, PhysiologyRequest* parent = nullptr); 15 | ~PhysiologyRequest(); 16 | 17 | QString name() const; 18 | void name(const QString& value); 19 | 20 | QString display_name() const; 21 | void display_name(const QString& value); 22 | 23 | bool usable() const; 24 | void usable(bool value); 25 | 26 | int rate() const; 27 | void rate(int value); 28 | 29 | int nested() const; 30 | void nested(int value); 31 | 32 | int rows() const; 33 | int columns() const; 34 | 35 | bool enabled() const; 36 | void enabled(bool value); 37 | 38 | bool auto_scale() const; 39 | void auto_scale(bool value); 40 | 41 | double y_max() const; 42 | void y_max(double value); 43 | 44 | double y_min() const; 45 | void y_min(double value); 46 | 47 | double x_interval() const; 48 | void x_interval(double value); 49 | 50 | bool custom() const; 51 | void custom(std::function&& value, std::function&& unit); 52 | 53 | biogears::SEUnitScalar const * unit_scalar() const; 54 | void unit_scalar(biogears::SEUnitScalar*); 55 | 56 | QString unit() const; 57 | void unit(QString u); 58 | 59 | biogears::SEScalar const* scalar() const; 60 | void scalar(biogears::SEScalar*); 61 | 62 | void clear(); 63 | PhysiologyRequest const* parent() const; 64 | PhysiologyRequest* parent(); 65 | PhysiologyRequest* child(int row); 66 | PhysiologyRequest const* child(int row) const; 67 | 68 | QString header(int col) const; 69 | PhysiologyRequest* append(QString prefix, QString name, QString display = "", bool enabled = false, bool usable = true); 70 | void modify(int row, const biogears::SEUnitScalar* data); 71 | void modify(int row, const biogears::SEScalar* data); 72 | void modify(int row, int refreshRate); 73 | void modify(int row, bool enabled); 74 | 75 | QVariant data(int role) const; 76 | 77 | bool operator==(const PhysiologyRequest& rhs) 78 | { 79 | return _name == rhs._name 80 | && _prefix == rhs._prefix; 81 | } 82 | bool operator!=(const PhysiologyRequest& rhs) 83 | { 84 | return !(*this == rhs); 85 | } 86 | void scalar(biogears::SEScalar const* given) 87 | { 88 | _scalar = given; 89 | _unit_scalar = nullptr; 90 | }; 91 | void unit_scalar(biogears::SEUnitScalar const* given) 92 | { 93 | _unit_scalar = given; 94 | _scalar = nullptr; 95 | }; 96 | 97 | private: 98 | PhysiologyRequest* _parent = nullptr; 99 | 100 | QVector _children; 101 | QString _prefix; 102 | QString _name; 103 | QString _display_name; 104 | QString _unit; 105 | bool _unit_override = false; //When user request unit different than base unit stored on _unit_scalar 106 | bool _usable = false; 107 | bool _enabled = false; 108 | bool _custom = false; 109 | bool _nested = false; 110 | int _refresh_rate = 10; 111 | bool _auto_scale; 112 | double _y_max; 113 | double _y_min; 114 | double _x_interval; 115 | biogears::SEScalar const* _scalar = nullptr; 116 | biogears::SEUnitScalar const* _unit_scalar = nullptr; 117 | 118 | 119 | std::function _customValueFunc; 120 | std::function _customUnitFunc; 121 | }; 122 | -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/PatientConditions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct PatientConditions { 6 | bool diabieties = false; 7 | 8 | bool operator==(const PatientConditions& rhs) const { return diabieties == rhs.diabieties; } 9 | bool operator!=(const PatientConditions& rhs) const { return !(*this == rhs); } 10 | 11 | private: 12 | Q_GADGET 13 | Q_PROPERTY(bool diabieties MEMBER diabieties) 14 | }; 15 | Q_DECLARE_METATYPE(PatientConditions) 16 | -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/PatientMetrics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | struct PatientMetrics : QObject { 8 | PatientMetrics(QObject* parent = nullptr) 9 | : QObject(parent) 10 | { 11 | } 12 | ~PatientMetrics() override { 13 | }; 14 | QString respiratory_rate_bpm; 15 | QString heart_rate_bpm; 16 | QString core_temperature_c; 17 | QString oxygen_saturation_pct; 18 | QString systolic_blood_pressure_mmHg; 19 | QString diastolic_blood_pressure_mmHg; 20 | 21 | double simulationTime; 22 | double timeStep; 23 | 24 | 25 | //! 26 | //! Operators 27 | //! 28 | bool operator==(const PatientMetrics& rhs) const 29 | { 30 | return respiratory_rate_bpm == rhs.respiratory_rate_bpm 31 | && heart_rate_bpm == rhs.heart_rate_bpm 32 | && core_temperature_c == rhs.core_temperature_c 33 | && oxygen_saturation_pct == rhs.oxygen_saturation_pct 34 | && systolic_blood_pressure_mmHg == rhs.systolic_blood_pressure_mmHg 35 | && diastolic_blood_pressure_mmHg == rhs.diastolic_blood_pressure_mmHg 36 | 37 | && simulationTime == rhs.simulationTime 38 | && timeStep == rhs.timeStep; 39 | } 40 | bool operator!=(const PatientMetrics& rhs) const { return !(*this == rhs); } 41 | 42 | private: 43 | Q_OBJECT 44 | Q_PROPERTY(QString RespiratoryRate MEMBER respiratory_rate_bpm) 45 | Q_PROPERTY(QString HeartRate MEMBER heart_rate_bpm) 46 | Q_PROPERTY(QString CoreTemp MEMBER core_temperature_c) 47 | Q_PROPERTY(QString OxygenSaturation MEMBER oxygen_saturation_pct) 48 | Q_PROPERTY(QString SystolicBloodPressure MEMBER systolic_blood_pressure_mmHg) 49 | Q_PROPERTY(QString DiastolicBloodPressure MEMBER diastolic_blood_pressure_mmHg) 50 | 51 | Q_PROPERTY(double SimulationTime MEMBER simulationTime) 52 | Q_PROPERTY(double TimeStep MEMBER timeStep) 53 | 54 | 55 | }; -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/PatientState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct PatientState { 6 | bool alive = false; 7 | bool tacycardia = false; 8 | 9 | QString age; 10 | QString height_cm; 11 | QString gender; 12 | QString weight_kg; 13 | QString body_surface_area_m_sq; 14 | QString body_mass_index_kg_per_m_sq; 15 | QString body_fat_pct; 16 | QString exercise_state; 17 | 18 | bool operator==(const PatientState& rhs) const 19 | { 20 | return alive == rhs.alive 21 | && tacycardia == rhs.tacycardia 22 | && age == rhs.age 23 | && height_cm == rhs.height_cm 24 | && gender == rhs.gender 25 | && weight_kg == rhs.weight_kg 26 | && body_surface_area_m_sq == rhs.body_surface_area_m_sq 27 | && body_mass_index_kg_per_m_sq == rhs.body_mass_index_kg_per_m_sq 28 | && body_fat_pct == rhs.body_fat_pct 29 | && exercise_state == rhs.exercise_state; 30 | } 31 | bool operator!=(const PatientState& rhs) const { return !(*this == rhs); } 32 | 33 | private: 34 | Q_GADGET 35 | Q_PROPERTY(bool Alive MEMBER alive) 36 | Q_PROPERTY(bool Tacycardia MEMBER tacycardia) 37 | 38 | Q_PROPERTY(QString Age MEMBER age) 39 | Q_PROPERTY(QString Height MEMBER height_cm) 40 | Q_PROPERTY(QString Gender MEMBER gender) 41 | Q_PROPERTY(QString Weight MEMBER weight_kg) 42 | Q_PROPERTY(QString BodySurfaceArea MEMBER body_surface_area_m_sq) 43 | Q_PROPERTY(QString BodyMassIndex MEMBER body_mass_index_kg_per_m_sq) 44 | Q_PROPERTY(QString BodyFat MEMBER body_fat_pct) 45 | Q_PROPERTY(QString ExerciseState MEMBER exercise_state) 46 | }; 47 | Q_DECLARE_METATYPE(PatientState) 48 | -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/Urinalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "Urinalysis.h" 2 | 3 | QString Urinalysis::Color() { return _color; } 4 | QString Urinalysis::Appearance() { return _appearance; } 5 | QString Urinalysis::Bilirubin() { return _bilirubin; } 6 | QString Urinalysis::SpecificGravity() { return _specificGravity; } 7 | QString Urinalysis::pH() { return _pH; } 8 | QString Urinalysis::Urobilinogen() { return _urobilinogem; } 9 | QString Urinalysis::Glucose() { return _glucose; } 10 | QString Urinalysis::Ketone() { return _ketone; } 11 | QString Urinalysis::Protein() { return _protein; } 12 | QString Urinalysis::Blood() { return _blood; } 13 | QString Urinalysis::Nitrite() { return _nitrite; } 14 | QString Urinalysis::LeukocyteEsterase() { return _leukocyteEsterase; } 15 | 16 | void Urinalysis::Color(int value) 17 | { 18 | switch (value) { 19 | case (CDM::enumUrineColor::PaleYellow): 20 | _color = "PaleYellow"; 21 | break; 22 | case (CDM::enumUrineColor::Yellow): 23 | _color = "Yellow"; 24 | break; 25 | case (CDM::enumUrineColor::DarkYellow): 26 | _color = "DarkYellow"; 27 | break; 28 | case (CDM::enumUrineColor::Pink): 29 | _color = "Pink"; 30 | break; 31 | default: 32 | _color = ""; 33 | break; 34 | } 35 | } 36 | void Urinalysis::Appearance(int value) 37 | { 38 | switch (value) { 39 | case CDM::enumClarityIndicator::Clear: 40 | _appearance = "Clear"; 41 | break; 42 | case CDM::enumClarityIndicator::SlightlyCloudy: 43 | _appearance = "SlightlyCloudy"; 44 | break; 45 | case CDM::enumClarityIndicator::Cloudy: 46 | _appearance = "Cloudy"; 47 | break; 48 | case CDM::enumClarityIndicator::Turbid: 49 | _appearance = "Turbid"; 50 | break; 51 | default: 52 | _appearance = ""; 53 | break; 54 | } 55 | } 56 | void Urinalysis::Bilirubin(double value) { _bilirubin = QString("%1").arg(value); } 57 | void Urinalysis::SpecificGravity(double value) { _specificGravity = QString("%1").arg(value); } 58 | void Urinalysis::pH(double value) { _pH = QString("%1").arg(value); } 59 | void Urinalysis::Urobilinogen(double value) { _urobilinogem = QString("%1").arg(value); } 60 | 61 | void Urinalysis::Glucose(bool value) 62 | { 63 | switch (value) { 64 | case CDM::enumPresenceIndicator::Positive: 65 | _glucose = "Positive"; 66 | break; 67 | default: 68 | _glucose = "Negative"; 69 | break; 70 | } 71 | } 72 | void Urinalysis::Ketone(bool value) 73 | { 74 | switch (value) { 75 | case CDM::enumPresenceIndicator::Positive: 76 | _ketone = "Positive"; 77 | break; 78 | default: 79 | _ketone = "Negative"; 80 | break; 81 | } 82 | } 83 | void Urinalysis::Protein(bool value) 84 | { 85 | switch (value) { 86 | case CDM::enumPresenceIndicator::Positive: 87 | _protein = "Positive"; 88 | break; 89 | default: 90 | _protein = "Negative"; 91 | break; 92 | } 93 | } 94 | void Urinalysis::Blood(bool value) 95 | { 96 | switch (value) { 97 | case CDM::enumPresenceIndicator::Positive: 98 | _blood = "Positive"; 99 | break; 100 | default: 101 | _blood = "Negative"; 102 | break; 103 | } 104 | } 105 | void Urinalysis::Nitrite(bool value) 106 | { 107 | switch (value) { 108 | case CDM::enumPresenceIndicator::Positive: 109 | _nitrite = "Positive"; 110 | break; 111 | default: 112 | _nitrite = "Negative"; 113 | break; 114 | } 115 | } 116 | void Urinalysis::LeukocyteEsterase(bool value) 117 | { 118 | switch (value) { 119 | case CDM::enumPresenceIndicator::Positive: 120 | _leukocyteEsterase = "Positive"; 121 | break; 122 | default: 123 | _leukocyteEsterase = "Negative"; 124 | break; 125 | } 126 | } -------------------------------------------------------------------------------- /projects/ui/cpp/biogears/Urinalysis.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | struct Urinalysis : public QObject { 7 | 8 | Urinalysis(QObject* parent = nullptr) 9 | : QObject(parent){}; 10 | 11 | QString Color(); 12 | QString Appearance(); 13 | QString Bilirubin(); 14 | QString SpecificGravity(); 15 | QString pH(); 16 | QString Urobilinogen(); 17 | QString Glucose(); 18 | QString Ketone(); 19 | QString Protein(); 20 | QString Blood(); 21 | QString Nitrite(); 22 | QString LeukocyteEsterase(); 23 | 24 | bool operator==(const Urinalysis& ua) const { return true; } 25 | bool operator!=(const Urinalysis& ua) const { return !(*this == ua); } 26 | 27 | 28 | void Color(int value); 29 | void Appearance(int value); 30 | void Bilirubin(double value); 31 | void SpecificGravity(double value); 32 | void pH(double value); 33 | void Urobilinogen(double value); 34 | void Glucose(bool value); 35 | void Ketone(bool value); 36 | void Protein(bool value); 37 | void Blood(bool value); 38 | void Nitrite(bool value); 39 | void LeukocyteEsterase(bool value); 40 | 41 | private: 42 | Q_OBJECT 43 | QString _color; 44 | QString _appearance; 45 | QString _bilirubin; 46 | QString _specificGravity; 47 | QString _pH; 48 | QString _urobilinogem; 49 | QString _glucose; 50 | QString _ketone; 51 | QString _protein; 52 | QString _blood; 53 | QString _nitrite; 54 | QString _leukocyteEsterase; 55 | 56 | 57 | Q_PROPERTY(QString Color READ Color) //NOTIFY colorChanged) 58 | Q_PROPERTY(QString Appearance READ Appearance) // NOTIFY appearanceChanged) 59 | Q_PROPERTY(QString Bilirubin READ Bilirubin) 60 | Q_PROPERTY(QString SpecificGravity READ SpecificGravity) 61 | Q_PROPERTY(QString pH READ pH) 62 | Q_PROPERTY(QString Urobilinogen READ Urobilinogen) 63 | Q_PROPERTY(QString Glucose READ Glucose) 64 | Q_PROPERTY(QString Ketone READ Ketone) 65 | Q_PROPERTY(QString Protein READ Protein) 66 | Q_PROPERTY(QString Blood READ Blood) 67 | Q_PROPERTY(QString Nitrite READ Nitrite) 68 | Q_PROPERTY(QString LeukocyteEsterase READ LeukocyteEsterase) 69 | 70 | }; -------------------------------------------------------------------------------- /projects/ui/cpp/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "version.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | void syncronize_runtime_directory(QDir source_directory, QDir destination_directory) 19 | { 20 | qInfo() << "Installation Path : " << source_directory.absoluteFilePath("."); 21 | QDir installation_data_directory = source_directory.absoluteFilePath(QString("../runtime/%1").arg(bgui::rev_tag())); 22 | if (!installation_data_directory.exists()) { 23 | installation_data_directory = source_directory.absoluteFilePath(QString("../../runtime")); 24 | if (!installation_data_directory.exists()) { 25 | QMessageBox msgBox; 26 | msgBox.setText("Unable to find runtime directory. Installation may be corrupted!"); 27 | msgBox.setIcon(QMessageBox::Critical); 28 | msgBox.exec(); 29 | exit(1); 30 | } 31 | } 32 | QDirIterator it(installation_data_directory.absoluteFilePath("."), QStringList() << "*.csv" << "*.xml" << "*.xsd", QDir::Files, QDirIterator::Subdirectories); 33 | while (it.hasNext()) { 34 | QFileInfo current = it.next(); 35 | auto relative_filepath = installation_data_directory.relativeFilePath(it.filePath()); 36 | QDir relative_fragment = installation_data_directory.relativeFilePath(it.filePath()+"/.."); 37 | // qInfo() << "Relative filepath : " << relative_filepath; 38 | // qInfo() << "Destination dirname : " << destination_directory.absoluteFilePath(relative_fragment.path()); 39 | if (!destination_directory.exists(relative_fragment.path())) 40 | { 41 | // qInfo() << "Creating : " << destination_directory.filePath(relative_fragment.path()); 42 | destination_directory.mkpath(relative_fragment.path()); 43 | } 44 | if (current.isFile()) { 45 | // qInfo() << QString("Copying : %1 -> %2").arg(current.absoluteFilePath()).arg(destination_directory.filePath(relative_filepath)); 46 | QFile::copy(current.absoluteFilePath(), destination_directory.filePath(relative_filepath)); 47 | } 48 | } 49 | } 50 | int main(int argc, char* argv[]) 51 | { 52 | QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 53 | QApplication app(argc, argv); 54 | app.setOrganizationDomain("Applied Research Associates"); 55 | app.setOrganizationName("https://biogearsengine.com"); 56 | 57 | QQuickStyle::setStyle("Material"); 58 | 59 | QDir installation_dir{ QCoreApplication::applicationDirPath() }; 60 | QString app_directory = QString("Biogears/%1").arg(biogears::rev_tag_str()); 61 | QDir runtime_directory{ QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) }; 62 | 63 | #ifdef BIOGEARS_EXPLORER_RELEASE_BUNDLE 64 | if (!runtime_directory.exists(app_directory)) { 65 | // qInfo() << "Absolute Path : " << runtime_directory.absoluteFilePath(app_directory); 66 | if (runtime_directory.mkpath(app_directory)) { 67 | syncronize_runtime_directory(installation_dir, runtime_directory.absoluteFilePath(app_directory)); 68 | } 69 | } else { 70 | syncronize_runtime_directory(installation_dir, runtime_directory.absoluteFilePath(app_directory)); 71 | } 72 | qInfo() << "Runtime Directory will be : " << runtime_directory.absoluteFilePath(app_directory); 73 | QDir::setCurrent(runtime_directory.absoluteFilePath(app_directory)); 74 | try { 75 | auto test_engine = biogears::CreateBioGearsEngine("TestRun.log"); 76 | if ( !test_engine->LoadState("states/DefaultMale@0s.xml") ) { 77 | runtime_directory.removeRecursively(); 78 | runtime_directory.mkpath(app_directory); 79 | syncronize_runtime_directory(installation_dir, runtime_directory.absoluteFilePath(app_directory)); 80 | } 81 | if (!test_engine->LoadState("states/DefaultMale@0s.xml")) { 82 | QMessageBox msgBox; 83 | msgBox.setText("Unable to restore runtime directory. Installation corrupted!"); 84 | msgBox.setIcon(QMessageBox::Critical); 85 | msgBox.exec(); 86 | exit(1); 87 | } 88 | } catch (...) { 89 | runtime_directory.removeRecursively(); 90 | runtime_directory.mkpath(app_directory); 91 | syncronize_runtime_directory(installation_dir, runtime_directory.absoluteFilePath(app_directory)); 92 | 93 | QMessageBox msgBox; 94 | msgBox.setText("Unknown exception. Restart application or reinstall application!"); 95 | msgBox.setIcon(QMessageBox::Critical); 96 | msgBox.exec(); 97 | exit(1); 98 | } 99 | #endif 100 | 101 | QQmlApplicationEngine engine; 102 | 103 | qmlRegisterType("com.biogearsengine.ui.scenario", 1, 0, "Scenario"); 104 | qmlRegisterType("com.biogearsengine.ui.scenario", 1, 0, "PatientMetrics"); 105 | qmlRegisterType("com.biogearsengine.ui.scenario", 1, 0, "Info"); 106 | qmlRegisterType("com.biogearsengine.ui.scenario", 1, 0, "PhysiologyModel"); 107 | qmlRegisterType("com.biogearsengine.ui.scenario", 1, 0, "LogForward"); 108 | qmlRegisterType("com.biogearsengine.ui.scenario", 1, 0, "Urinalysis"); 109 | qmlRegisterType("com.biogearsengine.ui.scenario", 1, 0, "DataRequestModel"); 110 | qmlRegisterType("com.biogearsengine.ui.scenario", 1, 0, "EventModel"); 111 | qRegisterMetaType(); 112 | QMetaType::registerEqualsComparator(); 113 | qmlRegisterUncreatableType("com.biogearsengine.ui.scenario", 1, 0, "PatientState", "State of the Patient"); 114 | qRegisterMetaType(); 115 | qRegisterMetaType(); 116 | QMetaType::registerEqualsComparator(); 117 | qmlRegisterUncreatableType("com.biogearsengine.ui.scenario", 1, 0, "PatientConditions", "Conditions of the Patient"); 118 | 119 | engine.load(QUrl(QStringLiteral("qrc:/Main.qml"))); 120 | 121 | return app.exec(); 122 | } 123 | -------------------------------------------------------------------------------- /projects/ui/cpp/version.cpp.in: -------------------------------------------------------------------------------- 1 | #include "version.h" 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | constexpr const char* _OS_ = 12 | #ifdef _WIN32 13 | "Windows" 14 | #elif defined __unix__ 15 | "Linux" 16 | #elif defined __APPLE__ 17 | "MacOS" 18 | #endif 19 | ; 20 | 21 | #if defined(_MSVC_LANG) 22 | constexpr const char* _COMPILER_NAME_ = "MSVC"; 23 | constexpr const char* _COMPILER_VERSION_ = 24 | #if _MSC_VER == 1200 25 | "6.0" 26 | # elif _MSC_VER == 1300 27 | "7.0" 28 | # elif _MSC_VER == 1310 29 | "7.1" 30 | # elif _MSC_VER == 1400 31 | "8.0" 32 | # elif _MSC_VER == 1500 33 | "9.0" 34 | # elif _MSC_VER == 1600 35 | "10.0" 36 | # elif _MSC_VER == 1700 37 | "11.0" 38 | # elif _MSC_VER == 1800 39 | "12.0" 40 | # elif _MSC_VER == 1900 41 | "14.0" 42 | # elif _MSC_VER <= 1920 43 | "15.X" 44 | # elif _MSC_VER <= 1930 45 | "16.X" 46 | # else 47 | "Unknown" 48 | # endif 49 | ; 50 | #elif defined(__clang__) 51 | constexpr const char* _COMPILER_NAME_ = "Clang"; 52 | constexpr const char* _COMPILER_VERSION_ = "__clang_major__.__clang_minor__.__clang_patchlevel__"; 53 | #elif defined(__GNUG__) 54 | constexpr const char* _COMPILER_NAME_ = "GCC"; 55 | constexpr const char* _COMPILER_VERSION_ = "__GNUC__.__GNUC_MINOR__"; 56 | #elif defined(__MINGW32__) || defined(__MINGW64__) 57 | constexpr const char* _COMPILER_NAME_ = "MiniGW"; 58 | constexpr const char* _COMPILER_VERSION_ = ""; 59 | #endif 60 | 61 | namespace bgui { 62 | 63 | 64 | //----------------------------------------------------------------------------- 65 | 66 | constexpr char const * _PROJECT_NAME_ = "${ROOT_PROJECT_NAME}"; 67 | constexpr char const * _REV_HASH_ = "${${ROOT_PROJECT_NAME}_VERSION_HASH}"; 68 | constexpr char const * _REV_TAG_ = "${${ROOT_PROJECT_NAME}_VERSION_TAG}"; 69 | constexpr char const * _REV_COMMIT_DATE_= "${${ROOT_PROJECT_NAME}_COMMIT_DATE}"; 70 | constexpr bool _OFFICAL_RELEASE_ = ${${ROOT_PROJECT_NAME}_CLEAN_BUILD}; 71 | 72 | constexpr int _MAJOR_VERSION_NUMBER_ = ${${ROOT_PROJECT_NAME}_VERSION_MAJOR}; 73 | constexpr int _MINOR_VERSION_NUMBER_ = ${${ROOT_PROJECT_NAME}_VERSION_MINOR}; 74 | constexpr int _PATCH_VERSION_NUMBER_ = ${${ROOT_PROJECT_NAME}_VERSION_PATCH}; 75 | constexpr char const * _TWEAK_VERSION_NUMBER_ = "${${ROOT_PROJECT_NAME}_VERSION_TWEAK}"; 76 | 77 | 78 | using namespace std::string_literals; 79 | //----------------------------------------------------------------------------- 80 | QString version_string(){ 81 | if ( 0 == std::strlen(_TWEAK_VERSION_NUMBER_)) { 82 | return QString("%1.%3.%3").arg(_MAJOR_VERSION_NUMBER_).arg(_MINOR_VERSION_NUMBER_).arg(_PATCH_VERSION_NUMBER_); 83 | } else { 84 | return QString("%1.%2.%3+%4").arg(_MAJOR_VERSION_NUMBER_).arg(_MINOR_VERSION_NUMBER_).arg(_PATCH_VERSION_NUMBER_).arg(_TWEAK_VERSION_NUMBER_); 85 | } 86 | } 87 | QString full_version_string(){ 88 | if ( 0 == std::strlen(_TWEAK_VERSION_NUMBER_)) { 89 | return QString("%1.%2.%3-%4").arg(_MAJOR_VERSION_NUMBER_).arg(_MINOR_VERSION_NUMBER_).arg(_PATCH_VERSION_NUMBER_).arg(_REV_HASH_); 90 | } else { 91 | return QString("%1.%2.%3+%4-%5").arg(_MAJOR_VERSION_NUMBER_).arg(_MINOR_VERSION_NUMBER_).arg(_PATCH_VERSION_NUMBER_).arg(_TWEAK_VERSION_NUMBER_).arg(_REV_HASH_); 92 | } 93 | } 94 | QString project_name(){ 95 | return _PROJECT_NAME_; 96 | } 97 | QString rev_hash(){ 98 | return _REV_HASH_; 99 | } 100 | QString rev_tag(){ 101 | return _REV_TAG_; 102 | } 103 | 104 | int bgui_major_version() 105 | { 106 | return _MAJOR_VERSION_NUMBER_; 107 | } 108 | int bgui_minor_version() 109 | { 110 | return _MINOR_VERSION_NUMBER_; 111 | } 112 | int bgui_patch_version() 113 | { 114 | return _PATCH_VERSION_NUMBER_; 115 | } 116 | 117 | bool bgui_offical_release() 118 | { 119 | return _OFFICAL_RELEASE_; 120 | } 121 | 122 | QString rev_commit_date(){ 123 | return _REV_COMMIT_DATE_; 124 | } 125 | QString biogears_build_date(){ 126 | return __DATE__; 127 | } 128 | //----------------------------------------------------------------------------- 129 | QString SystemInformation::about() 130 | { 131 | std::locale::global(std::locale()); 132 | std::time_t t = std::time(nullptr); 133 | char mbstr[10]; 134 | std::strftime(mbstr, sizeof(mbstr), "%Y", std::localtime(&t)); 135 | 136 | 137 | return QString("BioGears %1
" 138 | "\nBased on Qt %2 %3 %4
" 139 | "\nlibBioGears %5 - %9
" 140 | "\nBuilt on %6
" 141 | "\nFrom revision %7
" 142 | "\nCopyright 2012-%8 Applied Research Associates
" 143 | "\n
" 144 | "\nThis program is provided AS IS with NO WARRENTY OF ANY KIND
" 145 | "\nINCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
" 146 | "\nFOR A PARTICULAR PURPOSE
") 147 | .arg(_PROJECT_NAME_) 148 | .arg(QT_VERSION) 149 | .arg(_COMPILER_NAME_) 150 | .arg(_COMPILER_VERSION_) 151 | .arg(biogears::version_string().c_str()) 152 | .arg(__DATE__) 153 | .arg(_REV_HASH_) 154 | .arg(mbstr) 155 | .arg(biogears::rev_hash().c_str()); 156 | 157 | 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /projects/ui/cpp/version.h: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | Copyright 2019 Applied Research Associates, Inc. 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the License 5 | at: 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed under 8 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | specific language governing permissions and limitations under the License. 11 | **************************************************************************************/ 12 | 13 | #pragma once 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | namespace bgui { 24 | 25 | QString version_string(); 26 | QString full_version_string(); 27 | QString project_name(); 28 | QString rev_hash(); 29 | QString rev_tag(); 30 | 31 | int bgui_major_version(); 32 | int bgui_minor_version(); 33 | int bgui_patch_version(); 34 | 35 | bool bgui_offical_release(); 36 | 37 | QString rev_commit_date(); 38 | QString biogears_build_date(); 39 | 40 | 41 | class SystemInformation : public QObject { 42 | 43 | public: 44 | QString about(); 45 | 46 | 47 | signals: 48 | void aboutChanged(); 49 | private: 50 | Q_OBJECT 51 | public: 52 | //This Codes Library Info 53 | Q_PROPERTY(QString About READ about NOTIFY aboutChanged) 54 | 55 | }; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /projects/ui/lua/main.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/lua/main.lua -------------------------------------------------------------------------------- /projects/ui/qml/ActionDrawer.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Window 2.12 3 | import QtQml.Models 2.2 4 | import com.biogearsengine.ui.scenario 1.0 5 | 6 | 7 | ActionDrawerForm { 8 | id: root 9 | signal openActionDrawer() 10 | 11 | property Scenario scenario 12 | property Controls controls 13 | property ObjectModel actionModel 14 | 15 | onOpenActionDrawer:{ 16 | if (!root.opened){ 17 | root.open(); 18 | } 19 | } 20 | applyButton.onClicked: { 21 | if (root.opened){ 22 | if (actionDialog.opened){ 23 | actionDialog.close() 24 | actionDialog.setContent("") 25 | } 26 | root.close(); 27 | } 28 | } 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /projects/ui/qml/ControlsForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.12 2 | import QtQuick.Layouts 1.12 3 | import QtQuick 2.12 4 | import QtQuick.Controls.Material 2.12 5 | import QtQml.Models 2.2 6 | 7 | import com.biogearsengine.ui.scenario 1.0 8 | 9 | ColumnLayout { 10 | id: root 11 | spacing: 5 12 | Layout.preferredHeight: implicitHeight 13 | Layout.preferredWidth: implicitWidth 14 | z : 1 //Setting to higher than graph area so that action messages will not be hidden behind plots 15 | 16 | //property alias patientBox: patientBox 17 | property alias patientMenu: patientMenu 18 | property alias age_yr: age 19 | property alias gender: gender 20 | property alias fat_pct: fat_pct 21 | property alias core_temp_c: core_temp 22 | property alias height_cm: height_cm 23 | property alias weight_kg: weight 24 | property alias bodySufaceArea: bodySurfaceArea 25 | property alias bodyMassIndex: bodyMassIndex 26 | 27 | property alias heartRate : physiology.heartRate 28 | property alias systolicBloodPressure : physiology.systolicBloodPressure 29 | property alias dystolicBloodPressure : physiology.dystolicBloodPressure 30 | property alias respiratoryRate : physiology.respiratoryRate 31 | property alias oxygenSaturation : physiology.oxygenSaturation 32 | property alias condition : physiology.condition 33 | 34 | property alias playback : playback_controls 35 | property alias openDrawerButton : openDrawerButton 36 | property alias loadScenarioButton : loadScenarioButton 37 | property alias actionSwitchView : actionSwitchView 38 | 39 | 40 | PatientMenu { 41 | id : patientMenu 42 | Layout.preferredWidth : root.width 43 | } 44 | RowLayout { 45 | id: configuration_row1 46 | Layout.fillWidth: true 47 | Layout.alignment: Qt.AlignHCenter 48 | UITextInputForm { 49 | id: age 50 | name.text: "Age:" 51 | value.text: "21" 52 | Layout.alignment: Qt.AlignHCenter 53 | } 54 | UITextInputForm { 55 | id: gender 56 | name.text: "Gender:" 57 | value.text: "Female" 58 | Layout.alignment: Qt.AlignHCenter 59 | } 60 | UITextInputForm { 61 | id: fat_pct 62 | name.text: "Fat%:" 63 | value.text: "0.0%" 64 | Layout.alignment: Qt.AlignHCenter 65 | } 66 | UITextInputForm { 67 | id: core_temp 68 | name.text: "Temp:" 69 | value.text: "100.0" 70 | Layout.alignment: Qt.AlignHCenter 71 | } 72 | } 73 | RowLayout { 74 | id:configuration_row2 75 | Layout.fillWidth: true 76 | Layout.alignment: Qt.AlignHCenter 77 | UITextInputForm { 78 | id: height_cm 79 | name.text: "Height:" 80 | value.text: "160" 81 | Layout.alignment: Qt.AlignHCenter 82 | } 83 | UITextInputForm { 84 | id: weight 85 | name.text: "Weight:" 86 | value.text: "Male" 87 | Layout.alignment: Qt.AlignHCenter 88 | } 89 | UITextInputForm { 90 | id: bodySurfaceArea 91 | name.text: "BSA:" 92 | value.text: "1.55" 93 | Layout.alignment: Qt.AlignHCenter 94 | } 95 | UITextInputForm { 96 | id: bodyMassIndex 97 | name.text: "BMI:" 98 | value.text: "36.2" 99 | Layout.alignment: Qt.AlignHCenter 100 | } 101 | } 102 | UIControlPhysiology { 103 | id: physiology 104 | Layout.topMargin : 10 105 | Layout.fillWidth: true 106 | Layout.alignment : Qt.AlignHCenter 107 | } 108 | UIPlaybackForm { 109 | id: playback_controls 110 | Layout.topMargin : 10 111 | Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter 112 | Layout.fillWidth: true 113 | } 114 | RowLayout { 115 | Layout.fillWidth : true 116 | Layout.alignment : Qt.AlignHCenter 117 | UIBioGearsButtonForm { 118 | id : openDrawerButton 119 | enabled : !root.scenarioLoaded 120 | contentItem : Text { 121 | id : drawerText 122 | text : 'Add Actions' 123 | font.pointSize : 12 124 | color : 'white' 125 | horizontalAlignment : Text.AlignHCenter 126 | verticalAlignment : Text.AlignVCenter 127 | } 128 | Layout.preferredWidth: root.width / 2 - spacing 129 | Layout.alignment: Qt.AlignHCenter 130 | implicitHeight : drawerText.implicitHeight * 1.2 131 | } 132 | UIBioGearsButtonForm { 133 | id : loadScenarioButton 134 | contentItem : Text { 135 | id : loadText 136 | text : root.scenarioLoaded ? 'Clear Scenario' : 'Load Scenario' 137 | font.pointSize : 12 138 | color : 'white' 139 | horizontalAlignment : Text.AlignHCenter 140 | verticalAlignment : Text.AlignVCenter 141 | } 142 | Layout.preferredWidth: root.width / 2 - spacing 143 | Layout.alignment: Qt.AlignHCenter 144 | implicitHeight : loadText.implicitHeight * 1.2 145 | } 146 | } 147 | Rectangle { 148 | id : actionButtonWrapper 149 | Layout.preferredWidth : root.width 150 | color : "transparent" 151 | border.width : 0 152 | //This item needs to exactly fill remaining space, or else scroll feature of ListView will not have correct scoll boundaries 153 | //Controls item height is implicit (depends entirely on objects that fill it), so we cannot bind to it without creating a loop. 154 | //Since parent of Controls is main window, root.parent.height gets us an absolute height from which we can subtract other item 155 | //heights to get remaining space for action list view. Note that we need to subtract the height of the file menu bar, which sits 156 | //atop the controls area in the main window. 157 | implicitHeight : root.parent.height - (patientMenu.height + configuration_row1.height + configuration_row2.height + physiology.height + playback_controls.height + openDrawerButton.height + 6 * root.spacing + root.parent.menuArea.height) 158 | ListView { 159 | id : actionSwitchView 160 | clip: true 161 | anchors.fill : parent 162 | spacing : 5 163 | model : root.actionModel //Defined in Controls.qml 164 | property double simTime : 0 165 | } 166 | } 167 | } 168 | /*##^## Designer { 169 | D{i:0;autoSize:true;height:480;width:640} 170 | } 171 | ##^##*/ -------------------------------------------------------------------------------- /projects/ui/qml/CustomPlots.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtCharts 2.3 3 | import QtQuick.Controls 2.12 4 | 5 | import com.biogearsengine.ui.scenario 1.0 6 | 7 | CustomPlotsForm { 8 | id: root 9 | 10 | property real breathingCycles : 0 11 | property string plotName: "" 12 | 13 | property var model : null 14 | property var index : null 15 | property alias rate : root.refresh_rate 16 | property int refreshOffset : 0 17 | 18 | function initializeRespiratoryPVSeries(biogearsData, physiologyRequest, title) { 19 | root.model = biogearsData 20 | root.index = physiologyRequest 21 | root.rate = model.data(physiologyRequest, PhysiologyModel.RateRole) 22 | 23 | root.plotName = "pvCurve" 24 | let pvSeries = root.createSeries(ChartView.SeriesTypeLine, root.plotName, xAxis, yAxis); 25 | root.title = "Pressure-Volume Curve"; 26 | xAxis.titleText = "Pleural Pressure (cmH2O)"; 27 | yAxis.titleText = "Lung Volume (L)"; 28 | 29 | root.refreshOffset = Math.floor(Math.random() * 10); 30 | 31 | switch(model.data(index, PhysiologyModel.RateRole)) { 32 | case 1: 33 | speed_1hz.checked = true 34 | break; 35 | case 5: 36 | speed_5hz.checked = true 37 | break; 38 | case 10: 39 | speed_10hz.checked = true 40 | break; 41 | case -5: 42 | speed_5s.checked = true 43 | break; 44 | case -10: 45 | speed_10s.checked = true 46 | break; 47 | default: 48 | // code block 49 | } 50 | } 51 | 52 | function update(currentTime_s){ 53 | switch (root.title){ 54 | case "Pressure-Volume Curve": 55 | updateRespiratoryPVSeries() 56 | break 57 | default: 58 | console.log("Unknown Graph %1".arg(root.title)) 59 | break 60 | } 61 | } 62 | function updateRespiratoryPVSeries(){ 63 | let maxCycles = 3; 64 | 65 | let pIndex = model.index(0,0,index) 66 | let vIndex = model.index(1,0,index) 67 | let cycleIndex = model.index(2,0,index) 68 | 69 | let pressure = model.data(pIndex, PhysiologyModel.ValueRole) 70 | let volume = model.data(vIndex, PhysiologyModel.ValueRole) / 1000 71 | 72 | root.series(root.plotName).append(pressure, volume) 73 | if ( root.series(root.plotName).count == 1){ 74 | yAxis.min = root.series(root.plotName).at(0).y 75 | yAxis.max = root.series(root.plotName).at(0).y 76 | xAxis.min = root.series(root.plotName).at(0).x 77 | xAxis.max = root.series(root.plotName).at(0).x 78 | } 79 | if ( model.data(cycleIndex, PhysiologyModel.ValueRole) > 0.5 ){ 80 | ++breathingCycles; 81 | } 82 | if (breathingCycles > maxCycles){ 83 | root.series(root.plotName).remove(0); 84 | } 85 | updateDomainAndRange(); 86 | } 87 | 88 | function updateDomainAndRange(){ 89 | let index = root.series(root.plotName).count-1 90 | let newPoint = root.series(root.plotName).at(index) 91 | if(newPoint.x >=0){ 92 | xAxis.min = xAxis.min == 0 ? 0.975 * newPoint.x : Math.min(xAxis.min, Math.floor(0.975 * newPoint.x)) 93 | xAxis.max = xAxis.max == 1 ? 1.025 * newPoint.x : Math.max(xAxis.max, Math.ceil(1.025 * newPoint.x)) 94 | } else { 95 | xAxis.min = xAxis.min == 0 ? 1.025 * newPoint.x : Math.min(xAxis.min, Math.floor(1.025 * newPoint.x)) 96 | xAxis.max = xAxis.max == 1 ? 0.975 * newPoint.x : Math.max(xAxis.max, Math.ceil(0.975 * newPoint.x)) 97 | } 98 | if(newPoint.y >=0){ 99 | yAxis.min = yAxis.min == 0 ? 0.975 * newPoint.y : Math.min(yAxis.min, Math.floor(0.975 * newPoint.y)) 100 | yAxis.max = yAxis.max == 1 ? 1.025 * newPoint.y : Math.max(yAxis.max, Math.ceil(1.025 * newPoint.y)) 101 | } else { 102 | yAxis.min = Math.min(yAxis.min, 1.025 * newPoint.y) 103 | yAxis.max = Math.max(yAxis.max, 0.975 * newPoint.y) 104 | } 105 | } 106 | 107 | function clear(){ 108 | let series = root.series(root.plotName) 109 | let count = series.count 110 | series.removePoints(0,series.count) 111 | xAxis.min = 0 112 | xAxis.max = 1 113 | yAxis.min = 0 114 | yAxis.max = 1 115 | } 116 | 117 | function resizePlot(newWidth, newHeight){ 118 | root.width = newWidth 119 | root.height = newHeight 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /projects/ui/qml/CustomPlotsForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.12 2 | import QtQuick 2.12 3 | import QtQuick.Controls.Material 2.12 4 | import QtCharts 2.3 5 | 6 | ChartView { 7 | id: root 8 | 9 | legend.visible : false 10 | theme : ChartView.ChartThemeBlueCerulean 11 | titleFont.pointSize : 12 12 | titleFont.bold : true 13 | antialiasing: true 14 | property alias xAxis : xAxis 15 | property alias yAxis : yAxis 16 | 17 | property alias speed_1hz : speed_lhz 18 | property alias speed_5hz : speed_5hz 19 | property alias speed_10hz : speed_10hz 20 | property alias speed_5s : speed_5s 21 | property alias speed_10s : speed_10s 22 | 23 | property alias refresh_rate : contextMenu.refresh_rate 24 | ValueAxis { 25 | id: xAxis 26 | } 27 | ValueAxis { 28 | id: yAxis 29 | labelFormat: (max < 1.)? '%.3f' : (max < 10.)? '%.2f' : (max < 100.) ? '%.1f' : (max < 10000.) ? '%.0f' : '%.2e' 30 | tickCount : 3 31 | } 32 | MouseArea { 33 | anchors.fill : parent 34 | acceptedButtons: Qt.LeftButton | Qt.RightButton 35 | onClicked: { 36 | if (mouse.button === Qt.RightButton){ 37 | contextMenu.popup() 38 | } 39 | } 40 | onPressAndHold: { 41 | if (mouse.source === Qt.MouseEventNotSynthesized) 42 | contextMenu.popup() 43 | } 44 | Menu { 45 | id: contextMenu 46 | 47 | property int refresh_rate : rateGroup.checkedButton.rate 48 | 49 | Label { text: "Refresh Rate"; font.pixelSize: 16; font.bold: true} 50 | ButtonGroup { 51 | id: rateGroup 52 | } 53 | Row{ 54 | id: rateRow1; 55 | RadioButton{id:speed_lhz; property int rate: 1; text: "1hz"; ButtonGroup.group:rateGroup; checked: true} 56 | RadioButton{id:speed_5hz; property int rate: 5; text: "5hz"; ButtonGroup.group:rateGroup} 57 | RadioButton{id:speed_10hz; property int rate: 10; text: "10hz"; ButtonGroup.group:rateGroup} 58 | } 59 | Row{ 60 | id: rateRow2; 61 | RadioButton{id:speed_5s; property int rate: -5; text: "5s" ; ButtonGroup.group:rateGroup} 62 | RadioButton{id:speed_10s; property int rate: -10; text: "10s"; ButtonGroup.group:rateGroup} 63 | } 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /projects/ui/qml/LuaConsole.qml: -------------------------------------------------------------------------------- 1 | 2 | import QtQuick 2.4 3 | import QtQuick.Controls 2.12 4 | import QtQuick.Controls.Material 2.12 5 | import QtCharts 2.3 6 | import QtQml.Models 2.2 7 | 8 | import com.biogearsengine.ui.scenario 1.0 9 | 10 | 11 | LuaConsoleForm{ 12 | id:root 13 | property LogForward feeds 14 | 15 | function clear() { 16 | content.text = "" 17 | } 18 | 19 | onFeedsChanged : { 20 | feeds.messageReceived.connect(messageHandler) 21 | } 22 | 23 | Component.onCompleted : { 24 | scrollTo(Qt.Vertical,1.0) 25 | } 26 | 27 | onHeightChanged : { 28 | scrollTo(Qt.Vertical,1.0) 29 | } 30 | function messageHandler(message){ 31 | content.text += message + "\n" 32 | scrollTo(Qt.Vertical,1.0) 33 | } 34 | 35 | /** 36 | * @param type [Qt.Horizontal, Qt.Vertical] 37 | * @param ratio 1.0 to 1.0 38 | */ 39 | function scrollTo(type, ratio) { 40 | var scrollFunc = function (bar, ratio) { 41 | bar.position = ratio - bar.size 42 | } 43 | scrollFunc(view.ScrollBar.vertical, ratio) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /projects/ui/qml/LuaConsoleForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.4 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Controls.Material 2.12 4 | import QtQuick.Layouts 1.3 5 | import QtCharts 2.3 6 | import QtQml.Models 2.2 7 | 8 | 9 | Rectangle { 10 | property alias view : consoleView 11 | property alias content : consoleArea 12 | 13 | id: root 14 | Layout.margins: 0 15 | ScrollView { 16 | id: consoleView 17 | 18 | anchors.left : root.left 19 | anchors.right : root.right 20 | anchors.top : root.top 21 | height: root.height * .93 22 | 23 | // contentWidth : consoleArea.contentWidth 24 | 25 | TextArea { 26 | id: consoleArea 27 | height: root.height * .93 28 | width : root.width 29 | readOnly : true 30 | textFormat : TextEdit.RichText 31 | placeholderText :"--> Results Here\n" 32 | } 33 | } 34 | //Removing Until we have real LUA Scripting 35 | // RowLayout { 36 | // id : inputRow 37 | // anchors.top : consoleView.bottom 38 | // anchors.left : root.left 39 | // anchors.right : root.right 40 | 41 | // TextInput { 42 | // id:input 43 | // text :":\> Place Holder" 44 | // clip:true 45 | // Layout.maximumHeight : 25 46 | // Layout.preferredHeight : 25 47 | // Layout.fillWidth : true 48 | // } 49 | // Button { 50 | // text : "Submit" 51 | // Layout.fillWidth : true 52 | // Layout.preferredWidth : 50 53 | // Layout.maximumWidth : 75 54 | // Layout.maximumHeight : 25 55 | // } 56 | // } 57 | } -------------------------------------------------------------------------------- /projects/ui/qml/Main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Controls.Material 2.12 4 | import QtQuick.Layouts 1.12 5 | import QtQuick.Dialogs 1.2 6 | 7 | import QtGraphicalEffects 1.12 8 | 9 | import com.biogearsengine.ui.scenario 1.0 10 | 11 | 12 | ApplicationWindow { 13 | id: root 14 | visible: true 15 | 16 | width: 1280 17 | height: 768 18 | 19 | MainForm { 20 | anchors.rightMargin: 0 21 | anchors.bottomMargin: 1 22 | anchors.leftMargin: 0 23 | anchors.topMargin: -1 24 | anchors.fill : parent 25 | Component.onCompleted : { 26 | } 27 | controls.onPlayClicked: { 28 | graphArea.start() 29 | } 30 | controls.onPauseClicked: { 31 | graphArea.pause(paused) 32 | } 33 | controls.onRestartClicked: { 34 | graphArea.restart() 35 | } 36 | controls.onSpeedToggled: { 37 | graphArea.speedToggled(speed) 38 | } 39 | controls.onOpenActionDrawer: { 40 | actionDrawer.openActionDrawer(); 41 | } 42 | controls.onPatientPhysiologyChanged : { 43 | graphArea.newPhysiologyModel(model) 44 | consoleArea.clear() 45 | } 46 | controls.onDataRequestModelChanged : { 47 | menuArea.newDataRequestModel(requestTree) 48 | } 49 | controls.onLoadScenarioToBuilder : { 50 | menuArea.loadScenarioToBuilder(events, requests, sampling) 51 | } 52 | controls.onNewActiveSubstance : { 53 | graphArea.newActiveSubstance(subIndex) 54 | } 55 | controls.onUrinalysisDataChanged : { 56 | graphArea.urinalysis = controls.urinalysisData 57 | } 58 | graphArea.onUrinalysisRequest : { 59 | controls.requestUrinalysis() 60 | } 61 | } 62 | Info { 63 | id : info 64 | } 65 | footer: RowLayout { 66 | layoutDirection: Qt.RightToLeft 67 | Image { 68 | id: help 69 | Layout.bottomMargin: 4 70 | Layout.rightMargin: 4 71 | source : "icons/help.svg" 72 | sourceSize.width : 10 73 | sourceSize.height: 10 74 | MouseArea { 75 | anchors.fill : help 76 | onClicked: { infoBox.open() } 77 | } 78 | } 79 | Popup { 80 | id: infoBox 81 | width: 500; height: 300 82 | parent: Overlay.overlay 83 | anchors.centerIn: Overlay.overlay 84 | closePolicy: Popup.CloseOnEscape 85 | Image { 86 | id: infoBox_image 87 | source : "icons/biogears_logo.png" 88 | sourceSize.width : 100 89 | sourceSize.height: 100 90 | anchors.verticalCenter: parent.verticalCenter 91 | } 92 | Text { 93 | id: infoBox_text 94 | anchors.left: infoBox_image.right 95 | anchors.verticalCenter: parent.verticalCenter 96 | anchors.leftMargin: 5 97 | text : info.About 98 | } 99 | Button { 100 | id: infoBox_button 101 | text : "Ok!" 102 | onClicked: infoBox.close() 103 | anchors.bottom : parent.bottom 104 | anchors.right: parent.right 105 | } 106 | } 107 | } 108 | } 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /projects/ui/qml/MainForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Layouts 1.12 3 | import QtQuick.Controls 2.12 4 | import QtQuick.Controls.Material 2.12 5 | 6 | import com.biogearsengine.ui.scenario 1.0 7 | import QtQuick.Window 2.12 8 | 9 | GridLayout { 10 | id: root 11 | columns: 2 12 | rows: 3 13 | rowSpacing:0 14 | columnSpacing:0 15 | property alias scenario : controls.scenario 16 | property alias menuArea : menuArea 17 | property alias controls : controls 18 | property alias actionModel : controls.actionModel 19 | property alias graphArea: graphArea 20 | property alias consoleArea : consoleArea 21 | property alias actionDrawer : actionDrawer 22 | 23 | MenuArea { 24 | id: menuArea 25 | Layout.row : 0 26 | Layout.column : 0 27 | Layout.preferredWidth : root.width * (1/4) - root.columnSpacing / 2; 28 | } 29 | 30 | ActionDrawer { 31 | id: actionDrawer 32 | width : controls.width 33 | scenario : root.scenario 34 | controls : root.controls 35 | actionModel : root.actionModel 36 | } 37 | Controls { 38 | id: controls 39 | Layout.row : 1 40 | Layout.column : 0 41 | Layout.fillWidth: true 42 | Layout.maximumWidth : root.width * (1/4) - root.columnSpacing / 2; 43 | Layout.fillHeight: true 44 | Layout.rowSpan : 2 45 | } 46 | 47 | GraphArea { 48 | id: graphArea 49 | Layout.row : 0 50 | Layout.column : 1 51 | Layout.rowSpan : 2 52 | Layout.fillWidth: true 53 | Layout.maximumWidth : root.width * (4/5) - root.columnSpacing / 2; 54 | Layout.fillHeight: false 55 | Layout.preferredHeight:root.height * (4./5.)-10; 56 | Layout.margins:0 57 | } 58 | LuaConsole { 59 | id:consoleArea 60 | Layout.row : 2 61 | Layout.column : 1 62 | Layout.fillWidth: true 63 | Layout.fillHeight: true 64 | Layout.preferredHeight : root.height * (1./5.) - 10; 65 | Layout.margins:0 66 | Layout.alignment : Qt.AlignTop 67 | feeds : root.scenario.feeds 68 | 69 | } 70 | 71 | } 72 | 73 | /*##^## Designer { 74 | D{i:0;autoSize:true;height:720;width:1280} 75 | } 76 | ##^##*/ 77 | -------------------------------------------------------------------------------- /projects/ui/qml/MenuArea.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.4 2 | import com.biogearsengine.ui.scenario 1.0 3 | 4 | MenuAreaForm { 5 | id : root 6 | signal newDataRequestModel(DataRequestModel requestTree) 7 | signal loadScenarioToBuilder(EventModel events, var requests, string sampling) 8 | 9 | onNewDataRequestModel : { 10 | root.scenarioBuilder.bgRequests = requestTree 11 | } 12 | onLoadScenarioToBuilder : { 13 | scenarioBuilder.loadScenario(events, requests, sampling) 14 | } 15 | 16 | function parseToolsSelection (dataType, mode){ 17 | var biogearsTypes = { 18 | PATIENT : 'Patient', 19 | ENVIRONMENT : 'Environment', 20 | SUBSTANCE : 'Substance', 21 | COMPOUND : 'Compound', 22 | NUTRITION : 'Nutrition', 23 | ECG : 'ECG' 24 | } 25 | switch (dataType){ 26 | case biogearsTypes.PATIENT : 27 | if (mode === "Export"){ 28 | scenario.export_patient() 29 | } else { 30 | wizardDialog.launchPatient(mode) 31 | } 32 | break; 33 | case biogearsTypes.ENVIRONMENT : 34 | if (mode === "Export"){ 35 | scenario.export_environment() 36 | } else { 37 | wizardDialog.launchEnvironment(mode) 38 | } 39 | break; 40 | case biogearsTypes.SUBSTANCE : 41 | wizardDialog.launchSubstance(mode) 42 | break; 43 | case biogearsTypes.COMPOUND : 44 | wizardDialog.launchCompound(mode) 45 | break; 46 | case biogearsTypes.NUTRITION : 47 | wizardDialog.launchNutrition(mode) 48 | break; 49 | case biogearsTypes.ECG : 50 | wizardDialog.launchECG(mode) 51 | break; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /projects/ui/qml/PatientMenu.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import com.biogearsengine.ui.scenario 1.0 4 | 5 | PatientMenuForm { 6 | id: root 7 | 8 | function loadState(fileName){ 9 | biogears_scenario.restart(fileName) 10 | } 11 | 12 | function updateText(fileName){ 13 | console.log(fileName) 14 | var split_prop = fileName.split("@") 15 | if (split_prop.length > 1){ 16 | patientText.text = "Patient: " + split_prop[0] + "@" + split_prop[1].split(".")[0] 17 | } else { 18 | patientText.text = "Patient: " + split_prop[0].split(".")[0] 19 | } 20 | } 21 | 22 | function buildPatientMenu(){ 23 | patientMenuListModel.clear() 24 | var list = biogears_scenario.get_nested_patient_state_list(); 25 | for (var i = 0; i < list.length;++i) { 26 | var split_files = list[i].split(",") 27 | var patient_name = split_files.shift() 28 | var split_objects = [] 29 | for (var k = 0;k < split_files.length;++k) { 30 | split_objects.push({"propName" : split_files[k]}) 31 | } 32 | var menu_entry = {"patientName" : patient_name, "props" : split_objects} 33 | patientMenuListModel.append(menu_entry) 34 | } 35 | } 36 | 37 | Component.onCompleted: { 38 | root.loadState("DefaultMale@0s.xml") 39 | patientText.text = "Patient: DefaultMale@0s" 40 | root.buildPatientMenu() 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /projects/ui/qml/PatientMenuForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import com.biogearsengine.ui.scenario 1.0 4 | 5 | Button { 6 | id: patientMenuButton 7 | property alias patientText : patientText 8 | property alias patientMenuListModel : patientMenuListModel 9 | flat: true 10 | highlighted: false 11 | implicitHeight : patientText.implicitHeight * 2 12 | background : Rectangle { 13 | anchors.fill : parent 14 | color : "lightgray" 15 | border.color : "black" 16 | } 17 | Text { 18 | id : patientText 19 | anchors.fill : parent 20 | text : "Select Patient" // If you actually see this then something is very wrong 21 | font.capitalization : Font.MixedCase 22 | fontSizeMode : Text.Fit 23 | horizontalAlignment : Text.AlignHCenter 24 | verticalAlignment : Text.AlignVCenter 25 | } 26 | Menu { 27 | id : patientMenu 28 | x : -200 29 | y : 50 30 | closePolicy : Popup.CloseOnEscape | Popup.CloseOnReleaseOutside 31 | Instantiator { 32 | id : menuItemInstance 33 | model : patientMenuListModel 34 | delegate : Menu { 35 | id : patientSubMenu 36 | title : patientName 37 | property string patient : patientName 38 | property var repeaterModel : [] //Assign when object is added to instantiator to make sure that model exists 39 | Repeater { 40 | id : subMenuInstance 41 | model : repeaterModel 42 | delegate : MenuItem { 43 | Button { 44 | anchors.fill : parent 45 | flat : true 46 | highlighted : false 47 | text : propName 48 | onClicked : { 49 | patientMenu.close() 50 | if (!biogears_scenario.isRunning || biogears_scenario.isPaused){ // This should be redundant with the check to open the Menu, but I'm including it to be safe 51 | //Update text before loading state because menu checks text against new patient to determine whether 52 | // the name is correct (this check catches instances when state is loaded via "File->Load" vs patient menu) 53 | root.updateText(propName) 54 | root.loadState(propName) 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | onObjectAdded : { 62 | object.repeaterModel = patientMenuListModel.get(index).props 63 | patientMenu.insertMenu(index, object) 64 | } 65 | onObjectRemoved : { 66 | patientMenu.removeMenu(object) 67 | } 68 | } 69 | } 70 | onClicked: { 71 | if (!biogears_scenario.isRunning || biogears_scenario.isPaused) { 72 | if (patientMenu.visible) { 73 | patientMenu.close() 74 | } else { 75 | patientMenu.open() 76 | } 77 | } 78 | } 79 | 80 | ListModel { 81 | id : patientMenuListModel 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /projects/ui/qml/actions/UIPatientAssessment.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Window 2.12 3 | import QtQuick.Controls 2.12 4 | import QtQuick.Layouts 1.12 5 | import QtQml.Models 2.2 6 | import com.biogearsengine.ui.scenario 1.0 7 | 8 | UIActionForm { 9 | id: root 10 | color: "transparent" 11 | border.color: "black" 12 | 13 | property string type_str : "" 14 | property int type : { 15 | switch(type_str){ 16 | case "PulmonaryFunctionTest": 17 | return 0; 18 | case "CompleteBloodCount": 19 | return 1; 20 | case "MetabolicPanel": 21 | return 2; 22 | case "SOFA": 23 | return 3; 24 | case "Urinalysis": 25 | return 4; 26 | default : 27 | return -1; 28 | } 29 | } 30 | 31 | property bool validBuildConfig : type > -1 32 | 33 | actionType : "Patient Assessment" 34 | actionClass : EventModel.PatientAssessmentRequest 35 | fullName : "%1(%2)".arg(actionType).arg(type_str) 36 | shortName : "%2".arg(type_str) 37 | 38 | //Builder mode data -- data passed to scenario builder 39 | buildParams : "Type=" + type + ";" 40 | //Interactive mode -- TODO add assessments to runtime actions if we think necessary 41 | 42 | 43 | builderDetails : Component { 44 | id : builderDetails 45 | GridLayout { 46 | id: grid 47 | columns : 3 48 | rows : 3 49 | width : root.width -5 50 | anchors.centerIn : parent 51 | signal clear() 52 | onClear : { 53 | requestCombo.item.currentIndex = -1 54 | root.type_str = ""; 55 | root.type = -1; 56 | startTimeLoader.item.clear() 57 | } 58 | Label { 59 | id : actionLabel 60 | Layout.row : 0 61 | Layout.column : 0 62 | Layout.columnSpan : 3 63 | Layout.fillHeight : true 64 | Layout.fillWidth : true 65 | Layout.preferredWidth : grid.width * 0.5 66 | font.pixelSize : 20 67 | font.bold : true 68 | color : "blue" 69 | leftPadding : 5 70 | text : "%1".arg(actionType) 71 | } 72 | //Row 2 73 | RowLayout { 74 | id : requestWrapper 75 | Layout.maximumWidth : grid.width / 3 76 | Layout.fillWidth : true 77 | Layout.fillHeight : true 78 | Layout.row : 1 79 | Layout.column : 0 80 | Label { 81 | id: requestLabel 82 | font.pixelSize : 18 83 | text : "Type" 84 | leftPadding : 5 85 | } 86 | Loader { 87 | id : requestCombo 88 | sourceComponent : comboInput 89 | property var _combo_model : ['Pulmonary Function Test', 'Complete Blood Count', 'Metabolic Panel', 'SOFA', 'Urinalysis'] //Same order that requests appear in Patient Assessment Enum in schema 90 | property var _initial_value : root.type_str 91 | Layout.fillWidth : true 92 | Layout.maximumWidth : grid.width / 3 - 1.2 * requestLabel.width - parent.spacing 93 | } 94 | Connections { 95 | target : requestCombo.item 96 | onActivated : { 97 | root.type = target.currentIndex 98 | root.type_str = target.textAt(target.currentIndex) 99 | } 100 | } 101 | } 102 | Loader { 103 | id : startTimeLoader 104 | sourceComponent : timeEntry 105 | onLoaded : { 106 | item.entryName = "Start Time" 107 | Layout.row = 1 108 | Layout.column = 1 109 | Layout.alignment = Qt.AlignHCenter 110 | Layout.fillWidth = true 111 | Layout.fillHeight = true 112 | Layout.maximumWidth = grid.width / 5 113 | if (actionStartTime_s > 0.0){ 114 | item.reload(actionStartTime_s) 115 | } 116 | } 117 | } 118 | Connections { 119 | target : startTimeLoader.item 120 | onTimeUpdated : { 121 | root.actionStartTime_s = totalTime_s 122 | } 123 | } 124 | Rectangle { 125 | //placeholder for spacing 126 | color : "transparent" 127 | Layout.row : 1 128 | Layout.column : 2 129 | Layout.preferredHeight : requestWrapper.height //recs need preferred dimension explicity stated (not sure why fill width/height not enough to accomplish this) 130 | Layout.fillWidth : true 131 | Layout.maximumWidth : grid.width / 3 132 | Layout.fillHeight : true 133 | } 134 | 135 | //Row 3 136 | Rectangle { 137 | //placeholder for spacing 138 | color : "transparent" 139 | Layout.row : 2 140 | Layout.column : 0 141 | Layout.preferredHeight : requestWrapper.height //recs need preferred dimension explicity stated (not sure why fill width/height not enough to accomplish this) 142 | Layout.fillWidth : true 143 | Layout.maximumWidth : grid.width / 3 144 | Layout.fillHeight : true 145 | } 146 | Rectangle { 147 | Layout.row : 2 148 | Layout.column : 1 149 | Layout.fillWidth : true 150 | Layout.fillHeight : true 151 | Layout.preferredHeight : requestWrapper.height 152 | Layout.maximumWidth : grid.width / 3 153 | color : "transparent" 154 | border.width : 0 155 | Button { 156 | text : "Set Action" 157 | opacity : validBuildConfig ? 1 : 0.4 158 | anchors.centerIn : parent 159 | height : parent.height 160 | width : parent.width / 2 161 | onClicked : { 162 | if (validBuildConfig){ 163 | viewLoader.state = "collapsedBuilder" 164 | root.buildSet(root) 165 | } 166 | } 167 | } 168 | } 169 | Rectangle { 170 | Layout.row : 2 171 | Layout.column : 2 172 | Layout.fillWidth : true 173 | Layout.fillHeight : true 174 | Layout.preferredHeight : requestWrapper.height 175 | Layout.maximumWidth : grid.width / 3 176 | color : "transparent" 177 | border.width : 0 178 | Button { 179 | text : "Clear Fields" 180 | anchors.centerIn : parent 181 | height : parent.height 182 | width : parent.width / 2 183 | onClicked : { 184 | grid.clear() 185 | } 186 | } 187 | } 188 | 189 | } 190 | } //end builder details component 191 | } -------------------------------------------------------------------------------- /projects/ui/qml/actions/UISerialize.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Window 2.12 3 | import QtQuick.Controls 2.12 4 | import QtQuick.Layouts 1.12 5 | import QtQml.Models 2.2 6 | import com.biogearsengine.ui.scenario 1.0 7 | 8 | UIActionForm { 9 | id: root 10 | color: "transparent" 11 | border.color: "black" 12 | property string fileName : "" 13 | 14 | property bool validBuildConfig : fileName !=="" 15 | 16 | actionType : "Serialize State" 17 | actionClass : EventModel.SerializeState 18 | fullName : "%1".arg(actionType) 19 | shortName : "%1".arg(actionType) 20 | 21 | //Builder mode data -- data passed to scenario builder 22 | buildParams : "Filename=" + fileName + ";" 23 | //Interactive mode -- not defining interactive mode for serialize currently (we already have 'Save State' for interactive 24 | 25 | builderDetails : Component { 26 | id : builderDetails 27 | GridLayout { 28 | id: grid 29 | columns : 3 30 | rows : 3 31 | width : root.width -5 32 | anchors.centerIn : parent 33 | signal clear() 34 | onClear : { 35 | startTimeLoader.item.clear() 36 | } 37 | Label { 38 | id : actionLabel 39 | Layout.row : 0 40 | Layout.column : 0 41 | Layout.columnSpan : 3 42 | Layout.fillHeight : true 43 | Layout.fillWidth : true 44 | Layout.preferredWidth : grid.width * 0.5 45 | font.pixelSize : 20 46 | font.bold : true 47 | color : "blue" 48 | leftPadding : 5 49 | text : "%1".arg(actionType) 50 | } 51 | //Row 2 52 | RowLayout { 53 | id : nameWrapper 54 | Layout.maximumWidth : grid.width / 3 55 | Layout.fillWidth : true 56 | Layout.fillHeight : true 57 | Layout.row : 1 58 | Layout.column : 0 59 | Label { 60 | id: nameLabel 61 | font.pixelSize : 18 62 | bottomPadding : 8 63 | text : "File Name: " 64 | Layout.alignment : Qt.AlignRight 65 | leftPadding : 5 66 | } 67 | TextField { 68 | id : nameField 69 | placeholderText : "Name" 70 | text : root.fileName 71 | Layout.fillWidth : true 72 | font.pixelSize : 18 73 | Layout.alignment : Qt.AlignHCenter 74 | horizontalAlignment : TextInput.AlignHCenter 75 | onTextEdited : { 76 | root.fileName = text 77 | } 78 | } 79 | } 80 | Loader { 81 | id : startTimeLoader 82 | sourceComponent : timeEntry 83 | onLoaded : { 84 | item.entryName = "Start Time" 85 | Layout.row = 1 86 | Layout.column = 1 87 | Layout.alignment = Qt.AlignHCenter 88 | Layout.fillWidth = true 89 | Layout.fillHeight = true 90 | Layout.maximumWidth = grid.width / 5 91 | if (actionStartTime_s > 0.0){ 92 | item.reload(actionStartTime_s) 93 | } 94 | } 95 | } 96 | Connections { 97 | target : startTimeLoader.item 98 | onTimeUpdated : { 99 | root.actionStartTime_s = totalTime_s 100 | } 101 | } 102 | Rectangle { 103 | //placeholder for spacing 104 | color : "transparent" 105 | Layout.row : 1 106 | Layout.column : 2 107 | Layout.preferredHeight : nameWrapper.height //recs need preferred dimension explicity stated (not sure why fill width/height not enough to accomplish this) 108 | Layout.fillWidth : true 109 | Layout.maximumWidth : grid.width / 3 110 | Layout.fillHeight : true 111 | } 112 | //Row 3 113 | Rectangle { 114 | //placeholder for spacing 115 | color : "transparent" 116 | Layout.row : 2 117 | Layout.column : 0 118 | Layout.preferredHeight : nameWrapper.height //recs need preferred dimension explicity stated (not sure why fill width/height not enough to accomplish this) 119 | Layout.fillWidth : true 120 | Layout.maximumWidth : grid.width / 3 121 | Layout.fillHeight : true 122 | } 123 | Rectangle { 124 | Layout.row : 2 125 | Layout.column : 1 126 | Layout.fillWidth : true 127 | Layout.fillHeight : true 128 | Layout.preferredHeight : 50 129 | Layout.maximumWidth : grid.width / 3 130 | color : "transparent" 131 | border.width : 0 132 | Button { 133 | text : "Set Action" 134 | opacity : validBuildConfig ? 1 : 0.4 135 | anchors.centerIn : parent 136 | height : parent.height 137 | width : parent.width / 2 138 | onClicked : { 139 | if (validBuildConfig){ 140 | viewLoader.state = "collapsedBuilder" 141 | root.buildSet(root) 142 | } 143 | } 144 | } 145 | } 146 | Rectangle { 147 | Layout.row : 2 148 | Layout.column : 2 149 | Layout.fillWidth : true 150 | Layout.fillHeight : true 151 | Layout.preferredHeight : 50 152 | Layout.maximumWidth : grid.width / 3 153 | color : "transparent" 154 | border.width : 0 155 | Button { 156 | text : "Clear Fields" 157 | anchors.centerIn : parent 158 | height : parent.height 159 | width : parent.width / 2 160 | onClicked : { 161 | grid.clear() 162 | } 163 | } 164 | } 165 | } 166 | } //end builder details component 167 | } -------------------------------------------------------------------------------- /projects/ui/qml/dashboards/VitalsPanel.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.4 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Controls 1.4 4 | import QtQuick.Controls.Material 2.12 5 | import QtQuick.Extras 1.4 6 | import QtQuick.Controls.Styles 1.4 7 | import QtQuick.Layouts 1.3 8 | import QtCharts 2.3 9 | import QtQml.Models 2.2 10 | 11 | import com.biogearsengine.ui.scenario 1.0 12 | 13 | Item { 14 | id: root 15 | 16 | property alias vitalsGridView: vitalsGridView 17 | //property alias vitalsTimer : vitalsTimer 18 | 19 | Image { 20 | id: biogears_background 21 | source : "qrc:/icons/biogears_noBackground.png" 22 | width : plots.width 23 | height: plots.height 24 | anchors.centerIn : parent 25 | fillMode: Image.PreserveAspectFit 26 | Rectangle { 27 | id : colorBackground 28 | anchors.fill : biogears_background 29 | color : "#ecf0f1" 30 | opacity : 0.95 31 | } 32 | } 33 | GridView { 34 | id : vitalsGridView 35 | anchors.fill : parent 36 | anchors.bottomMargin : 20 37 | clip : true 38 | cellWidth : parent.width / 2 39 | cellHeight : parent.height / 2 40 | model : vitalsModel 41 | ScrollBar.vertical : ScrollBar { 42 | parent : vitalsGridView.parent 43 | anchors.top : vitalsGridView.top 44 | anchors.right : vitalsGridView.right 45 | anchors.bottom : vitalsGridView.bottom 46 | 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIActionDialogForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.3 5 | 6 | /* 7 | Brief: Defines a blank dialog window containing a 1 x 1 grid and standard buttons for customization of action editor dialog 8 | */ 9 | 10 | Dialog { 11 | id: dialogForm 12 | //Properties -- used to customize the functionality / look of the dialog window 13 | property var actionProps : ({}) 14 | property int numRows : 1 15 | property int numColumns : 1 16 | property int colSpace: 0 17 | property int rowSpace : 0 18 | property string errorString : "" 19 | property alias dialogLoader: dialogLoader 20 | property alias dialogItem : dialogLoader.item 21 | //Base properties 22 | width : 500 23 | height : 250 24 | bottomPadding : 0 25 | bottomInset : 0 26 | bottomMargin : 0 27 | modal : false 28 | closePolicy : Popup.NoAutoClose 29 | //Header 30 | header : Rectangle { 31 | id : headerBackground 32 | width : parent.width 33 | height : 30 34 | color: "#2980b9" 35 | border.color: "#2980b9" 36 | Text { 37 | id:content 38 | anchors.fill : parent 39 | text: dialogForm.title 40 | font.pointSize : 12 41 | leftPadding : 10 42 | color: "white" 43 | horizontalAlignment: Text.AlignLeft 44 | verticalAlignment: Text.AlignVCenter 45 | } 46 | } 47 | //Add standard buttons to footer 48 | footer : DialogButtonBox { 49 | UIBioGearsButtonForm { 50 | text : "Save" 51 | font.pixelSize : 16 52 | DialogButtonBox.buttonRole: DialogButtonBox.ApplyRole 53 | implicitHeight : 30 54 | implicitWidth : 80 55 | } 56 | UIBioGearsButtonForm { 57 | text : "Reset" 58 | font.pixelSize : 16 59 | DialogButtonBox.buttonRole: DialogButtonBox.ResetRole 60 | implicitHeight : 30 61 | implicitWidth : 80 62 | } 63 | UIBioGearsButtonForm { 64 | text : "Cancel" 65 | font.pixelSize : 16 66 | DialogButtonBox.buttonRole: DialogButtonBox.RejectRole 67 | implicitHeight : 30 68 | implicitWidth : 80 69 | } 70 | } 71 | contentItem : Loader { 72 | id : dialogLoader 73 | sourceComponent : undefined 74 | width : root.width 75 | anchors.top : header.bottom 76 | anchors.bottom : footer.top 77 | } 78 | } 79 | 80 | 81 | 82 | 83 | /*##^## Designer { 84 | D{i:0;autoSize:true;height:0;width:0} 85 | } 86 | ##^##*/ 87 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIActionSwitch.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Window 2.12 3 | import QtQml.Models 2.2 4 | 5 | UIActionSwitchForm { 6 | id: root 7 | 8 | property int scrollCount : 0 9 | property bool supportDeactivate : true 10 | property bool activated : false 11 | signal toggleActionOn() 12 | signal toggleActionOff() 13 | 14 | 15 | actionSwitch.onPositionChanged : { 16 | if(actionSwitch.position == 1 && !activated){ 17 | root.toggleActionOn(); 18 | activated = !activated 19 | } 20 | else if (supportDeactivate) { 21 | root.toggleActionOff(); 22 | activated = !activated 23 | } 24 | else { 25 | console.log('Action status cannot be changed once activated') 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIActionSwitchForm.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.12 2 | import QtQuick 2.12 3 | 4 | import com.biogearsengine.ui.scenario 1.0 5 | 6 | Row { 7 | id : actionRow 8 | spacing : 5 9 | property string nameLong 10 | property string namePretty 11 | property bool active : false 12 | property alias actionSwitch : actionSwitch 13 | property alias labelMouseArea : labelMouseArea 14 | property alias actionLabel : actionLabel 15 | 16 | Label { 17 | id : actionLabel 18 | width : parent.width * 3/4 - actionRow.spacing / 2 19 | height : parent.height * 0.9 20 | color : '#1A5276' 21 | text : actionRow.namePretty 22 | elide : Text.ElideRight 23 | font.pointSize : 12 24 | font.bold : true 25 | horizontalAlignment : Text.AlignLeft 26 | leftPadding : 5 27 | verticalAlignment : Text.AlignVCenter 28 | background : Rectangle { 29 | id : labelBackground 30 | anchors.fill : parent 31 | color : 'transparent' 32 | border.color : 'grey' 33 | border.width : 0 34 | } 35 | MouseArea { 36 | id : labelMouseArea 37 | anchors.fill : parent 38 | acceptedButtons : Qt.RightButton 39 | } 40 | ToolTip { 41 | id : actionTip 42 | parent : actionLabel 43 | x : 0 44 | y : parent.height + 5 45 | visible : labelMouseArea.pressed 46 | text : actionRow.nameLong 47 | contentItem : Text { 48 | text : actionTip.text 49 | color : '#1A5276' 50 | font.pointSize : 10 51 | } 52 | background : Rectangle { 53 | color : "white" 54 | border.color : "black" 55 | } 56 | } 57 | 58 | } 59 | Switch { 60 | id : actionSwitch 61 | width : parent.width * 1/4 - actionRow.spacing / 2 62 | height : parent.height 63 | position : 0 64 | } 65 | } 66 | 67 | /*##^## Designer { 68 | D{i:0;autoSize:true;height:480;width:640} 69 | } 70 | ##^##*/ 71 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIBioGearsButtonForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.3 5 | 6 | /* 7 | Brief: A standard button for BioGears interface 8 | */ 9 | Button { 10 | id : root 11 | property string primary : "#4CAF50" 12 | property string secondary : "#339933" 13 | padding : 0 14 | enabled : true 15 | background : Rectangle { 16 | id : background 17 | anchors.fill : parent 18 | radius : 5 19 | color : enabled ? primary : "#0B6623" 20 | } 21 | contentItem : Text { 22 | text : root.text 23 | color : "white" 24 | font : root.font 25 | horizontalAlignment : Text.AlignHCenter 26 | verticalAlignment: Text.AlignVCenter 27 | } 28 | onPressed : { 29 | background.color = secondary 30 | } 31 | onReleased : { 32 | background.color = primary 33 | } 34 | } 35 | 36 | /*##^## Designer { 37 | D{i:0;autoSize:true;height:0;width:0} 38 | } 39 | ##^##*/ -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIComboBox.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | import Qt.labs.folderlistmodel 2.12 4 | 5 | UIComboBoxForm { 6 | id: root 7 | //----------Signals and Handlers------------------ 8 | 9 | // Emit new value to dialog window when new entry selected from menu 10 | signal comboUpdate(string currentSelection) 11 | 12 | //Emit when dialog window Reset is detected 13 | signal resetCombo() 14 | 15 | // Handle new entry seleted from menu (according to model type) and emit comboUpdate 16 | comboBox.onActivated : { 17 | comboUpdate(comboBox.currentText) 18 | /*if (comboBox.model instanceof ListModel){ 19 | comboUpdate(comboBox.model.get(comboBox.currentIndex)[comboBox.textRole]) 20 | } else if (comboBox.model instanceof FolderListModel) { 21 | comboUpdate(comboBox.model.get(comboBox.currentIndex, comboBox.textRole)); 22 | } else { 23 | comboUpdate(comboBox.model.get(comboBox.currentIndex)) 24 | }*/ 25 | } 26 | 27 | // Handle reset signal by clearing box 28 | onResetCombo : { 29 | comboBox.currentIndex = -1 30 | comboUpdate("") 31 | } 32 | 33 | //---------Functions---------------------------- 34 | 35 | //---------------------------------------------- 36 | //Generates description of property for dialog window description assembly 37 | function getDescription(){ 38 | if (comboBox.currentIndex!=-1 && comboBox.model instanceof ListModel){ 39 | return label.text + " = " + comboBox.model.get(comboBox.currentIndex)[comboBox.textRole] 40 | } else if (comboBox.currentIndex!=-1 && comboBox.model instanceof FolderListModel){ 41 | return label.text + " = " + comboBox.model.get(comboBox.currentIndex, comboBox.textRole) 42 | } else { 43 | return '' 44 | } 45 | } 46 | //---------------------------------------------- 47 | //A combo box property is valid if the index is not equal to -1 (meaning nothing displayed in box) 48 | function isValid(){ 49 | return root.required ? comboBox.currentIndex != -1 : true 50 | } 51 | 52 | } 53 | 54 | 55 | 56 | 57 | /*##^## Designer { 58 | D{i:0;autoSize:true;height:0;width:0} 59 | } 60 | ##^##*/ 61 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIComboBoxForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.3 5 | 6 | /* 7 | Brief: A label and comboBox (dropdown menu) laid out in a row 8 | */ 9 | 10 | RowLayout { 11 | id: root 12 | //Properties -- used to customize look/functionality of component 13 | property real elementRatio : 0.5 //Element ratio used to adjust relative sizes of label and box. Default is to split available space evenly 14 | property real prefWidth : parent.width 15 | property real prefHeight 16 | property int colSpan : 1 17 | property int rowSpan : 1 18 | property bool required : true 19 | property bool available : true 20 | spacing : 20 21 | property string splitToken //When we use ComboBox with a FolderModel, we often want to only use part of file name. fileBaseName property helps get rid of file type (like .xml), but sometimes there is still info appended to name that 22 | //we do not want to display (e.g. PatientState@0s vs PatientState). This splitToken tells which character to split the file name at. 23 | property bool folderModel : false 24 | //Property aliases -- used to access subcomponents outside form file 25 | property alias label: name 26 | property alias comboBox: value 27 | //Layout options 28 | Layout.preferredHeight : prefHeight ? prefHeight : root.implicitHeight //If no preferred height, use implicit height determined by layout 29 | Layout.preferredWidth : prefWidth 30 | Layout.alignment : Qt.AlignHCenter | Qt.AlignVCenter 31 | 32 | //States 33 | state : "available" //Initial state is available 34 | states : [ 35 | State { 36 | //When the field is available for input it is fully opaque and enabled 37 | name : "available" ; when : root.available 38 | PropertyChanges {target : name; opacity : 1.0; enabled : true} 39 | PropertyChanges {target : value; opacity : 1.0; enabled : true} 40 | }, 41 | State { 42 | //When the field is unavailble for editing, turn down opacity ("ghost" out) and disable so that it cannot accept input 43 | name : "unavailable"; when : !root.avaialble 44 | PropertyChanges {target : name; opacity : 0.5; enabled : false} 45 | PropertyChanges {target : value; opacity : 0.5; enabled : false} 46 | } 47 | ] 48 | 49 | Label { 50 | id: name 51 | text: "Unset" 52 | Layout.fillHeight : true 53 | Layout.alignment : Qt.AlignVCenter 54 | verticalAlignment : Text.AlignVCenter 55 | horizontalAlignment : Text.AlignLeft 56 | font.pixelSize : 18 57 | } 58 | ComboBox { 59 | id: value 60 | Layout.maximumWidth : root.prefWidth * (1.0 - elementRatio) 61 | Layout.alignment : Qt.AlignRight | Qt.AlignVCenter 62 | Layout.fillWidth : true 63 | implicitHeight : 40 64 | topInset : 0 65 | bottomInset : 0 66 | padding : 0 67 | font.weight: Font.Medium 68 | font.pixelSize : 18 69 | editable: true 70 | currentIndex : -1 71 | contentItem : Text { 72 | //Controls the look of text that is currently displayed in the combo box 73 | anchors.left : value.left 74 | width : value.width - indicator.width 75 | height : parent.height 76 | text : value.displayText 77 | font : value.font 78 | verticalAlignment : Text.AlignVCenter; 79 | horizontalAlignment : Text.AlignHCenter; 80 | } 81 | delegate : ItemDelegate { 82 | id : comboDelegate 83 | contentItem : Text { 84 | text : comboDelegate.setText() 85 | verticalAlignment : Text.AlignVCenter; 86 | horizontalAlignment : Text.AlignHCenter; 87 | font: value.font; 88 | } 89 | height : value.height 90 | width : parent.width 91 | highlighted : value.highlightedIndex === index; 92 | function setText(){ 93 | if (!value.textRole){ 94 | //Just an array of strings, so return modelData 95 | return modelData 96 | } else { 97 | if (root.splitToken){ 98 | //ListModel with named roles and a delimiter we want to split on 99 | return model[value.textRole].split(root.splitToken)[0] 100 | } 101 | else { 102 | //ListModel with named roles 103 | return model[value.textRole] 104 | } 105 | } 106 | } 107 | } 108 | popup : Popup { 109 | y : value.height 110 | x : 0 111 | padding : 0 112 | width : value.width - value.indicator.width 113 | implicitHeight : contentItem.implicitHeight 114 | contentItem : ListView { 115 | clip : true 116 | implicitHeight : contentHeight 117 | model : value.popup.visible ? value.delegateModel : null 118 | currentIndex : value.highlightedIndex 119 | } 120 | } 121 | background : Rectangle { 122 | id : comboBackground 123 | border.color : "#2980b9" 124 | border.width : 1 125 | } 126 | indicator: Rectangle { 127 | id: indicator 128 | anchors.right : parent.right 129 | y: 0 130 | height : value.height 131 | width : height 132 | color : "#2980b9" 133 | border.color : "#2980b9" 134 | Image { 135 | source : "icons/comboIndicatorWhite.png" 136 | height : parent.height / 4 137 | fillMode : Image.PreserveAspectFit 138 | anchors.centerIn : parent 139 | } 140 | } 141 | } 142 | } 143 | 144 | 145 | 146 | 147 | /*##^## Designer { 148 | D{i:0;autoSize:true;height:0;width:0} 149 | } 150 | ##^##*/ -------------------------------------------------------------------------------- /projects/ui/qml/elements/UICompoundWizard.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Window 2.12 3 | 4 | 5 | UICompoundWizardForm { 6 | id: root 7 | 8 | signal validConfiguration (string type, var data) 9 | signal invalidConfiguration(string errorStr) 10 | signal resetConfiguration() 11 | signal loadConfiguration() 12 | signal nameEdited() 13 | 14 | property string compoundName : "" //Store name separate from list of compounds 15 | property var compoundList : ({}) 16 | property var resetData : ({}) //This will be empty strings when "new Compound", but when "edit Compound" it will be file as when first loaded 17 | property string resetName : "" //Holds the compound name in "Edit" mode in case we revert changes. Store separtely from component data because it makes it easier to operate by looping over components 18 | property bool editMode : false 19 | property bool nameWarningFlagged : false 20 | 21 | Component.onCompleted : { 22 | compoundGridView.forceLayout() //Make sure that all fields are drawn so that when we load data from file there are complete view items to map them to 23 | } 24 | 25 | onLoadConfiguration : { 26 | //Component fields do not exist yet when loading compound from file, so we have to add them to ListModel as we encounter them 27 | for (let sub in compoundList){ 28 | let newComponent = {name: sub, unit: "concentration", type: "double", hint: "", valid: true} 29 | compoundDataModel.append(newComponent) 30 | } 31 | } 32 | 33 | onResetConfiguration : { 34 | //If we are in edit mode, it's easier to wipe all the data and reset it from the merge info than to adjust on an 35 | // element by element basis 36 | if (root.editMode) { 37 | let numNewElements = compoundDataModel.count - Object.keys(root.resetData).length //How many elements were added in addition to the data from the file? 38 | compoundDataModel.clear() //Clear out list model 39 | for (let key in compoundList){ //Clear out data list -- would be nice if there were a "clear" function for JS arrays 40 | delete compoundList[key] 41 | } 42 | //Copy contents of reset data to data list 43 | compoundList = Object.assign({}, resetData); 44 | //Repopulate list model 45 | for (let sub in root.compoundList){ 46 | let newComponent = {name: sub, unit: "concentration", type: "double", hint: "", valid: true} 47 | compoundDataModel.append(newComponent) 48 | } 49 | //Make blank fields corresponding to any entries added after loading data 50 | for (let i = 0; i < numNewElements; ++i){ 51 | let newComponent = {name: "", unit: "concentration", type: "double", hint: "", valid: true} 52 | compoundDataModel.append(newComponent) 53 | } 54 | } 55 | } 56 | 57 | function checkConfiguration(){ 58 | let validConfiguration = true 59 | let errorStr = "*" 60 | //Check name 61 | if (root.compoundName === ""){ 62 | validConfiguration = false 63 | errorStr += "Compound name is a required field\n*" 64 | } 65 | //Check components 66 | for (let i = 0; i < compoundDataModel.count; ++i){ 67 | let validEntry = compoundDataModel.get(i).valid 68 | if (!validEntry){ 69 | validConfiguration = false 70 | errorStr += "Component " + (i+1) + " requires a substance name, concentration, and unit\n*" 71 | } 72 | } 73 | if (validConfiguration){ 74 | let nameData = {"Name" : root.compoundName} 75 | Object.assign(compoundList, nameData); //Need to bundle up "name" with component list because WizardDialog::SaveData expects one object 76 | root.validConfiguration('Compound', compoundList) //'Compound' flag tells Wizard manager which type of data to save 77 | } else { 78 | if (errorStr.charAt(errorStr.length-1)==='*'){ 79 | errorStr = errorStr.slice(0, errorStr.length-1) 80 | } 81 | root.invalidConfiguration(errorStr) 82 | } 83 | } 84 | 85 | function mergeCompoundData(compound){ 86 | //Set name and then remove from map (so that we can loop over all components) 87 | root.compoundName = compound["Name"][0] 88 | root.resetName = root.compoundName //Store loaded name in case we revert 89 | delete compound["Name"] 90 | let subNames = Object.keys(compound) //Getting array directly instead of for (let key in compound) because "key" is then the index, not the sub name, which we need 91 | for (let i = 0; i < subNames.length; ++i){ 92 | let sub = subNames[i] 93 | let componentEntry = {[sub] : compound[sub]} //Putting [] around sub in first item tells JS to use the value of sub, not the string "sub" 94 | Object.assign(compoundList, componentEntry) 95 | } 96 | resetData = Object.assign({}, compoundList) //Copy data to resetData ( can't do = because this does copy by reference 97 | 98 | root.loadConfiguration() 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIControlPhysiology.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.12 2 | import QtQuick.Layouts 1.12 3 | import QtQuick 2.12 4 | import QtQuick.Controls.Material 2.12 5 | 6 | GridLayout { 7 | id: root 8 | layoutDirection: Qt.LeftToRight 9 | antialiasing: false 10 | columns: 3 11 | rows: 2 12 | columnSpacing : 45 13 | rowSpacing : 10 14 | 15 | property alias heartRate : heartRate 16 | property alias systolicBloodPressure : systolicBloodPressure 17 | property alias dystolicBloodPressure : dystolicBloodPressure 18 | property alias respiratoryRate : respiratoryRate 19 | property alias oxygenSaturation : oxygenSaturation 20 | property alias condition : condition 21 | 22 | UIScalarForm { 23 | id:heartRate 24 | Layout.alignment: Qt.AlignHCenter 25 | Layout.margins: 0 26 | name: "HR" 27 | value: "75" 28 | } 29 | UIScalarForm { 30 | id:systolicBloodPressure 31 | Layout.alignment: Qt.AlignHCenter 32 | Layout.margins: 0 33 | name: "SBP" 34 | value: "110" 35 | } 36 | UIScalarForm { 37 | id:respiratoryRate 38 | Layout.alignment: Qt.AlignHCenter 39 | name: "RR" 40 | value: "12" 41 | } 42 | UIScalarForm { 43 | id:dystolicBloodPressure 44 | Layout.alignment: Qt.AlignHCenter 45 | name: "DBP" 46 | value: "68" 47 | } 48 | UIScalarForm { 49 | id:oxygenSaturation 50 | Layout.alignment: Qt.AlignHCenter 51 | name: "SAT" 52 | value: "99" 53 | } 54 | UIScalarForm { 55 | id:condition 56 | Layout.alignment: Qt.AlignHCenter 57 | name: "Conditon" 58 | value: "Running" 59 | } 60 | } 61 | 62 | 63 | 64 | 65 | /*##^## Designer { 66 | D{i:0;width:300} 67 | } 68 | ##^##*/ 69 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIDataRequest.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | 4 | UIDataRequestForm { 5 | id: root 6 | 7 | signal substanceQuantityChanged(string sub, string quantity) 8 | //Helper function to format request name 9 | function displayFormat (role) { 10 | let formatted = role.replace(/([a-z])([A-Z])([a-z])/g, '$1 $2$3') //Formats BloodVolume as "Blood Volume", but formats pH as "pH" 11 | return formatted 12 | } 13 | //Helper function to make sure strings are formatted properly to be sent to data request manager (no white space) 14 | function requestFormat (role){ 15 | let formatted = role.replace(/\s/g, ''); //removes all white space characters 16 | return formatted 17 | } 18 | function formatOutput(){ 19 | let type = "TYPE="; 20 | let name = "NAME="; 21 | let unit = "UNIT=" + unitValue; 22 | let precision = "PRECISION=" + precisionValue; 23 | if (requestRoot === "Compartment"){ 24 | type += (requestBranches[0] + requestRoot) //E.g. "TYPE=GasCompartment" 25 | if (requestLeaf.includes("SubstanceQuantity")){ 26 | name += (requestBranches[1] + "," + requestFormat(quantityValue)) //E.g. "NAME="VenaCava,PartialPressure" (sub stored in 'substanceValue') 27 | } else { 28 | name += (requestBranches[1] + "," + requestFormat(requestLeaf)) //E.g. "NAME=Aorta,Volume" 29 | } 30 | } else { 31 | type += requestRoot //E.g/ "TYPE="Substance" 32 | if (requestRoot === "Substance") { 33 | name += (requestBranches[0] + "," + requestFormat(requestLeaf)) //E.g. "NAME=Albuterol,PlasmaConcentration" 34 | } else { 35 | name += requestFormat(requestLeaf) //E.g. "NAME=MeanArterialPressure" 36 | } 37 | } 38 | let output = type + ";" + name + ";" + unit + ";" + precision 39 | if (requestLeaf.includes("SubstanceQuantity")){ 40 | output += (";" + "SUBSTANCE=" + substanceValue) 41 | } 42 | return output; 43 | } 44 | //Connected to "save" function in scenario builder. 45 | function isValid(){ 46 | if (requestLeaf.includes("SubstanceQuantity")){ 47 | if (unitValue === "" || precisionValue === "" || substanceValue === "" || quantityValue === ""){ 48 | return false 49 | } 50 | } else { 51 | if (unitValue === "" || precisionValue ===""){ 52 | return false 53 | } 54 | } 55 | return true 56 | } 57 | } 58 | 59 | 60 | 61 | 62 | /*##^## Designer { 63 | D{i:0;autoSize:true;height:0;width:0} 64 | } 65 | ##^##*/ 66 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UINutritionWizard.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Window 2.12 3 | 4 | 5 | UINutritionWizardForm { 6 | id: root 7 | 8 | signal validConfiguration (string type, var data) 9 | signal invalidConfiguration(string errorStr) 10 | signal resetConfiguration() 11 | signal loadConfiguration() 12 | signal nameEdited () 13 | 14 | property var nutritionData : ({}) 15 | property var resetData : ({}) //This will be empty strings when "new Nutrition", but when "edit Nutrition" it will be file as when first loaded 16 | property bool editMode : false 17 | property bool nameWarningFlagged : false 18 | 19 | Component.onCompleted : { 20 | for (let i = 0; i < nutritionDataModel.count; ++i){ 21 | let dataObject = {[nutritionDataModel.get(i).name] : [null, null]} 22 | Object.assign(nutritionData, dataObject) 23 | } 24 | nutritionGridView.forceLayout() //Make sure that all fields are drawn so that when we load data from file there are complete view items to map them to 25 | } 26 | 27 | function checkConfiguration(){ 28 | let validConfiguration = true 29 | let errorStr = "*" 30 | for (let i = 0; i < nutritionDataModel.count; ++i){ 31 | let validEntry = nutritionDataModel.get(i).valid 32 | if (!validEntry){ 33 | validConfiguration = false 34 | let invalidField = nutritionDataModel.get(i).name 35 | if (invalidField === "Name"){ 36 | errorStr += invalidField + " is a required field.\n*" 37 | } else { 38 | errorStr += root.displayFormat(invalidField) + " requires both value and unit (or neither to use engine defaults)\n*"; 39 | } 40 | } 41 | } 42 | if (validConfiguration){ 43 | root.validConfiguration('Nutrition', nutritionData) //'nutrition' flag tells Wizard manager which type of data to save 44 | } else { 45 | if (errorStr.charAt(errorStr.length-1)==='*'){ 46 | errorStr = errorStr.slice(0, errorStr.length-1) 47 | } 48 | root.invalidConfiguration(errorStr) 49 | } 50 | } 51 | 52 | function mergeNutritionData(nutrition){ 53 | for (let prop in nutrition){ 54 | nutritionData[prop] = nutrition[prop] 55 | } 56 | resetData = Object.assign({}, nutritionData) //Copy data to resetData ( can't do = because this does copy by reference) 57 | root.loadConfiguration(nutritionData) 58 | } 59 | 60 | function displayFormat (role) { 61 | let formatted = role.replace(/([a-z])([A-Z])/g, '$1 $2') 62 | return formatted 63 | } 64 | 65 | function assignValidator (type) { 66 | if (type === "double"){ 67 | return doubleValidator 68 | } else { 69 | return null 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UINutritionWizardForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.12 2 | import QtQuick 2.12 3 | import QtQuick.Layouts 1.12 4 | 5 | Page { 6 | id : nutritionWizard 7 | anchors.fill : parent 8 | property alias doubleValidator : doubleValidator 9 | property alias nutritionDataModel : nutritionDataModel 10 | property alias nutritionGridView : nutritionGridView 11 | 12 | GridView { 13 | id: nutritionGridView 14 | clip : true 15 | model : nutritionDataModel 16 | anchors.fill : parent 17 | cellHeight : parent.height / 10 18 | cellWidth : parent.width / 2 19 | ScrollIndicator.vertical: ScrollIndicator { } 20 | 21 | delegate : Item { 22 | //Wrapping scalar entry in an item helps us center the rectangle inside the gridview cell. If we tried to 23 | // anchor in center without this, every delegate instance would center itself in the middle of the view (not 24 | // the middle of the individual cell) 25 | id: delegateWrapper 26 | width : nutritionGridView.cellWidth 27 | height : nutritionGridView.cellHeight 28 | UIUnitScalarEntry { 29 | anchors.centerIn : parent 30 | prefWidth : nutritionGridView.cellWidth * 0.9 31 | prefHeight : nutritionGridView.cellHeight * 0.95 32 | label : root.displayFormat(model.name) 33 | unit : model.unit 34 | type : model.type 35 | hintText : model.hint 36 | entryValidator : root.assignValidator(model.type) 37 | function resetComponent(){ 38 | if (root.editMode && resetData[model.name][0]!=null){ 39 | setEntry(resetData[model.name]) 40 | nutritionData[model.name] = resetData[model.name] 41 | } else { 42 | reset() 43 | nutritionData[model.name] = [null, null] 44 | } 45 | } 46 | function loadComponentData(){ 47 | setEntry(nutritionData[model.name]) 48 | } 49 | onInputAccepted : { 50 | root.nutritionData[model.name] = input 51 | if (model.name === "Name" && root.editMode && !nameWarningFlagged){ 52 | root.nameEdited() 53 | nameWarningFlagged = true 54 | } 55 | } 56 | Component.onCompleted : { 57 | //Binds the "valid" role of each element with the validInput property of the entry, with the exception of 58 | //"Name". Since Name is a required input, we need to make sure it is filled. 59 | if (model.name === "Name"){ 60 | model.valid = Qt.binding(function() {return (entry.userInput[0]!= null && entry.userInput[0].length > 0)}) 61 | } else { 62 | model.valid = Qt.binding(function() {return entry.validInput}) 63 | } 64 | //Connect load function of wizard (called when opening an existing nutrition file) to individual entries 65 | root.onLoadConfiguration.connect(loadComponentData) 66 | //Connect wizard reset button to entry reset functions -- if we are editing an existing nutrition file, then restore 67 | //the loaded value on reset. If loaded file had no data for this field (null check), or if we are not in edit mode, then full reset 68 | root.onResetConfiguration.connect(resetComponent) 69 | } 70 | } 71 | } 72 | } 73 | 74 | DoubleValidator { 75 | id : doubleValidator 76 | bottom : 0 77 | decimals : 2 78 | } 79 | 80 | ListModel { 81 | id : nutritionDataModel 82 | ListElement {name : "Name"; unit: ""; type : "string"; hint : "*Required"; valid : true} 83 | ListElement {name : "Carbohydrate"; unit : "mass"; type : "double"; hint : "Mass of carbs to ingest"; valid : true} 84 | ListElement {name : "Protein"; unit : "mass"; type : "double"; hint : "Mass of protein to ingest"; valid : true} 85 | ListElement {name : "Fat"; unit : "mass"; type : "double"; hint : "Mass of fat to ingest"; valid : true} 86 | ListElement {name : "Calcium"; unit : "mass"; type : "double"; hint : "Amount of calcium to ingest"; valid : true} 87 | ListElement {name : "Sodium"; unit : "mass"; type : "double"; hint : "Amount of protein to ingest"; valid : true} 88 | ListElement {name : "Water"; unit : "volume"; type : "double"; hint : "Amount of water to ingest"; valid : true} 89 | } 90 | } 91 | /*##^## Designer { 92 | D{i:0;autoSize:true;height:480;width:640} 93 | } 94 | ##^##*/ 95 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIPatientWizard.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Window 2.12 3 | 4 | 5 | UIPatientWizardForm { 6 | id: root 7 | 8 | signal validConfiguration (string type, var data) 9 | signal invalidConfiguration(string errorStr) 10 | signal resetConfiguration() 11 | signal loadConfiguration() 12 | signal nameEdited () 13 | 14 | property var patientData : ({}) 15 | property var resetData : ({}) //This will be empty strings when "new Patient", but when "edit patient" it will be file as when first loaded 16 | property bool editMode : false 17 | property var invalidEntries: ({}) 18 | property bool nameWarningFlagged : false 19 | 20 | Component.onCompleted : { 21 | for (let i = 0; i < patientDataModel.count; ++i){ 22 | let dataObject = {[patientDataModel.get(i).name] : [null, null]} 23 | Object.assign(patientData, dataObject) 24 | } 25 | patientGridView.forceLayout() //Make sure that all fields are drawn so that when we load data from file there are complete view items to map them to 26 | } 27 | 28 | function checkConfiguration(){ 29 | let validConfiguration = true 30 | let errorStr = "*" 31 | for (let i = 0; i < patientDataModel.count; ++i){ 32 | let validEntry = patientDataModel.get(i).valid 33 | if (!validEntry){ 34 | validConfiguration = false 35 | let invalidField = patientDataModel.get(i).name 36 | if (invalidField === "Name" || invalidField === "Gender"){ 37 | errorStr += invalidField + " is a required field.\n*" 38 | } else { 39 | errorStr += root.displayFormat(invalidField) + " requires both value and unit (or neither to use engine defaults)\n*"; 40 | } 41 | } 42 | } 43 | if (validConfiguration){ 44 | root.validConfiguration('Patient', patientData) //'Patient' flag tells Wizard manager which type of data to save 45 | } else { 46 | if (errorStr.charAt(errorStr.length-1)==='*'){ 47 | errorStr = errorStr.slice(0, errorStr.length-1) 48 | } 49 | root.invalidConfiguration(errorStr) 50 | } 51 | } 52 | 53 | function mergePatientData(patient){ 54 | for (let prop in patient){ 55 | patientData[prop] = patient[prop] 56 | } 57 | resetData = Object.assign({}, patientData) //Copy data to resetData ( can't do = because this does copy by reference) 58 | loadConfiguration(patientData) 59 | } 60 | 61 | function displayFormat (role) { 62 | let formatted = role.replace(/([a-z])([A-Z])/g, '$1 $2') 63 | return formatted 64 | } 65 | 66 | function assignValidator (type) { 67 | if (type === "double"){ 68 | return doubleValidator 69 | } else if (type === "0To1"){ 70 | return fractionValidator 71 | } else if (type === "-1To1") { 72 | return neg1To1Validator 73 | } else { 74 | return null 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIPlaybackForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.3 5 | import QtGraphicalEffects 1.12 6 | 7 | ColumnLayout { 8 | id: root 9 | signal pauseClicked() 10 | signal playClicked() 11 | signal restartClicked() 12 | signal rateToggleClicked(int speed) 13 | 14 | property string simulationTime : "0:00:00" 15 | property alias rate : forward.rate 16 | property alias playing : pause_play.playing; 17 | property alias paused : pause_play.paused; 18 | 19 | property alias resetButton : reset 20 | property alias simButton: pause_play 21 | property alias speedButton : forward 22 | 23 | RowLayout { 24 | spacing: 10 25 | implicitHeight : timeText.implicitHeight * 1.2 26 | Layout.alignment : Qt.AlignHCenter 27 | Label { 28 | id : timeText 29 | text: "Time:" 30 | font.pixelSize : 15 31 | } 32 | Text { 33 | text: root.simulationTime 34 | font.pixelSize : 15 35 | } 36 | } 37 | RowLayout { 38 | spacing : 15 39 | UIBioGearsButtonForm { 40 | id: reset 41 | implicitHeight : 40 42 | implicitWidth : 75 43 | padding : 5 44 | text: "reset" 45 | display: AbstractButton.IconOnly 46 | contentItem : Image { 47 | id : resetImage 48 | fillMode : Image.PreserveAspectFit 49 | source: "icons/reverse.svg" 50 | height : 30 51 | } 52 | ColorOverlay { 53 | id:resetOverlay 54 | anchors.fill: resetImage 55 | source: resetImage 56 | color: "#006400" 57 | visible : reset.pressed 58 | } 59 | onClicked: {root.restartClicked()} 60 | } 61 | UIBioGearsButtonForm { 62 | id: pause_play 63 | implicitHeight : 40 64 | implicitWidth : 75 65 | padding : 5 66 | property bool playing : false; 67 | property bool paused : false; 68 | text: "Simulate" 69 | display: AbstractButton.IconOnly 70 | contentItem : Image { 71 | id : pausePlayImage 72 | fillMode : Image.PreserveAspectFit 73 | source: "icons/play.svg" 74 | height : 30 75 | } 76 | 77 | ColorOverlay { 78 | id:pause_playOverlay 79 | anchors.fill: pausePlayImage 80 | source: pausePlayImage 81 | color: "#006400" 82 | visible : false 83 | } 84 | 85 | state : "Stopped" 86 | onClicked: { 87 | console.log("UIPlaybackForm %1 %2".arg(playing).arg(paused)) 88 | if(playing) { 89 | if(paused){ 90 | state = "Simulating" 91 | } else { 92 | state = "Paused" 93 | } 94 | root.pauseClicked() 95 | } else { 96 | state = "Simulating" 97 | root.playClicked() 98 | } 99 | } 100 | states: [ 101 | State{ 102 | name: "Stopped" 103 | PropertyChanges { target: pause_play; text: "Play" } 104 | PropertyChanges { target: pause_play; playing: false } 105 | PropertyChanges { target: pause_play; paused: false } 106 | PropertyChanges { target: pause_playOverlay; visible: false } 107 | } 108 | ,State { 109 | name: "Simulating" 110 | PropertyChanges { target: pause_play; text: "Pause" } 111 | PropertyChanges { target: pause_play; playing: true } 112 | PropertyChanges { target: pause_play; paused: false } 113 | PropertyChanges { target: pause_playOverlay; visible: true } 114 | } 115 | ,State { 116 | name: "Paused" 117 | PropertyChanges { target: pause_play; text: "Resume" } 118 | PropertyChanges { target: pause_play; playing: true } 119 | PropertyChanges { target: pause_play; paused: true } 120 | PropertyChanges { target: pause_playOverlay; visible: false } 121 | } 122 | ] 123 | } 124 | UIBioGearsButtonForm { 125 | id: forward 126 | implicitHeight : 40 127 | implicitWidth : 75 128 | property int rate : 1 129 | font.capitalization: Font.AllLowercase 130 | display: AbstractButton.IconOnly 131 | padding : 5 132 | contentItem : Image { 133 | id : forwardImage 134 | fillMode : Image.PreserveAspectFit 135 | source: "icons/speedup.svg" 136 | height : 30 137 | 138 | ColorOverlay { 139 | id:fowardOverlay 140 | anchors.fill: forwardImage 141 | source: forwardImage 142 | color: "#006400" 143 | visible : false 144 | } 145 | } 146 | state : "realtime" 147 | onClicked: { 148 | if(rate == 2) { 149 | state = "realtime" 150 | } else { 151 | state = "max" 152 | } 153 | root.rateToggleClicked(rate) 154 | } 155 | states: [ 156 | State { 157 | name: "realtime" 158 | PropertyChanges { target: forward; rate: 1 } 159 | PropertyChanges { target: fowardOverlay; visible: false } 160 | } 161 | ,State { 162 | name: "max" 163 | PropertyChanges { target: fowardOverlay; visible: true } 164 | } 165 | ] 166 | } 167 | } 168 | } 169 | 170 | /*##^## Designer { 171 | D{i:0;height:62;width:271} 172 | } 173 | ##^##*/ 174 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIPlotSeriesForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.12 2 | import QtQuick 2.12 3 | import QtQuick.Controls.Material 2.12 4 | import QtQuick.Layouts 1.11 5 | import QtCharts 2.3 6 | 7 | ChartView { 8 | id: root 9 | legend.visible : false 10 | theme : ChartView.ChartThemeBlueNcs 11 | titleFont.family : "Arial" 12 | titleFont.pointSize : 12 13 | titleFont.bold : true 14 | antialiasing: true 15 | property alias xAxis : xAxis 16 | property alias yAxis : yAxis 17 | 18 | 19 | property bool calculateScale : true; 20 | 21 | property alias timeInterval_m : contextMenu.timeInterval 22 | property alias refresh_rate : contextMenu.refresh_rate 23 | property alias autoScaleEnabled : contextMenu.autoScaleEnabled 24 | property alias userSpecifiedMin : contextMenu.userSpecifiedMin 25 | property alias userSpecifiedMax : contextMenu.userSpecifiedMax 26 | 27 | property alias speed_1hz : speed_lhz 28 | property alias speed_5hz : speed_5hz 29 | property alias speed_10hz : speed_10hz 30 | property alias speed_5s : speed_5s 31 | property alias speed_10s : speed_10s 32 | 33 | localizeNumbers: true 34 | ValueAxis { 35 | id: xAxis 36 | property int tickCount : 5 37 | titleFont.family : "Arial" 38 | titleFont.bold : true 39 | titleText: "Simulation Time (min)" 40 | min: 0 41 | max: timeInterval_m 42 | } 43 | ValueAxis { 44 | id: yAxis 45 | titleFont.family : "Arial" 46 | titleFont.bold : true 47 | labelFormat: (max < 1.)? '%.3f' : (max < 10.)? '%.2f' : (max < 100.) ? '%.1f' : (max < 10000.) ? '%.0f' : '%.2e' 48 | tickCount : 5 49 | } 50 | MouseArea { 51 | anchors.fill : parent 52 | anchors.centerIn : parent 53 | acceptedButtons: Qt.LeftButton | Qt.RightButton 54 | onClicked: { 55 | if (mouse.button === Qt.RightButton) 56 | contextMenu.popup() 57 | } 58 | onPressAndHold: { 59 | if (mouse.source === Qt.MouseEventNotSynthesized) 60 | contextMenu.popup() 61 | } 62 | Menu { 63 | id: contextMenu 64 | 65 | property int timeInterval : (range_1.checked) ? 1 : (range_5.checked) ? 5 : (range_10.checked) ? 10 : 1 66 | property int refresh_rate : rateGroup.checkedButton.rate 67 | property alias autoScaleEnabled : autoEnabled.checked 68 | property double userSpecifiedMin : yAxis.min 69 | property double userSpecifiedMax : yAxis.max 70 | 71 | Label { text: "Refresh Rate"; font.pixelSize: 16; font.bold: true} 72 | ButtonGroup { id: rateGroup } 73 | Row{ 74 | id: rateRow1; 75 | RadioButton{id:speed_lhz; property int rate: 1; text: "1hz"; ButtonGroup.group:rateGroup; checked: false} 76 | RadioButton{id:speed_5hz; property int rate: 5; text: "5hz"; ButtonGroup.group:rateGroup; checked : false} 77 | RadioButton{id:speed_10hz; property int rate: 10; text: "10hz"; ButtonGroup.group:rateGroup; checked : true} 78 | } 79 | Row{ 80 | id: rateRow2; 81 | RadioButton{id:speed_5s; property int rate: -5; text: "5s" ; ButtonGroup.group:rateGroup; checked : false} 82 | RadioButton{id:speed_10s; property int rate: -10; text: "10s"; ButtonGroup.group:rateGroup; checked : false} 83 | } 84 | Label { text: "Time Scale"; font.pixelSize: 16; font.bold: true} 85 | Row{ 86 | RadioButton{ id:range_1; text: "1 min"; checked : true} 87 | RadioButton{id:range_5; text: "5 min"; checked : false} 88 | RadioButton{id:range_10; text: "10 min"; checked: false} 89 | } 90 | MenuSeparator {} 91 | Label { text : "Scaling"; font.pixelSize: 16; font.bold: true } 92 | CheckBox { id: autoEnabled; text: "Automatic"; checked: true} 93 | GridLayout{ 94 | columns : 4 95 | rows : 2 96 | anchors.left : parent.left ; anchors.right: parent.right; 97 | Label{ 98 | font.pixelSize: 14 99 | font.italic: true 100 | text: "Min" 101 | Layout.columnSpan: 2 102 | Layout.alignment: Qt.AlignHCenter|Qt.AlignVCenter 103 | } 104 | Label{ 105 | font.pixelSize: 14 106 | font.italic: true 107 | text: "Max" 108 | Layout.columnSpan: 2 109 | Layout.alignment:Qt.AlignHCenter|Qt.AlignVCenter 110 | } 111 | TextField{ 112 | text: (contextMenu.autoScaleEnabled) ? "%1".arg(yAxis.min) : userSpecifiedMin; 113 | horizontalAlignment: TextInput.AlignHCenter 114 | Layout.alignment:Qt.AlignHCenter|Qt.AlignVCenter 115 | Layout.preferredWidth : 50 116 | maximumLength : 7 117 | enabled : ! contextMenu.autoScaleEnabled 118 | onEditingFinished:{ 119 | userSpecifiedMin = parseFloat(text) 120 | } 121 | } 122 | Label{ 123 | font.pixelSize: 10 124 | font.bold: true 125 | text: yAxis.titleText 126 | Layout.alignment:Qt.AlignHCenter|Qt.AlignVCenter 127 | } 128 | TextField{ 129 | text: (contextMenu.autoScaleEnabled) ? "%1".arg(yAxis.max) : userSpecifiedMax 130 | horizontalAlignment: TextInput.AlignHCenter 131 | Layout.alignment:Qt.AlignHCenter|Qt.AlignVCenter 132 | Layout.preferredWidth : 50 133 | maximumLength : 7 134 | enabled : ! contextMenu.autoScaleEnabled 135 | onEditingFinished:{ 136 | userSpecifiedMax = parseFloat(text) 137 | } 138 | } 139 | Label{ 140 | font.pixelSize: 10 141 | font.bold: true 142 | text: yAxis.titleText 143 | Layout.alignment:Qt.AlignHCenter|Qt.AlignVCenter 144 | } 145 | } 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIRadioButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | import Qt.labs.folderlistmodel 2.12 4 | 5 | UIRadioButtonForm { 6 | id: root 7 | //--------Signals and Handlers------------------- 8 | 9 | //Emit when new radio selection is made 10 | signal radioGroupUpdate (int value) 11 | 12 | //Emit when dialog Reset signal is detected 13 | signal resetRadio() 14 | 15 | //Handle radio button clicked and emit radioUpdate with index of button (use index because we mostly use these buttons for passing to C++ based enums, which are int based) 16 | radioGroup.onClicked : { 17 | radioGroupUpdate(button.buttonIndex) 18 | } 19 | 20 | //Handle reset signal by unchecking all radio buttons in group 21 | onResetRadio : { 22 | radioGroup.checkState = Qt.Unchecked 23 | } 24 | 25 | //---------Functions---------------------------- 26 | 27 | //---------------------------------------------- 28 | //Generates description of property for dialog window description assembly 29 | function getDescription(){ 30 | return label.text + " = " + buttonModel[radioGroup.checkedButton.buttonIndex] 31 | } 32 | 33 | //---------------------------------------------- 34 | //A radio group property is valid if a button is checked (Qt.Unchecked state means no button is checked) 35 | function isValid(){ 36 | return radioGroup.checkState != Qt.Unchecked 37 | } 38 | 39 | } 40 | 41 | 42 | 43 | 44 | /*##^## Designer { 45 | D{i:0;autoSize:true;height:0;width:0} 46 | } 47 | ##^##*/ 48 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIRadioButtonForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.3 5 | 6 | /* 7 | Brief: A label and spinbox laid out in a row for use in action editor dialog boxes 8 | */ 9 | 10 | RowLayout { 11 | id: root 12 | //Properties -- used to customize look / functionality of component 13 | property real elementRatio : 0.5 //Element ratio used to adjust relative sizes of label and box. Default is to split available space evenly 14 | property var buttonModel : [] 15 | //Property aliases -- used to access sub-components outside of form file 16 | property alias label: name 17 | property alias buttonView : buttonView 18 | property alias radioGroup : radioGroup 19 | spacing : 10 20 | 21 | Label { 22 | id: name 23 | text: "Unset" 24 | horizontalAlignment : Text.AlignHCenter 25 | verticalAlignment : Text.AlignVCenter 26 | font.pixelSize : 18 27 | font.bold: false 28 | } 29 | 30 | ButtonGroup { 31 | id: radioGroup 32 | exclusive : true 33 | } 34 | 35 | ListView { 36 | id : buttonView 37 | implicitHeight : contentHeight 38 | Layout.maximumWidth : root.prefWidth * (1.0 - elementRatio) 39 | Layout.fillWidth : true 40 | Layout.alignment : Qt.AlignVCenter | Qt.AlignRight 41 | orientation : ListView.Vertical 42 | model : buttonModel 43 | delegate : RadioDelegate { 44 | id : radioDelegate 45 | ButtonGroup.group : radioGroup 46 | text : modelData 47 | height : 1.1 * buttonText.implicitHeight 48 | width : root.prefWidth * (1.0 - root.elementRatio) 49 | property int buttonIndex : index 50 | contentItem : Text { 51 | id : buttonText 52 | text : radioDelegate.text 53 | font.pixelSize : label.font.pixelSize 54 | x : delegateIndicator.width 55 | leftPadding : 10 56 | horizontalAlignment : Text.AlignLeft 57 | verticalAlignment : Text.AlignVCenter 58 | } 59 | indicator : Rectangle { 60 | id : delegateIndicator 61 | implicitWidth : 20 62 | implicitHeight : 20 63 | radius : 25 64 | x : 0 65 | y : radioDelegate.height / 2 - height / 2 66 | color : "transparent" 67 | border.color : "#2980b9" 68 | border.width : 2 69 | Rectangle { 70 | id : checkedDisplay 71 | width : 0.5 * parent.width 72 | height : 0.5 * parent.height 73 | radius : 25 74 | color : "#2980b9" 75 | anchors.centerIn : parent 76 | visible : radioDelegate.checked 77 | } 78 | } 79 | background : Rectangle { 80 | id : delegateBackground 81 | height : radioDelegate.height 82 | width : radioDelegate.width 83 | color : "transparent" 84 | border.color : "black" 85 | border.width : 0 //Set this to non-zero to visualize button locations 86 | } 87 | } 88 | } 89 | 90 | 91 | } 92 | 93 | 94 | 95 | 96 | /*##^## Designer { 97 | D{i:0;autoSize:true;height:0;width:0} 98 | } 99 | ##^##*/ 100 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIScalarForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Layouts 1.12 3 | import QtQuick.Controls 2.5 4 | import QtQuick.Controls.Material 2.3 5 | 6 | ColumnLayout { 7 | property alias value: value.text 8 | property alias name: name.text 9 | 10 | implicitHeight : (value.implicitHeight + name.implicitHeight) * 1.2 //Text and laber have implicit height based on font size. Define natural column size as 20% above combined height to give cushion 11 | Text { 12 | id: value 13 | Layout.alignment: Qt.AlignHCenter 14 | horizontalAlignment : Text.AlignHCenter 15 | text: "22" 16 | font.pixelSize: 20 17 | } 18 | Label { 19 | id: name 20 | text: "Age:" 21 | font.pixelSize: 14 22 | Layout.alignment: Qt.AlignHCenter 23 | horizontalAlignment : Text.AlignHCenter 24 | } 25 | } 26 | 27 | 28 | 29 | 30 | /*##^## Designer { 31 | D{i:0;height:54;width:30} 32 | } 33 | ##^##*/ 34 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIScenarioTimelineForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | 4 | Rectangle { 5 | id: root 6 | color :"red" 7 | } -------------------------------------------------------------------------------- /projects/ui/qml/elements/UISpinBox.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | import Qt.labs.folderlistmodel 2.12 4 | 5 | UISpinBoxForm { 6 | id: root 7 | //--------Signals and Handlers------------------- 8 | 9 | //Emit new value to dialog window when spin box value changes 10 | signal spinUpdate (real value) 11 | 12 | //Emit when dialog Reset signal is detected 13 | signal resetSpin() 14 | 15 | //Handle new spin box value (adjusted for scaling if necesary) and emit spinUpdate 16 | spinBox.onValueModified : { 17 | spinUpdate(spinBox.value / spinScale) 18 | } 19 | 20 | //Handle reset signal by setting spin box value back to 0 21 | onResetSpin : { 22 | if (resetValue === null){ 23 | spinBox.value = 0 24 | } else { 25 | spinBox.value = resetValue 26 | } 27 | spinUpdate(spinBox.value) 28 | } 29 | 30 | //---------Functions---------------------------- 31 | 32 | //---------------------------------------------- 33 | //Generates description of property for dialog window description assembly 34 | function getDescription(){ 35 | let dispValue = spinBox.value / spinScale 36 | if (displayEnum.length > 0){ 37 | dispValue = displayEnum[spinBox.value] 38 | } 39 | return label.text + " = " + dispValue 40 | } 41 | 42 | //---------------------------------------------- 43 | //A spin box property needs to return a non-zero value for the action to be valid 44 | function isValid(){ 45 | return root.required ? spinBox.value != 0 : true 46 | } 47 | 48 | //---------------------------------------------- 49 | //Generates value stored by spin box according to enum value (text) displayed in editable area 50 | //This function is assigned to the SpinBox property valueFromText when the displayEnum property is set 51 | //Ex : If displayEnum is ['Mild', 'Medium', 'Severe'] and current selection is 'Medium', spin box 52 | // will store value = 1 53 | function valueFromEnum (text) { 54 | if (displayEnum.length == 0){ 55 | console.log('UISpinBoxForm: You must define displayEnum property') 56 | return -1; 57 | } else { 58 | for (let i = 0; i < displayEnum.length; ++i){ 59 | if (displayEnum[i] == spinBox.text){ 60 | return i 61 | } 62 | } 63 | return spinBox.value 64 | } 65 | } 66 | 67 | //---------------------------------------------- 68 | //Generates text to display in editable area according to current stored spin box value 69 | //This function is assigned to the SpinBox property textFromValue when the displayEnum property is set 70 | //Ex : If displayEnum is ['Mild', 'Medium', 'Severe'] and stored value = 2, then spin box will display 71 | // 'Severe' 72 | function valueToEnum (value){ 73 | if (displayEnum.length == 0){ 74 | console.log('UISpinBoxForm: You must define displayEnum property') 75 | return -1 76 | } else { 77 | return displayEnum[value] 78 | } 79 | } 80 | 81 | //---------------------------------------------- 82 | //Generates value stored by spin box when the display text is adjusted to represented a decimal value 83 | //This function is assigned to the SpinBox property valueFromText when the unitScale property = true 84 | //The display text is assumed to be scaled by the maximum possible input for the spin box 85 | //Ex : If spin box displays 0.2 and spin.to = 100, then spin box will store 20 86 | //Note that the scaled value (spin.value / spin.to) is then passed to spinUpdate 87 | function valueFromDecimal (text, locale) { 88 | return Number.fromLocaleString(locale, text) * spinScale 89 | } 90 | 91 | //---------------------------------------------- 92 | //Generates text to be displayed by spin box so that stored value can be represented as a decimal 93 | //This function is assigned to the SpinBox property textFrom when the unitScale property = true 94 | //The display text is assumed to be scaled by the maximum possible input for the spin box 95 | //Ex : If spin box value = 30 and spin.to = 100, then 0.3 will be displayed. 96 | //Note that the scaled value (spin.value / spin.to) is then passed to spinUpdate 97 | function valueToDecimal (value ) { 98 | return Number(value/spinScale).toLocaleString('f', 2); //Defaulting to 2 decimals for now 99 | } 100 | } 101 | 102 | 103 | 104 | 105 | /*##^## Designer { 106 | D{i:0;autoSize:true;height:0;width:0} 107 | } 108 | ##^##*/ 109 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UISpinBoxForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.3 5 | 6 | /* 7 | Brief: A label and spinbox laid out in a row for use in action editor dialog boxes 8 | */ 9 | 10 | RowLayout { 11 | id: root 12 | //Properties -- used to customize look / functionality of component 13 | property real elementRatio : 0.5 //Element ratio used to adjust relative sizes of label and box. Default is to split available space evenly 14 | property real prefWidth : parent.width 15 | property var displayEnum : [] //Text to display insted of values, if desired (e.g. 'Mild', 'Moderate', 'Severe' instead of 0, 1, 2) 16 | property int spinScale : 1 //SpinBox does not support float step-sizes. This property scales all spinBox display values so that they are in the range [spin.from/spinScale, spin.to/spinScale] 17 | property int spinMax : 1 18 | property int spinStep : 1 19 | property int colSpan : 1 20 | property int rowSpan : 1 21 | property bool required : true 22 | property bool available : true 23 | property var resetValue : null 24 | spacing : 10 25 | //Property aliases -- used to access sub-components outside of form file 26 | property alias label: name 27 | property alias spinBox : spinBox 28 | 29 | //States 30 | state : "available" //Initial state is available 31 | states : [ 32 | State { 33 | //When the field is available for input it is fully opaque and enabled 34 | name : "available" ; when : root.available 35 | PropertyChanges {target : name; opacity : 1.0; enabled : true} 36 | PropertyChanges {target : spinBox; opacity : 1.0; enabled : true} 37 | }, 38 | State { 39 | //When the field is unavailble for editing, turn down opacity ("ghost" out) and disable so that it cannot accept input 40 | name : "unavailable"; when : !root.avaialble 41 | PropertyChanges {target : name; opacity : 0.5; enabled : false} 42 | PropertyChanges {target : spinBox; opacity : 0.5; enabled : false} 43 | } 44 | ] 45 | 46 | Label { 47 | id: name 48 | Layout.fillHeight : true 49 | text: "Unset" 50 | horizontalAlignment : Text.AlignLeft 51 | verticalAlignment : Text.AlignVCenter 52 | font.pixelSize : 18 53 | font.bold: false 54 | } 55 | 56 | SpinBox { 57 | id: spinBox 58 | Layout.maximumWidth : root.prefWidth * (1.0 - elementRatio) 59 | Layout.alignment : Qt.AlignRight 60 | Layout.fillWidth : true 61 | implicitHeight : 40 62 | font.pixelSize : 18 63 | padding : 0 64 | editable : true 65 | value : 0 //Default start at 0 (can override) 66 | from : 0 //Default minimum of 0 (can override) 67 | to : spinMax 68 | stepSize : spinStep 69 | validator : DoubleValidator { 70 | bottom : spinBox.from 71 | top : spinBox.to 72 | } 73 | contentItem : TextInput { 74 | id : spinInput 75 | anchors.verticalCenter : spinBox.verticalCenter 76 | text : spinBox.textFromValue(spinBox.value) 77 | readOnly : !spinBox.editable 78 | topPadding : 5 79 | font.pixelSize : 18 80 | verticalAlignment : TextInput.AlignVCenter 81 | horizontalAlignment : TextInput.AlignHCenter 82 | validator : spinBox.validator 83 | inputMethodHints: Qt.ImhFormattedNumbersOnly 84 | onEditingFinished : { 85 | spinBox.value = spinBox.valueFromText(spinInput.text, spinBox.locale) 86 | } 87 | } 88 | down.indicator: Rectangle { 89 | x: 0 90 | height: spinBox.height 91 | width : spinBox.height 92 | color: "#2980b9" 93 | border.color: "#2980b9" 94 | Text { 95 | text: "-" 96 | font.pixelSize: 20 97 | color: "white" 98 | anchors.fill: parent 99 | fontSizeMode: Text.Fit 100 | horizontalAlignment: Text.AlignHCenter 101 | verticalAlignment: Text.AlignVCenter 102 | } 103 | } 104 | up.indicator: Rectangle { 105 | x: spinBox.width - width 106 | height: spinBox.height 107 | width : spinBox.height 108 | color: "#2980b9" 109 | border.color: "#2980b9" 110 | Text { 111 | text: "+" 112 | font.pixelSize: 20 113 | color: "white" 114 | anchors.fill: parent 115 | fontSizeMode: Text.Fit 116 | horizontalAlignment: Text.AlignHCenter 117 | verticalAlignment: Text.AlignVCenter 118 | } 119 | } 120 | background: Rectangle { 121 | implicitWidth: 140 122 | border.color: "#2980b9" 123 | } 124 | } 125 | } 126 | 127 | 128 | 129 | 130 | /*##^## Designer { 131 | D{i:0;autoSize:true;height:0;width:0} 132 | } 133 | ##^##*/ 134 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UISubstanceEntry.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.3 4 | import QtQuick.Controls.Material 2.3 5 | import com.biogearsengine.ui.scenario 1.0 6 | 7 | UISubstanceEntryForm { 8 | id: root 9 | 10 | signal inputAccepted (var input) 11 | signal substanceUpdateRejected(string previousName) //Emitted if we try to set a component that already exists 12 | 13 | onSubstanceUpdateRejected : { 14 | entry.substanceInput.currentIndex = entry.substanceInput.find(previousName) 15 | } 16 | 17 | function setEntry( fromInput ){ 18 | //Component input is [substance, value, unit]. Trim value down to 2 decimal place. When setting 19 | // based off data loaded from file, we get strings from the text field. Thus, we check typeof input before trimming. 20 | if (fromInput[0]!=null && typeof fromInput[1]=="number"){ 21 | let formattedValue = fromInput[1].toFixed(2) 22 | fromInput[1] = formattedValue 23 | } 24 | root.entry.setFromExisting(fromInput) 25 | } 26 | 27 | function setComponentList(filter) { 28 | let components = [] 29 | if (filter === 'All'){ 30 | components = scenario.get_components() 31 | } 32 | if (filter === 'Aerosol'){ 33 | components = ['Sarin','ForestFireParticulate'] 34 | } 35 | if (filter === 'VolatileDrugs'){ 36 | components = scenario.get_volatile_drugs() 37 | } 38 | for (let i = 0; i < components.length; ++i){ 39 | let element = { "component" : components[i] } 40 | entry.componentListModel.append(element) 41 | } 42 | } 43 | 44 | function reset(){ 45 | root.entry.reset() 46 | } 47 | } 48 | 49 | 50 | 51 | 52 | /*##^## Designer { 53 | D{i:0;autoSize:true;height:480;width:640} 54 | } 55 | ##^##*/ 56 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UITabButtonForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.3 4 | import QtQuick.Controls.Material 2.3 5 | 6 | Rectangle { 7 | id: root 8 | property string text : "unasigned" 9 | color : "transparent" 10 | Layout.fillWidth: true 11 | Layout.fillHeight: true 12 | Text { 13 | id:content 14 | width : parent.width 15 | height : parent.height 16 | text: root.text 17 | font.pointSize : 20 18 | color: "white" 19 | horizontalAlignment: Text.AlignHCenter 20 | verticalAlignment: Text.AlignVCenter 21 | opacity: enabled ? 1.0 : 0.3 22 | elide: Text.ElideRight 23 | } 24 | } 25 | 26 | 27 | 28 | 29 | /*##^## Designer { 30 | D{i:0;autoSize:true;height:480;width:640} 31 | } 32 | ##^##*/ 33 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UITextField.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.3 4 | import QtQuick.Controls.Material 2.3 5 | 6 | UITextFieldForm { 7 | id: root 8 | 9 | //------Signals and Handlers--------------- 10 | 11 | //Emit when dialog Reset signal is detected 12 | signal resetText() 13 | 14 | //Emit new text to dialog window when field is updated 15 | signal textFieldUpdate(string inputText) 16 | 17 | // Handle reset signal by clearing text from field 18 | onResetText : { 19 | if (resetValue === null){ 20 | textField.clear(); 21 | } else { 22 | textField.text = resetValue 23 | } 24 | } 25 | 26 | // Handle newly edited text by calling update signal and passing new value 27 | // By default, this signal is only called if the input is acceptable to validator 28 | textField.onEditingFinished : { 29 | root.textFieldUpdate(textField.text) 30 | } 31 | 32 | // Handle text that has been edited but not valid (outside of range set by validator) 33 | // By constantly clearing invalid text, the user will not be able to enter "bad" data 34 | textField.onTextEdited : { 35 | if (!textField.acceptableInput){ 36 | textField.clear() 37 | } 38 | } 39 | 40 | //---------Functions---------------------------- 41 | 42 | function changeState(newState){ 43 | root.state = newState 44 | if (newState == "nonEditable"){ 45 | textField.clear() 46 | } 47 | } 48 | 49 | //---------------------------------------------- 50 | //Generates description of property for dialog window description assembly 51 | function getDescription(){ 52 | return textField.placeholderText + " = " + textField.text 53 | } 54 | 55 | //---------------------------------------------- 56 | //A text field property is valid if text in an *editable* field is not empty (as determined by length of text) 57 | function isValid() { 58 | if (root.available){ 59 | return root.required ? !(textField.text.length===0) : true 60 | } 61 | return !available 62 | } 63 | 64 | 65 | } 66 | 67 | 68 | 69 | 70 | /*##^## Designer { 71 | D{i:0;autoSize:true;height:480;width:640} 72 | } 73 | ##^##*/ 74 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UITextFieldForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.3 5 | 6 | Item { 7 | id: root 8 | //Properties -- used to customize look / functionality of component 9 | property real prefWidth : parent.width 10 | property real prefHeight : root.implicitHeight 11 | property int colSpan : 1 12 | property int rowSpan : 1 13 | property bool available : true 14 | property bool validateDouble : true 15 | property bool required : true 16 | property real maxValue : Infinity 17 | property var resetValue : null 18 | //Property aliases -- used to access text field sub-properties outside of form file 19 | property alias textField : textField 20 | //Layout options 21 | Layout.preferredWidth : prefWidth 22 | Layout.preferredHeight : prefHeight 23 | Layout.columnSpan : colSpan 24 | Layout.rowSpan : rowSpan 25 | Layout.alignment : Qt.AlignHCenter | Qt.AlignVCenter 26 | 27 | //States 28 | states : [ 29 | State { 30 | //When the field is available for input but not currently being edited, set background border to grey 31 | name : "available-unfocused" ; when : root.available && !textField.activeFocus 32 | PropertyChanges {target : backgroundRect; border.color : "#2980b9"; border.width : 2; opacity : 1.0; enabled : true} 33 | PropertyChanges {target : textField; opacity : 1.0; enabled : true} 34 | }, 35 | State { 36 | //When the field is available for input and being currently edited, set background to green 37 | name : "available-focused"; when : root.available && textField.activeFocus 38 | PropertyChanges {target : backgroundRect; border.color : "#4CAF50"; border.width : 3; opacity : 1.0; enabled : true} 39 | PropertyChanges {target : textField; opacity : 1.0; enabled : true} 40 | }, 41 | State { 42 | //When the field is unavailble for editing, turn off visibility and remove background border 43 | name : "unavailable"; when : !root.avaialble 44 | PropertyChanges {target : backgroundRect; opacity : 0.35; enabled : false} 45 | PropertyChanges {target : textField; opacity : 0.35; enabled : false} 46 | } 47 | ] 48 | 49 | DoubleValidator { 50 | id : doubleValidator 51 | bottom : 0.0 52 | top : root.maxValue 53 | decimals : 3 54 | } 55 | 56 | TextField { 57 | id:textField 58 | //Text field height is dictated by implicit height of text. If you try to set it using height properties, the text will not respect 59 | // the boundaries and will appear out of place w/ respect to other alignment settings. If you need a smaller text field, then you 60 | // need to set the text size smaller (or allow more space in widget for the field). 61 | topInset : 0 62 | bottomInset : 0 63 | padding : 0 64 | anchors.left : parent.left 65 | anchors.right : parent.right 66 | font.pixelSize : 18 67 | verticalAlignment : Text.AlignVCenter 68 | horizontalAlignment : Text.AlignHCenter 69 | validator : validateDouble ? doubleValidator : null 70 | background : Rectangle { 71 | id : backgroundRect 72 | border.width : 1 73 | anchors.fill : parent 74 | color : "transparent" 75 | } 76 | } 77 | } 78 | 79 | 80 | 81 | 82 | /*##^## Designer { 83 | D{i:0;height:25;width:200} 84 | } 85 | ##^##*/ 86 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UITextInputForm.ui.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.5 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.3 5 | 6 | RowLayout { 7 | id: root 8 | property alias name: name 9 | property alias value: value 10 | implicitHeight : name.implictHeight * 2 //Text items have implicit height based on font size. Make this row twice as big to give some cushion 11 | Label { 12 | id: name 13 | text: "Unset" 14 | font.pointSize: 8 15 | font.weight: Font.DemiBold 16 | font.bold: true 17 | //color : "#34495e" 18 | } 19 | 20 | TextInput { 21 | id: value 22 | text: qsTr("Placeholder Text") 23 | font.weight: Font.Medium 24 | font.pixelSize: 10 25 | //color : "#34495e" 26 | } 27 | } 28 | 29 | 30 | 31 | 32 | /*##^## Designer { 33 | D{i:0;height:25;width:200} 34 | } 35 | ##^##*/ 36 | -------------------------------------------------------------------------------- /projects/ui/qml/elements/UIUnitScalarEntry.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.3 4 | import QtQuick.Controls.Material 2.3 5 | 6 | UIUnitScalarEntryForm { 7 | id: root 8 | 9 | signal inputAccepted (var input) 10 | 11 | function setEntry( fromInput ){ 12 | //Trim decimals down to hundredths place. This is necessary when loading from an existing file, since 13 | // QML interprets the QVariant [input, unit] as [number, string] when parsing a double. When setting based off 14 | // values from the editor, we get strings from the text field. Thus, we check if the input is typeof number 15 | // before trimming. 16 | if (fromInput[0]!=null && typeof fromInput[0]=="number"){ 17 | let decimals = root.entryValidator ? root.entryValidator.decimals : 2 18 | let formattedValue = fromInput[0].toFixed(decimals) 19 | fromInput[0] = formattedValue 20 | if(fromInput[0] ==="Infinity"){ 21 | //We only support "inf" values for transport maximum in renal dynamics. Validator doesn't like the infinity string 22 | // so we just set to a really high number. 23 | fromInput[0] = 1e10 24 | } 25 | } 26 | root.entry.setFromExisting(fromInput) 27 | } 28 | 29 | function reset(){ 30 | root.entry.reset() 31 | } 32 | 33 | } 34 | 35 | 36 | 37 | 38 | /*##^## Designer { 39 | D{i:0;autoSize:true;height:480;width:640} 40 | } 41 | ##^##*/ 42 | -------------------------------------------------------------------------------- /projects/ui/qml/img/DownArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/DownArrow.png -------------------------------------------------------------------------------- /projects/ui/qml/img/HospitalRoom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/HospitalRoom.jpg -------------------------------------------------------------------------------- /projects/ui/qml/img/PlotsSelectionIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/PlotsSelectionIcon.png -------------------------------------------------------------------------------- /projects/ui/qml/img/UpArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/UpArrow.png -------------------------------------------------------------------------------- /projects/ui/qml/img/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/add.png -------------------------------------------------------------------------------- /projects/ui/qml/img/add_plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/add_plain.png -------------------------------------------------------------------------------- /projects/ui/qml/img/administer_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/administer_icon.png -------------------------------------------------------------------------------- /projects/ui/qml/img/backwards.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/backwards.png -------------------------------------------------------------------------------- /projects/ui/qml/img/biogears_logo_400_400.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/biogears_logo_400_400.ico -------------------------------------------------------------------------------- /projects/ui/qml/img/biogears_logo_400_400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/biogears_logo_400_400.png -------------------------------------------------------------------------------- /projects/ui/qml/img/biogears_noBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/biogears_noBackground.png -------------------------------------------------------------------------------- /projects/ui/qml/img/burn.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/ui/qml/img/clock-2X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/clock-2X.png -------------------------------------------------------------------------------- /projects/ui/qml/img/clock-max.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/clock-max.png -------------------------------------------------------------------------------- /projects/ui/qml/img/clock-realtime(white_background).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/clock-realtime(white_background).png -------------------------------------------------------------------------------- /projects/ui/qml/img/clock-realtime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/clock-realtime.png -------------------------------------------------------------------------------- /projects/ui/qml/img/collapsedOption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/collapsedOption.png -------------------------------------------------------------------------------- /projects/ui/qml/img/comboIndicatorWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/comboIndicatorWhite.png -------------------------------------------------------------------------------- /projects/ui/qml/img/exercise_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/exercise_icon.png -------------------------------------------------------------------------------- /projects/ui/qml/img/expandedOption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/expandedOption.png -------------------------------------------------------------------------------- /projects/ui/qml/img/foward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/foward.png -------------------------------------------------------------------------------- /projects/ui/qml/img/icon-round-question_mark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /projects/ui/qml/img/insult_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/insult_icon.png -------------------------------------------------------------------------------- /projects/ui/qml/img/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/menu.png -------------------------------------------------------------------------------- /projects/ui/qml/img/menu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/ui/qml/img/menu_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/menu_transparent.png -------------------------------------------------------------------------------- /projects/ui/qml/img/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/next.png -------------------------------------------------------------------------------- /projects/ui/qml/img/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/ui/qml/img/next1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/next1.png -------------------------------------------------------------------------------- /projects/ui/qml/img/next_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/next_transparent.png -------------------------------------------------------------------------------- /projects/ui/qml/img/nursing.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/ui/qml/img/openIndicatorBlue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/openIndicatorBlue.png -------------------------------------------------------------------------------- /projects/ui/qml/img/openIndicatorWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/openIndicatorWhite.png -------------------------------------------------------------------------------- /projects/ui/qml/img/patient.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/ui/qml/img/pause(white_background).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/pause(white_background).png -------------------------------------------------------------------------------- /projects/ui/qml/img/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/pause.png -------------------------------------------------------------------------------- /projects/ui/qml/img/play(white_background).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/play(white_background).png -------------------------------------------------------------------------------- /projects/ui/qml/img/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/play.png -------------------------------------------------------------------------------- /projects/ui/qml/img/play.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/ui/qml/img/playback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/playback.png -------------------------------------------------------------------------------- /projects/ui/qml/img/prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/prev.png -------------------------------------------------------------------------------- /projects/ui/qml/img/prev.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/ui/qml/img/prev1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/prev1.png -------------------------------------------------------------------------------- /projects/ui/qml/img/prev_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/prev_transparent.png -------------------------------------------------------------------------------- /projects/ui/qml/img/question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/question.png -------------------------------------------------------------------------------- /projects/ui/qml/img/remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/remove.png -------------------------------------------------------------------------------- /projects/ui/qml/img/renalPanelNephron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/renalPanelNephron.png -------------------------------------------------------------------------------- /projects/ui/qml/img/renalPanelNephronWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/renalPanelNephronWhite.png -------------------------------------------------------------------------------- /projects/ui/qml/img/reset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/reset.png -------------------------------------------------------------------------------- /projects/ui/qml/img/reverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/reverse.png -------------------------------------------------------------------------------- /projects/ui/qml/img/reverse.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/ui/qml/img/speedup.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/ui/qml/img/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BioGearsEngine/ui/1c9180a60eb1b7f563084daab111d5b3c567f316/projects/ui/qml/img/stop.png -------------------------------------------------------------------------------- /projects/ui/qml/qtquickcontrols2.conf: -------------------------------------------------------------------------------- 1 | [Controls] 2 | Style=Material 3 | 4 | [Universal] 5 | Theme=System 6 | Accent=Red 7 | 8 | [Material] 9 | Theme=Light 10 | Accent=Teal 11 | Primary=BlueGrey 12 | Variant=Dense 13 | 14 | 15 | [Material\Font] 16 | Family=Open Sans 17 | PixelSize=10 18 | -------------------------------------------------------------------------------- /visualizer.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | <NamingElement Priority="10"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="class field" /><type Name="struct field" /></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aa_bb" /></NamingElement> 3 | <NamingElement Priority="9"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="member function" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></NamingElement> 4 | <NamingElement Priority="1"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="__interface" /><type Name="class" /><type Name="struct" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></NamingElement> 5 | <NamingElement Priority="13"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="enumerator" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></NamingElement> 6 | <NamingElement Priority="7"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="global variable" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></NamingElement> 7 | LIVE_MONITOR 8 | LIVE_MONITOR 9 | DO_NOTHING 10 | LIVE_MONITOR 11 | LIVE_MONITOR 12 | LIVE_MONITOR 13 | LIVE_MONITOR 14 | LIVE_MONITOR 15 | LIVE_MONITOR 16 | LIVE_MONITOR 17 | LIVE_MONITOR 18 | DO_NOTHING 19 | LIVE_MONITOR -------------------------------------------------------------------------------- /visualizer.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": {} 8 | } --------------------------------------------------------------------------------