#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2020 , Nils Hilbricht , Germany ( https : / / www . hilbricht . net )
This file is part of the Laborejo Software Suite ( https : / / www . laborejo . org ) ,
Laborejo2 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
from sys import maxsize
#Third party
from PyQt5 import QtCore , QtGui , QtWidgets
translate = QtCore . QCoreApplication . translate
#Template
import template . engine . pitch as pitch
from template . qtgui . helper import QHLine
from template . qtgui . submenus import *
#Our own files
import engine . api as api
from midiinput . stepmidiinput import stepMidiInput #singleton instance. Don't allow midi input when submenus are open.
from . constantsAndConfigs import constantsAndConfigs
from . designer . tickWidget import Ui_tickWidget
#Wrap Submenu call to deactivate midi input while showing the menu.
orgCall = Submenu . __call__
def wrapCallDeactivateMidIn ( self ) :
remember = stepMidiInput . midiInIsActive
stepMidiInput . setMidiInputActive ( False )
orgCall ( self )
stepMidiInput . setMidiInputActive ( remember )
Submenu . __call__ = wrapCallDeactivateMidIn
class CombinedTickWidget ( QtWidgets . QFrame ) :
def __init__ ( self ) :
super ( ) . __init__ ( )
self . setFrameShape ( QtWidgets . QFrame . Box )
self . setFrameShadow ( QtWidgets . QFrame . Sunken )
self . horizontalLayout_3 = QtWidgets . QHBoxLayout ( self )
self . horizontalLayout_3 . setContentsMargins ( 3 , 0 , 3 , 0 )
self . horizontalLayout_3 . setSpacing ( 0 )
self . horizontalLayout_3 . setObjectName ( " horizontalLayout_3 " )
self . upbeatSpinBox = QtWidgets . QSpinBox ( self )
self . upbeatSpinBox . setPrefix ( " " )
self . upbeatSpinBox . setMinimum ( 0 )
self . upbeatSpinBox . setMaximum ( 999999999 )
self . upbeatSpinBox . setObjectName ( " upbeatSpinBox " )
self . horizontalLayout_3 . addWidget ( self . upbeatSpinBox )
self . callTickWidget = QtWidgets . QPushButton ( self )
sizePolicy = QtWidgets . QSizePolicy ( QtWidgets . QSizePolicy . Fixed , QtWidgets . QSizePolicy . Fixed )
sizePolicy . setHorizontalStretch ( 0 )
sizePolicy . setVerticalStretch ( 0 )
sizePolicy . setHeightForWidth ( self . callTickWidget . sizePolicy ( ) . hasHeightForWidth ( ) )
self . callTickWidget . setSizePolicy ( sizePolicy )
self . callTickWidget . setMaximumSize ( QtCore . QSize ( 25 , 16777215 ) )
self . callTickWidget . setFlat ( False )
self . callTickWidget . setObjectName ( " callTickWidget " )
self . callTickWidget . setText ( " 𝅘𝅥𝅮 " )
self . horizontalLayout_3 . addWidget ( self . callTickWidget )
self . callTickWidget . clicked . connect ( self . callClickWidgetForUpbeat )
self . setFocusPolicy ( 0 ) #no focus
self . callTickWidget . setFocusPolicy ( 0 ) #no focus
self . valueChanged = self . upbeatSpinBox . valueChanged
def setMinimum ( self , value ) :
self . upbeatSpinBox . setMinimum ( value )
def setMaximum ( self , value ) :
self . upbeatSpinBox . setMaximum ( value )
def setValue ( self , value ) :
self . upbeatSpinBox . setValue ( value )
def value ( self ) :
""" Make this widget behave like a spinbox signal """
return self . upbeatSpinBox . value ( )
def callClickWidgetForUpbeat ( self ) :
dialog = TickWidget ( self , initValue = self . upbeatSpinBox . value ( ) )
self . upbeatSpinBox . setValue ( dialog . ui . ticks . value ( ) )
class TickWidget ( QtWidgets . QDialog ) :
def __init__ ( self , mainWindow , initValue = 0 ) :
super ( ) . __init__ ( mainWindow )
#Set up the user interface from Designer.
self . ui = Ui_tickWidget ( )
self . ui . setupUi ( self )
#self.ui.ticks.setValue(initValue)
self . ui . ticks . setValue ( 0 ) #TODO: easier to drawLabel this way. change back to given value when drawLabel is autogenerated and does not work by keeping track anymore.
self . ui . ok . clicked . connect ( lambda : self . done ( True ) )
self . ui . cancel . clicked . connect ( lambda : self . done ( False ) )
self . ui . reset . clicked . connect ( self . reset )
self . ui . durationLabel . setText ( " " )
self . clickedSoFar = [ ] #keep track
self . ui . D1 . clicked . connect ( lambda : self . addDuration ( api . D1 ) )
self . ui . D2 . clicked . connect ( lambda : self . addDuration ( api . D2 ) )
self . ui . D4 . clicked . connect ( lambda : self . addDuration ( api . D4 ) )
self . ui . D8 . clicked . connect ( lambda : self . addDuration ( api . D8 ) )
self . ui . D16 . clicked . connect ( lambda : self . addDuration ( api . D16 ) )
self . ui . D32 . clicked . connect ( lambda : self . addDuration ( api . D32 ) )
self . ui . D64 . clicked . connect ( lambda : self . addDuration ( api . D64 ) )
self . ui . D128 . clicked . connect ( lambda : self . addDuration ( api . D128 ) )
self . ui . DB . clicked . connect ( lambda : self . addDuration ( api . DB ) )
self . ui . DL . clicked . connect ( lambda : self . addDuration ( api . DL ) )
self . ui . ticks . valueChanged . connect ( self . drawLabel )
self . exec ( ) #blocks until the dialog gets closed
#TODO: better key handling. Esc in the ticks field should not close the dialog but return the keyboard focus to the durations
def reset ( self ) :
self . ui . ticks . setValue ( 0 )
self . clickedSoFar = [ ]
self . ui . durationLabel . setText ( " " )
def addDuration ( self , duration ) :
self . clickedSoFar . append ( duration )
nowTicks = self . ui . ticks . value ( )
self . ui . ticks . setValue ( nowTicks + duration )
def drawLabel ( self ) :
#TODO: with nice partitions of real note icons.
#Error handling. A too complex or wrong duration (off by one, not equal to a partition etc.) blocks the "OK" button. No, just gives a warning.
#backendDurationInstance = api.items.Duration.createByGuessing(self.ui.ticks.value())
#text = backendDurationInstance.lilypond()
text = [ ]
for duration , symbol in reversed ( sorted ( constantsAndConfigs . realNoteDisplay . items ( ) ) ) :
times = self . clickedSoFar . count ( duration )
if times :
part = str ( times ) + " x " + symbol
text . append ( part )
self . ui . durationLabel . setText ( " + " . join ( text ) )
class SecondaryClefMenu ( Submenu ) :
clefs = [ ( translate ( " submenus " , " [1] Treble " ) , lambda : api . insertClef ( " treble " ) ) ,
( translate ( " submenus " , " [2] Bass " ) , lambda : api . insertClef ( " bass " ) ) ,
( translate ( " submenus " , " [3] Alto " ) , lambda : api . insertClef ( " alto " ) ) ,
( translate ( " submenus " , " [4] Drum " ) , lambda : api . insertClef ( " percussion " ) ) ,
( translate ( " submenus " , " [5] Treble ^8 " ) , lambda : api . insertClef ( " treble^8 " ) ) ,
( translate ( " submenus " , " [6] Treble _8 " ) , lambda : api . insertClef ( " treble_8 " ) ) ,
( translate ( " submenus " , " [7] Bass _8 (MIDI Drums) " ) , lambda : api . insertClef ( " bass_8 " ) ) ,
]
def __init__ ( self , mainWindow ) :
super ( ) . __init__ ( mainWindow , translate ( " submenus " , " choose a clef " ) , hasOkCancelButtons = 2 )
for number , ( prettyname , function ) in enumerate ( SecondaryClefMenu . clefs ) :
button = QtWidgets . QPushButton ( prettyname )
button . setShortcut ( QtGui . QKeySequence ( str ( number + 1 ) ) )
self . layout . addWidget ( button )
button . clicked . connect ( function )
button . clicked . connect ( self . done )
class SecondarySplitMenu ( Submenu ) :
splits = [ ( " [2] " , lambda : api . split ( 2 ) ) ,
( " [3] " , lambda : api . split ( 3 ) ) ,
( " [4] " , lambda : api . split ( 4 ) ) ,
( " [5] " , lambda : api . split ( 5 ) ) ,
( " [6] " , lambda : api . split ( 6 ) ) ,
( " [7] " , lambda : api . split ( 7 ) ) ,
( " [8] " , lambda : api . split ( 8 ) ) ,
( " [9] " , lambda : api . split ( 9 ) ) ,
]
def __init__ ( self , mainWindow ) :
super ( ) . __init__ ( mainWindow , translate ( " submenus " , " split chord in " ) , hasOkCancelButtons = 2 )
for number , ( prettyname , function ) in enumerate ( SecondarySplitMenu . splits ) :
button = QtWidgets . QPushButton ( prettyname )
button . setShortcut ( QtGui . QKeySequence ( str ( number + 2 ) ) ) #+1 for enumerate from 0, +2 we start at 2.
self . layout . addWidget ( button )
button . clicked . connect ( function )
button . clicked . connect ( self . done )
class SecondaryKeySignatureMenu ( Submenu ) :
def __init__ ( self , mainWindow ) :
super ( ) . __init__ ( mainWindow , translate ( " submenus " , " root note is the cursor position " ) , hasOkCancelButtons = 2 )
l = [ ( " [ {} ] {} " . format ( num + 1 , modeString . title ( ) ) , lambda r , modeString = modeString : api . insertCursorCommonKeySignature ( modeString ) ) for num , modeString in enumerate ( api . commonKeySignaturesAsList ( ) ) ]
for number , ( prettyname , function ) in enumerate ( l ) :
button = QtWidgets . QPushButton ( prettyname )
button . setShortcut ( QtGui . QKeySequence ( str ( number + 1 ) ) )
self . layout . addWidget ( button )
button . clicked . connect ( function )
button . clicked . connect ( self . done )
class SecondaryDynamicsMenu ( Submenu ) :
def __init__ ( self , mainWindow ) :
super ( ) . __init__ ( mainWindow , translate ( " submenus " , " choose a dynamic " ) , hasOkCancelButtons = 2 )
button = QtWidgets . QPushButton ( translate ( " submenus " , " [r] Ramp " ) )
button . setShortcut ( QtGui . QKeySequence ( " r " ) )
self . layout . addWidget ( button )
button . clicked . connect ( api . insertDynamicRamp )
button . clicked . connect ( self . done )
l = [ ( " [ {} ] {} " . format ( num + 1 , keyword ) , lambda r , keyword = keyword : api . insertDynamicSignature ( keyword ) ) for num , keyword in enumerate ( constantsAndConfigs . dynamics ) ]
for number , ( prettyname , function ) in enumerate ( l ) :
button = QtWidgets . QPushButton ( prettyname )
button . setShortcut ( QtGui . QKeySequence ( str ( number + 1 ) ) )
self . layout . addWidget ( button )
button . clicked . connect ( function )
button . clicked . connect ( self . done )
class SecondaryMetricalInstructionMenu ( Submenu ) :
def __init__ ( self , mainWindow ) :
super ( ) . __init__ ( mainWindow , translate ( " submenus " , " choose a metrical instruction " ) , hasOkCancelButtons = 2 )
l = [ ( " [ {} ] {} " . format ( num + 1 , modeString ) , lambda r , modeString = modeString : api . insertCommonMetricalInstrucions ( modeString ) ) for num , modeString in enumerate ( api . commonMetricalInstructionsAsList ( ) ) ]
for number , ( prettyname , function ) in enumerate ( l ) :
button = QtWidgets . QPushButton ( prettyname )
button . setShortcut ( QtGui . QKeySequence ( str ( number + 1 ) ) )
self . layout . addWidget ( button )
button . clicked . connect ( function )
button . clicked . connect ( self . done )
class SecondaryTempoChangeMenu ( Submenu ) :
""" A single tempo change where the user can decide which reference unit and how many of them
per minute .
Works as " edit tempo point " when there is already a point at this time position .
This would be the case anyway thanks to backend - behaviour but the gui has the opportunity to
present the current values as a base for editing """
def __init__ ( self , mainWindow , staticExportTempoItem = None ) :
super ( ) . __init__ ( mainWindow , translate ( " submenus " , " choose units per minute, reference note, graph type " ) , hasOkCancelButtons = True )
self . mainWindow = mainWindow
self . staticExportTempoItem = staticExportTempoItem
tickindex , unitsPerMinute , referenceTicks , graphType = self . getCurrentValues ( ) #takes self.staticExportTempoItem into account
self . unitbox = QtWidgets . QSpinBox ( )
self . unitbox . setMinimum ( 1 )
self . unitbox . setMaximum ( 999 )
self . unitbox . setValue ( unitsPerMinute )
self . layout . addWidget ( self . unitbox )
self . referenceList = QtWidgets . QComboBox ( )
self . referenceList . addItems ( constantsAndConfigs . prettyExtendedRhythmsStrings )
self . referenceList . setCurrentIndex ( constantsAndConfigs . prettyExtendedRhythmsValues . index ( referenceTicks ) )
self . layout . addWidget ( self . referenceList )
self . interpolationList = QtWidgets . QComboBox ( )
l = api . getListOfGraphInterpolationTypesAsStrings ( )
self . interpolationList . addItems ( l )
self . interpolationList . setCurrentIndex ( l . index ( graphType ) )
self . layout . addWidget ( self . interpolationList )
self . __call__ ( )
def process ( self ) :
""" It says ' insert ' but the backend is a dict. Changes are simply made by overwriting the
whole thing and the backend sends new data to draw to the GUI """
tickindex , unitsPerMinute , referenceTicks , graphType = self . getCurrentValues ( )
newReferenceTicks = constantsAndConfigs . prettyExtendedRhythmsValues [ self . referenceList . currentIndex ( ) ]
graphType = api . getListOfGraphInterpolationTypesAsStrings ( ) [ self . interpolationList . currentIndex ( ) ]
api . insertTempoItemAtAbsolutePosition ( tickindex , self . unitbox . value ( ) , newReferenceTicks , graphType )
self . done ( True )
def getCurrentValues ( self ) :
""" Get the current values from the note-editing backend cursor """
if self . staticExportTempoItem :
return self . staticExportTempoItem [ " position " ] , self . staticExportTempoItem [ " unitsPerMinute " ] , self . staticExportTempoItem [ " referenceTicks " ] , self . staticExportTempoItem [ " graphType " ] ,
else :
assert self . mainWindow . scoreView . scoreScene . cursor . cursorExportObject
return self . mainWindow . scoreView . scoreScene . cursor . cursorExportObject [ " tickindex " ] , self . mainWindow . scoreView . scoreScene . cursor . cursorExportObject [ " tempoUnitsPerMinute " ] , self . mainWindow . scoreView . scoreScene . cursor . cursorExportObject [ " tempoReferenceTicks " ] , self . mainWindow . scoreView . scoreScene . cursor . cursorExportObject [ " tempoGraphType " ] ,
class SecondaryTemporaryTempoChangeMenu ( Submenu ) :
""" Essentially: What kind of fermata effect do you want? """
lastCustomValue = 0.42
def __init__ ( self , mainWindow ) :
super ( ) . __init__ ( mainWindow , translate ( " submenus " , " [enter] to use value " ) , hasOkCancelButtons = True )
self . spinbox = QtWidgets . QDoubleSpinBox ( )
self . spinbox . setValue ( SecondaryTemporaryTempoChangeMenu . lastCustomValue )
self . spinbox . setDecimals ( 2 )
self . spinbox . setMinimum ( 0.01 )
self . spinbox . setSingleStep ( 0.01 )
self . layout . addWidget ( self . spinbox )
def process ( self ) :
v = round ( self . spinbox . value ( ) , 2 )
SecondaryTemporaryTempoChangeMenu . lastCustomValue = v
api . insertTempoChangeDuringDuration ( v )
self . done ( True )
class BlockPropertiesEdit ( Submenu ) :
def __init__ ( self , mainWindow , staticExportItem ) :
super ( ) . __init__ ( mainWindow , " " , hasOkCancelButtons = True )
self . mainWindow = mainWindow
self . staticExportItem = staticExportItem
self . layout . insertRow ( 0 , QtWidgets . QLabel ( translate ( " submenus " , " edit block # {} " ) . format ( staticExportItem [ " id " ] ) ) )
self . name = QtWidgets . QLineEdit ( self . staticExportItem [ " name " ] )
self . name . selectAll ( )
self . layout . addRow ( translate ( " submenus " , " name " ) , self . name )
#self.minimumInTicks = QtWidgets.QSpinBox()
self . minimumInTicks = CombinedTickWidget ( )
self . minimumInTicks . setValue ( self . staticExportItem [ " minimumInTicks " ] )
self . layout . addRow ( translate ( " submenus " , " minimum in ticks " ) , self . minimumInTicks )
self . __call__ ( )
def process ( self ) :
newParametersDict = {
" minimumInTicks " : self . minimumInTicks . value ( ) ,
" name " : self . name . text ( ) ,
}
api . changeBlock ( self . staticExportItem [ " id " ] , newParametersDict )
self . done ( True )
class TempoBlockPropertiesEdit ( Submenu ) :
def __init__ ( self , mainWindow , staticExportItem ) :
super ( ) . __init__ ( mainWindow , " " , hasOkCancelButtons = True )
self . mainWindow = mainWindow
self . staticExportItem = staticExportItem
self . layout . insertRow ( 0 , QtWidgets . QLabel ( translate ( " submenus " , " edit block # {} " ) . format ( staticExportItem [ " id " ] ) ) )
self . name = QtWidgets . QLineEdit ( self . staticExportItem [ " name " ] )
self . name . selectAll ( )
self . layout . addRow ( translate ( " submenus " , " name " ) , self . name )
self . duration = CombinedTickWidget ( )
self . duration . setValue ( self . staticExportItem [ " duration " ] )
self . layout . addRow ( translate ( " submenus " , " duration in ticks " ) , self . duration )
self . __call__ ( )
def process ( self ) :
newParametersDict = {
" duration " : self . duration . value ( ) ,
" name " : self . name . text ( ) ,
}
api . changeTempoBlock ( self . staticExportItem [ " id " ] , newParametersDict )
self . done ( True )
class TransposeMenu ( Submenu ) :
def __init__ ( self , mainWindow , what ) :
super ( ) . __init__ ( mainWindow , translate ( " submenus " , " Transpose {} " ) . format ( what . title ( ) ) , hasOkCancelButtons = True )
assert what in ( " item " , " score " )
self . what = what
self . layout . insertRow ( 0 , QtWidgets . QLabel ( translate ( " submenus " , " Construct Interval from relative distance " ) ) )
self . fromNote = QtWidgets . QComboBox ( )
self . fromNote . addItems ( pitch . sortedNoteNameList )
self . fromNote . setCurrentIndex ( pitch . sortedNoteNameList . index ( " c ' " ) )
self . layout . addRow ( " from " , self . fromNote )
self . to = QtWidgets . QComboBox ( )
self . to . addItems ( pitch . sortedNoteNameList )
self . to . setCurrentIndex ( pitch . sortedNoteNameList . index ( " c ' " ) )
self . layout . addRow ( " to " , self . to )
self . __call__ ( )
def process ( self ) :
fromPitch = pitch . ly2pitch [ self . fromNote . currentText ( ) ]
toPitch = pitch . ly2pitch [ self . to . currentText ( ) ]
if self . what == " item " :
api . transpose ( fromPitch , toPitch ) #item on cursor position
elif self . what == " score " :
api . transposeScore ( fromPitch , toPitch )
self . done ( True )
class SecondaryProperties ( Submenu ) :
def __init__ ( self , mainWindow ) :
""" Directly edits the backend score meta data. There is no api and no callbacks """
super ( ) . __init__ ( mainWindow , translate ( " submenus " , " Meta Data " ) , hasOkCancelButtons = True )
dictionary = api . getMetadata ( ) #TOOD: untranslated to keep relation to lilypond?
test = set ( type ( key ) for key in dictionary . keys ( ) )
assert len ( test ) == 1
assert list ( test ) [ 0 ] == str
self . widgets = { key : self . makeValueWidget ( value ) for key , value in dictionary . items ( ) }
importantKeys = ( " title " , " composer " , " instrument " , " copyright " )
#Draw important metadata widgets first
for k in importantKeys :
self . layout . addRow ( k . title ( ) , self . widgets [ k ] )
self . layout . addRow ( QHLine ( ) )
#Then the rest in alphabetical order
for key , widget in sorted ( self . widgets . items ( ) ) :
if not key in importantKeys :
self . layout . addRow ( key . title ( ) , widget )
self . __call__ ( )
def makeValueWidget ( self , value ) :
types = {
str : QtWidgets . QLineEdit ,
int : QtWidgets . QSpinBox ,
float : QtWidgets . QDoubleSpinBox ,
}
typ = type ( value )
widget = types [ typ ] ( )
if typ == str :
widget . setText ( value )
elif typ == int or typ == float :
widget . setValue ( value )
return widget
def getValueFromWidget ( self , widget ) :
typ = type ( widget )
if typ == QtWidgets . QLineEdit :
return widget . text ( )
elif typ == QtWidgets . QSpinBox or typ == QtWidgets . QDoubleSpinBox :
return widget . value ( )
def process ( self ) :
api . setMetadata ( { key : self . getValueFromWidget ( widget ) for key , widget in self . widgets . items ( ) } )
self . done ( True )
#Instance gets killed afterwards. No need to save the new values.
class SecondaryProgramChangeMenu ( Submenu ) :
lastProgramValue = 0
lastMsbValue = 0
lastLsbValue = 0
def __init__ ( self , mainWindow ) :
super ( ) . __init__ ( mainWindow , translate ( " submenus " , " Instrument Change " ) , hasOkCancelButtons = True )
self . program = QtWidgets . QSpinBox ( )
self . program . setValue ( type ( self ) . lastProgramValue )
self . msb = QtWidgets . QSpinBox ( )
self . msb . setValue ( type ( self ) . lastMsbValue )
self . lsb = QtWidgets . QSpinBox ( )
self . lsb . setValue ( type ( self ) . lastLsbValue )
self . shortInstrumentName = QtWidgets . QLineEdit ( )
for label , spinbox in ( ( translate ( " submenus " , " Program " ) , self . program ) , ( translate ( " submenus " , " Bank MSB " ) , self . msb ) , ( translate ( " submenus " , " Bank LSB " ) , self . lsb ) ) :
spinbox . setMinimum ( 0 )
spinbox . setMaximum ( 127 )
spinbox . setSingleStep ( 1 )
self . layout . addRow ( label , spinbox )
self . layout . addRow ( translate ( " submenus " , " Short Name " ) , self . shortInstrumentName )
def process ( self ) :
program = self . program . value ( )
type ( self ) . lastProgramValue = program
msb = self . msb . value ( )
type ( self ) . lastMsbValue = msb
lsb = self . lsb . value ( )
type ( self ) . lastLsbValue = lsb
api . instrumentChange ( program , msb , lsb , self . shortInstrumentName . text ( ) , )
self . done ( True )
class SecondaryChannelChangeMenu ( Submenu ) :
lastCustomValue = 0
def __init__ ( self , mainWindow ) :
super ( ) . __init__ ( mainWindow , translate ( " submenus " , " Channel Change 1-16. [enter] to use value " ) , hasOkCancelButtons = True )
self . spinbox = QtWidgets . QSpinBox ( )
self . spinbox . setValue ( type ( self ) . lastCustomValue )
self . spinbox . setMinimum ( 1 )
self . spinbox . setMaximum ( 16 )
self . spinbox . setSingleStep ( 1 )
self . layout . addRow ( translate ( " submenus " , " Channel " ) , self . spinbox )
self . name = QtWidgets . QLineEdit ( )
self . layout . addRow ( translate ( " submenus " , " Text " ) , self . name )
def process ( self ) :
v = self . spinbox . value ( )
type ( self ) . lastCustomValue = v
api . channelChange ( v - 1 , self . name . text ( ) )
self . done ( True )
class GridRhytmEdit ( Submenu ) :
def __init__ ( self , mainWindow ) :
super ( ) . __init__ ( mainWindow , " " , hasOkCancelButtons = True )
self . mainWindow = mainWindow
self . layout . insertRow ( 0 , QtWidgets . QLabel ( translate ( " submenus " , " Edit Grid " ) ) )
self . duration = CombinedTickWidget ( )
self . duration . setValue ( constantsAndConfigs . gridRhythm )
self . layout . addRow ( translate ( " submenus " , " duration in ticks " ) , self . duration )
self . opacity = QtWidgets . QSlider ( QtCore . Qt . Horizontal )
self . opacity . setMinimum ( 0 )
self . opacity . setMaximum ( 50 )
self . opacityLabel = QtWidgets . QLabel ( translate ( " submenus " , " opacity: {} % " ) . format ( int ( constantsAndConfigs . gridOpacity * 100 ) ) )
self . layout . addRow ( self . opacityLabel , self . opacity )
self . opacity . valueChanged . connect ( lambda : self . opacityLabel . setText ( translate ( " submenus " , " opacity: {} % " ) . format ( self . opacity . value ( ) ) ) )
self . opacity . setValue ( int ( constantsAndConfigs . gridOpacity * 100 ) )
self . opacity . valueChanged . connect ( lambda : self . mainWindow . scoreView . scoreScene . grid . setOpacity ( self . opacity . value ( ) / 100 ) ) #only react to changes after the initial value was set.
self . __call__ ( )
def process ( self ) :
constantsAndConfigs . gridRhythm = self . duration . value ( )
constantsAndConfigs . gridOpacity = self . opacity . value ( ) / 100
api . session . guiSharedDataToSave [ " grid_opacity " ] = constantsAndConfigs . gridOpacity
api . session . guiSharedDataToSave [ " grid_rhythm " ] = constantsAndConfigs . gridRhythm
self . mainWindow . scoreView . scoreScene . grid . redrawTickGrid ( ) #opacity was already set live, but finally it will be used here again.
self . done ( True )
def abortHandler ( self ) :
self . mainWindow . scoreView . scoreScene . grid . setOpacity ( constantsAndConfigs . gridOpacity ) #reset to initial value and undo the live preview
#Normal Functions
############
def pedalNoteChooser ( mainWindow ) :
try :
constantsAndConfigs . realNotesStrings [ constantsAndConfigs . realNotesValues . index ( constantsAndConfigs . gridRhythm ) + 1 ]
rhythmString = QtWidgets . QInputDialog . getItem ( mainWindow , translate ( " submenus " , " Insert Pedal Notes " ) , translate ( " submenus " , " Use duration as base " ) , constantsAndConfigs . realNotesStrings , constantsAndConfigs . realNotesValues . index ( constantsAndConfigs . gridRhythm ) + 1 , False )
except IndexError :
rhythmString = QtWidgets . QInputDialog . getItem ( mainWindow , translate ( " submenus " , " Insert Pedal Notes " ) , translate ( " submenus " , " Use duration as base " ) , constantsAndConfigs . realNotesStrings , constantsAndConfigs . realNotesValues . index ( constantsAndConfigs . gridRhythm ) , False )
if rhythmString [ 1 ] : #bool. Canceled?
for baseDuration , v in constantsAndConfigs . commonNotes :
if v == rhythmString [ 0 ] :
api . pedalNotes ( baseDuration )
def forwardText ( mainWindow , title , function ) :
text , status = QtWidgets . QInputDialog . getText ( mainWindow , title , title )
if status :
function ( text )