diff --git a/app/ui/main_window.py b/app/ui/main_window.py index 4caa735..8292a01 100644 --- a/app/ui/main_window.py +++ b/app/ui/main_window.py @@ -1,11 +1,13 @@ ''' app/ui/main_window.py ''' from PyQt6.QtCore import Qt, QTimer -from PyQt6.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QTextEdit, QLabel, QDialog +from PyQt6.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QTextEdit, QLabel, QDialog, QToolButton, QStatusBar +from PyQt6.QtWidgets import QToolBox from PyQt6.QtGui import QIcon from .widgets.menubar import MenuBar from .widgets.toolbar import ToolBar from .widgets.statusbar import StatusBar -from .widgets.metadata_input import MetadataInput2 +from .widgets.metadata_input import MetadataInput +from .widgets.measurement_settings import ScriptSelection, MeasurementSettings from .widgets.plot import Plot from .widgets.device_select import ListChoice # from .widgets.treeview import TreeView @@ -42,10 +44,10 @@ class MainWindow(QMainWindow): central_widget = QWidget(self) self.setCentralWidget(central_widget) + layout = QHBoxLayout(central_widget) central_widget.setLayout(layout) - # Create Widgets # self.treeview = self.create_treeview() self.editbox = self.create_edit() @@ -53,12 +55,21 @@ class MainWindow(QMainWindow): # Add Widgets to Window self.setMenuBar(MenuBar(self)) - self.setStatusBar(StatusBar(self)) + self.setStatusBar(StatusBar(QStatusBar(self))) + + self.w_leftbox = QToolBox(self) + layout.addWidget(self.w_leftbox) init_elements = [("name1", "val1"), ("name2", "val2"), ("interval", 0.5)] - layout.addWidget(MetadataInput2(init_elements)) - self.plot_widget = Plot() - layout.addWidget(self.plot_widget) + self.w_metadata = MetadataInput(init_elements) + self.w_leftbox.addItem(self.w_metadata, "Measurement metadata") + # Measurement settings + self.w_measurement_settings = MeasurementSettings() + self.w_leftbox.addItem(self.w_measurement_settings, "Measurement settings") + self.w_measurement_settings.set_value("interval", AppConfig.MAIN_CFG.get_or("interval", 0.5)) + + self.w_plot = Plot() + layout.addWidget(self.w_plot) self.verbose = True @@ -75,6 +86,11 @@ class MainWindow(QMainWindow): self.data_queue = None self.proc_measure = None + self.set_status("Ready") + + def set_status(self, msg): + self.statusBar().showMessage(msg) + def create_toolbars(self) -> None: """ Creates and adds the top and right toolbars to the main window. @@ -84,24 +100,23 @@ class MainWindow(QMainWindow): style=Qt.ToolButtonStyle.ToolButtonTextUnderIcon, icon_size=(24, 24)) # Top Toolbar Buttons - self.topbar.add_button("Devices", QIcon.fromTheme(QIcon.ThemeIcon.Printer), self.vmdev_connect_from_dialog) - self.topbar.add_button("Start", QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStart), self.measure_start) - self.topbar.add_button("Stop", QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStop), self.measure_stop) - self.topbar.add_button("Save", "resources/assets/icons/windows/shell32-259.ico", self.save_file) + self.topbar.add_button("meas_devices", "Devices", QIcon.fromTheme(QIcon.ThemeIcon.Printer), self.vmdev_connect_from_dialog) + self.topbar.add_button("meas_start", "Start", QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStart), self.measure_start) + self.topbar.add_button("meas_stop", "Stop", QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStop), self.measure_stop) + self.topbar.add_button("meas_save", "Save", QIcon.fromTheme(QIcon.ThemeIcon.DocumentSaveAs), self.save_file) self.topbar.add_separator() - self.topbar.add_button("Exit", "resources/assets/icons/windows/shell32-220.ico", self.exit_app) + self.topbar.add_button("app_exit", "Exit", QIcon.fromTheme(QIcon.ThemeIcon.ApplicationExit), self.exit_app) + self.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.topbar) + + # disable the Stop and Save buttons + self.topbar.disable_button("meas_stop") + self.topbar.disable_button("meas_save") # Right Toolbar [PyQt6.QtWidgets.QToolBar] - self.rightbar = ToolBar(self, orientation=Qt.Orientation.Vertical, - style=Qt.ToolButtonStyle.ToolButtonIconOnly, - icon_size=(24, 24)) - - # Right Toolbar Buttons - self.rightbar.add_separator() - self.rightbar.add_button("Settings", "resources/assets/icons/windows/shell32-315.ico", self.settings_window) - - self.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.topbar) - self.addToolBar(Qt.ToolBarArea.RightToolBarArea, self.rightbar) + # self.rightbar = ToolBar(self, orientation=Qt.Orientation.Vertical, style=Qt.ToolButtonStyle.ToolButtonIconOnly, icon_size=(24, 24)) + # self.rightbar.add_separator() + # self.rightbar.add_button("Settings", "resources/assets/icons/windows/shell32-315.ico", self.settings_window) + # self.addToolBar(Qt.ToolBarArea.RightToolBarArea, self.rightbar) # def create_treeview(self) -> TreeView: """ @@ -109,7 +124,6 @@ class MainWindow(QMainWindow): """ # return TreeView(self) - def leddev_connect(self, leddev_type, leddev_name): self.leddev = ledd.connect_device(leddev_type, leddev_name) AppConfig.MAIN_CFG.set("led_device_last.type", leddev_type) @@ -138,6 +152,7 @@ class MainWindow(QMainWindow): self.vmdev = vmd.connect_device(vmdev_type, vmdev_name) AppConfig.MAIN_CFG.set("voltage_measurement_device_last.type", vmdev_type) AppConfig.MAIN_CFG.set("voltage_measurement_device_last.name", vmdev_name) + def vmdev_autoconnect(self): if AppConfig.MAIN_CFG.get_or("voltage_measurement_device_auto_reconnect", False): try: @@ -146,6 +161,8 @@ class MainWindow(QMainWindow): self.vmdev_connect(vmdev_type, vmdev_name) except KeyError: pass + except Exception as e: + print(f"Failed to auto-connect to voltage measurement device: {e}") def vmdev_connect_from_dialog(self): """ Open a dialog that lets the user choose a voltage measurement device, @@ -168,20 +185,29 @@ class MainWindow(QMainWindow): self.leddev_connect_from_dialog() if self.leddev is None: raise ValueError("No led control device selected") + + self.topbar.disable_button("meas_start") + self.topbar.disable_button("meas_devices") + self.topbar.enable_button("meas_stop") script = 100 measurement_name = "guitest" led_script = LedScript(script=script) - flush_after = AppConfig.MAIN_CFG.get_or("flush_after", None) - use_buffer = AppConfig.MAIN_CFG.get_or("use_buffer", False) - max_measurements = AppConfig.MAIN_CFG.get_or("max_measurements", None) - stop_on_script_end = AppConfig.MAIN_CFG.get_or("stop_on_script_end", False) - interval = AppConfig.MAIN_CFG.get_or("measurement_interval_s", 1.0) + flush_after = self.w_measurement_settings.get_value("flush_after") + use_buffer = self.w_measurement_settings.get_value("use_buffer") + max_measurements = self.w_measurement_settings.get_value("max_measurements") + stop_on_script_end = self.w_measurement_settings.get_value("stop_on_script_end") + interval = self.w_measurement_settings.get_value("interval") - metadata = {} + metadata = self.w_metadata.get_dict() metadata["interval"] = str(interval) metadata["name"] = measurement_name metadata["led"] = "led" metadata["led_script"] = str(script) + self.w_metadata.update_from_dict({ + "interval": str(interval), + "led_script": str(script) + }) + if self.verbose: print(f"Starting measurement with:\n\tinterval = {interval}\n\tflush_after = {flush_after}\n\tuse_buffer = {use_buffer}\n\tmax_measurements = {max_measurements}\n\tstop_on_script_end = {stop_on_script_end}") @@ -216,13 +242,16 @@ class MainWindow(QMainWindow): self.command_queue.put("stop") self.measurement_timer.stop() self.proc_measure.join() - print("Measurement stopped" + " " * 50) + self.set_status("Ready") self.led_script.stop_updating() # stop watching for file updates (if enabled) self.data_collector.save_csv(verbose=True) data, metadata = self.data_collector.get_data() self.proc_measure = None self.led_script = None - + self.topbar.enable_button("meas_start") + self.topbar.enable_button("meas_devices") + self.topbar.enable_button("meas_save") + self.topbar.disable_button("meas_stop") def measure_update(self): if self.proc_measure.is_alive(): @@ -231,8 +260,9 @@ class MainWindow(QMainWindow): current_data = self.data_queue.get(block=False) i, tval, vval, led_val = current_data print(f"Data {i:03}: {tval}s, {vval}V, {led_val}%") + self.set_status(f"Data {i:03}: {tval}s, {vval}V, {led_val}%") # update the plot - self.plot_widget.update_plot(tval, vval, led_val) + self.w_plot.update_plot(tval, vval, led_val) def measurement_is_running(self): return self.proc_measure is not None