import sys from PyQt6.QtWidgets import ( QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QDialog, ) from PyQt6.QtCore import Qt import config from detektor_data import generate_data from detektor_plot import DetektorPlot from detektor_region import DetektorRegion from channels_menu import ChannelsMenu from chart_menu import ChartMenu from data_menu import DataMenu from menubar import Menubar from quit_dialog import QuitDialog from callbacks import CallbackDispatcher, CallbackType from open_file import file_opener from detektor_data import DetektorContainer class MainWindow(QMainWindow): region: DetektorRegion = None plot: DetektorPlot = None channels_menu: ChannelsMenu = None chart_menu = None data_menu = None def __init__(self, data_file: str = None): super().__init__() if data_file: file_opener(data_file) else: DetektorContainer().set( generate_data(channel_count=3, data_count=200, random_values=True) ) self.set_base_title() self.setGeometry(0, 0, 1800, 800) self.showMaximized() CallbackDispatcher().register(CallbackType.FILE_NAME_CHANGED, self.set_base_title) self.main_layout() # menubar has to be loaded after layout to have DetektorRegion available self.setMenuBar(Menubar(self, self.region)) def set_base_title(self): """Set the base window title (default or with filename).""" title = f"{config.APP_NAME} {config.APP_VERSION}" if DetektorContainer().get() and DetektorContainer().get().file_path: # Append filename if available title += f" ({DetektorContainer().get().file_path})" self.setWindowTitle(title) def main_layout(self): central_widget = QWidget() self.setCentralWidget(central_widget) main_layout = QHBoxLayout() central_widget.setLayout(main_layout) self.left_layout(main_layout) self.right_layout(main_layout) def left_layout(self, main_layout: QHBoxLayout): left_layout = QVBoxLayout() main_layout.addLayout(left_layout) self.plot = DetektorPlot(left_layout) self.region = DetektorRegion(self.plot) def right_layout(self, main_layout: QHBoxLayout): # Create a fixed-size widget to hold the right layout right_widget = QWidget() right_widget.setFixedWidth(220) # Ensure the width stays fixed # Create a vertical layout inside the fixed-width widget right_layout = QVBoxLayout() right_layout.setAlignment(Qt.AlignmentFlag.AlignTop) right_widget.setLayout(right_layout) # Set the layout inside the fixed widget # Add the fixed widget (not just the layout) to the main layout main_layout.addWidget(right_widget) # Add contents to right_layout self.channels_menu = ChannelsMenu(right_layout) self.chart_menu = ChartMenu(right_layout, self.plot) self.data_menu = DataMenu(right_layout, self.region) def closeEvent(self, event): if DetektorContainer().get().data_tainted: diag = QuitDialog() if diag.exec() == QDialog.DialogCode.Accepted: """Properly clean up before closing.""" if self.plot: if self.plot.view_box: self.plot.view_box.clear() self.plot.view_box.deleteLater() self.plot.view_box = None if self.plot.graphWidget: self.plot.graphWidget.clear() # Clear all items self.plot.graphWidget.deleteLater() self.plot.graphWidget = None event.accept() # Allow window to close else: # Prevent closing if "Cancel" was clicked event.ignore() else: # Allow closing if data is not tainted event.accept() def create_app(filename: str = None): app = QApplication(sys.argv) window = MainWindow(filename) return app, window