diff --git a/LICENSE b/LICENSE index dfb0c2a..d2890c7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -USACE ERDC ACESTAT + USACE ERDC ACESTAT Copyright (c) 2021 U.S. Army Corps of Engineers Engineering Research and Development Center. All rights reserved. diff --git a/requirements.txt b/requirements.txt index 67aab2e..76435e7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -#acestatpy==2022.4.28.1 # Must be installed from file +#acestatpy==2023.7.5.1 # Must be installed from file matplotlib==3.5.1 PyQt5==5.15.6 pyqtgraph==0.12.3 diff --git a/src/ACEstatGUI.py b/src/ACEstatGUI.py index a1d6aad..c2a9715 100644 --- a/src/ACEstatGUI.py +++ b/src/ACEstatGUI.py @@ -40,7 +40,7 @@ # import random # Global Variables -DEFAULT_BAUD = 9600 +DEFAULT_BAUD = 115200 CONFIGFILE = 'config.ini' CONFIG = LoadConfig(CONFIGFILE) @@ -247,9 +247,9 @@ def showTable(id, test): self.rDisplay = ResultTable([ f"{f.label}{f' ({f.units})' if hasattr(f, 'units') else ''}" - for f in info.fields], list(zip(*reversed([ + for f in info.fields], list(zip(*[ test.results[id][f.label] for f in info.fields - ]))), self) + ])), self) pltLayout.addWidget(self.rDisplay) pltLayout.update() self.rDisplay.setEnabled(True) diff --git a/src/Widgets/NumberSpinBox.py b/src/Widgets/NumberSpinBox.py new file mode 100644 index 0000000..889272c --- /dev/null +++ b/src/Widgets/NumberSpinBox.py @@ -0,0 +1,36 @@ +from PyQt5.QtWidgets import QDoubleSpinBox + + +class NumberSpinBox(QDoubleSpinBox): + def __init__(self, *args): + QDoubleSpinBox.__init__(self, *args) + self.float_min = None + self.float_max = None + + def setFloatRange(self, fmin, fmax): + self.setFloatMin(fmin) + self.setFloatMax(fmax) + + def setFloatMin(self, fmin): + self.float_min = fmin + + def setFloatMax(self, fmax): + self.float_max = fmax + + def validate(self, value, pos): + r = super().validate(value, pos) + v = r[1] + try: + v = float(v) + if v > self.maximum(): + self.setValue(self.maximum()) + if v < self.minimum(): + self.setValue(self.minimum()) + if self.float_max and v > self.float_max: + v = int(v) + elif self.float_min and v < self.float_min: + v = int(v) + v = f"{v}" + except: + pass + return (r[0], v, r[2]) diff --git a/src/Widgets/ResultPanel.py b/src/Widgets/ResultPanel.py index 999d5d3..d5489b3 100644 --- a/src/Widgets/ResultPanel.py +++ b/src/Widgets/ResultPanel.py @@ -18,11 +18,14 @@ QWidget, QFrame, QLabel, QPushButton, QScrollArea, QGridLayout, QVBoxLayout, QHBoxLayout, QSizePolicy, QGridLayout, QMenu, QFileDialog ) +from os import path as _path from datetime import datetime # Local from Widgets import CollapsibleBox, ElideLabel +LASTDIR = None + class ResultItem(QWidget): sigPlot = Signal(str, object) sigTable = Signal(str, object) @@ -132,10 +135,19 @@ def contextMenuEvent(self, event): savePreset = menu.addAction("Save as Preset") action = menu.exec_(self.mapToGlobal(event.pos())) if action == saveResults: - path = QFileDialog.getExistingDirectory( - self, "Choose Directory") - if path: - self.test.export(path) + global LASTDIR + filepath = self.test.generateFilename() + if LASTDIR: + filepath = _path.join(LASTDIR, filepath) + path = QFileDialog.getSaveFileName( + self, "Save Results", filepath, filter="CSV (*.CSV)") + if path[0]: + LASTDIR = _path.split(path[0])[0] + self.test.export(path[0]) + # path = QFileDialog.getExistingDirectory( + # self, "Choose Directory") + # if path: + # self.test.export(path) elif action == savePreset: path = QFileDialog.getSaveFileName( self, "Save Preset", filter="JSON (*.json)") diff --git a/src/Widgets/TestForm.py b/src/Widgets/TestForm.py index bb4ad4e..f6510e2 100644 --- a/src/Widgets/TestForm.py +++ b/src/Widgets/TestForm.py @@ -24,12 +24,12 @@ from PyQt5.QtWidgets import ( QWidget, QFrame, QComboBox, QLabel, QRadioButton, QPushButton, QSpinBox, QScrollArea, QGridLayout, QVBoxLayout, QHBoxLayout, QSizePolicy, QCheckBox, - QStackedWidget, QFileDialog + QStackedWidget, QFileDialog, QDoubleSpinBox ) # Local -from . import ElideLabel, FuncComboBox, GroupComboBox +from . import ElideLabel, FuncComboBox, GroupComboBox, NumberSpinBox class TestParameter(QWidget): @@ -45,6 +45,20 @@ def __init__(self, param, *args, **kwargs): self.input = QSpinBox() self.input.setRange(param.min, param.max) self.input.valueChanged.connect(self.valueChanged) + elif param.type == "float": + self.input = QDoubleSpinBox() + self.input.setRange(param.min, param.max) + self.input.setDecimals(param.precision) + self.input.valueChanged.connect(self.valueChanged) + elif param.type == "number": + self.input = NumberSpinBox() + self.input.setRange(param.min, param.max) + self.input.setDecimals(param.precision) + if param.float_min: + self.input.setFloatMin(param.float_min) + if param.float_max: + self.input.setFloatMax(param.float_max) + self.input.valueChanged.connect(self.valueChanged) elif param.type == "select": self.input = QComboBox() self.input.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength) @@ -64,13 +78,15 @@ def valueChanged(self, val): def setValue(self, value): if isinstance(self.input, QSpinBox): self.input.setValue(int(value)) + elif isinstance(self.input, QDoubleSpinBox): + self.input.setValue(float(value)) elif isinstance(self.input, QComboBox): self.input.setCurrentText(self.param.options[value]) def getValue(self): value = None # Check widget type - if isinstance(self.input, QSpinBox): + if isinstance(self.input, (QSpinBox, QDoubleSpinBox)): value = str(self.input.value()) elif isinstance(self.input, QComboBox): value = list(self.param.options.keys())[self.input.currentIndex()] @@ -101,6 +117,9 @@ def resetPreset(): presets.setCurrentIndex(-1) for id in self.test.parameters: + # Ignore static parameters + if self.test.parameters[id].type == "static": + continue p = self.test.parameters[id] layout.addWidget(QLabel("{0}:".format(p.name)), layout.rowCount(), 0) self.parameters[id] = TestParameter(p) diff --git a/src/Widgets/__init__.py b/src/Widgets/__init__.py index 071aa4a..0851d18 100644 --- a/src/Widgets/__init__.py +++ b/src/Widgets/__init__.py @@ -4,6 +4,7 @@ from . import Images from .PlotCanvas import PlotCanvas from .FuncComboBox import FuncComboBox +from .NumberSpinBox import NumberSpinBox from .TestForm import TestForm from .QueuePanel import QueuePanel from .ResultPanel import ResultPanel