adding an asterisk to modified, unsaved presets

flags for unsaved changes saved in project files
This commit is contained in:
tassaron 2017-06-12 22:34:37 -04:00
parent dbbefbf70e
commit 307d499f9a
9 changed files with 175 additions and 48 deletions

View File

@ -1,9 +1,15 @@
from PyQt4 import QtGui from PyQt4 import QtGui, QtCore
class Component(QtCore.QObject):
'''A base class for components to inherit from'''
class Component: # modified = QtCore.pyqtSignal(int, bool)
def __init__(self):
def __init__(self, moduleIndex, compPos):
super().__init__()
self.currentPreset = None self.currentPreset = None
self.moduleIndex = moduleIndex
self.compPos = compPos
def __str__(self): def __str__(self):
return self.__doc__ return self.__doc__
@ -13,12 +19,27 @@ class Component:
return 1 return 1
def cancel(self): def cancel(self):
# make sure your component responds to these variables in frameRender() # please stop any lengthy process in response to this variable
self.canceled = True self.canceled = True
def reset(self): def reset(self):
self.canceled = False self.canceled = False
def update(self):
self.modified.emit(self.compPos, True)
# use super().update() then read your widget values here
def loadPreset(self, presetDict, presetName):
'''Children should take (presetDict, presetName=None) as args'''
# Use super().loadPreset(presetDict, presetName)
# Then update your widgets using the preset dict
self.currentPreset = presetName \
if presetName != None else presetDict['preset']
def savePreset(self):
return {}
def preFrameRender(self, **kwargs): def preFrameRender(self, **kwargs):
for var, value in kwargs.items(): for var, value in kwargs.items():
exec('self.%s = value' % var) exec('self.%s = value' % var)
@ -62,7 +83,7 @@ class Component:
return page return page
def update(self): def update(self):
# read widget values super().update()
self.parent.drawPreview() self.parent.drawPreview()
def previewRender(self, previewWorker): def previewRender(self, previewWorker):
@ -77,13 +98,6 @@ class Component:
image = Image.new("RGBA", (width, height), (0,0,0,0)) image = Image.new("RGBA", (width, height), (0,0,0,0))
return image return image
def loadPreset(self, presetDict, presetName=None):
self.currentPreset = presetName
# update widgets using a preset dict
def savePreset(self):
return {}
def cancel(self): def cancel(self):
self.canceled = True self.canceled = True

View File

