projects can be saved and loaded

This commit is contained in:
Brianna 2017-06-01 22:17:12 -04:00 committed by GitHub
commit 30f2ea12df
2 changed files with 146 additions and 51 deletions

View File

@ -61,21 +61,29 @@ class Component(__base__.Component):
self.xPosition = self.page.spinBox_xTextAlign.value() self.xPosition = self.page.spinBox_xTextAlign.value()
self.yPosition = self.page.spinBox_yTextAlign.value() self.yPosition = self.page.spinBox_yTextAlign.value()
self.textColor = self.RGBFromString(self.page.lineEdit_textColor.text()) self.textColor = self.RGBFromString(self.page.lineEdit_textColor.text())
self.parent.drawPreview()
def getXY(self):
'''Returns true x, y after considering alignment settings'''
fm = QtGui.QFontMetrics(self.titleFont) fm = QtGui.QFontMetrics(self.titleFont)
if self.alignment == 0: #Left if self.alignment == 0: #Left
self.xPosition = self.xPosition x = self.xPosition
if self.alignment == 1: #Middle if self.alignment == 1: #Middle
self.xPosition = self.xPosition - fm.width(self.title)/2 x = self.xPosition - fm.width(self.title)/2
if self.alignment == 2: #Right if self.alignment == 2: #Right
self.xPosition = self.xPosition - fm.width(self.title) x = self.xPosition - fm.width(self.title)
self.parent.drawPreview() return x, self.yPosition
def loadPreset(self, pr): def loadPreset(self, pr):
self.page.lineEdit_title.setText(pr['title']) self.page.lineEdit_title.setText(pr['title'])
font = QFont(); font.fromString(pr['titleFont'])
self.page.fontComboBox_titleFont.setCurrentFont(font)
self.page.spinBox_fontSize.setValue(pr['fontSize']) self.page.spinBox_fontSize.setValue(pr['fontSize'])
self.page.comboBox_textAlign.setCurrentIndex(pr['alignment'])
self.page.spinBox_xTextAlign.setValue(pr['xPosition']) self.page.spinBox_xTextAlign.setValue(pr['xPosition'])
self.page.spinBox_yTextAlign.setValue(pr['yPosition']) self.page.spinBox_yTextAlign.setValue(pr['yPosition'])
self.page.comboBox_textAlign.setCurrentIndex(pr['alignment'])
self.page.lineEdit_textColor.setText('%s,%s,%s' % pr['textColor']) self.page.lineEdit_textColor.setText('%s,%s,%s' % pr['textColor'])
btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*pr['textColor']).name() btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*pr['textColor']).name()
self.page.pushButton_textColor.setStyleSheet(btnStyle) self.page.pushButton_textColor.setStyleSheet(btnStyle)
@ -83,6 +91,7 @@ class Component(__base__.Component):
def savePreset(self): def savePreset(self):
return { return {
'title' : self.title, 'title' : self.title,
'titleFont' : self.titleFont.toString(),
'alignment' : self.alignment, 'alignment' : self.alignment,
'fontSize' : self.fontSize, 'fontSize' : self.fontSize,
'xPosition' : self.xPosition, 'xPosition' : self.xPosition,
@ -105,6 +114,7 @@ class Component(__base__.Component):
return self.addText(width, height) return self.addText(width, height)
def addText(self, width, height): def addText(self, width, height):
x, y = self.getXY()
im = Image.new("RGBA", (width, height),(0,0,0,0)) im = Image.new("RGBA", (width, height),(0,0,0,0))
image = ImageQt(im) image = ImageQt(im)
@ -112,7 +122,7 @@ class Component(__base__.Component):
self.titleFont.setPixelSize(self.fontSize) self.titleFont.setPixelSize(self.fontSize)
painter.setFont(self.titleFont) painter.setFont(self.titleFont)
painter.setPen(QColor(*self.textColor)) painter.setPen(QColor(*self.textColor))
painter.drawText(self.xPosition, self.yPosition, self.title) painter.drawText(x, y, self.title)
painter.end() painter.end()
buffer = QtCore.QBuffer() buffer = QtCore.QBuffer()

173
main.py
View File

@ -1,8 +1,6 @@
import sys, io, os import sys, io, os, shutil, atexit, string, signal
from os.path import expanduser from os.path import expanduser
import atexit
from queue import Queue from queue import Queue
import signal
from importlib import import_module from importlib import import_module
from PyQt4 import QtCore, QtGui, uic from PyQt4 import QtCore, QtGui, uic
from PyQt4.QtCore import QSettings, QModelIndex from PyQt4.QtCore import QSettings, QModelIndex
@ -121,27 +119,25 @@ class Main(QtCore.QObject):
# print('main thread id: {}'.format(QtCore.QThread.currentThreadId())) # print('main thread id: {}'.format(QtCore.QThread.currentThreadId()))
self.window = window self.window = window
self.core = core.Core() self.core = core.Core()
self.settings = QSettings('settings.ini', QSettings.IniFormat) self.currentProject = None
LoadDefaultSettings(self) self.pages = []
self.selectedComponents = []
# create data directory structure if needed # create data directory structure if needed
self.dataDir = QDesktopServices.storageLocation(QDesktopServices.DataLocation) self.dataDir = QDesktopServices.storageLocation(QDesktopServices.DataLocation)
if not os.path.exists(self.dataDir): if not os.path.exists(self.dataDir):
os.makedirs(self.dataDir) os.makedirs(self.dataDir)
for neededDirectory in ('projects', 'presets'): for neededDirectory in ('projects', 'project-settings', 'presets'):
if not os.path.exists(os.path.join(self.dataDir, neededDirectory)): if not os.path.exists(os.path.join(self.dataDir, neededDirectory)):
os.mkdir(os.path.join(self.dataDir, neededDirectory)) os.mkdir(os.path.join(self.dataDir, neededDirectory))
self.settings = QSettings(os.path.join(self.dataDir, 'settings.ini'), QSettings.IniFormat)
self.pages = [] LoadDefaultSettings(self)
self.previewQueue = Queue() self.previewQueue = Queue()
self.previewThread = QtCore.QThread(self) self.previewThread = QtCore.QThread(self)
self.previewWorker = preview_thread.Worker(self, self.previewQueue) self.previewWorker = preview_thread.Worker(self, self.previewQueue)
self.previewWorker.moveToThread(self.previewThread) self.previewWorker.moveToThread(self.previewThread)
self.previewWorker.imageCreated.connect(self.showPreviewImage) self.previewWorker.imageCreated.connect(self.showPreviewImage)
self.previewThread.start() self.previewThread.start()
self.timer = QtCore.QTimer(self) self.timer = QtCore.QTimer(self)
@ -155,12 +151,11 @@ class Main(QtCore.QObject):
window.progressBar_createVideo.setValue(0) window.progressBar_createVideo.setValue(0)
window.pushButton_createVideo.clicked.connect(self.createAudioVisualisation) window.pushButton_createVideo.clicked.connect(self.createAudioVisualisation)
window.setWindowTitle("Audio Visualizer") window.setWindowTitle("Audio Visualizer")
self.modules = self.findComponents() self.modules = self.findComponents()
for component in self.modules: for component in self.modules:
window.comboBox_componentSelection.addItem(component.Component.__doc__) window.comboBox_componentSelection.addItem(component.Component.__doc__)
window.listWidget_componentList.clicked.connect(lambda _: self.changeComponentWidget()) window.listWidget_componentList.clicked.connect(lambda _: self.changeComponentWidget())
self.selectedComponents = []
self.window.pushButton_addComponent.clicked.connect( \ self.window.pushButton_addComponent.clicked.connect( \
lambda _: self.addComponent(self.window.comboBox_componentSelection.currentIndex()) lambda _: self.addComponent(self.window.comboBox_componentSelection.currentIndex())
@ -180,6 +175,9 @@ class Main(QtCore.QObject):
self.window.pushButton_savePreset.clicked.connect(self.openSavePresetDialog) self.window.pushButton_savePreset.clicked.connect(self.openSavePresetDialog)
self.window.comboBox_openPreset.currentIndexChanged.connect(self.openPreset) self.window.comboBox_openPreset.currentIndexChanged.connect(self.openPreset)
self.window.pushButton_saveAs.clicked.connect(self.openSaveProjectDialog)
self.window.pushButton_saveProject.clicked.connect(self.saveCurrentProject)
self.window.pushButton_openProject.clicked.connect(self.openOpenProjectDialog)
self.drawPreview() self.drawPreview()
@ -189,16 +187,11 @@ class Main(QtCore.QObject):
self.timer.stop() self.timer.stop()
self.previewThread.quit() self.previewThread.quit()
self.previewThread.wait() self.previewThread.wait()
# TODO: replace remembered settings with presets/projects backupPath = os.path.join(self.dataDir, 'settings.ini~')
''' settingsPath = self.settings.fileName()
self.settings.setValue("titleFont", self.window.fontComboBox_titleFont.currentFont().toString()) if self.currentProject:
self.settings.setValue("alignment", str(self.window.comboBox_textAlign.currentIndex())) os.remove(settingsPath)
self.settings.setValue("fontSize", str(self.window.spinBox_fontSize.value())) os.rename(backupPath, settingsPath)
self.settings.setValue("xPosition", str(self.window.spinBox_xTextAlign.value()))
self.settings.setValue("yPosition", str(self.window.spinBox_yTextAlign.value()))
self.settings.setValue("visColor", self.window.lineEdit_visColor.text())
self.settings.setValue("textColor", self.window.lineEdit_textColor.text())
'''
def openInputFileDialog(self): def openInputFileDialog(self):
inputDir = self.settings.value("inputDir", expanduser("~")) inputDir = self.settings.value("inputDir", expanduser("~"))
@ -251,8 +244,7 @@ class Main(QtCore.QObject):
self.window.lineEdit_outputFile.text(), self.window.lineEdit_outputFile.text(),
self.selectedComponents) self.selectedComponents)
else: else:
# TODO: use QMessageBox or similar to alert user that fields are empty self.showMessage("You must select an audio file and output filename.")
pass
def progressBarUpdated(self, value): def progressBarUpdated(self, value):
self.window.progressBar_createVideo.setValue(value) self.window.progressBar_createVideo.setValue(value)
@ -335,6 +327,7 @@ class Main(QtCore.QObject):
self.window.stackedWidget.insertWidget(row - 1, page) self.window.stackedWidget.insertWidget(row - 1, page)
self.window.listWidget_componentList.setCurrentRow(row - 1) self.window.listWidget_componentList.setCurrentRow(row - 1)
self.window.stackedWidget.setCurrentIndex(row -1) self.window.stackedWidget.setCurrentIndex(row -1)
self.drawPreview()
def moveComponentDown(self): def moveComponentDown(self):
row = self.window.listWidget_componentList.currentRow() row = self.window.listWidget_componentList.currentRow()
@ -351,6 +344,7 @@ class Main(QtCore.QObject):
self.window.stackedWidget.insertWidget(row + 1, page) self.window.stackedWidget.insertWidget(row + 1, page)
self.window.listWidget_componentList.setCurrentRow(row + 1) self.window.listWidget_componentList.setCurrentRow(row + 1)
self.window.stackedWidget.setCurrentIndex(row + 1) self.window.stackedWidget.setCurrentIndex(row + 1)
self.drawPreview()
def updateOpenPresetComboBox(self, component): def updateOpenPresetComboBox(self, component):
self.window.comboBox_openPreset.clear() self.window.comboBox_openPreset.clear()
@ -360,19 +354,29 @@ class Main(QtCore.QObject):
if not os.path.exists(destination): if not os.path.exists(destination):
os.makedirs(destination) os.makedirs(destination)
for f in os.listdir(destination): for f in os.listdir(destination):
self.window.comboBox_openPreset.addItem(f) self.window.comboBox_openPreset.addItem(f)
def openSavePresetDialog(self): def openSavePresetDialog(self):
if self.window.listWidget_componentList.currentRow() == -1: if self.window.listWidget_componentList.currentRow() == -1:
return return
newName, OK = QtGui.QInputDialog.getText(QtGui.QWidget(), 'Audio Visualizer', 'New Preset Name:') while True:
if OK and newName: newName, OK = QtGui.QInputDialog.getText(QtGui.QWidget(), 'Audio Visualizer', 'New Preset Name:')
index = self.window.listWidget_componentList.currentRow() badName = False
if index != -1: for letter in newName:
saveValueStore = self.selectedComponents[index].savePreset() if letter in string.punctuation:
componentName = str(self.selectedComponents[index]).strip() badName = True
vers = self.selectedComponents[index].version() if badName:
self.createPresetFile(componentName, vers, saveValueStore, newName) # some filesystems don't like bizarre characters
self.showMessage("Preset names must contain only letters, numbers, and spaces.")
continue
if OK and newName:
index = self.window.listWidget_componentList.currentRow()
if index != -1:
saveValueStore = self.selectedComponents[index].savePreset()
componentName = str(self.selectedComponents[index]).strip()
vers = self.selectedComponents[index].version()
self.createPresetFile(componentName, vers, saveValueStore, newName)
break
def createPresetFile(self, componentName, version, saveValueStore, filename): def createPresetFile(self, componentName, version, saveValueStore, filename):
dirname = os.path.join(self.dataDir, 'presets', componentName, str(version)) dirname = os.path.join(self.dataDir, 'presets', componentName, str(version))
@ -380,27 +384,23 @@ class Main(QtCore.QObject):
os.makedirs(dirname) os.makedirs(dirname)
filepath = os.path.join(dirname, filename) filepath = os.path.join(dirname, filename)
if os.path.exists(filepath): if os.path.exists(filepath):
msg = QtGui.QMessageBox() ch = self.showMessage("%s already exists! Overwrite it?" % filename, QtGui.QMessageBox.Warning, True)
msg.setIcon(QtGui.QMessageBox.Warning) if not ch:
msg.setText("%s already exists! Overwrite it?" % filename)
msg.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
ch = msg.exec_()
if ch != 1024: # 1024 = OK
return return
# remove old copies of the preset # remove old copies of the preset
for i in range(0, self.windowcomboBox_openPreset.count()): for i in range(0, self.window.comboBox_openPreset.count()):
if self.window.comboBox_openPreset.itemText(i) == filename: if self.window.comboBox_openPreset.itemText(i) == filename:
self.window.comboBox_openPreset.removeItem(i) self.window.comboBox_openPreset.removeItem(i)
with open(filepath, 'w') as f: with open(filepath, 'w') as f:
f.write('%s' % repr(saveValueStore)) f.write(repr(saveValueStore))
self.window.comboBox_openPreset.addItem(filename) self.window.comboBox_openPreset.addItem(filename)
self.window.comboBox_openPreset.setCurrentIndex(self.window.comboBox_openPreset.count()-1)
def openPreset(self): def openPreset(self):
if self.window.comboBox_openPreset.currentIndex() < 1: if self.window.comboBox_openPreset.currentIndex() < 1:
return return
index = self.window.listWidget_componentList.currentRow() index = self.window.listWidget_componentList.currentRow()
if index == -1: if index == -1:
# no component selected
return return
filename = self.window.comboBox_openPreset.itemText(self.window.comboBox_openPreset.currentIndex()) filename = self.window.comboBox_openPreset.itemText(self.window.comboBox_openPreset.currentIndex())
componentName = str(self.selectedComponents[index]).strip() componentName = str(self.selectedComponents[index]).strip()
@ -417,6 +417,92 @@ class Main(QtCore.QObject):
self.selectedComponents[index].loadPreset(saveValueStore) self.selectedComponents[index].loadPreset(saveValueStore)
self.drawPreview() self.drawPreview()
def saveCurrentProject(self):
if self.currentProject:
self.createProjectFile(self.currentProject)
else:
self.openSaveProjectDialog()
def openSaveProjectDialog(self):
outputDir = os.path.join(self.dataDir, 'projects')
filename = QtGui.QFileDialog.getSaveFileName(self.window, "Create Project File", outputDir)
if not filename:
return
filepath = os.path.join(outputDir, filename)
self.currentProject = filepath
self.createProjectFile(filepath)
def createProjectFile(self, filepath):
with open(filepath, 'w') as f:
for comp in self.selectedComponents:
saveValueStore = comp.savePreset()
f.write('%s\n' % str(comp))
f.write('%s\n' % str(comp.version()))
f.write('%s\n' % repr(saveValueStore))
projSettingsPath = os.path.join(self.dataDir, 'project-settings', os.path.basename('%s.ini' % filepath))
shutil.copyfile(self.settings.fileName(), projSettingsPath)
def openOpenProjectDialog(self):
inputDir = os.path.join(self.dataDir, 'projects')
filename = QtGui.QFileDialog.getOpenFileName(self.window, "Open Project File", inputDir)
if not filename:
return
filepath = os.path.join(inputDir, filename)
self.openProject(filepath)
def openProject(self, filepath):
self.clear()
self.currentProject = filepath
compNames = [mod.Component.__doc__ for mod in self.modules]
with open(filepath, 'r') as f:
i = 0
for line in f:
if i == 0:
compIndex = compNames.index(line.strip())
self.addComponent(compIndex)
i += 1
elif i == 1:
# version, not used yet
i += 1
elif i == 2:
saveValueStore = eval(line.strip())
self.selectedComponents[-1].loadPreset(saveValueStore)
i = 0
projSettingsPath = os.path.join(self.dataDir, 'project-settings', '%s.ini' % os.path.basename(filepath))
backupPath = os.path.join(self.dataDir, 'settings.ini~')
settingsPath = self.settings.fileName()
if os.path.exists(backupPath):
os.remove(backupPath)
os.rename(settingsPath, backupPath)
shutil.copyfile(projSettingsPath, settingsPath)
self.settings.sync()
currentRes = str(self.settings.value('outputWidth'))+'x'+str(self.settings.value('outputHeight'))
for i in range(self.window.comboBox_resolution.count()-1):
if self.window.comboBox_resolution.itemText(i) == currentRes:
self.window.comboBox_resolution.setCurrentIndex(i)
break
def showMessage(self, string, icon=QtGui.QMessageBox.Information, showCancel=False):
msg = QtGui.QMessageBox()
msg.setIcon(icon)
msg.setText(string)
if showCancel:
msg.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
else:
msg.setStandardButtons(QtGui.QMessageBox.Ok)
ch = msg.exec_()
if ch == 1024:
return True
return False
def clear(self):
''' empty out all components and fields, get a blank slate '''
self.selectedComponents = []
self.window.listWidget_componentList.clear()
for widget in self.pages:
self.window.stackedWidget.removeWidget(widget)
self.pages = []
def LoadDefaultSettings(self): def LoadDefaultSettings(self):
self.resolutions = [ self.resolutions = [
'1920x1080', '1920x1080',
@ -434,7 +520,6 @@ def LoadDefaultSettings(self):
"outputVideoFormat": "yuv420p", "outputVideoFormat": "yuv420p",
"outputPreset": "medium", "outputPreset": "medium",
"outputFormat": "mp4", "outputFormat": "mp4",
"visLayout": 0
} }
for parm, value in default.items(): for parm, value in default.items():