callbacks._updateGraphTrackCC(trId,cc)#create content: CC points. user points and interpolated points.
setMetronome(session.data.currentMetronomeTrack.asMetronomeData,label=session.data.currentMetronomeTrack.name)#track.asMetronomeData is generated in staticRepresentation #template api. has callbacks
setMetronome(session.data.currentMetronomeTrack.asMetronomeData,label=session.data.currentMetronomeTrack.name)#track.asMetronomeData is generated in staticRepresentation #template api. has callbacks
callbacks._setCursor()
globallaborejoEngineStarted#makes for a convenient check. stepMidiInput uses it, which needs to know that the gui already started the api.
"cboxMidiOutUuid":trackState.track.sequencerInterface.cboxMidiOutUuid,#used for midi throught. Step midi shall produce sound through the current track.
"midiChannel":trackState.midiChannel(),#zero based
lineNumber=int(cursorExportObject["dotOnLine"]/2)+1#gui-stafflines are counted from 0 to n, top to bottom (listindex) while backend stafflines begin on -4
lineNumber=int(cursorExportObject["dotOnLine"]/2)+2#gui-stafflines are counted from 0 to n, top to bottom (listindex) while backend stafflines begin on -4
self.gapVertical=constantsAndConfigs.gridRhythm/constantsAndConfigs.ticksToPixelRatio#this is necessarry every time after stretching (ticksToPixelRatio) and after changing the gridRhythm
foriinrange(start,end):#range includes the first value but not the end. We know that and all functions in GuiGrid are designed accordingly. For example reactToLongerDuration starts on the highest value of the old number of lines since that was never drawn in the last round.
foriinrange(start,end):#range includes the first value but not the end. We know that and all functions in GuiGrid are designed accordingly. For example reactToMoreTracks starts on the highest value of the old number of lines since that was never drawn in the last round.
#it is possible that the grid did not change. proceed nevertheless
forlinself.linesHorizontal+self.linesVertical:
self.parent.removeWhenIdle(l)
self.linesHorizontal=[]#like the staff lines
self.linesVertical=[]#makes comparing tick positions easier by eye
self.gapVertical=constantsAndConfigs.gridRhythm/constantsAndConfigs.ticksToPixelRatio#this is necessarry every time after stretching (ticksToPixelRatio) and after changing the gridRhythm
self.nrOfHorizontalLines=int(self.height/self.gapHorizontal)#we save that value if the score grows and we need more lines. Initially we use the screen size, not the content.
self.nrOfVerticalLines=int(self.width/self.gapVertical)#we save that value if the score grows and we need more lines. Initially we use the screen size, not the content.
@ -39,7 +39,6 @@ from midiinput.stepmidiinput import stepMidiInput #singleton instance
from.constantsAndConfigsimportconstantsAndConfigs
from.menuimportMenuActionDatabase
from.scoreviewimportScoreView
from.structuresimportGuiScore
from.trackEditorimportTrackEditor
from.resourcesimport*
@ -63,7 +62,7 @@ class MainWindow(TemplateMainWindow):
About.didYouKnow=[
QtCore.QCoreApplication.translate("About","<p>Most commands work in the appending position (last position in a track) and apply to the item before it.</p><p>Use it to apply dots, sharps and flats on the item you just inserted without moving the cursor back and forth.</p>"),
QtCore.QCoreApplication.translate("About","<p>Learn the keyboard shortcuts! Laborejo is designed to work with the keyboard alone and with midi instruments for full speed.</p>Everytime you grab your mouse you loose concentration, precision and time."),
QtCore.QCoreApplication.translate("About","<p>Spread/shrink the space between notes with Ctrl+Mousewheel or Ctrl with Plus and Minus.</p><p>Full zoom by additionaly holding the Shift key.</p>"),
QtCore.QCoreApplication.translate("About","<p>Spread/shrink the space between notes with Ctrl+Shift+Mousewheel or Ctrl+Shift with Plus and Minus.</p>"),
QtCore.QCoreApplication.translate("About","<p>Click with the left mouse button to set the cursor to that position. Hold Shift to create a selection.</p>"),
QtCore.QCoreApplication.translate("About","<p>Most commands can be applied to single notes and selections equally.</p><p>Use Shift + movement-keys to create selections.</p>"),
QtCore.QCoreApplication.translate("About","<p>Blocks and Tracks can be moved in Block-View Mode [F6]. Use Shift+Middle Mouse Button to move blocks and Alt+Middle to reorder tracks.</p>"),
@ -124,6 +123,12 @@ class MainWindow(TemplateMainWindow):
self.scoreView.scoreScene.grid.redrawTickGrid()#Init the grid only after everything got loaded and drawn to prevent a gap in the display. #TODO: which might be a bug. but this here works fine.
defzoom(self,scaleFactor:float):
"""Scale factor is absolute"""
self.scoreView.zoom(scaleFactor)
defstretchXCoordinates(self,factor:float):
self.scoreView.stretchXCoordinates(factor)
defupdateStatusBar(self,exportCursorDict):
"""Every cursor movement updates the statusBar message"""
@ -134,7 +139,7 @@ class MainWindow(TemplateMainWindow):
oneRectToReturnThemAll=QtCore.QRectF(0,0,0,0)#prevent the annoying "NotImplementError" from Qt for boundingRect. #TODO: implement in each class for realsies
cosmeticPen=QtGui.QPen()
cosmeticPen.setCosmetic(True)
classGuiBlockHandle(QtWidgets.QGraphicsRectItem):
"""A simplified version of a Block. Since we don't use blocks in the GUI, only in the backend
westillneedthemsometimesasmacrostrutures,wherewedon't care about the content.
@ -53,6 +54,8 @@ class GuiBlockHandle(QtWidgets.QGraphicsRectItem):
self.setFlag(QtWidgets.QGraphicsItem.ItemHasNoContents,True)#only child items. Without this we get notImplementedError: QGraphicsItem.paint() is abstract and must be overridden
self.color=None#inserted by the creating function in GuiTrack
self.trans=QtGui.QColor("transparent")
@ -185,6 +188,9 @@ class GuiTrack(QtWidgets.QGraphicsItem):
def__init__(self,parentScore,staticExportItem):
super().__init__()
self.setFlag(QtWidgets.QGraphicsItem.ItemHasNoContents,True)#only child items. Without this we get notImplementedError: QGraphicsItem.paint() is abstract and must be overridden
@ -392,14 +392,13 @@ class GuiTrack(QtWidgets.QGraphicsItem):
classTrackAnchor(QtWidgets.QGraphicsItem):
"""Handling all items as individuals when deleting a track to redraw it is too much.
BetterletQthandleitallatonce."""
oneRectToReturnThemAll=QtCore.QRectF(0,0,0,0)#prevent the annoying "NotImplementError" from Qt for boundingRect. For items that don't need any collision detection.
def__init__(self,parent):
super().__init__()
self.parent=parent
defpaint(self,*args):
pass
defboundingRect(self,*args):
returnoneRectToReturnThemAll
self.setFlag(QtWidgets.QGraphicsItem.ItemHasNoContents,True)#only child items. Without this we get notImplementedError: QGraphicsItem.paint() is abstract and must be overridden
self.tracks={}#trackId:guiTrack, #if we don't save the instances here in Python space Qt will loose them and they will not be displayed without any error message.
self.deleteOnIdleStack=[]# a stack that holds hidden items that need to be deleted. Hiding is much faster than deleting so we use that for the blocking function. Since we always recreate items and never re-use this is ok as a list. no need for a set.
self._deleteOnIdleLoop=QtCore.QTimer()
self._deleteOnIdleLoop.start(0)#0 means "if there is time"
self.hiddenTrackCounter=QtWidgets.QGraphicsSimpleTextItem("")#filled in by self.redraw on callback tracksChanged (loading or toggling visibility of backend tracks)
self.addItem(self.hiddenTrackCounter)
self.backColor=QtGui.QColor()
self.backColor.setNamedColor("#fdfdff")
self.setBackgroundBrush(self.backColor)
self.grid=GuiGrid(parent=self)
self.addItem(self.grid)
self.grid.setPos(0,-20*constantsAndConfigs.stafflineGap)#this is more calculation than simply using self.yStart, and might require manual adjustment in the future, but at least it guarantees the grid matches the staffline positions
self.grid.setZValue(-50)
self.cachedSceneHeight=0#set in self.redraw. Used by updateTrack to set the sceneRect
#return max(max(tr.lengthInPixel for tr in self.tracks.values()), self.parentView.geometry().width())
#return max(max(tr.lengthInPixel for tr in self.scene().tracks.values()), self.scene().parentView.geometry().width()) + self.scene().parentView.geometry().width()
targetTrack=self.trackAt(event.scenePos())#this ALWAYS returns a Conductor, GuiTrack or None. Not a CC sub-track. for CC see below when we test the block type and change this variable.
returnNone#TODO: Create a new CC sub-track with the moved block as first block. Mainly a backend call. Needs a call at the end of this function as well.
else:
raiseTypeError("Block must be a conductor, note or CC type but is {}".format(blockType))
#We now have a track and the track type matches the block type.
#Find the position to insert.
iftargetBlockisNone:#behind the last block
positionToInsert=len(targetTrack.transparentBlockHandles)#essentially we want append() but insert() is compatible with all types of operation here. len is based 1, so len results in "after the last one" position.
self.tracks={}#trackId:guiTrack, #if we don't save the instances here in Python space Qt will loose them and they will not be displayed without any error message.
self.deleteOnIdleStack=[]# a stack that holds hidden items that need to be deleted. Hiding is much faster than deleting so we use that for the blocking function. Since we always recreate items and never re-use this is ok as a list. no need for a set.
self._deleteOnIdleLoop=QtCore.QTimer()
self._deleteOnIdleLoop.start(0)#0 means "if there is time"
self.hiddenTrackCounter=QtWidgets.QGraphicsSimpleTextItem("")#filled in by self.redraw on callback tracksChanged (loading or toggling visibility of backend tracks)
self.addItem(self.hiddenTrackCounter)
self.backColor=QtGui.QColor()
self.backColor.setNamedColor("#fdfdff")
self.setBackgroundBrush(self.backColor)
self.grid=GuiGrid(parent=self)
self.addItem(self.grid)
self.grid.setPos(0,-20*constantsAndConfigs.stafflineGap)#this is more calculation than simply using self.yStart, and might require manual adjustment in the future, but at least it guarantees the grid matches the staffline positions
self.grid.setZValue(-50)
self.cachedSceneHeight=0#set in self.redraw. Used by updateTrack to set the sceneRect
#return max(max(tr.lengthInPixel for tr in self.tracks.values()), self.parentView.geometry().width())
#return max(max(tr.lengthInPixel for tr in self.scene().tracks.values()), self.scene().parentView.geometry().width()) + self.scene().parentView.geometry().width()