add component in context menu, del/ins hotkeys
+ preset manager uses mainwindow component list
This commit is contained in:
parent
f454814867
commit
450b944b87
|
@ -2,7 +2,7 @@ from cx_Freeze import setup, Executable
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from setup import VERSION
|
from setup import __version__
|
||||||
|
|
||||||
|
|
||||||
deps = [os.path.join('src', p) for p in os.listdir('src') if p]
|
deps = [os.path.join('src', p) for p in os.listdir('src') if p]
|
||||||
|
@ -52,7 +52,7 @@ executables = [
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='audio-visualizer-python',
|
name='audio-visualizer-python',
|
||||||
version=VERSION,
|
version=__version__,
|
||||||
description='GUI tool to render visualization videos of audio files',
|
description='GUI tool to render visualization videos of audio files',
|
||||||
options=dict(build_exe=buildOptions),
|
options=dict(build_exe=buildOptions),
|
||||||
executables=executables
|
executables=executables
|
||||||
|
|
4
setup.py
4
setup.py
|
@ -2,7 +2,7 @@ from setuptools import setup
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
VERSION = '2.0.0.rc1'
|
__version__ = '2.0.0.rc1'
|
||||||
|
|
||||||
|
|
||||||
def package_files(directory):
|
def package_files(directory):
|
||||||
|
@ -15,7 +15,7 @@ def package_files(directory):
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='audio_visualizer_python',
|
name='audio_visualizer_python',
|
||||||
version=VERSION,
|
version=__version__,
|
||||||
url='https://github.com/djfun/audio-visualizer-python/tree/feature-newgui',
|
url='https://github.com/djfun/audio-visualizer-python/tree/feature-newgui',
|
||||||
license='MIT',
|
license='MIT',
|
||||||
description='Create audio visualization videos from a GUI or commandline',
|
description='Create audio visualization videos from a GUI or commandline',
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -16,7 +16,7 @@ class Video:
|
||||||
'''Video Component Frame-Fetcher'''
|
'''Video Component Frame-Fetcher'''
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
mandatoryArgs = [
|
mandatoryArgs = [
|
||||||
'ffmpeg', # path to ffmpeg, usually core.FFMPEG_BIN
|
'ffmpeg', # path to ffmpeg, usually Core.FFMPEG_BIN
|
||||||
'videoPath',
|
'videoPath',
|
||||||
'width',
|
'width',
|
||||||
'height',
|
'height',
|
||||||
|
@ -28,7 +28,7 @@ class Video:
|
||||||
]
|
]
|
||||||
for arg in mandatoryArgs:
|
for arg in mandatoryArgs:
|
||||||
try:
|
try:
|
||||||
exec('self.%s = kwargs[arg]' % arg)
|
setattr(self, arg, kwargs[arg])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise BadComponentInit(arg, self.__doc__)
|
raise BadComponentInit(arg, self.__doc__)
|
||||||
|
|
||||||
|
|
10
src/core.py
10
src/core.py
|
@ -15,16 +15,14 @@ import video_thread
|
||||||
class Core:
|
class Core:
|
||||||
'''
|
'''
|
||||||
MainWindow and Command module both use an instance of this class
|
MainWindow and Command module both use an instance of this class
|
||||||
to store the main program state. This object tracks the components
|
to store the core program state. This object tracks the components,
|
||||||
as an instance, has methods for managing the components and for
|
talks to the components and handles opening/creating project files
|
||||||
opening/creating project files and presets.
|
and presets. The class also stores constants as class variables.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def storeSettings(cls):
|
def storeSettings(cls):
|
||||||
'''
|
'''Store settings/paths to directories as class variables.'''
|
||||||
Stores settings/paths to directories as class variables
|
|
||||||
'''
|
|
||||||
if getattr(sys, 'frozen', False):
|
if getattr(sys, 'frozen', False):
|
||||||
# frozen
|
# frozen
|
||||||
wd = os.path.dirname(sys.executable)
|
wd = os.path.dirname(sys.executable)
|
||||||
|
|
|
@ -178,7 +178,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
|
|
||||||
# Make component buttons
|
# Make component buttons
|
||||||
self.compMenu = QMenu()
|
self.compMenu = QMenu()
|
||||||
self.compActions = []
|
|
||||||
for i, comp in enumerate(self.core.modules):
|
for i, comp in enumerate(self.core.modules):
|
||||||
action = self.compMenu.addAction(comp.Component.name)
|
action = self.compMenu.addAction(comp.Component.name)
|
||||||
action.triggered.connect(
|
action.triggered.connect(
|
||||||
|
@ -191,6 +190,9 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
componentList.itemSelectionChanged.connect(
|
componentList.itemSelectionChanged.connect(
|
||||||
self.changeComponentWidget
|
self.changeComponentWidget
|
||||||
)
|
)
|
||||||
|
componentList.itemSelectionChanged.connect(
|
||||||
|
self.presetManager.clearPresetListSelection
|
||||||
|
)
|
||||||
self.window.pushButton_removeComponent.clicked.connect(
|
self.window.pushButton_removeComponent.clicked.connect(
|
||||||
lambda: self.removeComponent()
|
lambda: self.removeComponent()
|
||||||
)
|
)
|
||||||
|
@ -313,22 +315,23 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
)
|
)
|
||||||
self.settings.setValue("ffmpegMsgShown", True)
|
self.settings.setValue("ffmpegMsgShown", True)
|
||||||
|
|
||||||
# Setup Hotkeys
|
# Hotkeys for projects
|
||||||
QtWidgets.QShortcut("Ctrl+S", self.window, self.saveCurrentProject)
|
QtWidgets.QShortcut("Ctrl+S", self.window, self.saveCurrentProject)
|
||||||
QtWidgets.QShortcut("Ctrl+A", self.window, self.openSaveProjectDialog)
|
QtWidgets.QShortcut("Ctrl+A", self.window, self.openSaveProjectDialog)
|
||||||
QtWidgets.QShortcut("Ctrl+O", self.window, self.openOpenProjectDialog)
|
QtWidgets.QShortcut("Ctrl+O", self.window, self.openOpenProjectDialog)
|
||||||
QtWidgets.QShortcut("Ctrl+N", self.window, self.createNewProject)
|
QtWidgets.QShortcut("Ctrl+N", self.window, self.createNewProject)
|
||||||
QtWidgets.QShortcut(
|
|
||||||
"Ctrl+Alt+Shift+R", self.window, self.drawPreview
|
|
||||||
)
|
|
||||||
QtWidgets.QShortcut(
|
|
||||||
"Ctrl+Alt+Shift+F", self.window, self.showFfmpegCommand
|
|
||||||
)
|
|
||||||
|
|
||||||
|
# Hotkeys for component list
|
||||||
|
for inskey in ("Ctrl+T", QtCore.Qt.Key_Insert):
|
||||||
QtWidgets.QShortcut(
|
QtWidgets.QShortcut(
|
||||||
"Ctrl+T", self.window,
|
inskey, self.window,
|
||||||
activated=lambda: self.window.pushButton_addComponent.click()
|
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
|
||||||
|
)
|
||||||
QtWidgets.QShortcut(
|
QtWidgets.QShortcut(
|
||||||
"Ctrl+Space", self.window,
|
"Ctrl+Space", self.window,
|
||||||
activated=lambda: self.window.listWidget_componentList.setFocus()
|
activated=lambda: self.window.listWidget_componentList.setFocus()
|
||||||
|
@ -342,22 +345,29 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
)
|
)
|
||||||
|
|
||||||
QtWidgets.QShortcut(
|
QtWidgets.QShortcut(
|
||||||
"Ctrl+Up", self.window,
|
"Ctrl+Up", self.window.listWidget_componentList,
|
||||||
activated=lambda: self.moveComponent(-1)
|
activated=lambda: self.moveComponent(-1)
|
||||||
)
|
)
|
||||||
QtWidgets.QShortcut(
|
QtWidgets.QShortcut(
|
||||||
"Ctrl+Down", self.window,
|
"Ctrl+Down", self.window.listWidget_componentList,
|
||||||
activated=lambda: self.moveComponent(1)
|
activated=lambda: self.moveComponent(1)
|
||||||
)
|
)
|
||||||
QtWidgets.QShortcut(
|
QtWidgets.QShortcut(
|
||||||
"Ctrl+Home", self.window,
|
"Ctrl+Home", self.window.listWidget_componentList,
|
||||||
activated=lambda: self.moveComponent('top')
|
activated=lambda: self.moveComponent('top')
|
||||||
)
|
)
|
||||||
QtWidgets.QShortcut(
|
QtWidgets.QShortcut(
|
||||||
"Ctrl+End", self.window,
|
"Ctrl+End", self.window.listWidget_componentList,
|
||||||
activated=lambda: self.moveComponent('bottom')
|
activated=lambda: self.moveComponent('bottom')
|
||||||
)
|
)
|
||||||
QtWidgets.QShortcut("Ctrl+r", self.window, self.removeComponent)
|
|
||||||
|
# Debug Hotkeys
|
||||||
|
QtWidgets.QShortcut(
|
||||||
|
"Ctrl+Alt+Shift+R", self.window, self.drawPreview
|
||||||
|
)
|
||||||
|
QtWidgets.QShortcut(
|
||||||
|
"Ctrl+Alt+Shift+F", self.window, self.showFfmpegCommand
|
||||||
|
)
|
||||||
|
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def cleanUp(self):
|
def cleanUp(self):
|
||||||
|
@ -677,9 +687,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
stackedWidget.setCurrentIndex(newRow)
|
stackedWidget.setCurrentIndex(newRow)
|
||||||
self.drawPreview()
|
self.drawPreview()
|
||||||
|
|
||||||
@disableWhenEncoding
|
def getComponentListRects(self):
|
||||||
def dragComponent(self, event):
|
|
||||||
'''Used as Qt drop event for the component listwidget'''
|
|
||||||
componentList = self.window.listWidget_componentList
|
componentList = self.window.listWidget_componentList
|
||||||
|
|
||||||
modelIndexes = [
|
modelIndexes = [
|
||||||
|
@ -690,6 +698,13 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
componentList.visualRect(modelIndex)
|
componentList.visualRect(modelIndex)
|
||||||
for modelIndex in modelIndexes
|
for modelIndex in modelIndexes
|
||||||
]
|
]
|
||||||
|
return rects
|
||||||
|
|
||||||
|
@disableWhenEncoding
|
||||||
|
def dragComponent(self, event):
|
||||||
|
'''Used as Qt drop event for the component listwidget'''
|
||||||
|
componentList = self.window.listWidget_componentList
|
||||||
|
rects = self.getComponentListRects()
|
||||||
|
|
||||||
rowPos = [rect.contains(event.pos()) for rect in rects]
|
rowPos = [rect.contains(event.pos()) for rect in rects]
|
||||||
if not any(rowPos):
|
if not any(rowPos):
|
||||||
|
@ -826,20 +841,24 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
|
|
||||||
@disableWhenEncoding
|
@disableWhenEncoding
|
||||||
def componentContextMenu(self, QPos):
|
def componentContextMenu(self, QPos):
|
||||||
'''Appears when right-clicking a component in the list'''
|
'''Appears when right-clicking the component list'''
|
||||||
componentList = self.window.listWidget_componentList
|
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()
|
index = componentList.currentRow()
|
||||||
modelIndex = componentList.model().index(index)
|
|
||||||
if not componentList.visualRect(modelIndex).contains(QPos):
|
|
||||||
return
|
|
||||||
|
|
||||||
self.presetManager.findPresets()
|
|
||||||
self.menu = QMenu()
|
self.menu = QMenu()
|
||||||
|
parentPosition = componentList.mapToGlobal(QtCore.QPoint(0, 0))
|
||||||
|
|
||||||
|
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 = self.menu.addAction("Save Preset")
|
||||||
menuItem.triggered.connect(
|
menuItem.triggered.connect(
|
||||||
self.presetManager.openSavePresetDialog
|
self.presetManager.openSavePresetDialog
|
||||||
|
@ -850,11 +869,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
presets = self.presetManager.presets[
|
presets = self.presetManager.presets[
|
||||||
str(self.core.selectedComponents[index])
|
str(self.core.selectedComponents[index])
|
||||||
]
|
]
|
||||||
self.submenu = QMenu("Open Preset")
|
self.presetSubmenu = QMenu("Open Preset")
|
||||||
self.menu.addMenu(self.submenu)
|
self.menu.addMenu(self.presetSubmenu)
|
||||||
|
|
||||||
for version, presetName in presets:
|
for version, presetName in presets:
|
||||||
menuItem = self.submenu.addAction(presetName)
|
menuItem = self.presetSubmenu.addAction(presetName)
|
||||||
menuItem.triggered.connect(
|
menuItem.triggered.connect(
|
||||||
lambda _, presetName=presetName:
|
lambda _, presetName=presetName:
|
||||||
self.presetManager.openPreset(presetName)
|
self.presetManager.openPreset(presetName)
|
||||||
|
@ -867,6 +886,18 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
menuItem.triggered.connect(
|
menuItem.triggered.connect(
|
||||||
self.presetManager.clearPreset
|
self.presetManager.clearPreset
|
||||||
)
|
)
|
||||||
|
self.menu.addSeparator()
|
||||||
|
|
||||||
|
# "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)
|
||||||
|
menuItem.triggered.connect(
|
||||||
|
lambda _, item=i: self.core.insertComponent(
|
||||||
|
rowPos, item, self
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
self.menu.move(parentPosition + QPos)
|
self.menu.move(parentPosition + QPos)
|
||||||
self.menu.show()
|
self.menu.show()
|
||||||
|
|
|
@ -245,11 +245,25 @@ class PresetManager(QtWidgets.QDialog):
|
||||||
def openRenamePresetDialog(self):
|
def openRenamePresetDialog(self):
|
||||||
# TODO: maintain consistency by changing this to call createNewPreset()
|
# TODO: maintain consistency by changing this to call createNewPreset()
|
||||||
presetList = self.window.listWidget_presets
|
presetList = self.window.listWidget_presets
|
||||||
if presetList.currentRow() == -1:
|
index = presetList.currentRow()
|
||||||
|
if index == -1:
|
||||||
|
# check if component selected in MainWindow has preset loaded
|
||||||
|
componentList = self.parent.window.listWidget_componentList
|
||||||
|
compIndex = componentList.currentRow()
|
||||||
|
if compIndex == -1:
|
||||||
|
return
|
||||||
|
preset = self.core.selectedComponents[compIndex].currentPreset
|
||||||
|
if not preset:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
for i, tup in enumerate(self.presetRows):
|
||||||
|
if preset == tup[2]:
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
index = presetList.currentRow()
|
|
||||||
newName, OK = QtWidgets.QInputDialog.getText(
|
newName, OK = QtWidgets.QInputDialog.getText(
|
||||||
self.window,
|
self.window,
|
||||||
'Preset Manager',
|
'Preset Manager',
|
||||||
|
@ -321,3 +335,6 @@ class PresetManager(QtWidgets.QDialog):
|
||||||
parent=self.window
|
parent=self.window
|
||||||
)
|
)
|
||||||
self.settings.setValue("presetDir", os.path.dirname(filename))
|
self.settings.setValue("presetDir", os.path.dirname(filename))
|
||||||
|
|
||||||
|
def clearPresetListSelection(self):
|
||||||
|
self.window.listWidget_presets.setCurrentRow(-1)
|
||||||
|
|
|
@ -113,7 +113,7 @@ def createFfmpegCommand(inputFile, outputFile, components, duration=-1):
|
||||||
'-t', safeDuration,
|
'-t', safeDuration,
|
||||||
# Tell ffmpeg about shorter clips (seemingly not needed)
|
# Tell ffmpeg about shorter clips (seemingly not needed)
|
||||||
# streamDuration = getAudioDuration(extraInputFile)
|
# streamDuration = getAudioDuration(extraInputFile)
|
||||||
# if streamDuration > float(safeDuration)
|
# if streamDuration and streamDuration > float(safeDuration)
|
||||||
# else "{0:.3f}".format(streamDuration),
|
# else "{0:.3f}".format(streamDuration),
|
||||||
'-i', extraInputFile
|
'-i', extraInputFile
|
||||||
])
|
])
|
||||||
|
@ -228,11 +228,18 @@ def getAudioDuration(filename):
|
||||||
d = d.split(' ')[3]
|
d = d.split(' ')[3]
|
||||||
d = d.split(':')
|
d = d.split(':')
|
||||||
duration = float(d[0])*3600 + float(d[1])*60 + float(d[2])
|
duration = float(d[0])*3600 + float(d[1])*60 + float(d[2])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# String not found in output
|
||||||
|
return False
|
||||||
return duration
|
return duration
|
||||||
|
|
||||||
|
|
||||||
def readAudioFile(filename, parent):
|
def readAudioFile(filename, parent):
|
||||||
duration = getAudioDuration(filename)
|
duration = getAudioDuration(filename)
|
||||||
|
if not duration:
|
||||||
|
print('Audio file doesn\'t exist or unreadable.')
|
||||||
|
return
|
||||||
|
|
||||||
command = [
|
command = [
|
||||||
Core.FFMPEG_BIN,
|
Core.FFMPEG_BIN,
|
||||||
|
|
Reference in New Issue