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