From 292d21c20372634f4d0cabf43611d0e50386bc4c Mon Sep 17 00:00:00 2001 From: tassaron Date: Wed, 7 Jun 2017 23:22:55 -0400 Subject: added submenu for opening presets, moved code --- components/image.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'components/image.py') diff --git a/components/image.py b/components/image.py index f9a92ca..6ccddb6 100644 --- a/components/image.py +++ b/components/image.py @@ -48,7 +48,8 @@ class Component(__base__.Component): frame.paste(image) return frame - def loadPreset(self, pr): + def loadPreset(self, pr, presetName=None): + self.currentPreset = presetName self.page.lineEdit_image.setText(pr['image']) def savePreset(self): @@ -60,7 +61,7 @@ class Component(__base__.Component): imgDir = self.settings.value("backgroundDir", os.path.expanduser("~")) filename = QtGui.QFileDialog.getOpenFileName( self.page, "Choose Image", imgDir, "Image Files (*.jpg *.png)") - if filename: + if filename: self.settings.setValue("backgroundDir", os.path.dirname(filename)) self.page.lineEdit_image.setText(filename) self.update() -- cgit v1.2.3 From bb1e54b31eb6157ef041764cfccd60484a0e02d8 Mon Sep 17 00:00:00 2001 From: tassaron Date: Thu, 8 Jun 2017 16:50:48 -0400 Subject: saved preset titles, code clean-ups componentList drag'n'drop disabled for now; will work on it in another branch --- components/color.py | 3 +- components/image.py | 3 +- components/original.py | 3 +- components/text.py | 3 +- components/video.py | 3 +- core.py | 58 +++++++++++++----- mainwindow.py | 159 +++++++++++++++++++++++++++++-------------------- mainwindow.ui | 2 +- presetmanager.py | 42 +++++++------ 9 files changed, 169 insertions(+), 107 deletions(-) (limited to 'components/image.py') diff --git a/components/color.py b/components/color.py index b13f54e..a86927b 100644 --- a/components/color.py +++ b/components/color.py @@ -70,7 +70,7 @@ class Component(__base__.Component): return Image.new("RGBA", (width, height), (r, g, b, 255)) def loadPreset(self, pr, presetName=None): - self.currentPreset = presetName + self.currentPreset = presetName if presetName else pr['preset'] self.page.lineEdit_color1.setText('%s,%s,%s' % pr['color1']) self.page.lineEdit_color2.setText('%s,%s,%s' % pr['color2']) @@ -85,6 +85,7 @@ class Component(__base__.Component): def savePreset(self): return { + 'preset': self.currentPreset, 'color1': self.color1, 'color2': self.color2, } diff --git a/components/image.py b/components/image.py index 6ccddb6..441e0e1 100644 --- a/components/image.py +++ b/components/image.py @@ -49,11 +49,12 @@ class Component(__base__.Component): return frame def loadPreset(self, pr, presetName=None): - self.currentPreset = presetName + self.currentPreset = presetName if presetName else pr['preset'] self.page.lineEdit_image.setText(pr['image']) def savePreset(self): return { + 'preset': self.currentPreset, 'image': self.imagePath, } diff --git a/components/original.py b/components/original.py index a2059d1..7873f43 100644 --- a/components/original.py +++ b/components/original.py @@ -38,7 +38,7 @@ class Component(__base__.Component): self.parent.drawPreview() def loadPreset(self, pr, presetName=None): - self.currentPreset = presetName + self.currentPreset = presetName if presetName else pr['preset'] self.page.lineEdit_visColor.setText('%s,%s,%s' % pr['visColor']) btnStyle = "QPushButton { background-color : %s; outline: none; }" \ % QColor(*pr['visColor']).name() @@ -47,6 +47,7 @@ class Component(__base__.Component): def savePreset(self): return { + 'preset': self.currentPreset, 'layout': self.layout, 'visColor': self.visColor, } diff --git a/components/text.py b/components/text.py index 1725a41..68cffca 100644 --- a/components/text.py +++ b/components/text.py @@ -79,7 +79,7 @@ class Component(__base__.Component): return x, self.yPosition def loadPreset(self, pr, presetName=None): - self.currentPreset = presetName + self.currentPreset = presetName if presetName else pr['preset'] self.page.lineEdit_title.setText(pr['title']) font = QFont() font.fromString(pr['titleFont']) @@ -95,6 +95,7 @@ class Component(__base__.Component): def savePreset(self): return { + 'preset': self.currentPreset, 'title': self.title, 'titleFont': self.titleFont.toString(), 'alignment': self.alignment, diff --git a/components/video.py b/components/video.py index e636224..c529658 100644 --- a/components/video.py +++ b/components/video.py @@ -129,12 +129,13 @@ class Component(__base__.Component): return self.video.frame(frameNo) def loadPreset(self, pr, presetName=None): - self.currentPreset = presetName + self.currentPreset = presetName if presetName else pr['preset'] self.page.lineEdit_video.setText(pr['video']) self.page.checkBox_loop.setChecked(pr['loop']) def savePreset(self): return { + 'preset': self.currentPreset, 'video': self.videoPath, 'loop': self.loopVideo, } diff --git a/core.py b/core.py index 0fa5ec5..797749d 100644 --- a/core.py +++ b/core.py @@ -6,29 +6,34 @@ from os.path import expanduser import subprocess as sp import numpy from PIL import Image -import tempfile +#import tempfile from shutil import rmtree -import atexit +#import atexit import time from collections import OrderedDict import json from importlib import import_module +from PyQt4.QtGui import QDesktopServices class Core(): def __init__(self): self.FFMPEG_BIN = self.findFfmpeg() - self.tempDir = os.path.join( - tempfile.gettempdir(), 'audio-visualizer-python-data') - if not os.path.exists(self.tempDir): - os.makedirs(self.tempDir) - atexit.register(self.deleteTempDir) + #self.tempDir = os.path.join( + # tempfile.gettempdir(), 'audio-visualizer-python-data') + #if not os.path.exists(self.tempDir): + # os.makedirs(self.tempDir) + #atexit.register(self.deleteTempDir) + self.dataDir = QDesktopServices.storageLocation( + QDesktopServices.DataLocation) + self.presetDir = os.path.join(self.dataDir, 'presets') self.wd = os.path.dirname(os.path.realpath(__file__)) self.loadEncoderOptions() self.modules = self.findComponents() self.selectedComponents = [] + self.selectedModules = [] def findComponents(self): def findComponents(): @@ -45,19 +50,40 @@ class Core(): for name in findComponents()] def insertComponent(self, compPos, moduleIndex): + if compPos < 0: + compPos = len(self.selectedComponents) -1 self.selectedComponents.insert( compPos, - self.modules[moduleIndex].Component()) - return compPos #if compPos > -1 else len(self.selectedComponents)-1 + self.modules[moduleIndex].Component() + ) + self.selectedModules.insert( + compPos, + moduleIndex + ) + return compPos def moveComponent(self, startI, endI): comp = self.selectedComponents.pop(startI) - i = self.selectedComponents.insert(endI, comp) - return i + self.selectedComponents.insert(endI, comp) + i = self.selectedModules.pop(startI) + self.selectedModules.insert(endI, i) + return endI def updateComponent(self, i): + print('updating %s' % self.selectedComponents[i]) self.selectedComponents[i].update() + def moduleIndexFor(self, compIndex): + return self.selectedModules[compIndex] + + def createPresetFile(self, compName, vers, saveValueStore, filename): + dirname = os.path.join(self.presetDir, compName, str(vers)) + if not os.path.exists(dirname): + os.makedirs(dirname) + filepath = os.path.join(dirname, filename) + with open(filepath, 'w') as f: + f.write(Core.stringOrderedDict(saveValueStore)) + def loadEncoderOptions(self): file_path = os.path.join(self.wd, 'encoder-options.json') with open(file_path) as json_file: @@ -139,11 +165,11 @@ class Core(): return completeAudioArray - def deleteTempDir(self): - try: - rmtree(self.tempDir) - except FileNotFoundError: - pass + #def deleteTempDir(self): + # try: + # rmtree(self.tempDir) + # except FileNotFoundError: + # pass def cancel(self): self.canceled = True diff --git a/mainwindow.py b/mainwindow.py index f24fc66..8812e7f 100644 --- a/mainwindow.py +++ b/mainwindow.py @@ -3,7 +3,7 @@ from queue import Queue from collections import OrderedDict from PyQt4 import QtCore, QtGui, uic from PyQt4.QtCore import QSettings, Qt -from PyQt4.QtGui import QDesktopServices, QMenu +from PyQt4.QtGui import QMenu import sys import os import signal @@ -55,12 +55,11 @@ class MainWindow(QtCore.QObject): self.core = core.Core() self.pages = [] # widgets of component settings - self.componentRows = {} # QListWidgetItems + self.componentRows = [] # (moduleIndex, QListWidgetItem) tuples self.lastAutosave = time.time() # Create data directory, load/create settings - self.dataDir = QDesktopServices.storageLocation( - QDesktopServices.DataLocation) + self.dataDir = self.core.dataDir self.presetManager = PresetManager( uic.loadUi( os.path.join(os.path.dirname(os.path.realpath(__file__)), @@ -73,7 +72,7 @@ class MainWindow(QtCore.QObject): if not os.path.exists(self.dataDir): os.makedirs(self.dataDir) for neededDirectory in ( - self.presetManager.presetDir, self.settings.value("projectDir")): + self.core.presetDir, self.settings.value("projectDir")): if not os.path.exists(neededDirectory): os.mkdir(neededDirectory) @@ -90,6 +89,8 @@ class MainWindow(QtCore.QObject): self.timer.start(500) # Begin decorating the window and connecting events + componentList = self.window.listWidget_componentList + window.toolButton_selectAudioFile.clicked.connect( self.openInputFileDialog) @@ -120,7 +121,7 @@ class MainWindow(QtCore.QObject): codec = window.comboBox_videoCodec.itemText(i) if codec == self.settings.value('outputVideoCodec'): window.comboBox_videoCodec.setCurrentIndex(i) - print(codec) + #print(codec) for i in range(window.comboBox_audioCodec.count()): codec = window.comboBox_audioCodec.itemText(i) @@ -157,17 +158,17 @@ class MainWindow(QtCore.QObject): self.window.pushButton_addComponent.setMenu(self.compMenu) - self.window.listWidget_componentList.dropEvent = self.componentMoved - self.window.listWidget_componentList.clicked.connect( + componentList.dropEvent = self.componentListChanged + componentList.clicked.connect( lambda _: self.changeComponentWidget()) self.window.pushButton_removeComponent.clicked.connect( lambda _: self.removeComponent()) - self.window.listWidget_componentList.setContextMenuPolicy( + componentList.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) - self.window.listWidget_componentList.connect( - self.window.listWidget_componentList, + componentList.connect( + componentList, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.componentContextMenu) @@ -182,9 +183,11 @@ class MainWindow(QtCore.QObject): self.updateResolution) self.window.pushButton_listMoveUp.clicked.connect( - self.moveComponentUp) - #self.window.pushButton_listMoveDown.clicked.connect( - # self.moveComponentDown) + lambda: self.moveComponent(-1) + ) + self.window.pushButton_listMoveDown.clicked.connect( + lambda: self.moveComponent(1) + ) # Configure the Projects Menu self.projectMenu = QMenu() @@ -210,8 +213,7 @@ class MainWindow(QtCore.QObject): # Show the window and load current project window.show() self.currentProject = self.settings.value("currentProject") - if self.currentProject and os.path.exists(self.autosavePath) \ - and filecmp.cmp(self.autosavePath, self.currentProject): + if self.autosaveExists(): # delete autosave if it's identical to the project os.remove(self.autosavePath) @@ -235,6 +237,14 @@ class MainWindow(QtCore.QObject): self.previewThread.wait() self.autosave() + def updateComponentTitle(self, pos): + if pos < 0: + pos = len(self.core.selectedComponents)-1 + title = str(self.core.selectedComponents[pos]) + if self.core.selectedComponents[pos].currentPreset: + title += ' - %s' % self.core.selectedComponents[pos].currentPreset + self.window.listWidget_componentList.item(pos).setText(title) + def updateCodecs(self): containerWidget = self.window.comboBox_videoContainer vCodecWidget = self.window.comboBox_videoCodec @@ -270,12 +280,20 @@ class MainWindow(QtCore.QObject): self.settings.setValue('outputAudioBitrate', currentAudioBitrate) def autosave(self): - if time.time() - self.lastAutosave >= 2.0: + if not self.currentProject: if os.path.exists(self.autosavePath): os.remove(self.autosavePath) + elif time.time() - self.lastAutosave >= 2.0: self.createProjectFile(self.autosavePath) self.lastAutosave = time.time() + def autosaveExists(self): + if self.currentProject and os.path.exists(self.autosavePath) \ + and filecmp.cmp(self.autosavePath, self.currentProject): + return True + else: + return False + def openInputFileDialog(self): inputDir = self.settings.value("inputDir", expanduser("~")) @@ -393,88 +411,94 @@ class MainWindow(QtCore.QObject): def insertComponent(self, moduleIndex, compPos=0): componentList = self.window.listWidget_componentList + stackedWidget = self.window.stackedWidget + if compPos < 0: + compPos = componentList.count() index = self.core.insertComponent( compPos, moduleIndex) row = componentList.insertItem( index, self.core.selectedComponents[index].__doc__) - self.componentRows[index] = componentList.row(row) + self.componentRows.insert(compPos, (moduleIndex, row)) componentList.setCurrentRow(index) self.pages.insert(index, self.core.selectedComponents[index].widget(self)) - self.window.stackedWidget.insertWidget(index, self.pages[index]) - self.window.stackedWidget.setCurrentIndex(index) + stackedWidget.insertWidget(index, self.pages[index]) + stackedWidget.setCurrentIndex(index) + self.core.updateComponent(index) def removeComponent(self): - for selected in self.window.listWidget_componentList.selectedItems(): - index = self.window.listWidget_componentList.row(selected) + componentList = self.window.listWidget_componentList + + for selected in componentList.selectedItems(): + index = componentList.row(selected) self.window.stackedWidget.removeWidget(self.pages[index]) - self.window.listWidget_componentList.takeItem(index) + componentList.takeItem(index) + self.componentRows.pop(index) self.core.selectedComponents.pop(index) self.pages.pop(index) self.changeComponentWidget() self.drawPreview() - def changeComponentWidget(self): - selected = self.window.listWidget_componentList.selectedItems() - if selected: - index = self.window.listWidget_componentList.row(selected[0]) - self.window.stackedWidget.setCurrentIndex(index) + def moveComponent(self, change): + '''Moves a component relatively from its current position''' + componentList = self.window.listWidget_componentList + stackedWidget = self.window.stackedWidget - def moveComponentUp(self): - row = self.window.listWidget_componentList.currentRow() - if row > 0: - self.core.moveComponent(row, row - 1) - page = self.pages.pop(row) - self.pages.insert(row - 1, page) + row = componentList.currentRow() + newRow = row + change + if newRow > -1 and newRow < componentList.count(): + self.core.moveComponent(row, newRow) # update widgets - componentList = self.window.listWidget_componentList - stackedWidget = self.window.stackedWidget + page = self.pages.pop(row) + self.pages.insert(newRow, page) item = componentList.takeItem(row) - componentList.insertItem(row - 1, item) + newItem = componentList.insertItem(newRow, item) widget = stackedWidget.removeWidget(page) - stackedWidget.insertWidget(row - 1, page) - componentList.setCurrentRow(row - 1) - stackedWidget.setCurrentIndex(row - 1) - self.drawPreview() - ''' - def moveComponentDown(self): - row = self.window.listWidget_componentList.currentRow() - if row != -1 and row < len(self.pages)+1: - module = self.selectedComponents[row] - self.selectedComponents.pop(row) - self.selectedComponents.insert(row + 1, module) - page = self.pages[row] - self.pages.pop(row) - self.pages.insert(row + 1, page) - item = self.window.listWidget_componentList.takeItem(row) - self.window.listWidget_componentList.insertItem(row + 1, item) - widget = self.window.stackedWidget.removeWidget(page) - self.window.stackedWidget.insertWidget(row + 1, page) - self.window.listWidget_componentList.setCurrentRow(row + 1) - self.window.stackedWidget.setCurrentIndex(row + 1) + stackedWidget.insertWidget(newRow, page) + componentList.setCurrentRow(newRow) + stackedWidget.setCurrentIndex(newRow) + self.componentRows.pop(row) + self.componentRows.insert(newRow, (self.core.moduleIndexFor(row), newItem)) self.drawPreview() - ''' - def componentMoved(self, event): - widget = self.window.listWidget_componentList - for i in range(widget.count()): - pass - #print(widget.item(i) == self.componentRows[i]) + + def componentListChanged(self, *args): + '''Update all our tracking variables to match the widget''' + pass + + def changeComponentWidget(self): + selected = self.window.listWidget_componentList.selectedItems() + if selected: + index = self.window.listWidget_componentList.row(selected[0]) + self.window.stackedWidget.setCurrentIndex(index) def openPresetManager(self): '''Preset manager for importing, exporting, renaming, deleting''' self.presetManager.show() - def createNewProject(self): - self.currentProject = None + def clear(self): + '''Get a blank slate''' self.core.selectedComponents = [] self.window.listWidget_componentList.clear() for widget in self.pages: self.window.stackedWidget.removeWidget(widget) self.pages = [] + + def createNewProject(self): + if self.autosaveExists(): + ch = self.showMessage( + msg="You have unsaved changes in project '%s'. " + "Save before starting a new project?" + % os.path.basename(self.currentProject)[:-4], + showCancel=True) + if ch: + self.saveCurrentProject() + + self.clear() + self.currentProject = None self.settings.setValue("currentProject", None) self.drawPreview() @@ -496,6 +520,8 @@ class MainWindow(QtCore.QObject): def createProjectFile(self, filepath): if not filepath.endswith(".avp"): filepath += '.avp' + if os.path.exists(filepath): + os.remove(filepath) with open(filepath, 'w') as f: print('creating %s' % filepath) f.write('[Components]\n') @@ -520,7 +546,7 @@ class MainWindow(QtCore.QObject): if not filepath or not os.path.exists(filepath) \ or not filepath.endswith('.avp'): return - self.createNewProject() + self.clear() self.currentProject = filepath self.settings.setValue("currentProject", filepath) self.settings.setValue("projectDir", os.path.dirname(filepath)) @@ -558,6 +584,7 @@ class MainWindow(QtCore.QObject): saveValueStore = dict(eval(line)) self.core.selectedComponents[-1].loadPreset( saveValueStore) + self.updateComponentTitle(-1) i = 0 except (IndexError, ValueError, NameError, SyntaxError, AttributeError, TypeError) as e: diff --git a/mainwindow.ui b/mainwindow.ui index e809ee8..af47cee 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -188,7 +188,7 @@ true - true + false false diff --git a/presetmanager.py b/presetmanager.py index 50efd8d..268754e 100644 --- a/presetmanager.py +++ b/presetmanager.py @@ -10,7 +10,8 @@ class PresetManager(QtGui.QDialog): def __init__(self, window, parent): super().__init__() self.parent = parent - self.presetDir = os.path.join(self.parent.dataDir, 'presets') + self.core = self.parent.core + self.presetDir = self.core.presetDir self.window = window self.findPresets() self.lastFilter = '*' @@ -83,11 +84,14 @@ class PresetManager(QtGui.QDialog): def openSavePresetDialog(self): window = self.parent.window - if window.listWidget_componentList.currentRow() == -1: + self.selectedComponents = self.parent.core.selectedComponents + componentList = window.listWidget_componentList + + if componentList.currentRow() == -1: return while True: - index = window.listWidget_componentList.currentRow() - currentPreset = self.parent.selectedComponents[index].currentPreset + index = componentList.currentRow() + currentPreset = self.selectedComponents[index].currentPreset newName, OK = QtGui.QInputDialog.getText( self.parent.window, 'Audio Visualizer', @@ -109,35 +113,34 @@ class PresetManager(QtGui.QDialog): if newName: if index != -1: saveValueStore = \ - self.parent.selectedComponents[index].savePreset() - componentName = str(self.parent.selectedComponents[index]).strip() - vers = self.parent.selectedComponents[index].version() + self.selectedComponents[index].savePreset() + componentName = str(self.selectedComponents[index]).strip() + vers = self.selectedComponents[index].version() self.createPresetFile( componentName, vers, saveValueStore, newName) - self.parent.selectedComponents[index].currentPreset = newName + self.selectedComponents[index].currentPreset = newName break def createPresetFile(self, compName, vers, saveValueStore, filename): - dirname = os.path.join(self.presetDir, compName, str(vers)) - if not os.path.exists(dirname): - os.makedirs(dirname) - filepath = os.path.join(dirname, filename) - if os.path.exists(filepath): + path = os.path.join(self.presetDir, compName, str(vers), filename) + if os.path.exists(path): ch = self.parent.showMessage( msg="%s already exists! Overwrite it?" % filename, showCancel=True, icon=QtGui.QMessageBox.Warning) if not ch: return - with open(filepath, 'w') as f: - f.write(core.Core.stringOrderedDict(saveValueStore)) + self.core.createPresetFile(compName, vers, saveValueStore, filename) self.drawPresetList() def openPreset(self, presetName): - index = self.parent.window.listWidget_componentList.currentRow() + componentList = self.parent.window.listWidget_componentList + selectedComponents = self.parent.core.selectedComponents + + index = componentList.currentRow() if index == -1: return - componentName = str(self.parent.selectedComponents[index]).strip() - version = self.parent.selectedComponents[index].version() + componentName = str(selectedComponents[index]).strip() + version = selectedComponents[index].version() dirname = os.path.join(self.presetDir, componentName, str(version)) filepath = os.path.join(dirname, presetName) if not os.path.exists(filepath): @@ -146,9 +149,10 @@ class PresetManager(QtGui.QDialog): for line in f: saveValueStore = dict(eval(line.strip())) break - self.parent.selectedComponents[index].loadPreset( + selectedComponents[index].loadPreset( saveValueStore, presetName ) + self.parent.updateComponentTitle(index) self.parent.drawPreview() -- cgit v1.2.3 From 307d499f9ae2729c790fe9258d88aca72331cdf6 Mon Sep 17 00:00:00 2001 From: tassaron Date: Mon, 12 Jun 2017 22:34:37 -0400 Subject: adding an asterisk to modified, unsaved presets flags for unsaved changes saved in project files --- components/__base__.py | 38 +++++++++++++++------- components/color.py | 7 +++- components/image.py | 6 +++- components/original.py | 10 ++++-- components/text.py | 11 +++++-- components/video.py | 6 +++- core.py | 87 +++++++++++++++++++++++++++++++++++++++++++++++--- mainwindow.py | 26 +++++++++------ presetmanager.py | 32 +++++++++++-------- 9 files changed, 175 insertions(+), 48 deletions(-) (limited to 'components/image.py') diff --git a/components/__base__.py b/components/__base__.py index 3ccb5dc..b32c120 100644 --- a/components/__base__.py +++ b/components/__base__.py @@ -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: - def __init__(self): + # modified = QtCore.pyqtSignal(int, bool) + + def __init__(self, moduleIndex, compPos): + super().__init__() self.currentPreset = None + self.moduleIndex = moduleIndex + self.compPos = compPos def __str__(self): return self.__doc__ @@ -13,12 +19,27 @@ class Component: return 1 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 def reset(self): 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): for var, value in kwargs.items(): exec('self.%s = value' % var) @@ -62,7 +83,7 @@ class Component: return page def update(self): - # read widget values + super().update() self.parent.drawPreview() def previewRender(self, previewWorker): @@ -77,13 +98,6 @@ class Component: image = Image.new("RGBA", (width, height), (0,0,0,0)) return image - def loadPreset(self, presetDict, presetName=None): - self.currentPreset = presetName - # update widgets using a preset dict - - def savePreset(self): - return {} - def cancel(self): self.canceled = True diff --git a/components/color.py b/components/color.py index 11c1b19..b6105c8 100644 --- a/components/color.py +++ b/components/color.py @@ -7,6 +7,9 @@ from . import __base__ class Component(__base__.Component): '''Color''' + + modified = QtCore.pyqtSignal(int, bool) + def widget(self, parent): self.parent = parent page = uic.loadUi(os.path.join( @@ -45,6 +48,7 @@ class Component(__base__.Component): return page def update(self): + super().update() self.color1 = self.RGBFromString(self.page.lineEdit_color1.text()) self.color2 = self.RGBFromString(self.page.lineEdit_color2.text()) 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)) 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_color2.setText('%s,%s,%s' % pr['color2']) diff --git a/components/image.py b/components/image.py index 441e0e1..ed5f243 100644 --- a/components/image.py +++ b/components/image.py @@ -6,6 +6,9 @@ from . import __base__ class Component(__base__.Component): '''Image''' + + modified = QtCore.pyqtSignal(int, bool) + def widget(self, parent): self.parent = parent self.settings = parent.settings @@ -22,6 +25,7 @@ class Component(__base__.Component): return page def update(self): + super().update() self.imagePath = self.page.lineEdit_image.text() self.parent.drawPreview() @@ -49,7 +53,7 @@ class Component(__base__.Component): return frame 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']) def savePreset(self): diff --git a/components/original.py b/components/original.py index 7873f43..f3f578d 100644 --- a/components/original.py +++ b/components/original.py @@ -1,9 +1,8 @@ import numpy from PIL import Image, ImageDraw -from PyQt4 import uic, QtGui +from PyQt4 import uic, QtGui, QtCore from PyQt4.QtGui import QColor import os -import random from . import __base__ import time from copy import copy @@ -11,6 +10,9 @@ from copy import copy class Component(__base__.Component): '''Original Audio Visualization''' + + modified = QtCore.pyqtSignal(int, bool) + def widget(self, parent): self.parent = parent self.visColor = (255, 255, 255) @@ -33,12 +35,14 @@ class Component(__base__.Component): return page def update(self): + super().update() self.layout = self.page.comboBox_visLayout.currentIndex() self.visColor = self.RGBFromString(self.page.lineEdit_visColor.text()) self.parent.drawPreview() 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']) btnStyle = "QPushButton { background-color : %s; outline: none; }" \ % QColor(*pr['visColor']).name() diff --git a/components/text.py b/components/text.py index e8fb3d5..a40e2a9 100644 --- a/components/text.py +++ b/components/text.py @@ -9,8 +9,11 @@ from . import __base__ class Component(__base__.Component): '''Title Text''' - def __init__(self): - super().__init__() + + modified = QtCore.pyqtSignal(int, bool) + + def __init__(self, *args): + super().__init__(*args) self.titleFont = QFont() def widget(self, parent): @@ -53,6 +56,7 @@ class Component(__base__.Component): return page def update(self): + super().update() self.title = self.page.lineEdit_title.text() self.alignment = self.page.comboBox_textAlign.currentIndex() self.titleFont = self.page.fontComboBox_titleFont.currentFont() @@ -79,7 +83,8 @@ class Component(__base__.Component): return x, self.yPosition 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']) font = QFont() font.fromString(pr['titleFont']) diff --git a/components/video.py b/components/video.py index bd1bf96..ff06329 100644 --- a/components/video.py +++ b/components/video.py @@ -86,6 +86,9 @@ class Video: class Component(__base__.Component): '''Video''' + + modified = QtCore.pyqtSignal(int, bool) + def widget(self, parent): self.parent = parent self.settings = parent.settings @@ -106,6 +109,7 @@ class Component(__base__.Component): return page def update(self): + super().update() self.videoPath = self.page.lineEdit_video.text() self.loopVideo = self.page.checkBox_loop.isChecked() self.parent.drawPreview() @@ -136,7 +140,7 @@ class Component(__base__.Component): return self.video.frame(frameNo) 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.checkBox_loop.setChecked(pr['loop']) diff --git a/core.py b/core.py index c47068c..5617c81 100644 --- a/core.py +++ b/core.py @@ -34,6 +34,7 @@ class Core(): self.findComponents() self.selectedComponents = [] + self.modifiedComponents = {} def findComponents(self): def findComponents(): @@ -50,24 +51,86 @@ class Core(): for name in findComponents()] 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): if compPos < 0: compPos = len(self.selectedComponents) -1 + + component = self.modules[moduleIndex].Component( + moduleIndex, compPos) self.selectedComponents.insert( 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 def moveComponent(self, startI, endI): + def insert(target, comp): + self.selectedComponents.insert(target, comp) + 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 + 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): # print('updating %s' % self.selectedComponents[i]) 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): compNames = [mod.Component.__doc__ for mod in self.modules] index = compNames.index(compName) @@ -78,11 +141,17 @@ class Core(): which implements an insertComponent method''' errcode, data = self.parseAvFile(filepath) if errcode == 0: - for name, vers, preset in data['Components']: + for i, tup in enumerate(data['Components']): + name, vers, preset = tup loader.insertComponent( self.moduleIndexFor(name), -1) self.selectedComponents[-1].loadPreset( preset) + if data['Modified'][i] == True: + self.componentModified(i) + loader.updateComponentTitle(i, True) + else: + loader.updateComponentTitle(i) elif errcode == 1: typ, value, _ = data if typ.__name__ == KeyError: @@ -105,7 +174,7 @@ class Core(): with open(filepath, 'r') as f: def parseLine(line): '''Decides if a given avp or avl line is a section header''' - validSections = ('Components') + validSections = ('Components', 'Modified') line = line.strip() newSection = '' @@ -138,6 +207,8 @@ class Core(): lastCompPreset) ) i = 0 + if line and section == 'Modified': + data[section].append(eval(line)) return 0, data except: return 1, sys.exc_info() @@ -223,6 +294,12 @@ class Core(): f.write('%s\n' % str(comp)) f.write('%s\n' % str(comp.version())) 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 except: return False diff --git a/mainwindow.py b/mainwindow.py index 42105d1..2a04a4a 100644 --- a/mainwindow.py +++ b/mainwindow.py @@ -235,13 +235,21 @@ class MainWindow(QtCore.QObject): self.previewThread.wait() self.autosave() - def updateComponentTitle(self, pos): + @QtCore.pyqtSlot(int, bool) + def updateComponentTitle(self, pos, modified=False): + #print(pos, modified) if pos < 0: pos = len(self.core.selectedComponents)-1 title = str(self.core.selectedComponents[pos]) if self.core.selectedComponents[pos].currentPreset: title += ' - %s' % self.core.selectedComponents[pos].currentPreset + if modified: + title += '*' self.window.listWidget_componentList.item(pos).setText(title) + if modified: + self.core.componentModified(pos) + else: + self.core.componentUnmodified(pos) def updateCodecs(self): containerWidget = self.window.comboBox_videoContainer @@ -344,9 +352,6 @@ class MainWindow(QtCore.QObject): self.showMessage( msg="You must select an audio file and output filename.") - def progressBarUpdated(self, value): - self.window.progressBar_createVideo.setValue(value) - def changeEncodingStatus(self, status): if status: self.window.pushButton_createVideo.setEnabled(False) @@ -385,6 +390,9 @@ class MainWindow(QtCore.QObject): self.window.pushButton_presets.setEnabled(True) self.window.listWidget_componentList.setEnabled(True) + def progressBarUpdated(self, value): + self.window.progressBar_createVideo.setValue(value) + def progressBarSetText(self, value): self.window.progressBar_createVideo.setFormat(value) @@ -420,6 +428,10 @@ class MainWindow(QtCore.QObject): self.core.selectedComponents[index].__doc__) 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)) stackedWidget.insertWidget(index, self.pages[index]) stackedWidget.setCurrentIndex(index) @@ -433,7 +445,7 @@ class MainWindow(QtCore.QObject): index = componentList.row(selected) self.window.stackedWidget.removeWidget(self.pages[index]) componentList.takeItem(index) - self.core.selectedComponents.pop(index) + self.core.removeComponent(index) self.pages.pop(index) self.changeComponentWidget() self.drawPreview() @@ -533,10 +545,6 @@ class MainWindow(QtCore.QObject): # actually load the project using core method 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): parent = kwargs['parent'] if 'parent' in kwargs else self.window msg = QtGui.QMessageBox(parent) diff --git a/presetmanager.py b/presetmanager.py index 91dc373..4300ce1 100644 --- a/presetmanager.py +++ b/presetmanager.py @@ -105,14 +105,14 @@ class PresetManager(QtGui.QDialog): def openSavePresetDialog(self): '''Functions on mainwindow level from the context menu''' window = self.parent.window - self.selectedComponents = self.parent.core.selectedComponents + selectedComponents = self.parent.core.selectedComponents componentList = self.parent.window.listWidget_componentList if componentList.currentRow() == -1: return while True: index = componentList.currentRow() - currentPreset = self.selectedComponents[index].currentPreset + currentPreset = selectedComponents[index].currentPreset newName, OK = QtGui.QInputDialog.getText( self.parent.window, 'Audio Visualizer', @@ -127,30 +127,35 @@ class PresetManager(QtGui.QDialog): if newName: if index != -1: saveValueStore = \ - self.selectedComponents[index].savePreset() - componentName = str(self.selectedComponents[index]).strip() - vers = self.selectedComponents[index].version() + selectedComponents[index].savePreset() + componentName = str(selectedComponents[index]).strip() + vers = selectedComponents[index].version() self.createNewPreset( - componentName, vers, newName, saveValueStore) - self.selectedComponents[index].currentPreset = newName - self.findPresets() - self.drawPresetList() + componentName, vers, newName, + saveValueStore, window=self.parent.window) + selectedComponents[index].currentPreset = newName + #self.findPresets() + #self.drawPresetList() + self.parent.updateComponentTitle(index) 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) - if self.presetExists(path): + if self.presetExists(path, **kwargs): return self.core.createPresetFile(compName, vers, filename, saveValueStore) - def presetExists(self, path): + def presetExists(self, path, **kwargs): if os.path.exists(path): + window = self.window \ + if 'window' not in kwargs else kwargs['window'] ch = self.parent.showMessage( msg="%s already exists! Overwrite it?" % os.path.basename(path), showCancel=True, icon=QtGui.QMessageBox.Warning, - parent=self.window) + parent=window) if not ch: # user clicked cancel return True @@ -204,6 +209,7 @@ class PresetManager(QtGui.QDialog): os.remove(filepath) def warnMessage(self, window=None): + print(window) self.parent.showMessage( msg='Preset names must contain only letters, ' 'numbers, and spaces.', -- cgit v1.2.3 From 2ad14b7d6ca9216bcdc72c5e13937fcbccc887a3 Mon Sep 17 00:00:00 2001 From: tassaron Date: Tue, 13 Jun 2017 22:47:18 -0400 Subject: asterisk next to modified preset is more accurate hopefully --- components/__base__.py | 9 ++-- components/color.py | 4 +- components/image.py | 4 +- components/original.py | 4 +- components/text.py | 4 +- components/video.py | 4 +- core.py | 125 +++++++++++++++++++------------------------------ mainwindow.py | 20 +++++--- presetmanager.py | 19 ++------ 9 files changed, 80 insertions(+), 113 deletions(-) (limited to 'components/image.py') diff --git a/components/__base__.py b/components/__base__.py index b32c120..bc6644b 100644 --- a/components/__base__.py +++ b/components/__base__.py @@ -1,5 +1,6 @@ from PyQt4 import QtGui, QtCore + class Component(QtCore.QObject): '''A base class for components to inherit from''' @@ -26,8 +27,8 @@ class Component(QtCore.QObject): self.canceled = False def update(self): - self.modified.emit(self.compPos, True) - # use super().update() then read your widget values here + self.modified.emit(self.compPos, self.savePreset()) + # read your widget values, then call super().update() def loadPreset(self, presetDict, presetName): '''Children should take (presetDict, presetName=None) as args''' @@ -36,10 +37,10 @@ class Component(QtCore.QObject): # 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): for var, value in kwargs.items(): exec('self.%s = value' % var) diff --git a/components/color.py b/components/color.py index b6105c8..5912bfa 100644 --- a/components/color.py +++ b/components/color.py @@ -8,7 +8,7 @@ from . import __base__ class Component(__base__.Component): '''Color''' - modified = QtCore.pyqtSignal(int, bool) + modified = QtCore.pyqtSignal(int, dict) def widget(self, parent): self.parent = parent @@ -48,12 +48,12 @@ class Component(__base__.Component): return page def update(self): - super().update() self.color1 = self.RGBFromString(self.page.lineEdit_color1.text()) self.color2 = self.RGBFromString(self.page.lineEdit_color2.text()) self.x = self.page.spinBox_x.value() self.y = self.page.spinBox_y.value() self.parent.drawPreview() + super().update() def previewRender(self, previewWorker): width = int(previewWorker.core.settings.value('outputWidth')) diff --git a/components/image.py b/components/image.py index ed5f243..cdf10c7 100644 --- a/components/image.py +++ b/components/image.py @@ -7,7 +7,7 @@ from . import __base__ class Component(__base__.Component): '''Image''' - modified = QtCore.pyqtSignal(int, bool) + modified = QtCore.pyqtSignal(int, dict) def widget(self, parent): self.parent = parent @@ -25,9 +25,9 @@ class Component(__base__.Component): return page def update(self): - super().update() self.imagePath = self.page.lineEdit_image.text() self.parent.drawPreview() + super().update() def previewRender(self, previewWorker): width = int(previewWorker.core.settings.value('outputWidth')) diff --git a/components/original.py b/components/original.py index f3f578d..9df2815 100644 --- a/components/original.py +++ b/components/original.py @@ -11,7 +11,7 @@ from copy import copy class Component(__base__.Component): '''Original Audio Visualization''' - modified = QtCore.pyqtSignal(int, bool) + modified = QtCore.pyqtSignal(int, dict) def widget(self, parent): self.parent = parent @@ -35,10 +35,10 @@ class Component(__base__.Component): return page def update(self): - super().update() self.layout = self.page.comboBox_visLayout.currentIndex() self.visColor = self.RGBFromString(self.page.lineEdit_visColor.text()) self.parent.drawPreview() + super().update() def loadPreset(self, pr, presetName=None): super().loadPreset(pr, presetName) diff --git a/components/text.py b/components/text.py index a40e2a9..165a093 100644 --- a/components/text.py +++ b/components/text.py @@ -10,7 +10,7 @@ from . import __base__ class Component(__base__.Component): '''Title Text''' - modified = QtCore.pyqtSignal(int, bool) + modified = QtCore.pyqtSignal(int, dict) def __init__(self, *args): super().__init__(*args) @@ -56,7 +56,6 @@ class Component(__base__.Component): return page def update(self): - super().update() self.title = self.page.lineEdit_title.text() self.alignment = self.page.comboBox_textAlign.currentIndex() self.titleFont = self.page.fontComboBox_titleFont.currentFont() @@ -66,6 +65,7 @@ class Component(__base__.Component): self.textColor = self.RGBFromString( self.page.lineEdit_textColor.text()) self.parent.drawPreview() + super().update() def getXY(self): '''Returns true x, y after considering alignment settings''' diff --git a/components/video.py b/components/video.py index ff06329..841f77b 100644 --- a/components/video.py +++ b/components/video.py @@ -87,7 +87,7 @@ class Video: class Component(__base__.Component): '''Video''' - modified = QtCore.pyqtSignal(int, bool) + modified = QtCore.pyqtSignal(int, dict) def widget(self, parent): self.parent = parent @@ -109,10 +109,10 @@ class Component(__base__.Component): return page def update(self): - super().update() self.videoPath = self.page.lineEdit_video.text() self.loopVideo = self.page.checkBox_loop.isChecked() self.parent.drawPreview() + super().update() def previewRender(self, previewWorker): width = int(previewWorker.core.settings.value('outputWidth')) diff --git a/core.py b/core.py index 5617c81..ef369c9 100644 --- a/core.py +++ b/core.py @@ -6,9 +6,7 @@ from os.path import expanduser import subprocess as sp import numpy from PIL import Image -#import tempfile from shutil import rmtree -#import atexit import time from collections import OrderedDict import json @@ -21,11 +19,6 @@ class Core(): def __init__(self): self.FFMPEG_BIN = self.findFfmpeg() - #self.tempDir = os.path.join( - # tempfile.gettempdir(), 'audio-visualizer-python-data') - #if not os.path.exists(self.tempDir): - # os.makedirs(self.tempDir) - #atexit.register(self.deleteTempDir) self.dataDir = QDesktopServices.storageLocation( QDesktopServices.DataLocation) self.presetDir = os.path.join(self.dataDir, 'presets') @@ -34,7 +27,8 @@ class Core(): self.findComponents() self.selectedComponents = [] - self.modifiedComponents = {} + # copies of named presets to detect modification + self.savedPresets = {} def findComponents(self): def findComponents(): @@ -54,7 +48,6 @@ class Core(): def componentListChanged(self): for i, component in enumerate(self.selectedComponents): component.compPos = i - # print('Modified Components: ', self.modifiedComponents) def insertComponent(self, compPos, moduleIndex): if compPos < 0: @@ -66,76 +59,52 @@ class Core(): compPos, 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 def moveComponent(self, startI, endI): - def insert(target, comp): - self.selectedComponents.insert(target, comp) - comp = self.selectedComponents.pop(startI) - 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.selectedComponents.insert(endI, comp) self.componentListChanged() 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): # print('updating %s' % self.selectedComponents[i]) 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): compNames = [mod.Component.__doc__ for mod in self.modules] index = compNames.index(compName) return self.moduleIndexes[index] + def openPreset(self, filepath, compIndex, presetName): + '''Applies a preset to a specific component''' + saveValueStore = self.getPreset(filepath) + if not saveValueStore: + return False + + self.selectedComponents[compIndex].loadPreset( + saveValueStore, + presetName + ) + self.savedPresets[presetName] = dict(saveValueStore) + return True + + def getPreset(self, filepath): + '''Returns the preset dict stored at this filepath''' + if not os.path.exists(filepath): + return False + with open(filepath, 'r') as f: + for line in f: + saveValueStore = Core.presetFromString(line.strip()) + break + return saveValueStore + def openProject(self, loader, filepath): '''loader is the object calling this method (mainwindow/command) which implements an insertComponent method''' @@ -143,15 +112,29 @@ class Core(): if errcode == 0: for i, tup in enumerate(data['Components']): name, vers, preset = tup + + # add loaded named presets to savedPresets dict + if 'preset' in preset and preset['preset'] != None: + nam = preset['preset'] + filepath2 = os.path.join( + self.presetDir, name, str(vers), nam) + origSaveValueStore = self.getPreset(filepath2) + self.savedPresets[nam] = dict(origSaveValueStore) + + # insert component into the loader loader.insertComponent( self.moduleIndexFor(name), -1) - self.selectedComponents[-1].loadPreset( - preset) - if data['Modified'][i] == True: - self.componentModified(i) - loader.updateComponentTitle(i, True) + + if 'preset' in preset and preset['preset'] != None: + self.selectedComponents[-1].loadPreset( + preset + ) else: - loader.updateComponentTitle(i) + self.selectedComponents[-1].loadPreset( + preset, + preset['preset'] + ) + elif errcode == 1: typ, value, _ = data if typ.__name__ == KeyError: @@ -174,7 +157,7 @@ class Core(): with open(filepath, 'r') as f: def parseLine(line): '''Decides if a given avp or avl line is a section header''' - validSections = ('Components', 'Modified') + validSections = ('Components') line = line.strip() newSection = '' @@ -207,8 +190,6 @@ class Core(): lastCompPreset) ) i = 0 - if line and section == 'Modified': - data[section].append(eval(line)) return 0, data except: return 1, sys.exc_info() @@ -294,12 +275,6 @@ class Core(): f.write('%s\n' % str(comp)) f.write('%s\n' % str(comp.version())) 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 except: return False @@ -385,12 +360,6 @@ class Core(): return completeAudioArray - #def deleteTempDir(self): - # try: - # rmtree(self.tempDir) - # except FileNotFoundError: - # pass - def cancel(self): self.canceled = True diff --git a/mainwindow.py b/mainwindow.py index 2a04a4a..3ea4f58 100644 --- a/mainwindow.py +++ b/mainwindow.py @@ -235,9 +235,17 @@ class MainWindow(QtCore.QObject): self.previewThread.wait() self.autosave() - @QtCore.pyqtSlot(int, bool) - def updateComponentTitle(self, pos, modified=False): - #print(pos, modified) + @QtCore.pyqtSlot(int, dict) + def updateComponentTitle(self, pos, presetStore=False): + if type(presetStore) == dict: + name = presetStore['preset'] + if name == None: + modified = False + else: + modified = (presetStore != self.core.savedPresets[name]) + else: + print(pos, presetStore) + modified = bool(presetStore) if pos < 0: pos = len(self.core.selectedComponents)-1 title = str(self.core.selectedComponents[pos]) @@ -246,10 +254,6 @@ class MainWindow(QtCore.QObject): if modified: title += '*' self.window.listWidget_componentList.item(pos).setText(title) - if modified: - self.core.componentModified(pos) - else: - self.core.componentUnmodified(pos) def updateCodecs(self): containerWidget = self.window.comboBox_videoContainer @@ -521,6 +525,8 @@ class MainWindow(QtCore.QObject): "Project Files (*.avp)") if not filename: return + if not filename.endswith(".avp"): + filename += '.avp' self.settings.setValue("projectDir", os.path.dirname(filename)) self.settings.setValue("currentProject", filename) self.currentProject = filename diff --git a/presetmanager.py b/presetmanager.py index 4300ce1..2083483 100644 --- a/presetmanager.py +++ b/presetmanager.py @@ -14,6 +14,7 @@ class PresetManager(QtGui.QDialog): self.presetDir = self.core.presetDir self.findPresets() + # window self.lastFilter = '*' self.presetRows = [] # list of (comp, vers, name) tuples self.window = window @@ -126,6 +127,7 @@ class PresetManager(QtGui.QDialog): continue if newName: if index != -1: + selectedComponents[index].currentPreset = newName saveValueStore = \ selectedComponents[index].savePreset() componentName = str(selectedComponents[index]).strip() @@ -133,10 +135,7 @@ class PresetManager(QtGui.QDialog): self.createNewPreset( componentName, vers, newName, saveValueStore, window=self.parent.window) - selectedComponents[index].currentPreset = newName - #self.findPresets() - #self.drawPresetList() - self.parent.updateComponentTitle(index) + self.openPreset(newName) break def createNewPreset( @@ -173,16 +172,8 @@ class PresetManager(QtGui.QDialog): version = selectedComponents[index].version() dirname = os.path.join(self.presetDir, componentName, str(version)) filepath = os.path.join(dirname, presetName) - if not os.path.exists(filepath): - return - with open(filepath, 'r') as f: - for line in f: - saveValueStore = core.Core.presetFromString(line.strip()) - break - selectedComponents[index].loadPreset( - saveValueStore, - presetName - ) + self.core.openPreset(filepath, index, presetName) + self.parent.updateComponentTitle(index) self.parent.drawPreview() -- cgit v1.2.3 From 8846af57ba9635fe4a1c44778dc468f22277e538 Mon Sep 17 00:00:00 2001 From: tassaron Date: Wed, 14 Jun 2017 19:37:47 -0400 Subject: image component stretch/scale/x/y options --- components/image.py | 24 +++++++++++++++++-- components/image.ui | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++--- components/video.ui | 43 +++++++++++++++++++++++++++++---- core.py | 23 ++++++++++-------- 4 files changed, 139 insertions(+), 19 deletions(-) (limited to 'components/image.py') diff --git a/components/image.py b/components/image.py index cdf10c7..a2f0521 100644 --- a/components/image.py +++ b/components/image.py @@ -20,12 +20,20 @@ class Component(__base__.Component): page.lineEdit_image.textChanged.connect(self.update) page.pushButton_image.clicked.connect(self.pickImage) + page.spinBox_scale.valueChanged.connect(self.update) + page.checkBox_stretch.stateChanged.connect(self.update) + page.spinBox_x.valueChanged.connect(self.update) + page.spinBox_y.valueChanged.connect(self.update) self.page = page return page def update(self): self.imagePath = self.page.lineEdit_image.text() + self.scale = self.page.spinBox_scale.value() + self.xPosition = self.page.spinBox_x.value() + self.yPosition = self.page.spinBox_y.value() + self.stretched = self.page.checkBox_stretch.isChecked() self.parent.drawPreview() super().update() @@ -47,19 +55,31 @@ class Component(__base__.Component): frame = Image.new("RGBA", (width, height), (0, 0, 0, 0)) if self.imagePath and os.path.exists(self.imagePath): image = Image.open(self.imagePath) - if image.size != (width, height): + if self.stretched and image.size != (width, height): image = image.resize((width, height), Image.ANTIALIAS) - frame.paste(image) + if self.scale != 100: + newHeight = int((image.height / 100) * self.scale) + newWidth = int((image.width / 100) * self.scale) + image = image.resize((newWidth, newHeight), Image.ANTIALIAS) + frame.paste(image, box=(self.xPosition, self.yPosition)) return frame def loadPreset(self, pr, presetName=None): super().loadPreset(pr, presetName) self.page.lineEdit_image.setText(pr['image']) + self.page.spinBox_scale.setValue(pr['scale']) + self.page.spinBox_x.setValue(pr['x']) + self.page.spinBox_y.setValue(pr['y']) + self.page.checkBox_stretch.setChecked(pr['stretched']) def savePreset(self): return { 'preset': self.currentPreset, 'image': self.imagePath, + 'scale': self.scale, + 'stretched': self.stretched, + 'x': self.xPosition, + 'y': self.yPosition, } def pickImage(self): diff --git a/components/image.ui b/components/image.ui index 3cd5b1b..685e997 100644 --- a/components/image.ui +++ b/components/image.ui @@ -124,8 +124,11 @@ 16777215 + + -10000 + - 999999999 + 10000 @@ -163,10 +166,10 @@ - 0 + -1000 - 999999999 + 1000 0 @@ -177,6 +180,65 @@ + + + + + + Stretch + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + Scale + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + QAbstractSpinBox::UpDownArrows + + + % + + + 10 + + + 200 + + + 100 + + + + + diff --git a/components/video.ui b/components/video.ui index 6a01368..aca46b4 100644 --- a/components/video.ui +++ b/components/video.ui @@ -111,7 +111,7 @@ - + 0 @@ -124,8 +124,11 @@ 16777215 + + -10000 + - 999999999 + 10000 @@ -163,10 +166,10 @@ - 0 + -10000 - 999999999 + 10000 0 @@ -202,6 +205,35 @@ + + + + Scale + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + QAbstractSpinBox::UpDownArrows + + + % + + + 10 + + + 200 + + + 100 + + + @@ -217,6 +249,9 @@ + + + diff --git a/core.py b/core.py index ef369c9..9276f4a 100644 --- a/core.py +++ b/core.py @@ -124,16 +124,19 @@ class Core(): # insert component into the loader loader.insertComponent( self.moduleIndexFor(name), -1) - - if 'preset' in preset and preset['preset'] != None: - self.selectedComponents[-1].loadPreset( - preset - ) - else: - self.selectedComponents[-1].loadPreset( - preset, - preset['preset'] - ) + try: + if 'preset' in preset and preset['preset'] != None: + self.selectedComponents[-1].loadPreset( + preset + ) + else: + self.selectedComponents[-1].loadPreset( + preset, + preset['preset'] + ) + except KeyError as e: + print('%s missing value %s' % + (self.selectedComponents[-1], e)) elif errcode == 1: typ, value, _ = data -- cgit v1.2.3 From c05efc73ee069fe2eb8776a27b503ada2adb4af6 Mon Sep 17 00:00:00 2001 From: tassaron Date: Thu, 15 Jun 2017 22:15:03 -0400 Subject: various bugfixes, blankFrame method for components don't crash from broken project files or nonexistent videopaths, and shareable common paths in core.py --- components/__base__.py | 4 ++ components/color.py | 2 +- components/image.py | 6 ++- components/image.ui | 2 +- components/original.py | 4 +- components/text.py | 2 +- components/video.py | 27 ++++++++----- components/video.ui | 2 +- core.py | 106 +++++++++++++++++++++++++++++++++---------------- mainwindow.py | 4 +- preview_thread.py | 5 +-- 11 files changed, 107 insertions(+), 57 deletions(-) (limited to 'components/image.py') diff --git a/components/__base__.py b/components/__base__.py index bc6644b..88f22d4 100644 --- a/components/__base__.py +++ b/components/__base__.py @@ -1,4 +1,5 @@ from PyQt4 import QtGui, QtCore +from PIL import Image class Component(QtCore.QObject): @@ -45,6 +46,9 @@ class Component(QtCore.QObject): for var, value in kwargs.items(): exec('self.%s = value' % var) + def blankFrame(self, width, height): + return Image.new("RGBA", (width, height), (0, 0, 0, 0)) + def pickColor(self): dialog = QtGui.QColorDialog() dialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True) diff --git a/components/color.py b/components/color.py index 5912bfa..36f3906 100644 --- a/components/color.py +++ b/components/color.py @@ -71,7 +71,7 @@ class Component(__base__.Component): def drawFrame(self, width, height): r, g, b = self.color1 - return Image.new("RGBA", (width, height), (r, g, b, 255)) + return self.blankFrame(width, height) def loadPreset(self, pr, presetName=None): super().loadPreset(pr, presetName) diff --git a/components/image.py b/components/image.py index a2f0521..b6aa29b 100644 --- a/components/image.py +++ b/components/image.py @@ -38,6 +38,7 @@ class Component(__base__.Component): super().update() def previewRender(self, previewWorker): + self.imageFormats = previewWorker.core.imageFormats width = int(previewWorker.core.settings.value('outputWidth')) height = int(previewWorker.core.settings.value('outputHeight')) return self.drawFrame(width, height) @@ -52,7 +53,7 @@ class Component(__base__.Component): return self.drawFrame(width, height) def drawFrame(self, width, height): - frame = Image.new("RGBA", (width, height), (0, 0, 0, 0)) + frame = self.blankFrame(width, height) if self.imagePath and os.path.exists(self.imagePath): image = Image.open(self.imagePath) if self.stretched and image.size != (width, height): @@ -85,7 +86,8 @@ class Component(__base__.Component): def pickImage(self): imgDir = self.settings.value("backgroundDir", os.path.expanduser("~")) filename = QtGui.QFileDialog.getOpenFileName( - self.page, "Choose Image", imgDir, "Image Files (*.jpg *.png)") + self.page, "Choose Image", imgDir, + "Image Files (%s)" % " ".join(self.imageFormats)) if filename: self.settings.setValue("backgroundDir", os.path.dirname(filename)) self.page.lineEdit_image.setText(filename) diff --git a/components/image.ui b/components/image.ui index 685e997..6df03a5 100644 --- a/components/image.ui +++ b/components/image.ui @@ -230,7 +230,7 @@ 10 - 200 + 400 100 diff --git a/components/original.py b/components/original.py index 9df2815..5e2f9d4 100644 --- a/components/original.py +++ b/components/original.py @@ -145,7 +145,7 @@ class Component(__base__.Component): bF = width / 64 bH = bF / 2 bQ = bF / 4 - imTop = Image.new("RGBA", (width, height), (0, 0, 0, 0)) + imTop = self.blankFrame(width, height) draw = ImageDraw.Draw(imTop) r, g, b = color color2 = (r, g, b, 125) @@ -163,7 +163,7 @@ class Component(__base__.Component): imBottom = imTop.transpose(Image.FLIP_TOP_BOTTOM) - im = Image.new("RGBA", (width, height), (0, 0, 0, 0)) + im = self.blankFrame(width, height) if layout == 0: y = 0 - int(height/100*43) diff --git a/components/text.py b/components/text.py index 165a093..f8ef7b3 100644 --- a/components/text.py +++ b/components/text.py @@ -126,7 +126,7 @@ class Component(__base__.Component): def addText(self, width, height): x, y = self.getXY() - im = Image.new("RGBA", (width, height), (0, 0, 0, 0)) + im = self.blankFrame(width, height) image = ImageQt(im) painter = QPainter(image) diff --git a/components/video.py b/components/video.py index 5f55211..3d43a18 100644 --- a/components/video.py +++ b/components/video.py @@ -128,12 +128,13 @@ class Component(__base__.Component): super().update() def previewRender(self, previewWorker): + self.videoFormats = previewWorker.core.videoFormats width = int(previewWorker.core.settings.value('outputWidth')) height = int(previewWorker.core.settings.value('outputHeight')) self.updateChunksize(width, height) frame = self.getPreviewFrame(width, height) if not frame: - return Image.new("RGBA", (width, height), (0, 0, 0, 0)) + return self.blankFrame(width, height) else: return frame @@ -141,6 +142,7 @@ class Component(__base__.Component): super().preFrameRender(**kwargs) width = int(self.worker.core.settings.value('outputWidth')) height = int(self.worker.core.settings.value('outputHeight')) + self.blankFrame_ = self.blankFrame(width, height) self.updateChunksize(width, height) self.video = Video( ffmpeg=self.parent.core.FFMPEG_BIN, videoPath=self.videoPath, @@ -148,10 +150,13 @@ class Component(__base__.Component): frameRate=int(self.settings.value("outputFrameRate")), parent=self.parent, loopVideo=self.loopVideo, component=self, scale=self.scale - ) + ) if os.path.exists(self.videoPath) else None def frameRender(self, moduleNo, arrayNo, frameNo): - return self.video.frame(frameNo) + if self.video: + return self.video.frame(frameNo) + else: + return self.blankFrame_ def loadPreset(self, pr, presetName=None): super().loadPreset(pr, presetName) @@ -177,7 +182,7 @@ class Component(__base__.Component): imgDir = self.settings.value("backgroundDir", os.path.expanduser("~")) filename = QtGui.QFileDialog.getOpenFileName( self.page, "Choose Video", - imgDir, "Video Files (*.mp4 *.mov)" + imgDir, "Video Files (%s)" % " ".join(self.videoFormats) ) if filename: self.settings.setValue("backgroundDir", os.path.dirname(filename)) @@ -228,10 +233,14 @@ def scale(scale, width, height, returntype=None): def finalizeFrame(self, imageData, width, height): if self.distort: - image = Image.frombytes( - 'RGBA', - (width, height), - imageData) + try: + image = Image.frombytes( + 'RGBA', + (width, height), + imageData) + except ValueError: + print('#### ignored invalid data caused by distortion ####') + image = self.blankFrame(width, height) else: image = Image.frombytes( 'RGBA', @@ -240,7 +249,7 @@ def finalizeFrame(self, imageData, width, height): if self.scale != 100 \ or self.xPosition != 0 or self.yPosition != 0: - frame = Image.new("RGBA", (width, height), (0, 0, 0, 0)) + frame = self.blankFrame(width, height) frame.paste(image, box=(self.xPosition, self.yPosition)) else: frame = image diff --git a/components/video.ui b/components/video.ui index fa088fa..f05e8a5 100644 --- a/components/video.ui +++ b/components/video.ui @@ -234,7 +234,7 @@ 10 - 200 + 400 100 diff --git a/core.py b/core.py index 8eb7d16..3fca7bf 100644 --- a/core.py +++ b/core.py @@ -24,6 +24,32 @@ class Core(): self.presetDir = os.path.join(self.dataDir, 'presets') self.wd = os.path.dirname(os.path.realpath(__file__)) self.loadEncoderOptions() + self.videoFormats = Core.appendUppercase([ + '*.mp4', + '*.mov', + '*.mkv', + '*.avi', + '*.webm', + '*.flv', + ]) + self.audioFormats = Core.appendUppercase([ + '*.mp3', + '*.wav', + '*.ogg', + '*.fla', + '*.aac', + ]) + self.imageFormats = Core.appendUppercase([ + '*.png', + '*.jpg', + '*.tif', + '*.tiff', + '*.gif', + '*.bmp', + '*.ico', + '*.xbm', + '*.xpm', + ]) self.findComponents() self.selectedComponents = [] @@ -116,44 +142,48 @@ class Core(): which implements an insertComponent method''' errcode, data = self.parseAvFile(filepath) if errcode == 0: - for i, tup in enumerate(data['Components']): - name, vers, preset = tup - clearThis = False - - # add loaded named presets to savedPresets dict - if 'preset' in preset and preset['preset'] != None: - nam = preset['preset'] - filepath2 = os.path.join( - self.presetDir, name, str(vers), nam) - origSaveValueStore = self.getPreset(filepath2) - if origSaveValueStore: - self.savedPresets[nam] = dict(origSaveValueStore) - else: - # saved preset was renamed or deleted - clearThis = True - - # insert component into the loader - loader.insertComponent( - self.moduleIndexFor(name), -1) - try: + try: + for i, tup in enumerate(data['Components']): + name, vers, preset = tup + clearThis = False + + # add loaded named presets to savedPresets dict if 'preset' in preset and preset['preset'] != None: - self.selectedComponents[-1].loadPreset( - preset - ) - else: - self.selectedComponents[-1].loadPreset( - preset, - preset['preset'] - ) - except KeyError as e: - print('%s missing value %s' % - (self.selectedComponents[-1], e)) - - if clearThis: - self.clearPreset(-1, loader) + nam = preset['preset'] + filepath2 = os.path.join( + self.presetDir, name, str(vers), nam) + origSaveValueStore = self.getPreset(filepath2) + if origSaveValueStore: + self.savedPresets[nam] = dict(origSaveValueStore) + else: + # saved preset was renamed or deleted + clearThis = True + + # insert component into the loader + loader.insertComponent( + self.moduleIndexFor(name), -1) + try: + if 'preset' in preset and preset['preset'] != None: + self.selectedComponents[-1].loadPreset( + preset + ) + else: + self.selectedComponents[-1].loadPreset( + preset, + preset['preset'] + ) + except KeyError as e: + print('%s missing value %s' % + (self.selectedComponents[-1], e)) + if clearThis: + self.clearPreset(-1, loader) + except: + errcode = 1 + data = sys.exc_info() - elif errcode == 1: + + if errcode == 1: typ, value, _ = data if typ.__name__ == KeyError: # probably just an old version, still loadable @@ -398,3 +428,9 @@ class Core(): def presetFromString(string): '''Turns a string repr of OrderedDict into a regular dict''' return dict(eval(string)) + + @staticmethod + def appendUppercase(lst): + for form, i in zip(lst, range(len(lst))): + lst.append(form.upper()) + return lst diff --git a/mainwindow.py b/mainwindow.py index ad1df10..f1959cb 100644 --- a/mainwindow.py +++ b/mainwindow.py @@ -310,7 +310,7 @@ class MainWindow(QtCore.QObject): fileName = QtGui.QFileDialog.getOpenFileName( self.window, "Open Music File", - inputDir, "Music Files (*.mp3 *.wav *.ogg *.fla *.aac)") + inputDir, "Music Files (%s)" % " ".join(self.core.audioFormats)) if not fileName == "": self.settings.setValue("inputDir", os.path.dirname(fileName)) @@ -322,7 +322,7 @@ class MainWindow(QtCore.QObject): fileName = QtGui.QFileDialog.getSaveFileName( self.window, "Set Output Video File", outputDir, - "Video Files (*.mp4 *.mov *.mkv *.avi *.webm *.flv);; All Files (*)") + "Video Files (%s);; All Files (*)" % " ".join(self.core.videoFormats)) if not fileName == "": self.settings.setValue("outputDir", os.path.dirname(fileName)) diff --git a/preview_thread.py b/preview_thread.py index d54dba5..e3e8279 100644 --- a/preview_thread.py +++ b/preview_thread.py @@ -1,11 +1,9 @@ from PyQt4 import QtCore, QtGui, uic from PyQt4.QtCore import pyqtSignal, pyqtSlot -from PIL import Image, ImageDraw, ImageFont +from PIL import Image from PIL.ImageQt import ImageQt import core -import time from queue import Queue, Empty -import numpy import os from copy import copy @@ -18,6 +16,7 @@ class Worker(QtCore.QObject): QtCore.QObject.__init__(self) parent.newTask.connect(self.createPreviewImage) parent.processTask.connect(self.process) + self.parent = parent self.core = core.Core() self.queue = queue self.core.settings = parent.settings -- cgit v1.2.3