Redesigned preset UI + video & image component scaling/positioning

Added preset manager
This commit is contained in:
Brianna 2017-06-15 23:21:34 -04:00 committed by GitHub
commit fc7ee6d8e5
16 changed files with 1424 additions and 470 deletions

View File

@ -1,7 +1,18 @@
from PyQt4 import QtGui
from PyQt4 import QtGui, QtCore
from PIL import Image
class Component:
class Component(QtCore.QObject):
'''A base class for components to inherit from'''
# 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__
@ -10,18 +21,38 @@ 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, self.savePreset())
# read your widget values, then call super().update()
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)
def blankFrame(self, width, height):
return Image.new("RGBA", (width, height), (0, 0, 0, 0))
def pickColor(self):
color = QtGui.QColorDialog.getColor()
dialog = QtGui.QColorDialog()
dialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True)
color = dialog.getColor()
if color.isValid():
RGBstring = '%s,%s,%s' % (
str(color.red()), str(color.green()), str(color.blue()))
@ -57,7 +88,7 @@ class Component:
return page
def update(self):
# read widget values
super().update()
self.parent.drawPreview()
def previewRender(self, previewWorker):
@ -72,12 +103,6 @@ class Component:
image = Image.new("RGBA", (width, height), (0,0,0,0))
return image
def loadPreset(self, presetDict):
# update widgets using a preset dict
def savePreset(self):
return {}
def cancel(self):
self.canceled = True

View File

@ -7,6 +7,9 @@ from . import __base__
class Component(__base__.Component):
'''Color'''
modified = QtCore.pyqtSignal(int, dict)
def widget(self, parent):
self.parent = parent
page = uic.loadUi(os.path.join(
@ -20,14 +23,14 @@ class Component(__base__.Component):
page.lineEdit_color1.setText('%s,%s,%s' % self.color1)
page.lineEdit_color2.setText('%s,%s,%s' % self.color2)
btnStyle = "QPushButton { background-color : %s; outline: none; }" \
btnStyle1 = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*self.color1).name()
btnStyle = "QPushButton { background-color : %s; outline: none; }" \
btnStyle2 = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*self.color2).name()
page.pushButton_color1.setStyleSheet(btnStyle)
page.pushButton_color2.setStyleSheet(btnStyle)
page.pushButton_color1.setStyleSheet(btnStyle1)
page.pushButton_color2.setStyleSheet(btnStyle2)
page.pushButton_color1.clicked.connect(lambda: self.pickColor(1))
page.pushButton_color2.clicked.connect(lambda: self.pickColor(2))
@ -50,6 +53,7 @@ class Component(__base__.Component):
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'))
@ -67,23 +71,26 @@ 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)
def loadPreset(self, pr):
self.page.lineEdit_color1.setText('%s,%s,%s' % pr['color1'])
self.page.lineEdit_color2.setText('%s,%s,%s' % pr['color2'])
btnStyle = "QPushButton { background-color : %s; outline: none; }" \
btnStyle1 = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*pr['color1']).name()
btnStyle = "QPushButton { background-color : %s; outline: none; }" \
btnStyle2 = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*pr['color2']).name()
self.page.pushButton_color1.setStyleSheet(btnStyle)
self.page.pushButton_color2.setStyleSheet(btnStyle)
self.page.pushButton_color1.setStyleSheet(btnStyle1)
self.page.pushButton_color2.setStyleSheet(btnStyle2)
def savePreset(self):
return {
'preset': self.currentPreset,
'color1': self.color1,
'color2': self.color2,
}

View File

@ -6,6 +6,9 @@ from . import __base__
class Component(__base__.Component):
'''Image'''
modified = QtCore.pyqtSignal(int, dict)
def widget(self, parent):
self.parent = parent
self.settings = parent.settings
@ -17,15 +20,25 @@ 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()
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)
@ -40,27 +53,42 @@ 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 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):
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):
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~"))
filename = QtGui.QFileDialog.getOpenFileName(
self.page, "Choose Image", imgDir, "Image Files (*.jpg *.png)")
if filename:
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)
self.update()

View File

@ -124,8 +124,11 @@
<height>16777215</height>
</size>
</property>
<property name="minimum">
<number>-10000</number>
</property>
<property name="maximum">
<number>999999999</number>
<number>10000</number>
</property>
</widget>
</item>
@ -163,10 +166,10 @@
</size>
</property>
<property name="minimum">
<number>0</number>
<number>-1000</number>
</property>
<property name="maximum">
<number>999999999</number>
<number>1000</number>
</property>
<property name="value">
<number>0</number>
@ -177,6 +180,65 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QCheckBox" name="checkBox_stretch">
<property name="text">
<string>Stretch</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Scale</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_scale">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::UpDownArrows</enum>
</property>
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>400</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">

View File

@ -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, dict)
def widget(self, parent):
self.parent = parent
self.visColor = (255, 255, 255)
@ -36,8 +38,11 @@ class Component(__base__.Component):
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)
def loadPreset(self, pr):
self.page.lineEdit_visColor.setText('%s,%s,%s' % pr['visColor'])
btnStyle = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*pr['visColor']).name()
@ -46,6 +51,7 @@ class Component(__base__.Component):
def savePreset(self):
return {
'preset': self.currentPreset,
'layout': self.layout,
'visColor': self.visColor,
}
@ -139,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)
@ -157,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)

View File

