From 733c005eeaf5d3ff15e0f60d320f5c03472bad60 Mon Sep 17 00:00:00 2001 From: tassaron Date: Mon, 14 Aug 2017 18:41:45 -0400 Subject: undoable removeComponent action --- src/gui/actions.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/gui/actions.py (limited to 'src/gui/actions.py') diff --git a/src/gui/actions.py b/src/gui/actions.py new file mode 100644 index 0000000..5cf64e1 --- /dev/null +++ b/src/gui/actions.py @@ -0,0 +1,37 @@ +''' + QCommand classes for every undoable user action performed in the MainWindow +''' +from PyQt5.QtWidgets import QUndoCommand + + +class RemoveComponent(QUndoCommand): + def __init__(self, parent, selectedRows): + super().__init__('Remove component') + self.parent = parent + componentList = self.parent.window.listWidget_componentList + self.selectedRows = [ + componentList.row(selected) for selected in selectedRows + ] + self.components = [ + parent.core.selectedComponents[i] for i in self.selectedRows + ] + + def redo(self): + stackedWidget = self.parent.window.stackedWidget + componentList = self.parent.window.listWidget_componentList + for index in self.selectedRows: + stackedWidget.removeWidget(self.parent.pages[index]) + componentList.takeItem(index) + self.parent.core.removeComponent(index) + self.parent.pages.pop(index) + self.parent.changeComponentWidget() + self.parent.drawPreview() + + def undo(self): + componentList = self.parent.window.listWidget_componentList + for index, comp in zip(self.selectedRows, self.components): + self.parent.core.insertComponent( + index, comp, self.parent + ) + self.parent.drawPreview() + -- cgit v1.2.3 From f66ec40ba6e9c4062d1e41894e0a88f713add96d Mon Sep 17 00:00:00 2001 From: tassaron Date: Wed, 16 Aug 2017 22:17:12 -0400 Subject: undoable component movement --- src/core.py | 1 + src/gui/actions.py | 39 +++++++++++++++++++++++++++++++++++++++ src/gui/mainwindow.py | 18 +++++------------- 3 files changed, 45 insertions(+), 13 deletions(-) (limited to 'src/gui/actions.py') diff --git a/src/core.py b/src/core.py index cee0f56..14517b0 100644 --- a/src/core.py +++ b/src/core.py @@ -73,6 +73,7 @@ class Core: compPos = len(self.selectedComponents) if len(self.selectedComponents) > 50: return None + if type(component) is int: # create component using module index in self.modules moduleIndex = int(component) diff --git a/src/gui/actions.py b/src/gui/actions.py index 5cf64e1..5a0869d 100644 --- a/src/gui/actions.py +++ b/src/gui/actions.py @@ -35,3 +35,42 @@ class RemoveComponent(QUndoCommand): ) self.parent.drawPreview() + +class MoveComponent(QUndoCommand): + def __init__(self, parent, row, newRow, tag): + super().__init__("Move component %s" % tag) + self.parent = parent + self.row = row + self.newRow = newRow + self.id_ = ord(tag[0]) + + def id(self): + '''If 2 consecutive updates have same id, Qt will call mergeWith()''' + return self.id_ + + def mergeWith(self, other): + self.newRow = other.newRow + return True + + def do(self, rowa, rowb): + componentList = self.parent.window.listWidget_componentList + + page = self.parent.pages.pop(rowa) + self.parent.pages.insert(rowb, page) + + item = componentList.takeItem(rowa) + componentList.insertItem(rowb, item) + + stackedWidget = self.parent.window.stackedWidget + widget = stackedWidget.removeWidget(page) + stackedWidget.insertWidget(rowb, page) + componentList.setCurrentRow(rowb) + stackedWidget.setCurrentIndex(rowb) + self.parent.core.moveComponent(rowa, rowb) + self.parent.drawPreview(True) + + def redo(self): + self.do(self.row, self.newRow) + + def undo(self): + self.do(self.newRow, self.row) diff --git a/src/gui/mainwindow.py b/src/gui/mainwindow.py index 47111a0..26464a9 100644 --- a/src/gui/mainwindow.py +++ b/src/gui/mainwindow.py @@ -716,27 +716,19 @@ class MainWindow(QtWidgets.QMainWindow): def moveComponent(self, change): '''Moves a component relatively from its current position''' componentList = self.window.listWidget_componentList + tag = change if change == 'top': change = -componentList.currentRow() elif change == 'bottom': change = len(componentList)-componentList.currentRow()-1 - stackedWidget = self.window.stackedWidget + else: + tag = 'down' if change == 1 else 'up' row = componentList.currentRow() newRow = row + change if newRow > -1 and newRow < componentList.count(): - self.core.moveComponent(row, newRow) - - # update widgets - page = self.pages.pop(row) - self.pages.insert(newRow, page) - item = componentList.takeItem(row) - newItem = componentList.insertItem(newRow, item) - widget = stackedWidget.removeWidget(page) - stackedWidget.insertWidget(newRow, page) - componentList.setCurrentRow(newRow) - stackedWidget.setCurrentIndex(newRow) - self.drawPreview(True) + action = MoveComponent(self, row, newRow, tag) + self.undoStack.push(action) def getComponentListMousePos(self, position): ''' -- cgit v1.2.3 From c06ca5cdcb603f1855cb0122fc2ab6d2473f3c24 Mon Sep 17 00:00:00 2001 From: tassaron Date: Thu, 17 Aug 2017 10:42:15 -0400 Subject: undoable add-comp & clear-preset actions --- src/component.py | 35 +++++++++++++++++++++++++++++++---- src/gui/actions.py | 45 ++++++++++++++++++++++++++++++++++++--------- src/gui/mainwindow.py | 31 ++++++++++++++++++++++++------- src/gui/presetmanager.py | 5 +++-- 4 files changed, 94 insertions(+), 22 deletions(-) (limited to 'src/gui/actions.py') diff --git a/src/component.py b/src/component.py index b883627..f0a8c6b 100644 --- a/src/component.py +++ b/src/component.py @@ -99,6 +99,23 @@ class ComponentMetaclass(type(QtCore.QObject)): return func(self) return errorWrapper + def presetWrapper(func): + '''Wraps loadPreset to handle the self.openingPreset boolean''' + class openingPreset: + def __init__(self, comp): + self.comp = comp + + def __enter__(self): + self.comp.openingPreset = True + + def __exit__(self, *args): + self.comp.openingPreset = False + + def presetWrapper(self, *args): + with openingPreset(self): + return func(self, *args) + return presetWrapper + def __new__(cls, name, parents, attrs): if 'ui' not in attrs: # Use module name as ui filename by default @@ -111,7 +128,7 @@ class ComponentMetaclass(type(QtCore.QObject)): 'names', # Class methods 'error', 'audio', 'properties', # Properties 'preFrameRender', 'previewRender', - 'frameRender', 'command', + 'frameRender', 'command', 'loadPreset' ) # Auto-decorate methods @@ -140,6 +157,9 @@ class ComponentMetaclass(type(QtCore.QObject)): if key == 'error': attrs[key] = cls.errorWrapper(attrs[key]) + if key == 'loadPreset': + attrs[key] = cls.presetWrapper(attrs[key]) + # Turn version string into a number try: if 'version' not in attrs: @@ -180,6 +200,7 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): self.compPos = compPos self.core = core self.currentPreset = None + self.openingPreset = False self._trackedWidgets = {} self._presetNames = {} @@ -207,7 +228,10 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): preset = self.savePreset() except Exception as e: preset = '%s occurred while saving preset' % str(e) - return '%s\n%s\n%s' % ( + + return 'Component(%s, %s, Core)\n' \ + 'Name: %s v%s\n Preset: %s' % ( + self.moduleIndex, self.compPos, self.__class__.name, str(self.__class__.version), preset ) @@ -308,6 +332,9 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): A component update triggered by the user changing a widget value Call super() at the END when subclassing this. ''' + if self.openingPreset or not hasattr(self.parent, 'undoStack'): + return self._update() + oldWidgetVals = { attr: getattr(self, attr) for attr in self._trackedWidgets @@ -328,7 +355,7 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): self.parent.undoStack.push(action) def _update(self): - '''An internal component update that is not undoable''' + '''A component update that is not undoable''' newWidgetVals = { attr: getWidgetValue(widget) @@ -684,7 +711,7 @@ class ComponentUpdate(QtWidgets.QUndoCommand): self.id_ = -1 if len(self.modifiedVals) == 1: attr, val = self.modifiedVals.popitem() - self.id_ = sum([ord(letter) for letter in attr[:14]]) + self.id_ = sum([ord(letter) for letter in attr[-14:]]) self.modifiedVals[attr] = val else: log.warning( diff --git a/src/gui/actions.py b/src/gui/actions.py index 5a0869d..cdd3dfa 100644 --- a/src/gui/actions.py +++ b/src/gui/actions.py @@ -4,6 +4,23 @@ from PyQt5.QtWidgets import QUndoCommand +class AddComponent(QUndoCommand): + def __init__(self, parent, compI, moduleI): + super().__init__( + "New %s component" % + parent.core.modules[moduleI].Component.name + ) + self.parent = parent + self.moduleI = moduleI + self.compI = compI + + def redo(self): + self.parent.core.insertComponent(self.compI, self.moduleI, self.parent) + + def undo(self): + self.parent._removeComponent(self.compI) + + class RemoveComponent(QUndoCommand): def __init__(self, parent, selectedRows): super().__init__('Remove component') @@ -17,15 +34,7 @@ class RemoveComponent(QUndoCommand): ] def redo(self): - stackedWidget = self.parent.window.stackedWidget - componentList = self.parent.window.listWidget_componentList - for index in self.selectedRows: - stackedWidget.removeWidget(self.parent.pages[index]) - componentList.takeItem(index) - self.parent.core.removeComponent(index) - self.parent.pages.pop(index) - self.parent.changeComponentWidget() - self.parent.drawPreview() + self.parent._removeComponent(self.selectedRows[0]) def undo(self): componentList = self.parent.window.listWidget_componentList @@ -74,3 +83,21 @@ class MoveComponent(QUndoCommand): def undo(self): self.do(self.newRow, self.row) + + +class ClearPreset(QUndoCommand): + def __init__(self, parent, compI): + super().__init__("Clear preset") + self.parent = parent + self.compI = compI + self.component = self.parent.core.selectedComponents[compI] + self.store = self.component.savePreset() + self.store['preset'] = self.component.currentPreset + + def redo(self): + self.parent.core.clearPreset(self.compI) + self.parent.updateComponentTitle(self.compI, False) + + def undo(self): + self.parent.core.selectedComponents[self.compI].loadPreset(self.store) + self.parent.updateComponentTitle(self.compI, self.store) diff --git a/src/gui/mainwindow.py b/src/gui/mainwindow.py index 26464a9..8000b3b 100644 --- a/src/gui/mainwindow.py +++ b/src/gui/mainwindow.py @@ -20,7 +20,9 @@ import gui.preview_thread as preview_thread from gui.preview_win import PreviewWindow from gui.presetmanager import PresetManager from gui.actions import * -from toolkit import disableWhenEncoding, disableWhenOpeningProject, checkOutput +from toolkit import ( + disableWhenEncoding, disableWhenOpeningProject, checkOutput, blockSignals +) log = logging.getLogger('AVP.MainWindow') @@ -165,7 +167,7 @@ class MainWindow(QtWidgets.QMainWindow): for i, comp in enumerate(self.core.modules): action = self.compMenu.addAction(comp.Component.name) action.triggered.connect( - lambda _, item=i: self.core.insertComponent(0, item, self) + lambda _, item=i: self.addComponent(0, item) ) self.window.pushButton_addComponent.setMenu(self.compMenu) @@ -686,7 +688,13 @@ class MainWindow(QtWidgets.QMainWindow): msg="Current FFmpeg command:\n\n %s" % " ".join(lines) ) + def addComponent(self, compPos, moduleIndex): + '''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.''' componentList = self.window.listWidget_componentList stackedWidget = self.window.stackedWidget @@ -712,6 +720,16 @@ class MainWindow(QtWidgets.QMainWindow): action = RemoveComponent(self, selected) self.undoStack.push(action) + def _removeComponent(self, index): + stackedWidget = self.window.stackedWidget + componentList = self.window.listWidget_componentList + stackedWidget.removeWidget(self.pages[index]) + componentList.takeItem(index) + self.core.removeComponent(index) + self.pages.pop(index) + self.changeComponentWidget() + self.drawPreview() + @disableWhenEncoding def moveComponent(self, change): '''Moves a component relatively from its current position''' @@ -786,9 +804,8 @@ class MainWindow(QtWidgets.QMainWindow): self.window.lineEdit_audioFile, self.window.lineEdit_outputFile ): - field.blockSignals(True) - field.setText('') - field.blockSignals(False) + with blockSignals(field): + field.setText('') self.progressBarUpdated(0) self.progressBarSetText('') self.undoStack.clear() @@ -938,8 +955,8 @@ class MainWindow(QtWidgets.QMainWindow): for i, comp in enumerate(self.core.modules): menuItem = self.submenu.addAction(comp.Component.name) menuItem.triggered.connect( - lambda _, item=i: self.core.insertComponent( - 0 if insertCompAtTop else index, item, self + lambda _, item=i: self.addComponent( + 0 if insertCompAtTop else index, item ) ) diff --git a/src/gui/presetmanager.py b/src/gui/presetmanager.py index 1cc0887..79ec539 100644 --- a/src/gui/presetmanager.py +++ b/src/gui/presetmanager.py @@ -8,6 +8,7 @@ import os from toolkit import badName from core import Core +from gui.actions import * class PresetManager(QtWidgets.QDialog): @@ -130,8 +131,8 @@ class PresetManager(QtWidgets.QDialog): def clearPreset(self, compI=None): '''Functions on mainwindow level from the context menu''' compI = self.parent.window.listWidget_componentList.currentRow() - self.core.clearPreset(compI) - self.parent.updateComponentTitle(compI, False) + action = ClearPreset(self.parent, compI) + self.parent.undoStack.push(action) def openSavePresetDialog(self): '''Functions on mainwindow level from the context menu''' -- cgit v1.2.3 From 87e762a8aa3fa97a3d43a18c59098b287bb95506 Mon Sep 17 00:00:00 2001 From: tassaron Date: Thu, 17 Aug 2017 20:12:46 -0400 Subject: undoable preset open, rename, and delete' --- src/core.py | 4 +-- src/gui/actions.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ src/gui/presetmanager.py | 49 ++++++++++++++++-------------- 3 files changed, 107 insertions(+), 25 deletions(-) (limited to 'src/gui/actions.py') diff --git a/src/core.py b/src/core.py index 7609698..d9499f7 100644 --- a/src/core.py +++ b/src/core.py @@ -83,7 +83,7 @@ class Core: ) # init component's widget for loading/saving presets component.widget(loader) - # use autoUpdate() method before update() this 1 time to set attrs + # use autoUpdate() method before update() this 1 time to set attrs component._autoUpdate() else: moduleIndex = -1 @@ -169,7 +169,7 @@ class Core: def getPresetDir(self, comp): '''Get the preset subdir for a particular version of a component''' - return os.path.join(Core.presetDir, str(comp), str(comp.version)) + return os.path.join(Core.presetDir, comp.name, str(comp.version)) def openProject(self, loader, filepath): ''' loader is the object calling this method which must have diff --git a/src/gui/actions.py b/src/gui/actions.py index cdd3dfa..0fe97f2 100644 --- a/src/gui/actions.py +++ b/src/gui/actions.py @@ -2,7 +2,14 @@ QCommand classes for every undoable user action performed in the MainWindow ''' from PyQt5.QtWidgets import QUndoCommand +import os +from core import Core + + +# =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ +# COMPONENT ACTIONS +# =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ class AddComponent(QUndoCommand): def __init__(self, parent, compI, moduleI): @@ -85,6 +92,10 @@ class MoveComponent(QUndoCommand): self.do(self.newRow, self.row) +# =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ +# PRESET ACTIONS +# =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ + class ClearPreset(QUndoCommand): def __init__(self, parent, compI): super().__init__("Clear preset") @@ -101,3 +112,71 @@ class ClearPreset(QUndoCommand): def undo(self): self.parent.core.selectedComponents[self.compI].loadPreset(self.store) self.parent.updateComponentTitle(self.compI, self.store) + + +class OpenPreset(QUndoCommand): + def __init__(self, parent, presetName, compI): + super().__init__("Open %s preset" % presetName) + self.parent = parent + self.presetName = presetName + self.compI = compI + + comp = self.parent.core.selectedComponents[compI] + self.store = comp.savePreset() + self.store['preset'] = str(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.parent.updateComponentTitle(self.compI, self.store) + + +class RenamePreset(QUndoCommand): + def __init__(self, parent, path, oldName, newName): + super().__init__('Rename preset') + self.parent = parent + self.path = path + self.oldName = oldName + self.newName = newName + + def redo(self): + self.parent.renamePreset(self.path, self.oldName, self.newName) + + def undo(self): + self.parent.renamePreset(self.path, self.newName, self.oldName) + + +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.store = self.parent.core.getPreset(self.path) + 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) + if self.presetName == str(comp.currentPreset) + ] + + def redo(self): + os.remove(self.path) + for i in self.loadedPresets: + self.parent.core.clearPreset(i) + self.parent.parent.updateComponentTitle(i, False) + self.parent.findPresets() + self.parent.drawPresetList() + + def undo(self): + self.parent.createNewPreset(*self.preset, self.store) + selectedComponents = self.parent.core.selectedComponents + for i in self.loadedPresets: + selectedComponents[i].currentPreset = self.presetName + self.parent.parent.updateComponentTitle(i) + self.parent.findPresets() + self.parent.drawPresetList() diff --git a/src/gui/presetmanager.py b/src/gui/presetmanager.py index 79ec539..dce5333 100644 --- a/src/gui/presetmanager.py +++ b/src/gui/presetmanager.py @@ -197,11 +197,15 @@ class PresetManager(QtWidgets.QDialog): def openPreset(self, presetName, compPos=None): componentList = self.parent.window.listWidget_componentList - selectedComponents = self.core.selectedComponents - index = compPos if compPos is not None else componentList.currentRow() if index == -1: return + action = OpenPreset(self, presetName, index) + self.parent.undoStack.push(action) + + def _openPreset(self, presetName, index): + selectedComponents = self.core.selectedComponents + componentName = str(selectedComponents[index]).strip() version = selectedComponents[index].version dirname = os.path.join(self.presetDir, componentName, str(version)) @@ -225,16 +229,10 @@ class PresetManager(QtWidgets.QDialog): if not ch: return self.deletePreset(comp, vers, name) - self.findPresets() - self.drawPresetList() - - for i, comp in enumerate(self.core.selectedComponents): - if comp.currentPreset == name: - self.clearPreset(i) def deletePreset(self, comp, vers, name): - filepath = os.path.join(self.presetDir, comp, str(vers), name) - os.remove(filepath) + action = DeletePreset(self, comp, vers, name) + self.parent.undoStack.push(action) def warnMessage(self, window=None): self.parent.showMessage( @@ -271,7 +269,6 @@ class PresetManager(QtWidgets.QDialog): return index def openRenamePresetDialog(self): - # TODO: maintain consistency by changing this to call createNewPreset() presetList = self.window.listWidget_presets index = self.getPresetRow() if index == -1: @@ -294,22 +291,28 @@ class PresetManager(QtWidgets.QDialog): path = os.path.join( self.presetDir, comp, str(vers)) newPath = os.path.join(path, newName) - oldPath = os.path.join(path, oldName) if self.presetExists(newPath): return - if os.path.exists(newPath): - os.remove(newPath) - os.rename(oldPath, newPath) - self.findPresets() - self.drawPresetList() - for i, comp in enumerate(self.core.selectedComponents): - if self.core.getPresetDir(comp) == path \ - and comp.currentPreset == oldName: - self.core.openPreset(newPath, i, newName) - self.parent.updateComponentTitle(i, False) - self.parent.drawPreview() + action = RenamePreset(self, path, oldName, newName) + self.parent.undoStack.push(action) break + def renamePreset(self, path, oldName, newName): + oldPath = os.path.join(path, oldName) + newPath = os.path.join(path, newName) + if os.path.exists(newPath): + os.remove(newPath) + os.rename(oldPath, newPath) + self.findPresets() + 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: + self.core.openPreset(newPath, i, newName) + self.parent.updateComponentTitle(i, False) + self.parent.drawPreview() + def openImportDialog(self): filename, _ = QtWidgets.QFileDialog.getOpenFileName( self.window, "Import Preset File", -- cgit v1.2.3 From c07f2426ceeada205fdacbfba66329179a74a1dc Mon Sep 17 00:00:00 2001 From: tassaron Date: Sat, 19 Aug 2017 18:32:12 -0400 Subject: fixed issues with undoing relative widgets --- src/component.py | 198 +++++++++++++++++++++++++++++++++------------ src/components/color.py | 2 - src/components/image.py | 2 - src/components/life.py | 1 - src/components/sound.py | 1 - src/components/spectrum.py | 4 +- src/components/text.py | 1 - src/components/video.py | 2 - src/components/waveform.py | 2 +- src/core.py | 11 +-- src/gui/actions.py | 11 ++- src/gui/mainwindow.py | 4 +- src/gui/presetmanager.py | 4 + src/gui/preview_thread.py | 2 +- src/gui/preview_win.py | 2 +- src/main.py | 2 +- src/toolkit/common.py | 47 +++++++++-- 17 files changed, 215 insertions(+), 81 deletions(-) (limited to 'src/gui/actions.py') diff --git a/src/component.py b/src/component.py index 1fe9237..ba86422 100644 --- a/src/component.py +++ b/src/component.py @@ -9,6 +9,7 @@ import sys import math import time import logging +from copy import copy from toolkit.frame import BlankFrame from toolkit import ( @@ -113,14 +114,20 @@ class ComponentMetaclass(type(QtCore.QObject)): def presetWrapper(self, *args): with openingPreset(self): - return func(self, *args) + try: + return func(self, *args) + except Exception: + try: + raise ComponentError(self, 'preset loader') + except ComponentError: + return return presetWrapper def updateWrapper(func): ''' - For undoable updates triggered by the user, - call _userUpdate() after the subclass's update() method. - For non-user updates, call _autoUpdate() + Calls _preUpdate before every subclass update(). + Afterwards, for non-user updates, calls _autoUpdate(). + For undoable updates triggered by the user, calls _userUpdate() ''' class wrap: def __init__(self, comp, auto): @@ -128,24 +135,57 @@ class ComponentMetaclass(type(QtCore.QObject)): self.auto = auto def __enter__(self): - pass + self.comp._preUpdate() def __exit__(self, *args): if self.auto or self.comp.openingPreset \ or not hasattr(self.comp.parent, 'undoStack'): + log.verbose('Automatic update') self.comp._autoUpdate() else: + log.verbose('User update') self.comp._userUpdate() def updateWrapper(self, **kwargs): - auto = False - if 'auto' in kwargs: - auto = kwargs['auto'] - + auto = kwargs['auto'] if 'auto' in kwargs else False with wrap(self, auto): - return func(self) + try: + return func(self) + except Exception: + try: + raise ComponentError(self, 'update method') + except ComponentError: + return return updateWrapper + def widgetWrapper(func): + '''Connects all widgets to update method after the subclass's method''' + class wrap: + def __init__(self, comp): + self.comp = comp + + def __enter__(self): + pass + + def __exit__(self, *args): + for widgetList in self.comp._allWidgets.values(): + for widget in widgetList: + log.verbose('Connecting %s' % str( + widget.__class__.__name__)) + connectWidget(widget, self.comp.update) + + def widgetWrapper(self, *args, **kwargs): + auto = kwargs['auto'] if 'auto' in kwargs else False + with wrap(self): + try: + return func(self, *args, **kwargs) + except Exception: + try: + raise ComponentError(self, 'widget creation') + except ComponentError: + return + return widgetWrapper + def __new__(cls, name, parents, attrs): if 'ui' not in attrs: # Use module name as ui filename by default @@ -153,13 +193,12 @@ class ComponentMetaclass(type(QtCore.QObject)): attrs['__module__'].split('.')[-1] )[0] - # if parents[0] == QtCore.QObject: else: decorate = ( 'names', # Class methods 'error', 'audio', 'properties', # Properties 'preFrameRender', 'previewRender', 'frameRender', 'command', - 'loadPreset', 'update' + 'loadPreset', 'update', 'widget', ) # Auto-decorate methods @@ -184,6 +223,8 @@ class ComponentMetaclass(type(QtCore.QObject)): attrs[key] = cls.loadPresetWrapper(attrs[key]) elif key == 'update': attrs[key] = cls.updateWrapper(attrs[key]) + elif key == 'widget' and parents[0] != QtCore.QObject: + attrs[key] = cls.widgetWrapper(attrs[key]) # Turn version string into a number try: @@ -224,23 +265,28 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): self.moduleIndex = moduleIndex self.compPos = compPos self.core = core - self.currentPreset = None - self.openingPreset = False + # STATUS VARIABLES + self.currentPreset = None + self._allWidgets = {} self._trackedWidgets = {} self._presetNames = {} self._commandArgs = {} self._colorWidgets = {} self._colorFuncs = {} self._relativeWidgets = {} - # pixel values stored as floats + # Pixel values stored as floats self._relativeValues = {} - # maximum values of spinBoxes at 1080p (Core.resolutions[0]) + # Maximum values of spinBoxes at 1080p (Core.resolutions[0]) self._relativeMaximums = {} + # LOCKING VARIABLES + self.openingPreset = False self._lockedProperties = None self._lockedError = None self._lockedSize = None + # If set to a dict, values are used as basis to update relative widgets + self.oldAttrs = None # Stop lengthy processes in response to this variable self.canceled = False @@ -338,21 +384,21 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): ''' self.parent = parent self.settings = parent.settings + log.verbose('Creating UI for %s #%s\'s widget' % ( + self.name, self.compPos + )) self.page = self.loadUi(self.__class__.ui) - # Connect widget signals - widgets = { + # Find all normal widgets which will be connected after subclass method + self._allWidgets = { 'lineEdit': self.page.findChildren(QtWidgets.QLineEdit), 'checkBox': self.page.findChildren(QtWidgets.QCheckBox), 'spinBox': self.page.findChildren(QtWidgets.QSpinBox), 'comboBox': self.page.findChildren(QtWidgets.QComboBox), } - widgets['spinBox'].extend( + self._allWidgets['spinBox'].extend( self.page.findChildren(QtWidgets.QDoubleSpinBox) ) - for widgetList in widgets.values(): - for widget in widgetList: - connectWidget(widget, self.update) def update(self): ''' @@ -427,10 +473,15 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ # "Private" Methods # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ + def _preUpdate(self): + '''Happens before subclass update()''' + for attr in self._relativeWidgets: + self.updateRelativeWidget(attr) + def _userUpdate(self): - '''An undoable component update triggered by the user''' + '''Happens after subclass update() for an undoable update by user.''' oldWidgetVals = { - attr: getattr(self, attr) + attr: copy(getattr(self, attr)) for attr in self._trackedWidgets } newWidgetVals = { @@ -443,13 +494,12 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): for attr, val in newWidgetVals.items() if val != oldWidgetVals[attr] } - if modifiedWidgets: action = ComponentUpdate(self, oldWidgetVals, modifiedWidgets) self.parent.undoStack.push(action) def _autoUpdate(self): - '''An internal component update that is not undoable''' + '''Happens after subclass update() for an internal component update.''' newWidgetVals = { attr: getWidgetValue(widget) for attr, widget in self._trackedWidgets.items() @@ -459,12 +509,12 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): def setAttrs(self, attrDict): ''' - Sets attrs (linked to trackedWidgets) in this preset to + Sets attrs (linked to trackedWidgets) in this component to the values in the attrDict. Mutates certain widget values if needed ''' for attr, val in attrDict.items(): if attr in self._colorWidgets: - # Color Widgets: text stored as tuple & update the button color + # Color Widgets must have a tuple & have a button to update if type(val) is tuple: rgbTuple = val else: @@ -475,15 +525,25 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): self._colorWidgets[attr].setStyleSheet(btnStyle) setattr(self, attr, rgbTuple) - elif attr in self._relativeWidgets: - # Relative widgets: number scales to fit export resolution - self.updateRelativeWidget(attr) - setattr(self, attr, val) - else: # Normal tracked widget setattr(self, attr, val) + def setWidgetValues(self, attrDict): + ''' + Sets widgets defined by keys in trackedWidgets in this preset to + the values in the attrDict. + ''' + affectedWidgets = [ + self._trackedWidgets[attr] for attr in attrDict + ] + with blockSignals(affectedWidgets): + for attr, val in attrDict.items(): + widget = self._trackedWidgets[attr] + if attr in self._colorWidgets: + val = '%s,%s,%s' % val + setWidgetValue(widget, val) + def _sendUpdateSignal(self): if not self.core.openingProject: self.parent.drawPreview() @@ -499,6 +559,8 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): Optional args: 'presetNames': preset variable names to replace attr names 'commandArgs': arg keywords that differ from attr names + 'colorWidgets': identify attr as RGB tuple & update button CSS + 'relativeWidgets': change value proportionally to resolution NOTE: Any kwarg key set to None will selectively disable tracking. ''' @@ -542,6 +604,8 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): self._relativeMaximums[attr] = \ self._trackedWidgets[attr].maximum() self.updateRelativeWidgetMaximum(attr) + self._preUpdate() + self._autoUpdate() def pickColor(self, textWidget, button): '''Use color picker to get color input from the user.''' @@ -627,12 +691,28 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): def setRelativeWidget(self, attr, floatVal): '''Set a relative widget using a float''' pixelVal = self.pixelValForAttr(attr, floatVal) - self._trackedWidgets[attr].setValue(pixelVal) + with blockSignals(self._allWidgets): + self._trackedWidgets[attr].setValue(pixelVal) + self.update(auto=True) + + def getOldAttr(self, attr): + ''' + Returns previous state of this attr. Used to determine whether + a relative widget must be updated. Required because undoing/redoing + can make determining the 'previous' value tricky. + ''' + if self.oldAttrs is not None: + log.verbose('Using nonstandard oldAttr for %s' % attr) + return self.oldAttrs[attr] + else: + return getattr(self, attr) def updateRelativeWidget(self, attr): + '''Called by _preUpdate() for each relativeWidget before each update''' try: - oldUserValue = getattr(self, attr) - except AttributeError: + oldUserValue = self.getOldAttr(attr) + except (AttributeError, KeyError): + log.info('Using visible values as basis for relative widgets') oldUserValue = self._trackedWidgets[attr].value() newUserValue = self._trackedWidgets[attr].value() newRelativeVal = self.floatValForAttr(attr, newUserValue) @@ -645,11 +725,10 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): # means the pixel value needs to be updated log.debug('Updating %s #%s\'s relative widget: %s' % ( self.name, self.compPos, attr)) - self._trackedWidgets[attr].blockSignals(True) - self.updateRelativeWidgetMaximum(attr) - pixelVal = self.pixelValForAttr(attr, oldRelativeVal) - self._trackedWidgets[attr].setValue(pixelVal) - self._trackedWidgets[attr].blockSignals(False) + with blockSignals(self._trackedWidgets[attr]): + self.updateRelativeWidgetMaximum(attr) + pixelVal = self.pixelValForAttr(attr, oldRelativeVal) + self._trackedWidgets[attr].setValue(pixelVal) if attr not in self._relativeValues \ or oldUserValue != newUserValue: @@ -725,14 +804,22 @@ class ComponentUpdate(QtWidgets.QUndoCommand): parent.name, parent.compPos ) ) + self.undone = False self.parent = parent self.oldWidgetVals = { - attr: val + attr: copy(val) for attr, val in oldWidgetVals.items() if attr in modifiedVals } self.modifiedVals = modifiedVals + # Because relative widgets change themselves every update based on + # their previous value, we must store ALL their values in case of undo + self.redoRelativeWidgetVals = { + attr: copy(getattr(self.parent, attr)) + for attr in self.parent._relativeWidgets + } + # Determine if this update is mergeable self.id_ = -1 if len(self.modifiedVals) == 1: @@ -755,15 +842,26 @@ class ComponentUpdate(QtWidgets.QUndoCommand): return True def redo(self): + if self.undone: + log.debug('Redoing component update') + self.parent.setWidgetValues(self.modifiedVals) self.parent.setAttrs(self.modifiedVals) - self.parent._sendUpdateSignal() + if self.undone: + self.parent.oldAttrs = self.redoRelativeWidgetVals + self.parent.update(auto=True) + self.parent.oldAttrs = None + else: + self.undoRelativeWidgetVals = { + attr: copy(getattr(self.parent, attr)) + for attr in self.parent._relativeWidgets + } + self.parent._sendUpdateSignal() def undo(self): + log.debug('Undoing component update') + self.undone = True + self.parent.oldAttrs = self.undoRelativeWidgetVals + self.parent.setWidgetValues(self.oldWidgetVals) self.parent.setAttrs(self.oldWidgetVals) - with blockSignals(self.parent): - for attr, val in self.oldWidgetVals.items(): - widget = self.parent._trackedWidgets[attr] - if attr in self.parent._colorWidgets: - val = '%s,%s,%s' % val - setWidgetValue(widget, val) - self.parent._sendUpdateSignal() + self.parent.update(auto=True) + self.parent.oldAttrs = None diff --git a/src/components/color.py b/src/components/color.py index d09cee8..a55aa10 100644 --- a/src/components/color.py +++ b/src/components/color.py @@ -82,8 +82,6 @@ class Component(Component): self.page.pushButton_color2.setEnabled(False) self.page.fillWidget.setCurrentIndex(fillType) - super().update() - def previewRender(self): return self.drawFrame(self.width, self.height) diff --git a/src/components/image.py b/src/components/image.py index 63bee1a..c57b69c 100644 --- a/src/components/image.py +++ b/src/components/image.py @@ -84,7 +84,6 @@ class Component(Component): if filename: self.settings.setValue("componentDir", os.path.dirname(filename)) self.page.lineEdit_image.setText(filename) - self.update() def command(self, arg): if '=' in arg: @@ -123,4 +122,3 @@ class Component(Component): else: scaleBox.setVisible(True) stretchScaleBox.setVisible(False) - super().update() diff --git a/src/components/life.py b/src/components/life.py index 2383d30..76d2c5f 100644 --- a/src/components/life.py +++ b/src/components/life.py @@ -53,7 +53,6 @@ class Component(Component): if filename: self.settings.setValue("componentDir", os.path.dirname(filename)) self.page.lineEdit_image.setText(filename) - self.update() def shiftGrid(self, d): def newGrid(Xchange, Ychange): diff --git a/src/components/sound.py b/src/components/sound.py index 26ecf93..b86f40c 100644 --- a/src/components/sound.py +++ b/src/components/sound.py @@ -53,7 +53,6 @@ class Component(Component): if filename: self.settings.setValue("componentDir", os.path.dirname(filename)) self.page.lineEdit_sound.setText(filename) - self.update() def commandHelp(self): print('Path to audio file:\n path=/filepath/to/sound.ogg') diff --git a/src/components/spectrum.py b/src/components/spectrum.py index 89130a2..2b98dc2 100644 --- a/src/components/spectrum.py +++ b/src/components/spectrum.py @@ -76,8 +76,6 @@ class Component(Component): else: self.page.checkBox_mono.setEnabled(True) - super().update() - def previewRender(self): changedSize = self.updateChunksize() if not changedSize \ @@ -138,7 +136,7 @@ class Component(Component): '-r', self.settings.value("outputFrameRate"), '-ss', "{0:.3f}".format(startPt), '-i', - os.path.join(self.core.wd, 'background.png') + self.core.junkStream if genericPreview else inputFile, '-f', 'image2pipe', '-pix_fmt', 'rgba', diff --git a/src/components/text.py b/src/components/text.py index d3afd5c..92f0599 100644 --- a/src/components/text.py +++ b/src/components/text.py @@ -68,7 +68,6 @@ class Component(Component): self.page.spinBox_shadY.setHidden(True) self.page.label_shadBlur.setHidden(True) self.page.spinBox_shadBlur.setHidden(True) - super().update() def centerXY(self): self.setRelativeWidget('xPosition', 0.5) diff --git a/src/components/video.py b/src/components/video.py index a189f60..9c0d608 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -52,7 +52,6 @@ class Component(Component): else: self.page.label_volume.setEnabled(False) self.page.spinBox_volume.setEnabled(False) - super().update() def previewRender(self): self.updateChunksize() @@ -119,7 +118,6 @@ class Component(Component): if filename: self.settings.setValue("componentDir", os.path.dirname(filename)) self.page.lineEdit_video.setText(filename) - self.update() def getPreviewFrame(self, width, height): if not self.videoPath or not os.path.exists(self.videoPath): diff --git a/src/components/waveform.py b/src/components/waveform.py index 0743e55..5c02bbf 100644 --- a/src/components/waveform.py +++ b/src/components/waveform.py @@ -98,7 +98,7 @@ class Component(Component): '-r', self.settings.value("outputFrameRate"), '-ss', "{0:.3f}".format(startPt), '-i', - os.path.join(self.core.wd, 'background.png') + self.core.junkStream if genericPreview else inputFile, '-f', 'image2pipe', '-pix_fmt', 'rgba', diff --git a/src/core.py b/src/core.py index d9499f7..169716c 100644 --- a/src/core.py +++ b/src/core.py @@ -13,7 +13,7 @@ import toolkit log = logging.getLogger('AVP.Core') -STDOUT_LOGLVL = logging.WARNING +STDOUT_LOGLVL = logging.VERBOSE FILE_LOGLVL = logging.DEBUG @@ -81,10 +81,7 @@ class Core: component = self.modules[moduleIndex].Component( moduleIndex, compPos, self ) - # init component's widget for loading/saving presets component.widget(loader) - # use autoUpdate() method before update() this 1 time to set attrs - component._autoUpdate() else: moduleIndex = -1 log.debug( @@ -186,9 +183,8 @@ class Core: if hasattr(loader, 'window'): for widget, value in data['WindowFields']: widget = eval('loader.window.%s' % widget) - widget.blockSignals(True) - toolkit.setWidgetValue(widget, value) - widget.blockSignals(False) + with toolkit.blockSignals(widget): + toolkit.setWidgetValue(widget, value) for key, value in data['Settings']: Core.settings.setValue(key, value) @@ -474,6 +470,7 @@ class Core: 'logDir': os.path.join(dataDir, 'log'), 'presetDir': os.path.join(dataDir, 'presets'), 'componentsPath': os.path.join(wd, 'components'), + 'junkStream': os.path.join(wd, 'gui', 'background.png'), 'encoderOptions': encoderOptions, 'resolutions': [ '1920x1080', diff --git a/src/gui/actions.py b/src/gui/actions.py index 0fe97f2..1444569 100644 --- a/src/gui/actions.py +++ b/src/gui/actions.py @@ -20,11 +20,20 @@ class AddComponent(QUndoCommand): self.parent = parent self.moduleI = moduleI self.compI = compI + self.comp = None def redo(self): - self.parent.core.insertComponent(self.compI, self.moduleI, self.parent) + if self.comp is None: + self.parent.core.insertComponent( + self.compI, self.moduleI, self.parent) + else: + # inserting previously-created component + self.parent.core.insertComponent( + self.compI, self.comp, self.parent) + def undo(self): + self.comp = self.parent.core.selectedComponents[self.compI] self.parent._removeComponent(self.compI) diff --git a/src/gui/mainwindow.py b/src/gui/mainwindow.py index 8000b3b..76c53af 100644 --- a/src/gui/mainwindow.py +++ b/src/gui/mainwindow.py @@ -25,7 +25,7 @@ from toolkit import ( ) -log = logging.getLogger('AVP.MainWindow') +log = logging.getLogger('AVP.Gui.MainWindow') class MainWindow(QtWidgets.QMainWindow): @@ -76,7 +76,7 @@ class MainWindow(QtWidgets.QMainWindow): # Create the preview window and its thread, queues, and timers log.debug('Creating preview window') self.previewWindow = PreviewWindow(self, os.path.join( - Core.wd, "background.png")) + Core.wd, 'gui', "background.png")) window.verticalLayout_previewWrapper.addWidget(self.previewWindow) log.debug('Starting preview thread') diff --git a/src/gui/presetmanager.py b/src/gui/presetmanager.py index dce5333..befa7cd 100644 --- a/src/gui/presetmanager.py +++ b/src/gui/presetmanager.py @@ -5,12 +5,16 @@ from PyQt5 import QtCore, QtWidgets import string import os +import logging from toolkit import badName from core import Core from gui.actions import * +log = logging.getLogger('AVP.Gui.PresetManager') + + class PresetManager(QtWidgets.QDialog): def __init__(self, window, parent): super().__init__(parent.window) diff --git a/src/gui/preview_thread.py b/src/gui/preview_thread.py index 9615884..33a9e7a 100644 --- a/src/gui/preview_thread.py +++ b/src/gui/preview_thread.py @@ -14,7 +14,7 @@ from toolkit.frame import Checkerboard from toolkit import disableWhenOpeningProject -log = logging.getLogger("AVP.PreviewThread") +log = logging.getLogger("AVP.Gui.PreviewThread") class Worker(QtCore.QObject): diff --git a/src/gui/preview_win.py b/src/gui/preview_win.py index 40c19c6..c6b9a32 100644 --- a/src/gui/preview_win.py +++ b/src/gui/preview_win.py @@ -7,7 +7,7 @@ class PreviewWindow(QtWidgets.QLabel): Paints the preview QLabel in MainWindow and maintains the aspect ratio when the window is resized. ''' - log = logging.getLogger('AVP.PreviewWindow') + log = logging.getLogger('AVP.Gui.PreviewWindow') def __init__(self, parent, img): super(PreviewWindow, self).__init__() diff --git a/src/main.py b/src/main.py index c1278da..6d18af3 100644 --- a/src/main.py +++ b/src/main.py @@ -6,7 +6,7 @@ import logging from __init__ import wd -log = logging.getLogger('AVP.Entrypoint') +log = logging.getLogger('AVP.Main') def main(): diff --git a/src/toolkit/common.py b/src/toolkit/common.py index 51ad023..74143e8 100644 --- a/src/toolkit/common.py +++ b/src/toolkit/common.py @@ -6,19 +6,53 @@ import string import os import sys import subprocess +import logging +from copy import copy from collections import OrderedDict +log = logging.getLogger('AVP.Toolkit.Common') + + class blockSignals: - '''A context manager to temporarily block a Qt widget from updating''' - def __init__(self, widget): - self.widget = widget + ''' + Context manager to temporarily block list of QtWidgets from updating, + and guarantee restoring the previous state afterwards. + ''' + def __init__(self, widgets): + if type(widgets) is dict: + self.widgets = concatDictVals(widgets) + else: + self.widgets = ( + widgets if hasattr(widgets, '__iter__') + else [widgets] + ) def __enter__(self): - self.widget.blockSignals(True) + log.verbose('Blocking signals for %s' % ", ".join([ + str(w.__class__.__name__) for w in self.widgets + ])) + self.oldStates = [w.signalsBlocked() for w in self.widgets] + for w in self.widgets: + w.blockSignals(True) def __exit__(self, *args): - self.widget.blockSignals(False) + log.verbose('Resetting blockSignals to %s' % sum(self.oldStates)) + for w, state in zip(self.widgets, self.oldStates): + w.blockSignals(state) + + +def concatDictVals(d): + '''Concatenates all values in given dict into one list.''' + key, value = d.popitem() + d[key] = value + final = copy(value) + if type(final) is not list: + final = [final] + final.extend([val for val in d.values()]) + else: + value.extend([item for val in d.values() for item in val]) + return final def badName(name): @@ -119,12 +153,14 @@ def connectWidget(widget, func): elif type(widget) == QtWidgets.QComboBox: widget.currentIndexChanged.connect(func) else: + log.warning('Failed to connect %s ' % str(widget.__class__.__name__)) return False return True def setWidgetValue(widget, val): '''Generic setValue method for use with any typical QtWidget''' + log.verbose('Setting %s to %s' % (str(widget.__class__.__name__), val)) if type(widget) == QtWidgets.QLineEdit: widget.setText(val) elif type(widget) == QtWidgets.QSpinBox \ @@ -135,6 +171,7 @@ def setWidgetValue(widget, val): elif type(widget) == QtWidgets.QComboBox: widget.setCurrentIndex(val) else: + log.warning('Failed to set %s ' % str(widget.__class__.__name__)) return False return True -- cgit v1.2.3 From d4b63e4d4612db262424fe10c83f8eaa4f741f24 Mon Sep 17 00:00:00 2001 From: tassaron Date: Sat, 19 Aug 2017 20:45:44 -0400 Subject: remove % from log calls --- src/component.py | 32 +++++++++++++++++--------------- src/core.py | 19 ++++++++++--------- src/gui/actions.py | 3 ++- src/gui/mainwindow.py | 26 +++++++++++++++++++++----- src/gui/presetmanager.py | 2 +- src/toolkit/common.py | 16 ++++++++++------ src/toolkit/ffmpeg.py | 2 +- src/video_thread.py | 7 ++++--- 8 files changed, 66 insertions(+), 41 deletions(-) (limited to 'src/gui/actions.py') diff --git a/src/component.py b/src/component.py index ba86422..992a82e 100644 --- a/src/component.py +++ b/src/component.py @@ -40,11 +40,11 @@ class ComponentMetaclass(type(QtCore.QObject)): def renderWrapper(func): def renderWrapper(self, *args, **kwargs): try: - log.verbose('### %s #%s renders%s frame %s###' % ( + log.verbose('### %s #%s renders%s frame %s###', self.__class__.name, str(self.compPos), '' if args else ' a preview', '' if not args else '%s ' % args[0], - )) + ) return func(self, *args, **kwargs) except Exception as e: try: @@ -170,7 +170,7 @@ class ComponentMetaclass(type(QtCore.QObject)): def __exit__(self, *args): for widgetList in self.comp._allWidgets.values(): for widget in widgetList: - log.verbose('Connecting %s' % str( + log.verbose('Connecting %s', str( widget.__class__.__name__)) connectWidget(widget, self.comp.update) @@ -230,16 +230,18 @@ class ComponentMetaclass(type(QtCore.QObject)): try: if 'version' not in attrs: log.error( - 'No version attribute in %s. Defaulting to 1' % + 'No version attribute in %s. Defaulting to 1', attrs['name']) attrs['version'] = 1 else: attrs['version'] = int(attrs['version'].split('.')[0]) except ValueError: - log.critical('%s component has an invalid version string:\n%s' % ( - attrs['name'], str(attrs['version']))) + log.critical( + '%s component has an invalid version string:\n%s', + attrs['name'], str(attrs['version']) + ) except KeyError: - log.critical('%s component has no version string.' % attrs['name']) + log.critical('%s component has no version string.', attrs['name']) else: return super().__new__(cls, name, parents, attrs) quit(1) @@ -384,9 +386,9 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): ''' self.parent = parent self.settings = parent.settings - log.verbose('Creating UI for %s #%s\'s widget' % ( + log.verbose('Creating UI for %s #%s\'s widget', self.name, self.compPos - )) + ) self.page = self.loadUi(self.__class__.ui) # Find all normal widgets which will be connected after subclass method @@ -702,7 +704,7 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): can make determining the 'previous' value tricky. ''' if self.oldAttrs is not None: - log.verbose('Using nonstandard oldAttr for %s' % attr) + log.verbose('Using nonstandard oldAttr for %s', attr) return self.oldAttrs[attr] else: return getattr(self, attr) @@ -723,8 +725,9 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): and oldRelativeVal != newRelativeVal: # Float changed without pixel value changing, which # means the pixel value needs to be updated - log.debug('Updating %s #%s\'s relative widget: %s' % ( - self.name, self.compPos, attr)) + log.debug( + 'Updating %s #%s\'s relative widget: %s', + self.name, self.compPos, attr) with blockSignals(self._trackedWidgets[attr]): self.updateRelativeWidgetMaximum(attr) pixelVal = self.pixelValForAttr(attr, oldRelativeVal) @@ -828,9 +831,8 @@ class ComponentUpdate(QtWidgets.QUndoCommand): self.modifiedVals[attr] = val else: log.warning( - '%s component settings changed at once. (%s)' % ( - len(self.modifiedVals), repr(self.modifiedVals) - ) + '%s component settings changed at once. (%s)', + len(self.modifiedVals), repr(self.modifiedVals) ) def id(self): diff --git a/src/core.py b/src/core.py index 169716c..bfb8272 100644 --- a/src/core.py +++ b/src/core.py @@ -77,7 +77,8 @@ class Core: if type(component) is int: # create component using module index in self.modules moduleIndex = int(component) - log.debug('Creating new component from module #%s' % moduleIndex) + log.debug( + 'Creating new component from module #%s', str(moduleIndex)) component = self.modules[moduleIndex].Component( moduleIndex, compPos, self ) @@ -85,7 +86,7 @@ class Core: else: moduleIndex = -1 log.debug( - 'Inserting previously-created %s component' % component.name) + 'Inserting previously-created %s component', component.name) component._error.connect( loader.videoThreadError @@ -117,8 +118,9 @@ class Core: self.componentListChanged() def updateComponent(self, i): - log.debug('Auto-updating %s #%s' % ( - self.selectedComponents[i], str(i))) + log.debug( + 'Auto-updating %s #%s', + self.selectedComponents[i], str(i)) self.selectedComponents[i].update(auto=True) def moduleIndexFor(self, compName): @@ -146,9 +148,8 @@ class Core: ) except KeyError as e: log.warning( - '%s #%s\'s preset is missing value: %s' % ( - comp.name, str(compIndex), str(e) - ) + '%s #%s\'s preset is missing value: %s', + comp.name, str(compIndex), str(e) ) self.savedPresets[presetName] = dict(saveValueStore) @@ -266,7 +267,7 @@ class Core: Returns dictionary with section names as the keys, each one contains a list of tuples: (compName, version, compPresetDict) ''' - log.debug('Parsing av file: %s' % filepath) + log.debug('Parsing av file: %s', filepath) validSections = ( 'Components', 'Settings', @@ -385,7 +386,7 @@ class Core: def createProjectFile(self, filepath, window=None): '''Create a project file (.avp) using the current program state''' - log.info('Creating %s' % filepath) + log.info('Creating %s', filepath) settingsKeys = [ 'componentDir', 'inputDir', diff --git a/src/gui/actions.py b/src/gui/actions.py index 1444569..f101bd7 100644 --- a/src/gui/actions.py +++ b/src/gui/actions.py @@ -3,6 +3,7 @@ ''' from PyQt5.QtWidgets import QUndoCommand import os +from copy import copy from core import Core @@ -132,7 +133,7 @@ class OpenPreset(QUndoCommand): comp = self.parent.core.selectedComponents[compI] self.store = comp.savePreset() - self.store['preset'] = str(comp.currentPreset) + self.store['preset'] = copy(comp.currentPreset) def redo(self): self.parent._openPreset(self.presetName, self.compI) diff --git a/src/gui/mainwindow.py b/src/gui/mainwindow.py index 76c53af..833d2d1 100644 --- a/src/gui/mainwindow.py +++ b/src/gui/mainwindow.py @@ -387,30 +387,46 @@ 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. + ''' if type(presetStore) is dict: name = presetStore['preset'] if name is None or name not in self.core.savedPresets: modified = False else: modified = (presetStore != self.core.savedPresets[name]) + if modified: + log.verbose( + 'Differing values between presets: %s', + ", ".join([ + '%s: %s' % item for item in presetStore.items() + if val != self.core.savedPresets[name][key] + ]) + ) else: modified = bool(presetStore) if pos < 0: pos = len(self.core.selectedComponents)-1 - name = str(self.core.selectedComponents[pos]) + name = self.core.selectedComponents[pos].name title = str(name) if self.core.selectedComponents[pos].currentPreset: title += ' - %s' % self.core.selectedComponents[pos].currentPreset if modified: title += '*' if type(presetStore) is bool: - log.debug('Forcing %s #%s\'s modified status to %s: %s' % ( + log.debug( + 'Forcing %s #%s\'s modified status to %s: %s', name, pos, modified, title - )) + ) else: - log.debug('Setting %s #%s\'s title: %s' % ( + log.debug( + 'Setting %s #%s\'s title: %s', name, pos, title - )) + ) self.window.listWidget_componentList.item(pos).setText(title) def updateCodecs(self): diff --git a/src/gui/presetmanager.py b/src/gui/presetmanager.py index befa7cd..2445760 100644 --- a/src/gui/presetmanager.py +++ b/src/gui/presetmanager.py @@ -210,7 +210,7 @@ class PresetManager(QtWidgets.QDialog): def _openPreset(self, presetName, index): selectedComponents = self.core.selectedComponents - componentName = str(selectedComponents[index]).strip() + componentName = selectedComponents[index].name.strip() version = selectedComponents[index].version dirname = os.path.join(self.presetDir, componentName, str(version)) filepath = os.path.join(dirname, presetName) diff --git a/src/toolkit/common.py b/src/toolkit/common.py index 74143e8..95aeab3 100644 --- a/src/toolkit/common.py +++ b/src/toolkit/common.py @@ -29,15 +29,19 @@ class blockSignals: ) def __enter__(self): - log.verbose('Blocking signals for %s' % ", ".join([ - str(w.__class__.__name__) for w in self.widgets - ])) + log.verbose( + 'Blocking signals for %s', + ", ".join([ + str(w.__class__.__name__) for w in self.widgets + ]) + ) self.oldStates = [w.signalsBlocked() for w in self.widgets] for w in self.widgets: w.blockSignals(True) def __exit__(self, *args): - log.verbose('Resetting blockSignals to %s' % sum(self.oldStates)) + log.verbose( + 'Resetting blockSignals to %s', str(bool(sum(self.oldStates)))) for w, state in zip(self.widgets, self.oldStates): w.blockSignals(state) @@ -153,7 +157,7 @@ def connectWidget(widget, func): elif type(widget) == QtWidgets.QComboBox: widget.currentIndexChanged.connect(func) else: - log.warning('Failed to connect %s ' % str(widget.__class__.__name__)) + log.warning('Failed to connect %s ', str(widget.__class__.__name__)) return False return True @@ -171,7 +175,7 @@ def setWidgetValue(widget, val): elif type(widget) == QtWidgets.QComboBox: widget.setCurrentIndex(val) else: - log.warning('Failed to set %s ' % str(widget.__class__.__name__)) + log.warning('Failed to set %s ', str(widget.__class__.__name__)) return False return True diff --git a/src/toolkit/ffmpeg.py b/src/toolkit/ffmpeg.py index 8fe9148..f007f90 100644 --- a/src/toolkit/ffmpeg.py +++ b/src/toolkit/ffmpeg.py @@ -93,7 +93,7 @@ class FfmpegVideo: from component import ComponentError logFilename = os.path.join( core.Core.logDir, 'render_%s.log' % str(self.component.compPos)) - log.debug('Creating ffmpeg process (log at %s)' % logFilename) + log.debug('Creating ffmpeg process (log at %s)', logFilename) with open(logFilename, 'w') as logf: logf.write(" ".join(self.command) + '\n\n') with open(logFilename, 'a') as logf: diff --git a/src/video_thread.py b/src/video_thread.py index 87fb9bd..823ac73 100644 --- a/src/video_thread.py +++ b/src/video_thread.py @@ -179,7 +179,7 @@ class Worker(QtCore.QObject): for num, component in enumerate(reversed(self.components)) ]) print('Loaded Components:', initText) - log.info('Calling preFrameRender for %s' % initText) + log.info('Calling preFrameRender for %s', initText) self.staticComponents = {} for compNo, comp in enumerate(reversed(self.components)): try: @@ -221,12 +221,13 @@ class Worker(QtCore.QObject): if self.canceled: if canceledByComponent: - log.error('Export cancelled by component #%s (%s): %s' % ( + log.error( + 'Export cancelled by component #%s (%s): %s', compNo, comp.name, 'No message.' if comp.error() is None else ( comp.error() if type(comp.error()) is str - else comp.error()[0]) + else comp.error()[0] ) ) self.cancelExport() -- cgit v1.2.3 From 6bf8a553d6170e0ca6e7d2002e46ae327a6e5e81 Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 20 Aug 2017 18:36:43 -0400 Subject: don't merge undos when setting text with a button plus changes to life.py for pep8 compliance --- src/component.py | 5 ++++- src/components/image.py | 2 ++ src/components/life.py | 46 +++++++++++++++++++++++++++------------------- src/components/sound.py | 2 ++ src/components/video.py | 2 ++ src/gui/actions.py | 1 - 6 files changed, 37 insertions(+), 21 deletions(-) (limited to 'src/gui/actions.py') diff --git a/src/component.py b/src/component.py index 0ff2fbd..1f55a19 100644 --- a/src/component.py +++ b/src/component.py @@ -285,6 +285,7 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): # LOCKING VARIABLES self.openingPreset = False + self.mergeUndo = True self._lockedProperties = None self._lockedError = None self._lockedSize = None @@ -587,10 +588,12 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): if kwarg == 'colorWidgets': def makeColorFunc(attr): def pickColor_(): + self.mergeUndo = False self.pickColor( self._trackedWidgets[attr], self._colorWidgets[attr] ) + self.mergeUndo = True return pickColor_ self._colorFuncs = { attr: makeColorFunc(attr) for attr in kwargs[kwarg] @@ -850,7 +853,7 @@ class ComponentUpdate(QtWidgets.QUndoCommand): # Determine if this update is mergeable self.id_ = -1 - if len(self.modifiedVals) == 1: + if len(self.modifiedVals) == 1 and self.parent.mergeUndo: attr, val = self.modifiedVals.popitem() self.id_ = sum([ord(letter) for letter in attr[-14:]]) self.modifiedVals[attr] = val diff --git a/src/components/image.py b/src/components/image.py index c57b69c..dd363bf 100644 --- a/src/components/image.py +++ b/src/components/image.py @@ -83,7 +83,9 @@ class Component(Component): "Image Files (%s)" % " ".join(self.core.imageFormats)) if filename: self.settings.setValue("componentDir", os.path.dirname(filename)) + self.mergeUndo = False self.page.lineEdit_image.setText(filename) + self.mergeUndo = True def command(self, arg): if '=' in arg: diff --git a/src/components/life.py b/src/components/life.py index 5d00987..d4a455d 100644 --- a/src/components/life.py +++ b/src/components/life.py @@ -35,6 +35,7 @@ class Component(Component): self.page.toolButton_left, self.page.toolButton_right, ) + def shiftFunc(i): def shift(): self.shiftGrid(i) @@ -52,7 +53,9 @@ class Component(Component): "Image Files (%s)" % " ".join(self.core.imageFormats)) if filename: self.settings.setValue("componentDir", os.path.dirname(filename)) + self.mergeUndo = False self.page.lineEdit_image.setText(filename) + self.mergeUndo = True def shiftGrid(self, d): def newGrid(Xchange, Ychange): @@ -197,7 +200,7 @@ class Component(Component): # Circle if shape == 'circle': drawer.ellipse(outlineShape, fill=self.color) - drawer.ellipse(smallerShape, fill=(0,0,0,0)) + drawer.ellipse(smallerShape, fill=(0, 0, 0, 0)) # Lilypad elif shape == 'lilypad': @@ -207,9 +210,9 @@ class Component(Component): elif shape == 'pac-man': drawer.pieslice(outlineShape, 35, 320, fill=self.color) - hX, hY = scale(50, self.pxWidth, self.pxHeight, int) # halfline - tX, tY = scale(33, self.pxWidth, self.pxHeight, int) # thirdline - qX, qY = scale(20, self.pxWidth, self.pxHeight, int) # quarterline + hX, hY = scale(50, self.pxWidth, self.pxHeight, int) # halfline + tX, tY = scale(33, self.pxWidth, self.pxHeight, int) # thirdline + qX, qY = scale(20, self.pxWidth, self.pxHeight, int) # quarterline # Path if shape == 'path': @@ -245,19 +248,19 @@ class Component(Component): sect = ( (drawPtX, drawPtY + hY), (drawPtX + self.pxWidth, - drawPtY + self.pxHeight) + drawPtY + self.pxHeight) ) elif direction == 'left': sect = ( (drawPtX, drawPtY), (drawPtX + hX, - drawPtY + self.pxHeight) + drawPtY + self.pxHeight) ) elif direction == 'right': sect = ( (drawPtX + hX, drawPtY), (drawPtX + self.pxWidth, - drawPtY + self.pxHeight) + drawPtY + self.pxHeight) ) drawer.rectangle(sect, fill=self.color) @@ -287,20 +290,25 @@ class Component(Component): # Peace elif shape == 'peace': - line = ( - (drawPtX + hX - int(tenthX / 2), drawPtY + int(tenthY / 2)), + line = (( + drawPtX + hX - int(tenthX / 2), drawPtY + int(tenthY / 2)), (drawPtX + hX + int(tenthX / 2), - drawPtY + self.pxHeight - int(tenthY / 2)) + drawPtY + self.pxHeight - int(tenthY / 2)) ) drawer.ellipse(outlineShape, fill=self.color) - drawer.ellipse(smallerShape, fill=(0,0,0,0)) + drawer.ellipse(smallerShape, fill=(0, 0, 0, 0)) drawer.rectangle(line, fill=self.color) - slantLine = lambda difference: ( - ((drawPtX + difference), - (drawPtY + self.pxHeight - qY)), - ((drawPtX + hX), - (drawPtY + hY)), - ) + + def slantLine(difference): + return ( + (drawPtX + difference), + (drawPtY + self.pxHeight - qY) + ), + ( + (drawPtX + hX), + (drawPtY + hY) + ) + drawer.line( slantLine(qX), fill=self.color, @@ -337,13 +345,13 @@ class Component(Component): for x in range(self.pxWidth, self.width, self.pxWidth): drawer.rectangle( ((x, 0), - (x + w, self.height)), + (x + w, self.height)), fill=self.color, ) for y in range(self.pxHeight, self.height, self.pxHeight): drawer.rectangle( ((0, y), - (self.width, y + h)), + (self.width, y + h)), fill=self.color, ) diff --git a/src/components/sound.py b/src/components/sound.py index b86f40c..18d2a65 100644 --- a/src/components/sound.py +++ b/src/components/sound.py @@ -52,7 +52,9 @@ class Component(Component): "Audio Files (%s)" % " ".join(self.core.audioFormats)) if filename: self.settings.setValue("componentDir", os.path.dirname(filename)) + self.mergeUndo = False self.page.lineEdit_sound.setText(filename) + self.mergeUndo = True def commandHelp(self): print('Path to audio file:\n path=/filepath/to/sound.ogg') diff --git a/src/components/video.py b/src/components/video.py index 9c0d608..e6486ea 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -117,7 +117,9 @@ class Component(Component): ) if filename: self.settings.setValue("componentDir", os.path.dirname(filename)) + self.mergeUndo = False self.page.lineEdit_video.setText(filename) + self.mergeUndo = True def getPreviewFrame(self, width, height): if not self.videoPath or not os.path.exists(self.videoPath): diff --git a/src/gui/actions.py b/src/gui/actions.py index f101bd7..ebd9702 100644 --- a/src/gui/actions.py +++ b/src/gui/actions.py @@ -32,7 +32,6 @@ class AddComponent(QUndoCommand): self.parent.core.insertComponent( self.compI, self.comp, self.parent) - def undo(self): self.comp = self.parent.core.selectedComponents[self.compI] self.parent._removeComponent(self.compI) -- cgit v1.2.3 From 9d9c4076ac1dfccdd1a753d137d87bcf5f179e3b Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 20 Aug 2017 22:04:57 -0400 Subject: added undo button to GUI with icons that theoretically should look ok cross-platform --- src/component.py | 2 +- src/gui/actions.py | 14 +++++++------- src/gui/mainwindow.py | 36 ++++++++++++++++++++++++++++++++++++ src/gui/mainwindow.ui | 7 +++++++ 4 files changed, 51 insertions(+), 8 deletions(-) (limited to 'src/gui/actions.py') diff --git a/src/component.py b/src/component.py index 1f55a19..35fc717 100644 --- a/src/component.py +++ b/src/component.py @@ -823,7 +823,7 @@ class ComponentUpdate(QtWidgets.QUndoCommand): '''Command object for making a component action undoable''' def __init__(self, parent, oldWidgetVals, modifiedVals): super().__init__( - 'Changed %s component #%s' % ( + 'change %s component #%s' % ( parent.name, parent.compPos ) ) diff --git a/src/gui/actions.py b/src/gui/actions.py index ebd9702..8e867b9 100644 --- a/src/gui/actions.py +++ b/src/gui/actions.py @@ -15,7 +15,7 @@ from core import Core class AddComponent(QUndoCommand): def __init__(self, parent, compI, moduleI): super().__init__( - "New %s component" % + "create new %s component" % parent.core.modules[moduleI].Component.name ) self.parent = parent @@ -39,7 +39,7 @@ class AddComponent(QUndoCommand): class RemoveComponent(QUndoCommand): def __init__(self, parent, selectedRows): - super().__init__('Remove component') + super().__init__('remove component') self.parent = parent componentList = self.parent.window.listWidget_componentList self.selectedRows = [ @@ -63,7 +63,7 @@ class RemoveComponent(QUndoCommand): class MoveComponent(QUndoCommand): def __init__(self, parent, row, newRow, tag): - super().__init__("Move component %s" % tag) + super().__init__("move component %s" % tag) self.parent = parent self.row = row self.newRow = newRow @@ -107,7 +107,7 @@ class MoveComponent(QUndoCommand): class ClearPreset(QUndoCommand): def __init__(self, parent, compI): - super().__init__("Clear preset") + super().__init__("clear preset") self.parent = parent self.compI = compI self.component = self.parent.core.selectedComponents[compI] @@ -125,7 +125,7 @@ class ClearPreset(QUndoCommand): class OpenPreset(QUndoCommand): def __init__(self, parent, presetName, compI): - super().__init__("Open %s preset" % presetName) + super().__init__("open %s preset" % presetName) self.parent = parent self.presetName = presetName self.compI = compI @@ -145,7 +145,7 @@ class OpenPreset(QUndoCommand): 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 @@ -167,7 +167,7 @@ class DeletePreset(QUndoCommand): ) self.store = self.parent.core.getPreset(self.path) self.presetName = self.store['preset'] - super().__init__('Delete %s preset (%s)' % (self.presetName, compName)) + super().__init__('delete %s preset (%s)' % (self.presetName, compName)) self.loadedPresets = [ 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 2841896..3b204b7 100644 --- a/src/gui/mainwindow.py +++ b/src/gui/mainwindow.py @@ -100,6 +100,42 @@ class MainWindow(QtWidgets.QMainWindow): self.window.installEventFilter(self) componentList = self.window.listWidget_componentList + style = window.pushButton_undo.style() + undoButton = window.pushButton_undo + undoButton.setIcon( + style.standardIcon(QtWidgets.QStyle.SP_FileDialogBack) + ) + undoButton.clicked.connect(self.undoStack.undo) + undoButton.setEnabled(False) + self.undoStack.cleanChanged.connect( + lambda change: undoButton.setEnabled(self.undoStack.count()) + ) + self.undoMenu = 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() + ) + undoButton.setMenu(self.undoMenu) + + style = window.pushButton_listMoveUp.style() + window.pushButton_listMoveUp.setIcon( + style.standardIcon(QtWidgets.QStyle.SP_ArrowUp) + ) + style = window.pushButton_listMoveDown.style() + window.pushButton_listMoveDown.setIcon( + style.standardIcon(QtWidgets.QStyle.SP_ArrowDown) + ) + style = window.pushButton_removeComponent.style() + window.pushButton_removeComponent.setIcon( + style.standardIcon(QtWidgets.QStyle.SP_DialogDiscardButton) + ) + if sys.platform == 'darwin': log.debug( 'Darwin detected: showing progress label below progress bar') diff --git a/src/gui/mainwindow.ui b/src/gui/mainwindow.ui index b43d375..cd8454d 100644 --- a/src/gui/mainwindow.ui +++ b/src/gui/mainwindow.ui @@ -110,6 +110,13 @@ QLayout::SetMinimumSize + + + + Undo + + + -- cgit v1.2.3 From 05d2ebc3c69f5a876d602004f69202c5ba8b09f7 Mon Sep 17 00:00:00 2001 From: tassaron Date: Fri, 22 Apr 2022 17:09:50 -0400 Subject: make pip-installable as a package --- MANIFEST.in | 7 ++++++ setup.py | 61 ++++++++++++++++++++++++++-------------------- src/__init__.py | 6 ++--- src/__main__.py | 4 +-- src/component.py | 4 +-- src/components/color.py | 4 +-- src/components/image.py | 4 +-- src/components/life.py | 4 +-- src/components/original.py | 4 +-- src/components/sound.py | 4 +-- src/components/spectrum.py | 8 +++--- src/components/text.py | 4 +-- src/components/video.py | 8 +++--- src/components/waveform.py | 8 +++--- src/core.py | 12 ++++----- src/gui/actions.py | 2 +- src/gui/mainwindow.py | 13 +++++----- src/gui/presetmanager.py | 6 ++--- src/gui/preview_thread.py | 4 +-- src/main.py | 11 ++++----- src/toolkit/__init__.py | 2 +- src/toolkit/ffmpeg.py | 8 +++--- src/toolkit/frame.py | 2 +- src/video_thread.py | 8 +++--- 24 files changed, 106 insertions(+), 92 deletions(-) create mode 100644 MANIFEST.in (limited to 'src/gui/actions.py') diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..2b2d794 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,7 @@ +recursive-include src/tests +include src/components/*.ui +include src/gui/*.ui +include src/gui/background.png +include src/encoder-options.json +global-exclude src/components/__template__.ui +global-exclude *.py[cod] diff --git a/setup.py b/setup.py index cdf4c4a..5e01229 100644 --- a/setup.py +++ b/setup.py @@ -1,29 +1,39 @@ -from setuptools import setup -import os +from setuptools import setup, find_packages +from importlib import import_module +from os import path +import re -__version__ = '2.0.0rc5' +def getTextFromFile(filename, fallback): + try: + with open( + path.join(path.abspath(path.dirname(__file__)), filename), encoding="utf-8" + ) as f: + output = f.read() + except Exception: + output = fallback + return output -def package_files(directory): - paths = [] - for (path, directories, filenames) in os.walk(directory): - for filename in filenames: - paths.append(os.path.join('..', path, filename)) - return paths +PACKAGE_NAME = 'avp' +SOURCE_DIRECTORY = 'src' +SOURCE_PACKAGE_REGEX = re.compile(rf'^{SOURCE_DIRECTORY}') +PACKAGE_DESCRIPTION = 'Create audio visualization videos from a GUI or commandline' + + +avp = import_module(SOURCE_DIRECTORY) +source_packages = find_packages(include=[SOURCE_DIRECTORY, f'{SOURCE_DIRECTORY}.*']) +proj_packages = [SOURCE_PACKAGE_REGEX.sub(PACKAGE_NAME, name) for name in source_packages] setup( name='audio_visualizer_python', - version=__version__, + version=avp.__version__, url='https://github.com/djfun/audio-visualizer-python/tree/feature-newgui', license='MIT', - description='Create audio visualization videos from a GUI or commandline', - long_description="Create customized audio visualization videos and save " - "them as Projects to continue editing later. Different components can " - "be added and layered to add visualizers, images, videos, gradients, " - "text, etc. Use Projects created in the GUI with commandline mode to " - "automate your video production workflow without any complex syntax.", + description=PACKAGE_DESCRIPTION, + author=getTextFromFile('AUTHORS', 'djfun, tassaron'), + long_description=getTextFromFile('README.md', PACKAGE_DESCRIPTION), classifiers=[ 'Development Status :: 4 - Beta', 'License :: OSI Approved :: MIT License', @@ -35,19 +45,18 @@ setup( 'visualizer', 'visualization', 'commandline video', 'video editor', 'ffmpeg', 'podcast' ], - packages=[ - 'avpython', - 'avpython.toolkit', - 'avpython.components' + packages=proj_packages, + package_dir={PACKAGE_NAME: SOURCE_DIRECTORY}, + include_package_data=True, + install_requires=[ + 'Pillow-SIMD', + 'PyQt5', + 'numpy', + 'pytest' ], - package_dir={'avpython': 'src'}, - package_data={ - 'avpython': package_files('src'), - }, - install_requires=['Pillow-SIMD', 'PyQt5', 'numpy'], entry_points={ 'gui_scripts': [ - 'avp = avpython.main:main' + f'avp = {PACKAGE_NAME}.main:main' ], } ) diff --git a/src/__init__.py b/src/__init__.py index 73f174a..08131ce 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -3,6 +3,9 @@ import os import logging +__version__ = '2.0.0rc6' + + class Logger(logging.getLoggerClass()): ''' Custom Logger class to handle custom VERBOSE log level. @@ -31,6 +34,3 @@ if getattr(sys, 'frozen', False): else: # unfrozen wd = os.path.dirname(os.path.realpath(__file__)) - -# make relative imports work when using /src as a package -sys.path.insert(0, wd) diff --git a/src/__main__.py b/src/__main__.py index 3babeae..3206bc8 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,5 +1,5 @@ -# Allows for launching with python3 -m avpython +# Allows for launching with python3 -m avp -from avpython.main import main +from .main import main main() diff --git a/src/component.py b/src/component.py index f3ee188..33c7657 100644 --- a/src/component.py +++ b/src/component.py @@ -11,8 +11,8 @@ import time import logging from copy import copy -from toolkit.frame import BlankFrame -from toolkit import ( +from .toolkit.frame import BlankFrame +from .toolkit import ( getWidgetValue, setWidgetValue, connectWidget, rgbFromString, blockSignals ) diff --git a/src/components/color.py b/src/components/color.py index 7d4f86d..6336194 100644 --- a/src/components/color.py +++ b/src/components/color.py @@ -4,8 +4,8 @@ from PyQt5.QtGui import QColor from PIL.ImageQt import ImageQt import os -from component import Component -from toolkit.frame import BlankFrame, FloodFrame, FramePainter, PaintColor +from ..component import Component +from ..toolkit.frame import BlankFrame, FloodFrame, FramePainter, PaintColor class Component(Component): diff --git a/src/components/image.py b/src/components/image.py index dd363bf..42f9564 100644 --- a/src/components/image.py +++ b/src/components/image.py @@ -2,8 +2,8 @@ from PIL import Image, ImageDraw, ImageEnhance from PyQt5 import QtGui, QtCore, QtWidgets import os -from component import Component -from toolkit.frame import BlankFrame +from ..component import Component +from ..toolkit.frame import BlankFrame class Component(Component): diff --git a/src/components/life.py b/src/components/life.py index 7a610eb..94704bc 100644 --- a/src/components/life.py +++ b/src/components/life.py @@ -4,8 +4,8 @@ from PIL import Image, ImageDraw, ImageEnhance, ImageChops, ImageFilter import os import math -from component import Component -from toolkit.frame import BlankFrame, scale +from ..component import Component +from ..toolkit.frame import BlankFrame, scale class Component(Component): diff --git a/src/components/original.py b/src/components/original.py index f886374..80228fe 100644 --- a/src/components/original.py +++ b/src/components/original.py @@ -6,8 +6,8 @@ import os import time from copy import copy -from component import Component -from toolkit.frame import BlankFrame +from ..component import Component +from ..toolkit.frame import BlankFrame class Component(Component): diff --git a/src/components/sound.py b/src/components/sound.py index 18d2a65..118ea23 100644 --- a/src/components/sound.py +++ b/src/components/sound.py @@ -1,8 +1,8 @@ from PyQt5 import QtGui, QtCore, QtWidgets import os -from component import Component -from toolkit.frame import BlankFrame +from ..component import Component +from ..toolkit.frame import BlankFrame class Component(Component): diff --git a/src/components/spectrum.py b/src/components/spectrum.py index 6675f5b..d1f8fb6 100644 --- a/src/components/spectrum.py +++ b/src/components/spectrum.py @@ -6,10 +6,10 @@ import subprocess import time import logging -from component import Component -from toolkit.frame import BlankFrame, scale -from toolkit import checkOutput, connectWidget -from toolkit.ffmpeg import ( +from ..component import Component +from ..toolkit.frame import BlankFrame, scale +from ..toolkit import checkOutput, connectWidget +from ..toolkit.ffmpeg import ( openPipe, closePipe, getAudioDuration, FfmpegVideo, exampleSound ) diff --git a/src/components/text.py b/src/components/text.py index 32a108e..e8c5a9c 100644 --- a/src/components/text.py +++ b/src/components/text.py @@ -4,8 +4,8 @@ from PyQt5 import QtGui, QtCore, QtWidgets import os import logging -from component import Component -from toolkit.frame import FramePainter, PaintColor +from ..component import Component +from ..toolkit.frame import FramePainter, PaintColor log = logging.getLogger('AVP.Components.Text') diff --git a/src/components/video.py b/src/components/video.py index 8ad21b5..070940d 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -5,10 +5,10 @@ import math import subprocess import logging -from component import Component -from toolkit.frame import BlankFrame, scale -from toolkit.ffmpeg import openPipe, closePipe, testAudioStream, FfmpegVideo -from toolkit import checkOutput +from ..component import Component +from ..toolkit.frame import BlankFrame, scale +from ..toolkit.ffmpeg import openPipe, closePipe, testAudioStream, FfmpegVideo +from ..toolkit import checkOutput log = logging.getLogger('AVP.Components.Video') diff --git a/src/components/waveform.py b/src/components/waveform.py index cbfc47f..1a6035f 100644 --- a/src/components/waveform.py +++ b/src/components/waveform.py @@ -6,10 +6,10 @@ import math import subprocess import logging -from component import Component -from toolkit.frame import BlankFrame, scale -from toolkit import checkOutput -from toolkit.ffmpeg import ( +from ..component import Component +from ..toolkit.frame import BlankFrame, scale +from ..toolkit import checkOutput +from ..toolkit.ffmpeg import ( openPipe, closePipe, getAudioDuration, FfmpegVideo, exampleSound ) diff --git a/src/core.py b/src/core.py index d7445c9..bc6f9b4 100644 --- a/src/core.py +++ b/src/core.py @@ -9,12 +9,12 @@ import json from importlib import import_module import logging -import toolkit +from . import toolkit log = logging.getLogger('AVP.Core') STDOUT_LOGLVL = logging.WARNING -FILE_LOGLVL = None +FILE_LOGLVL = logging.ERROR class Core: @@ -47,7 +47,7 @@ class Core: yield name log.debug('Importing component modules') self.modules = [ - import_module('components.%s' % name) + import_module('.components.%s' % name, __package__) for name in findComponents() ] # store canonical module names and indexes @@ -426,7 +426,7 @@ class Core: def newVideoWorker(self, loader, audioFile, outputPath): '''loader is MainWindow or Command object which must own the thread''' - import video_thread + from . import video_thread self.videoThread = QtCore.QThread(loader) videoWorker = video_thread.Worker( loader, audioFile, outputPath, self.selectedComponents @@ -450,8 +450,8 @@ class Core: @classmethod def storeSettings(cls): '''Store settings/paths to directories as class variables''' - from __init__ import wd - from toolkit.ffmpeg import findFfmpeg + from .__init__ import wd + from .toolkit.ffmpeg import findFfmpeg cls.wd = wd dataDir = QtCore.QStandardPaths.writableLocation( diff --git a/src/gui/actions.py b/src/gui/actions.py index 8e867b9..eb7b953 100644 --- a/src/gui/actions.py +++ b/src/gui/actions.py @@ -5,7 +5,7 @@ from PyQt5.QtWidgets import QUndoCommand import os from copy import copy -from core import Core +from ..core import Core # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ diff --git a/src/gui/mainwindow.py b/src/gui/mainwindow.py index 75534c2..da8370d 100644 --- a/src/gui/mainwindow.py +++ b/src/gui/mainwindow.py @@ -16,12 +16,12 @@ import filecmp import time import logging -from core import Core -import gui.preview_thread as preview_thread -from gui.preview_win import PreviewWindow -from gui.presetmanager import PresetManager -from gui.actions import * -from toolkit import ( +from ..core import Core +from . import preview_thread +from .preview_win import PreviewWindow +from .presetmanager import PresetManager +from .actions import * +from ..toolkit import ( disableWhenEncoding, disableWhenOpeningProject, checkOutput, blockSignals ) @@ -65,7 +65,6 @@ class MainWindow(QtWidgets.QMainWindow): self.settings = Core.settings # Register clean-up functions - signal.signal(signal.SIGINT, self.terminate) atexit.register(self.cleanUp) # Create stack of undoable user actions diff --git a/src/gui/presetmanager.py b/src/gui/presetmanager.py index 2445760..1e47a7f 100644 --- a/src/gui/presetmanager.py +++ b/src/gui/presetmanager.py @@ -7,9 +7,9 @@ import string import os import logging -from toolkit import badName -from core import Core -from gui.actions import * +from ..toolkit import badName +from ..core import Core +from .actions import * log = logging.getLogger('AVP.Gui.PresetManager') diff --git a/src/gui/preview_thread.py b/src/gui/preview_thread.py index d3e0581..7829476 100644 --- a/src/gui/preview_thread.py +++ b/src/gui/preview_thread.py @@ -10,8 +10,8 @@ from queue import Queue, Empty import os import logging -from toolkit.frame import Checkerboard -from toolkit import disableWhenOpeningProject +from ..toolkit.frame import Checkerboard +from ..toolkit import disableWhenOpeningProject log = logging.getLogger("AVP.Gui.PreviewThread") diff --git a/src/main.py b/src/main.py index 126e4a8..5fabda3 100644 --- a/src/main.py +++ b/src/main.py @@ -3,7 +3,7 @@ import sys import os import logging -from __init__ import wd +from .__init__ import wd log = logging.getLogger('AVP.Main') @@ -12,6 +12,7 @@ log = logging.getLogger('AVP.Main') def main(): app = QtWidgets.QApplication(sys.argv) app.setApplicationName("audio-visualizer") + proj = None # Determine mode mode = 'GUI' @@ -23,19 +24,17 @@ def main(): else: # opening a project file with gui proj = sys.argv[1] - else: - # normal gui launch - proj = None # Launch program if mode == 'commandline': - from command import Command + from .command import Command main = Command() + main.parseArgs() log.debug("Finished creating command object") elif mode == 'GUI': - from gui.mainwindow import MainWindow + from .gui.mainwindow import MainWindow window = uic.loadUi(os.path.join(wd, "gui", "mainwindow.ui")) # window.adjustSize() diff --git a/src/toolkit/__init__.py b/src/toolkit/__init__.py index 3fca275..55e5f84 100644 --- a/src/toolkit/__init__.py +++ b/src/toolkit/__init__.py @@ -1 +1 @@ -from toolkit.common import * +from .common import * diff --git a/src/toolkit/ffmpeg.py b/src/toolkit/ffmpeg.py index 419d491..3298c04 100644 --- a/src/toolkit/ffmpeg.py +++ b/src/toolkit/ffmpeg.py @@ -10,8 +10,8 @@ import signal from queue import PriorityQueue import logging -import core -from toolkit.common import checkOutput, pipeWrapper +from .. import core +from .common import checkOutput, pipeWrapper log = logging.getLogger('AVP.Toolkit.Ffmpeg') @@ -90,7 +90,7 @@ class FfmpegVideo: self.frameBuffer.task_done() def fillBuffer(self): - from component import ComponentError + from ..component import ComponentError if core.Core.logEnabled: logFilename = os.path.join( core.Core.logDir, 'render_%s.log' % str(self.component.compPos) @@ -144,7 +144,7 @@ def openPipe(commandList, **kwargs): def closePipe(pipe): pipe.stdout.close() - pipe.send_signal(signal.SIGINT) + pipe.send_signal(signal.SIGTERM) def findFfmpeg(): diff --git a/src/toolkit/frame.py b/src/toolkit/frame.py index 0e200b5..f2511fe 100644 --- a/src/toolkit/frame.py +++ b/src/toolkit/frame.py @@ -9,7 +9,7 @@ import os import math import logging -import core +from .. import core log = logging.getLogger('AVP.Toolkit.Frame') diff --git a/src/video_thread.py b/src/video_thread.py index 0a39f28..31331a3 100644 --- a/src/video_thread.py +++ b/src/video_thread.py @@ -19,9 +19,9 @@ import time import signal import logging -from component import ComponentError -from toolkit.frame import Checkerboard -from toolkit.ffmpeg import ( +from .component import ComponentError +from .toolkit.frame import Checkerboard +from .toolkit.ffmpeg import ( openPipe, readAudioFile, getAudioDuration, createFfmpegCommand ) @@ -400,7 +400,7 @@ class Worker(QtCore.QObject): comp.cancel() try: - self.out_pipe.send_signal(signal.SIGINT) + self.out_pipe.send_signal(signal.SIGTERM) except Exception: pass -- cgit v1.2.3 From c2c3f0aa5adf3127b84b3d50da9e1aa655c8a824 Mon Sep 17 00:00:00 2001 From: tassaron Date: Fri, 29 Apr 2022 21:15:17 -0400 Subject: remove extra window properties from window objects instead of windows with properties which are windows, windows now have the UI added directly to them using an argument of `uic.loadUi` Also, DPI scaling moved to MainWindow __init__ --- src/components/spectrum.py | 6 +- src/components/video.py | 4 +- src/components/waveform.py | 6 +- src/core.py | 2 +- src/gui/actions.py | 8 +- src/gui/mainwindow.py | 351 +++++++++++++++++++++++---------------------- src/gui/presetmanager.py | 88 ++++++------ src/gui/preview_win.py | 2 +- src/main.py | 18 +-- 9 files changed, 242 insertions(+), 243 deletions(-) (limited to 'src/gui/actions.py') diff --git a/src/components/spectrum.py b/src/components/spectrum.py index d1f8fb6..91f2afb 100644 --- a/src/components/spectrum.py +++ b/src/components/spectrum.py @@ -30,9 +30,9 @@ class Component(Component): self.previewSize = (214, 120) self.previewPipe = None - if hasattr(self.parent, 'window'): + if hasattr(self.parent, 'lineEdit_audioFile'): # update preview when audio file changes (if genericPreview is off) - self.parent.window.lineEdit_audioFile.textChanged.connect( + self.parent.lineEdit_audioFile.textChanged.connect( self.update ) @@ -123,7 +123,7 @@ class Component(Component): genericPreview = self.settings.value("pref_genericPreview") startPt = 0 if not genericPreview: - inputFile = self.parent.window.lineEdit_audioFile.text() + inputFile = self.parent.lineEdit_audioFile.text() if not inputFile or not os.path.exists(inputFile): return duration = getAudioDuration(inputFile) diff --git a/src/components/video.py b/src/components/video.py index 070940d..9fffc26 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -63,8 +63,8 @@ class Component(Component): def properties(self): props = [] - if hasattr(self.parent, 'window'): - outputFile = self.parent.window.lineEdit_outputFile.text() + if hasattr(self.parent, 'lineEdit_outputFile'): + outputFile = self.parent.lineEdit_outputFile.text() else: outputFile = str(self.parent.args.output) diff --git a/src/components/waveform.py b/src/components/waveform.py index 1a6035f..227f711 100644 --- a/src/components/waveform.py +++ b/src/components/waveform.py @@ -27,8 +27,8 @@ class Component(Component): self.page.lineEdit_color.setText('255,255,255') - if hasattr(self.parent, 'window'): - self.parent.window.lineEdit_audioFile.textChanged.connect( + if hasattr(self.parent, 'lineEdit_audioFile'): + self.parent.lineEdit_audioFile.textChanged.connect( self.update ) @@ -82,7 +82,7 @@ class Component(Component): genericPreview = self.settings.value("pref_genericPreview") startPt = 0 if not genericPreview: - inputFile = self.parent.window.lineEdit_audioFile.text() + inputFile = self.parent.lineEdit_audioFile.text() if not inputFile or not os.path.exists(inputFile): return duration = getAudioDuration(inputFile) diff --git a/src/core.py b/src/core.py index 42fd1c3..225d8e0 100644 --- a/src/core.py +++ b/src/core.py @@ -181,7 +181,7 @@ class Core: try: if hasattr(loader, 'window'): for widget, value in data['WindowFields']: - widget = eval('loader.window.%s' % widget) + widget = eval('loader.%s' % widget) with toolkit.blockSignals(widget): toolkit.setWidgetValue(widget, value) diff --git a/src/gui/actions.py b/src/gui/actions.py index eb7b953..afb980a 100644 --- a/src/gui/actions.py +++ b/src/gui/actions.py @@ -41,7 +41,7 @@ class RemoveComponent(QUndoCommand): def __init__(self, parent, selectedRows): super().__init__('remove component') self.parent = parent - componentList = self.parent.window.listWidget_componentList + componentList = self.parent.listWidget_componentList self.selectedRows = [ componentList.row(selected) for selected in selectedRows ] @@ -53,7 +53,7 @@ class RemoveComponent(QUndoCommand): self.parent._removeComponent(self.selectedRows[0]) def undo(self): - componentList = self.parent.window.listWidget_componentList + componentList = self.parent.listWidget_componentList for index, comp in zip(self.selectedRows, self.components): self.parent.core.insertComponent( index, comp, self.parent @@ -78,7 +78,7 @@ class MoveComponent(QUndoCommand): return True def do(self, rowa, rowb): - componentList = self.parent.window.listWidget_componentList + componentList = self.parent.listWidget_componentList page = self.parent.pages.pop(rowa) self.parent.pages.insert(rowb, page) @@ -86,7 +86,7 @@ class MoveComponent(QUndoCommand): item = componentList.takeItem(rowa) componentList.insertItem(rowb, item) - stackedWidget = self.parent.window.stackedWidget + stackedWidget = self.parent.stackedWidget widget = stackedWidget.removeWidget(page) stackedWidget.insertWidget(rowb, page) componentList.setCurrentRow(rowb) diff --git a/src/gui/mainwindow.py b/src/gui/mainwindow.py index 463d028..c31eec9 100644 --- a/src/gui/mainwindow.py +++ b/src/gui/mainwindow.py @@ -4,13 +4,12 @@ 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, QtGui, uic, QtWidgets -from PyQt5.QtWidgets import QMenu, QShortcut +from PyQt5 import QtCore, QtGui, QtWidgets, uic +import PyQt5.QtWidgets as QtWidgets from PIL import Image from queue import Queue import sys import os -import signal import atexit import filecmp import time @@ -43,11 +42,22 @@ class MainWindow(QtWidgets.QMainWindow): newTask = QtCore.pyqtSignal(list) # for the preview window processTask = QtCore.pyqtSignal() - def __init__(self, window, project): - QtWidgets.QMainWindow.__init__(self) + def __init__(self, project): + super().__init__() log.debug( 'Main thread id: {}'.format(int(QtCore.QThread.currentThreadId()))) - self.window = window + 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 / 96)), + int(self.height() * + (dpi / 96)) + ) + self.core = Core() Core.mode = 'GUI' # widgets of component settings @@ -73,15 +83,13 @@ class MainWindow(QtWidgets.QMainWindow): self.undoStack.setUndoLimit(undoLimit) # Create Preset Manager - self.presetManager = PresetManager( - uic.loadUi( - os.path.join(Core.wd, 'gui', 'presetmanager.ui')), self) + 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")) - window.verticalLayout_previewWrapper.addWidget(self.previewWindow) + self.verticalLayout_previewWrapper.addWidget(self.previewWindow) log.debug('Starting preview thread') self.previewQueue = Queue() @@ -105,7 +113,7 @@ class MainWindow(QtWidgets.QMainWindow): self.timer.start(timeout) # Begin decorating the window and connecting events - componentList = self.window.listWidget_componentList + componentList = self.listWidget_componentList # Undo Feature def toggleUndoButtonEnabled(*_): @@ -116,15 +124,15 @@ class MainWindow(QtWidgets.QMainWindow): # program is probably in midst of exiting pass - style = window.pushButton_undo.style() - undoButton = window.pushButton_undo + style = self.pushButton_undo.style() + undoButton = self.pushButton_undo undoButton.setIcon( style.standardIcon(QtWidgets.QStyle.SP_FileDialogBack) ) undoButton.clicked.connect(self.undoStack.undo) undoButton.setEnabled(False) self.undoStack.cleanChanged.connect(toggleUndoButtonEnabled) - self.undoMenu = QMenu() + self.undoMenu = QtWidgets.QMenu() self.undoMenu.addAction( self.undoStack.createUndoAction(self) ) @@ -138,93 +146,93 @@ class MainWindow(QtWidgets.QMainWindow): undoButton.setMenu(self.undoMenu) # end of Undo Feature - style = window.pushButton_listMoveUp.style() - window.pushButton_listMoveUp.setIcon( + style = self.pushButton_listMoveUp.style() + self.pushButton_listMoveUp.setIcon( style.standardIcon(QtWidgets.QStyle.SP_ArrowUp) ) - style = window.pushButton_listMoveDown.style() - window.pushButton_listMoveDown.setIcon( + style = self.pushButton_listMoveDown.style() + self.pushButton_listMoveDown.setIcon( style.standardIcon(QtWidgets.QStyle.SP_ArrowDown) ) - style = window.pushButton_removeComponent.style() - window.pushButton_removeComponent.setIcon( + style = self.pushButton_removeComponent.style() + self.pushButton_removeComponent.setIcon( style.standardIcon(QtWidgets.QStyle.SP_DialogDiscardButton) ) if sys.platform == 'darwin': log.debug( 'Darwin detected: showing progress label below progress bar') - window.progressBar_createVideo.setTextVisible(False) + self.progressBar_createVideo.setTextVisible(False) else: - window.progressLabel.setHidden(True) + self.progressLabel.setHidden(True) - window.toolButton_selectAudioFile.clicked.connect( + self.toolButton_selectAudioFile.clicked.connect( self.openInputFileDialog) - window.toolButton_selectOutputFile.clicked.connect( + self.toolButton_selectOutputFile.clicked.connect( self.openOutputFileDialog) def changedField(): self.autosave() self.updateWindowTitle() - window.lineEdit_audioFile.textChanged.connect(changedField) - window.lineEdit_outputFile.textChanged.connect(changedField) + self.lineEdit_audioFile.textChanged.connect(changedField) + self.lineEdit_outputFile.textChanged.connect(changedField) - window.progressBar_createVideo.setValue(0) + self.progressBar_createVideo.setValue(0) - window.pushButton_createVideo.clicked.connect( + self.pushButton_createVideo.clicked.connect( self.createAudioVisualisation) - window.pushButton_Cancel.clicked.connect(self.stopVideo) + self.pushButton_Cancel.clicked.connect(self.stopVideo) for i, container in enumerate(Core.encoderOptions['containers']): - window.comboBox_videoContainer.addItem(container['name']) + self.comboBox_videoContainer.addItem(container['name']) if container['name'] == self.settings.value('outputContainer'): selectedContainer = i - window.comboBox_videoContainer.setCurrentIndex(selectedContainer) - window.comboBox_videoContainer.currentIndexChanged.connect( + self.comboBox_videoContainer.setCurrentIndex(selectedContainer) + self.comboBox_videoContainer.currentIndexChanged.connect( self.updateCodecs ) self.updateCodecs() - for i in range(window.comboBox_videoCodec.count()): - codec = window.comboBox_videoCodec.itemText(i) + for i in range(self.comboBox_videoCodec.count()): + codec = self.comboBox_videoCodec.itemText(i) if codec == self.settings.value('outputVideoCodec'): - window.comboBox_videoCodec.setCurrentIndex(i) + self.comboBox_videoCodec.setCurrentIndex(i) - for i in range(window.comboBox_audioCodec.count()): - codec = window.comboBox_audioCodec.itemText(i) + for i in range(self.comboBox_audioCodec.count()): + codec = self.comboBox_audioCodec.itemText(i) if codec == self.settings.value('outputAudioCodec'): - window.comboBox_audioCodec.setCurrentIndex(i) + self.comboBox_audioCodec.setCurrentIndex(i) - window.comboBox_videoCodec.currentIndexChanged.connect( + self.comboBox_videoCodec.currentIndexChanged.connect( self.updateCodecSettings ) - window.comboBox_audioCodec.currentIndexChanged.connect( + self.comboBox_audioCodec.currentIndexChanged.connect( self.updateCodecSettings ) vBitrate = int(self.settings.value('outputVideoBitrate')) aBitrate = int(self.settings.value('outputAudioBitrate')) - window.spinBox_vBitrate.setValue(vBitrate) - window.spinBox_aBitrate.setValue(aBitrate) - window.spinBox_vBitrate.valueChanged.connect(self.updateCodecSettings) - window.spinBox_aBitrate.valueChanged.connect(self.updateCodecSettings) + self.spinBox_vBitrate.setValue(vBitrate) + self.spinBox_aBitrate.setValue(aBitrate) + self.spinBox_vBitrate.valueChanged.connect(self.updateCodecSettings) + self.spinBox_aBitrate.valueChanged.connect(self.updateCodecSettings) # Make component buttons - self.compMenu = QMenu() + 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) ) - self.window.pushButton_addComponent.setMenu(self.compMenu) + self.pushButton_addComponent.setMenu(self.compMenu) componentList.dropEvent = self.dragComponent componentList.itemSelectionChanged.connect( @@ -233,7 +241,7 @@ class MainWindow(QtWidgets.QMainWindow): componentList.itemSelectionChanged.connect( self.presetManager.clearPresetListSelection ) - self.window.pushButton_removeComponent.clicked.connect( + self.pushButton_removeComponent.clicked.connect( lambda: self.removeComponent() ) @@ -245,33 +253,33 @@ class MainWindow(QtWidgets.QMainWindow): currentRes = str(self.settings.value('outputWidth'))+'x' + \ str(self.settings.value('outputHeight')) for i, res in enumerate(Core.resolutions): - window.comboBox_resolution.addItem(res) + self.comboBox_resolution.addItem(res) if res == currentRes: currentRes = i - window.comboBox_resolution.setCurrentIndex(currentRes) - window.comboBox_resolution.currentIndexChanged.connect( + self.comboBox_resolution.setCurrentIndex(currentRes) + self.comboBox_resolution.currentIndexChanged.connect( self.updateResolution ) - self.window.pushButton_listMoveUp.clicked.connect( + self.pushButton_listMoveUp.clicked.connect( lambda: self.moveComponent(-1) ) - self.window.pushButton_listMoveDown.clicked.connect( + self.pushButton_listMoveDown.clicked.connect( lambda: self.moveComponent(1) ) # Configure the Projects Menu - self.projectMenu = QMenu() - self.window.menuButton_newProject = self.projectMenu.addAction( + self.projectMenu = QtWidgets.QMenu() + self.menuButton_newProject = self.projectMenu.addAction( "New Project" ) - self.window.menuButton_newProject.triggered.connect( + self.menuButton_newProject.triggered.connect( lambda: self.createNewProject() ) - self.window.menuButton_openProject = self.projectMenu.addAction( + self.menuButton_openProject = self.projectMenu.addAction( "Open Project" ) - self.window.menuButton_openProject.triggered.connect( + self.menuButton_openProject.triggered.connect( lambda: self.openOpenProjectDialog() ) @@ -281,16 +289,16 @@ class MainWindow(QtWidgets.QMainWindow): action = self.projectMenu.addAction("Save Project As") action.triggered.connect(self.openSaveProjectDialog) - self.window.pushButton_projects.setMenu(self.projectMenu) + self.pushButton_projects.setMenu(self.projectMenu) # Configure the Presets Button - self.window.pushButton_presets.clicked.connect( + self.pushButton_presets.clicked.connect( self.openPresetManager ) self.updateWindowTitle() log.debug('Showing main window') - window.show() + self.show() if project and project != self.autosavePath: if not project.endswith('.avp'): @@ -358,77 +366,80 @@ class MainWindow(QtWidgets.QMainWindow): self.settings.setValue("ffmpegMsgShown", True) # Hotkeys for projects - QtWidgets.QShortcut("Ctrl+S", self.window, self.saveCurrentProject) - QtWidgets.QShortcut("Ctrl+A", self.window, self.openSaveProjectDialog) - QtWidgets.QShortcut("Ctrl+O", self.window, self.openOpenProjectDialog) - QtWidgets.QShortcut("Ctrl+N", self.window, self.createNewProject) + 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) - QtWidgets.QShortcut("Ctrl+Z", self.window, self.undoStack.undo) - QtWidgets.QShortcut("Ctrl+Y", self.window, self.undoStack.redo) - QtWidgets.QShortcut("Ctrl+Shift+Z", self.window, self.undoStack.redo) + # 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) # Hotkeys for component list for inskey in ("Ctrl+T", QtCore.Qt.Key_Insert): QtWidgets.QShortcut( - inskey, self.window, - activated=lambda: self.window.pushButton_addComponent.click() + inskey, self, + activated=lambda: self.pushButton_addComponent.click() ) for delkey in ("Ctrl+R", QtCore.Qt.Key_Delete): QtWidgets.QShortcut( - delkey, self.window.listWidget_componentList, + delkey, self.listWidget_componentList, self.removeComponent ) QtWidgets.QShortcut( - "Ctrl+Space", self.window, - activated=lambda: self.window.listWidget_componentList.setFocus() + "Ctrl+Space", self, + activated=lambda: self.listWidget_componentList.setFocus() ) QtWidgets.QShortcut( - "Ctrl+Shift+S", self.window, + "Ctrl+Shift+S", self, self.presetManager.openSavePresetDialog ) QtWidgets.QShortcut( - "Ctrl+Shift+C", self.window, self.presetManager.clearPreset + "Ctrl+Shift+C", self, self.presetManager.clearPreset ) QtWidgets.QShortcut( - "Ctrl+Up", self.window.listWidget_componentList, + "Ctrl+Up", self.listWidget_componentList, activated=lambda: self.moveComponent(-1) ) QtWidgets.QShortcut( - "Ctrl+Down", self.window.listWidget_componentList, + "Ctrl+Down", self.listWidget_componentList, activated=lambda: self.moveComponent(1) ) QtWidgets.QShortcut( - "Ctrl+Home", self.window.listWidget_componentList, + "Ctrl+Home", self.listWidget_componentList, activated=lambda: self.moveComponent('top') ) QtWidgets.QShortcut( - "Ctrl+End", self.window.listWidget_componentList, + "Ctrl+End", self.listWidget_componentList, activated=lambda: self.moveComponent('bottom') ) QtWidgets.QShortcut( - "Ctrl+Shift+F", self.window, self.showFfmpegCommand + "Ctrl+Shift+F", self, self.showFfmpegCommand ) QtWidgets.QShortcut( - "Ctrl+Shift+U", self.window, self.showUndoStack + "Ctrl+Shift+U", self, self.showUndoStack ) if log.isEnabledFor(logging.DEBUG): QtWidgets.QShortcut( - "Ctrl+Alt+Shift+R", self.window, self.drawPreview + "Ctrl+Alt+Shift+R", self, self.drawPreview ) QtWidgets.QShortcut( - "Ctrl+Alt+Shift+A", self.window, lambda: log.debug(repr(self)) + "Ctrl+Alt+Shift+A", self, lambda: log.debug(repr(self)) ) def __repr__(self): return ( + '%s\n' '\n%s\n' '#####\n' 'Preview thread is %s\n' % ( - repr(self.core), - 'live' if self.previewThread.isRunning() else 'dead', + 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', ) ) @@ -456,7 +467,7 @@ class MainWindow(QtWidgets.QMainWindow): except AttributeError: pass log.verbose(f'Window title is "{appName}"') - self.window.setWindowTitle(appName) + self.setWindowTitle(appName) @QtCore.pyqtSlot(int, dict) def updateComponentTitle(self, pos, presetStore=False): @@ -492,12 +503,12 @@ class MainWindow(QtWidgets.QMainWindow): 'Setting %s #%s\'s title: %s', name, pos, title ) - self.window.listWidget_componentList.item(pos).setText(title) + self.listWidget_componentList.item(pos).setText(title) def updateCodecs(self): - containerWidget = self.window.comboBox_videoContainer - vCodecWidget = self.window.comboBox_videoCodec - aCodecWidget = self.window.comboBox_audioCodec + containerWidget = self.comboBox_videoContainer + vCodecWidget = self.comboBox_videoCodec + aCodecWidget = self.comboBox_audioCodec index = containerWidget.currentIndex() name = containerWidget.itemText(index) self.settings.setValue('outputContainer', name) @@ -514,10 +525,10 @@ class MainWindow(QtWidgets.QMainWindow): def updateCodecSettings(self): '''Updates settings.ini to match encoder option widgets''' - vCodecWidget = self.window.comboBox_videoCodec - vBitrateWidget = self.window.spinBox_vBitrate - aBitrateWidget = self.window.spinBox_aBitrate - aCodecWidget = self.window.comboBox_audioCodec + vCodecWidget = self.comboBox_videoCodec + vBitrateWidget = self.spinBox_vBitrate + aBitrateWidget = self.spinBox_aBitrate + aCodecWidget = self.comboBox_audioCodec currentVideoCodec = vCodecWidget.currentIndex() currentVideoCodec = vCodecWidget.itemText(currentVideoCodec) currentVideoBitrate = vBitrateWidget.value() @@ -535,7 +546,7 @@ class MainWindow(QtWidgets.QMainWindow): if os.path.exists(self.autosavePath): os.remove(self.autosavePath) elif force or time.time() - self.lastAutosave >= self.autosaveCooldown: - self.core.createProjectFile(self.autosavePath, self.window) + self.core.createProjectFile(self.autosavePath, self) self.lastAutosave = time.time() if len(self.autosaveTimes) >= 5: # Do some math to reduce autosave spam. This gives a smooth @@ -588,25 +599,25 @@ class MainWindow(QtWidgets.QMainWindow): inputDir = self.settings.value("inputDir", os.path.expanduser("~")) fileName, _ = QtWidgets.QFileDialog.getOpenFileName( - self.window, "Open Audio File", + self, "Open Audio File", inputDir, "Audio Files (%s)" % " ".join(Core.audioFormats)) if fileName: self.settings.setValue("inputDir", os.path.dirname(fileName)) - self.window.lineEdit_audioFile.setText(fileName) + self.lineEdit_audioFile.setText(fileName) def openOutputFileDialog(self): outputDir = self.settings.value("outputDir", os.path.expanduser("~")) fileName, _ = QtWidgets.QFileDialog.getSaveFileName( - self.window, "Set Output Video File", + self, "Set Output Video File", outputDir, "Video Files (%s);; All Files (*)" % " ".join( Core.videoFormats)) if fileName: self.settings.setValue("outputDir", os.path.dirname(fileName)) - self.window.lineEdit_outputFile.setText(fileName) + self.lineEdit_outputFile.setText(fileName) def stopVideo(self): log.info('Export cancelled') @@ -615,8 +626,8 @@ class MainWindow(QtWidgets.QMainWindow): def createAudioVisualisation(self): # create output video if mandatory settings are filled in - audioFile = self.window.lineEdit_audioFile.text() - outputPath = self.window.lineEdit_outputFile.text() + audioFile = self.lineEdit_audioFile.text() + outputPath = self.lineEdit_outputFile.text() if audioFile and outputPath and self.core.selectedComponents: if not os.path.dirname(outputPath): @@ -670,62 +681,62 @@ class MainWindow(QtWidgets.QMainWindow): def changeEncodingStatus(self, status): self.encoding = status if status: - self.window.pushButton_createVideo.setEnabled(False) - self.window.pushButton_Cancel.setEnabled(True) - self.window.comboBox_resolution.setEnabled(False) - self.window.stackedWidget.setEnabled(False) - self.window.tab_encoderSettings.setEnabled(False) - self.window.label_audioFile.setEnabled(False) - self.window.toolButton_selectAudioFile.setEnabled(False) - self.window.label_outputFile.setEnabled(False) - self.window.toolButton_selectOutputFile.setEnabled(False) - self.window.lineEdit_audioFile.setEnabled(False) - self.window.lineEdit_outputFile.setEnabled(False) - self.window.pushButton_addComponent.setEnabled(False) - self.window.pushButton_removeComponent.setEnabled(False) - self.window.pushButton_listMoveDown.setEnabled(False) - self.window.pushButton_listMoveUp.setEnabled(False) - self.window.menuButton_newProject.setEnabled(False) - self.window.menuButton_openProject.setEnabled(False) + self.pushButton_createVideo.setEnabled(False) + self.pushButton_Cancel.setEnabled(True) + self.comboBox_resolution.setEnabled(False) + self.stackedWidget.setEnabled(False) + self.tab_encoderSettings.setEnabled(False) + self.label_audioFile.setEnabled(False) + self.toolButton_selectAudioFile.setEnabled(False) + self.label_outputFile.setEnabled(False) + self.toolButton_selectOutputFile.setEnabled(False) + self.lineEdit_audioFile.setEnabled(False) + self.lineEdit_outputFile.setEnabled(False) + self.pushButton_addComponent.setEnabled(False) + self.pushButton_removeComponent.setEnabled(False) + self.pushButton_listMoveDown.setEnabled(False) + self.pushButton_listMoveUp.setEnabled(False) + self.menuButton_newProject.setEnabled(False) + self.menuButton_openProject.setEnabled(False) if sys.platform == 'darwin': - self.window.progressLabel.setHidden(False) + self.progressLabel.setHidden(False) else: - self.window.listWidget_componentList.setEnabled(False) + self.listWidget_componentList.setEnabled(False) else: - self.window.pushButton_createVideo.setEnabled(True) - self.window.pushButton_Cancel.setEnabled(False) - self.window.comboBox_resolution.setEnabled(True) - self.window.stackedWidget.setEnabled(True) - self.window.tab_encoderSettings.setEnabled(True) - self.window.label_audioFile.setEnabled(True) - self.window.toolButton_selectAudioFile.setEnabled(True) - self.window.lineEdit_audioFile.setEnabled(True) - self.window.label_outputFile.setEnabled(True) - self.window.toolButton_selectOutputFile.setEnabled(True) - self.window.lineEdit_outputFile.setEnabled(True) - self.window.pushButton_addComponent.setEnabled(True) - self.window.pushButton_removeComponent.setEnabled(True) - self.window.pushButton_listMoveDown.setEnabled(True) - self.window.pushButton_listMoveUp.setEnabled(True) - self.window.menuButton_newProject.setEnabled(True) - self.window.menuButton_openProject.setEnabled(True) - self.window.listWidget_componentList.setEnabled(True) - self.window.progressLabel.setHidden(True) + self.pushButton_createVideo.setEnabled(True) + self.pushButton_Cancel.setEnabled(False) + self.comboBox_resolution.setEnabled(True) + self.stackedWidget.setEnabled(True) + self.tab_encoderSettings.setEnabled(True) + self.label_audioFile.setEnabled(True) + self.toolButton_selectAudioFile.setEnabled(True) + self.lineEdit_audioFile.setEnabled(True) + self.label_outputFile.setEnabled(True) + self.toolButton_selectOutputFile.setEnabled(True) + self.lineEdit_outputFile.setEnabled(True) + self.pushButton_addComponent.setEnabled(True) + self.pushButton_removeComponent.setEnabled(True) + self.pushButton_listMoveDown.setEnabled(True) + self.pushButton_listMoveUp.setEnabled(True) + self.menuButton_newProject.setEnabled(True) + self.menuButton_openProject.setEnabled(True) + self.listWidget_componentList.setEnabled(True) + self.progressLabel.setHidden(True) self.drawPreview(True) @QtCore.pyqtSlot(int) def progressBarUpdated(self, value): - self.window.progressBar_createVideo.setValue(value) + self.progressBar_createVideo.setValue(value) @QtCore.pyqtSlot(str) def progressBarSetText(self, value): if sys.platform == 'darwin': - self.window.progressLabel.setText(value) + self.progressLabel.setText(value) else: - self.window.progressBar_createVideo.setFormat(value) + self.progressBar_createVideo.setFormat(value) def updateResolution(self): - resIndex = int(self.window.comboBox_resolution.currentIndex()) + resIndex = int(self.comboBox_resolution.currentIndex()) res = Core.resolutions[resIndex].split('x') changed = res[0] != self.settings.value("outputWidth") self.settings.setValue('outputWidth', res[0]) @@ -750,7 +761,7 @@ class MainWindow(QtWidgets.QMainWindow): self.previewWindow.changePixmap(image) def showUndoStack(self): - dialog = QtWidgets.QDialog(self.window) + dialog = QtWidgets.QDialog(self) undoView = QtWidgets.QUndoView(self.undoStack) layout = QtWidgets.QVBoxLayout() layout.addWidget(undoView) @@ -761,8 +772,8 @@ class MainWindow(QtWidgets.QMainWindow): from textwrap import wrap from ..toolkit.ffmpeg import createFfmpegCommand command = createFfmpegCommand( - self.window.lineEdit_audioFile.text(), - self.window.lineEdit_outputFile.text(), + self.lineEdit_audioFile.text(), + self.lineEdit_outputFile.text(), self.core.selectedComponents ) command = " ".join(command) @@ -779,8 +790,8 @@ class MainWindow(QtWidgets.QMainWindow): def insertComponent(self, index): '''Triggered by Core to finish initializing a new component.''' - componentList = self.window.listWidget_componentList - stackedWidget = self.window.stackedWidget + componentList = self.listWidget_componentList + stackedWidget = self.stackedWidget componentList.insertItem( index, @@ -798,15 +809,15 @@ class MainWindow(QtWidgets.QMainWindow): return index def removeComponent(self): - componentList = self.window.listWidget_componentList + componentList = self.listWidget_componentList selected = componentList.selectedItems() if selected: action = RemoveComponent(self, selected) self.undoStack.push(action) def _removeComponent(self, index): - stackedWidget = self.window.stackedWidget - componentList = self.window.listWidget_componentList + stackedWidget = self.stackedWidget + componentList = self.listWidget_componentList stackedWidget.removeWidget(self.pages[index]) componentList.takeItem(index) self.core.removeComponent(index) @@ -817,7 +828,7 @@ class MainWindow(QtWidgets.QMainWindow): @disableWhenEncoding def moveComponent(self, change): '''Moves a component relatively from its current position''' - componentList = self.window.listWidget_componentList + componentList = self.listWidget_componentList tag = change if change == 'top': change = -componentList.currentRow() @@ -837,7 +848,7 @@ class MainWindow(QtWidgets.QMainWindow): Given a QPos, returns the component index under the mouse cursor or -1 if no component is there. ''' - componentList = self.window.listWidget_componentList + componentList = self.listWidget_componentList modelIndexes = [ componentList.model().index(i) @@ -859,7 +870,7 @@ class MainWindow(QtWidgets.QMainWindow): @disableWhenEncoding def dragComponent(self, event): '''Used as Qt drop event for the component listwidget''' - componentList = self.window.listWidget_componentList + componentList = self.listWidget_componentList mousePos = self.getComponentListMousePos(event.pos()) if mousePos > -1: change = (componentList.currentRow() - mousePos) * -1 @@ -868,25 +879,25 @@ class MainWindow(QtWidgets.QMainWindow): self.moveComponent(change) def changeComponentWidget(self): - selected = self.window.listWidget_componentList.selectedItems() + selected = self.listWidget_componentList.selectedItems() if selected: - index = self.window.listWidget_componentList.row(selected[0]) - self.window.stackedWidget.setCurrentIndex(index) + index = self.listWidget_componentList.row(selected[0]) + self.stackedWidget.setCurrentIndex(index) def openPresetManager(self): '''Preset manager for importing, exporting, renaming, deleting''' - self.presetManager.show() + self.presetManager.show_() def clear(self): '''Get a blank slate''' self.core.clearComponents() - self.window.listWidget_componentList.clear() + self.listWidget_componentList.clear() for widget in self.pages: - self.window.stackedWidget.removeWidget(widget) + self.stackedWidget.removeWidget(widget) self.pages = [] for field in ( - self.window.lineEdit_audioFile, - self.window.lineEdit_outputFile + self.lineEdit_audioFile, + self.lineEdit_outputFile ): with blockSignals(field): field.setText('') @@ -906,7 +917,7 @@ class MainWindow(QtWidgets.QMainWindow): def saveCurrentProject(self): if self.currentProject: - self.core.createProjectFile(self.currentProject, self.window) + self.core.createProjectFile(self.currentProject, self) try: os.remove(self.autosavePath) except FileNotFoundError: @@ -933,7 +944,7 @@ class MainWindow(QtWidgets.QMainWindow): def openSaveProjectDialog(self): filename, _ = QtWidgets.QFileDialog.getSaveFileName( - self.window, "Create Project File", + self, "Create Project File", self.settings.value("projectDir"), "Project Files (*.avp)") if not filename: @@ -943,13 +954,13 @@ class MainWindow(QtWidgets.QMainWindow): self.settings.setValue("projectDir", os.path.dirname(filename)) self.settings.setValue("currentProject", filename) self.currentProject = filename - self.core.createProjectFile(filename, self.window) + self.core.createProjectFile(filename, self) self.updateWindowTitle() @disableWhenEncoding def openOpenProjectDialog(self): filename, _ = QtWidgets.QFileDialog.getOpenFileName( - self.window, "Open Project File", + self, "Open Project File", self.settings.value("projectDir"), "Project Files (*.avp)") self.openProject(filename) @@ -973,7 +984,7 @@ class MainWindow(QtWidgets.QMainWindow): self.updateWindowTitle() def showMessage(self, **kwargs): - parent = kwargs['parent'] if 'parent' in kwargs else self.window + parent = kwargs['parent'] if 'parent' in kwargs else self msg = QtWidgets.QMessageBox(parent) msg.setModal(True) msg.setText(kwargs['msg']) @@ -995,8 +1006,8 @@ class MainWindow(QtWidgets.QMainWindow): @disableWhenEncoding def componentContextMenu(self, QPos): '''Appears when right-clicking the component list''' - componentList = self.window.listWidget_componentList - self.menu = QMenu() + componentList = self.listWidget_componentList + self.menu = QtWidgets.QMenu() parentPosition = componentList.mapToGlobal(QtCore.QPoint(0, 0)) index = self.getComponentListMousePos(QPos) @@ -1013,7 +1024,7 @@ class MainWindow(QtWidgets.QMainWindow): presets = self.presetManager.presets[ str(self.core.selectedComponents[index]) ] - self.presetSubmenu = QMenu("Open Preset") + self.presetSubmenu = QtWidgets.QMenu("Open Preset") self.menu.addMenu(self.presetSubmenu) for version, presetName in presets: @@ -1033,7 +1044,7 @@ class MainWindow(QtWidgets.QMainWindow): self.menu.addSeparator() # "Add Component" submenu - self.submenu = QMenu("Add") + self.submenu = QtWidgets.QMenu("Add") self.menu.addMenu(self.submenu) insertCompAtTop = self.settings.value("pref_insertCompAtTop") for i, comp in enumerate(self.core.modules): diff --git a/src/gui/presetmanager.py b/src/gui/presetmanager.py index 1e47a7f..9cf95b4 100644 --- a/src/gui/presetmanager.py +++ b/src/gui/presetmanager.py @@ -2,7 +2,7 @@ Preset manager object handles all interactions with presets, including the context menu accessed from MainWindow. ''' -from PyQt5 import QtCore, QtWidgets +from PyQt5 import QtCore, QtWidgets, uic import string import os import logging @@ -16,8 +16,10 @@ log = logging.getLogger('AVP.Gui.PresetManager') class PresetManager(QtWidgets.QDialog): - def __init__(self, window, parent): - super().__init__(parent.window) + def __init__(self, parent): + super().__init__() + uic.loadUi( + os.path.join(Core.wd, 'gui', 'presetmanager.ui'), self) self.parent = parent self.core = parent.core self.settings = parent.settings @@ -32,32 +34,31 @@ class PresetManager(QtWidgets.QDialog): # window self.lastFilter = '*' self.presetRows = [] # list of (comp, vers, name) tuples - self.window = window - self.window.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) + self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) # connect button signals - self.window.pushButton_delete.clicked.connect( + self.pushButton_delete.clicked.connect( self.openDeletePresetDialog ) - self.window.pushButton_rename.clicked.connect( + self.pushButton_rename.clicked.connect( self.openRenamePresetDialog ) - self.window.pushButton_import.clicked.connect( + self.pushButton_import.clicked.connect( self.openImportDialog ) - self.window.pushButton_export.clicked.connect( + self.pushButton_export.clicked.connect( self.openExportDialog ) - self.window.pushButton_close.clicked.connect( - self.window.close + self.pushButton_close.clicked.connect( + self.close ) # create filter box and preset list self.drawFilterList() - self.window.comboBox_filter.currentIndexChanged.connect( + self.comboBox_filter.currentIndexChanged.connect( lambda: self.drawPresetList( - self.window.comboBox_filter.currentText(), - self.window.lineEdit_search.text() + self.comboBox_filter.currentText(), + self.lineEdit_search.text() ) ) @@ -65,23 +66,24 @@ class PresetManager(QtWidgets.QDialog): self.autocomplete = QtCore.QStringListModel() completer = QtWidgets.QCompleter() completer.setModel(self.autocomplete) - self.window.lineEdit_search.setCompleter(completer) - self.window.lineEdit_search.textChanged.connect( + self.lineEdit_search.setCompleter(completer) + self.lineEdit_search.textChanged.connect( lambda: self.drawPresetList( - self.window.comboBox_filter.currentText(), - self.window.lineEdit_search.text() + self.comboBox_filter.currentText(), + self.lineEdit_search.text() ) ) self.drawPresetList('*') - def show(self): + def show_(self): '''Open a new preset manager window from the mainwindow''' self.findPresets() self.drawFilterList() self.drawPresetList('*') - self.window.show() + self.show() def findPresets(self): + log.debug("Searching %s for presets", self.presetDir) parseList = [] for dirpath, dirnames, filenames in os.walk(self.presetDir): # anything without a subdirectory must be a preset folder @@ -106,7 +108,7 @@ class PresetManager(QtWidgets.QDialog): } def drawPresetList(self, compFilter=None, presetFilter=''): - self.window.listWidget_presets.clear() + self.listWidget_presets.clear() if compFilter: self.lastFilter = str(compFilter) else: @@ -118,7 +120,7 @@ class PresetManager(QtWidgets.QDialog): continue for vers, preset in presets: if not presetFilter or presetFilter in preset: - self.window.listWidget_presets.addItem( + self.listWidget_presets.addItem( '%s: %s' % (component, preset) ) self.presetRows.append((component, vers, preset)) @@ -127,22 +129,21 @@ class PresetManager(QtWidgets.QDialog): self.autocomplete.setStringList(presetNames) def drawFilterList(self): - self.window.comboBox_filter.clear() - self.window.comboBox_filter.addItem('*') + self.comboBox_filter.clear() + self.comboBox_filter.addItem('*') for component in self.presets: - self.window.comboBox_filter.addItem(component) + self.comboBox_filter.addItem(component) def clearPreset(self, compI=None): '''Functions on mainwindow level from the context menu''' - compI = self.parent.window.listWidget_componentList.currentRow() + 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''' - window = self.parent.window selectedComponents = self.core.selectedComponents - componentList = self.parent.window.listWidget_componentList + componentList = self.parent.listWidget_componentList if componentList.currentRow() == -1: return @@ -150,7 +151,7 @@ class PresetManager(QtWidgets.QDialog): index = componentList.currentRow() currentPreset = selectedComponents[index].currentPreset newName, OK = QtWidgets.QInputDialog.getText( - self.parent.window, + self.parent, 'Audio Visualizer', 'New Preset Name:', QtWidgets.QLineEdit.Normal, @@ -158,7 +159,7 @@ class PresetManager(QtWidgets.QDialog): ) if OK: if badName(newName): - self.warnMessage(self.parent.window) + self.warnMessage(self.parent) continue if newName: if index != -1: @@ -170,7 +171,7 @@ class PresetManager(QtWidgets.QDialog): vers = selectedComponents[index].version self.createNewPreset( componentName, vers, newName, - saveValueStore, window=self.parent.window) + saveValueStore, window=self.parent) self.findPresets() self.drawPresetList() self.openPreset(newName, index) @@ -185,8 +186,7 @@ class PresetManager(QtWidgets.QDialog): def presetExists(self, path, **kwargs): if os.path.exists(path): - window = self.window \ - if 'window' not in kwargs else kwargs['window'] + window = kwargs.get("window", self) ch = self.parent.showMessage( msg="%s already exists! Overwrite it?" % os.path.basename(path), @@ -200,7 +200,7 @@ class PresetManager(QtWidgets.QDialog): return False def openPreset(self, presetName, compPos=None): - componentList = self.parent.window.listWidget_componentList + componentList = self.parent.listWidget_componentList index = compPos if compPos is not None else componentList.currentRow() if index == -1: return @@ -228,7 +228,7 @@ class PresetManager(QtWidgets.QDialog): msg='Really delete %s?' % name, showCancel=True, icon='Warning', - parent=self.window + parent=self ) if not ch: return @@ -242,15 +242,15 @@ class PresetManager(QtWidgets.QDialog): self.parent.showMessage( msg='Preset names must contain only letters, ' 'numbers, and spaces.', - parent=window if window else self.window) + parent=window if window else self) def getPresetRow(self): - row = self.window.listWidget_presets.currentRow() + row = self.listWidget_presets.currentRow() if row > -1: return row # check if component selected in MainWindow has preset loaded - componentList = self.parent.window.listWidget_componentList + componentList = self.parent.listWidget_componentList compIndex = componentList.currentRow() if compIndex == -1: return compIndex @@ -273,14 +273,14 @@ class PresetManager(QtWidgets.QDialog): return index def openRenamePresetDialog(self): - presetList = self.window.listWidget_presets + presetList = self.listWidget_presets index = self.getPresetRow() if index == -1: return while True: newName, OK = QtWidgets.QInputDialog.getText( - self.window, + self, 'Preset Manager', 'Rename Preset:', QtWidgets.QLineEdit.Normal, @@ -319,7 +319,7 @@ class PresetManager(QtWidgets.QDialog): def openImportDialog(self): filename, _ = QtWidgets.QFileDialog.getOpenFileName( - self.window, "Import Preset File", + self, "Import Preset File", self.settings.value("presetDir"), "Preset Files (*.avl)") if filename: @@ -345,7 +345,7 @@ class PresetManager(QtWidgets.QDialog): if index == -1: return filename, _ = QtWidgets.QFileDialog.getSaveFileName( - self.window, "Export Preset", + self, "Export Preset", self.settings.value("presetDir"), "Preset Files (*.avl)") if filename: @@ -353,9 +353,9 @@ class PresetManager(QtWidgets.QDialog): if not self.core.exportPreset(filename, comp, vers, name): self.parent.showMessage( msg='Couldn\'t export %s.' % filename, - parent=self.window + parent=self ) self.settings.setValue("presetDir", os.path.dirname(filename)) def clearPresetListSelection(self): - self.window.listWidget_presets.setCurrentRow(-1) + self.listWidget_presets.setCurrentRow(-1) diff --git a/src/gui/preview_win.py b/src/gui/preview_win.py index 426ff66..d910456 100644 --- a/src/gui/preview_win.py +++ b/src/gui/preview_win.py @@ -37,7 +37,7 @@ class PreviewWindow(QtWidgets.QLabel): if self.parent.encoding: return - i = self.parent.window.listWidget_componentList.currentRow() + i = self.parent.listWidget_componentList.currentRow() if i >= 0: component = self.parent.core.selectedComponents[i] if not hasattr(component, 'previewClickEvent'): diff --git a/src/main.py b/src/main.py index ec4b8bc..709e5e7 100644 --- a/src/main.py +++ b/src/main.py @@ -42,21 +42,9 @@ def main(): if mode == 'GUI': from .gui.mainwindow import MainWindow - window = uic.loadUi(os.path.join(wd, "gui", "mainwindow.ui")) - desc = QtWidgets.QDesktopWidget() - dpi = desc.physicalDpiX() - log.info("Detected screen DPI: %s", dpi) - - window.resize( - int(window.width() * - (dpi / 96)), - int(window.height() * - (dpi / 96)) - ) - - main = MainWindow(window, proj) - log.debug("Finished creating main window") - window.raise_() + mainWindow = MainWindow(proj) + log.debug("Finished creating MainWindow") + mainWindow.raise_() sys.exit(app.exec_()) -- cgit v1.2.3