component updateWrapper and more obvious method names

This commit is contained in:
tassaron 2017-08-17 15:12:22 -04:00
parent c06ca5cdcb
commit 43ea3bfd73
2 changed files with 122 additions and 93 deletions

View File

@ -99,7 +99,7 @@ class ComponentMetaclass(type(QtCore.QObject)):
return func(self)
return errorWrapper
def presetWrapper(func):
def loadPresetWrapper(func):
'''Wraps loadPreset to handle the self.openingPreset boolean'''
class openingPreset:
def __init__(self, comp):
@ -116,6 +116,36 @@ class ComponentMetaclass(type(QtCore.QObject)):
return func(self, *args)
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()
'''
class wrap:
def __init__(self, comp, auto):
self.comp = comp
self.auto = auto
def __enter__(self):
pass
def __exit__(self, *args):
if self.auto or self.comp.openingPreset \
or not hasattr(self.comp.parent, 'undoStack'):
self.comp._autoUpdate()
else:
self.comp._userUpdate()
def updateWrapper(self, **kwargs):
auto = False
if 'auto' in kwargs:
auto = kwargs['auto']
with wrap(self, auto):
return func(self)
return updateWrapper
def __new__(cls, name, parents, attrs):
if 'ui' not in attrs:
# Use module name as ui filename by default
@ -128,37 +158,32 @@ class ComponentMetaclass(type(QtCore.QObject)):
'names', # Class methods
'error', 'audio', 'properties', # Properties
'preFrameRender', 'previewRender',
'frameRender', 'command', 'loadPreset'
'frameRender', 'command',
'loadPreset', 'update'
)
# Auto-decorate methods
for key in decorate:
if key not in attrs:
continue
if key in ('names'):
attrs[key] = classmethod(attrs[key])
if key in ('audio'):
elif key in ('audio'):
attrs[key] = property(attrs[key])
if key == 'command':
elif key == 'command':
attrs[key] = cls.commandWrapper(attrs[key])
if key in ('previewRender', 'frameRender'):
elif key in ('previewRender', 'frameRender'):
attrs[key] = cls.renderWrapper(attrs[key])
if key == 'preFrameRender':
elif key == 'preFrameRender':
attrs[key] = cls.initializationWrapper(attrs[key])
if key == 'properties':
elif key == 'properties':
attrs[key] = cls.propertiesWrapper(attrs[key])
if key == 'error':
elif key == 'error':
attrs[key] = cls.errorWrapper(attrs[key])
if key == 'loadPreset':
attrs[key] = cls.presetWrapper(attrs[key])
elif key == 'loadPreset':
attrs[key] = cls.loadPresetWrapper(attrs[key])
elif key == 'update':
attrs[key] = cls.updateWrapper(attrs[key])
# Turn version string into a number
try:
@ -229,10 +254,12 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass):
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' % (
self.moduleIndex, self.compPos,
self.__class__.name, str(self.__class__.version), preset
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
)
)
# =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~
@ -329,74 +356,10 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass):
def update(self):
'''
A component update triggered by the user changing a widget value
Call super() at the END when subclassing this.
Starting point for a component update. A subclass should override
this method, and the base class will then magically insert a call
to either _autoUpdate() or _userUpdate() at the end.
'''
if self.openingPreset or not hasattr(self.parent, 'undoStack'):
return self._update()
oldWidgetVals = {
attr: getattr(self, attr)
for attr in self._trackedWidgets
}
newWidgetVals = {
attr: getWidgetValue(widget)
if attr not in self._colorWidgets else rgbFromString(widget.text())
for attr, widget in self._trackedWidgets.items()
}
modifiedWidgets = {
attr: val
for attr, val in newWidgetVals.items()
if val != oldWidgetVals[attr]
}
if modifiedWidgets:
action = ComponentUpdate(self, oldWidgetVals, modifiedWidgets)
self.parent.undoStack.push(action)
def _update(self):
'''A component update that is not undoable'''
newWidgetVals = {
attr: getWidgetValue(widget)
for attr, widget in self._trackedWidgets.items()
}
self.setAttrs(newWidgetVals)
self.sendUpdateSignal()
def setAttrs(self, attrDict):
'''
Sets attrs (linked to trackedWidgets) in this preset 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
if type(val) is tuple:
rgbTuple = val
else:
rgbTuple = rgbFromString(val)
btnStyle = (
"QPushButton { background-color : %s; outline: none; }"
% QColor(*rgbTuple).name())
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 sendUpdateSignal(self):
if not self.core.openingProject:
self.parent.drawPreview()
saveValueStore = self.savePreset()
saveValueStore['preset'] = self.currentPreset
self.modified.emit(self.compPos, saveValueStore)
def loadPreset(self, presetDict, presetName=None):
'''
@ -464,6 +427,69 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass):
# =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~
# "Private" Methods
# =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~
def _userUpdate(self):
'''An undoable component update triggered by the user'''
oldWidgetVals = {
attr: getattr(self, attr)
for attr in self._trackedWidgets
}
newWidgetVals = {
attr: getWidgetValue(widget)
if attr not in self._colorWidgets else rgbFromString(widget.text())
for attr, widget in self._trackedWidgets.items()
}
modifiedWidgets = {
attr: val
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'''
newWidgetVals = {
attr: getWidgetValue(widget)
for attr, widget in self._trackedWidgets.items()
}
self.setAttrs(newWidgetVals)
self._sendUpdateSignal()
def setAttrs(self, attrDict):
'''
Sets attrs (linked to trackedWidgets) in this preset 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
if type(val) is tuple:
rgbTuple = val
else:
rgbTuple = rgbFromString(val)
btnStyle = (
"QPushButton { background-color : %s; outline: none; }"
% QColor(*rgbTuple).name())
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 _sendUpdateSignal(self):
if not self.core.openingProject:
self.parent.drawPreview()
saveValueStore = self.savePreset()
saveValueStore['preset'] = self.currentPreset
self.modified.emit(self.compPos, saveValueStore)
def trackWidgets(self, trackDict, **kwargs):
'''
@ -730,7 +756,7 @@ class ComponentUpdate(QtWidgets.QUndoCommand):
def redo(self):
self.parent.setAttrs(self.modifiedVals)
self.parent.sendUpdateSignal()
self.parent._sendUpdateSignal()
def undo(self):
self.parent.setAttrs(self.oldWidgetVals)
@ -740,4 +766,4 @@ class ComponentUpdate(QtWidgets.QUndoCommand):
if attr in self.parent._colorWidgets:
val = '%s,%s,%s' % val
setWidgetValue(widget, val)
self.parent.sendUpdateSignal()
self.parent._sendUpdateSignal()

View File

@ -83,6 +83,8 @@ class Core:
)
# 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(
@ -118,8 +120,9 @@ class Core:
self.componentListChanged()
def updateComponent(self, i):
log.debug('Updating %s #%s' % (self.selectedComponents[i], str(i)))
self.selectedComponents[i]._update()
log.debug('Auto-updating %s #%s' % (
self.selectedComponents[i], str(i)))
self.selectedComponents[i].update(auto=True)
def moduleIndexFor(self, compName):
try: