def __init__(self): QMainWindow.__init__(self) self.logger = logging.getLogger(__name__) # exception hook that logs to console, file, and display a message box self.errorDialogOpened = False sys.excepthook = self.excepthook # Setup the user interface self.ui = Ui_MainWindow() self.ui.setupUi(self) # Initialize the audio data ring buffer self.audiobuffer = AudioBuffer() # Initialize the audio backend # signal containing new data from the audio callback thread, processed as numpy array AudioBackend().new_data_available.connect( self.audiobuffer.handle_new_data) # this timer is used to update widgets that just need to display as fast as they can self.display_timer = QtCore.QTimer() self.display_timer.setInterval( SMOOTH_DISPLAY_TIMER_PERIOD_MS) # constant timing # slow timer self.slow_timer = QtCore.QTimer() self.slow_timer.setInterval(SLOW_TIMER_PERIOD_MS) # constant timing self.about_dialog = About_Dialog(self, self.slow_timer) self.settings_dialog = Settings_Dialog(self) self.level_widget = Levels_Widget(self) self.level_widget.set_buffer(self.audiobuffer) self.audiobuffer.new_data_available.connect( self.level_widget.handle_new_data) self.hboxLayout = QHBoxLayout(self.ui.centralwidget) self.hboxLayout.setContentsMargins(0, 0, 0, 0) self.hboxLayout.addWidget(self.level_widget) self.centralLayout = TileLayout() self.centralLayout.setContentsMargins(0, 0, 0, 0) self.hboxLayout.addLayout(self.centralLayout) self.dockmanager = DockManager(self) # timer ticks self.display_timer.timeout.connect(self.dockmanager.canvasUpdate) self.display_timer.timeout.connect(self.level_widget.canvasUpdate) self.display_timer.timeout.connect(AudioBackend().fetchAudioData) # toolbar clicks self.ui.actionStart.triggered.connect(self.timer_toggle) self.ui.actionSettings.triggered.connect(self.settings_called) self.ui.actionAbout.triggered.connect(self.about_called) self.ui.actionNew_dock.triggered.connect(self.dockmanager.new_dock) # restore the settings and widgets geometries self.restoreAppState() # make sure the toolbar is shown # in case it was closed by mistake (before it was made impossible) self.ui.toolBar.setVisible(True) # prevent from hiding or moving the toolbar self.ui.toolBar.toggleViewAction().setVisible(True) self.ui.toolBar.setMovable(False) self.ui.toolBar.setFloatable(False) # start timers self.timer_toggle() self.slow_timer.start() self.logger.info("Init finished, entering the main loop")
class Friture( QMainWindow, ): def __init__(self): QMainWindow.__init__(self) self.logger = logging.getLogger(__name__) # exception hook that logs to console, file, and display a message box self.errorDialogOpened = False sys.excepthook = self.excepthook # Setup the user interface self.ui = Ui_MainWindow() self.ui.setupUi(self) # Initialize the audio data ring buffer self.audiobuffer = AudioBuffer() # Initialize the audio backend # signal containing new data from the audio callback thread, processed as numpy array AudioBackend().new_data_available.connect( self.audiobuffer.handle_new_data) # this timer is used to update widgets that just need to display as fast as they can self.display_timer = QtCore.QTimer() self.display_timer.setInterval( SMOOTH_DISPLAY_TIMER_PERIOD_MS) # constant timing # slow timer self.slow_timer = QtCore.QTimer() self.slow_timer.setInterval(SLOW_TIMER_PERIOD_MS) # constant timing self.about_dialog = About_Dialog(self, self.slow_timer) self.settings_dialog = Settings_Dialog(self) self.level_widget = Levels_Widget(self) self.level_widget.set_buffer(self.audiobuffer) self.audiobuffer.new_data_available.connect( self.level_widget.handle_new_data) self.hboxLayout = QHBoxLayout(self.ui.centralwidget) self.hboxLayout.setContentsMargins(0, 0, 0, 0) self.hboxLayout.addWidget(self.level_widget) self.centralLayout = TileLayout() self.centralLayout.setContentsMargins(0, 0, 0, 0) self.hboxLayout.addLayout(self.centralLayout) self.dockmanager = DockManager(self) # timer ticks self.display_timer.timeout.connect(self.dockmanager.canvasUpdate) self.display_timer.timeout.connect(self.level_widget.canvasUpdate) self.display_timer.timeout.connect(AudioBackend().fetchAudioData) # toolbar clicks self.ui.actionStart.triggered.connect(self.timer_toggle) self.ui.actionSettings.triggered.connect(self.settings_called) self.ui.actionAbout.triggered.connect(self.about_called) self.ui.actionNew_dock.triggered.connect(self.dockmanager.new_dock) # restore the settings and widgets geometries self.restoreAppState() # make sure the toolbar is shown # in case it was closed by mistake (before it was made impossible) self.ui.toolBar.setVisible(True) # prevent from hiding or moving the toolbar self.ui.toolBar.toggleViewAction().setVisible(True) self.ui.toolBar.setMovable(False) self.ui.toolBar.setFloatable(False) # start timers self.timer_toggle() self.slow_timer.start() self.logger.info("Init finished, entering the main loop") # exception hook that logs to console, file, and display a message box def excepthook(self, exception_type, exception_value, traceback_object): gui_message = fileexcepthook(exception_type, exception_value, traceback_object) # we do not want to flood the user with message boxes when the error happens repeatedly on each timer event if not self.errorDialogOpened: self.errorDialogOpened = True errorBox(gui_message) self.errorDialogOpened = False # slot def settings_called(self): self.settings_dialog.show() # slot def about_called(self): self.about_dialog.show() # event handler def closeEvent(self, event): AudioBackend().close() self.saveAppState() event.accept() # method def saveAppState(self): settings = QtCore.QSettings("Friture", "Friture") settings.beginGroup("Docks") self.dockmanager.saveState(settings) settings.endGroup() settings.beginGroup("MainWindow") windowGeometry = self.saveGeometry() settings.setValue("windowGeometry", windowGeometry) windowState = self.saveState() settings.setValue("windowState", windowState) settings.endGroup() settings.beginGroup("AudioBackend") self.settings_dialog.saveState(settings) settings.endGroup() # method def migrateSettings(self): settings = QtCore.QSettings("Friture", "Friture") # 1. move the central widget to a normal dock if settings.contains("CentralWidget/type"): settings.beginGroup("CentralWidget") centralWidgetKeys = settings.allKeys() children = { key: settings.value(key, type=QtCore.QVariant) for key in centralWidgetKeys } settings.endGroup() if not settings.contains("Docks/central/type"): # write them to a new dock instead for key, value in children.items(): settings.setValue("Docks/central/" + key, value) # add the new dock name to dockNames docknames = settings.value("Docks/dockNames", []) docknames = ["central"] + docknames settings.setValue("Docks/dockNames", docknames) settings.remove("CentralWidget") # 2. remove any level widget if settings.contains("Docks/dockNames"): docknames = settings.value("Docks/dockNames", []) if docknames == None: docknames = [] newDockNames = [] for dockname in docknames: widgetType = settings.value("Docks/" + dockname + "/type", 0, type=int) if widgetType == 0: settings.remove("Docks/" + dockname) else: newDockNames.append(dockname) settings.setValue("Docks/dockNames", newDockNames) # method def restoreAppState(self): self.migrateSettings() settings = QtCore.QSettings("Friture", "Friture") settings.beginGroup("Docks") self.dockmanager.restoreState(settings) settings.endGroup() settings.beginGroup("MainWindow") self.restoreGeometry( settings.value("windowGeometry", type=QtCore.QByteArray)) self.restoreState(settings.value("windowState", type=QtCore.QByteArray)) settings.endGroup() settings.beginGroup("AudioBackend") self.settings_dialog.restoreState(settings) settings.endGroup() # slot def timer_toggle(self): if self.display_timer.isActive(): self.logger.info("Timer stop") self.display_timer.stop() self.ui.actionStart.setText("Start") AudioBackend().pause() self.dockmanager.pause() else: self.logger.info("Timer start") self.display_timer.start() self.ui.actionStart.setText("Stop") AudioBackend().restart() self.dockmanager.restart()