2017-07-06 12:40:03 -04:00
|
|
|
'''
|
|
|
|
When using GUI mode, this module's object (the main window) takes
|
|
|
|
user input to construct a program state (stored in the Core object).
|
|
|
|
This shows a preview of the video being created and allows for saving
|
|
|
|
projects and exporting the video at a later time.
|
|
|
|
'''
|
2017-06-23 18:38:05 -04:00
|
|
|
from PyQt5 import QtCore, QtGui, uic, QtWidgets
|
|
|
|
from PyQt5.QtWidgets import QMenu, QShortcut
|
2017-07-09 01:10:06 -04:00
|
|
|
from PIL import Image
|
2017-07-04 19:52:52 -04:00
|
|
|
from queue import Queue
|
2017-06-06 11:14:39 -04:00
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import signal
|
|
|
|
import filecmp
|
|
|
|
import time
|
|
|
|
|
2017-07-20 20:31:38 -04:00
|
|
|
from core import Core
|
2017-06-06 11:14:39 -04:00
|
|
|
import preview_thread
|
2017-06-07 20:30:37 -04:00
|
|
|
from presetmanager import PresetManager
|
2017-07-20 20:31:38 -04:00
|
|
|
from toolkit import loadDefaultSettings, disableWhenEncoding, checkOutput
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-06-26 19:07:49 -04:00
|
|
|
|
2017-06-23 18:38:05 -04:00
|
|
|
class PreviewWindow(QtWidgets.QLabel):
|
2017-07-20 20:31:38 -04:00
|
|
|
'''
|
|
|
|
Paints the preview QLabel and maintains the aspect ratio when the
|
|
|
|
window is resized.
|
|
|
|
'''
|
2017-06-06 11:14:39 -04:00
|
|
|
def __init__(self, parent, img):
|
|
|
|
super(PreviewWindow, self).__init__()
|
|
|
|
self.parent = parent
|
2017-06-23 18:38:05 -04:00
|
|
|
self.setFrameStyle(QtWidgets.QFrame.StyledPanel)
|
2017-06-06 11:14:39 -04:00
|
|
|
self.pixmap = QtGui.QPixmap(img)
|
|
|
|
|
|
|
|
def paintEvent(self, event):
|
|
|
|
size = self.size()
|
|
|
|
painter = QtGui.QPainter(self)
|
|
|
|
point = QtCore.QPoint(0, 0)
|
|
|
|
scaledPix = self.pixmap.scaled(
|
2017-06-25 14:27:56 -04:00
|
|
|
size,
|
|
|
|
QtCore.Qt.KeepAspectRatio,
|
|
|
|
transformMode=QtCore.Qt.SmoothTransformation)
|
2017-06-06 11:14:39 -04:00
|
|
|
|
|
|
|
# start painting the label from left upper corner
|
|
|
|
point.setX((size.width() - scaledPix.width())/2)
|
|
|
|
point.setY((size.height() - scaledPix.height())/2)
|
|
|
|
painter.drawPixmap(point, scaledPix)
|
|
|
|
|
|
|
|
def changePixmap(self, img):
|
|
|
|
self.pixmap = QtGui.QPixmap(img)
|
|
|
|
self.repaint()
|
|
|
|
|
|
|
|
|
2017-06-23 18:38:05 -04:00
|
|
|
class MainWindow(QtWidgets.QMainWindow):
|
2017-07-20 20:31:38 -04:00
|
|
|
'''
|
|
|
|
The MainWindow wraps many Core methods in order to update the GUI
|
|
|
|
accordingly. E.g., instead of self.core.openProject(), it will use
|
|
|
|
self.openProject() and update the window titlebar within the wrapper.
|
|
|
|
|
|
|
|
MainWindow manages the autosave feature, although Core has the
|
|
|
|
primary functions for opening and creating project files.
|
|
|
|
'''
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-07-15 01:00:03 -04:00
|
|
|
createVideo = QtCore.pyqtSignal()
|
|
|
|
newTask = QtCore.pyqtSignal(list) # for the preview window
|
2017-06-06 11:14:39 -04:00
|
|
|
processTask = QtCore.pyqtSignal()
|
|
|
|
|
2017-06-18 14:46:08 -04:00
|
|
|
def __init__(self, window, project):
|
2017-06-23 18:38:05 -04:00
|
|
|
QtWidgets.QMainWindow.__init__(self)
|
2017-06-06 11:14:39 -04:00
|
|
|
|
|
|
|
# print('main thread id: {}'.format(QtCore.QThread.currentThreadId()))
|
|
|
|
self.window = window
|
2017-07-20 20:31:38 -04:00
|
|
|
self.core = Core()
|
2017-06-08 09:56:57 -04:00
|
|
|
|
|
|
|
self.pages = [] # widgets of component settings
|
2017-06-06 11:14:39 -04:00
|
|
|
self.lastAutosave = time.time()
|
2017-06-25 10:36:32 -04:00
|
|
|
self.encoding = False
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-06-07 20:30:37 -04:00
|
|
|
# Create data directory, load/create settings
|
2017-07-20 20:31:38 -04:00
|
|
|
self.dataDir = Core.dataDir
|
|
|
|
self.presetDir = Core.presetDir
|
2017-06-08 22:56:33 -04:00
|
|
|
self.autosavePath = os.path.join(self.dataDir, 'autosave.avp')
|
2017-07-20 20:31:38 -04:00
|
|
|
self.settings = Core.settings
|
|
|
|
loadDefaultSettings(self)
|
2017-06-07 23:22:55 -04:00
|
|
|
self.presetManager = PresetManager(
|
|
|
|
uic.loadUi(
|
2017-07-20 20:31:38 -04:00
|
|
|
os.path.join(Core.wd, 'presetmanager.ui')), self)
|
2017-06-15 11:36:26 -04:00
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
if not os.path.exists(self.dataDir):
|
|
|
|
os.makedirs(self.dataDir)
|
|
|
|
for neededDirectory in (
|
2017-07-20 20:31:38 -04:00
|
|
|
self.presetDir, self.settings.value("projectDir")):
|
2017-06-06 11:14:39 -04:00
|
|
|
if not os.path.exists(neededDirectory):
|
|
|
|
os.mkdir(neededDirectory)
|
|
|
|
|
2017-06-07 20:30:37 -04:00
|
|
|
# Make queues/timers for the preview thread
|
2017-06-06 11:14:39 -04:00
|
|
|
self.previewQueue = Queue()
|
|
|
|
self.previewThread = QtCore.QThread(self)
|
|
|
|
self.previewWorker = preview_thread.Worker(self, self.previewQueue)
|
|
|
|
self.previewWorker.moveToThread(self.previewThread)
|
|
|
|
self.previewWorker.imageCreated.connect(self.showPreviewImage)
|
2017-07-06 12:40:03 -04:00
|
|
|
self.previewWorker.error.connect(self.cleanUp)
|
2017-06-06 11:14:39 -04:00
|
|
|
self.previewThread.start()
|
|
|
|
|
|
|
|
self.timer = QtCore.QTimer(self)
|
|
|
|
self.timer.timeout.connect(self.processTask.emit)
|
|
|
|
self.timer.start(500)
|
|
|
|
|
2017-06-07 20:30:37 -04:00
|
|
|
# Begin decorating the window and connecting events
|
2017-06-08 16:50:48 -04:00
|
|
|
componentList = self.window.listWidget_componentList
|
|
|
|
|
2017-06-25 23:05:44 -04:00
|
|
|
if sys.platform == 'darwin':
|
|
|
|
window.progressBar_createVideo.setTextVisible(False)
|
|
|
|
else:
|
|
|
|
window.progressLabel.setHidden(True)
|
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
window.toolButton_selectAudioFile.clicked.connect(
|
|
|
|
self.openInputFileDialog)
|
|
|
|
|
|
|
|
window.toolButton_selectOutputFile.clicked.connect(
|
|
|
|
self.openOutputFileDialog)
|
|
|
|
|
2017-06-25 14:27:56 -04:00
|
|
|
def changedField():
|
|
|
|
self.autosave()
|
|
|
|
self.updateWindowTitle()
|
|
|
|
|
|
|
|
window.lineEdit_audioFile.textChanged.connect(changedField)
|
|
|
|
window.lineEdit_outputFile.textChanged.connect(changedField)
|
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
window.progressBar_createVideo.setValue(0)
|
|
|
|
|
|
|
|
window.pushButton_createVideo.clicked.connect(
|
|
|
|
self.createAudioVisualisation)
|
|
|
|
|
|
|
|
window.pushButton_Cancel.clicked.connect(self.stopVideo)
|
|
|
|
|
2017-07-20 20:31:38 -04:00
|
|
|
for i, container in enumerate(Core.encoderOptions['containers']):
|
2017-06-07 12:59:59 -04:00
|
|
|
window.comboBox_videoContainer.addItem(container['name'])
|
|
|
|
if container['name'] == self.settings.value('outputContainer'):
|
|
|
|
selectedContainer = i
|
|
|
|
|
|
|
|
window.comboBox_videoContainer.setCurrentIndex(selectedContainer)
|
|
|
|
window.comboBox_videoContainer.currentIndexChanged.connect(
|
|
|
|
self.updateCodecs
|
|
|
|
)
|
|
|
|
|
|
|
|
self.updateCodecs()
|
|
|
|
|
|
|
|
for i in range(window.comboBox_videoCodec.count()):
|
|
|
|
codec = window.comboBox_videoCodec.itemText(i)
|
|
|
|
if codec == self.settings.value('outputVideoCodec'):
|
|
|
|
window.comboBox_videoCodec.setCurrentIndex(i)
|
|
|
|
|
|
|
|
for i in range(window.comboBox_audioCodec.count()):
|
|
|
|
codec = window.comboBox_audioCodec.itemText(i)
|
|
|
|
if codec == self.settings.value('outputAudioCodec'):
|
|
|
|
window.comboBox_audioCodec.setCurrentIndex(i)
|
|
|
|
|
|
|
|
window.comboBox_videoCodec.currentIndexChanged.connect(
|
|
|
|
self.updateCodecSettings
|
|
|
|
)
|
|
|
|
|
|
|
|
window.comboBox_audioCodec.currentIndexChanged.connect(
|
|
|
|
self.updateCodecSettings
|
|
|
|
)
|
|
|
|
|
2017-06-07 13:33:22 -04:00
|
|
|
vBitrate = int(self.settings.value('outputVideoBitrate'))
|
2017-06-07 23:22:55 -04:00
|
|
|
aBitrate = int(self.settings.value('outputAudioBitrate'))
|
2017-06-07 13:33:22 -04:00
|
|
|
|
|
|
|
window.spinBox_vBitrate.setValue(vBitrate)
|
|
|
|
window.spinBox_aBitrate.setValue(aBitrate)
|
|
|
|
|
|
|
|
window.spinBox_vBitrate.valueChanged.connect(self.updateCodecSettings)
|
|
|
|
window.spinBox_aBitrate.valueChanged.connect(self.updateCodecSettings)
|
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
self.previewWindow = PreviewWindow(self, os.path.join(
|
2017-07-20 20:31:38 -04:00
|
|
|
Core.wd, "background.png"))
|
2017-06-06 11:14:39 -04:00
|
|
|
window.verticalLayout_previewWrapper.addWidget(self.previewWindow)
|
|
|
|
|
2017-06-07 20:30:37 -04:00
|
|
|
# Make component buttons
|
2017-06-06 11:14:39 -04:00
|
|
|
self.compMenu = QMenu()
|
2017-06-08 09:56:57 -04:00
|
|
|
for i, comp in enumerate(self.core.modules):
|
2017-07-20 20:31:38 -04:00
|
|
|
action = self.compMenu.addAction(comp.Component.name)
|
2017-06-23 18:38:05 -04:00
|
|
|
action.triggered.connect(
|
2017-06-25 10:36:32 -04:00
|
|
|
lambda _, item=i: self.core.insertComponent(0, item, self)
|
|
|
|
)
|
2017-06-06 11:14:39 -04:00
|
|
|
|
|
|
|
self.window.pushButton_addComponent.setMenu(self.compMenu)
|
2017-06-07 20:30:37 -04:00
|
|
|
|
2017-06-15 23:13:36 -04:00
|
|
|
componentList.dropEvent = self.dragComponent
|
2017-06-11 17:03:40 -04:00
|
|
|
componentList.itemSelectionChanged.connect(
|
2017-06-25 10:36:32 -04:00
|
|
|
self.changeComponentWidget
|
|
|
|
)
|
2017-07-20 22:37:15 -04:00
|
|
|
componentList.itemSelectionChanged.connect(
|
|
|
|
self.presetManager.clearPresetListSelection
|
|
|
|
)
|
2017-06-06 11:14:39 -04:00
|
|
|
self.window.pushButton_removeComponent.clicked.connect(
|
2017-06-25 10:36:32 -04:00
|
|
|
lambda: self.removeComponent()
|
|
|
|
)
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-06-23 23:00:24 -04:00
|
|
|
componentList.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
|
|
|
componentList.customContextMenuRequested.connect(
|
|
|
|
self.componentContextMenu
|
|
|
|
)
|
2017-06-07 20:30:37 -04:00
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
currentRes = str(self.settings.value('outputWidth'))+'x' + \
|
|
|
|
str(self.settings.value('outputHeight'))
|
|
|
|
for i, res in enumerate(self.resolutions):
|
|
|
|
window.comboBox_resolution.addItem(res)
|
2017-06-07 12:59:59 -04:00
|
|
|
if res == currentRes:
|
|
|
|
currentRes = i
|
|
|
|
window.comboBox_resolution.setCurrentIndex(currentRes)
|
|
|
|
window.comboBox_resolution.currentIndexChanged.connect(
|
2017-06-25 10:36:32 -04:00
|
|
|
self.updateResolution
|
|
|
|
)
|
2017-06-06 11:14:39 -04:00
|
|
|
|
|
|
|
self.window.pushButton_listMoveUp.clicked.connect(
|
2017-06-08 16:50:48 -04:00
|
|
|
lambda: self.moveComponent(-1)
|
|
|
|
)
|
|
|
|
self.window.pushButton_listMoveDown.clicked.connect(
|
|
|
|
lambda: self.moveComponent(1)
|
|
|
|
)
|
2017-06-07 15:32:05 -04:00
|
|
|
|
|
|
|
# Configure the Projects Menu
|
|
|
|
self.projectMenu = QMenu()
|
2017-06-17 19:08:18 -04:00
|
|
|
self.window.menuButton_newProject = self.projectMenu.addAction(
|
2017-06-25 10:36:32 -04:00
|
|
|
"New Project"
|
|
|
|
)
|
2017-06-23 18:38:05 -04:00
|
|
|
self.window.menuButton_newProject.triggered.connect(
|
2017-06-25 10:36:32 -04:00
|
|
|
lambda: self.createNewProject()
|
|
|
|
)
|
2017-06-17 19:08:18 -04:00
|
|
|
self.window.menuButton_openProject = self.projectMenu.addAction(
|
2017-06-25 10:36:32 -04:00
|
|
|
"Open Project"
|
|
|
|
)
|
2017-06-23 18:38:05 -04:00
|
|
|
self.window.menuButton_openProject.triggered.connect(
|
2017-06-25 10:36:32 -04:00
|
|
|
lambda: self.openOpenProjectDialog()
|
|
|
|
)
|
2017-06-07 15:32:05 -04:00
|
|
|
|
|
|
|
action = self.projectMenu.addAction("Save Project")
|
2017-06-23 18:38:05 -04:00
|
|
|
action.triggered.connect(self.saveCurrentProject)
|
2017-06-07 15:32:05 -04:00
|
|
|
|
|
|
|
action = self.projectMenu.addAction("Save Project As")
|
2017-06-23 18:38:05 -04:00
|
|
|
action.triggered.connect(self.openSaveProjectDialog)
|
2017-06-07 15:32:05 -04:00
|
|
|
|
|
|
|
self.window.pushButton_projects.setMenu(self.projectMenu)
|
|
|
|
|
|
|
|
# Configure the Presets Button
|
|
|
|
self.window.pushButton_presets.clicked.connect(
|
|
|
|
self.openPresetManager
|
|
|
|
)
|
|
|
|
|
2017-06-25 10:36:32 -04:00
|
|
|
self.updateWindowTitle()
|
2017-06-06 11:14:39 -04:00
|
|
|
window.show()
|
|
|
|
|
2017-06-18 14:46:08 -04:00
|
|
|
if project and project != self.autosavePath:
|
2017-06-23 07:41:11 -04:00
|
|
|
if not project.endswith('.avp'):
|
|
|
|
project += '.avp'
|
2017-06-18 14:46:08 -04:00
|
|
|
# open a project from the commandline
|
|
|
|
if not os.path.dirname(project):
|
2017-06-25 15:31:42 -04:00
|
|
|
project = os.path.join(
|
|
|
|
self.settings.value("projectDir"), project
|
|
|
|
)
|
2017-06-18 14:46:08 -04:00
|
|
|
self.currentProject = project
|
|
|
|
self.settings.setValue("currentProject", project)
|
|
|
|
if os.path.exists(self.autosavePath):
|
|
|
|
os.remove(self.autosavePath)
|
|
|
|
else:
|
|
|
|
# open the last currentProject from settings
|
|
|
|
self.currentProject = self.settings.value("currentProject")
|
|
|
|
|
|
|
|
# delete autosave if it's identical to this project
|
|
|
|
if self.autosaveExists(identical=True):
|
2017-06-06 11:14:39 -04:00
|
|
|
os.remove(self.autosavePath)
|
2017-06-18 14:46:08 -04:00
|
|
|
|
|
|
|
if self.currentProject and os.path.exists(self.autosavePath):
|
|
|
|
ch = self.showMessage(
|
|
|
|
msg="Restore unsaved changes in project '%s'?"
|
|
|
|
% os.path.basename(self.currentProject)[:-4],
|
|
|
|
showCancel=True)
|
|
|
|
if ch:
|
|
|
|
self.saveProjectChanges()
|
|
|
|
else:
|
|
|
|
os.remove(self.autosavePath)
|
|
|
|
|
2017-06-17 11:15:24 -04:00
|
|
|
self.openProject(self.currentProject, prompt=False)
|
2017-06-18 14:46:08 -04:00
|
|
|
self.drawPreview(True)
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-07-09 01:10:06 -04:00
|
|
|
# verify Pillow version
|
|
|
|
if not self.settings.value("pilMsgShown") \
|
|
|
|
and 'post' not in Image.PILLOW_VERSION:
|
|
|
|
self.showMessage(
|
|
|
|
msg="You are using the standard version of the "
|
|
|
|
"Python imaging library (Pillow %s). Upgrade "
|
|
|
|
"to the Pillow-SIMD fork to enable hardware accelerations "
|
|
|
|
"and export videos faster." % Image.PILLOW_VERSION
|
|
|
|
)
|
|
|
|
self.settings.setValue("pilMsgShown", True)
|
|
|
|
|
|
|
|
# verify Ffmpeg version
|
|
|
|
if not self.settings.value("ffmpegMsgShown"):
|
|
|
|
try:
|
|
|
|
with open(os.devnull, "w") as f:
|
|
|
|
ffmpegVers = checkOutput(
|
|
|
|
['ffmpeg', '-version'], stderr=f
|
|
|
|
)
|
|
|
|
goodVersion = str(ffmpegVers).split()[2].startswith('3')
|
|
|
|
except:
|
|
|
|
goodVersion = False
|
|
|
|
else:
|
|
|
|
goodVersion = True
|
|
|
|
|
|
|
|
if not goodVersion:
|
|
|
|
self.showMessage(
|
|
|
|
msg="You're using an old version of Ffmpeg. "
|
|
|
|
"Some features may not work as expected."
|
|
|
|
)
|
|
|
|
self.settings.setValue("ffmpegMsgShown", True)
|
|
|
|
|
2017-07-20 22:37:15 -04:00
|
|
|
# Hotkeys for projects
|
2017-06-23 18:38:05 -04:00
|
|
|
QtWidgets.QShortcut("Ctrl+S", self.window, self.saveCurrentProject)
|
|
|
|
QtWidgets.QShortcut("Ctrl+A", self.window, self.openSaveProjectDialog)
|
|
|
|
QtWidgets.QShortcut("Ctrl+O", self.window, self.openOpenProjectDialog)
|
|
|
|
QtWidgets.QShortcut("Ctrl+N", self.window, self.createNewProject)
|
2017-06-23 02:20:59 -04:00
|
|
|
|
2017-07-20 22:37:15 -04:00
|
|
|
# Hotkeys for component list
|
|
|
|
for inskey in ("Ctrl+T", QtCore.Qt.Key_Insert):
|
|
|
|
QtWidgets.QShortcut(
|
|
|
|
inskey, self.window,
|
|
|
|
activated=lambda: self.window.pushButton_addComponent.click()
|
|
|
|
)
|
|
|
|
for delkey in ("Ctrl+R", QtCore.Qt.Key_Delete):
|
|
|
|
QtWidgets.QShortcut(
|
|
|
|
delkey, self.window.listWidget_componentList,
|
|
|
|
self.removeComponent
|
|
|
|
)
|
2017-06-23 23:00:24 -04:00
|
|
|
QtWidgets.QShortcut(
|
|
|
|
"Ctrl+Space", self.window,
|
|
|
|
activated=lambda: self.window.listWidget_componentList.setFocus()
|
|
|
|
)
|
|
|
|
QtWidgets.QShortcut(
|
|
|
|
"Ctrl+Shift+S", self.window,
|
|
|
|
self.presetManager.openSavePresetDialog
|
|
|
|
)
|
|
|
|
QtWidgets.QShortcut(
|
|
|
|
"Ctrl+Shift+C", self.window, self.presetManager.clearPreset
|
|
|
|
)
|
|
|
|
|
|
|
|
QtWidgets.QShortcut(
|
2017-07-20 22:37:15 -04:00
|
|
|
"Ctrl+Up", self.window.listWidget_componentList,
|
2017-06-23 23:00:24 -04:00
|
|
|
activated=lambda: self.moveComponent(-1)
|
|
|
|
)
|
|
|
|
QtWidgets.QShortcut(
|
2017-07-20 22:37:15 -04:00
|
|
|
"Ctrl+Down", self.window.listWidget_componentList,
|
2017-06-23 23:00:24 -04:00
|
|
|
activated=lambda: self.moveComponent(1)
|
|
|
|
)
|
2017-07-20 20:31:38 -04:00
|
|
|
QtWidgets.QShortcut(
|
2017-07-20 22:37:15 -04:00
|
|
|
"Ctrl+Home", self.window.listWidget_componentList,
|
2017-07-20 20:31:38 -04:00
|
|
|
activated=lambda: self.moveComponent('top')
|
|
|
|
)
|
|
|
|
QtWidgets.QShortcut(
|
2017-07-20 22:37:15 -04:00
|
|
|
"Ctrl+End", self.window.listWidget_componentList,
|
2017-07-20 20:31:38 -04:00
|
|
|
activated=lambda: self.moveComponent('bottom')
|
|
|
|
)
|
2017-07-20 22:37:15 -04:00
|
|
|
|
|
|
|
# Debug Hotkeys
|
|
|
|
QtWidgets.QShortcut(
|
|
|
|
"Ctrl+Alt+Shift+R", self.window, self.drawPreview
|
|
|
|
)
|
|
|
|
QtWidgets.QShortcut(
|
|
|
|
"Ctrl+Alt+Shift+F", self.window, self.showFfmpegCommand
|
|
|
|
)
|
2017-06-23 02:20:59 -04:00
|
|
|
|
2017-07-06 12:40:03 -04:00
|
|
|
@QtCore.pyqtSlot()
|
2017-06-06 11:14:39 -04:00
|
|
|
def cleanUp(self):
|
|
|
|
self.timer.stop()
|
|
|
|
self.previewThread.quit()
|
|
|
|
self.previewThread.wait()
|
|
|
|
|
2017-06-17 11:15:24 -04:00
|
|
|
def updateWindowTitle(self):
|
|
|
|
appName = 'Audio Visualizer'
|
2017-06-25 10:36:32 -04:00
|
|
|
try:
|
|
|
|
if self.currentProject:
|
|
|
|
appName += ' - %s' % \
|
|
|
|
os.path.splitext(
|
|
|
|
os.path.basename(self.currentProject))[0]
|
|
|
|
if self.autosaveExists(identical=False):
|
|
|
|
appName += '*'
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
2017-06-17 11:15:24 -04:00
|
|
|
self.window.setWindowTitle(appName)
|
|
|
|
|
2017-06-13 22:47:18 -04:00
|
|
|
@QtCore.pyqtSlot(int, dict)
|
|
|
|
def updateComponentTitle(self, pos, presetStore=False):
|
|
|
|
if type(presetStore) == dict:
|
|
|
|
name = presetStore['preset']
|
2017-06-23 23:00:24 -04:00
|
|
|
if name is None or name not in self.core.savedPresets:
|
2017-06-13 22:47:18 -04:00
|
|
|
modified = False
|
|
|
|
else:
|
|
|
|
modified = (presetStore != self.core.savedPresets[name])
|
|
|
|
else:
|
|
|
|
modified = bool(presetStore)
|
2017-06-08 16:50:48 -04:00
|
|
|
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
|
2017-06-12 22:34:37 -04:00
|
|
|
if modified:
|
|
|
|
title += '*'
|
2017-06-08 16:50:48 -04:00
|
|
|
self.window.listWidget_componentList.item(pos).setText(title)
|
|
|
|
|
2017-06-07 12:59:59 -04:00
|
|
|
def updateCodecs(self):
|
|
|
|
containerWidget = self.window.comboBox_videoContainer
|
|
|
|
vCodecWidget = self.window.comboBox_videoCodec
|
|
|
|
aCodecWidget = self.window.comboBox_audioCodec
|
|
|
|
index = containerWidget.currentIndex()
|
|
|
|
name = containerWidget.itemText(index)
|
|
|
|
self.settings.setValue('outputContainer', name)
|
|
|
|
|
|
|
|
vCodecWidget.clear()
|
|
|
|
aCodecWidget.clear()
|
|
|
|
|
2017-07-20 20:31:38 -04:00
|
|
|
for container in Core.encoderOptions['containers']:
|
2017-06-07 12:59:59 -04:00
|
|
|
if container['name'] == name:
|
|
|
|
for vCodec in container['video-codecs']:
|
|
|
|
vCodecWidget.addItem(vCodec)
|
|
|
|
for aCodec in container['audio-codecs']:
|
|
|
|
aCodecWidget.addItem(aCodec)
|
|
|
|
|
|
|
|
def updateCodecSettings(self):
|
2017-07-20 20:31:38 -04:00
|
|
|
'''Updates settings.ini to match encoder option widgets'''
|
2017-06-07 12:59:59 -04:00
|
|
|
vCodecWidget = self.window.comboBox_videoCodec
|
2017-06-07 13:33:22 -04:00
|
|
|
vBitrateWidget = self.window.spinBox_vBitrate
|
|
|
|
aBitrateWidget = self.window.spinBox_aBitrate
|
2017-06-07 12:59:59 -04:00
|
|
|
aCodecWidget = self.window.comboBox_audioCodec
|
|
|
|
currentVideoCodec = vCodecWidget.currentIndex()
|
|
|
|
currentVideoCodec = vCodecWidget.itemText(currentVideoCodec)
|
2017-06-07 13:33:22 -04:00
|
|
|
currentVideoBitrate = vBitrateWidget.value()
|
2017-06-07 12:59:59 -04:00
|
|
|
currentAudioCodec = aCodecWidget.currentIndex()
|
|
|
|
currentAudioCodec = aCodecWidget.itemText(currentAudioCodec)
|
2017-06-07 13:33:22 -04:00
|
|
|
currentAudioBitrate = aBitrateWidget.value()
|
2017-06-07 12:59:59 -04:00
|
|
|
self.settings.setValue('outputVideoCodec', currentVideoCodec)
|
|
|
|
self.settings.setValue('outputAudioCodec', currentAudioCodec)
|
2017-06-07 13:33:22 -04:00
|
|
|
self.settings.setValue('outputVideoBitrate', currentVideoBitrate)
|
|
|
|
self.settings.setValue('outputAudioBitrate', currentAudioBitrate)
|
2017-06-07 12:59:59 -04:00
|
|
|
|
2017-06-17 11:15:24 -04:00
|
|
|
def autosave(self, force=False):
|
2017-06-08 16:50:48 -04:00
|
|
|
if not self.currentProject:
|
2017-06-06 11:14:39 -04:00
|
|
|
if os.path.exists(self.autosavePath):
|
|
|
|
os.remove(self.autosavePath)
|
2017-07-20 20:31:38 -04:00
|
|
|
elif force or time.time() - self.lastAutosave >= 0.2:
|
2017-06-25 14:27:56 -04:00
|
|
|
self.core.createProjectFile(self.autosavePath, self.window)
|
2017-06-06 11:14:39 -04:00
|
|
|
self.lastAutosave = time.time()
|
|
|
|
|
2017-06-17 11:15:24 -04:00
|
|
|
def autosaveExists(self, identical=True):
|
2017-07-20 20:31:38 -04:00
|
|
|
'''Determines if creating the autosave should be blocked.'''
|
2017-06-18 14:46:08 -04:00
|
|
|
try:
|
|
|
|
if self.currentProject and os.path.exists(self.autosavePath) \
|
|
|
|
and filecmp.cmp(
|
|
|
|
self.autosavePath, self.currentProject) == identical:
|
|
|
|
return True
|
|
|
|
except FileNotFoundError:
|
|
|
|
print('project file couldn\'t be located:', self.currentProject)
|
|
|
|
return identical
|
2017-06-17 11:15:24 -04:00
|
|
|
return False
|
|
|
|
|
|
|
|
def saveProjectChanges(self):
|
2017-07-20 20:31:38 -04:00
|
|
|
'''Overwrites project file with autosave file'''
|
2017-06-23 07:41:11 -04:00
|
|
|
try:
|
|
|
|
os.remove(self.currentProject)
|
|
|
|
os.rename(self.autosavePath, self.currentProject)
|
|
|
|
return True
|
|
|
|
except (FileNotFoundError, IsADirectoryError) as e:
|
|
|
|
self.showMessage(
|
|
|
|
msg='Project file couldn\'t be saved.',
|
|
|
|
detail=str(e))
|
|
|
|
return False
|
2017-06-08 16:50:48 -04:00
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
def openInputFileDialog(self):
|
2017-06-17 19:08:18 -04:00
|
|
|
inputDir = self.settings.value("inputDir", os.path.expanduser("~"))
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-06-23 23:00:24 -04:00
|
|
|
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(
|
2017-06-17 19:08:18 -04:00
|
|
|
self.window, "Open Audio File",
|
2017-07-20 20:31:38 -04:00
|
|
|
inputDir, "Audio Files (%s)" % " ".join(Core.audioFormats))
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-06-23 23:00:24 -04:00
|
|
|
if fileName:
|
2017-06-06 11:14:39 -04:00
|
|
|
self.settings.setValue("inputDir", os.path.dirname(fileName))
|
|
|
|
self.window.lineEdit_audioFile.setText(fileName)
|
|
|
|
|
|
|
|
def openOutputFileDialog(self):
|
2017-06-17 19:08:18 -04:00
|
|
|
outputDir = self.settings.value("outputDir", os.path.expanduser("~"))
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-06-23 23:00:24 -04:00
|
|
|
fileName, _ = QtWidgets.QFileDialog.getSaveFileName(
|
2017-06-06 11:14:39 -04:00
|
|
|
self.window, "Set Output Video File",
|
2017-06-15 15:09:45 -04:00
|
|
|
outputDir,
|
2017-06-23 23:00:24 -04:00
|
|
|
"Video Files (%s);; All Files (*)" % " ".join(
|
2017-07-20 20:31:38 -04:00
|
|
|
Core.videoFormats))
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-06-25 10:36:32 -04:00
|
|
|
if fileName:
|
2017-06-06 11:14:39 -04:00
|
|
|
self.settings.setValue("outputDir", os.path.dirname(fileName))
|
|
|
|
self.window.lineEdit_outputFile.setText(fileName)
|
|
|
|
|
|
|
|
def stopVideo(self):
|
|
|
|
print('stop')
|
|
|
|
self.videoWorker.cancel()
|
|
|
|
self.canceled = True
|
|
|
|
|
|
|
|
def createAudioVisualisation(self):
|
|
|
|
# create output video if mandatory settings are filled in
|
2017-06-25 10:36:32 -04:00
|
|
|
audioFile = self.window.lineEdit_audioFile.text()
|
|
|
|
outputPath = self.window.lineEdit_outputFile.text()
|
|
|
|
|
|
|
|
if audioFile and outputPath and self.core.selectedComponents:
|
2017-06-17 19:08:18 -04:00
|
|
|
if not os.path.dirname(outputPath):
|
|
|
|
outputPath = os.path.join(
|
|
|
|
os.path.expanduser("~"), outputPath)
|
2017-06-25 10:36:32 -04:00
|
|
|
if outputPath and os.path.isdir(outputPath):
|
|
|
|
self.showMessage(
|
|
|
|
msg='Chosen filename matches a directory, which '
|
|
|
|
'cannot be overwritten. Please choose a different '
|
2017-06-25 15:31:42 -04:00
|
|
|
'filename or move the directory.',
|
|
|
|
icon='Warning',
|
2017-06-25 10:36:32 -04:00
|
|
|
)
|
|
|
|
return
|
2017-06-06 11:14:39 -04:00
|
|
|
else:
|
2017-06-25 10:36:32 -04:00
|
|
|
if not audioFile or not outputPath:
|
|
|
|
self.showMessage(
|
|
|
|
msg="You must select an audio file and output filename."
|
|
|
|
)
|
|
|
|
elif not self.core.selectedComponents:
|
|
|
|
self.showMessage(
|
|
|
|
msg="Not enough components."
|
|
|
|
)
|
|
|
|
return
|
|
|
|
|
|
|
|
self.canceled = False
|
|
|
|
self.progressBarUpdated(-1)
|
2017-07-15 01:00:03 -04:00
|
|
|
self.videoWorker = self.core.newVideoWorker(
|
|
|
|
self, audioFile, outputPath
|
|
|
|
)
|
2017-06-25 10:36:32 -04:00
|
|
|
self.videoWorker.progressBarUpdate.connect(self.progressBarUpdated)
|
|
|
|
self.videoWorker.progressBarSetText.connect(
|
|
|
|
self.progressBarSetText)
|
|
|
|
self.videoWorker.imageCreated.connect(self.showPreviewImage)
|
|
|
|
self.videoWorker.encoding.connect(self.changeEncodingStatus)
|
2017-07-15 01:00:03 -04:00
|
|
|
self.createVideo.emit()
|
2017-06-06 11:14:39 -04:00
|
|
|
|
|
|
|
def changeEncodingStatus(self, status):
|
2017-06-25 10:36:32 -04:00
|
|
|
self.encoding = status
|
2017-06-06 11:14:39 -04:00
|
|
|
if status:
|
|
|
|
self.window.pushButton_createVideo.setEnabled(False)
|
|
|
|
self.window.pushButton_Cancel.setEnabled(True)
|
|
|
|
self.window.comboBox_resolution.setEnabled(False)
|
|
|
|
self.window.stackedWidget.setEnabled(False)
|
|
|
|
self.window.tab_encoderSettings.setEnabled(False)
|
|
|
|
self.window.label_audioFile.setEnabled(False)
|
|
|
|
self.window.toolButton_selectAudioFile.setEnabled(False)
|
|
|
|
self.window.label_outputFile.setEnabled(False)
|
|
|
|
self.window.toolButton_selectOutputFile.setEnabled(False)
|
|
|
|
self.window.lineEdit_audioFile.setEnabled(False)
|
|
|
|
self.window.lineEdit_outputFile.setEnabled(False)
|
|
|
|
self.window.pushButton_addComponent.setEnabled(False)
|
|
|
|
self.window.pushButton_removeComponent.setEnabled(False)
|
|
|
|
self.window.pushButton_listMoveDown.setEnabled(False)
|
|
|
|
self.window.pushButton_listMoveUp.setEnabled(False)
|
2017-06-17 19:08:18 -04:00
|
|
|
self.window.menuButton_newProject.setEnabled(False)
|
|
|
|
self.window.menuButton_openProject.setEnabled(False)
|
2017-06-25 23:05:44 -04:00
|
|
|
if sys.platform == 'darwin':
|
|
|
|
self.window.progressLabel.setHidden(False)
|
|
|
|
else:
|
|
|
|
self.window.listWidget_componentList.setEnabled(False)
|
2017-06-06 11:14:39 -04:00
|
|
|
else:
|
|
|
|
self.window.pushButton_createVideo.setEnabled(True)
|
|
|
|
self.window.pushButton_Cancel.setEnabled(False)
|
|
|
|
self.window.comboBox_resolution.setEnabled(True)
|
|
|
|
self.window.stackedWidget.setEnabled(True)
|
|
|
|
self.window.tab_encoderSettings.setEnabled(True)
|
|
|
|
self.window.label_audioFile.setEnabled(True)
|
|
|
|
self.window.toolButton_selectAudioFile.setEnabled(True)
|
|
|
|
self.window.lineEdit_audioFile.setEnabled(True)
|
|
|
|
self.window.label_outputFile.setEnabled(True)
|
|
|
|
self.window.toolButton_selectOutputFile.setEnabled(True)
|
|
|
|
self.window.lineEdit_outputFile.setEnabled(True)
|
|
|
|
self.window.pushButton_addComponent.setEnabled(True)
|
|
|
|
self.window.pushButton_removeComponent.setEnabled(True)
|
|
|
|
self.window.pushButton_listMoveDown.setEnabled(True)
|
|
|
|
self.window.pushButton_listMoveUp.setEnabled(True)
|
2017-06-17 19:08:18 -04:00
|
|
|
self.window.menuButton_newProject.setEnabled(True)
|
|
|
|
self.window.menuButton_openProject.setEnabled(True)
|
2017-06-25 23:05:44 -04:00
|
|
|
self.window.listWidget_componentList.setEnabled(True)
|
|
|
|
self.window.progressLabel.setHidden(True)
|
2017-06-18 14:46:08 -04:00
|
|
|
self.drawPreview(True)
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-07-09 14:31:19 -04:00
|
|
|
@QtCore.pyqtSlot(int)
|
2017-06-12 22:34:37 -04:00
|
|
|
def progressBarUpdated(self, value):
|
|
|
|
self.window.progressBar_createVideo.setValue(value)
|
|
|
|
|
2017-07-09 14:31:19 -04:00
|
|
|
@QtCore.pyqtSlot(str)
|
2017-06-06 11:14:39 -04:00
|
|
|
def progressBarSetText(self, value):
|
2017-06-25 23:05:44 -04:00
|
|
|
if sys.platform == 'darwin':
|
|
|
|
self.window.progressLabel.setText(value)
|
|
|
|
else:
|
|
|
|
self.window.progressBar_createVideo.setFormat(value)
|
2017-06-06 11:14:39 -04:00
|
|
|
|
|
|
|
def updateResolution(self):
|
2017-06-07 12:59:59 -04:00
|
|
|
resIndex = int(self.window.comboBox_resolution.currentIndex())
|
2017-06-06 11:14:39 -04:00
|
|
|
res = self.resolutions[resIndex].split('x')
|
|
|
|
self.settings.setValue('outputWidth', res[0])
|
|
|
|
self.settings.setValue('outputHeight', res[1])
|
|
|
|
self.drawPreview()
|
|
|
|
|
2017-06-17 11:15:24 -04:00
|
|
|
def drawPreview(self, force=False):
|
2017-06-08 09:56:57 -04:00
|
|
|
self.newTask.emit(self.core.selectedComponents)
|
2017-06-06 11:14:39 -04:00
|
|
|
# self.processTask.emit()
|
2017-06-17 11:15:24 -04:00
|
|
|
self.autosave(force)
|
2017-06-24 23:40:32 -04:00
|
|
|
self.updateWindowTitle()
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-07-13 00:05:11 -04:00
|
|
|
@QtCore.pyqtSlot(QtGui.QImage)
|
2017-06-06 11:14:39 -04:00
|
|
|
def showPreviewImage(self, image):
|
|
|
|
self.previewWindow.changePixmap(image)
|
|
|
|
|
2017-07-16 23:13:00 -04:00
|
|
|
def showFfmpegCommand(self):
|
|
|
|
from textwrap import wrap
|
2017-07-20 20:31:38 -04:00
|
|
|
from toolkit.ffmpeg import createFfmpegCommand
|
|
|
|
command = createFfmpegCommand(
|
2017-07-16 23:13:00 -04:00
|
|
|
self.window.lineEdit_audioFile.text(),
|
|
|
|
self.window.lineEdit_outputFile.text(),
|
2017-07-20 20:31:38 -04:00
|
|
|
self.core.selectedComponents
|
2017-07-16 23:13:00 -04:00
|
|
|
)
|
|
|
|
lines = wrap(" ".join(command), 49)
|
|
|
|
self.showMessage(
|
|
|
|
msg="Current FFmpeg command:\n\n %s" % " ".join(lines)
|
|
|
|
)
|
|
|
|
|
2017-06-18 14:46:08 -04:00
|
|
|
def insertComponent(self, index):
|
2017-06-08 09:56:57 -04:00
|
|
|
componentList = self.window.listWidget_componentList
|
2017-06-08 16:50:48 -04:00
|
|
|
stackedWidget = self.window.stackedWidget
|
2017-06-17 11:15:24 -04:00
|
|
|
|
2017-06-18 14:46:08 -04:00
|
|
|
componentList.insertItem(
|
2017-06-08 09:56:57 -04:00
|
|
|
index,
|
2017-07-20 20:31:38 -04:00
|
|
|
self.core.selectedComponents[index].name)
|
2017-06-08 09:56:57 -04:00
|
|
|
componentList.setCurrentRow(index)
|
|
|
|
|
2017-06-12 22:34:37 -04:00
|
|
|
# connect to signal that adds an asterisk when modified
|
|
|
|
self.core.selectedComponents[index].modified.connect(
|
|
|
|
self.updateComponentTitle)
|
|
|
|
|
2017-06-18 14:46:08 -04:00
|
|
|
self.pages.insert(index, self.core.selectedComponents[index].page)
|
2017-06-08 16:50:48 -04:00
|
|
|
stackedWidget.insertWidget(index, self.pages[index])
|
|
|
|
stackedWidget.setCurrentIndex(index)
|
|
|
|
|
2017-06-17 11:15:24 -04:00
|
|
|
return index
|
2017-06-06 11:14:39 -04:00
|
|
|
|
|
|
|
def removeComponent(self):
|
2017-06-08 16:50:48 -04:00
|
|
|
componentList = self.window.listWidget_componentList
|
|
|
|
|
|
|
|
for selected in componentList.selectedItems():
|
|
|
|
index = componentList.row(selected)
|
2017-06-06 11:14:39 -04:00
|
|
|
self.window.stackedWidget.removeWidget(self.pages[index])
|
2017-06-08 16:50:48 -04:00
|
|
|
componentList.takeItem(index)
|
2017-06-12 22:34:37 -04:00
|
|
|
self.core.removeComponent(index)
|
2017-06-06 11:14:39 -04:00
|
|
|
self.pages.pop(index)
|
|
|
|
self.changeComponentWidget()
|
|
|
|
self.drawPreview()
|
|
|
|
|
2017-06-25 20:43:06 -04:00
|
|
|
@disableWhenEncoding
|
2017-06-08 16:50:48 -04:00
|
|
|
def moveComponent(self, change):
|
|
|
|
'''Moves a component relatively from its current position'''
|
|
|
|
componentList = self.window.listWidget_componentList
|
2017-07-20 20:31:38 -04:00
|
|
|
if change == 'top':
|
|
|
|
change = -componentList.currentRow()
|
|
|
|
elif change == 'bottom':
|
|
|
|
change = len(componentList)-componentList.currentRow()-1
|
2017-06-08 16:50:48 -04:00
|
|
|
stackedWidget = self.window.stackedWidget
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-06-08 16:50:48 -04:00
|
|
|
row = componentList.currentRow()
|
|
|
|
newRow = row + change
|
|
|
|
if newRow > -1 and newRow < componentList.count():
|
|
|
|
self.core.moveComponent(row, newRow)
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-06-08 09:56:57 -04:00
|
|
|
# update widgets
|
2017-06-08 16:50:48 -04:00
|
|
|
page = self.pages.pop(row)
|
|
|
|
self.pages.insert(newRow, page)
|
2017-06-08 09:56:57 -04:00
|
|
|
item = componentList.takeItem(row)
|
2017-06-08 16:50:48 -04:00
|
|
|
newItem = componentList.insertItem(newRow, item)
|
2017-06-08 09:56:57 -04:00
|
|
|
widget = stackedWidget.removeWidget(page)
|
2017-06-08 16:50:48 -04:00
|
|
|
stackedWidget.insertWidget(newRow, page)
|
|
|
|
componentList.setCurrentRow(newRow)
|
|
|
|
stackedWidget.setCurrentIndex(newRow)
|
2017-06-06 11:14:39 -04:00
|
|
|
self.drawPreview()
|
2017-06-08 16:50:48 -04:00
|
|
|
|
2017-07-20 22:37:15 -04:00
|
|
|
def getComponentListRects(self):
|
2017-06-15 23:13:36 -04:00
|
|
|
componentList = self.window.listWidget_componentList
|
|
|
|
|
2017-06-23 23:00:24 -04:00
|
|
|
modelIndexes = [
|
|
|
|
componentList.model().index(i)
|
|
|
|
for i in range(componentList.count())
|
2017-06-15 23:13:36 -04:00
|
|
|
]
|
2017-06-23 23:00:24 -04:00
|
|
|
rects = [
|
|
|
|
componentList.visualRect(modelIndex)
|
|
|
|
for modelIndex in modelIndexes
|
2017-06-15 23:13:36 -04:00
|
|
|
]
|
2017-07-20 22:37:15 -04:00
|
|
|
return rects
|
|
|
|
|
|
|
|
@disableWhenEncoding
|
|
|
|
def dragComponent(self, event):
|
|
|
|
'''Used as Qt drop event for the component listwidget'''
|
|
|
|
componentList = self.window.listWidget_componentList
|
|
|
|
rects = self.getComponentListRects()
|
2017-06-15 23:13:36 -04:00
|
|
|
|
|
|
|
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)
|
2017-06-08 16:50:48 -04:00
|
|
|
|
|
|
|
def changeComponentWidget(self):
|
|
|
|
selected = self.window.listWidget_componentList.selectedItems()
|
|
|
|
if selected:
|
|
|
|
index = self.window.listWidget_componentList.row(selected[0])
|
|
|
|
self.window.stackedWidget.setCurrentIndex(index)
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-06-07 15:32:05 -04:00
|
|
|
def openPresetManager(self):
|
2017-06-07 20:30:37 -04:00
|
|
|
'''Preset manager for importing, exporting, renaming, deleting'''
|
|
|
|
self.presetManager.show()
|
2017-06-07 15:32:05 -04:00
|
|
|
|
2017-06-08 16:50:48 -04:00
|
|
|
def clear(self):
|
|
|
|
'''Get a blank slate'''
|
2017-06-17 11:15:24 -04:00
|
|
|
self.core.clearComponents()
|
2017-06-07 17:09:28 -04:00
|
|
|
self.window.listWidget_componentList.clear()
|
|
|
|
for widget in self.pages:
|
|
|
|
self.window.stackedWidget.removeWidget(widget)
|
|
|
|
self.pages = []
|
2017-06-25 14:27:56 -04:00
|
|
|
for field in (
|
|
|
|
self.window.lineEdit_audioFile,
|
|
|
|
self.window.lineEdit_outputFile
|
|
|
|
):
|
|
|
|
field.blockSignals(True)
|
|
|
|
field.setText('')
|
|
|
|
field.blockSignals(False)
|
2017-06-08 16:50:48 -04:00
|
|
|
|
2017-06-25 10:36:32 -04:00
|
|
|
@disableWhenEncoding
|
2017-06-25 18:12:16 -04:00
|
|
|
def createNewProject(self, prompt=True):
|
|
|
|
if prompt:
|
|
|
|
self.openSaveChangesDialog('starting a new project')
|
2017-06-08 16:50:48 -04:00
|
|
|
|
|
|
|
self.clear()
|
|
|
|
self.currentProject = None
|
2017-06-07 17:09:28 -04:00
|
|
|
self.settings.setValue("currentProject", None)
|
2017-06-17 11:15:24 -04:00
|
|
|
self.drawPreview(True)
|
2017-06-07 15:32:05 -04:00
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
def saveCurrentProject(self):
|
|
|
|
if self.currentProject:
|
2017-06-25 14:27:56 -04:00
|
|
|
self.core.createProjectFile(self.currentProject, self.window)
|
2017-07-11 06:06:22 -04:00
|
|
|
try:
|
|
|
|
os.remove(self.autosavePath)
|
|
|
|
except FileNotFoundError:
|
|
|
|
pass
|
2017-06-24 23:40:32 -04:00
|
|
|
self.updateWindowTitle()
|
2017-06-06 11:14:39 -04:00
|
|
|
else:
|
|
|
|
self.openSaveProjectDialog()
|
|
|
|
|
2017-06-17 11:15:24 -04:00
|
|
|
def openSaveChangesDialog(self, phrase):
|
2017-06-23 07:41:11 -04:00
|
|
|
success = True
|
2017-06-17 11:15:24 -04:00
|
|
|
if self.autosaveExists(identical=False):
|
|
|
|
ch = self.showMessage(
|
|
|
|
msg="You have unsaved changes in project '%s'. "
|
2017-06-23 23:00:24 -04:00
|
|
|
"Save before %s?" % (
|
|
|
|
os.path.basename(self.currentProject)[:-4],
|
|
|
|
phrase
|
|
|
|
),
|
2017-06-17 11:15:24 -04:00
|
|
|
showCancel=True)
|
|
|
|
if ch:
|
2017-06-23 07:41:11 -04:00
|
|
|
success = self.saveProjectChanges()
|
2017-06-17 11:15:24 -04:00
|
|
|
|
2017-06-23 07:41:11 -04:00
|
|
|
if success and os.path.exists(self.autosavePath):
|
2017-06-17 11:15:24 -04:00
|
|
|
os.remove(self.autosavePath)
|
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
def openSaveProjectDialog(self):
|
2017-06-23 23:00:24 -04:00
|
|
|
filename, _ = QtWidgets.QFileDialog.getSaveFileName(
|
2017-06-06 11:14:39 -04:00
|
|
|
self.window, "Create Project File",
|
|
|
|
self.settings.value("projectDir"),
|
|
|
|
"Project Files (*.avp)")
|
|
|
|
if not filename:
|
|
|
|
return
|
2017-06-13 22:47:18 -04:00
|
|
|
if not filename.endswith(".avp"):
|
|
|
|
filename += '.avp'
|
2017-06-10 14:52:01 -04:00
|
|
|
self.settings.setValue("projectDir", os.path.dirname(filename))
|
|
|
|
self.settings.setValue("currentProject", filename)
|
|
|
|
self.currentProject = filename
|
2017-06-25 14:27:56 -04:00
|
|
|
self.core.createProjectFile(filename, self.window)
|
2017-06-24 23:40:32 -04:00
|
|
|
self.updateWindowTitle()
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2017-06-25 10:36:32 -04:00
|
|
|
@disableWhenEncoding
|
2017-06-06 11:14:39 -04:00
|
|
|
def openOpenProjectDialog(self):
|
2017-06-23 23:00:24 -04:00
|
|
|
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
|
2017-06-06 11:14:39 -04:00
|
|
|
self.window, "Open Project File",
|
|
|
|
self.settings.value("projectDir"),
|
|
|
|
"Project Files (*.avp)")
|
|
|
|
self.openProject(filename)
|
|
|
|
|
2017-06-17 11:15:24 -04:00
|
|
|
def openProject(self, filepath, prompt=True):
|
2017-06-06 11:14:39 -04:00
|
|
|
if not filepath or not os.path.exists(filepath) \
|
|
|
|
or not filepath.endswith('.avp'):
|
|
|
|
return
|
2017-06-17 11:15:24 -04:00
|
|
|
|
2017-06-08 16:50:48 -04:00
|
|
|
self.clear()
|
2017-06-17 11:15:24 -04:00
|
|
|
# ask to save any changes that are about to get deleted
|
|
|
|
if prompt:
|
|
|
|
self.openSaveChangesDialog('opening another project')
|
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
self.currentProject = filepath
|
|
|
|
self.settings.setValue("currentProject", filepath)
|
|
|
|
self.settings.setValue("projectDir", os.path.dirname(filepath))
|
2017-06-11 23:29:13 -04:00
|
|
|
# actually load the project using core method
|
|
|
|
self.core.openProject(self, filepath)
|
2017-06-17 11:15:24 -04:00
|
|
|
if self.window.listWidget_componentList.count() == 0:
|
|
|
|
self.drawPreview()
|
|
|
|
self.autosave(True)
|
2017-06-25 10:36:32 -04:00
|
|
|
self.updateWindowTitle()
|
2017-06-11 23:29:13 -04:00
|
|
|
|
2017-06-07 20:30:37 -04:00
|
|
|
def showMessage(self, **kwargs):
|
2017-06-10 12:10:05 -04:00
|
|
|
parent = kwargs['parent'] if 'parent' in kwargs else self.window
|
2017-06-23 23:00:24 -04:00
|
|
|
msg = QtWidgets.QMessageBox(parent)
|
2017-06-10 12:10:05 -04:00
|
|
|
msg.setModal(True)
|
2017-06-07 20:30:37 -04:00
|
|
|
msg.setText(kwargs['msg'])
|
2017-06-07 23:22:55 -04:00
|
|
|
msg.setIcon(
|
2017-06-25 14:27:56 -04:00
|
|
|
eval('QtWidgets.QMessageBox.%s' % kwargs['icon'])
|
2017-06-23 23:00:24 -04:00
|
|
|
if 'icon' in kwargs else QtWidgets.QMessageBox.Information
|
|
|
|
)
|
2017-06-07 20:30:37 -04:00
|
|
|
msg.setDetailedText(kwargs['detail'] if 'detail' in kwargs else None)
|
|
|
|
if 'showCancel'in kwargs and kwargs['showCancel']:
|
2017-06-06 11:14:39 -04:00
|
|
|
msg.setStandardButtons(
|
2017-06-23 23:00:24 -04:00
|
|
|
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
|
2017-06-06 11:14:39 -04:00
|
|
|
else:
|
2017-06-23 23:00:24 -04:00
|
|
|
msg.setStandardButtons(QtWidgets.QMessageBox.Ok)
|
2017-06-06 11:14:39 -04:00
|
|
|
ch = msg.exec_()
|
|
|
|
if ch == 1024:
|
|
|
|
return True
|
|
|
|
return False
|
2017-06-07 20:30:37 -04:00
|
|
|
|
2017-06-25 20:43:06 -04:00
|
|
|
@disableWhenEncoding
|
2017-06-07 20:30:37 -04:00
|
|
|
def componentContextMenu(self, QPos):
|
2017-07-20 22:37:15 -04:00
|
|
|
'''Appears when right-clicking the component list'''
|
2017-06-11 12:52:29 -04:00
|
|
|
componentList = self.window.listWidget_componentList
|
|
|
|
index = componentList.currentRow()
|
2017-06-07 23:22:55 -04:00
|
|
|
|
2017-06-23 23:00:24 -04:00
|
|
|
self.menu = QMenu()
|
2017-07-20 22:37:15 -04:00
|
|
|
parentPosition = componentList.mapToGlobal(QtCore.QPoint(0, 0))
|
2017-06-07 23:22:55 -04:00
|
|
|
|
2017-07-20 22:37:15 -04:00
|
|
|
rects = self.getComponentListRects()
|
|
|
|
rowPos = [rect.contains(QPos) for rect in rects]
|
|
|
|
if not any(rowPos):
|
|
|
|
# Insert components at the top if clicking nothing
|
|
|
|
rowPos = 0
|
|
|
|
else:
|
|
|
|
rowPos = rowPos.index(True)
|
|
|
|
|
|
|
|
if index == rowPos:
|
|
|
|
# Show preset menu if clicking a component
|
|
|
|
self.presetManager.findPresets()
|
|
|
|
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.presetSubmenu = QMenu("Open Preset")
|
|
|
|
self.menu.addMenu(self.presetSubmenu)
|
|
|
|
|
|
|
|
for version, presetName in presets:
|
|
|
|
menuItem = self.presetSubmenu.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")
|
2017-06-11 12:52:29 -04:00
|
|
|
menuItem.triggered.connect(
|
2017-07-20 22:37:15 -04:00
|
|
|
self.presetManager.clearPreset
|
2017-06-07 23:22:55 -04:00
|
|
|
)
|
2017-07-20 22:37:15 -04:00
|
|
|
self.menu.addSeparator()
|
2017-06-11 12:52:29 -04:00
|
|
|
|
2017-07-20 22:37:15 -04:00
|
|
|
# "Add Component" submenu
|
|
|
|
self.submenu = QMenu("Add")
|
|
|
|
self.menu.addMenu(self.submenu)
|
|
|
|
for i, comp in enumerate(self.core.modules):
|
|
|
|
menuItem = self.submenu.addAction(comp.Component.name)
|
2017-06-15 23:13:36 -04:00
|
|
|
menuItem.triggered.connect(
|
2017-07-20 22:37:15 -04:00
|
|
|
lambda _, item=i: self.core.insertComponent(
|
|
|
|
rowPos, item, self
|
|
|
|
)
|
|
|
|
)
|
2017-06-15 11:36:26 -04:00
|
|
|
|
2017-06-07 20:30:37 -04:00
|
|
|
self.menu.move(parentPosition + QPos)
|
|
|
|
self.menu.show()
|