You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
406 lines
31 KiB
406 lines
31 KiB
#! /usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net )
|
|
|
|
This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),
|
|
|
|
This is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
"""
|
|
import logging; logger = logging.getLogger(__name__); logger.info("import")
|
|
|
|
#Standard Library Modules
|
|
|
|
#Third Party Modules
|
|
from PyQt5 import QtWidgets, QtCore, QtGui
|
|
|
|
#Template Modules
|
|
from template.qtgui.mainwindow import MainWindow as TemplateMainWindow
|
|
from template.qtgui.menu import Menu
|
|
from template.qtgui.about import About
|
|
|
|
#User modules
|
|
import engine.api as api
|
|
from .scoreview import ScoreView
|
|
from .verticalpiano import VerticalPiano
|
|
from .velocityview import VelocityView
|
|
from .constantsAndConfigs import constantsAndConfigs
|
|
from .submenus import *
|
|
|
|
class MainWindow(TemplateMainWindow):
|
|
|
|
#Undo/Redo Translations in our api
|
|
QtCore.QT_TRANSLATE_NOOP("NOOPengineHistory", "Record Events")
|
|
QtCore.QT_TRANSLATE_NOOP("NOOPengineHistory", "Delete Events")
|
|
QtCore.QT_TRANSLATE_NOOP("NOOPengineHistory", "Insert Events")
|
|
QtCore.QT_TRANSLATE_NOOP("NOOPengineHistory", "Create Event")
|
|
QtCore.QT_TRANSLATE_NOOP("NOOPengineHistory", "Move Events")
|
|
QtCore.QT_TRANSLATE_NOOP("NOOPengineHistory", "Reposition Events")
|
|
QtCore.QT_TRANSLATE_NOOP("NOOPengineHistory", "Change Byte1")
|
|
QtCore.QT_TRANSLATE_NOOP("NOOPengineHistory", "Change Byte2")
|
|
QtCore.QT_TRANSLATE_NOOP("NOOPengineHistory", "Free Text")
|
|
|
|
|
|
def __init__(self):
|
|
"""The order of calls is very important.
|
|
The split ploint is calling the super.__init. Some functions need to be called before,
|
|
some after.
|
|
For example:
|
|
|
|
The about dialog is created in the template main window init. So we need to set additional
|
|
help texts before that init.
|
|
"""
|
|
|
|
#Inject more help texts in the templates About "Did You Know" field.
|
|
#About.didYouKnow is a class variable.
|
|
#Make the first three words matter!
|
|
#Do not start them all with "You can..." or "...that you can", in response to the Did you know? title.
|
|
#We use injection into the class and not a parameter because this dialog gets shown by creating an object. We can't give the parameters when this is shown via the mainWindow menu.
|
|
About.didYouKnow = [
|
|
QtCore.QCoreApplication.translate("About", "Every command can be found in the menus, except mouse commands: Wheel=Scroll up/down, Shift+Wheel=Scroll left/right, Ctrl+Wheel=zoom, Ctrl+Shift+Wheel=scale duration. During moving events: Hold Ctrl to move only up/down, hold Alt to move only left/right."),
|
|
QtCore.QCoreApplication.translate("About", "Most command require a selection. There is no editing for single events, e.g. under the cursor."),
|
|
QtCore.QCoreApplication.translate("About", "All events can have a custom text annotation. Right click on any event to edit."),
|
|
QtCore.QCoreApplication.translate("About", "Snap to grid has effect on placing notes and events and moving them around."),
|
|
QtCore.QCoreApplication.translate("About", "Use the middle mouse button to pre-listen to a note through your connected instrument."),
|
|
QtCore.QCoreApplication.translate("About", "All midi notes will be forwarded to connected instruments on the layers channel."),
|
|
QtCore.QCoreApplication.translate("About", "Use layer colors to keep the overview."),
|
|
QtCore.QCoreApplication.translate("About", "Only selected notes will show in the velocity view."),
|
|
QtCore.QCoreApplication.translate("About", "Use the mousewheel on notes in the velocity view to change individual volume, no matter the current selection."),
|
|
QtCore.QCoreApplication.translate("About", "Clearing the selection with your right mouse button is the safest and quickest way."),
|
|
QtCore.QCoreApplication.translate("About", "You will never run out of space. Vico can record as long as your system is capable."),
|
|
QtCore.QCoreApplication.translate("About", "The selection remembers event from all layers."),
|
|
QtCore.QCoreApplication.translate("About", "Commands that work on selected events (e.g. increase velocity) will work on all selected evens on all layers."),
|
|
QtCore.QCoreApplication.translate("About", "Pasting (Ctrl+V) inserts events at the same position. If you paste to the same layer the new items are on top and need to be moved manually."),
|
|
QtCore.QCoreApplication.translate("About", "Setting Snap To Grid to eighths or sixteenths notes is usually a good compromise between robust input and rhythmic flexibility."),
|
|
] + About.didYouKnow
|
|
|
|
super().__init__()
|
|
|
|
#Set up the main widgets
|
|
self.scoreView = ScoreView(self)
|
|
self.ui.grid.addWidget(self.scoreView, 0, 1)
|
|
|
|
|
|
self.verticalPiano = VerticalPiano(self)
|
|
self.ui.grid.addWidget(self.verticalPiano, 0, 0)
|
|
#Sync the vertical verticalPiano scrollbar (which is never shown) with the scoreView scrollbar.
|
|
self.scoreView.setVerticalScrollBar(self.verticalPiano.verticalScrollBar()) #this seems backwards, but it is correct :)
|
|
|
|
self.velocityView = VelocityView(self)
|
|
self.ui.grid.addWidget(self.velocityView, 1, 1)
|
|
self.velocityView.setHorizontalScrollBar(self.scoreView.horizontalScrollBar()) #this seems backwards, but it is correct :)
|
|
|
|
self.barBeatTempo = BarBeatTempoClock(self)
|
|
self.ui.grid.addWidget(self.barBeatTempo, 1, 0)
|
|
self.barBeatTempo.setFixedWidth(self.verticalPiano.geometry().width()-1)
|
|
|
|
#The statusbar is intended for tooltips. To make it permanent we add our own widget
|
|
self.statusLabel = QtWidgets.QLabel()
|
|
self.statusBar().insertPermanentWidget(0, self.statusLabel)
|
|
|
|
self.createMenu() #in its own function for readability
|
|
|
|
|
|
#Callbacks
|
|
self._cachedSongDuration = None
|
|
api.callbacks.songDurationChanged.append(self._cacheSongDuration)
|
|
api.callbacks.recordingModeChanged.append(self.ui.actionToggleRecordingMode.setChecked)
|
|
api.callbacks.activeLayerChanged.append(self.updateStatusBar)
|
|
api.callbacks.layerMidiChannelChanged.append(self.updateStatusBar)
|
|
|
|
|
|
#Initial Setup
|
|
if not "lastCCtype" in api.session.guiSharedDataToSave:
|
|
api.session.guiSharedDataToSave["lastCCtype"] = 0x07
|
|
if not "lastPolyphonicAftertouchNote" in api.session.guiSharedDataToSave:
|
|
api.session.guiSharedDataToSave["lastPolyphonicAftertouchNote"] = 60
|
|
|
|
self.setInsert("actionSetInsertFree", 0x90, None) #Free note drawing mode.
|
|
self.setSnapToGrid("actionSetSnapFree", 1)
|
|
self.setContextMenuPolicy(QtCore.Qt.NoContextMenu) #Make toolbars unclosable by preventing the main window from having context menus.
|
|
#self.scoreView.setFocus() #So the user can start typing from moment 0.
|
|
self.start() #This shows the GUI, or not, depends on the NSM gui save setting. We need to call that after the menu, otherwise the about dialog will block and then we get new menu entries, which looks strange.
|
|
|
|
#There is so much going on in the engine, we never reach a save status on load.
|
|
#Here is the crowbar-method.
|
|
self.nsmClient.announceSaveStatus(isClean = True)
|
|
|
|
def updateStatusBar(self, *args):
|
|
t = QtCore.QCoreApplication.translate("mainwindow", "Active Layer: {layer}, Midi Channel: {channel}").format(layer=api.getActiveLayer(), channel=api.getActiveMidiChannel())
|
|
self.statusLabel.setText(t)
|
|
|
|
def _cacheSongDuration(self, firstEvent:int, lastEvent:int):
|
|
"""We save the actual tick value, not the pixel value.
|
|
toEndAndView uses backend ticks directly"""
|
|
self._cachedFirstEvent = firstEvent
|
|
self._cachedSongDuration = lastEvent
|
|
|
|
def toStartAndView(self):
|
|
api.toStart()
|
|
self.scoreView.centerOnPlayhead()
|
|
|
|
def toEndAndView(self):
|
|
api.seek(self._cachedSongDuration)
|
|
self.scoreView.centerOnPlayhead()
|
|
|
|
def toFirstAndView(self):
|
|
api.seek(self._cachedFirstEvent)
|
|
self.scoreView.centerOnPlayhead()
|
|
|
|
def chooseActiveLayerMidiChannel(self):
|
|
h = QtCore.QCoreApplication.translate("mainwindow", "Choose Midi Channel")
|
|
t = QtCore.QCoreApplication.translate("mainwindow", "Choose Midi Channel for active Layer")
|
|
result, ok = QtWidgets.QInputDialog.getInt(self, h, t, value=api.getActiveMidiChannel(), min=1, max=16)
|
|
if ok:
|
|
api.setLayerMidiChannel(api.getActiveLayer(), result)
|
|
|
|
def chooseActiveLayerColor(self):
|
|
qcolor = QtWidgets.QColorDialog.getColor() #returns QColor
|
|
if (qcolor.isValid()):
|
|
hexString = qcolor.name()
|
|
api.setLayerColor(api.getActiveLayer(), hexString)
|
|
|
|
def playFromMouseCursor(self):
|
|
p = self.scoreView.mousePosAsTickposition()
|
|
api.playFrom(p)
|
|
|
|
def toggleFollowPlayhead(self):
|
|
"""A GUI only setting. Has no callbacks involved"""
|
|
constantsAndConfigs.followPlayhead = not constantsAndConfigs.followPlayhead
|
|
self.ui.actionFollowPlayhead.setChecked(constantsAndConfigs.followPlayhead)
|
|
|
|
def toggleRhythmEnabled(self):
|
|
newState = self.scoreView.scoreScene.grid.toggleRhythmEnabled()
|
|
self.ui.actionShowRhythmLines.setChecked(newState)
|
|
|
|
def setKeyboardEnabled(self, state:bool):
|
|
if state:
|
|
self.menu.enable()
|
|
else:
|
|
self.menu.disable()
|
|
|
|
def zoom(self, scaleFactor:float):
|
|
"""Scale factor is absolute"""
|
|
|
|
self.verticalPiano.zoom(scaleFactor)
|
|
self.velocityView.zoom(scaleFactor)
|
|
self.scoreView.zoom(scaleFactor) #call scoreView as last one because it sets the scrollbars
|
|
|
|
height = min(self.ui.centralwidget.geometry().height()-self.velocityView.geometry().height()-5, constantsAndConfigs.scoreHeight*constantsAndConfigs.zoomFactor)
|
|
self.verticalPiano.setFixedHeight(height)
|
|
self.scoreView.setFixedHeight(height)
|
|
|
|
def stretchXCoordinates(self, factor:float):
|
|
self.scoreView.stretchXCoordinates(factor)
|
|
self.velocityView.stretchXCoordinates(factor)
|
|
|
|
def selectionChanged(self, listOfEngineIdsAndLayers:list):
|
|
"""Only scoreView creates and manipulates selections, but other widgets,
|
|
like VelocityView, need to know what the selection is. We call a mainWindow function to let
|
|
them know and use engineIDs for item identifiers and give a layerIndex, too"""
|
|
self.velocityView.velocityScene.selectionChanged(listOfEngineIdsAndLayers)
|
|
|
|
def highlight(self, layerIndex:int, noteOnEngineId:int, state:bool):
|
|
"""Highlight an item. We take a roundtrip over the mainwindow to have access to all
|
|
parallel views, now and for future extensions"""
|
|
#we skip the views.
|
|
self.scoreView.scoreScene.highlight(layerIndex, noteOnEngineId, state)
|
|
self.velocityView.velocityScene.highlight(layerIndex, noteOnEngineId, state)
|
|
|
|
def toggleDottedNotes(self):
|
|
#self.ui.actionSetInsertToggleDot.setChecked(self.ui.actionSetInsertToggleDot.isChecked())
|
|
self.scoreView.scoreScene.inputCursor.setDottedNotes(self.ui.actionSetInsertToggleDot.isChecked())
|
|
|
|
def setInsert(self, callingAction:str, status:int, duration:int=None):
|
|
"""
|
|
duration is only needed if status=0x90.
|
|
|
|
Notes:
|
|
None is free mode. Otherwise it is api durations.
|
|
|
|
If a selection exists quantise the selected note with it.
|
|
If no selection exists make the mouse cursor a quantised note "stamp".
|
|
|
|
Default is free mode."""
|
|
|
|
allActions = (
|
|
self.ui.actionSetInsertD1,
|
|
self.ui.actionSetInsertD2,
|
|
self.ui.actionSetInsertD4,
|
|
self.ui.actionSetInsertD8,
|
|
self.ui.actionSetInsertD16,
|
|
self.ui.actionSetInsertD32,
|
|
self.ui.actionSetInsertFree,
|
|
self.ui.actionSetPolyphonicAftertouch,
|
|
self.ui.actionSetInsertCC,
|
|
self.ui.actionSetInsertPitchBend,
|
|
self.ui.actionSetInsertChannelPressure,
|
|
self.ui.actionSetInsertProgramChange,
|
|
)
|
|
|
|
for action in allActions:
|
|
action.setChecked(False)
|
|
menuAction = getattr(self.ui, callingAction)
|
|
menuAction.setChecked(True)
|
|
|
|
if callingAction == "actionSetInsertCC":
|
|
CCSubmenu(mainWindow=self) #saves to the GUI storage dict in session.
|
|
elif callingAction == "actionSetPolyphonicAftertouch":
|
|
PolyAfterTouchSubmenu(mainWindow=self) #saves to the GUI storage dict in session.
|
|
|
|
self.scoreView.scoreScene.inputCursor.setMode(callingAction)
|
|
|
|
def setSnapToGrid(self, callingAction:str, duration:int):
|
|
"""One of them is always active
|
|
Duration None is special, that triggers the dot and does not change the other mods"""
|
|
if duration is None:
|
|
constantsAndConfigs.snapToDot = self.ui.actionSetSnapDot.isChecked()
|
|
#Modify the existing duration. We assume the dot is exactly the opposite of before.
|
|
if constantsAndConfigs.snapToDot:
|
|
constantsAndConfigs.snapToGrid = 1.5 * constantsAndConfigs.snapToGrid
|
|
else:
|
|
constantsAndConfigs.snapToGrid = constantsAndConfigs.snapToGrid / 1.5
|
|
return
|
|
|
|
else:
|
|
duration = duration / constantsAndConfigs.ticksToPixelRatio
|
|
#When setting a fresh duration check if the dot is present.
|
|
if constantsAndConfigs.snapToDot:
|
|
duration = 1.5 * duration
|
|
constantsAndConfigs.snapToGrid = duration
|
|
|
|
allActions = (
|
|
self.ui.actionSetSnapD1,
|
|
self.ui.actionSetSnapD2,
|
|
self.ui.actionSetSnapD4,
|
|
self.ui.actionSetSnapD8,
|
|
self.ui.actionSetSnapD16,
|
|
self.ui.actionSetSnapD32,
|
|
self.ui.actionSetSnapFree,
|
|
)
|
|
|
|
for action in allActions:
|
|
action.setChecked(False)
|
|
menuAction = getattr(self.ui, callingAction)
|
|
menuAction.setChecked(True)
|
|
|
|
|
|
def createMenu(self):
|
|
|
|
#New menu entries and template-menu overrides
|
|
self.menu.addSubmenu("menuGeneric", "generic")
|
|
self.menu.hideSubmenu("menuGeneric")
|
|
|
|
self.menu.addMenuEntry("menuEdit", "actionToggleRecordingMode", QtCore.QCoreApplication.translate("menu", "Toggle Recording Mode"), api.toggleRecordingMode, shortcut="r")
|
|
self.ui.actionToggleRecordingMode.setCheckable(True) #Checked via callback
|
|
self.menu.addMenuEntry("menuEdit", "actionFollowPlayhead", QtCore.QCoreApplication.translate("menu", "Follow Playhead"), self.toggleFollowPlayhead , shortcut="f")
|
|
self.ui.actionFollowPlayhead.setCheckable(True) #no callbacks. Just the menu entry alone.
|
|
self.ui.actionFollowPlayhead.setChecked(constantsAndConfigs.followPlayhead)
|
|
self.menu.addMenuEntry("menuEdit", "actionShowRhythmLines", QtCore.QCoreApplication.translate("menu", "Show Rhythm Lines In Grid"), self.toggleRhythmEnabled , shortcut="l")
|
|
self.ui.actionShowRhythmLines.setCheckable(True)
|
|
self.ui.actionShowRhythmLines.setChecked(True)
|
|
self.menu.addSeparator("menuEdit")
|
|
self.menu.addMenuEntry("menuEdit", "actionSelectActiveLayer", QtCore.QCoreApplication.translate("menu", "Select Active Layer"), self.scoreView.scoreScene.selectActiveLayer , shortcut="Ctrl+A")
|
|
self.menu.addMenuEntry("menuEdit", "actionSelectAll", QtCore.QCoreApplication.translate("menu","Select All Events"), self.scoreView.scoreScene.selectAll , shortcut="Ctrl+Shift+A")
|
|
self.menu.addSeparator("menuEdit")
|
|
self.menu.addMenuEntry("menuEdit", "actionMoveSelectionUp", QtCore.QCoreApplication.translate("menu","Move Selection Up"), lambda: self.scoreView.scoreScene.moveSelectedItemsRelative(1) , shortcut="Up")
|
|
self.menu.addMenuEntry("menuEdit", "actionMoveSelectionDown", QtCore.QCoreApplication.translate("menu","Move Selection Down"), lambda: self.scoreView.scoreScene.moveSelectedItemsRelative(-1) , shortcut="Down")
|
|
self.menu.addMenuEntry("menuEdit", "actionMoveSelectionLeft", QtCore.QCoreApplication.translate("menu","Move Selection Left"), lambda: self.scoreView.scoreScene.repositionSelectedItemsRelative(-1*api.D32) , shortcut="Left")
|
|
self.menu.addMenuEntry("menuEdit", "actionMoveSelectionRight", QtCore.QCoreApplication.translate("menu","Move Selection Right"), lambda: self.scoreView.scoreScene.repositionSelectedItemsRelative(api.D32) , shortcut="Right")
|
|
self.menu.addSeparator("menuEdit")
|
|
self.menu.addMenuEntry("menuEdit", "actionVelocityPlus", QtCore.QCoreApplication.translate("menu","Velocity Louder"), lambda: self.scoreView.scoreScene.velocityChangeRelative(1) , shortcut="+")
|
|
self.menu.addMenuEntry("menuEdit", "actionVelocityMinus", QtCore.QCoreApplication.translate("menu","Velocity Softer"), lambda: self.scoreView.scoreScene.velocityChangeRelative(-1) , shortcut="-")
|
|
self.menu.addMenuEntry("menuEdit", "actionVelocitySubmenu", QtCore.QCoreApplication.translate("menu","Change Velocity of Selected Events"), lambda: VelocityChange(mainWindow=self), shortcut="v")
|
|
self.menu.addMenuEntry("menuEdit", "actionCompressVelocitySubmenu", QtCore.QCoreApplication.translate("menu","Compress Velocity of Selected Events"), lambda: CompressVelocity(mainWindow=self), shortcut="Shift+v" )
|
|
|
|
self.menu.addSeparator("menuEdit")
|
|
self.menu.addMenuEntry("menuEdit", "actionCopy", QtCore.QCoreApplication.translate("menu","Copy"), self.scoreView.scoreScene.copy , shortcut="Ctrl+C")
|
|
self.menu.addMenuEntry("menuEdit", "actionCut", QtCore.QCoreApplication.translate("menu","Cut"), self.scoreView.scoreScene.cut , shortcut="Ctrl+X")
|
|
self.menu.addMenuEntry("menuEdit", "actionPaste", QtCore.QCoreApplication.translate("menu","Paste"), self.scoreView.scoreScene.paste , shortcut="Ctrl+V")
|
|
self.menu.addMenuEntry("menuEdit", "actionDeleteSelection", QtCore.QCoreApplication.translate("menu","Delete Selected Events"), self.scoreView.scoreScene.deleteSelectedItems , shortcut="Delete")
|
|
|
|
self.menu.addSubmenu("menuNavigation", QtCore.QCoreApplication.translate("menu","Navigation"))
|
|
self.menu.addMenuEntry("menuNavigation", "actionPlayPause", QtCore.QCoreApplication.translate("menu","Play/Pause"), api.playPause, shortcut="Space")
|
|
self.menu.addMenuEntry("menuNavigation", "actionMousePos", QtCore.QCoreApplication.translate("menu","Play from Mouse Position"), self.playFromMouseCursor , shortcut="Ctrl+Space")
|
|
self.menu.addMenuEntry("menuNavigation", "actionToStart", QtCore.QCoreApplication.translate("menu","Jump to Start"), self.toStartAndView, shortcut="Home")
|
|
self.menu.addMenuEntry("menuNavigation", "actionToFirst", QtCore.QCoreApplication.translate("menu","Jump to First Event"), self.toFirstAndView, shortcut="Ctrl+Home")
|
|
self.menu.addMenuEntry("menuNavigation", "actionToEnd", QtCore.QCoreApplication.translate("menu","Jump to Last Event"), self.toEndAndView, shortcut="End")
|
|
self.menu.addMenuEntry("menuNavigation", "actionToPlayhead", QtCore.QCoreApplication.translate("menu","Center View on Playhead"), self.scoreView.centerOnPlayhead, shortcut="Insert")
|
|
|
|
self.menu.addSubmenu("menuInput", QtCore.QCoreApplication.translate("menu","Input"))
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertD1", QtCore.QCoreApplication.translate("menu","Whole Note Duration"), lambda: self.setInsert("actionSetInsertD1", 0x90, api.D1), shortcut="1", checkable=True)#, iconResource=":template/icons/wholeNote.png")
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertD2", QtCore.QCoreApplication.translate("menu","Half Note Duration") , lambda: self.setInsert("actionSetInsertD2", 0x90, api.D2), shortcut="2", checkable=True)
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertD4", QtCore.QCoreApplication.translate("menu","Quarter Note Duration"), lambda: self.setInsert("actionSetInsertD4", 0x90, api.D4), shortcut="3", checkable=True)
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertD8", QtCore.QCoreApplication.translate("menu","8th Note Duration") , lambda: self.setInsert("actionSetInsertD8", 0x90, api.D8), shortcut="4", checkable=True)
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertD16", QtCore.QCoreApplication.translate("menu","16th Note Duration") , lambda: self.setInsert("actionSetInsertD16", 0x90, api.D16), shortcut="5", checkable=True)
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertD32", QtCore.QCoreApplication.translate("menu","32nd Note Duration") , lambda: self.setInsert("actionSetInsertD32", 0x90, api.D32), shortcut="6", checkable=True)
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertFree", QtCore.QCoreApplication.translate("menu","Free Duration") , lambda: self.setInsert("actionSetInsertFree", 0x90, None), shortcut="0", checkable=True)
|
|
self.menu.addSeparator("menuInput")
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertToggleDot", QtCore.QCoreApplication.translate("menu","Dotted Notes (x 1.5)") , self.toggleDottedNotes, shortcut="q", checkable=True)
|
|
|
|
self.menu.addSeparator("menuInput")
|
|
self.menu.addMenuEntry("menuInput", "actionSetPolyphonicAftertouch", QtCore.QCoreApplication.translate("menu","Polyphonic Aftertouch") , lambda: self.setInsert("actionSetPolyphonicAftertouch", 0xA0), shortcut="a", checkable=True)
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertCC", QtCore.QCoreApplication.translate("menu","Control Change (CC)") , lambda: self.setInsert("actionSetInsertCC", 0xB0), shortcut="c", checkable=True)
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertProgramChange", QtCore.QCoreApplication.translate("menu","Program Change") , lambda: self.setInsert("actionSetInsertProgramChange", 0xC0), shortcut="p", checkable=True)
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertPitchBend", QtCore.QCoreApplication.translate("menu","Pitch Bend") , lambda: self.setInsert("actionSetInsertPitchBend", 0xC0), shortcut="b", checkable=True)
|
|
self.menu.addMenuEntry("menuInput", "actionSetInsertChannelPressure", QtCore.QCoreApplication.translate("menu","Channel Pressure") , lambda: self.setInsert("actionSetInsertChannelPressure", 0xC0), shortcut="x", checkable=True)
|
|
|
|
self.menu.addSubmenu("menuLayer", "Layer")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerColor", QtCore.QCoreApplication.translate("menu","Choose Color for Active Layer"), self.chooseActiveLayerColor)
|
|
self.menu.addMenuEntry("menuLayer", "activeLayerChannel", QtCore.QCoreApplication.translate("menu","Choose Midi Channel for Active Layer"), self.chooseActiveLayerMidiChannel)
|
|
|
|
self.menu.addSeparator("menuLayer")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayer1", QtCore.QCoreApplication.translate("menu","Layer 1"), lambda: api.chooseActiveLayer(1), shortcut="F1")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayer2", QtCore.QCoreApplication.translate("menu","Layer 2"), lambda: api.chooseActiveLayer(2), shortcut="F2")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayer3", QtCore.QCoreApplication.translate("menu","Layer 3"), lambda: api.chooseActiveLayer(3), shortcut="F3")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayer4", QtCore.QCoreApplication.translate("menu","Layer 4"), lambda: api.chooseActiveLayer(4), shortcut="F4")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayer5", QtCore.QCoreApplication.translate("menu","Layer 5"), lambda: api.chooseActiveLayer(5), shortcut="F5")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayer6", QtCore.QCoreApplication.translate("menu","Layer 6"), lambda: api.chooseActiveLayer(6), shortcut="F6")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayer7", QtCore.QCoreApplication.translate("menu", "Layer 7"), lambda: api.chooseActiveLayer(7), shortcut="F7")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayer8", QtCore.QCoreApplication.translate("menu","Layer 8"), lambda: api.chooseActiveLayer(8), shortcut="F8")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayer9", QtCore.QCoreApplication.translate("menu","Layer 9"), lambda: api.chooseActiveLayer(9), shortcut="F9")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayer0", QtCore.QCoreApplication.translate("menu","Layer 0"), lambda: api.chooseActiveLayer(0), shortcut="F10")
|
|
self.menu.addSeparator("menuLayer")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerShadowAll", QtCore.QCoreApplication.translate("menu","Show All Shadows"), self.scoreView.scoreScene.showAllShadows, shortcut="F12")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerShadow1", QtCore.QCoreApplication.translate("menu","Toggle Shadow 1"), lambda: self.scoreView.scoreScene.toggleShadowLayer(1), shortcut="Shift+F1")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerShadow2", QtCore.QCoreApplication.translate("menu","Toggle Shadow 2"), lambda: self.scoreView.scoreScene.toggleShadowLayer(2), shortcut="Shift+F2")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerShadow3", QtCore.QCoreApplication.translate("menu","Toggle Shadow 3"), lambda: self.scoreView.scoreScene.toggleShadowLayer(3), shortcut="Shift+F3")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerShadow4", QtCore.QCoreApplication.translate("menu","Toggle Shadow 4"), lambda: self.scoreView.scoreScene.toggleShadowLayer(4), shortcut="Shift+F4")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerShadow5", QtCore.QCoreApplication.translate("menu","Toggle Shadow 5"), lambda: self.scoreView.scoreScene.toggleShadowLayer(5), shortcut="Shift+F5")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerShadow6", QtCore.QCoreApplication.translate("menu","Toggle Shadow 6"), lambda: self.scoreView.scoreScene.toggleShadowLayer(6), shortcut="Shift+F6")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerShadow7", QtCore.QCoreApplication.translate("menu","Toggle Shadow 7"), lambda: self.scoreView.scoreScene.toggleShadowLayer(7), shortcut="Shift+F7")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerShadow8", QtCore.QCoreApplication.translate("menu","Toggle Shadow 8"), lambda: self.scoreView.scoreScene.toggleShadowLayer(8), shortcut="Shift+F8")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerShadow9", QtCore.QCoreApplication.translate("menu","Toggle Shadow 9"), lambda: self.scoreView.scoreScene.toggleShadowLayer(9), shortcut="Shift+F9")
|
|
self.menu.addMenuEntry("menuLayer", "actionLayerShadow0", QtCore.QCoreApplication.translate("menu","Toggle Shadow 0"), lambda: self.scoreView.scoreScene.toggleShadowLayer(0), shortcut="Shift+F10")
|
|
|
|
self.menu.addSubmenu("menuSnap", QtCore.QCoreApplication.translate("menu","Snap to Grid"))
|
|
self.menu.addMenuEntry("menuSnap", "actionSetSnapFree", QtCore.QCoreApplication.translate("menu","Free Positioning") , lambda: self.setSnapToGrid("actionSetSnapFree", 1), shortcut="Shift+0", checkable=True)
|
|
self.menu.addMenuEntry("menuSnap", "actionSetSnapD1", QtCore.QCoreApplication.translate("menu","Snap to Whole Notes") , lambda: self.setSnapToGrid("actionSetSnapD1", api.D1), shortcut="Shift+1", checkable=True)
|
|
self.menu.addMenuEntry("menuSnap", "actionSetSnapD2", QtCore.QCoreApplication.translate("menu","Snap to Half Notes") , lambda: self.setSnapToGrid("actionSetSnapD2", api.D2), shortcut="Shift+2", checkable=True)
|
|
self.menu.addMenuEntry("menuSnap", "actionSetSnapD4", QtCore.QCoreApplication.translate("menu","Snap to Quarter Notes") , lambda: self.setSnapToGrid("actionSetSnapD4", api.D4), shortcut="Shift+3", checkable=True)
|
|
self.menu.addMenuEntry("menuSnap", "actionSetSnapD8", QtCore.QCoreApplication.translate("menu","Snap to 8th Notes") , lambda: self.setSnapToGrid("actionSetSnapD8", api.D8), shortcut="Shift+4", checkable=True)
|
|
self.menu.addMenuEntry("menuSnap", "actionSetSnapD16", QtCore.QCoreApplication.translate("menu","Snap to 16th Notes") , lambda: self.setSnapToGrid("actionSetSnapD16", api.D16), shortcut="Shift+5", checkable=True)
|
|
self.menu.addMenuEntry("menuSnap", "actionSetSnapD32", QtCore.QCoreApplication.translate("menu","Snap to 32nd Notes") , lambda: self.setSnapToGrid("actionSetSnapD32", api.D32), shortcut="Shift+6", checkable=True)
|
|
self.menu.addSeparator("menuSnap")
|
|
self.menu.addMenuEntry("menuSnap", "actionSetSnapDot", QtCore.QCoreApplication.translate("menu","Snap with Dotted Notes (x 1.5)") , lambda: self.setSnapToGrid("actionSetSnapDot", None), shortcut="Shift+Q", checkable=True)
|
|
|
|
self.menu.addSubmenu("menuFilter", QtCore.QCoreApplication.translate("menu","Filter"))
|
|
self.menu.addMenuEntry("menuFilter", "actionFilterAndMove", QtCore.QCoreApplication.translate("menu","Filter and Move Events Single Layer"), lambda: EventFilterAndMover(mainWindow=self, allLayers=False), shortcut="m")
|
|
self.menu.addMenuEntry("menuFilter", "actionFilterAndMoveAllLayers", QtCore.QCoreApplication.translate("menu","Filter and Move Events All Layers"), lambda: EventFilterAndMover(mainWindow=self, allLayers=True), shortcut="Alt+m")
|
|
self.menu.addSeparator("menuFilter")
|
|
self.menu.addMenuEntry("menuFilter", "actionFilterAndMoveAllLayers", QtCore.QCoreApplication.translate("menu","Filter and Move Events All Layers"), lambda: EventFilterAndMover(mainWindow=self, allLayers=True), shortcut="Alt+m")
|
|
|
|
self.menu.orderSubmenus(["menuFile", "menuEdit", "menuNavigation", "menuLayer", "menuInput", "menuSnap", "menuFilter", "menuHelp", "menuDebug", "menuGeneric"])
|
|
#print(self.menu.getTemplateSubmenus())
|
|
|
|
|