From 669756b391d26661cf2e2a97a304e73343ef6655 Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 11 Jan 2026 14:29:58 -0500 Subject: update to Qt 6 and Pillow 12 and yeah, I accidentally ran black on the codebase. I don't want to spend more free time fixing that. All of these changes are simple renames or removals, nothing too major. --- src/gui/actions.py | 69 ++--- src/gui/mainwindow.py | 648 ++++++++++++++++++++++------------------------ src/gui/presetmanager.py | 157 ++++++----- src/gui/preview_thread.py | 50 ++-- src/gui/preview_win.py | 45 ++-- 5 files changed, 471 insertions(+), 498 deletions(-) (limited to 'src/gui') diff --git a/src/gui/actions.py b/src/gui/actions.py index afb980a..654b2a0 100644 --- a/src/gui/actions.py +++ b/src/gui/actions.py @@ -1,53 +1,61 @@ -''' - QCommand classes for every undoable user action performed in the MainWindow -''' -from PyQt5.QtWidgets import QUndoCommand +""" +QCommand classes for every undoable user action performed in the MainWindow +""" + +from PyQt6.QtGui import QUndoCommand import os +import logging from copy import copy from ..core import Core +log = logging.getLogger("AVP.Gui.Actions") + + # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ # COMPONENT ACTIONS # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ + class AddComponent(QUndoCommand): def __init__(self, parent, compI, moduleI): super().__init__( - "create new %s component" % - parent.core.modules[moduleI].Component.name + "create new %s component" % parent.core.modules[moduleI].Component.name ) self.parent = parent self.moduleI = moduleI self.compI = compI self.comp = None + self.valid = True def redo(self): if self.comp is None: - self.parent.core.insertComponent( - self.compI, self.moduleI, self.parent) + i = self.parent.core.insertComponent(self.compI, self.moduleI, self.parent) + if i != self.compI: + self.valid = False + if i is not None: + log.error( + f"Expected new component index to be {self.compI} but received {i}" + ) else: # inserting previously-created component - self.parent.core.insertComponent( - self.compI, self.comp, self.parent) + self.parent.core.insertComponent(self.compI, self.comp, self.parent) def undo(self): + if not self.valid: + return self.comp = self.parent.core.selectedComponents[self.compI] self.parent._removeComponent(self.compI) class RemoveComponent(QUndoCommand): def __init__(self, parent, selectedRows): - super().__init__('remove component') + super().__init__("remove component") self.parent = parent componentList = self.parent.listWidget_componentList - self.selectedRows = [ - componentList.row(selected) for selected in selectedRows - ] - self.components = [ - parent.core.selectedComponents[i] for i in self.selectedRows - ] + self.selectedRows = [componentList.row(selected) for selected in selectedRows] + self.components = [parent.core.selectedComponents[i] for i in self.selectedRows] def redo(self): self.parent._removeComponent(self.selectedRows[0]) @@ -55,9 +63,7 @@ class RemoveComponent(QUndoCommand): def undo(self): componentList = self.parent.listWidget_componentList for index, comp in zip(self.selectedRows, self.components): - self.parent.core.insertComponent( - index, comp, self.parent - ) + self.parent.core.insertComponent(index, comp, self.parent) self.parent.drawPreview() @@ -70,7 +76,7 @@ class MoveComponent(QUndoCommand): self.id_ = ord(tag[0]) def id(self): - '''If 2 consecutive updates have same id, Qt will call mergeWith()''' + """If 2 consecutive updates have same id, Qt will call mergeWith()""" return self.id_ def mergeWith(self, other): @@ -105,6 +111,7 @@ class MoveComponent(QUndoCommand): # PRESET ACTIONS # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ + class ClearPreset(QUndoCommand): def __init__(self, parent, compI): super().__init__("clear preset") @@ -112,7 +119,7 @@ class ClearPreset(QUndoCommand): self.compI = compI self.component = self.parent.core.selectedComponents[compI] self.store = self.component.savePreset() - self.store['preset'] = self.component.currentPreset + self.store["preset"] = self.component.currentPreset def redo(self): self.parent.core.clearPreset(self.compI) @@ -132,20 +139,19 @@ class OpenPreset(QUndoCommand): comp = self.parent.core.selectedComponents[compI] self.store = comp.savePreset() - self.store['preset'] = copy(comp.currentPreset) + self.store["preset"] = copy(comp.currentPreset) def redo(self): self.parent._openPreset(self.presetName, self.compI) def undo(self): - self.parent.core.selectedComponents[self.compI].loadPreset( - self.store) + self.parent.core.selectedComponents[self.compI].loadPreset(self.store) self.parent.parent.updateComponentTitle(self.compI, self.store) class RenamePreset(QUndoCommand): def __init__(self, parent, path, oldName, newName): - super().__init__('rename preset') + super().__init__("rename preset") self.parent = parent self.path = path self.oldName = oldName @@ -162,14 +168,13 @@ class DeletePreset(QUndoCommand): def __init__(self, parent, compName, vers, presetFile): self.parent = parent self.preset = (compName, vers, presetFile) - self.path = os.path.join( - Core.presetDir, compName, str(vers), presetFile - ) + self.path = os.path.join(Core.presetDir, compName, str(vers), presetFile) self.store = self.parent.core.getPreset(self.path) - self.presetName = self.store['preset'] - super().__init__('delete %s preset (%s)' % (self.presetName, compName)) + self.presetName = self.store["preset"] + super().__init__("delete %s preset (%s)" % (self.presetName, compName)) self.loadedPresets = [ - i for i, comp in enumerate(self.parent.core.selectedComponents) + i + for i, comp in enumerate(self.parent.core.selectedComponents) if self.presetName == str(comp.currentPreset) ] diff --git a/src/gui/mainwindow.py b/src/gui/mainwindow.py index 159dc02..b0a564b 100644 --- a/src/gui/mainwindow.py +++ b/src/gui/mainwindow.py @@ -1,11 +1,13 @@ -''' - When using GUI mode, this module's object (the main window) takes - user input to construct a program state (stored in the Core object). - This shows a preview of the video being created and allows for saving - projects and exporting the video at a later time. -''' -from PyQt5 import QtCore, QtWidgets, uic -import PyQt5.QtWidgets as QtWidgets +""" +When using GUI mode, this module's object (the main window) takes +user input to construct a program state (stored in the Core object). +This shows a preview of the video being created and allows for saving +projects and exporting the video at a later time. +""" + +from PyQt6 import QtCore, QtWidgets, uic +import PyQt6.QtWidgets as QtWidgets +from PyQt6.QtGui import QUndoStack, QShortcut from PIL import Image from queue import Queue import sys @@ -21,46 +23,59 @@ from .preview_win import PreviewWindow from .presetmanager import PresetManager from .actions import * from ..toolkit import ( - disableWhenEncoding, disableWhenOpeningProject, checkOutput, blockSignals + disableWhenEncoding, + disableWhenOpeningProject, + checkOutput, + blockSignals, ) -appName = 'Audio Visualizer' -log = logging.getLogger('AVP.Gui.MainWindow') +appName = "Audio Visualizer" +log = logging.getLogger("AVP.Gui.MainWindow") + + +class MyQUndoStack(QUndoStack): + # FIXME move this class + @property + def encoding(self): + return self.parent().encoding + + @disableWhenEncoding + def undo(self, *args, **kwargs): + super().undo(*args, **kwargs) + + @disableWhenEncoding + def redo(self, *args, **kwargs): + super().redo(*args, **kwargs) class MainWindow(QtWidgets.QMainWindow): - ''' - The MainWindow wraps many Core methods in order to update the GUI - accordingly. E.g., instead of self.core.openProject(), it will use - self.openProject() and update the window titlebar within the wrapper. + """ + The MainWindow wraps many Core methods in order to update the GUI + accordingly. E.g., instead of self.core.openProject(), it will use + self.openProject() and update the window titlebar within the wrapper. - MainWindow manages the autosave feature, although Core has the - primary functions for opening and creating project files. - ''' + MainWindow manages the autosave feature, although Core has the + primary functions for opening and creating project files. + """ createVideo = QtCore.pyqtSignal() newTask = QtCore.pyqtSignal(list) # for the preview window processTask = QtCore.pyqtSignal() - def __init__(self, project): + def __init__(self, project, dpi): super().__init__() - log.debug( - 'Main thread id: {}'.format(int(QtCore.QThread.currentThreadId()))) + log.debug("Main thread id: {}".format(int(QtCore.QThread.currentThreadId()))) uic.loadUi(os.path.join(Core.wd, "gui", "mainwindow.ui"), self) - desk = QtWidgets.QDesktopWidget() - dpi = desk.physicalDpiX() - log.info("Detected screen DPI: %s", dpi) - - self.resize( - int(self.width() * - (dpi / 144)), - int(self.height() * - (dpi / 144)) - ) + + if dpi: + self.resize( + int(self.width() * (dpi / 144)), + int(self.height() * (dpi / 144)), + ) self.core = Core() - Core.mode = 'GUI' + Core.mode = "GUI" # widgets of component settings self.pages = [] self.lastAutosave = time.time() @@ -72,15 +87,13 @@ class MainWindow(QtWidgets.QMainWindow): # Find settings created by Core object self.dataDir = Core.dataDir self.presetDir = Core.presetDir - self.autosavePath = os.path.join(self.dataDir, 'autosave.avp') + self.autosavePath = os.path.join(self.dataDir, "autosave.avp") self.settings = Core.settings # Create stack of undoable user actions - self.undoStack = QtWidgets.QUndoStack(self) + self.undoStack = MyQUndoStack(self) undoLimit = self.settings.value("pref_undoLimit") self.undoStack.setUndoLimit(undoLimit) - self.undoStack.undo = disableWhenEncoding(self.undoStack.undo) - self.undoStack.redo = disableWhenEncoding(self.undoStack.redo) # Create Undo Dialog - A standard QUndoView on a standard QDialog self.undoDialog = QtWidgets.QDialog(self) @@ -94,18 +107,17 @@ class MainWindow(QtWidgets.QMainWindow): self.presetManager = PresetManager(self) # Create the preview window and its thread, queues, and timers - log.debug('Creating preview window') - self.previewWindow = PreviewWindow(self, os.path.join( - Core.wd, 'gui', "background.png")) + log.debug("Creating preview window") + self.previewWindow = PreviewWindow( + self, os.path.join(Core.wd, "gui", "background.png") + ) self.verticalLayout_previewWrapper.addWidget(self.previewWindow) - log.debug('Starting preview thread') + log.debug("Starting preview thread") self.previewQueue = Queue() self.previewThread = QtCore.QThread(self) self.previewWorker = preview_thread.Worker( - self.core, - self.settings, - self.previewQueue + self.core, self.settings, self.previewQueue ) self.previewWorker.moveToThread(self.previewThread) self.newTask.connect(self.previewWorker.createPreviewImage) @@ -113,12 +125,12 @@ class MainWindow(QtWidgets.QMainWindow): self.previewWorker.error.connect(self.previewWindow.threadError) self.previewWorker.imageCreated.connect(self.showPreviewImage) self.previewThread.start() - self.previewThread.finished.connect(lambda: log.info('Preview thread finished.')) + self.previewThread.finished.connect( + lambda: log.info("Preview thread finished.") + ) timeout = 500 - log.debug( - 'Preview timer set to trigger when idle for %sms' % str(timeout) - ) + log.debug("Preview timer set to trigger when idle for %sms" % str(timeout)) self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.processTask.emit) self.timer.start(timeout) @@ -128,7 +140,7 @@ class MainWindow(QtWidgets.QMainWindow): # Undo Feature def toggleUndoButtonEnabled(*_): - """ Enable/disable undo button depending on whether UndoStack contains Actions """ + """Enable/disable undo button depending on whether UndoStack contains Actions""" try: undoButton.setEnabled(self.undoStack.count()) except RuntimeError: @@ -138,50 +150,41 @@ class MainWindow(QtWidgets.QMainWindow): style = self.pushButton_undo.style() undoButton = self.pushButton_undo undoButton.setIcon( - style.standardIcon(QtWidgets.QStyle.SP_FileDialogBack) + style.standardIcon(QtWidgets.QStyle.StandardPixmap.SP_FileDialogBack) ) undoButton.clicked.connect(self.undoStack.undo) undoButton.setEnabled(False) self.undoStack.cleanChanged.connect(toggleUndoButtonEnabled) self.undoMenu = QtWidgets.QMenu() - self.undoMenu.addAction( - self.undoStack.createUndoAction(self) - ) - self.undoMenu.addAction( - self.undoStack.createRedoAction(self) - ) - action = self.undoMenu.addAction('Show History...') - action.triggered.connect( - lambda _: self.showUndoStack() - ) + self.undoMenu.addAction(self.undoStack.createUndoAction(self)) + self.undoMenu.addAction(self.undoStack.createRedoAction(self)) + action = self.undoMenu.addAction("Show History...") + action.triggered.connect(lambda _: self.showUndoStack()) undoButton.setMenu(self.undoMenu) # end of Undo Feature style = self.pushButton_listMoveUp.style() self.pushButton_listMoveUp.setIcon( - style.standardIcon(QtWidgets.QStyle.SP_ArrowUp) + style.standardIcon(QtWidgets.QStyle.StandardPixmap.SP_ArrowUp) ) style = self.pushButton_listMoveDown.style() self.pushButton_listMoveDown.setIcon( - style.standardIcon(QtWidgets.QStyle.SP_ArrowDown) + style.standardIcon(QtWidgets.QStyle.StandardPixmap.SP_ArrowDown) ) style = self.pushButton_removeComponent.style() self.pushButton_removeComponent.setIcon( - style.standardIcon(QtWidgets.QStyle.SP_DialogDiscardButton) + style.standardIcon(QtWidgets.QStyle.StandardPixmap.SP_DialogDiscardButton) ) - if sys.platform == 'darwin': - log.debug( - 'Darwin detected: showing progress label below progress bar') + if sys.platform == "darwin": + log.debug("Darwin detected: showing progress label below progress bar") self.progressBar_createVideo.setTextVisible(False) else: self.progressLabel.setHidden(True) - self.toolButton_selectAudioFile.clicked.connect( - self.openInputFileDialog) + self.toolButton_selectAudioFile.clicked.connect(self.openInputFileDialog) - self.toolButton_selectOutputFile.clicked.connect( - self.openOutputFileDialog) + self.toolButton_selectOutputFile.clicked.connect(self.openOutputFileDialog) def changedField(): self.autosave() @@ -192,43 +195,36 @@ class MainWindow(QtWidgets.QMainWindow): self.progressBar_createVideo.setValue(0) - self.pushButton_createVideo.clicked.connect( - self.createAudioVisualization) + self.pushButton_createVideo.clicked.connect(self.createAudioVisualization) self.pushButton_Cancel.clicked.connect(self.stopVideo) - for i, container in enumerate(Core.encoderOptions['containers']): - self.comboBox_videoContainer.addItem(container['name']) - if container['name'] == self.settings.value('outputContainer'): + for i, container in enumerate(Core.encoderOptions["containers"]): + self.comboBox_videoContainer.addItem(container["name"]) + if container["name"] == self.settings.value("outputContainer"): selectedContainer = i self.comboBox_videoContainer.setCurrentIndex(selectedContainer) - self.comboBox_videoContainer.currentIndexChanged.connect( - self.updateCodecs - ) + self.comboBox_videoContainer.currentIndexChanged.connect(self.updateCodecs) self.updateCodecs() for i in range(self.comboBox_videoCodec.count()): codec = self.comboBox_videoCodec.itemText(i) - if codec == self.settings.value('outputVideoCodec'): + if codec == self.settings.value("outputVideoCodec"): self.comboBox_videoCodec.setCurrentIndex(i) for i in range(self.comboBox_audioCodec.count()): codec = self.comboBox_audioCodec.itemText(i) - if codec == self.settings.value('outputAudioCodec'): + if codec == self.settings.value("outputAudioCodec"): self.comboBox_audioCodec.setCurrentIndex(i) - self.comboBox_videoCodec.currentIndexChanged.connect( - self.updateCodecSettings - ) + self.comboBox_videoCodec.currentIndexChanged.connect(self.updateCodecSettings) - self.comboBox_audioCodec.currentIndexChanged.connect( - self.updateCodecSettings - ) + self.comboBox_audioCodec.currentIndexChanged.connect(self.updateCodecSettings) - vBitrate = int(self.settings.value('outputVideoBitrate')) - aBitrate = int(self.settings.value('outputAudioBitrate')) + vBitrate = int(self.settings.value("outputVideoBitrate")) + aBitrate = int(self.settings.value("outputAudioBitrate")) self.spinBox_vBitrate.setValue(vBitrate) self.spinBox_aBitrate.setValue(aBitrate) @@ -239,30 +235,27 @@ class MainWindow(QtWidgets.QMainWindow): self.compMenu = QtWidgets.QMenu() for i, comp in enumerate(self.core.modules): action = self.compMenu.addAction(comp.Component.name) - action.triggered.connect( - lambda _, item=i: self.addComponent(0, item) - ) + action.triggered.connect(lambda _, item=i: self.addComponent(0, item)) self.pushButton_addComponent.setMenu(self.compMenu) componentList.dropEvent = self.dragComponent - componentList.itemSelectionChanged.connect( - self.changeComponentWidget - ) + componentList.itemSelectionChanged.connect(self.changeComponentWidget) componentList.itemSelectionChanged.connect( self.presetManager.clearPresetListSelection ) - self.pushButton_removeComponent.clicked.connect( - lambda: self.removeComponent() - ) + self.pushButton_removeComponent.clicked.connect(lambda: self.removeComponent()) - componentList.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) - componentList.customContextMenuRequested.connect( - self.componentContextMenu + componentList.setContextMenuPolicy( + QtCore.Qt.ContextMenuPolicy.CustomContextMenu ) + componentList.customContextMenuRequested.connect(self.componentContextMenu) - currentRes = str(self.settings.value('outputWidth'))+'x' + \ - str(self.settings.value('outputHeight')) + currentRes = ( + str(self.settings.value("outputWidth")) + + "x" + + str(self.settings.value("outputHeight")) + ) for i, res in enumerate(Core.resolutions): self.comboBox_resolution.addItem(res) if res == currentRes: @@ -272,24 +265,14 @@ class MainWindow(QtWidgets.QMainWindow): self.updateResolution ) - self.pushButton_listMoveUp.clicked.connect( - lambda: self.moveComponent(-1) - ) - self.pushButton_listMoveDown.clicked.connect( - lambda: self.moveComponent(1) - ) + self.pushButton_listMoveUp.clicked.connect(lambda: self.moveComponent(-1)) + self.pushButton_listMoveDown.clicked.connect(lambda: self.moveComponent(1)) # Configure the Projects Menu self.projectMenu = QtWidgets.QMenu() - self.menuButton_newProject = self.projectMenu.addAction( - "New Project" - ) - self.menuButton_newProject.triggered.connect( - lambda: self.createNewProject() - ) - self.menuButton_openProject = self.projectMenu.addAction( - "Open Project" - ) + self.menuButton_newProject = self.projectMenu.addAction("New Project") + self.menuButton_newProject.triggered.connect(lambda: self.createNewProject()) + self.menuButton_openProject = self.projectMenu.addAction("Open Project") self.menuButton_openProject.triggered.connect( lambda: self.openOpenProjectDialog() ) @@ -303,22 +286,18 @@ class MainWindow(QtWidgets.QMainWindow): self.pushButton_projects.setMenu(self.projectMenu) # Configure the Presets Button - self.pushButton_presets.clicked.connect( - self.openPresetManager - ) + self.pushButton_presets.clicked.connect(self.openPresetManager) self.updateWindowTitle() - log.debug('Showing main window') + log.debug("Showing main window") self.show() if project and project != self.autosavePath: - if not project.endswith('.avp'): - project += '.avp' + if not project.endswith(".avp"): + project += ".avp" # open a project from the commandline if not os.path.dirname(project): - project = os.path.join( - self.settings.value("projectDir"), project - ) + project = os.path.join(self.settings.value("projectDir"), project) self.currentProject = project self.settings.setValue("currentProject", project) if os.path.exists(self.autosavePath): @@ -335,7 +314,8 @@ class MainWindow(QtWidgets.QMainWindow): ch = self.showMessage( msg="Restore unsaved changes in project '%s'?" % os.path.basename(self.currentProject)[:-4], - showCancel=True) + showCancel=True, + ) if ch: self.saveProjectChanges() else: @@ -352,16 +332,16 @@ class MainWindow(QtWidgets.QMainWindow): msg="FFmpeg could not be found. This is a critical error. " "Install FFmpeg, or download it and place the program executable " "in the same folder as this program.", - icon='Critical' + icon="Critical", ) else: if not self.settings.value("ffmpegMsgShown"): try: with open(os.devnull, "w") as f: ffmpegVers = checkOutput( - [self.core.FFMPEG_BIN, '-version'], stderr=f + [self.core.FFMPEG_BIN, "-version"], stderr=f ) - goodVersion = str(ffmpegVers).split()[2].startswith('4') + goodVersion = str(ffmpegVers).split()[2].startswith("4") except Exception: goodVersion = False else: @@ -375,70 +355,61 @@ class MainWindow(QtWidgets.QMainWindow): self.settings.setValue("ffmpegMsgShown", True) # Hotkeys for projects - QtWidgets.QShortcut("Ctrl+S", self, self.saveCurrentProject) - QtWidgets.QShortcut("Ctrl+A", self, self.openSaveProjectDialog) - QtWidgets.QShortcut("Ctrl+O", self, self.openOpenProjectDialog) - QtWidgets.QShortcut("Ctrl+N", self, self.createNewProject) + + QShortcut("Ctrl+S", self, self.saveCurrentProject) + QShortcut("Ctrl+A", self, self.openSaveProjectDialog) + QShortcut("Ctrl+O", self, self.openOpenProjectDialog) + QShortcut("Ctrl+N", self, self.createNewProject) # Hotkeys for undo/redo - QtWidgets.QShortcut("Ctrl+Z", self, self.undoStack.undo) - QtWidgets.QShortcut("Ctrl+Y", self, self.undoStack.redo) - QtWidgets.QShortcut("Ctrl+Shift+Z", self, self.undoStack.redo) + QShortcut("Ctrl+Z", self, self.undoStack.undo) + QShortcut("Ctrl+Y", self, self.undoStack.redo) + QShortcut("Ctrl+Shift+Z", self, self.undoStack.redo) # Hotkeys for component list - for inskey in ("Ctrl+T", QtCore.Qt.Key_Insert): - QtWidgets.QShortcut( - inskey, self, - activated=lambda: self.pushButton_addComponent.click() - ) - for delkey in ("Ctrl+R", QtCore.Qt.Key_Delete): - QtWidgets.QShortcut( - delkey, self.listWidget_componentList, - self.removeComponent + for inskey in ("Ctrl+T", QtCore.Qt.Key.Key_Insert): + QShortcut( + inskey, + self, + activated=lambda: self.pushButton_addComponent.click(), ) - QtWidgets.QShortcut( - "Ctrl+Space", self, - activated=lambda: self.listWidget_componentList.setFocus() - ) - QtWidgets.QShortcut( - "Ctrl+Shift+S", self, - self.presetManager.openSavePresetDialog - ) - QtWidgets.QShortcut( - "Ctrl+Shift+C", self, self.presetManager.clearPreset + for delkey in ("Ctrl+R", QtCore.Qt.Key.Key_Delete): + QShortcut(delkey, self.listWidget_componentList, self.removeComponent) + QShortcut( + "Ctrl+Space", + self, + activated=lambda: self.listWidget_componentList.setFocus(), ) + QShortcut("Ctrl+Shift+S", self, self.presetManager.openSavePresetDialog) + QShortcut("Ctrl+Shift+C", self, self.presetManager.clearPreset) - QtWidgets.QShortcut( - "Ctrl+Up", self.listWidget_componentList, - activated=lambda: self.moveComponent(-1) + QShortcut( + "Ctrl+Up", + self.listWidget_componentList, + activated=lambda: self.moveComponent(-1), ) - QtWidgets.QShortcut( - "Ctrl+Down", self.listWidget_componentList, - activated=lambda: self.moveComponent(1) + QShortcut( + "Ctrl+Down", + self.listWidget_componentList, + activated=lambda: self.moveComponent(1), ) - QtWidgets.QShortcut( - "Ctrl+Home", self.listWidget_componentList, - activated=lambda: self.moveComponent('top') + QShortcut( + "Ctrl+Home", + self.listWidget_componentList, + activated=lambda: self.moveComponent("top"), ) - QtWidgets.QShortcut( - "Ctrl+End", self.listWidget_componentList, - activated=lambda: self.moveComponent('bottom') + QShortcut( + "Ctrl+End", + self.listWidget_componentList, + activated=lambda: self.moveComponent("bottom"), ) - QtWidgets.QShortcut( - "Ctrl+Shift+F", self, self.showFfmpegCommand - ) - QtWidgets.QShortcut( - "Ctrl+Shift+U", self, self.showUndoStack - ) + QShortcut("Ctrl+Shift+F", self, self.showFfmpegCommand) + QShortcut("Ctrl+Shift+U", self, self.showUndoStack) if log.isEnabledFor(logging.DEBUG): - QtWidgets.QShortcut( - "Ctrl+Alt+Shift+R", self, self.drawPreview - ) - QtWidgets.QShortcut( - "Ctrl+Alt+Shift+A", self, lambda: log.debug(repr(self)) - ) + QShortcut("Ctrl+Alt+Shift+R", self, self.drawPreview) + QShortcut("Ctrl+Alt+Shift+A", self, lambda: log.debug(repr(self))) # Close MainWindow when receiving Ctrl+C from terminal signal.signal(signal.SIGINT, lambda *args: self.close()) @@ -450,18 +421,27 @@ class MainWindow(QtWidgets.QMainWindow): def __repr__(self): return ( - '%s\n' - '\n%s\n' - '#####\n' - 'Preview thread is %s\n' % ( + "%s\n" + "\n%s\n" + "#####\n" + "Preview thread is %s\n" + % ( super().__repr__(), - "core not initialized" if not hasattr(self, "core") else repr(self.core), - 'live' if hasattr(self, "previewThread") and self.previewThread.isRunning() else 'dead', + ( + "core not initialized" + if not hasattr(self, "core") + else repr(self.core) + ), + ( + "live" + if hasattr(self, "previewThread") and self.previewThread.isRunning() + else "dead" + ), ) ) def closeEvent(self, event): - log.info('Ending the preview thread') + log.info("Ending the preview thread") self.timer.stop() self.previewThread.quit() self.previewThread.wait() @@ -473,11 +453,11 @@ class MainWindow(QtWidgets.QMainWindow): windowTitle = appName try: if self.currentProject: - windowTitle += ' - %s' % \ - os.path.splitext( - os.path.basename(self.currentProject))[0] + windowTitle += ( + " - %s" % os.path.splitext(os.path.basename(self.currentProject))[0] + ) if self.autosaveExists(identical=False): - windowTitle += '*' + windowTitle += "*" except AttributeError: pass log.verbose(f'Window title is "{windowTitle}"') @@ -485,38 +465,38 @@ class MainWindow(QtWidgets.QMainWindow): @QtCore.pyqtSlot(int, dict) def updateComponentTitle(self, pos, presetStore=False): - ''' - Sets component title to modified or unmodified when given boolean. - If given a preset dict, compares it against the component to - determine if it is modified. - A component with no preset is always unmodified. - ''' + """ + Sets component title to modified or unmodified when given boolean. + If given a preset dict, compares it against the component to + determine if it is modified. + A component with no preset is always unmodified. + """ if type(presetStore) is dict: - name = presetStore['preset'] + name = presetStore["preset"] if name is None or name not in self.core.savedPresets: modified = False else: - modified = (presetStore != self.core.savedPresets[name]) + modified = presetStore != self.core.savedPresets[name] modified = bool(presetStore) if pos < 0: - pos = len(self.core.selectedComponents)-1 + pos = len(self.core.selectedComponents) - 1 name = self.core.selectedComponents[pos].name title = str(name) if self.core.selectedComponents[pos].currentPreset: - title += ' - %s' % self.core.selectedComponents[pos].currentPreset + title += " - %s" % self.core.selectedComponents[pos].currentPreset if modified: - title += '*' + title += "*" if type(presetStore) is bool: log.debug( - 'Forcing %s #%s\'s modified status to %s: %s', - name, pos, modified, title + "Forcing %s #%s's modified status to %s: %s", + name, + pos, + modified, + title, ) else: - log.debug( - 'Setting %s #%s\'s title: %s', - name, pos, title - ) + log.debug("Setting %s #%s's title: %s", name, pos, title) self.listWidget_componentList.item(pos).setText(title) def updateCodecs(self): @@ -525,20 +505,20 @@ class MainWindow(QtWidgets.QMainWindow): aCodecWidget = self.comboBox_audioCodec index = containerWidget.currentIndex() name = containerWidget.itemText(index) - self.settings.setValue('outputContainer', name) + self.settings.setValue("outputContainer", name) vCodecWidget.clear() aCodecWidget.clear() - for container in Core.encoderOptions['containers']: - if container['name'] == name: - for vCodec in container['video-codecs']: + for container in Core.encoderOptions["containers"]: + if container["name"] == name: + for vCodec in container["video-codecs"]: vCodecWidget.addItem(vCodec) - for aCodec in container['audio-codecs']: + for aCodec in container["audio-codecs"]: aCodecWidget.addItem(aCodec) def updateCodecSettings(self): - '''Updates settings.ini to match encoder option widgets''' + """Updates settings.ini to match encoder option widgets""" vCodecWidget = self.comboBox_videoCodec vBitrateWidget = self.spinBox_vBitrate aBitrateWidget = self.spinBox_aBitrate @@ -549,10 +529,10 @@ class MainWindow(QtWidgets.QMainWindow): currentAudioCodec = aCodecWidget.currentIndex() currentAudioCodec = aCodecWidget.itemText(currentAudioCodec) currentAudioBitrate = aBitrateWidget.value() - self.settings.setValue('outputVideoCodec', currentVideoCodec) - self.settings.setValue('outputAudioCodec', currentAudioCodec) - self.settings.setValue('outputVideoBitrate', currentVideoBitrate) - self.settings.setValue('outputAudioBitrate', currentAudioBitrate) + self.settings.setValue("outputVideoCodec", currentVideoCodec) + self.settings.setValue("outputAudioCodec", currentAudioCodec) + self.settings.setValue("outputVideoBitrate", currentVideoBitrate) + self.settings.setValue("outputAudioBitrate", currentAudioBitrate) @disableWhenOpeningProject def autosave(self, force=False): @@ -567,54 +547,54 @@ class MainWindow(QtWidgets.QMainWindow): # curve up to 5 seconds cooldown and maintains that for 30 secs # if a component is continuously updated timeDiff = self.lastAutosave - self.autosaveTimes.pop() - if not force and timeDiff >= 1.0 \ - and timeDiff <= 10.0: + if not force and timeDiff >= 1.0 and timeDiff <= 10.0: if self.autosaveCooldown / 4.0 < 0.5: self.autosaveCooldown += 1.0 - self.autosaveCooldown = ( - 5.0 * (self.autosaveCooldown / 5.0) - ) + (self.autosaveCooldown / 5.0) * 2 + self.autosaveCooldown = (5.0 * (self.autosaveCooldown / 5.0)) + ( + self.autosaveCooldown / 5.0 + ) * 2 elif force or timeDiff >= self.autosaveCooldown * 5: self.autosaveCooldown = 0.2 self.autosaveTimes.insert(0, self.lastAutosave) else: - log.debug('Autosave rejected by cooldown') + log.debug("Autosave rejected by cooldown") def autosaveExists(self, identical=True): - '''Determines if creating the autosave should be blocked.''' + """Determines if creating the autosave should be blocked.""" try: - if self.currentProject and os.path.exists(self.autosavePath) \ - and filecmp.cmp( - self.autosavePath, self.currentProject) == identical: + if ( + self.currentProject + and os.path.exists(self.autosavePath) + and filecmp.cmp(self.autosavePath, self.currentProject) == identical + ): log.debug( - 'Autosave found %s to be identical' - % 'not' if not identical else '' + "Autosave found %s to be identical" % "not" if not identical else "" ) return True except FileNotFoundError: - log.error( - 'Project file couldn\'t be located: %s', self.currentProject) + log.error("Project file couldn't be located: %s", self.currentProject) return identical return False def saveProjectChanges(self): - '''Overwrites project file with autosave file''' + """Overwrites project file with autosave file""" try: os.remove(self.currentProject) os.rename(self.autosavePath, self.currentProject) return True except (FileNotFoundError, IsADirectoryError) as e: - self.showMessage( - msg='Project file couldn\'t be saved.', - detail=str(e)) + self.showMessage(msg="Project file couldn't be saved.", detail=str(e)) return False def openInputFileDialog(self): inputDir = self.settings.value("inputDir", os.path.expanduser("~")) fileName, _ = QtWidgets.QFileDialog.getOpenFileName( - self, "Open Audio File", - inputDir, "Audio Files (%s)" % " ".join(Core.audioFormats)) + self, + "Open Audio File", + inputDir, + "Audio Files (%s)" % " ".join(Core.audioFormats), + ) if fileName: self.settings.setValue("inputDir", os.path.dirname(fileName)) @@ -624,17 +604,18 @@ class MainWindow(QtWidgets.QMainWindow): outputDir = self.settings.value("outputDir", os.path.expanduser("~")) fileName, _ = QtWidgets.QFileDialog.getSaveFileName( - self, "Set Output Video File", + self, + "Set Output Video File", outputDir, - "Video Files (%s);; All Files (*)" % " ".join( - Core.videoFormats)) + "Video Files (%s);; All Files (*)" % " ".join(Core.videoFormats), + ) if fileName: self.settings.setValue("outputDir", os.path.dirname(fileName)) self.lineEdit_outputFile.setText(fileName) def stopVideo(self): - log.info('Export cancelled') + log.info("Export cancelled") self.videoWorker.cancel() self.canceled = True @@ -645,14 +626,13 @@ class MainWindow(QtWidgets.QMainWindow): if audioFile and outputPath and self.core.selectedComponents: if not os.path.dirname(outputPath): - outputPath = os.path.join( - os.path.expanduser("~"), outputPath) + outputPath = os.path.join(os.path.expanduser("~"), outputPath) if outputPath and os.path.isdir(outputPath): self.showMessage( - msg='Chosen filename matches a directory, which ' - 'cannot be overwritten. Please choose a different ' - 'filename or move the directory.', - icon='Warning', + msg="Chosen filename matches a directory, which " + "cannot be overwritten. Please choose a different " + "filename or move the directory.", + icon="Warning", ) return else: @@ -661,19 +641,14 @@ class MainWindow(QtWidgets.QMainWindow): msg="You must select an audio file and output filename." ) elif not self.core.selectedComponents: - self.showMessage( - msg="Not enough components." - ) + self.showMessage(msg="Not enough components.") return self.canceled = False self.progressBarUpdated(-1) - self.videoWorker = self.core.newVideoWorker( - self, audioFile, outputPath - ) + self.videoWorker = self.core.newVideoWorker(self, audioFile, outputPath) self.videoWorker.progressBarUpdate.connect(self.progressBarUpdated) - self.videoWorker.progressBarSetText.connect( - self.progressBarSetText) + self.videoWorker.progressBarSetText.connect(self.progressBarSetText) self.videoWorker.imageCreated.connect(self.showPreviewImage) self.videoWorker.encoding.connect(self.changeEncodingStatus) self.createVideo.emit() @@ -683,14 +658,14 @@ class MainWindow(QtWidgets.QMainWindow): try: self.stopVideo() except AttributeError as e: - if 'videoWorker' not in str(e): + if "videoWorker" not in str(e): raise self.showMessage( msg=msg, detail=detail, - icon='Critical', + icon="Critical", ) - log.info('%s', repr(self)) + log.info("%s", repr(self)) def changeEncodingStatus(self, status): self.encoding = status @@ -718,7 +693,7 @@ class MainWindow(QtWidgets.QMainWindow): # Close undo history dialog if open self.undoDialog.close() # Show label under progress bar on macOS - if sys.platform == 'darwin': + if sys.platform == "darwin": self.progressLabel.setHidden(False) else: self.pushButton_createVideo.setEnabled(True) @@ -749,33 +724,33 @@ class MainWindow(QtWidgets.QMainWindow): @QtCore.pyqtSlot(str) def progressBarSetText(self, value): - if sys.platform == 'darwin': + if sys.platform == "darwin": self.progressLabel.setText(value) else: self.progressBar_createVideo.setFormat(value) def updateResolution(self): resIndex = int(self.comboBox_resolution.currentIndex()) - res = Core.resolutions[resIndex].split('x') + res = Core.resolutions[resIndex].split("x") changed = res[0] != self.settings.value("outputWidth") - self.settings.setValue('outputWidth', res[0]) - self.settings.setValue('outputHeight', res[1]) + self.settings.setValue("outputWidth", res[0]) + self.settings.setValue("outputHeight", res[1]) if changed: for i in range(len(self.core.selectedComponents)): self.core.updateComponent(i) def drawPreview(self, force=False, **kwargs): - '''Use autosave keyword arg to force saving or not saving if needed''' + """Use autosave keyword arg to force saving or not saving if needed""" self.newTask.emit(self.core.selectedComponents) # self.processTask.emit() - if force or 'autosave' in kwargs: - if force or kwargs['autosave']: + if force or "autosave" in kwargs: + if force or kwargs["autosave"]: self.autosave(True) else: self.autosave() self.updateWindowTitle() - @QtCore.pyqtSlot('QImage') + @QtCore.pyqtSlot("QImage") def showPreviewImage(self, image): self.previewWindow.changePixmap(image) @@ -786,36 +761,35 @@ class MainWindow(QtWidgets.QMainWindow): def showFfmpegCommand(self): from textwrap import wrap from ..toolkit.ffmpeg import createFfmpegCommand + command = createFfmpegCommand( self.lineEdit_audioFile.text(), self.lineEdit_outputFile.text(), - self.core.selectedComponents + self.core.selectedComponents, ) command = " ".join(command) log.info(f"FFmpeg command: {command}") lines = wrap(command, 49) - self.showMessage( - msg=f"Current FFmpeg command:\n\n{' '.join(lines)}" - ) + self.showMessage(msg=f"Current FFmpeg command:\n\n{' '.join(lines)}") def addComponent(self, compPos, moduleIndex): - '''Creates an undoable action that adds a new component.''' + """Creates an undoable action that adds a new component.""" action = AddComponent(self, compPos, moduleIndex) self.undoStack.push(action) def insertComponent(self, index): - '''Triggered by Core to finish initializing a new component.''' + """Triggered by Core to finish initializing a new component.""" + if not hasattr(self.core.selectedComponents[index], "page"): + log.error("Component failed to initialize") + return componentList = self.listWidget_componentList stackedWidget = self.stackedWidget - componentList.insertItem( - index, - self.core.selectedComponents[index].name) + componentList.insertItem(index, self.core.selectedComponents[index].name) componentList.setCurrentRow(index) # connect to signal that adds an asterisk when modified - self.core.selectedComponents[index].modified.connect( - self.updateComponentTitle) + self.core.selectedComponents[index].modified.connect(self.updateComponentTitle) self.pages.insert(index, self.core.selectedComponents[index].page) stackedWidget.insertWidget(index, self.pages[index]) @@ -842,15 +816,15 @@ class MainWindow(QtWidgets.QMainWindow): @disableWhenEncoding def moveComponent(self, change): - '''Moves a component relatively from its current position''' + """Moves a component relatively from its current position""" componentList = self.listWidget_componentList tag = change - if change == 'top': + if change == "top": change = -componentList.currentRow() - elif change == 'bottom': - change = len(componentList)-componentList.currentRow()-1 + elif change == "bottom": + change = len(componentList) - componentList.currentRow() - 1 else: - tag = 'down' if change == 1 else 'up' + tag = "down" if change == 1 else "up" row = componentList.currentRow() newRow = row + change @@ -859,38 +833,39 @@ class MainWindow(QtWidgets.QMainWindow): self.undoStack.push(action) def getComponentListMousePos(self, position): - ''' + """ Given a QPos, returns the component index under the mouse cursor or -1 if no component is there. - ''' + """ componentList = self.listWidget_componentList + if hasattr(position, "toPointF"): + position = position.toPointF() + position = position.toPoint() + modelIndexes = [ - componentList.model().index(i) - for i in range(componentList.count()) - ] - rects = [ - componentList.visualRect(modelIndex) - for modelIndex in modelIndexes + componentList.model().index(i) for i in range(componentList.count()) ] + rects = [componentList.visualRect(modelIndex) for modelIndex in modelIndexes] mousePos = [rect.contains(position) for rect in rects] if not any(mousePos): # Not clicking a component mousePos = -1 else: mousePos = mousePos.index(True) - log.debug('Click component list row %s' % mousePos) + log.debug("Click component list row %s" % mousePos) return mousePos @disableWhenEncoding def dragComponent(self, event): - '''Used as Qt drop event for the component listwidget''' + """Used as Qt drop event for the component listwidget""" componentList = self.listWidget_componentList - mousePos = self.getComponentListMousePos(event.pos()) + mousePos = self.getComponentListMousePos(event.position()) + if mousePos > -1: change = (componentList.currentRow() - mousePos) * -1 else: - change = (componentList.count() - componentList.currentRow() - 1) + change = componentList.count() - componentList.currentRow() - 1 self.moveComponent(change) def changeComponentWidget(self): @@ -900,30 +875,27 @@ class MainWindow(QtWidgets.QMainWindow): self.stackedWidget.setCurrentIndex(index) def openPresetManager(self): - '''Preset manager for importing, exporting, renaming, deleting''' + """Preset manager for importing, exporting, renaming, deleting""" self.presetManager.show_() def clear(self): - '''Get a blank slate''' + """Get a blank slate""" self.core.clearComponents() self.listWidget_componentList.clear() for widget in self.pages: self.stackedWidget.removeWidget(widget) self.pages = [] - for field in ( - self.lineEdit_audioFile, - self.lineEdit_outputFile - ): + for field in (self.lineEdit_audioFile, self.lineEdit_outputFile): with blockSignals(field): - field.setText('') + field.setText("") self.progressBarUpdated(0) - self.progressBarSetText('') + self.progressBarSetText("") self.undoStack.clear() @disableWhenEncoding def createNewProject(self, prompt=True): if prompt: - self.openSaveChangesDialog('starting a new project') + self.openSaveChangesDialog("starting a new project") self.clear() self.currentProject = None @@ -946,11 +918,10 @@ class MainWindow(QtWidgets.QMainWindow): if self.autosaveExists(identical=False): ch = self.showMessage( msg="You have unsaved changes in project '%s'. " - "Save before %s?" % ( - os.path.basename(self.currentProject)[:-4], - phrase - ), - showCancel=True) + "Save before %s?" + % (os.path.basename(self.currentProject)[:-4], phrase), + showCancel=True, + ) if ch: success = self.saveProjectChanges() @@ -959,13 +930,15 @@ class MainWindow(QtWidgets.QMainWindow): def openSaveProjectDialog(self): filename, _ = QtWidgets.QFileDialog.getSaveFileName( - self, "Create Project File", + self, + "Create Project File", self.settings.value("projectDir"), - "Project Files (*.avp)") + "Project Files (*.avp)", + ) if not filename: return if not filename.endswith(".avp"): - filename += '.avp' + filename += ".avp" self.settings.setValue("projectDir", os.path.dirname(filename)) self.settings.setValue("currentProject", filename) self.currentProject = filename @@ -975,20 +948,25 @@ class MainWindow(QtWidgets.QMainWindow): @disableWhenEncoding def openOpenProjectDialog(self): filename, _ = QtWidgets.QFileDialog.getOpenFileName( - self, "Open Project File", + self, + "Open Project File", self.settings.value("projectDir"), - "Project Files (*.avp)") + "Project Files (*.avp)", + ) self.openProject(filename) def openProject(self, filepath, prompt=True): - if not filepath or not os.path.exists(filepath) \ - or not filepath.endswith('.avp'): + if ( + not filepath + or not os.path.exists(filepath) + or not filepath.endswith(".avp") + ): return self.clear() # ask to save any changes that are about to get deleted if prompt: - self.openSaveChangesDialog('opening another project') + self.openSaveChangesDialog("opening another project") self.currentProject = filepath self.settings.setValue("currentProject", filepath) @@ -999,29 +977,32 @@ class MainWindow(QtWidgets.QMainWindow): self.updateWindowTitle() def showMessage(self, **kwargs): - parent = kwargs['parent'] if 'parent' in kwargs else self + parent = kwargs["parent"] if "parent" in kwargs else self msg = QtWidgets.QMessageBox(parent) msg.setWindowTitle(appName) msg.setModal(True) - msg.setText(kwargs['msg']) + msg.setText(kwargs["msg"]) msg.setIcon( - eval('QtWidgets.QMessageBox.%s' % kwargs['icon']) - if 'icon' in kwargs else QtWidgets.QMessageBox.Information + eval("QtWidgets.QMessageBox.Icon.%s" % kwargs["icon"]) + if "icon" in kwargs + else QtWidgets.QMessageBox.Icon.Information ) - msg.setDetailedText(kwargs['detail'] if 'detail' in kwargs else None) - if 'showCancel'in kwargs and kwargs['showCancel']: + msg.setDetailedText(kwargs["detail"] if "detail" in kwargs else None) + if "showCancel" in kwargs and kwargs["showCancel"]: msg.setStandardButtons( - QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) + QtWidgets.QMessageBox.StandardButton.Ok + | QtWidgets.QMessageBox.StandardButton.Cancel + ) else: - msg.setStandardButtons(QtWidgets.QMessageBox.Ok) - ch = msg.exec_() + msg.setStandardButtons(QtWidgets.QMessageBox.StandardButton.Ok) + ch = msg.exec() if ch == 1024: return True return False @disableWhenEncoding def componentContextMenu(self, QPos): - '''Appears when right-clicking the component list''' + """Appears when right-clicking the component list""" componentList = self.listWidget_componentList self.menu = QtWidgets.QMenu() parentPosition = componentList.mapToGlobal(QtCore.QPoint(0, 0)) @@ -1031,9 +1012,7 @@ class MainWindow(QtWidgets.QMainWindow): # Show preset menu if clicking a component self.presetManager.findPresets() menuItem = self.menu.addAction("Save Preset") - menuItem.triggered.connect( - self.presetManager.openSavePresetDialog - ) + menuItem.triggered.connect(self.presetManager.openSavePresetDialog) # submenu for opening presets try: @@ -1046,17 +1025,16 @@ class MainWindow(QtWidgets.QMainWindow): for version, presetName in presets: menuItem = self.presetSubmenu.addAction(presetName) menuItem.triggered.connect( - lambda _, presetName=presetName: - self.presetManager.openPreset(presetName) + lambda _, presetName=presetName: self.presetManager.openPreset( + presetName + ) ) except KeyError: pass if self.core.selectedComponents[index].currentPreset: menuItem = self.menu.addAction("Clear Preset") - menuItem.triggered.connect( - self.presetManager.clearPreset - ) + menuItem.triggered.connect(self.presetManager.clearPreset) self.menu.addSeparator() # "Add Component" submenu diff --git a/src/gui/presetmanager.py b/src/gui/presetmanager.py index 9cf95b4..11a9d9b 100644 --- a/src/gui/presetmanager.py +++ b/src/gui/presetmanager.py @@ -1,8 +1,9 @@ -''' - Preset manager object handles all interactions with presets, including - the context menu accessed from MainWindow. -''' -from PyQt5 import QtCore, QtWidgets, uic +""" +Preset manager object handles all interactions with presets, including +the context menu accessed from MainWindow. +""" + +from PyQt6 import QtCore, QtWidgets, uic import string import os import logging @@ -12,53 +13,43 @@ from ..core import Core from .actions import * -log = logging.getLogger('AVP.Gui.PresetManager') +log = logging.getLogger("AVP.Gui.PresetManager") class PresetManager(QtWidgets.QDialog): def __init__(self, parent): super().__init__() - uic.loadUi( - os.path.join(Core.wd, 'gui', 'presetmanager.ui'), self) + uic.loadUi(os.path.join(Core.wd, "gui", "presetmanager.ui"), self) self.parent = parent self.core = parent.core self.settings = parent.settings self.presetDir = parent.presetDir - if not self.settings.value('presetDir'): + if not self.settings.value("presetDir"): self.settings.setValue( - "presetDir", - os.path.join(parent.dataDir, 'projects')) + "presetDir", os.path.join(parent.dataDir, "projects") + ) self.findPresets() # window - self.lastFilter = '*' + self.lastFilter = "*" self.presetRows = [] # list of (comp, vers, name) tuples - self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) + + # FIXME + # self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) # connect button signals - self.pushButton_delete.clicked.connect( - self.openDeletePresetDialog - ) - self.pushButton_rename.clicked.connect( - self.openRenamePresetDialog - ) - self.pushButton_import.clicked.connect( - self.openImportDialog - ) - self.pushButton_export.clicked.connect( - self.openExportDialog - ) - self.pushButton_close.clicked.connect( - self.close - ) + self.pushButton_delete.clicked.connect(self.openDeletePresetDialog) + self.pushButton_rename.clicked.connect(self.openRenamePresetDialog) + self.pushButton_import.clicked.connect(self.openImportDialog) + self.pushButton_export.clicked.connect(self.openExportDialog) + self.pushButton_close.clicked.connect(self.close) # create filter box and preset list self.drawFilterList() self.comboBox_filter.currentIndexChanged.connect( lambda: self.drawPresetList( - self.comboBox_filter.currentText(), - self.lineEdit_search.text() + self.comboBox_filter.currentText(), self.lineEdit_search.text() ) ) @@ -69,17 +60,16 @@ class PresetManager(QtWidgets.QDialog): self.lineEdit_search.setCompleter(completer) self.lineEdit_search.textChanged.connect( lambda: self.drawPresetList( - self.comboBox_filter.currentText(), - self.lineEdit_search.text() + self.comboBox_filter.currentText(), self.lineEdit_search.text() ) ) - self.drawPresetList('*') + self.drawPresetList("*") def show_(self): - '''Open a new preset manager window from the mainwindow''' + """Open a new preset manager window from the mainwindow""" self.findPresets() self.drawFilterList() - self.drawPresetList('*') + self.drawPresetList("*") self.show() def findPresets(self): @@ -100,14 +90,12 @@ class PresetManager(QtWidgets.QDialog): continue self.presets = { compName: [ - (vers, preset) - for name, vers, preset in parseList - if name == compName + (vers, preset) for name, vers, preset in parseList if name == compName ] for compName, _, __ in parseList } - def drawPresetList(self, compFilter=None, presetFilter=''): + def drawPresetList(self, compFilter=None, presetFilter=""): self.listWidget_presets.clear() if compFilter: self.lastFilter = str(compFilter) @@ -116,13 +104,11 @@ class PresetManager(QtWidgets.QDialog): self.presetRows = [] presetNames = [] for component, presets in self.presets.items(): - if compFilter != '*' and component != compFilter: + if compFilter != "*" and component != compFilter: continue for vers, preset in presets: if not presetFilter or presetFilter in preset: - self.listWidget_presets.addItem( - '%s: %s' % (component, preset) - ) + self.listWidget_presets.addItem("%s: %s" % (component, preset)) self.presetRows.append((component, vers, preset)) if preset not in presetNames: presetNames.append(preset) @@ -130,18 +116,18 @@ class PresetManager(QtWidgets.QDialog): def drawFilterList(self): self.comboBox_filter.clear() - self.comboBox_filter.addItem('*') + self.comboBox_filter.addItem("*") for component in self.presets: self.comboBox_filter.addItem(component) def clearPreset(self, compI=None): - '''Functions on mainwindow level from the context menu''' + """Functions on mainwindow level from the context menu""" compI = self.parent.listWidget_componentList.currentRow() action = ClearPreset(self.parent, compI) self.parent.undoStack.push(action) def openSavePresetDialog(self): - '''Functions on mainwindow level from the context menu''' + """Functions on mainwindow level from the context menu""" selectedComponents = self.core.selectedComponents componentList = self.parent.listWidget_componentList @@ -152,10 +138,10 @@ class PresetManager(QtWidgets.QDialog): currentPreset = selectedComponents[index].currentPreset newName, OK = QtWidgets.QInputDialog.getText( self.parent, - 'Audio Visualizer', - 'New Preset Name:', - QtWidgets.QLineEdit.Normal, - currentPreset + "Audio Visualizer", + "New Preset Name:", + QtWidgets.QLineEdit.EchoMode.Normal, + currentPreset, ) if OK: if badName(newName): @@ -164,21 +150,23 @@ class PresetManager(QtWidgets.QDialog): if newName: if index != -1: selectedComponents[index].currentPreset = newName - saveValueStore = \ - selectedComponents[index].savePreset() - saveValueStore['preset'] = newName + saveValueStore = selectedComponents[index].savePreset() + saveValueStore["preset"] = newName componentName = str(selectedComponents[index]).strip() vers = selectedComponents[index].version self.createNewPreset( - componentName, vers, newName, - saveValueStore, window=self.parent) + componentName, + vers, + newName, + saveValueStore, + window=self.parent, + ) self.findPresets() self.drawPresetList() self.openPreset(newName, index) break - def createNewPreset( - self, compName, vers, filename, saveValueStore, **kwargs): + def createNewPreset(self, compName, vers, filename, saveValueStore, **kwargs): path = os.path.join(self.presetDir, compName, str(vers), filename) if self.presetExists(path, **kwargs): return @@ -188,11 +176,11 @@ class PresetManager(QtWidgets.QDialog): if os.path.exists(path): window = kwargs.get("window", self) ch = self.parent.showMessage( - msg="%s already exists! Overwrite it?" % - os.path.basename(path), + msg="%s already exists! Overwrite it?" % os.path.basename(path), showCancel=True, - icon='Warning', - parent=window) + icon="Warning", + parent=window, + ) if not ch: # user clicked cancel return True @@ -225,10 +213,10 @@ class PresetManager(QtWidgets.QDialog): return comp, vers, name = self.presetRows[row] ch = self.parent.showMessage( - msg='Really delete %s?' % name, + msg="Really delete %s?" % name, showCancel=True, - icon='Warning', - parent=self + icon="Warning", + parent=self, ) if not ch: return @@ -240,9 +228,9 @@ class PresetManager(QtWidgets.QDialog): def warnMessage(self, window=None): self.parent.showMessage( - msg='Preset names must contain only letters, ' - 'numbers, and spaces.', - parent=window if window else self) + msg="Preset names must contain only letters, " "numbers, and spaces.", + parent=window if window else self, + ) def getPresetRow(self): row = self.listWidget_presets.currentRow() @@ -262,14 +250,14 @@ class PresetManager(QtWidgets.QDialog): rowTuple = ( self.core.selectedComponents[compIndex].name, self.core.selectedComponents[compIndex].version, - preset + preset, ) for i, tup in enumerate(self.presetRows): if rowTuple == tup: index = i break else: - return -1 + return -1 return index def openRenamePresetDialog(self): @@ -281,10 +269,10 @@ class PresetManager(QtWidgets.QDialog): while True: newName, OK = QtWidgets.QInputDialog.getText( self, - 'Preset Manager', - 'Rename Preset:', - QtWidgets.QLineEdit.Normal, - self.presetRows[index][2] + "Preset Manager", + "Rename Preset:", + QtWidgets.QLineEdit.EchoMode.Normal, + self.presetRows[index][2], ) if OK: if badName(newName): @@ -292,8 +280,7 @@ class PresetManager(QtWidgets.QDialog): continue if newName: comp, vers, oldName = self.presetRows[index] - path = os.path.join( - self.presetDir, comp, str(vers)) + path = os.path.join(self.presetDir, comp, str(vers)) newPath = os.path.join(path, newName) if self.presetExists(newPath): return @@ -311,20 +298,21 @@ class PresetManager(QtWidgets.QDialog): self.drawPresetList() path = os.path.dirname(newPath) for i, comp in enumerate(self.core.selectedComponents): - if self.core.getPresetDir(comp) == path \ - and comp.currentPreset == oldName: + if self.core.getPresetDir(comp) == path and comp.currentPreset == oldName: self.core.openPreset(newPath, i, newName) self.parent.updateComponentTitle(i, False) self.parent.drawPreview() def openImportDialog(self): filename, _ = QtWidgets.QFileDialog.getOpenFileName( - self, "Import Preset File", + self, + "Import Preset File", self.settings.value("presetDir"), - "Preset Files (*.avl)") + "Preset Files (*.avl)", + ) if filename: # get installed path & ask user to overwrite if needed - path = '' + path = "" while True: if path: if self.presetExists(path): @@ -345,15 +333,16 @@ class PresetManager(QtWidgets.QDialog): if index == -1: return filename, _ = QtWidgets.QFileDialog.getSaveFileName( - self, "Export Preset", + self, + "Export Preset", self.settings.value("presetDir"), - "Preset Files (*.avl)") + "Preset Files (*.avl)", + ) if filename: comp, vers, name = self.presetRows[index] if not self.core.exportPreset(filename, comp, vers, name): self.parent.showMessage( - msg='Couldn\'t export %s.' % filename, - parent=self + msg="Couldn't export %s." % filename, parent=self ) self.settings.setValue("presetDir", os.path.dirname(filename)) diff --git a/src/gui/preview_thread.py b/src/gui/preview_thread.py index 3943a5c..1d78516 100644 --- a/src/gui/preview_thread.py +++ b/src/gui/preview_thread.py @@ -1,9 +1,10 @@ -''' - Thread that runs to create QImages for MainWindow's preview label. - Processes a queue of component lists. -''' -from PyQt5 import QtCore, QtGui, uic -from PyQt5.QtCore import pyqtSignal, pyqtSlot +""" +Thread that runs to create QImages for MainWindow's preview label. +Processes a queue of component lists. +""" + +from PyQt6 import QtCore, QtGui, uic +from PyQt6.QtCore import pyqtSignal, pyqtSlot from PIL import Image from PIL.ImageQt import ImageQt from queue import Queue, Empty @@ -26,8 +27,8 @@ class Worker(QtCore.QObject): super().__init__() self.core = core self.settings = settings - width = int(self.settings.value('outputWidth')) - height = int(self.settings.value('outputHeight')) + width = int(self.settings.value("outputWidth")) + height = int(self.settings.value("outputHeight")) self.queue = queue self.background = Checkerboard(width, height) @@ -35,10 +36,10 @@ class Worker(QtCore.QObject): @pyqtSlot(list) def createPreviewImage(self, components): dic = { - "components": components, + "components": components, } self.queue.put(dic) - log.debug('Preview thread id: {}'.format(int(QtCore.QThread.currentThreadId()))) + log.debug("Preview thread id: {}".format(int(QtCore.QThread.currentThreadId()))) @pyqtSlot() def process(self): @@ -49,31 +50,34 @@ class Worker(QtCore.QObject): self.queue.get(block=False) except Empty: continue - width = int(self.settings.value('outputWidth')) - height = int(self.settings.value('outputHeight')) - if self.background.width != width \ - or self.background.height != height: + width = int(self.settings.value("outputWidth")) + height = int(self.settings.value("outputHeight")) + if self.background.width != width or self.background.height != height: self.background = Checkerboard(width, height) frame = self.background.copy() - log.info('Creating new preview frame') + log.info("Creating new preview frame") components = nextPreviewInformation["components"] for component in reversed(components): try: component.lockSize(width, height) newFrame = component.previewRender() component.unlockSize() - frame = Image.alpha_composite( - frame, newFrame - ) + frame = Image.alpha_composite(frame, newFrame) except ValueError as e: - errMsg = "Bad frame returned by %s's preview renderer. " \ - "%s. New frame size was %s*%s; should be %s*%s." % ( - str(component), str(e).capitalize(), - newFrame.width, newFrame.height, - width, height + errMsg = ( + "Bad frame returned by %s's preview renderer. " + "%s. New frame size was %s*%s; should be %s*%s." + % ( + str(component), + str(e).capitalize(), + newFrame.width, + newFrame.height, + width, + height, ) + ) log.critical(errMsg) self.error.emit(errMsg) break diff --git a/src/gui/preview_win.py b/src/gui/preview_win.py index d910456..f52f8a3 100644 --- a/src/gui/preview_win.py +++ b/src/gui/preview_win.py @@ -1,18 +1,20 @@ -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt6 import QtCore, QtGui, QtWidgets import logging -log = logging.getLogger('AVP.Gui.PreviewWindow') +log = logging.getLogger("AVP.Gui.PreviewWindow") class PreviewWindow(QtWidgets.QLabel): - ''' - Paints the preview QLabel in MainWindow and maintains the aspect ratio - when the window is resized. - ''' + """ + Paints the preview QLabel in MainWindow and maintains the aspect ratio + when the window is resized. + """ + def __init__(self, parent, img): super().__init__() self.parent = parent - self.setFrameStyle(QtWidgets.QFrame.StyledPanel) + # FIXME + # self.setFrameStyle(QtWidgets.QFrame.StyledPanel) self.pixmap = QtGui.QPixmap(img) def paintEvent(self, event): @@ -21,12 +23,13 @@ class PreviewWindow(QtWidgets.QLabel): point = QtCore.QPoint(0, 0) scaledPix = self.pixmap.scaled( size, - QtCore.Qt.KeepAspectRatio, - transformMode=QtCore.Qt.SmoothTransformation) + QtCore.Qt.AspectRatioMode.KeepAspectRatio, + transformMode=QtCore.Qt.TransformationMode.SmoothTransformation, + ) # start painting the label from left upper corner - point.setX(int((size.width() - scaledPix.width())/2)) - point.setY(int((size.height() - scaledPix.height())/2)) + point.setX(int((size.width() - scaledPix.width()) / 2)) + point.setY(int((size.height() - scaledPix.height()) / 2)) painter.drawPixmap(point, scaledPix) def changePixmap(self, img): @@ -40,22 +43,16 @@ class PreviewWindow(QtWidgets.QLabel): i = self.parent.listWidget_componentList.currentRow() if i >= 0: component = self.parent.core.selectedComponents[i] - if not hasattr(component, 'previewClickEvent'): + if not hasattr(component, "previewClickEvent"): return - pos = (event.x(), event.y()) + qpoint = event.position().toPoint() + pos = (qpoint.x(), qpoint.y()) size = (self.width(), self.height()) butt = event.button() - log.info('Click event for #%s: %s button %s' % ( - i, pos, butt)) - component.previewClickEvent( - pos, size, butt - ) + log.info("Click event for #%s: %s button %s" % (i, pos, butt)) + component.previewClickEvent(pos, size, butt) @QtCore.pyqtSlot(str) def threadError(self, msg): - self.parent.showMessage( - msg=msg, - icon='Critical', - parent=self - ) - log.info('%', repr(self.parent)) + self.parent.showMessage(msg=msg, icon="Critical", parent=self) + log.info("%", repr(self.parent)) -- cgit v1.2.3