@ -9,8 +9,11 @@ from . import __base__
class Component(__base__.Component):
'''Title Text'''
def __init__(self):
super().__init__()
modified = QtCore.pyqtSignal(int, dict)
def __init__(self, *args):
super().__init__(*args)
self.titleFont = QFont()
def widget(self, parent):
@ -31,7 +34,7 @@ class Component(__base__.Component):
page.comboBox_textAlign.addItem("Right")
page.lineEdit_textColor.setText('%s,%s,%s' % self.textColor)
page.pushButton_textColor.clicked.connect(lambda: self.pickColor())
page.pushButton_textColor.clicked.connect(self.pickColor)
btnStyle = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*self.textColor).name()
page.pushButton_textColor.setStyleSheet(btnStyle)
@ -62,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'''
@ -78,7 +82,9 @@ class Component(__base__.Component):
x = self.xPosition - offset
return x, self.yPosition
def loadPreset(self, pr):
def loadPreset(self, pr, presetName=None):
super().loadPreset(pr, presetName)
self.page.lineEdit_title.setText(pr['title'])
font = QFont()
font.fromString(pr['titleFont'])
@ -94,6 +100,7 @@ class Component(__base__.Component):
def savePreset(self):
return {
'preset': self.currentPreset,
'title': self.title,
'titleFont': self.titleFont.toString(),
'alignment': self.alignment,
@ -119,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)

View File

@ -5,12 +5,22 @@ import subprocess
import threading
from queue import PriorityQueue
from . import __base__
class Video:
'''Video Component Frame-Fetcher'''
def __init__(self, **kwargs):
mandatoryArgs = ['ffmpeg', 'videoPath', 'width', 'height',
'frameRate', 'chunkSize', 'parent']
mandatoryArgs = [
'ffmpeg', # path to ffmpeg, usually core.FFMPEG_BIN
'videoPath',
'width',
'height',
'scale', # percentage scale
'frameRate', # frames per second
'chunkSize', # number of bytes in one frame
'parent', # mainwindow object
'component', # component object
]
for arg in mandatoryArgs:
try:
exec('self.%s = kwargs[arg]' % arg)
@ -31,7 +41,8 @@ class Video:
'-i', self.videoPath,
'-f', 'image2pipe',
'-pix_fmt', 'rgba',
'-filter:v', 'scale='+str(self.width)+':'+str(self.height),
'-filter:v', 'scale=%s:%s' %
scale(self.scale, self.width, self.height, str),
'-vcodec', 'rawvideo', '-',
]
@ -50,7 +61,9 @@ class Video:
while True:
if num in self.finishedFrames:
image = self.finishedFrames.pop(num)
return Image.frombytes('RGBA', (self.width, self.height), image)
return finalizeFrame(
self.component, image, self.width, self.height)
i, image = self.frameBuffer.get()
self.finishedFrames[i] = image
self.frameBuffer.task_done()
@ -78,6 +91,9 @@ class Video:
class Component(__base__.Component):
'''Video'''
modified = QtCore.pyqtSignal(int, dict)
def widget(self, parent):
self.parent = parent
self.settings = parent.settings
@ -93,6 +109,10 @@ class Component(__base__.Component):
page.lineEdit_video.textChanged.connect(self.update)
page.pushButton_video.clicked.connect(self.pickVideo)
page.checkBox_loop.stateChanged.connect(self.update)
page.checkBox_distort.stateChanged.connect(self.update)
page.spinBox_scale.valueChanged.connect(self.update)
page.spinBox_x.valueChanged.connect(self.update)
page.spinBox_y.valueChanged.connect(self.update)
self.page = page
return page
@ -100,15 +120,21 @@ class Component(__base__.Component):
def update(self):
self.videoPath = self.page.lineEdit_video.text()
self.loopVideo = self.page.checkBox_loop.isChecked()
self.distort = self.page.checkBox_distort.isChecked()
self.scale = self.page.spinBox_scale.value()
self.xPosition = self.page.spinBox_x.value()
self.yPosition = self.page.spinBox_y.value()
self.parent.drawPreview()
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.chunkSize = 4*width*height
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
@ -116,32 +142,49 @@ class Component(__base__.Component):
super().preFrameRender(**kwargs)
width = int(self.worker.core.settings.value('outputWidth'))
height = int(self.worker.core.settings.value('outputHeight'))
self.chunkSize = 4*width*height
self.blankFrame_ = self.blankFrame(width, height)
self.updateChunksize(width, height)
self.video = Video(
ffmpeg=self.parent.core.FFMPEG_BIN, videoPath=self.videoPath,
width=width, height=height, chunkSize=self.chunkSize,
frameRate=int(self.settings.value("outputFrameRate")),
parent=self.parent, loopVideo=self.loopVideo
)
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):
def loadPreset(self, pr, presetName=None):
super().loadPreset(pr, presetName)
self.page.lineEdit_video.setText(pr['video'])
self.page.checkBox_loop.setChecked(pr['loop'])
self.page.checkBox_distort.setChecked(pr['distort'])
self.page.spinBox_scale.setValue(pr['scale'])
self.page.spinBox_x.setValue(pr['x'])
self.page.spinBox_y.setValue(pr['y'])
def savePreset(self):
return {
'preset': self.currentPreset,
'video': self.videoPath,
'loop': self.loopVideo,
'distort': self.distort,
'scale': self.scale,
'x': self.xPosition,
'y': self.yPosition,
}
def pickVideo(self):
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:
if filename:
self.settings.setValue("backgroundDir", os.path.dirname(filename))
self.page.lineEdit_video.setText(filename)
self.update()
@ -149,13 +192,15 @@ class Component(__base__.Component):
def getPreviewFrame(self, width, height):
if not self.videoPath or not os.path.exists(self.videoPath):
return
command = [
self.parent.core.FFMPEG_BIN,
'-thread_queue_size', '512',
'-i', self.videoPath,
'-f', 'image2pipe',
'-pix_fmt', 'rgba',
'-filter:v', 'scale='+str(width)+':'+str(height),
'-filter:v', 'scale=%s:%s' %
scale(self.scale, width, height, str),
'-vcodec', 'rawvideo', '-',
'-ss', '90',
'-vframes', '1',
@ -165,7 +210,47 @@ class Component(__base__.Component):
stderr=subprocess.DEVNULL, bufsize=10**8
)
byteFrame = pipe.stdout.read(self.chunkSize)
image = Image.frombytes('RGBA', (width, height), byteFrame)
frame = finalizeFrame(self, byteFrame, width, height)
pipe.stdout.close()
pipe.kill()
return image
return frame
def updateChunksize(self, width, height):
if self.scale != 100 and not self.distort:
width, height = scale(self.scale, width, height, int)
self.chunkSize = 4*width*height
def scale(scale, width, height, returntype=None):
width = (float(width) / 100.0) * float(scale)
height = (float(height) / 100.0) * float(scale)
if returntype == str:
return (str(int(width)), str(int(height)))
elif returntype == int:
return (int(width), int(height))
else:
return (width, height)
def finalizeFrame(self, imageData, width, height):
if self.distort:
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',
scale(self.scale, width, height, int),
imageData)
if self.scale != 100 \
or self.xPosition != 0 or self.yPosition != 0:
frame = self.blankFrame(width, height)
frame.paste(image, box=(self.xPosition, self.yPosition))
else:
frame = image
return frame

View File

@ -111,7 +111,7 @@
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_x_2">
<widget class="QSpinBox" name="spinBox_x">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -124,8 +124,11 @@
<height>16777215</height>
</size>
</property>
<property name="minimum">
<number>-10000</number>
</property>
<property name="maximum">
<number>999999999</number>
<number>10000</number>
</property>
</widget>
</item>
@ -163,10 +166,10 @@
</size>
</property>
<property name="minimum">
<number>0</number>
<number>-10000</number>
</property>
<property name="maximum">
<number>999999999</number>
<number>10000</number>
</property>
<property name="value">
<number>0</number>
@ -202,6 +205,42 @@
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="checkBox_distort">
<property name="text">
<string>Distort by scale</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Scale</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_scale">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::UpDownArrows</enum>
</property>
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>400</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
@ -217,6 +256,9 @@
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="widget" native="true"/>
</item>
</layout>
</widget>
<resources/>

347
core.py
View File

@ -6,25 +6,330 @@ 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
from importlib import import_module
from PyQt4.QtGui import QDesktopServices
import string
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')
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 = []
# copies of named presets to detect modification
self.savedPresets = {}
def findComponents(self):
def findComponents():
srcPath = os.path.join(self.wd, 'components')
if os.path.exists(srcPath):
for f in sorted(os.listdir(srcPath)):
name, ext = os.path.splitext(f)
if name.startswith("__"):
continue
elif ext == '.py':
yield name
self.modules = [
import_module('components.%s' % name)
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
def insertComponent(self, compPos, moduleIndex):
if compPos < 0:
compPos = len(self.selectedComponents) -1
component = self.modules[moduleIndex].Component(
moduleIndex, compPos)
self.selectedComponents.insert(
compPos,
component)
self.componentListChanged()
return compPos
def moveComponent(self, startI, endI):
comp = self.selectedComponents.pop(startI)
self.selectedComponents.insert(endI, comp)
self.componentListChanged()
return endI
def removeComponent(self, i):
self.selectedComponents.pop(i)
self.componentListChanged()
def updateComponent(self, i):
# print('updating %s' % self.selectedComponents[i])
self.selectedComponents[i].update()
def moduleIndexFor(self, compName):
compNames = [mod.Component.__doc__ for mod in self.modules]
index = compNames.index(compName)
return self.moduleIndexes[index]
def clearPreset(self, compIndex, loader=None):
'''Clears a preset from a component'''
self.selectedComponents[compIndex].currentPreset = None
if loader:
loader.updateComponentTitle(compIndex)
def openPreset(self, filepath, compIndex, presetName):
'''Applies a preset to a specific component'''
saveValueStore = self.getPreset(filepath)
if not saveValueStore:
return False
try:
self.selectedComponents[compIndex].loadPreset(
saveValueStore,
presetName
)
except KeyError as e:
print('preset missing value: %s' % e)
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'''
errcode, data = self.parseAvFile(filepath)
if errcode == 0:
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:
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()
if errcode == 1:
typ, value, _ = data
if typ.__name__ == KeyError:
# probably just an old version, still loadable
print('file missing value: %s' % value)
return
loader.createNewProject()
msg = '%s: %s' % (typ.__name__, value)
loader.showMessage(
msg="Project file '%s' is corrupted." % filepath,
showCancel=False,
icon=QtGui.QMessageBox.Warning,
detail=msg)
def parseAvFile(self, filepath):
'''Parses an avp (project) or avl (preset package) file.
Returns data usable by another method.'''
data = {}
try:
with open(filepath, 'r') as f:
def parseLine(line):
'''Decides if a given avp or avl line is a section header'''
validSections = ('Components')
line = line.strip()
newSection = ''
if line.startswith('[') and line.endswith(']') \
and line[1:-1] in validSections:
newSection = line[1:-1]
return line, newSection
section = ''
i = 0
for line in f:
line, newSection = parseLine(line)
if newSection:
section = str(newSection)
data[section] = []
continue
if line and section == 'Components':
if i == 0:
lastCompName = str(line)
i += 1
elif i == 1:
lastCompVers = str(line)
i += 1
elif i == 2:
lastCompPreset = Core.presetFromString(line)
data[section].append(
(lastCompName,
lastCompVers,
lastCompPreset)
)
i = 0
return 0, data
except:
return 1, sys.exc_info()
def importPreset(self, filepath):
errcode, data = self.parseAvFile(filepath)
returnList = []
if errcode == 0:
name, vers, preset = data['Components'][0]
presetName = preset['preset'] \
if preset['preset'] else os.path.basename(filepath)[:-4]
newPath = os.path.join(
self.presetDir,
name,
vers,
presetName
)
if os.path.exists(newPath):
return False, newPath
preset['preset'] = presetName
self.createPresetFile(
name, vers, presetName, preset
)
return True, presetName
elif errcode == 1:
# TODO: an error message
return False, ''
def exportPreset(self, exportPath, compName, vers, origName):
internalPath = os.path.join(self.presetDir, compName, str(vers), origName)
if not os.path.exists(internalPath):
return
if os.path.exists(exportPath):
os.remove(exportPath)
with open(internalPath, 'r') as f:
internalData = [line for line in f]
try:
saveValueStore = Core.presetFromString(internalData[0].strip())
self.createPresetFile(
compName, vers,
origName, saveValueStore,
exportPath
)
return True
except:
return False
def createPresetFile(
self, compName, vers, presetName, saveValueStore, filepath=''):
'''Create a preset file (.avl) at filepath using args.
Or if filepath is empty, create an internal preset using
the args for the filepath.'''
if not filepath:
dirname = os.path.join(self.presetDir, compName, str(vers))
if not os.path.exists(dirname):
os.makedirs(dirname)
filepath = os.path.join(dirname, presetName)
internal = True
else:
if not filepath.endswith('.avl'):
filepath += '.avl'
internal = False
with open(filepath, 'w') as f:
if not internal:
f.write('[Components]\n')
f.write('%s\n' % compName)
f.write('%s\n' % str(vers))
f.write(Core.presetToString(saveValueStore))
def createProjectFile(self, filepath):
'''Create a project file (.avp) using the current program state'''
try:
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')
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' % Core.presetToString(saveValueStore))
return True
except:
return False
def loadEncoderOptions(self):
file_path = os.path.join(self.wd, 'encoder-options.json')
@ -107,12 +412,6 @@ class Core():
return completeAudioArray
def deleteTempDir(self):
try:
rmtree(self.tempDir)
except FileNotFoundError:
pass
def cancel(self):
self.canceled = True
@ -120,6 +419,22 @@ class Core():
self.canceled = False
@staticmethod
def stringOrderedDict(dictionary):
sorted_ = OrderedDict(sorted(dictionary.items(), key=lambda t: t[0]))
return repr(sorted_)
def badName(name):
'''Returns whether a name contains non-alphanumeric chars'''
return any([letter in string.punctuation for letter in name])
@staticmethod
def presetToString(dictionary):
'''Alphabetizes a dict into OrderedDict & returns string repr'''
return repr(OrderedDict(sorted(dictionary.items(), key=lambda t: t[0])))
@staticmethod
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