@ -7,6 +7,9 @@ from . import __base__
class Component(__base__.Component): class Component(__base__.Component):
'''Color''' '''Color'''
modified = QtCore.pyqtSignal(int, bool)
def widget(self, parent): def widget(self, parent):
self.parent = parent self.parent = parent
page = uic.loadUi(os.path.join( page = uic.loadUi(os.path.join(
@ -45,6 +48,7 @@ class Component(__base__.Component):
return page return page
def update(self): def update(self):
super().update()
self.color1 = self.RGBFromString(self.page.lineEdit_color1.text()) self.color1 = self.RGBFromString(self.page.lineEdit_color1.text())
self.color2 = self.RGBFromString(self.page.lineEdit_color2.text()) self.color2 = self.RGBFromString(self.page.lineEdit_color2.text())
self.x = self.page.spinBox_x.value() self.x = self.page.spinBox_x.value()
@ -70,7 +74,8 @@ class Component(__base__.Component):
return Image.new("RGBA", (width, height), (r, g, b, 255)) return Image.new("RGBA", (width, height), (r, g, b, 255))
def loadPreset(self, pr, presetName=None): def loadPreset(self, pr, presetName=None):
self.currentPreset = presetName if presetName else pr['preset'] super().loadPreset(pr, presetName)
self.page.lineEdit_color1.setText('%s,%s,%s' % pr['color1']) self.page.lineEdit_color1.setText('%s,%s,%s' % pr['color1'])
self.page.lineEdit_color2.setText('%s,%s,%s' % pr['color2']) self.page.lineEdit_color2.setText('%s,%s,%s' % pr['color2'])

View File

@ -6,6 +6,9 @@ from . import __base__
class Component(__base__.Component): class Component(__base__.Component):
'''Image''' '''Image'''
modified = QtCore.pyqtSignal(int, bool)
def widget(self, parent): def widget(self, parent):
self.parent = parent self.parent = parent
self.settings = parent.settings self.settings = parent.settings
@ -22,6 +25,7 @@ class Component(__base__.Component):
return page return page
def update(self): def update(self):
super().update()
self.imagePath = self.page.lineEdit_image.text() self.imagePath = self.page.lineEdit_image.text()
self.parent.drawPreview() self.parent.drawPreview()
@ -49,7 +53,7 @@ class Component(__base__.Component):
return frame return frame
def loadPreset(self, pr, presetName=None): def loadPreset(self, pr, presetName=None):
self.currentPreset = presetName if presetName else pr['preset'] super().loadPreset(pr, presetName)
self.page.lineEdit_image.setText(pr['image']) self.page.lineEdit_image.setText(pr['image'])
def savePreset(self): def savePreset(self):

View File

@ -1,9 +1,8 @@
import numpy import numpy
from PIL import Image, ImageDraw from PIL import Image, ImageDraw
from PyQt4 import uic, QtGui from PyQt4 import uic, QtGui, QtCore
from PyQt4.QtGui import QColor from PyQt4.QtGui import QColor
import os import os
import random
from . import __base__ from . import __base__
import time import time
from copy import copy from copy import copy
@ -11,6 +10,9 @@ from copy import copy
class Component(__base__.Component): class Component(__base__.Component):
'''Original Audio Visualization''' '''Original Audio Visualization'''
modified = QtCore.pyqtSignal(int, bool)
def widget(self, parent): def widget(self, parent):
self.parent = parent self.parent = parent
self.visColor = (255, 255, 255) self.visColor = (255, 255, 255)
@ -33,12 +35,14 @@ class Component(__base__.Component):
return page return page
def update(self): def update(self):
super().update()
self.layout = self.page.comboBox_visLayout.currentIndex() self.layout = self.page.comboBox_visLayout.currentIndex()
self.visColor = self.RGBFromString(self.page.lineEdit_visColor.text()) self.visColor = self.RGBFromString(self.page.lineEdit_visColor.text())
self.parent.drawPreview() self.parent.drawPreview()
def loadPreset(self, pr, presetName=None): def loadPreset(self, pr, presetName=None):
self.currentPreset = presetName if presetName else pr['preset'] super().loadPreset(pr, presetName)
self.page.lineEdit_visColor.setText('%s,%s,%s' % pr['visColor']) self.page.lineEdit_visColor.setText('%s,%s,%s' % pr['visColor'])
btnStyle = "QPushButton { background-color : %s; outline: none; }" \ btnStyle = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*pr['visColor']).name() % QColor(*pr['visColor']).name()

View File

@ -9,8 +9,11 @@ from . import __base__
class Component(__base__.Component): class Component(__base__.Component):
'''Title Text''' '''Title Text'''
def __init__(self):
super().__init__() modified = QtCore.pyqtSignal(int, bool)
def __init__(self, *args):
super().__init__(*args)
self.titleFont = QFont() self.titleFont = QFont()
def widget(self, parent): def widget(self, parent):
@ -53,6 +56,7 @@ class Component(__base__.Component):
return page return page
def update(self): def update(self):
super().update()
self.title = self.page.lineEdit_title.text() self.title = self.page.lineEdit_title.text()
self.alignment = self.page.comboBox_textAlign.currentIndex() self.alignment = self.page.comboBox_textAlign.currentIndex()
self.titleFont = self.page.fontComboBox_titleFont.currentFont() self.titleFont = self.page.fontComboBox_titleFont.currentFont()
@ -79,7 +83,8 @@ class Component(__base__.Component):
return x, self.yPosition return x, self.yPosition
def loadPreset(self, pr, presetName=None): def loadPreset(self, pr, presetName=None):
self.currentPreset = presetName if presetName else pr['preset'] super().loadPreset(pr, presetName)
self.page.lineEdit_title.setText(pr['title']) self.page.lineEdit_title.setText(pr['title'])
font = QFont() font = QFont()
font.fromString(pr['titleFont']) font.fromString(pr['titleFont'])

View File

@ -86,6 +86,9 @@ class Video:
class Component(__base__.Component): class Component(__base__.Component):
'''Video''' '''Video'''
modified = QtCore.pyqtSignal(int, bool)
def widget(self, parent): def widget(self, parent):
self.parent = parent self.parent = parent
self.settings = parent.settings self.settings = parent.settings
@ -106,6 +109,7 @@ class Component(__base__.Component):
return page return page
def update(self): def update(self):
super().update()
self.videoPath = self.page.lineEdit_video.text() self.videoPath = self.page.lineEdit_video.text()
self.loopVideo = self.page.checkBox_loop.isChecked() self.loopVideo = self.page.checkBox_loop.isChecked()
self.parent.drawPreview() self.parent.drawPreview()
@ -136,7 +140,7 @@ class Component(__base__.Component):
return self.video.frame(frameNo) return self.video.frame(frameNo)
def loadPreset(self, pr, presetName=None): def loadPreset(self, pr, presetName=None):
self.currentPreset = presetName if presetName else pr['preset'] super().loadPreset(pr, presetName)
self.page.lineEdit_video.setText(pr['video']) self.page.lineEdit_video.setText(pr['video'])
self.page.checkBox_loop.setChecked(pr['loop']) self.page.checkBox_loop.setChecked(pr['loop'])

87
core.py
View File

@ -34,6 +34,7 @@ class Core():
self.findComponents() self.findComponents()
self.selectedComponents = [] self.selectedComponents = []
self.modifiedComponents = {}
def findComponents(self): def findComponents(self):
def findComponents(): def findComponents():
@ -50,24 +51,86 @@ class Core():
for name in findComponents()] for name in findComponents()]
self.moduleIndexes = [i for i in range(len(self.modules))] self.moduleIndexes = [i for i in range(len(self.modules))]
def componentListChanged(self):
for i, component in enumerate(self.selectedComponents):
component.compPos = i
# print('Modified Components: ', self.modifiedComponents)
def insertComponent(self, compPos, moduleIndex): def insertComponent(self, compPos, moduleIndex):
if compPos < 0: if compPos < 0:
compPos = len(self.selectedComponents) -1 compPos = len(self.selectedComponents) -1
component = self.modules[moduleIndex].Component(
moduleIndex, compPos)
self.selectedComponents.insert( self.selectedComponents.insert(
compPos, compPos,
self.modules[moduleIndex].Component() component)
)
newDict = {}
for i, val in self.modifiedComponents.items():
if i >= compPos:
newDict[i+1] = bool(val)
else:
newDict[i] = bool(val)
self.modifiedComponents.clear()
self.modifiedComponents = newDict
self.componentListChanged()
return compPos return compPos
def moveComponent(self, startI, endI): def moveComponent(self, startI, endI):
def insert(target, comp):
self.selectedComponents.insert(target, comp)
comp = self.selectedComponents.pop(startI) comp = self.selectedComponents.pop(startI)
self.selectedComponents.insert(endI, comp) insert(endI, comp)
try:
oldModified = self.modifiedComponents.pop(startI)
if endI in self.modifiedComponents:
self.modifiedComponents[startI] = \
self.modifiedComponents.pop(endI)
self.modifiedComponents[endI] = oldModified
except KeyError:
pass
self.componentListChanged()
return endI return endI
def removeComponent(self, i):
self.selectedComponents.pop(i)
try:
self.modifiedComponents.pop(i)
except KeyError:
pass
newDict = {}
for index, val in self.modifiedComponents.items():
if index >= i:
newDict[index-1] = bool(val)
else:
newDict[index] = bool(val)
self.modifiedComponents.clear()
self.modifiedComponents = newDict
self.componentListChanged()
def updateComponent(self, i): def updateComponent(self, i):
# print('updating %s' % self.selectedComponents[i]) # print('updating %s' % self.selectedComponents[i])
self.selectedComponents[i].update() self.selectedComponents[i].update()
def componentModified(self, i):
'''Triggered by mainwindow.updateComponentTitle()
Tracks temporary state of whether components are modified or not
for retrieval upon loading a project file'''
self.modifiedComponents[i] = True
def componentUnmodified(self, i):
try:
self.modifiedComponents.pop(i)
except KeyError:
pass
def moduleIndexFor(self, compName): def moduleIndexFor(self, compName):
compNames = [mod.Component.__doc__ for mod in self.modules] compNames = [mod.Component.__doc__ for mod in self.modules]
index = compNames.index(compName) index = compNames.index(compName)
@ -78,11 +141,17 @@ class Core():
which implements an insertComponent method''' which implements an insertComponent method'''
errcode, data = self.parseAvFile(filepath) errcode, data = self.parseAvFile(filepath)
if errcode == 0: if errcode == 0:
for name, vers, preset in data['Components']: for i, tup in enumerate(data['Components']):
name, vers, preset = tup
loader.insertComponent( loader.insertComponent(
self.moduleIndexFor(name), -1) self.moduleIndexFor(name), -1)
self.selectedComponents[-1].loadPreset( self.selectedComponents[-1].loadPreset(
preset) preset)
if data['Modified'][i] == True:
self.componentModified(i)
loader.updateComponentTitle(i, True)
else:
loader.updateComponentTitle(i)
elif errcode == 1: elif errcode == 1:
typ, value, _ = data typ, value, _ = data
if typ.__name__ == KeyError: if typ.__name__ == KeyError:
@ -105,7 +174,7 @@ class Core():
with open(filepath, 'r') as f: with open(filepath, 'r') as f:
def parseLine(line): def parseLine(line):
'''Decides if a given avp or avl line is a section header''' '''Decides if a given avp or avl line is a section header'''
validSections = ('Components') validSections = ('Components', 'Modified')
line = line.strip() line = line.strip()
newSection = '' newSection = ''
@ -138,6 +207,8 @@ class Core():
lastCompPreset) lastCompPreset)
) )
i = 0 i = 0
if line and section == 'Modified':
data[section].append(eval(line))
return 0, data return 0, data
except: except:
return 1, sys.exc_info() return 1, sys.exc_info()
@ -223,6 +294,12 @@ class Core():
f.write('%s\n' % str(comp)) f.write('%s\n' % str(comp))
f.write('%s\n' % str(comp.version())) f.write('%s\n' % str(comp.version()))
f.write('%s\n' % Core.presetToString(saveValueStore)) f.write('%s\n' % Core.presetToString(saveValueStore))
f.write('[Modified]\n')
for i in range(len(self.selectedComponents)):
if i in self.modifiedComponents:
f.write('%s\n' % repr(True))
else:
f.write('%s\n' % repr(False))
return True return True
except: except:
return False return False

