Browse Source

Undo part 1

master
Nils 3 years ago
parent
commit
48439acb05
  1. 254
      engine/api.py
  2. 4
      qtgui/mainwindow.py
  3. 5
      template/engine/api.py
  4. 2
      template/engine/sequencer.py

254
engine/api.py

@ -208,6 +208,7 @@ class ClientCallbacks(Callbacks): #inherits from the templates api callbacks
for func in self.patternLengthMultiplicatorChanged:
func(export)
self._patternChanged(track) #includes dataChanged
callbacks._dataChanged()
def _swingChanged(self):
export = session.data.swing
@ -216,6 +217,7 @@ class ClientCallbacks(Callbacks): #inherits from the templates api callbacks
for func in self.swingPercentChanged:
func(_swingToPercent_Table[export])
callbacks._dataChanged()
#Inject our derived Callbacks into the parent module
template.engine.api.callbacks = ClientCallbacks()
@ -322,6 +324,17 @@ def seek(value):
##Score
def set_quarterNotesPerMinute(value):
"""Transport Master is set implicitly. If value == None Patroneo will switch into
JackTransport Slave mode"""
if session.data.tempoMap.isTransportMaster:
oldValue = session.data.tempoMap.getQuarterNotesPerMinute()
else:
oldValue = None
if oldValue == value: return # no change
session.history.register(lambda v=oldValue: set_quarterNotesPerMinute(v), descriptionString="Tempo")
if value is None:
session.data.tempoMap.isTransportMaster = False #triggers rebuild
elif value == "on":
@ -338,8 +351,10 @@ def set_quarterNotesPerMinute(value):
def set_whatTypeOfUnit(ticks):
"""Denominator of Time Signature"""
if session.data.whatTypeOfUnit == ticks: return
"""Denominator of Time Signature = Each Group produces a Quarter """
if session.data.whatTypeOfUnit == ticks: return #no change
session.history.register(lambda v=session.data.whatTypeOfUnit: set_whatTypeOfUnit(v), descriptionString="Group Duration")
session.data.whatTypeOfUnit = ticks
session.data.buildAllTracks()
if session.inLoopMode:
@ -348,8 +363,10 @@ def set_whatTypeOfUnit(ticks):
callbacks._timeSignatureChanged()
def set_howManyUnits(value):
"""Numerator of Time Signature"""
if session.data.howManyUnits == value: return
"""Numerator of Time Signature = Steps per Pattern"""
if session.data.howManyUnits == value: return #no change
session.history.register(lambda v=session.data.howManyUnits: set_howManyUnits(v), descriptionString="Steps per Pattern")
session.data.howManyUnits = value
session.data.buildAllTracks()
if session.inLoopMode:
@ -359,7 +376,9 @@ def set_howManyUnits(value):
def set_subdivisions(value):
if session.data.subdivisions == value: return
"""In groups of 1, 2, 4"""
if session.data.subdivisions == value: return #no change
session.history.register(lambda v=session.data.subdivisions: set_subdivisions(v), descriptionString="Group Size")
session.data.subdivisions = value
session.data.buildAllTracks()
if session.inLoopMode:
@ -369,9 +388,10 @@ def set_subdivisions(value):
def convert_subdivisions(value, errorHandling):
""""errorHandling can be fail, delete or merge"""
if session.data.subdivisions == value: return
oldValue = session.data.subdivisions
result = session.data.convertSubdivisions(value, errorHandling)
if result:
if result: #bool for success
session.history.register(lambda v=oldValue: convert_subdivisions(v, "delete"), descriptionString="Convert Grouping") #the error handling = delete should not matter at all. We are always in a position where this is possible because we just converted to the current state.
session.data.buildAllTracks()
updatePlayback()
callbacks._timeSignatureChanged() #includes subdivisions
@ -392,6 +412,7 @@ def set_swing(value:float):
logger.warning(f"Swing can only be between -0.5 and 0.5, not {value}")
return
session.history.register(lambda v=session.data.swing: set_swing(v), descriptionString="Swing")
session.data.swing = value
session.data.buildAllTracks()
updatePlayback()
@ -409,12 +430,14 @@ def setSwingPercent(value:int):
if value < -100 or value > 100:
logger.warning(f"Swing in percent can only be between -100 and +100, not {value}")
return
set_swing(_percentToSwing_Table[value])
set_swing(_percentToSwing_Table[value]) #handles undo and callbacks
def set_numberOfMeasures(value):
if session.data.numberOfMeasures == value:
return
session.history.register(lambda v=session.data.numberOfMeasures: set_numberOfMeasures(v), descriptionString="Measures per Track")
session.data.numberOfMeasures = value
session.data.buildSongDuration()
updatePlayback()
@ -424,12 +447,14 @@ def set_numberOfMeasures(value):
def set_measuresPerGroup(value):
if session.data.measuresPerGroup == value:
return
session.history.register(lambda v=session.data.measuresPerGroup: set_measuresPerGroup(v), descriptionString="Measures per Group")
session.data.measuresPerGroup = value
#No playback change
callbacks._scoreChanged()
def changeTrackName(trackId, name):
track = session.data.trackById(trackId)
session.history.register(lambda trId=trackId, v=track.sequencerInterface.name: changeTrackName(trId,v), descriptionString="Track Name")
track.sequencerInterface.name = " ".join(name.split())
callbacks._trackMetaDataChanged(track)
@ -437,6 +462,7 @@ def changeTrackColor(trackId, colorInHex):
"""Expects "#rrggbb"""
track = session.data.trackById(trackId)
assert len(colorInHex) == 7, colorInHex
session.history.register(lambda trId=trackId, v=track.color: changeTrackColor(trId,v), descriptionString="Track Color")
track.color = colorInHex
callbacks._trackMetaDataChanged(track)
@ -447,6 +473,7 @@ def changeTrackMidiChannel(trackId, newChannel:int):
logger.warning(f"Midi Channel must be between 1-16 for this function, was: {newChannel}. Doing nothing.")
return
track = session.data.trackById(trackId)
session.history.register(lambda trId=trackId, v=track.midiChannel: changeTrackMidiChannel(trId,v), descriptionString="Track Midi Channel")
track.midiChannel = newChannel-1
track.pattern.buildExportCache()
track.buildTrack()
@ -456,7 +483,10 @@ def changeTrackMidiChannel(trackId, newChannel:int):
def addTrack(scale=None):
if scale:
assert type(scale) == tuple
session.data.addTrack(scale=scale)
track = session.data.addTrack(scale=scale)
assert track
trackId = id(track)
session.history.register(lambda trId=trackId: deleteTrack(trId), descriptionString="Add Track")
callbacks._numberOfTracksChanged()
def createSiblingTrack(trackId):
@ -478,14 +508,30 @@ def createSiblingTrack(trackId):
newTrackAgain = session.data.tracks.pop(newIndex)
assert newTrackAgain is newTrack
session.data.tracks.insert(oldIndex+1, newTrackAgain)
session.history.register(lambda trId=id(newTrackAgain): deleteTrack(trId), descriptionString="Clone Track")
callbacks._numberOfTracksChanged()
return newTrack.export()
def _reinsertDeletedTrack(track, trackIndex):
"""For undo"""
track.sequencerInterface.recreateThroughUndo()
session.data.tracks.insert(trackIndex, track)
session.history.register(lambda trId=id(track): deleteTrack(trId), descriptionString="Add deleted Track again")
updatePlayback()
callbacks._numberOfTracksChanged()
def deleteTrack(trackId):
track = session.data.trackById(trackId)
session.data.deleteTrack(track)
oldIndex = session.data.tracks.index(track)
deletedTrack = session.data.deleteTrack(track)
if not session.data.tracks: #always keep at least one track
session.data.addTrack()
with session.history.sequence("Delete Track and autocreated Track"):
addTrack() #has it's own undo
session.history.register(lambda tr=deletedTrack, pos=oldIndex: _reinsertDeletedTrack(tr, pos), descriptionString="Delete Track")
else:
session.history.register(lambda tr=deletedTrack, pos=oldIndex: _reinsertDeletedTrack(tr, pos), descriptionString="Delete Track")
updatePlayback()
callbacks._numberOfTracksChanged()
@ -494,6 +540,7 @@ def moveTrack(trackId, newIndex):
track = session.data.trackById(trackId)
oldIndex = session.data.tracks.index(track)
if not oldIndex == newIndex:
session.history.register(lambda tr=trackId, pos=oldIndex: moveTrack(trackId, pos), descriptionString="Move Track")
session.data.tracks.pop(oldIndex)
session.data.tracks.insert(newIndex, track)
callbacks._numberOfTracksChanged()
@ -503,6 +550,7 @@ def setTrackPatternLengthMultiplicator(trackId, newMultiplicator:int):
return #Invalid input
track = session.data.trackById(trackId)
session.history.register(lambda tr=trackId, v=track.patternLengthMultiplicator: setTrackPatternLengthMultiplicator(trackId, v), descriptionString="Pattern Multiplier")
track.patternLengthMultiplicator = newMultiplicator
track.pattern.buildExportCache()
track.buildTrack()
@ -513,22 +561,37 @@ def setTrackPatternLengthMultiplicator(trackId, newMultiplicator:int):
callbacks._patternChanged(track)
#Track Switches
#Aka measures
def _setTrackStructure(trackId, structure):
"""For undo. Used by all functions as entry point, then calls itself for undo/redo.
structure is a set of integers which we can copy with .copy()"""
track = session.data.trackById(trackId)
session.history.register(lambda tr=trackId, v=track.structure.copy(): _setTrackStructure(trackId, v), descriptionString="Set Measures")
track.structure = structure #restore data
track.buildTrack()
updatePlayback()
callbacks._trackStructureChanged(track)
#Track Switches
def setSwitches(trackId, setOfPositions, newBool):
"""Used in the GUI to select multiple switches in a row by dragging the mouse"""
track = session.data.trackById(trackId)
session.history.register(lambda tr=trackId, v=track.structure.copy(): _setTrackStructure(trackId, v), descriptionString="Set Measures")
if newBool:
track.structure = track.structure.union(setOfPositions) #add setOfPositions to the existing one
track.structure = track.structure.union(setOfPositions) #merge: add setOfPositions to the existing one
else:
track.structure = track.structure.difference(setOfPositions) #remove everything from setOfPositions that is in the existing one, ignore entries from setOfPositions not in existing.
track.structure = track.structure.difference(setOfPositions) #replace: remove everything from setOfPositions that is in the existing one, ignore entries from setOfPositions not in existing.
track.buildTrack()
updatePlayback()
callbacks._trackStructureChanged(track)
def setSwitch(trackId, position, newBool):
track = session.data.trackById(trackId)
session.history.register(lambda trId=trackId, v=track.structure.copy(): _setTrackStructure(trId, v), descriptionString="Set Measures")
if newBool:
if position in track.structure: return
track.structure.add(position)
@ -542,6 +605,7 @@ def setSwitch(trackId, position, newBool):
def trackInvertSwitches(trackId):
track = session.data.trackById(trackId)
session.history.register(lambda trId=trackId, v=track.structure.copy(): _setTrackStructure(trId, v), descriptionString="Set Measures")
"""
if track.structure:
new = set(i for i in range(max(track.structure)))
@ -557,6 +621,7 @@ def trackInvertSwitches(trackId):
def trackOffAllSwitches(trackId):
track = session.data.trackById(trackId)
session.history.register(lambda trId=trackId, v=track.structure.copy(): _setTrackStructure(trId, v), descriptionString="Set Measures")
track.structure = set()
track.buildTrack()
updatePlayback()
@ -564,6 +629,7 @@ def trackOffAllSwitches(trackId):
def trackOnAllSwitches(trackId):
track = session.data.trackById(trackId)
session.history.register(lambda trId=trackId, v=track.structure.copy(): _setTrackStructure(trId, v), descriptionString="Set Measures")
track.structure = set(i for i in range(session.data.numberOfMeasures))
track.buildTrack()
updatePlayback()
@ -573,6 +639,7 @@ def trackMergeCopyFrom(sourceTrackId, targetTrackId):
if not sourceTrackId == targetTrackId:
sourceTrack = session.data.trackById(sourceTrackId)
targetTrack = session.data.trackById(targetTrackId)
session.history.register(lambda trId=id(targetTrack), v=targetTrack.structure.copy(): _setTrackStructure(trId, v), descriptionString="Set Measures")
targetTrack.structure = targetTrack.structure.union(sourceTrack.structure)
targetTrack.whichPatternsAreScaleTransposed.update(sourceTrack.whichPatternsAreScaleTransposed)
targetTrack.whichPatternsAreHalftoneTransposed.update(sourceTrack.whichPatternsAreHalftoneTransposed)
@ -584,6 +651,7 @@ def trackPatternReplaceFrom(sourceTrackId, targetTrackId):
if not sourceTrackId == targetTrackId:
sourceTrack = session.data.trackById(sourceTrackId)
targetTrack = session.data.trackById(targetTrackId)
session.history.register(lambda trId=id(targetTrack), v=targetTrack.structure.copy(): _setTrackStructure(trId, v), descriptionString="Set Measures")
copyPattern = sourceTrack.pattern.copy(newParentTrack = targetTrack)
targetTrack.pattern = copyPattern
@ -592,24 +660,66 @@ def trackPatternReplaceFrom(sourceTrackId, targetTrackId):
updatePlayback()
callbacks._patternChanged(targetTrack)
#Transpositions and Modal Shifts
def _setSwitchesScaleTranspose(trackId, whichPatternsAreScaleTransposed):
"""For undo. Used by all functions as entry point, then calls itself for undo/redo.
whichPatternsAreScaleTransposed is a dicts of int:int which we can copy with .copy()"""
track = session.data.trackById(trackId)
session.history.register(lambda tr=trackId, v=track.whichPatternsAreScaleTransposed.copy(): _setSwitchesScaleTranspose(trackId, v), descriptionString="Set Modal Shift")
track.whichPatternsAreScaleTransposed = whichPatternsAreScaleTransposed #restore data
track.buildTrack()
updatePlayback()
callbacks._trackStructureChanged(track)
def setSwitchScaleTranspose(trackId, position, transpose):
"""Scale transposition is flipped. lower value means higher pitch"""
track = session.data.trackById(trackId)
session.history.register(lambda tr=trackId, v=track.whichPatternsAreScaleTransposed.copy(): _setSwitchesScaleTranspose(trackId, v), descriptionString="Set Modal Shift")
track.whichPatternsAreScaleTransposed[position] = transpose
track.buildTrack()
updatePlayback()
callbacks._trackStructureChanged(track)
return True
def _setSwitchHalftoneTranspose(trackId, whichPatternsAreHalftoneTransposed):
"""For undo. Used by all functions as entry point, then calls itself for undo/redo.
whichPatternsAreScaleTransposed is a dicts of int:int which we can copy with .copy()"""
track = session.data.trackById(trackId)
session.history.register(lambda tr=trackId, v=track.whichPatternsAreHalftoneTransposed.copy(): _setSwitchHalftoneTranspose(trackId, v), descriptionString="Set Half Tone Shift")
track.whichPatternsAreHalftoneTransposed = whichPatternsAreHalftoneTransposed #restore data
track.buildTrack()
updatePlayback()
callbacks._trackStructureChanged(track)
def setSwitchHalftoneTranspose(trackId, position, transpose):
"""Halftone transposition is not flipped. Higher value means higher pitch"""
track = session.data.trackById(trackId)
session.history.register(lambda tr=trackId, v=track.whichPatternsAreHalftoneTransposed.copy(): _setSwitchHalftoneTranspose(trackId, v), descriptionString="Set Half Tone Shift")
track.whichPatternsAreHalftoneTransposed[position] = transpose
track.buildTrack()
updatePlayback()
callbacks._trackStructureChanged(track)
return True
def _registerHistoryWholeTrackSwitches(track):
"""This is used by insertSilence, clearSwitchGroupTranspositions etc.
It assumes to run inside the context:
with session.history.sequence(""):
"""
trackId = id(track)
session.history.register(lambda trId=trackId, v=track.patternLengthMultiplicator: setTrackPatternLengthMultiplicator(trId, v), descriptionString="Pattern Multiplier")
session.history.register(lambda trId=trackId, v=track.structure.copy(): _setTrackStructure(trId, v), descriptionString="Set Measures")
session.history.register(lambda trId=trackId, v=track.whichPatternsAreScaleTransposed.copy(): _setSwitchesScaleTranspose(trId, v), descriptionString="Set Modal Shift")
session.history.register(lambda trId=trackId, v=track.whichPatternsAreHalftoneTransposed.copy(): _setSwitchHalftoneTranspose(trId, v), descriptionString="Set Half Tone Shift")
def insertSilence(howMany:int, beforeMeasureNumber:int):
"""Insert empty measures into all tracks.
Parameters are un-multiplied."""
@ -617,13 +727,18 @@ def insertSilence(howMany:int, beforeMeasureNumber:int):
#In each track shift every switch to the right if it is before the dividing measure number
#Keep the concept of a "group" even if there are multiplicators in the track.
#If you insert 4 normal measures then a multiplicator-track of two gets only 2 new ones.
for track in session.data.tracks:
thisTrackWhere = beforeMeasureNumber // track.patternLengthMultiplicator #integer division
thisTrackHowMany = howMany // track.patternLengthMultiplicator #integer division
track.structure = set( (switch + thisTrackHowMany if switch >= thisTrackWhere else switch) for switch in track.structure )
track.whichPatternsAreScaleTransposed = { (k+thisTrackHowMany if k >= thisTrackWhere else k):v for k,v in track.whichPatternsAreScaleTransposed.items() }
track.whichPatternsAreHalftoneTransposed = { (k+thisTrackHowMany if k >= thisTrackWhere else k):v for k,v in track.whichPatternsAreHalftoneTransposed.items() }
callbacks._trackStructureChanged(track)
with session.history.sequence("Insert/Duplicate Group"): #this actually handles duplicateSwitchGroup undo as well!!!
for track in session.data.tracks:
_registerHistoryWholeTrackSwitches(track)
thisTrackWhere = beforeMeasureNumber // track.patternLengthMultiplicator #integer division
thisTrackHowMany = howMany // track.patternLengthMultiplicator #integer division
track.structure = set( (switch + thisTrackHowMany if switch >= thisTrackWhere else switch) for switch in track.structure )
track.whichPatternsAreScaleTransposed = { (k+thisTrackHowMany if k >= thisTrackWhere else k):v for k,v in track.whichPatternsAreScaleTransposed.items() }
track.whichPatternsAreHalftoneTransposed = { (k+thisTrackHowMany if k >= thisTrackWhere else k):v for k,v in track.whichPatternsAreHalftoneTransposed.items() }
callbacks._trackStructureChanged(track)
callbacks._dataChanged() #register undo
session.data.buildAllTracks()
updatePlayback()
@ -632,8 +747,9 @@ def duplicateSwitchGroup(startMeasureForGroup:int, endMeasureExclusive:int):
format."""
groupSize = endMeasureExclusive-startMeasureForGroup
insertSilence(groupSize, endMeasureExclusive) #insert silence handles multiplicator-tracks on its own
#Undo: InsertSilence has a complete undo already registered. We chose a neutral undo description so it handles both duplicate and insert silence.
insertSilence(groupSize, endMeasureExclusive) #insert silence handles multiplicator-tracks on its own
for track in session.data.tracks:
thisTrackStartMeasure = startMeasureForGroup // track.patternLengthMultiplicator #integer division
thisTrackEndMeasure = endMeasureExclusive // track.patternLengthMultiplicator
@ -647,59 +763,69 @@ def duplicateSwitchGroup(startMeasureForGroup:int, endMeasureExclusive:int):
if switch-thisGroupSize in track.whichPatternsAreHalftoneTransposed:
track.whichPatternsAreHalftoneTransposed[switch] = track.whichPatternsAreHalftoneTransposed[switch-thisGroupSize]
callbacks._trackStructureChanged(track)
session.data.buildAllTracks()
updatePlayback()
def clearSwitchGroupTranspositions(startMeasureForGroup:int, endMeasureExclusive:int):
"""startMeasureForGroup and endMeasureExclusive are in the global, un-multiplied measure counting
format."""
for track in session.data.tracks:
thisTrackStartMeasure = startMeasureForGroup // track.patternLengthMultiplicator #integer division
thisTrackEndMeasure = endMeasureExclusive // track.patternLengthMultiplicator
for switch in range(thisTrackStartMeasure, thisTrackEndMeasure):
if switch in track.whichPatternsAreScaleTransposed:
del track.whichPatternsAreScaleTransposed[switch]
if switch in track.whichPatternsAreHalftoneTransposed:
del track.whichPatternsAreHalftoneTransposed[switch]
callbacks._trackStructureChanged(track)
with session.history.sequence("Clear all Group Transpositions"):
for track in session.data.tracks:
_registerHistoryWholeTrackSwitches(track)
thisTrackStartMeasure = startMeasureForGroup // track.patternLengthMultiplicator #integer division
thisTrackEndMeasure = endMeasureExclusive // track.patternLengthMultiplicator
for switch in range(thisTrackStartMeasure, thisTrackEndMeasure):
if switch in track.whichPatternsAreScaleTransposed:
del track.whichPatternsAreScaleTransposed[switch]
if switch in track.whichPatternsAreHalftoneTransposed:
del track.whichPatternsAreHalftoneTransposed[switch]
callbacks._trackStructureChanged(track)
callbacks._dataChanged() #register undo
session.data.buildAllTracks()
updatePlayback()
def deleteSwitches(howMany, fromMeasureNumber):
"""Parameters are un-multiplied measures."""
for track in session.data.tracks:
thisTrackHowMany = howMany // track.patternLengthMultiplicator #integer division
thisTrackWhere = fromMeasureNumber // track.patternLengthMultiplicator #integer division
new_structure = set()
for switch in track.structure:
if switch < thisTrackWhere:
new_structure.add(switch)
elif switch >= thisTrackWhere+thisTrackHowMany: #like a text editor let gravitate left into the hole left by the deleted range
new_structure.add(switch-thisTrackHowMany)
#else: #discard all in range to delete
track.structure = new_structure
new_scaleTransposed = dict()
for k,v in track.whichPatternsAreScaleTransposed.items():
if k < thisTrackWhere:
new_scaleTransposed[k] = v
elif k >= thisTrackWhere+thisTrackHowMany: #like a text editor let gravitate left into the hole left by the deleted range
new_scaleTransposed[k-thisTrackHowMany] = v
#else: #discard all in range to delete
track.whichPatternsAreScaleTransposed = new_scaleTransposed
new_halftoneTransposed = dict()
for k,v in track.whichPatternsAreHalftoneTransposed.items():
if k < thisTrackWhere:
new_halftoneTransposed[k] = v
elif k >= thisTrackWhere+thisTrackHowMany: #like a text editor let gravitate left into the hole left by the deleted range
new_halftoneTransposed[k-thisTrackHowMany] = v
#else: #discard all in range to delete
track.whichPatternsAreHalftoneTransposed = new_halftoneTransposed
callbacks._trackStructureChanged(track)
with session.history.sequence("Delete whole Group"):
for track in session.data.tracks:
_registerHistoryWholeTrackSwitches(track)
thisTrackHowMany = howMany // track.patternLengthMultiplicator #integer division
thisTrackWhere = fromMeasureNumber // track.patternLengthMultiplicator #integer division
new_structure = set()
for switch in track.structure:
if switch < thisTrackWhere:
new_structure.add(switch)
elif switch >= thisTrackWhere+thisTrackHowMany: #like a text editor let gravitate left into the hole left by the deleted range
new_structure.add(switch-thisTrackHowMany)
#else: #discard all in range to delete
track.structure = new_structure
new_scaleTransposed = dict()
for k,v in track.whichPatternsAreScaleTransposed.items():
if k < thisTrackWhere:
new_scaleTransposed[k] = v
elif k >= thisTrackWhere+thisTrackHowMany: #like a text editor let gravitate left into the hole left by the deleted range
new_scaleTransposed[k-thisTrackHowMany] = v
#else: #discard all in range to delete
track.whichPatternsAreScaleTransposed = new_scaleTransposed
new_halftoneTransposed = dict()
for k,v in track.whichPatternsAreHalftoneTransposed.items():
if k < thisTrackWhere:
new_halftoneTransposed[k] = v
elif k >= thisTrackWhere+thisTrackHowMany: #like a text editor let gravitate left into the hole left by the deleted range
new_halftoneTransposed[k-thisTrackHowMany] = v
#else: #discard all in range to delete
track.whichPatternsAreHalftoneTransposed = new_halftoneTransposed
callbacks._trackStructureChanged(track)
callbacks._dataChanged() #register undo
session.data.buildAllTracks()
updatePlayback()

