diff --git a/sailsim/gui/SailsimGUI.py b/sailsim/gui/SailsimGUI.py index 17ad939..2991c42 100644 --- a/sailsim/gui/SailsimGUI.py +++ b/sailsim/gui/SailsimGUI.py @@ -1,17 +1,21 @@ """This class is the main GUI for the sailsim project.""" +from typing import Any, Union from PySide6.QtCore import QTimer from PySide6.QtWidgets import QMainWindow from sailsim.gui.boatInspector import BoatInspectorScene from sailsim.gui.mapView import MapViewScene +from sailsim.simulation.Simulation import Simulation from sailsim.gui.qtmain import Ui_MainWindow class SailsimGUI(QMainWindow): """Main GUI for sailsim.""" - def __init__(self, simulation): + frame = 0 + + def __init__(self, simulation: Simulation, varspace: Union[dict[str, Any], None] = None) -> None: """ Create SailsimGUI object. @@ -21,7 +25,10 @@ def __init__(self, simulation): super().__init__() self.simulation = simulation - self.frame = 0 + + self.varspace = {"sailsim": self} + if varspace is not None: + self.varspace.update(varspace) # Load UI from QT generated file self.ui = Ui_MainWindow() @@ -43,22 +50,22 @@ def __init__(self, simulation): self.boatInspectorScene = BoatInspectorScene(simulation.boat) self.ui.boatInspector.setScene(self.boatInspectorScene) + self.ui.valueInspector.setSimulation(simulation) + self.updateFrame(0) self.updateViewStates() def updateFrame(self, framenumber): """Update display when the frame changed.""" - frames = self.simulation.boat.frameList.frames - if framenumber < len(frames): + if framenumber < len(self.simulation.boat.frameList.frames): self.frame = framenumber - frame = frames[framenumber] # Update widgets maxFrame = str(len(self.simulation)) self.ui.frameNr.setText(str(framenumber).zfill(len(maxFrame)) + "/" + maxFrame) self.mapViewScene.viewFrame(framenumber) self.boatInspectorScene.viewFrame(framenumber) - self.ui.valueInspector.viewFrame(frame) + self.ui.valueInspector.viewFrame(framenumber) def incFrame(self): """Move to the next frame if it is in the range of the slider.""" @@ -113,6 +120,15 @@ def updateViewStates(self): # Slots + def runCode(self) -> None: + """Run custom code in the window.""" + try: + exec(self.ui.console.text(), self.varspace) + self.ui.console.setStyleSheet("") + except Exception: + self.ui.console.setStyleSheet("border: 1px solid red") + self.ui.console.setText("") + # Display for mapView def actionViewShowBoatMap(self, state): """Show/hide the boat on the map view.""" diff --git a/sailsim/gui/main.ui b/sailsim/gui/main.ui index 297cc38..277194e 100644 --- a/sailsim/gui/main.ui +++ b/sailsim/gui/main.ui @@ -20,7 +20,22 @@ - + + + 1 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -532,6 +547,28 @@ + + + + + + + Cascadia Mono + + + + avaiable vars: sailsim, simulation, boat, wind + + + + + + false + + + + + @@ -718,8 +755,8 @@ updateFrame(int) - 354 - 571 + 587 + 551 296 @@ -734,8 +771,8 @@ incFrame() - 119 - 583 + 138 + 552 138 @@ -750,8 +787,8 @@ decFrame() - 65 - 583 + 77 + 552 42 @@ -766,8 +803,8 @@ pressedPlay(bool) - 95 - 583 + 105 + 552 73 @@ -782,8 +819,8 @@ startFrame() - 29 - 571 + 41 + 552 30 @@ -798,8 +835,8 @@ endFrame() - 139 - 572 + 171 + 552 149 @@ -919,6 +956,22 @@ + + console + returnPressed() + MainWindow + runCode() + + + 665 + 580 + + + 673 + 560 + + + updateFrame(int) @@ -934,5 +987,6 @@ actionViewShowWaypointsPathMap(bool) actionViewShowBoatInspector(bool) actionViewShowVectorsInspector(bool) + runCode() diff --git a/sailsim/gui/qtmain.py b/sailsim/gui/qtmain.py index 7aba72e..659ee67 100644 --- a/sailsim/gui/qtmain.py +++ b/sailsim/gui/qtmain.py @@ -17,9 +17,9 @@ QPainter, QPalette, QPixmap, QRadialGradient, QTransform) from PySide6.QtWidgets import (QApplication, QAbstractItemView, QHBoxLayout, QHeaderView, QLabel, - QMainWindow, QMenu, QMenuBar, QSizePolicy, - QSlider, QSplitter, QToolButton, QTreeWidgetItem, - QVBoxLayout, QWidget) + QLineEdit, QMainWindow, QMenu, QMenuBar, + QSizePolicy, QSlider, QSplitter, QToolButton, + QTreeWidgetItem, QVBoxLayout, QWidget) from sailsim.gui.boatInspector import BoatInspectorView from sailsim.gui.mapView import MapViewView @@ -68,7 +68,9 @@ def setupUi(self, MainWindow): self.layout.setObjectName(u"layout") self.layout.setLocale(QLocale(QLocale.English, QLocale.Germany)) self.verticalLayout = QVBoxLayout(self.layout) + self.verticalLayout.setSpacing(1) self.verticalLayout.setObjectName(u"verticalLayout") + self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.main = QSplitter(self.layout) self.main.setObjectName(u"main") self.main.setOrientation(Qt.Horizontal) @@ -186,6 +188,20 @@ def setupUi(self, MainWindow): self.verticalLayout.addLayout(self.controlBar) + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.console = QLineEdit(self.layout) + self.console.setObjectName(u"console") + font = QFont() + font.setFamilies([u"Cascadia Mono"]) + self.console.setFont(font) + self.console.setFrame(False) + + self.horizontalLayout.addWidget(self.console) + + + self.verticalLayout.addLayout(self.horizontalLayout) + self.verticalLayout.setStretch(0, 1) MainWindow.setCentralWidget(self.layout) self.menubar = QMenuBar(MainWindow) @@ -241,6 +257,7 @@ def setupUi(self, MainWindow): self.actionShowBoatMap.toggled.connect(MainWindow.actionViewShowBoatMap) self.actionShowVectorsMap.toggled.connect(MainWindow.actionViewShowVectorsMap) self.actionShowBoatPathMap.toggled.connect(MainWindow.actionViewShowBoatPathMap) + self.console.returnPressed.connect(MainWindow.runCode) QMetaObject.connectSlotsByName(MainWindow) # setupUi @@ -377,6 +394,10 @@ def retranslateUi(self, MainWindow): self.buttonIncFrame.setText(QCoreApplication.translate("MainWindow", u"\u23e9", None)) self.buttonEndFrame.setText(QCoreApplication.translate("MainWindow", u"\u23ed", None)) self.frameNr.setText(QCoreApplication.translate("MainWindow", u"0000/1000", None)) +#if QT_CONFIG(tooltip) + self.console.setToolTip(QCoreApplication.translate("MainWindow", u"avaiable vars: sailsim, simulation, boat, wind", None)) +#endif // QT_CONFIG(tooltip) + self.console.setText("") self.menuFile.setTitle(QCoreApplication.translate("MainWindow", u"File", None)) self.menuEdit.setTitle(QCoreApplication.translate("MainWindow", u"Edit", None)) self.menuView.setTitle(QCoreApplication.translate("MainWindow", u"View", None)) diff --git a/sailsim/gui/valueInspector.py b/sailsim/gui/valueInspector.py index 8f1b36b..a4a684b 100644 --- a/sailsim/gui/valueInspector.py +++ b/sailsim/gui/valueInspector.py @@ -1,8 +1,11 @@ """This module contains the class declaration for the ValueInspectorWidget.""" from math import pi, sqrt +from typing import Optional, Union -from PySide6.QtWidgets import QTreeWidget +from PySide6.QtWidgets import QTreeWidget, QWidget + +from sailsim.simulation.Simulation import Simulation def toString(text): return f'{text:.4f}'.rstrip('0').rstrip('.') @@ -10,7 +13,16 @@ def toString(text): class ValueInspectorWidget(QTreeWidget): """List Widget that displays the boat's values.""" - def viewFrame(self, frame): + simulation: Simulation + + def __init__(self, parent: Optional[Union[QWidget, None]] = None) -> None: + super().__init__(parent) + + def setSimulation(self, simulation: Simulation) -> None: + self.simulation = simulation + + def viewFrame(self, framenumber): + frame = self.simulation.boat.frameList[framenumber] self.updateValueInspectorRow(self.topLevelItem(0), frame.boatPosX, frame.boatPosY) self.topLevelItem(1).setText(1, toString(frame.boatDirection * 180 / pi)) diff --git a/sailsim/simulation/Simulation.py b/sailsim/simulation/Simulation.py index 7c4cfae..2f000a6 100644 --- a/sailsim/simulation/Simulation.py +++ b/sailsim/simulation/Simulation.py @@ -84,4 +84,4 @@ def __repr__(self): def __len__(self): """Return number of frames. Might be None.""" - return self.lastFrame + return self.frame diff --git a/tests/basictest.py b/tests/basictest.py index 2fce749..63f4c11 100644 --- a/tests/basictest.py +++ b/tests/basictest.py @@ -19,25 +19,25 @@ sailor = Sailor(commandListExample) #sailor = Sailor([Waypoint(-30, 30, 1), Waypoint(10, 47, 1), Waypoint(100, 60, 1), Waypoint(0, 100, 2)]) -b = Boat(0, 0, 0) -b.sailor = sailor +boat = Boat(0, 0, 0) +boat.sailor = sailor -sailor.importBoat(b) +sailor.importBoat(boat) # Create simulation -s = Simulation(b, wind, 0.01, 10000) +simulation = Simulation(boat, wind, 0.01, 10000) # Run simulation try: - s.run() + simulation.run() except (OverflowError, ValueError): - s.lastFrame = s.frame - 1 - print("Overflow after Frame", s.frame) + simulation.lastFrame = simulation.frame - 1 + print("Overflow after Frame", simulation.frame) #OUTPUT_PATH = "..\\..\\MATLAB\\sailsim\\out.csv" #s.boat.frameList.saveCSV(OUTPUT_PATH) app = QApplication(sys.argv) -window = SailsimGUI(s) +window = SailsimGUI(simulation, locals()) window.show() sys.exit(app.exec())