View File

@ -235,13 +235,21 @@ class MainWindow(QtCore.QObject):
self.previewThread.wait() self.previewThread.wait()
self.autosave() self.autosave()
def updateComponentTitle(self, pos): @QtCore.pyqtSlot(int, bool)
def updateComponentTitle(self, pos, modified=False):
#print(pos, modified)
if pos < 0: if pos < 0:
pos = len(self.core.selectedComponents)-1 pos = len(self.core.selectedComponents)-1
title = str(self.core.selectedComponents[pos]) title = str(self.core.selectedComponents[pos])
if self.core.selectedComponents[pos].currentPreset: if self.core.selectedComponents[pos].currentPreset:
title += ' - %s' % self.core.selectedComponents[pos].currentPreset title += ' - %s' % self.core.selectedComponents[pos].currentPreset
if modified:
title += '*'
self.window.listWidget_componentList.item(pos).setText(title) self.window.listWidget_componentList.item(pos).setText(title)
if modified:
self.core.componentModified(pos)
else:
self.core.componentUnmodified(pos)
def updateCodecs(self): def updateCodecs(self):
containerWidget = self.window.comboBox_videoContainer containerWidget = self.window.comboBox_videoContainer
@ -344,9 +352,6 @@ class MainWindow(QtCore.QObject):
self.showMessage( self.showMessage(
msg="You must select an audio file and output filename.") msg="You must select an audio file and output filename.")
def progressBarUpdated(self, value):
self.window.progressBar_createVideo.setValue(value)
def changeEncodingStatus(self, status): def changeEncodingStatus(self, status):
if status: if status:
self.window.pushButton_createVideo.setEnabled(False) self.window.pushButton_createVideo.setEnabled(False)
@ -385,6 +390,9 @@ class MainWindow(QtCore.QObject):
self.window.pushButton_presets.setEnabled(True) self.window.pushButton_presets.setEnabled(True)
self.window.listWidget_componentList.setEnabled(True) self.window.listWidget_componentList.setEnabled(True)
def progressBarUpdated(self, value):
self.window.progressBar_createVideo.setValue(value)
def progressBarSetText(self, value): def progressBarSetText(self, value):
self.window.progressBar_createVideo.setFormat(value) self.window.progressBar_createVideo.setFormat(value)
@ -420,6 +428,10 @@ class MainWindow(QtCore.QObject):
self.core.selectedComponents[index].__doc__) self.core.selectedComponents[index].__doc__)
componentList.setCurrentRow(index) componentList.setCurrentRow(index)
# connect to signal that adds an asterisk when modified
self.core.selectedComponents[index].modified.connect(
self.updateComponentTitle)
self.pages.insert(index, self.core.selectedComponents[index].widget(self)) self.pages.insert(index, self.core.selectedComponents[index].widget(self))
stackedWidget.insertWidget(index, self.pages[index]) stackedWidget.insertWidget(index, self.pages[index])
stackedWidget.setCurrentIndex(index) stackedWidget.setCurrentIndex(index)
@ -433,7 +445,7 @@ class MainWindow(QtCore.QObject):
index = componentList.row(selected) index = componentList.row(selected)
self.window.stackedWidget.removeWidget(self.pages[index]) self.window.stackedWidget.removeWidget(self.pages[index])
componentList.takeItem(index) componentList.takeItem(index)
self.core.selectedComponents.pop(index) self.core.removeComponent(index)
self.pages.pop(index) self.pages.pop(index)
self.changeComponentWidget() self.changeComponentWidget()
self.drawPreview() self.drawPreview()
@ -533,10 +545,6 @@ class MainWindow(QtCore.QObject):
# actually load the project using core method # actually load the project using core method
self.core.openProject(self, filepath) self.core.openProject(self, filepath)
for i in range(self.window.listWidget_componentList.count()):
# update listwidget titles to indicate loaded presets
self.updateComponentTitle(i)
def showMessage(self, **kwargs): def showMessage(self, **kwargs):
parent = kwargs['parent'] if 'parent' in kwargs else self.window parent = kwargs['parent'] if 'parent' in kwargs else self.window
msg = QtGui.QMessageBox(parent) msg = QtGui.QMessageBox(parent)