4
qtgui/mainwindow.py

@ -75,8 +75,8 @@ class MainWindow(TemplateMainWindow):
tooltip=QtCore.QCoreApplication.translate("Menu", "Change step-grouping but keep your music the same"),
)
self.ui.actionUndo.setVisible(False)
self.ui.actionRedo.setVisible(False)
#self.ui.actionUndo.setVisible(False)
#self.ui.actionRedo.setVisible(False)
#Playback Controls

5
template/engine/api.py

@ -78,7 +78,7 @@ class Callbacks(object):
def _dataChanged(self):
"""Only called from within the callbacks.
"""Only called from within the callbacks or template api.
This is about data the user cares about. In other words this is the indicator if you need
to save again.
@ -136,6 +136,7 @@ class Callbacks(object):
status = playbackStatus()
for func in self.setPlaybackTicks:
func(ppqn, status)
self._dataChanged() #includes _historyChanged
def _playbackStatusChanged(self):
"""Returns a bool if the playback is running.
@ -243,6 +244,8 @@ class Callbacks(object):
lst = [track.export() for track in session.data.tracks]
for func in self.numberOfTracksChanged:
func(lst)
self._dataChanged() #includes _historyChanged
def _metronomeChanged(self):
"""returns a dictionary with meta data such as the mute-state and the track name"""

2
template/engine/sequencer.py

@ -88,6 +88,7 @@ class Score(Data):
#Tracks
def addTrack(self, name:str=""):
"""Create and add a new track. Not an existing one"""
track = Score.TrackClass(parentData=self, name=name)
assert track.sequencerInterface
self.tracks.append(track)
@ -96,6 +97,7 @@ class Score(Data):
def deleteTrack(self, track):
track.sequencerInterface.prepareForDeletion()
self.tracks.remove(track)
return track #for undo
def updateJackMetadataSorting(self):
"""Add this to you "tracksChanged" or "numberOfTracksChanged" callback.

Loading…
Cancel
Save