View File

@ -1,5 +1,4 @@
from importlib import import_module
from collections import OrderedDict
from PyQt4 import QtGui, uic
from PyQt4.QtCore import Qt
import sys

View File

@ -1,14 +1,10 @@
from os.path import expanduser
from queue import Queue
from importlib import import_module
from collections import OrderedDict
from PyQt4 import QtCore, QtGui
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 io
import os
import string
import signal
import filecmp
import time
@ -16,6 +12,7 @@ import time
import core
import preview_thread
import video_thread
from presetmanager import PresetManager
from main import LoadDefaultSettings
@ -55,26 +52,30 @@ class MainWindow(QtCore.QObject):
# print('main thread id: {}'.format(QtCore.QThread.currentThreadId()))
self.window = window
self.core = core.Core()
self.pages = []
self.selectedComponents = []
self.pages = [] # widgets of component settings
self.lastAutosave = time.time()
# create data directory, load/create settings
self.dataDir = QDesktopServices.storageLocation(
QDesktopServices.DataLocation)
# Create data directory, load/create settings
self.dataDir = self.core.dataDir
self.autosavePath = os.path.join(self.dataDir, 'autosave.avp')
self.presetDir = os.path.join(self.dataDir, 'presets')
self.settings = QSettings(
os.path.join(self.dataDir, 'settings.ini'), QSettings.IniFormat)
LoadDefaultSettings(self)
self.presetManager = PresetManager(
uic.loadUi(
os.path.join(os.path.dirname(os.path.realpath(__file__)),
'presetmanager.ui')),
self)
if not os.path.exists(self.dataDir):
os.makedirs(self.dataDir)
for neededDirectory in (
self.presetDir, self.settings.value("projectDir")):
self.core.presetDir, self.settings.value("projectDir")):
if not os.path.exists(neededDirectory):
os.mkdir(neededDirectory)
#
# Make queues/timers for the preview thread
self.previewQueue = Queue()
self.previewThread = QtCore.QThread(self)
self.previewWorker = preview_thread.Worker(self, self.previewQueue)
@ -86,7 +87,9 @@ class MainWindow(QtCore.QObject):
self.timer.timeout.connect(self.processTask.emit)
self.timer.start(500)
# begin decorating the window and connecting events
# Begin decorating the window and connecting events
componentList = self.window.listWidget_componentList
window.toolButton_selectAudioFile.clicked.connect(
self.openInputFileDialog)
@ -117,7 +120,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)
@ -141,25 +144,33 @@ class MainWindow(QtCore.QObject):
window.spinBox_vBitrate.valueChanged.connect(self.updateCodecSettings)
window.spinBox_aBitrate.valueChanged.connect(self.updateCodecSettings)
self.previewWindow = PreviewWindow(self, os.path.join(
os.path.dirname(os.path.realpath(__file__)), "background.png"))
window.verticalLayout_previewWrapper.addWidget(self.previewWindow)
self.modules = self.findComponents()
# Make component buttons
self.compMenu = QMenu()
for i, comp in enumerate(self.modules):
for i, comp in enumerate(self.core.modules):
action = self.compMenu.addAction(comp.Component.__doc__)
action.triggered[()].connect(
lambda item=i: self.insertComponent(item))
self.window.pushButton_addComponent.setMenu(self.compMenu)
window.listWidget_componentList.clicked.connect(
lambda _: self.changeComponentWidget())
componentList.dropEvent = self.dragComponent
componentList.itemSelectionChanged.connect(
self.changeComponentWidget)
self.window.pushButton_removeComponent.clicked.connect(
lambda _: self.removeComponent())
componentList.setContextMenuPolicy(
QtCore.Qt.CustomContextMenu)
componentList.connect(
componentList,
QtCore.SIGNAL("customContextMenuRequested(QPoint)"),
self.componentContextMenu)
currentRes = str(self.settings.value('outputWidth'))+'x' + \
str(self.settings.value('outputHeight'))
for i, res in enumerate(self.resolutions):
@ -169,36 +180,47 @@ class MainWindow(QtCore.QObject):
window.comboBox_resolution.setCurrentIndex(currentRes)
window.comboBox_resolution.currentIndexChanged.connect(
self.updateResolution)
self.window.pushButton_listMoveUp.clicked.connect(
self.moveComponentUp)
lambda: self.moveComponent(-1)
)
self.window.pushButton_listMoveDown.clicked.connect(
self.moveComponentDown)
self.window.pushButton_savePreset.clicked.connect(
self.openSavePresetDialog)
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)
lambda: self.moveComponent(1)
)
# show the window and load current project
# Configure the Projects Menu
self.projectMenu = QMenu()
self.ui_newProject = self.projectMenu.addAction("New Project")
self.ui_newProject.triggered[()].connect(self.createNewProject)
self.ui_openProject = self.projectMenu.addAction("Open Project")
self.ui_openProject.triggered[()].connect(self.openOpenProjectDialog)
action = self.projectMenu.addAction("Save Project")
action.triggered[()].connect(self.saveCurrentProject)
action = self.projectMenu.addAction("Save Project As")
action.triggered[()].connect(self.openSaveProjectDialog)
self.window.pushButton_projects.setMenu(self.projectMenu)
# Configure the Presets Button
self.window.pushButton_presets.clicked.connect(
self.openPresetManager
)
# 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)
if self.currentProject and os.path.exists(self.autosavePath):
ch = self.showMessage(
"Restore unsaved changes in project '%s'?"
% os.path.basename(self.currentProject)[:-4], True)
msg="Restore unsaved changes in project '%s'?"
% os.path.basename(self.currentProject)[:-4],
showCancel=True)
if ch:
os.remove(self.currentProject)
os.rename(self.autosavePath, self.currentProject)
@ -214,6 +236,26 @@ class MainWindow(QtCore.QObject):
self.previewThread.wait()
self.autosave()
@QtCore.pyqtSlot(int, dict)
def updateComponentTitle(self, pos, presetStore=False):
if type(presetStore) == dict:
name = presetStore['preset']
if name == None or name not in self.core.savedPresets:
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])
if self.core.selectedComponents[pos].currentPreset:
title += ' - %s' % self.core.selectedComponents[pos].currentPreset
if modified:
title += '*'
self.window.listWidget_componentList.item(pos).setText(title)
def updateCodecs(self):
containerWidget = self.window.comboBox_videoContainer
vCodecWidget = self.window.comboBox_videoCodec
@ -249,18 +291,26 @@ class MainWindow(QtCore.QObject):
self.settings.setValue('outputAudioBitrate', currentAudioBitrate)
def autosave(self):
if time.time() - self.lastAutosave >= 1.0:
if not self.currentProject:
if os.path.exists(self.autosavePath):
os.remove(self.autosavePath)
self.createProjectFile(self.autosavePath)
elif time.time() - self.lastAutosave >= 2.0:
self.core.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("~"))
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))
@ -271,7 +321,8 @@ class MainWindow(QtCore.QObject):
fileName = QtGui.QFileDialog.getSaveFileName(
self.window, "Set Output Video File",
outputDir, "Video Files (*.mp4 *.mov *.mkv *.avi *.webm *.flv)")
outputDir,
"Video Files (%s);; All Files (*)" % " ".join(self.core.videoFormats))
if not fileName == "":
self.settings.setValue("outputDir", os.path.dirname(fileName))
@ -302,13 +353,10 @@ class MainWindow(QtCore.QObject):
self.videoTask.emit(
self.window.lineEdit_audioFile.text(),
self.window.lineEdit_outputFile.text(),
self.selectedComponents)
self.core.selectedComponents)
else:
self.showMessage(
"You must select an audio file and output filename.")
def progressBarUpdated(self, value):
self.window.progressBar_createVideo.setValue(value)
msg="You must select an audio file and output filename.")
def changeEncodingStatus(self, status):
if status:
@ -327,11 +375,9 @@ class MainWindow(QtCore.QObject):
self.window.pushButton_removeComponent.setEnabled(False)
self.window.pushButton_listMoveDown.setEnabled(False)
self.window.pushButton_listMoveUp.setEnabled(False)
self.window.comboBox_openPreset.setEnabled(False)
self.window.pushButton_removePreset.setEnabled(False)
self.window.pushButton_savePreset.setEnabled(False)
self.window.pushButton_openProject.setEnabled(False)
self.window.listWidget_componentList.setEnabled(False)
self.ui_newProject.setEnabled(False)
self.ui_openProject.setEnabled(False)
else:
self.window.pushButton_createVideo.setEnabled(True)
self.window.pushButton_Cancel.setEnabled(False)
@ -348,11 +394,12 @@ class MainWindow(QtCore.QObject):
self.window.pushButton_removeComponent.setEnabled(True)
self.window.pushButton_listMoveDown.setEnabled(True)
self.window.pushButton_listMoveUp.setEnabled(True)
self.window.comboBox_openPreset.setEnabled(True)
self.window.pushButton_removePreset.setEnabled(True)
self.window.pushButton_savePreset.setEnabled(True)
self.window.pushButton_openProject.setEnabled(True)
self.window.listWidget_componentList.setEnabled(True)
self.ui_newProject.setEnabled(True)
self.ui_openProject.setEnabled(True)
def progressBarUpdated(self, value):
self.window.progressBar_createVideo.setValue(value)
def progressBarSetText(self, value):
self.window.progressBar_createVideo.setFormat(value)
@ -369,187 +416,126 @@ class MainWindow(QtCore.QObject):
self.drawPreview()
def drawPreview(self):
self.newTask.emit(self.selectedComponents)
self.newTask.emit(self.core.selectedComponents)
# self.processTask.emit()
self.autosave()
def showPreviewImage(self, image):
self.previewWindow.changePixmap(image)
def findComponents(self):
def findComponents():
srcPath = os.path.join(
os.path.dirname(os.path.realpath(__file__)), 'components')
if os.path.exists(srcPath):
for f in sorted(os.listdir(srcPath)):
name, ext = os.path.splitext(f)
if name.startswith("__"):
continue
elif ext == '.py':
yield name
return [
import_module('components.%s' % name)
for name in findComponents()]
def insertComponent(self, moduleIndex, compPos=0):
componentList = self.window.listWidget_componentList
stackedWidget = self.window.stackedWidget
if compPos < 0:
compPos = componentList.count()
def addComponent(self, moduleIndex):
index = len(self.pages)
self.selectedComponents.append(self.modules[moduleIndex].Component())
self.window.listWidget_componentList.addItem(
self.selectedComponents[-1].__doc__)
self.pages.append(self.selectedComponents[-1].widget(self))
self.window.listWidget_componentList.setCurrentRow(index)
self.window.stackedWidget.addWidget(self.pages[-1])
self.window.stackedWidget.setCurrentIndex(index)
self.selectedComponents[-1].update()
self.updateOpenPresetComboBox(self.selectedComponents[-1])
index = self.core.insertComponent(
compPos, moduleIndex)
row = componentList.insertItem(
index,
self.core.selectedComponents[index].__doc__)
componentList.setCurrentRow(index)
def insertComponent(self, moduleIndex):
self.selectedComponents.insert(
0, self.modules[moduleIndex].Component())
self.window.listWidget_componentList.insertItem(
0, self.selectedComponents[0].__doc__)
self.pages.insert(0, self.selectedComponents[0].widget(self))
self.window.listWidget_componentList.setCurrentRow(0)
self.window.stackedWidget.insertWidget(0, self.pages[0])
self.window.stackedWidget.setCurrentIndex(0)
self.selectedComponents[0].update()
self.updateOpenPresetComboBox(self.selectedComponents[0])
# 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)
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)
self.selectedComponents.pop(index)
componentList.takeItem(index)
self.core.removeComponent(index)
self.pages.pop(index)
self.changeComponentWidget()
self.drawPreview()
def moveComponent(self, change):
'''Moves a component relatively from its current position'''
componentList = self.window.listWidget_componentList
stackedWidget = self.window.stackedWidget
row = componentList.currentRow()
newRow = row + change
if newRow > -1 and newRow < componentList.count():
self.core.moveComponent(row, newRow)
# update widgets
page = self.pages.pop(row)
self.pages.insert(newRow, page)
item = componentList.takeItem(row)
newItem = componentList.insertItem(newRow, item)
widget = stackedWidget.removeWidget(page)
stackedWidget.insertWidget(newRow, page)
componentList.setCurrentRow(newRow)
stackedWidget.setCurrentIndex(newRow)
self.drawPreview()
def dragComponent(self, event):
'''Drop event for the component listwidget'''
componentList = self.window.listWidget_componentList
modelIndexes = [ \
componentList.model().index(i) \
for i in range(componentList.count()) \
]
rects = [ \
componentList.visualRect(modelIndex) \
for modelIndex in modelIndexes \
]
rowPos = [rect.contains(event.pos()) for rect in rects]
if not any(rowPos):
return
i = rowPos.index(True)
change = (componentList.currentRow() - i) * -1
self.moveComponent(change)
def changeComponentWidget(self):
selected = self.window.listWidget_componentList.selectedItems()
if selected:
index = self.window.listWidget_componentList.row(selected[0])
self.window.stackedWidget.setCurrentIndex(index)
self.updateOpenPresetComboBox(self.selectedComponents[index])
def moveComponentUp(self):
row = self.window.listWidget_componentList.currentRow()
if row > 0:
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)
self.drawPreview()
def openPresetManager(self):
'''Preset manager for importing, exporting, renaming, deleting'''
self.presetManager.show()
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)
self.drawPreview()
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 updateOpenPresetComboBox(self, component):
self.window.comboBox_openPreset.clear()
self.window.comboBox_openPreset.addItem("Component Presets")
destination = os.path.join(
self.presetDir, str(component).strip(), str(component.version()))
if not os.path.exists(destination):
os.makedirs(destination)
for f in os.listdir(destination):
self.window.comboBox_openPreset.addItem(f)
def openSavePresetDialog(self):
if self.window.listWidget_componentList.currentRow() == -1:
return
while True:
newName, OK = QtGui.QInputDialog.getText(
QtGui.QWidget(), 'Audio Visualizer', 'New Preset Name:')
badName = False
for letter in newName:
if letter in string.punctuation:
badName = True
if badName:
# 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):
dirname = os.path.join(self.presetDir, componentName, str(version))
if not os.path.exists(dirname):
os.makedirs(dirname)
filepath = os.path.join(dirname, filename)
if os.path.exists(filepath):
def createNewProject(self):
if self.autosaveExists():
ch = self.showMessage(
"%s already exists! Overwrite it?" % filename,
True, QtGui.QMessageBox.Warning)
if not ch:
return
# remove old copies of the preset
for i in range(0, self.window.comboBox_openPreset.count()):
if self.window.comboBox_openPreset.itemText(i) == filename:
self.window.comboBox_openPreset.removeItem(i)
with open(filepath, 'w') as f:
f.write(core.Core.stringOrderedDict(saveValueStore))
self.window.comboBox_openPreset.addItem(filename)
self.window.comboBox_openPreset.setCurrentIndex(
self.window.comboBox_openPreset.count()-1)
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()
def openPreset(self):
if self.window.comboBox_openPreset.currentIndex() < 1:
return
index = self.window.listWidget_componentList.currentRow()
if index == -1:
return
filename = self.window.comboBox_openPreset.itemText(
self.window.comboBox_openPreset.currentIndex())
componentName = str(self.selectedComponents[index]).strip()
version = self.selectedComponents[index].version()
dirname = os.path.join(self.presetDir, componentName, str(version))
filepath = os.path.join(dirname, filename)
if not os.path.exists(filepath):
self.window.comboBox_openPreset.removeItem(
self.window.comboBox_openPreset.currentIndex())
return
with open(filepath, 'r') as f:
for line in f:
saveValueStore = dict(eval(line.strip()))
break
self.selectedComponents[index].loadPreset(saveValueStore)
self.clear()
self.currentProject = None
self.settings.setValue("currentProject", None)
self.drawPreview()
def saveCurrentProject(self):
if self.currentProject:
self.createProjectFile(self.currentProject)
self.core.createProjectFile(self.currentProject)
else:
self.openSaveProjectDialog()
@ -560,23 +546,13 @@ class MainWindow(QtCore.QObject):
"Project Files (*.avp)")
if not filename:
return
self.createProjectFile(filename)
if not filename.endswith(".avp"):
filename += '.avp'
self.settings.setValue("projectDir", os.path.dirname(filename))
self.settings.setValue("currentProject", filename)
self.currentProject = filename
def createProjectFile(self, filepath):
if not filepath.endswith(".avp"):
filepath += '.avp'
with open(filepath, 'w') as f:
print('creating %s' % filepath)
f.write('[Components]\n')
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' % core.Core.stringOrderedDict(saveValueStore))
if filepath != self.autosavePath:
self.settings.setValue("projectDir", os.path.dirname(filepath))
self.settings.setValue("currentProject", filepath)
self.currentProject = filepath
self.core.createProjectFile(filename)
def openOpenProjectDialog(self):
filename = QtGui.QFileDialog.getOpenFileName(
@ -593,58 +569,18 @@ class MainWindow(QtCore.QObject):
self.currentProject = filepath
self.settings.setValue("currentProject", filepath)
self.settings.setValue("projectDir", os.path.dirname(filepath))
compNames = [mod.Component.__doc__ for mod in self.modules]
try:
with open(filepath, 'r') as f:
validSections = ('Components')
section = ''
# actually load the project using core method
self.core.openProject(self, filepath)
def parseLine(line):
line = line.strip()
newSection = ''
if line.startswith('[') and line.endswith(']') \
and line[1:-1] in validSections:
newSection = line[1:-1]
return line, newSection
i = 0
for line in f:
line, newSection = parseLine(line)
if newSection:
section = str(newSection)
continue
if line and section == 'Components':
if i == 0:
compIndex = compNames.index(line)
self.addComponent(compIndex)
i += 1
elif i == 1:
# version, not used yet
i += 1
elif i == 2:
saveValueStore = dict(eval(line))
self.selectedComponents[-1].loadPreset(
saveValueStore)
i = 0
except (IndexError, ValueError, KeyError, NameError,
SyntaxError, AttributeError, TypeError) as e:
self.clear()
typ, value, _ = sys.exc_info()
msg = '%s: %s' % (typ.__name__, value)
self.showMessage(
"Project file '%s' is corrupted." % filepath, False,
QtGui.QMessageBox.Warning, msg)
def showMessage(
self, string, showCancel=False,
icon=QtGui.QMessageBox.Information, detail=None):
msg = QtGui.QMessageBox()
msg.setIcon(icon)
msg.setText(string)
msg.setDetailedText(detail)
if showCancel:
def showMessage(self, **kwargs):
parent = kwargs['parent'] if 'parent' in kwargs else self.window
msg = QtGui.QMessageBox(parent)
msg.setModal(True)
msg.setText(kwargs['msg'])
msg.setIcon(
kwargs['icon'] if 'icon' in kwargs else QtGui.QMessageBox.Information)
msg.setDetailedText(kwargs['detail'] if 'detail' in kwargs else None)
if 'showCancel'in kwargs and kwargs['showCancel']:
msg.setStandardButtons(
QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
else:
@ -654,10 +590,46 @@ class MainWindow(QtCore.QObject):
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 componentContextMenu(self, QPos):
'''Appears when right-clicking a component in the list'''
componentList = self.window.listWidget_componentList
if not componentList.selectedItems():
return
# don't show menu if clicking empty space
parentPosition = componentList.mapToGlobal(QtCore.QPoint(0, 0))
index = componentList.currentRow()
modelIndex = componentList.model().index(index)
if not componentList.visualRect(modelIndex).contains(QPos):
return
self.presetManager.findPresets()
self.menu = QtGui.QMenu()
menuItem = self.menu.addAction("Save Preset")
menuItem.triggered.connect(
self.presetManager.openSavePresetDialog
)
# submenu for opening presets
try:
presets = self.presetManager.presets[str(self.core.selectedComponents[index])]
self.submenu = QtGui.QMenu("Open Preset")
self.menu.addMenu(self.submenu)
for version, presetName in presets:
menuItem = self.submenu.addAction(presetName)
menuItem.triggered.connect(
lambda _, presetName=presetName:
self.presetManager.openPreset(presetName)
)
except KeyError:
pass
if self.core.selectedComponents[index].currentPreset:
menuItem = self.menu.addAction("Clear Preset")
menuItem.triggered.connect(
self.presetManager.clearPreset
)
self.menu.move(parentPosition + QPos)
self.menu.show()

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1008</width>
<height>575</height>
<width>1028</width>
<height>592</height>
</rect>
</property>
<property name="sizePolicy">
@ -108,23 +108,32 @@
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="QPushButton" name="pushButton_openProject">
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>140</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_projects">
<property name="text">
<string>Open Project</string>
<string>Projects</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_saveProject">
<widget class="QPushButton" name="pushButton_presets">
<property name="text">
<string>Save Project</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_saveAs">
<property name="text">
<string>Save As</string>
<string>Presets</string>
</property>
</widget>
</item>
@ -141,11 +150,60 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>15</height>
<height>2</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QListWidget" name="listWidget_componentList">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="tabKeyNavigation">
<bool>true</bool>
</property>
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropOverwriteMode">
<bool>false</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_14">
<item>
@ -188,97 +246,6 @@
<property name="rightMargin">
<number>2</number>
</property>
<item>
<widget class="QListWidget" name="listWidget_componentList">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="dragEnabled">
<bool>false</bool>
</property>
<property name="dragDropOverwriteMode">
<bool>false</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::NoDragDrop</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<property name="leftMargin">
<number>2</number>
</property>
<item>
<widget class="QComboBox" name="comboBox_openPreset">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>180</width>
<height>0</height>
</size>
</property>
<item>
<property name="text">
<string>Component Presets</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_savePreset">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_removePreset">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>

290
presetmanager.py Normal file
View File

@ -0,0 +1,290 @@
from PyQt4 import QtGui, QtCore
import string
import os
import core
class PresetManager(QtGui.QDialog):
def __init__(self, window, parent):
super().__init__(parent.window)
self.parent = parent
self.core = parent.core
self.settings = parent.settings
self.presetDir = self.core.presetDir
if not self.settings.value('presetDir'):
self.settings.setValue(
"presetDir",
os.path.join(self.core.dataDir, 'projects'))
self.findPresets()
# window
self.lastFilter = '*'
self.presetRows = [] # list of (comp, vers, name) tuples
self.window = window
self.window.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
# connect button signals
self.window.pushButton_delete.clicked.connect(self.openDeletePresetDialog)
self.window.pushButton_rename.clicked.connect(self.openRenamePresetDialog)
self.window.pushButton_import.clicked.connect(self.openImportDialog)
self.window.pushButton_export.clicked.connect(self.openExportDialog)
self.window.pushButton_close.clicked.connect(self.window.close)
# create filter box and preset list
self.drawFilterList()
self.window.comboBox_filter.currentIndexChanged.connect(
lambda: self.drawPresetList(
self.window.comboBox_filter.currentText(), self.window.lineEdit_search.text()
)
)
# make auto-completion for search bar
self.autocomplete = QtGui.QStringListModel()
completer = QtGui.QCompleter()
completer.setModel(self.autocomplete)
self.window.lineEdit_search.setCompleter(completer)
self.window.lineEdit_search.textChanged.connect(
lambda: self.drawPresetList(
self.window.comboBox_filter.currentText(), self.window.lineEdit_search.text()
)
)
self.drawPresetList('*')
def show(self):
'''Open a new preset manager window from the mainwindow'''
self.findPresets()
self.drawFilterList()
self.drawPresetList('*')
self.window.show()
def findPresets(self):
parseList = []
for dirpath, dirnames, filenames in os.walk(self.presetDir):
# anything without a subdirectory must be a preset folder
if dirnames:
continue
for preset in filenames:
compName = os.path.basename(os.path.dirname(dirpath))
compVers = os.path.basename(dirpath)
try:
parseList.append((compName, int(compVers), preset))
except ValueError:
continue
self.presets =\
{
compName : \
[
(vers, preset) \
for name, vers, preset in parseList \
if name == compName \
] \
for compName, _, __ in parseList \
}
def drawPresetList(self, compFilter=None, presetFilter=''):
self.window.listWidget_presets.clear()
if compFilter:
self.lastFilter = str(compFilter)
else:
compFilter = str(self.lastFilter)
self.presetRows = []
presetNames = []
for component, presets in self.presets.items():
if compFilter != '*' and component != compFilter:
continue
for vers, preset in presets:
if not presetFilter or presetFilter in preset:
self.window.listWidget_presets.addItem('%s: %s' % (component, preset))
self.presetRows.append((component, vers, preset))
if preset not in presetNames:
presetNames.append(preset)
self.autocomplete.setStringList(presetNames)
def drawFilterList(self):
self.window.comboBox_filter.clear()
self.window.comboBox_filter.addItem('*')
for component in self.presets:
self.window.comboBox_filter.addItem(component)
def clearPreset(self, compI=None):
'''Functions on mainwindow level from the context menu'''
compI = self.parent.window.listWidget_componentList.currentRow()
self.core.clearPreset(compI, self.parent)
def openSavePresetDialog(self):
'''Functions on mainwindow level from the context menu'''
window = self.parent.window
selectedComponents = self.core.selectedComponents
componentList = self.parent.window.listWidget_componentList
if componentList.currentRow() == -1:
return
while True:
index = componentList.currentRow()
currentPreset = selectedComponents[index].currentPreset
newName, OK = QtGui.QInputDialog.getText(
self.parent.window,
'Audio Visualizer',
'New Preset Name:',
QtGui.QLineEdit.Normal,
currentPreset
)
if OK:
if core.Core.badName(newName):
self.warnMessage(self.parent.window)
continue
if newName:
if index != -1:
selectedComponents[index].currentPreset = newName
saveValueStore = \
selectedComponents[index].savePreset()
componentName = str(selectedComponents[index]).strip()
vers = selectedComponents[index].version()
self.createNewPreset(
componentName, vers, newName,
saveValueStore, window=self.parent.window)
self.openPreset(newName)
break
def createNewPreset(
self, compName, vers, filename, saveValueStore, **kwargs):
path = os.path.join(self.presetDir, compName, str(vers), filename)
if self.presetExists(path, **kwargs):
return
self.core.createPresetFile(compName, vers, filename, saveValueStore)
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=window)
if not ch:
# user clicked cancel
return True
return False
def openPreset(self, presetName):
componentList = self.parent.window.listWidget_componentList
selectedComponents = self.parent.core.selectedComponents
index = componentList.currentRow()
if index == -1:
return
componentName = str(selectedComponents[index]).strip()
version = selectedComponents[index].version()
dirname = os.path.join(self.presetDir, componentName, str(version))
filepath = os.path.join(dirname, presetName)
self.core.openPreset(filepath, index, presetName)
self.parent.updateComponentTitle(index)
self.parent.drawPreview()
def openDeletePresetDialog(self):
selected = self.window.listWidget_presets.selectedItems()
if not selected:
return
row = self.window.listWidget_presets.row(selected[0])
comp, vers, name = self.presetRows[row]
ch = self.parent.showMessage(
msg='Really delete %s?' % name,
showCancel=True,
icon=QtGui.QMessageBox.Warning,
parent=self.window
)
if not ch:
return
self.deletePreset(comp, vers, name)
self.findPresets()
self.drawPresetList()
def deletePreset(self, comp, vers, name):
filepath = os.path.join(self.presetDir, comp, str(vers), name)
os.remove(filepath)
def warnMessage(self, window=None):
print(window)
self.parent.showMessage(
msg='Preset names must contain only letters, '
'numbers, and spaces.',
parent=window if window else self.window)
def openRenamePresetDialog(self):
presetList = self.window.listWidget_presets
if presetList.currentRow() == -1:
return
while True:
index = presetList.currentRow()
newName, OK = QtGui.QInputDialog.getText(
self.window,
'Preset Manager',
'Rename Preset:',
QtGui.QLineEdit.Normal,
self.presetRows[index][2]
)
if OK:
if core.Core.badName(newName):
self.warnMessage()
continue
if newName:
comp, vers, oldName = self.presetRows[index]
path = os.path.join(
self.presetDir, comp, str(vers))
newPath = os.path.join(path, newName)
oldPath = os.path.join(path, oldName)
if self.presetExists(newPath):
return
if os.path.exists(newPath):
os.remove(newPath)
os.rename(oldPath, newPath)
self.findPresets()
self.drawPresetList()
break
def openImportDialog(self):
filename = QtGui.QFileDialog.getOpenFileName(
self.window, "Import Preset File",
self.settings.value("presetDir"),
"Preset Files (*.avl)")
if filename:
# get installed path & ask user to overwrite if needed
path = ''
while True:
if path:
if self.presetExists(path):
break
else:
if os.path.exists(path):
os.remove(path)
success, path = self.core.importPreset(filename)
if success:
break
self.findPresets()
self.drawPresetList()
self.settings.setValue("presetDir", os.path.dirname(filename))
def openExportDialog(self):
if not self.window.listWidget_presets.selectedItems():
return
filename = QtGui.QFileDialog.getSaveFileName(
self.window, "Export Preset",
self.settings.value("presetDir"),
"Preset Files (*.avl)")
if filename:
index = self.window.listWidget_presets.currentRow()
comp, vers, name = self.presetRows[index]
if not self.core.exportPreset(filename, comp, vers, name):
self.parent.showMessage(
msg='Couldn\'t export %s.' % filename,
parent=self.window
)
self.settings.setValue("presetDir", os.path.dirname(filename))

150
presetmanager.ui Normal file
View File

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>presetmanager</class>
<widget class="QWidget" name="presetmanager">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>497</width>
<height>377</height>
</rect>
</property>
<property name="windowTitle">
<string>Preset Manager</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="lineEdit_search">
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>Filter by name</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_filter">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QListWidget" name="listWidget_presets">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="tabKeyNavigation">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="QPushButton" name="pushButton_import">
<property name="text">
<string>Import</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_export">
<property name="text">
<string>Export</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_rename">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Rename</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_delete">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item alignment="Qt::AlignRight">
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt; font-style:italic;&quot;&gt;Right-click components in the main window to create presets&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -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

View File

@ -26,7 +26,7 @@ class Worker(QtCore.QObject):
QtCore.QObject.__init__(self)
self.core = core.Core()
self.core.settings = parent.settings
self.modules = parent.modules
self.modules = parent.core.modules
self.stackedWidget = parent.window.stackedWidget
self.parent = parent
parent.videoTask.connect(self.createVideo)