View File

@ -105,14 +105,14 @@ class PresetManager(QtGui.QDialog):
def openSavePresetDialog(self): def openSavePresetDialog(self):
'''Functions on mainwindow level from the context menu''' '''Functions on mainwindow level from the context menu'''
window = self.parent.window window = self.parent.window
self.selectedComponents = self.parent.core.selectedComponents selectedComponents = self.parent.core.selectedComponents
componentList = self.parent.window.listWidget_componentList componentList = self.parent.window.listWidget_componentList
if componentList.currentRow() == -1: if componentList.currentRow() == -1:
return return
while True: while True:
index = componentList.currentRow() index = componentList.currentRow()
currentPreset = self.selectedComponents[index].currentPreset currentPreset = selectedComponents[index].currentPreset
newName, OK = QtGui.QInputDialog.getText( newName, OK = QtGui.QInputDialog.getText(
self.parent.window, self.parent.window,
'Audio Visualizer', 'Audio Visualizer',
@ -127,30 +127,35 @@ class PresetManager(QtGui.QDialog):
if newName: if newName:
if index != -1: if index != -1:
saveValueStore = \ saveValueStore = \
self.selectedComponents[index].savePreset() selectedComponents[index].savePreset()
componentName = str(self.selectedComponents[index]).strip() componentName = str(selectedComponents[index]).strip()
vers = self.selectedComponents[index].version() vers = selectedComponents[index].version()
self.createNewPreset( self.createNewPreset(
componentName, vers, newName, saveValueStore) componentName, vers, newName,
self.selectedComponents[index].currentPreset = newName saveValueStore, window=self.parent.window)
self.findPresets() selectedComponents[index].currentPreset = newName
self.drawPresetList() #self.findPresets()
#self.drawPresetList()
self.parent.updateComponentTitle(index)
break break
def createNewPreset(self, compName, vers, filename, saveValueStore): def createNewPreset(
self, compName, vers, filename, saveValueStore, **kwargs):
path = os.path.join(self.presetDir, compName, str(vers), filename) path = os.path.join(self.presetDir, compName, str(vers), filename)
if self.presetExists(path): if self.presetExists(path, **kwargs):
return return
self.core.createPresetFile(compName, vers, filename, saveValueStore) self.core.createPresetFile(compName, vers, filename, saveValueStore)
def presetExists(self, path): def presetExists(self, path, **kwargs):
if os.path.exists(path): if os.path.exists(path):
window = self.window \
if 'window' not in kwargs else kwargs['window']
ch = self.parent.showMessage( ch = self.parent.showMessage(
msg="%s already exists! Overwrite it?" % msg="%s already exists! Overwrite it?" %
os.path.basename(path), os.path.basename(path),
showCancel=True, showCancel=True,
icon=QtGui.QMessageBox.Warning, icon=QtGui.QMessageBox.Warning,
parent=self.window) parent=window)
if not ch: if not ch:
# user clicked cancel # user clicked cancel
return True return True
@ -204,6 +209,7 @@ class PresetManager(QtGui.QDialog):
os.remove(filepath) os.remove(filepath)
def warnMessage(self, window=None): def warnMessage(self, window=None):
print(window)
self.parent.showMessage( self.parent.showMessage(
msg='Preset names must contain only letters, ' msg='Preset names must contain only letters, '
'numbers, and spaces.', 'numbers, and spaces.',