From a327bec4e42cc572fb84e559025e888a4a20edd3 Mon Sep 17 00:00:00 2001 From: tassaron Date: Mon, 14 Aug 2017 16:39:53 -0400 Subject: organizing GUImode-specific code --- src/gui/preview_win.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/gui/preview_win.py (limited to 'src/gui/preview_win.py') diff --git a/src/gui/preview_win.py b/src/gui/preview_win.py new file mode 100644 index 0000000..40c19c6 --- /dev/null +++ b/src/gui/preview_win.py @@ -0,0 +1,62 @@ +from PyQt5 import QtCore, QtGui, QtWidgets +import logging + + +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') + + def __init__(self, parent, img): + super(PreviewWindow, self).__init__() + self.parent = parent + self.setFrameStyle(QtWidgets.QFrame.StyledPanel) + self.pixmap = QtGui.QPixmap(img) + + def paintEvent(self, event): + size = self.size() + painter = QtGui.QPainter(self) + point = QtCore.QPoint(0, 0) + scaledPix = self.pixmap.scaled( + size, + QtCore.Qt.KeepAspectRatio, + transformMode=QtCore.Qt.SmoothTransformation) + + # start painting the label from left upper corner + point.setX((size.width() - scaledPix.width())/2) + point.setY((size.height() - scaledPix.height())/2) + painter.drawPixmap(point, scaledPix) + + def changePixmap(self, img): + self.pixmap = QtGui.QPixmap(img) + self.repaint() + + def mousePressEvent(self, event): + if self.parent.encoding: + return + + i = self.parent.window.listWidget_componentList.currentRow() + if i >= 0: + component = self.parent.core.selectedComponents[i] + if not hasattr(component, 'previewClickEvent'): + self.log.info('Ignored click event') + return + pos = (event.x(), event.y()) + size = (self.width(), self.height()) + butt = event.button() + self.log.info('Click event for #%s: %s button %s' % ( + i, pos, butt)) + component.previewClickEvent( + pos, size, butt + ) + self.parent.core.updateComponent(i) + + @QtCore.pyqtSlot(str) + def threadError(self, msg): + self.parent.showMessage( + msg=msg, + icon='Critical', + parent=self + ) -- 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/preview_win.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 85d3b779d07ad92b0f540ea52185777c3c3f5e48 Mon Sep 17 00:00:00 2001 From: tassaron Date: Sat, 26 Aug 2017 21:23:44 -0400 Subject: fixed too-large Color sizes, fixed a redoing bug, rm pointless things and now Ctrl+Alt+Shift+A gives a bunch of debug info --- src/component.py | 30 +++++++++++------------ src/components/color.py | 2 +- src/components/color.ui | 4 ++-- src/components/text.py | 13 ++++++---- src/core.py | 8 +++++-- src/gui/mainwindow.py | 63 +++++++++++++++++++++++++++++-------------------- src/gui/preview_win.py | 1 + src/main.py | 5 ---- src/toolkit/ffmpeg.py | 2 +- src/toolkit/frame.py | 3 --- 10 files changed, 72 insertions(+), 59 deletions(-) (limited to 'src/gui/preview_win.py') diff --git a/src/component.py b/src/component.py index 35fc717..de4b6a7 100644 --- a/src/component.py +++ b/src/component.py @@ -41,10 +41,8 @@ class ComponentMetaclass(type(QtCore.QObject)): def renderWrapper(self, *args, **kwargs): try: log.verbose( - '### %s #%s renders%s frame %s###', + '### %s #%s renders a preview frame ###', 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: @@ -198,8 +196,8 @@ class ComponentMetaclass(type(QtCore.QObject)): 'names', # Class methods 'error', 'audio', 'properties', # Properties 'preFrameRender', 'previewRender', - 'frameRender', 'command', - 'loadPreset', 'update', 'widget', + 'loadPreset', 'command', + 'update', 'widget', ) # Auto-decorate methods @@ -212,7 +210,7 @@ class ComponentMetaclass(type(QtCore.QObject)): attrs[key] = property(attrs[key]) elif key == 'command': attrs[key] = cls.commandWrapper(attrs[key]) - elif key in ('previewRender', 'frameRender'): + elif key == 'previewRender': attrs[key] = cls.renderWrapper(attrs[key]) elif key == 'preFrameRender': attrs[key] = cls.initializationWrapper(attrs[key]) @@ -298,16 +296,19 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): return self.__class__.name def __repr__(self): + import pprint try: preset = self.savePreset() except Exception as e: preset = '%s occurred while saving preset' % str(e) return ( - 'Component(%s, %s, Core)\n' - 'Name: %s v%s\n Preset: %s' % ( + 'Component(module %s, pos %s) (%s)\n' + 'Name: %s v%s\nPreset: %s' % ( self.moduleIndex, self.compPos, - self.__class__.name, str(self.__class__.version), preset + object.__repr__(self), + self.__class__.name, str(self.__class__.version), + pprint.pformat(preset) ) ) @@ -886,12 +887,11 @@ class ComponentUpdate(QtWidgets.QUndoCommand): def redo(self): if self.undone: log.debug('Redoing component update') - self.parent.oldAttrs = self.relativeWidgetValsAfterUndo - self.setWidgetValues(self.modifiedVals) - self.parent.update(auto=True) - self.parent.oldAttrs = None - else: - self.parent.setAttrs(self.modifiedVals) + self.parent.oldAttrs = self.relativeWidgetValsAfterUndo + self.setWidgetValues(self.modifiedVals) + self.parent.update(auto=True) + self.parent.oldAttrs = None + if not self.undone: self.relativeWidgetValsAfterRedo = { attr: copy(getattr(self.parent, attr)) for attr in self.parent._relativeWidgets diff --git a/src/components/color.py b/src/components/color.py index a55aa10..7d4f86d 100644 --- a/src/components/color.py +++ b/src/components/color.py @@ -102,7 +102,7 @@ class Component(Component): # Return a solid image at x, y if self.fillType == 0: frame = BlankFrame(width, height) - image = Image.new("RGBA", shapeSize, (r, g, b, 255)) + image = FloodFrame(self.sizeWidth, self.sizeHeight, (r, g, b, 255)) frame.paste(image, box=(self.x, self.y)) return frame diff --git a/src/components/color.ui b/src/components/color.ui index 1865e60..c1713fb 100644 --- a/src/components/color.ui +++ b/src/components/color.ui @@ -204,7 +204,7 @@ 0 - 999999999 + 19200 0 @@ -239,7 +239,7 @@ - 999999999 + 10800 diff --git a/src/components/text.py b/src/components/text.py index 92f0599..32a108e 100644 --- a/src/components/text.py +++ b/src/components/text.py @@ -2,10 +2,13 @@ from PIL import ImageEnhance, ImageFilter, ImageChops from PyQt5.QtGui import QColor, QFont from PyQt5 import QtGui, QtCore, QtWidgets import os +import logging from component import Component from toolkit.frame import FramePainter, PaintColor +log = logging.getLogger('AVP.Components.Text') + class Component(Component): name = 'Title Text' @@ -76,16 +79,15 @@ class Component(Component): def getXY(self): '''Returns true x, y after considering alignment settings''' fm = QtGui.QFontMetrics(self.titleFont) - if self.alignment == 0: # Left - x = int(self.xPosition) + x = self.pixelValForAttr('xPosition') if self.alignment == 1: # Middle offset = int(fm.width(self.title)/2) - x = self.xPosition - offset - + x -= offset if self.alignment == 2: # Right offset = fm.width(self.title) - x = self.xPosition - offset + x -= offset + return x, self.yPosition def loadPreset(self, pr, *args): @@ -137,6 +139,7 @@ class Component(Component): image = FramePainter(width, height) x, y = self.getXY() + log.debug('Text position translates to %s, %s', x, y) if self.stroke > 0: outliner = QtGui.QPainterPathStroker() outliner.setWidth(self.stroke) diff --git a/src/core.py b/src/core.py index 784f3b8..b9e2335 100644 --- a/src/core.py +++ b/src/core.py @@ -14,7 +14,7 @@ import toolkit log = logging.getLogger('AVP.Core') STDOUT_LOGLVL = logging.VERBOSE -FILE_LOGLVL = logging.VERBOSE +FILE_LOGLVL = logging.DEBUG class Core: @@ -32,6 +32,11 @@ class Core: self.savedPresets = {} # copies of presets to detect modification self.openingProject = False + def __repr__(self): + return "\n=~=~=~=\n".join( + [repr(comp) for comp in self.selectedComponents] + ) + def importComponents(self): def findComponents(): for f in os.listdir(Core.componentsPath): @@ -482,7 +487,6 @@ class Core: '854x480', ], 'FFMPEG_BIN': findFfmpeg(), - 'windowHasFocus': False, 'canceled': False, } diff --git a/src/gui/mainwindow.py b/src/gui/mainwindow.py index 3b204b7..d7fde5c 100644 --- a/src/gui/mainwindow.py +++ b/src/gui/mainwindow.py @@ -11,6 +11,7 @@ from queue import Queue import sys import os import signal +import atexit import filecmp import time import logging @@ -49,6 +50,13 @@ class MainWindow(QtWidgets.QMainWindow): self.window = window self.core = Core() Core.mode = 'GUI' + # widgets of component settings + self.pages = [] + self.lastAutosave = time.time() + # list of previous five autosave times, used to reduce update spam + self.autosaveTimes = [] + self.autosaveCooldown = 0.2 + self.encoding = False # Find settings created by Core object self.dataDir = Core.dataDir @@ -56,19 +64,16 @@ class MainWindow(QtWidgets.QMainWindow): self.autosavePath = os.path.join(self.dataDir, 'autosave.avp') self.settings = Core.settings + # Register clean-up functions + signal.signal(signal.SIGINT, self.terminate) + atexit.register(self.cleanUp) + # Create stack of undoable user actions self.undoStack = QtWidgets.QUndoStack(self) undoLimit = self.settings.value("pref_undoLimit") self.undoStack.setUndoLimit(undoLimit) - # widgets of component settings - self.pages = [] - self.lastAutosave = time.time() - # list of previous five autosave times, used to reduce update spam - self.autosaveTimes = [] - self.autosaveCooldown = 0.2 - self.encoding = False - + # Create Preset Manager self.presetManager = PresetManager( uic.loadUi( os.path.join(Core.wd, 'gui', 'presetmanager.ui')), self) @@ -97,7 +102,6 @@ class MainWindow(QtWidgets.QMainWindow): self.timer.start(timeout) # Begin decorating the window and connecting events - self.window.installEventFilter(self) componentList = self.window.listWidget_componentList style = window.pushButton_undo.style() @@ -391,24 +395,41 @@ class MainWindow(QtWidgets.QMainWindow): activated=lambda: self.moveComponent('bottom') ) - # Debug Hotkeys QtWidgets.QShortcut( - "Ctrl+Alt+Shift+R", self.window, self.drawPreview + "Ctrl+Shift+F", self.window, self.showFfmpegCommand ) QtWidgets.QShortcut( - "Ctrl+Alt+Shift+F", self.window, self.showFfmpegCommand + "Ctrl+Shift+U", self.window, self.showUndoStack ) - QtWidgets.QShortcut( - "Ctrl+Alt+Shift+U", self.window, self.showUndoStack + + if log.isEnabledFor(logging.DEBUG): + QtWidgets.QShortcut( + "Ctrl+Alt+Shift+R", self.window, self.drawPreview + ) + QtWidgets.QShortcut( + "Ctrl+Alt+Shift+A", self.window, lambda: log.debug(repr(self)) + ) + + def __repr__(self): + return ( + '\n%s\n' + '#####\n' + 'Preview thread is %s\n' % ( + repr(self.core), + 'live' if self.previewThread.isRunning() else 'dead', + ) ) - @QtCore.pyqtSlot() def cleanUp(self, *args): log.info('Ending the preview thread') self.timer.stop() self.previewThread.quit() self.previewThread.wait() + def terminate(self, *args): + self.cleanUp() + sys.exit(0) + @disableWhenOpeningProject def updateWindowTitle(self): appName = 'Audio Visualizer' @@ -542,7 +563,7 @@ class MainWindow(QtWidgets.QMainWindow): return True except FileNotFoundError: log.error( - 'Project file couldn\'t be located:', self.currentProject) + 'Project file couldn\'t be located: %s', self.currentProject) return identical return False @@ -639,6 +660,7 @@ class MainWindow(QtWidgets.QMainWindow): detail=detail, icon='Critical', ) + log.info('%s', repr(self)) def changeEncodingStatus(self, status): self.encoding = status @@ -1017,12 +1039,3 @@ class MainWindow(QtWidgets.QMainWindow): self.menu.move(parentPosition + QPos) self.menu.show() - - def eventFilter(self, object, event): - if event.type() == QtCore.QEvent.WindowActivate \ - or event.type() == QtCore.QEvent.FocusIn: - Core.windowHasFocus = True - elif event.type() == QtCore.QEvent.WindowDeactivate \ - or event.type() == QtCore.QEvent.FocusOut: - Core.windowHasFocus = False - return False diff --git a/src/gui/preview_win.py b/src/gui/preview_win.py index c6b9a32..49a22eb 100644 --- a/src/gui/preview_win.py +++ b/src/gui/preview_win.py @@ -60,3 +60,4 @@ class PreviewWindow(QtWidgets.QLabel): icon='Critical', parent=self ) + log.info('%', repr(self.parent)) diff --git a/src/main.py b/src/main.py index 6d18af3..f767de1 100644 --- a/src/main.py +++ b/src/main.py @@ -36,8 +36,6 @@ def main(): elif mode == 'GUI': from gui.mainwindow import MainWindow - import atexit - import signal window = uic.loadUi(os.path.join(wd, "gui", "mainwindow.ui")) # window.adjustSize() @@ -56,9 +54,6 @@ def main(): log.debug("Finished creating main window") window.raise_() - signal.signal(signal.SIGINT, main.cleanUp) - atexit.register(main.cleanUp) - sys.exit(app.exec_()) if __name__ == "__main__": diff --git a/src/toolkit/ffmpeg.py b/src/toolkit/ffmpeg.py index f007f90..a77831e 100644 --- a/src/toolkit/ffmpeg.py +++ b/src/toolkit/ffmpeg.py @@ -157,7 +157,7 @@ def findFfmpeg(): ['ffmpeg', '-version'], stderr=f ) return "ffmpeg" - except subprocess.CalledProcessError: + except (subprocess.CalledProcessError, FileNotFoundError): return "avconv" diff --git a/src/toolkit/frame.py b/src/toolkit/frame.py index 2104978..aefb55f 100644 --- a/src/toolkit/frame.py +++ b/src/toolkit/frame.py @@ -21,7 +21,6 @@ class FramePainter(QtGui.QPainter): Pillow image with finalize() ''' def __init__(self, width, height): - log.verbose('Creating new FramePainter') image = BlankFrame(width, height) self.image = QtGui.QImage(ImageQt(image)) super().__init__(self.image) @@ -78,8 +77,6 @@ def defaultSize(framefunc): def FloodFrame(width, height, RgbaTuple): - log.verbose('Creating new %s*%s %s flood frame' % ( - width, height, RgbaTuple)) return Image.new("RGBA", (width, height), RgbaTuple) -- cgit v1.2.3 From ad6dd9f5329f3e23e75c181c21ca8701028b538f Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 27 Aug 2017 19:59:51 -0400 Subject: undoable Life component grid actions --- src/components/life.py | 132 ++++++++++++++++++++++++++++++++++++------------- src/gui/preview_win.py | 8 ++- 2 files changed, 102 insertions(+), 38 deletions(-) (limited to 'src/gui/preview_win.py') diff --git a/src/components/life.py b/src/components/life.py index d4a455d..7a610eb 100644 --- a/src/components/life.py +++ b/src/components/life.py @@ -1,4 +1,5 @@ from PyQt5 import QtGui, QtCore, QtWidgets +from PyQt5.QtWidgets import QUndoCommand from PIL import Image, ImageDraw, ImageEnhance, ImageChops, ImageFilter import os import math @@ -58,22 +59,8 @@ class Component(Component): self.mergeUndo = True def shiftGrid(self, d): - def newGrid(Xchange, Ychange): - return { - (x + Xchange, y + Ychange) - for x, y in self.startingGrid - } - - if d == 0: - newGrid = newGrid(0, -1) - elif d == 1: - newGrid = newGrid(0, 1) - elif d == 2: - newGrid = newGrid(-1, 0) - elif d == 3: - newGrid = newGrid(1, 0) - self.startingGrid = newGrid - self._sendUpdateSignal() + action = ShiftGrid(self, d) + self.parent.undoStack.push(action) def update(self): self.updateGridSize() @@ -98,17 +85,14 @@ class Component(Component): enabled = (len(self.startingGrid) > 0) for widget in self.shiftButtons: widget.setEnabled(enabled) - super().update() def previewClickEvent(self, pos, size, button): pos = ( math.ceil((pos[0] / size[0]) * self.gridWidth) - 1, math.ceil((pos[1] / size[1]) * self.gridHeight) - 1 ) - if button == 1: - self.startingGrid.add(pos) - elif button == 2: - self.startingGrid.discard(pos) + action = ClickGrid(self, pos, button) + self.parent.undoStack.push(action) def updateGridSize(self): w, h = self.core.resolutions[-1].split('x') @@ -223,7 +207,7 @@ class Component(Component): 'up', 'down', 'left', 'right', ) } - for cell in nearbyCoords(x, y): + for cell in self.nearbyCoords(x, y): if cell not in grid: continue if cell[0] == x: @@ -363,7 +347,7 @@ class Component(Component): def neighbours(x, y): return { - cell for cell in nearbyCoords(x, y) + cell for cell in self.nearbyCoords(x, y) if cell in lastGrid } @@ -374,7 +358,7 @@ class Component(Component): newGrid.add((x, y)) potentialNewCells = { coordTup for origin in lastGrid - for coordTup in list(nearbyCoords(*origin)) + for coordTup in list(self.nearbyCoords(*origin)) } for x, y in potentialNewCells: if (x, y) in newGrid: @@ -397,13 +381,95 @@ class Component(Component): widget.setEnabled(True) super().loadPreset(pr, *args) + def nearbyCoords(self, x, y): + yield x + 1, y + 1 + yield x + 1, y - 1 + yield x - 1, y + 1 + yield x - 1, y - 1 + yield x, y + 1 + yield x, y - 1 + yield x + 1, y + yield x - 1, y + + +class ClickGrid(QUndoCommand): + def __init__(self, comp, pos, id_): + super().__init__( + "click %s component #%s" % (comp.name, comp.compPos)) + self.comp = comp + self.pos = [pos] + self.id_ = id_ + + def id(self): + return self.id_ + + def mergeWith(self, other): + self.pos.extend(other.pos) + return True + + def add(self): + for pos in self.pos[:]: + self.comp.startingGrid.add(pos) + self.comp.update(auto=True) + + def remove(self): + for pos in self.pos[:]: + self.comp.startingGrid.discard(pos) + self.comp.update(auto=True) + + def redo(self): + if self.id_ == 1: # Left-click + self.add() + elif self.id_ == 2: # Right-click + self.remove() + + def undo(self): + if self.id_ == 1: # Left-click + self.remove() + elif self.id_ == 2: # Right-click + self.add() + +class ShiftGrid(QUndoCommand): + def __init__(self, comp, direction): + super().__init__( + "change %s component #%s" % (comp.name, comp.compPos)) + self.comp = comp + self.direction = direction + self.distance = 1 + + def id(self): + return self.direction + + def mergeWith(self, other): + self.distance += other.distance + return True + + def newGrid(self, Xchange, Ychange): + return { + (x + Xchange, y + Ychange) + for x, y in self.comp.startingGrid + } -def nearbyCoords(x, y): - yield x + 1, y + 1 - yield x + 1, y - 1 - yield x - 1, y + 1 - yield x - 1, y - 1 - yield x, y + 1 - yield x, y - 1 - yield x + 1, y - yield x - 1, y + def redo(self): + if self.direction == 0: + newGrid = self.newGrid(0, -self.distance) + elif self.direction == 1: + newGrid = self.newGrid(0, self.distance) + elif self.direction == 2: + newGrid = self.newGrid(-self.distance, 0) + elif self.direction == 3: + newGrid = self.newGrid(self.distance, 0) + self.comp.startingGrid = newGrid + self.comp._sendUpdateSignal() + + def undo(self): + if self.direction == 0: + newGrid = self.newGrid(0, self.distance) + elif self.direction == 1: + newGrid = self.newGrid(0, -self.distance) + elif self.direction == 2: + newGrid = self.newGrid(self.distance, 0) + elif self.direction == 3: + newGrid = self.newGrid(-self.distance, 0) + self.comp.startingGrid = newGrid + self.comp._sendUpdateSignal() diff --git a/src/gui/preview_win.py b/src/gui/preview_win.py index 49a22eb..3db420c 100644 --- a/src/gui/preview_win.py +++ b/src/gui/preview_win.py @@ -1,14 +1,14 @@ from PyQt5 import QtCore, QtGui, QtWidgets import logging +log = logging.getLogger('AVP.Gui.PreviewWindow') + class PreviewWindow(QtWidgets.QLabel): ''' Paints the preview QLabel in MainWindow and maintains the aspect ratio when the window is resized. ''' - log = logging.getLogger('AVP.Gui.PreviewWindow') - def __init__(self, parent, img): super(PreviewWindow, self).__init__() self.parent = parent @@ -41,17 +41,15 @@ class PreviewWindow(QtWidgets.QLabel): if i >= 0: component = self.parent.core.selectedComponents[i] if not hasattr(component, 'previewClickEvent'): - self.log.info('Ignored click event') return pos = (event.x(), event.y()) size = (self.width(), self.height()) butt = event.button() - self.log.info('Click event for #%s: %s button %s' % ( + log.info('Click event for #%s: %s button %s' % ( i, pos, butt)) component.previewClickEvent( pos, size, butt ) - self.parent.core.updateComponent(i) @QtCore.pyqtSlot(str) def threadError(self, msg): -- cgit v1.2.3 From 765a35119f258f352718a556fbea4af708236900 Mon Sep 17 00:00:00 2001 From: tassaron Date: Wed, 13 Apr 2022 16:04:32 -0400 Subject: cast floats to ints when calling resize(), setX(), and setY() (argument types changed in newer version) --- src/gui/preview_win.py | 4 ++-- src/main.py | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/gui/preview_win.py') diff --git a/src/gui/preview_win.py b/src/gui/preview_win.py index 3db420c..27e0a59 100644 --- a/src/gui/preview_win.py +++ b/src/gui/preview_win.py @@ -25,8 +25,8 @@ class PreviewWindow(QtWidgets.QLabel): transformMode=QtCore.Qt.SmoothTransformation) # start painting the label from left upper corner - point.setX((size.width() - scaledPix.width())/2) - point.setY((size.height() - scaledPix.height())/2) + point.setX(int((size.width() - scaledPix.width())/2)) + point.setY(int((size.height() - scaledPix.height())/2)) painter.drawPixmap(point, scaledPix) def changePixmap(self, img): diff --git a/src/main.py b/src/main.py index f767de1..126e4a8 100644 --- a/src/main.py +++ b/src/main.py @@ -44,9 +44,10 @@ def main(): topMargin = 0 if (dpi == 96) else int(10 * (dpi / 96)) window.resize( - window.width() * - (dpi / 96), window.height() * - (dpi / 96) + int(window.width() * + (dpi / 96)), + int(window.height() * + (dpi / 96)) ) # window.verticalLayout_2.setContentsMargins(0, topMargin, 0, 0) -- cgit v1.2.3 From 069edd9086ad7a99c78c5637af23d50a633396cf Mon Sep 17 00:00:00 2001 From: tassaron Date: Fri, 29 Apr 2022 12:58:26 -0400 Subject: use super().__init__ in the modern python3 style --- src/command.py | 2 +- src/gui/preview_thread.py | 4 ++-- src/gui/preview_win.py | 2 +- src/video_thread.py | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/gui/preview_win.py') diff --git a/src/command.py b/src/command.py index 267117e..cc13684 100644 --- a/src/command.py +++ b/src/command.py @@ -25,7 +25,7 @@ class Command(QtCore.QObject): createVideo = QtCore.pyqtSignal() def __init__(self): - super() + super().__init__() self.core = core.Core() core.Core.mode = 'commandline' self.dataDir = self.core.dataDir diff --git a/src/gui/preview_thread.py b/src/gui/preview_thread.py index 7829476..614b584 100644 --- a/src/gui/preview_thread.py +++ b/src/gui/preview_thread.py @@ -23,10 +23,10 @@ class Worker(QtCore.QObject): error = pyqtSignal(str) def __init__(self, parent=None, queue=None): - QtCore.QObject.__init__(self) + super().__init__() parent.newTask.connect(self.createPreviewImage) parent.processTask.connect(self.process) - self.parent = parent + #self.parent = parent self.core = parent.core self.settings = parent.settings self.queue = queue diff --git a/src/gui/preview_win.py b/src/gui/preview_win.py index 27e0a59..426ff66 100644 --- a/src/gui/preview_win.py +++ b/src/gui/preview_win.py @@ -10,7 +10,7 @@ class PreviewWindow(QtWidgets.QLabel): when the window is resized. ''' def __init__(self, parent, img): - super(PreviewWindow, self).__init__() + super().__init__() self.parent = parent self.setFrameStyle(QtWidgets.QFrame.StyledPanel) self.pixmap = QtGui.QPixmap(img) diff --git a/src/video_thread.py b/src/video_thread.py index 2fe264a..4a28261 100644 --- a/src/video_thread.py +++ b/src/video_thread.py @@ -39,13 +39,13 @@ class Worker(QtCore.QObject): encoding = pyqtSignal(bool) def __init__(self, parent, inputFile, outputFile, components): - QtCore.QObject.__init__(self) + super().__init__() self.core = parent.core self.settings = parent.settings self.modules = parent.core.modules parent.createVideo.connect(self.createVideo) - self.parent = parent + #self.parent = parent self.components = components self.outputFile = outputFile self.inputFile = inputFile -- 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/preview_win.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