Browse Source

Add missing rects and removal of whitespace

master
Nils 4 years ago
parent
commit
58de2ba26c
  1. 135
      qtgui/conductor.py
  2. 21
      qtgui/cursor.py
  3. 22
      qtgui/graphs.py
  4. 21
      qtgui/grid.py
  5. 9
      qtgui/items.py
  6. 54
      qtgui/mainwindow.py
  7. 26
      qtgui/menu.py
  8. 20
      qtgui/musicstructures.py
  9. 45
      qtgui/scorescene.py
  10. 16
      qtgui/scoreview.py
  11. 28
      qtgui/submenus.py
  12. 6
      qtgui/trackEditor.py

135
qtgui/conductor.py

@ -30,12 +30,12 @@ import engine.api as api
oneRectToReturnThemAll = QtCore.QRectF(0,0,0,0) #prevent the annoying "NotImplementError" from Qt for boundingRect. For items that don't need any collision detection.
_zValuesRelativeToConductor = { #Only use for objects added directly to the Conductor, not their children.
_zValuesRelativeToConductor = { #Only use for objects added directly to the Conductor, not their children.
"line":0,
"startItem":1,
"block":2,
"item":4,
"handle":5,
"startItem":1,
"block":2,
"item":4,
"handle":5,
}
class Conductor(QtWidgets.QGraphicsItem):
@ -52,6 +52,8 @@ class Conductor(QtWidgets.QGraphicsItem):
self.staticBlocks = None #Cached Block Data list
self.staticMeta = None #Cached track meta data dict.
self.setFlag(QtWidgets.QGraphicsItem.ItemHasNoContents, True) #only child items. Without this we get notImplementedError: QGraphicsItem.paint() is abstract and must be overridden
self.staffLine = QtWidgets.QGraphicsLineItem(0,0,10,0) #x1, y1, x2, y2
self.staffLine.setParentItem(self)
self.staffLine.setPos(0,0)
@ -64,10 +66,9 @@ class Conductor(QtWidgets.QGraphicsItem):
api.callbacks.updateTempoTrack.append(self.createGraphicItemsFromData)
api.callbacks.updateTempoTrackMeta.append(self.updateMetaData)
def paint(self, *args):
pass
def boundingRect(self, *args):
return oneRectToReturnThemAll
"""The tempo track extends above the real tracks"""
return QtCore.QRectF(0, -1*self.totalHeight, 20000, 1.2*self.totalHeight) #x,y,w,h
def blockAt(self, xScenePosition):
for block in ConductorTransparentBlock.instances:
@ -97,7 +98,7 @@ class Conductor(QtWidgets.QGraphicsItem):
for dictExportItem in staticRepresentationList:
guiBlock = ConductorTransparentBlock(parent = self, staticExportItem = dictExportItem, x = 0, y = -10, w = dictExportItem["duration"] / constantsAndConfigs.ticksToPixelRatio, h = 20)
guiBlock.setParentItem(self)
guiBlock.setPos(dictExportItem["position"] / constantsAndConfigs.ticksToPixelRatio,0)
guiBlock.setPos(dictExportItem["position"] / constantsAndConfigs.ticksToPixelRatio,0)
rightBorder = (dictExportItem["duration"] + dictExportItem["position"]) / constantsAndConfigs.ticksToPixelRatio
self.updateStaffLine(rightBorder)
@ -108,7 +109,7 @@ class Conductor(QtWidgets.QGraphicsItem):
return guiblock
#else:
# raise ValueError(f"{backendId} not found")
def updateStaffLine(self, x):
assert not self.staffLine.line().isNull()
@ -117,8 +118,8 @@ class Conductor(QtWidgets.QGraphicsItem):
self.staffLine.setLine(line)
self.staffLine.setZValue(_zValuesRelativeToConductor["line"])
def createGraphicItemsFromData(self, staticRepresentationList):
def createGraphicItemsFromData(self, staticRepresentationList):
self.staticPoints = staticRepresentationList
removeInstancesFromScene(TempoPoint)
@ -129,8 +130,8 @@ class Conductor(QtWidgets.QGraphicsItem):
x = point["position"] / constantsAndConfigs.ticksToPixelRatio
p = TempoPoint(self, point, self.blockById(point["blockId"]))
p.setParentItem(self)
p.setPos(x, y)
p.setPos(x, y)
def stretchXCoordinates(self, factor):
"""Reposition the items on the X axis.
@ -163,21 +164,21 @@ class Conductor(QtWidgets.QGraphicsItem):
def add(self, scenePos):
"""Use a scenePos (from self.mousePressEvent) to instruct the backend
to create a new tempo point.
Uses the values from the item left of it
Uses the values from the item left of it
"""
sp = scenePos.x() * constantsAndConfigs.ticksToPixelRatio
if constantsAndConfigs.snapToGrid:
sp = round(sp / constantsAndConfigs.gridRhythm) * constantsAndConfigs.gridRhythm
unitsPerMinute, referenceTicks = api.tempoAtTickPosition(sp)
api.insertTempoItemAtAbsolutePosition(sp, unitsPerMinute, referenceTicks, graphType = "standalone")
class ConductorTransparentBlock(QtWidgets.QGraphicsRectItem):
"""A simplified version of a Block. Since we don't use blocks in the GUI, only in the backend
we still need them sometimes as macro strutures, where we don't care about the content.
The block handle is at the END of a block. """
@ -205,9 +206,9 @@ class ConductorTransparentBlock(QtWidgets.QGraphicsRectItem):
self.color = stringToColor(staticExportItem["name"])
self.trans = QtGui.QColor("transparent")
self.setPen(self.trans)
self.setBrush(self.color)
self.setOpacity(0.2) #mimic background behaviour
self.staticExportItem = staticExportItem
self.setBrush(self.color)
self.setOpacity(0.2) #mimic background behaviour
self.staticExportItem = staticExportItem
self.posBeforeMove = None
self.cursorPosOnMoveStart = None
@ -230,14 +231,19 @@ class ConductorTransparentBlock(QtWidgets.QGraphicsRectItem):
self.startLabel = QtWidgets.QGraphicsSimpleTextItem("")
self.endLabel = QtWidgets.QGraphicsSimpleTextItem("")
#Add Resizing Handle at the end
#Add Resizing Handle at the end
self.marker = ConductorBlockHandle(parent = self)
self.marker.setParentItem(self)
self.marker.setPos(staticExportItem["duration"] / constantsAndConfigs.ticksToPixelRatio, -1/2* self.rect().height()+2)
#self.setZValue(_zValuesRelativeToConductor["handle"]) #includes the handle
#Doesn't need it because only pure QGraphicItem subclasses need that. But we are already a rect.
#def boundingRect(self, *args):
# return oneRectToReturnThemAll
#Doesn't need it because only pure QGraphicItem subclasses need that. But we are already a rect.
#def paint(self, *args):
# """Prevent the selection rectangle when clicking the item"""
#!! This also prevents the rectangle to show up. Very bad decision.
@ -251,13 +257,13 @@ class ConductorTransparentBlock(QtWidgets.QGraphicsRectItem):
self.marker.setX(self.marker.pos().x() * factor)
def mouseMoveEvent(self, event):
"""Don't use the qt system. we move ourselves"""
"""Don't use the qt system. we move ourselves"""
event.accept()
def mousePressEvent(self, event):
self.parent.mousePressEvent(event)
def mouseMoveEventCustom(self, event):
def mouseMoveEventCustom(self, event):
"""
Move the whole block, change the tempoTrack form.
Custom gets called by the scene mouse press event directly only when the right keys
@ -272,7 +278,7 @@ class ConductorTransparentBlock(QtWidgets.QGraphicsRectItem):
#posView = self.parent.parentScore.parentView.mapFromGlobal(posGlobal) #a widget
#posScene = self.parent.parentScore.parentView.mapToScene(posView)
#print (posGlobal, posView, posScene, event.scenePos())
if self.cursorPosOnMoveStart:
self.setPos(event.scenePos().x(), self.posBeforeMove.y())
@ -340,13 +346,13 @@ class ConductorBlockHandle(QtWidgets.QGraphicsRectItem):
def __init__(self, parent):
self.parentTransparentBlock = parent
#Line item super().__init__(0,-1, 0, parent.rect().height()-4) #x1, y1, x2, y2
super().__init__(-3, -2, 3, parent.rect().height()) #x, y, w, h
super().__init__(-3, -2, 3, parent.rect().height()) #x, y, w, h
self.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable|QtWidgets.QGraphicsItem.ItemSendsGeometryChanges|QtWidgets.QGraphicsItem.ItemIsFocusable|QtWidgets.QGraphicsItem.ItemIgnoresParentOpacity) #QtWidgets.QGraphicsItem.ItemClipsToShape puts the item behind the parent rect and only receives event inside its own shape.
self.setAcceptHoverEvents(True)
self.setCursor(QtCore.Qt.SizeHorCursor)
self.setZValue(_zValuesRelativeToConductor["handle"]) #The handle does not compete with the transparent block but with its contents! Therefore the startItem is set to have a custom lower priority than the handle
self.setBrush(QtGui.QColor("black"))
self.minimalSize = api.D1 / constantsAndConfigs.ticksToPixelRatio
pen = QtGui.QPen() # creates a default pen
@ -359,8 +365,8 @@ class ConductorBlockHandle(QtWidgets.QGraphicsRectItem):
self.inactivePen.setColor(QtGui.QColor("black"))
self.activePen = QtGui.QPen(pen)
self.activePen.setColor(QtGui.QColor("cyan"))
self.activePen.setColor(QtGui.QColor("cyan"))
def shape(self):
"""Return a more accurate shape for this item so that
mouse hovering is more accurate"""
@ -368,14 +374,14 @@ class ConductorBlockHandle(QtWidgets.QGraphicsRectItem):
path.addRect(QtCore.QRectF(-2, -2, 5, self.parentTransparentBlock.rect().height()+2 )) #this is directly related to inits parameter x, y, w, h
return path
def hoverEnterEvent(self, event):
def hoverEnterEvent(self, event):
self.setPen(self.activePen)
#self.parentTransparentBlock.setBrush(self.parentTransparentBlock.color)
self.setBrush(QtGui.QColor("cyan"))
#self.parentTransparentBlock.setBrush(self.parentTransparentBlock.color)
self.setBrush(QtGui.QColor("cyan"))
def hoverLeaveEvent(self, event):
def hoverLeaveEvent(self, event):
self.setPen(self.inactivePen)
#self.parentTransparentBlock.setBrush(self.parentTransparentBlock.trans)
#self.parentTransparentBlock.setBrush(self.parentTransparentBlock.trans)
self.setBrush(QtGui.QColor("black"))
def mousePressEvent(self, event):
@ -418,7 +424,7 @@ class ConductorBlockHandle(QtWidgets.QGraphicsRectItem):
class TempoPoint(QtWidgets.QGraphicsItem):
"""A point where the values can be edited by the user.
The first TempoPoint cannot be hovered. It is instead attached to a block handle.
"""
@ -429,19 +435,16 @@ class TempoPoint(QtWidgets.QGraphicsItem):
super().__init__()
self.staticExportItem = staticExportItem
self.parentTempoTrack = parentTempoTrack
self.parentBlock = parentBlock
self.parentBlock = parentBlock
self.setZValue(_zValuesRelativeToConductor["item"])
self.setAcceptHoverEvents(True)
if not self.staticExportItem["positionInBlock"] == 0:
if not self.staticExportItem["positionInBlock"] == 0:
self.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable|QtWidgets.QGraphicsItem.ItemIsFocusable)
#Too irritating. And confuses with handle movement. self.setCursor(QtCore.Qt.SizeHorCursor) #this sets the cursor while the mouse is over the item. It is independent of AcceptHoverEvents
else:
else:
self.setZValue(0) #avoid hovering conflict with block handle
self.ungrabMouse = api.nothing #to surpress a warning from the context menu
self.ungrabMouse = api.nothing #to surpress a warning from the context menu
self.note = QtWidgets.QGraphicsTextItem("")
self.note.setParentItem(self)
@ -465,7 +468,7 @@ class TempoPoint(QtWidgets.QGraphicsItem):
for n in (self.note, self.number, self.arrow):
if n: n.setDefaultTextColor(QtGui.QColor("black"))
self.wheelEventChangedValue = 0 #resetted in hoverEnterEvent. But we still need it for new items that appear directly under the mouse cursor
self.wheelEventChangedValue = 0 #resetted in hoverEnterEvent. But we still need it for new items that appear directly under the mouse cursor
def paint(self, painter, options, widget=None):
#painter.drawRect(self.boundingRect()) #uncomment to show the bounding rect
@ -491,21 +494,21 @@ class TempoPoint(QtWidgets.QGraphicsItem):
event.accept()
def mousePressEvent(self, event):
"""Override the mousePressEvent to deactivate it.
"""Override the mousePressEvent to deactivate it.
Otherwise the event will be sent to the parent block and create a new TempoItem
at this point even if there is already one. Effectively replacing a custom item with
at this point even if there is already one. Effectively replacing a custom item with
default value"""
#if self.staticExportItem["positionInBlock"] == 0:
# print ("no")
# #super().mousePressEvent(event)
# #super().mousePressEvent(event)
event.accept() #
def mouseReleaseEvent(self, event):
def mouseReleaseEvent(self, event):
if self.staticExportItem["positionInBlock"] == 0:
#First in block can't be moved
event.accept()
return
tickPositionAbsolute = self.scenePos().x() * constantsAndConfigs.ticksToPixelRatio
if constantsAndConfigs.snapToGrid:
@ -513,17 +516,17 @@ class TempoPoint(QtWidgets.QGraphicsItem):
api.moveTempoItem(self.staticExportItem["id"], tickPositionAbsolute)
event.accept()
def hoverEnterEvent(self, event):
self.parentTempoTrack.parentView.mainWindow.ui.actionDelete.setEnabled(False) #Delete key collides with our hover-delete.
self.grabKeyboard()
self.wheelEventChangedValue = 0
def hoverEnterEvent(self, event):
self.parentTempoTrack.parentView.mainWindow.ui.actionDelete.setEnabled(False) #Delete key collides with our hover-delete.
self.grabKeyboard()
self.wheelEventChangedValue = 0
for n in (self.note, self.number, self.arrow):
if n: n.setDefaultTextColor(QtGui.QColor("cyan"))
def hoverLeaveEvent(self, event):
def hoverLeaveEvent(self, event):
self.parentTempoTrack.parentView.mainWindow.ui.actionDelete.setEnabled(True) #Delete key collides with our hover-delete.
self.ungrabKeyboard()
self.ungrabKeyboard()
for n in (self.note, self.number, self.arrow):
if n: n.setDefaultTextColor(QtGui.QColor("black"))
if self.wheelEventChangedValue:
@ -531,7 +534,6 @@ class TempoPoint(QtWidgets.QGraphicsItem):
def wheelEvent(self, event):
"""This buffers until hoverLeaveEvent and then the new value is sent in self.hoverLeaveEvent"""
print ("w")
if event.delta() > 0:
self.wheelEventChangedValue += 1
else:
@ -542,15 +544,15 @@ class TempoPoint(QtWidgets.QGraphicsItem):
def keyPressEvent(self, event):
"""Handle the delete item key.
Needs grabKeyboard, but NOT setFocus
The event will not be sent if it is blocked by a global shortcut.
"""
key = event.key()
key = event.key()
if key == 16777223:
#after delete the item and tempo tracks gets recreated so we need to reactivate the shortcut now. It will work without these two lines, but that is only implicit behaviour.
self.parentTempoTrack.parentView.mainWindow.ui.actionDelete.setEnabled(True) #Delete key collides with our hover-delete.
self.ungrabKeyboard()
api.removeTempoItem(self.staticExportItem["id"])
self.ungrabKeyboard()
api.removeTempoItem(self.staticExportItem["id"])
else:
return super().keyPressEvent(event)
@ -581,15 +583,16 @@ class TimeLine(QtWidgets.QGraphicsItem):
def __init__(self, parent):
super().__init__()
self.parent = parent
self.parent = parent #
self.gridInSeconds = 10
api.callbacks.updateTempoTrackBlocks.append(self.redraw)
#no redraw on init. self.parent.staticPoints is not set yet.
def paint(self, *args):
pass
def boundingRect(self, *args):
return oneRectToReturnThemAll
return self.parent.boundingRect()
def redraw(self, staticRepresentationList):
if not self.parent.staticPoints:
@ -640,7 +643,3 @@ class TimeLine(QtWidgets.QGraphicsItem):
time grid"""
for timePoint in self.TimePoint.instances:
timePoint.setX(timePoint.pos().x() * factor)

21
qtgui/cursor.py

@ -31,6 +31,8 @@ pen.setJoinStyle(QtCore.Qt.RoundJoin)
pen.setWidth(2)
#pen.setColor(QtGui.QColor("red"))
oneRectToReturnThemAll = QtCore.QRectF(0,0,0,0) #prevent the annoying "NotImplementError" from Qt for boundingRect. For items that don't need any collision detection.
class PitchCursor(QtWidgets.QGraphicsRectItem):
def __init__(self):
"""Does not need the actual dotOnLine.
@ -42,6 +44,8 @@ class PitchCursor(QtWidgets.QGraphicsRectItem):
self.setPen(pen)
self.setEnabled(False)
def boundingRect(self, *args): return oneRectToReturnThemAll
class PositionCursor(QtWidgets.QGraphicsRectItem):
def __init__(self):
"""Does not need the actual position.
@ -53,6 +57,10 @@ class PositionCursor(QtWidgets.QGraphicsRectItem):
self.setScale(0.8)
self.setEnabled(False)
def boundingRect(self, *args):
return oneRectToReturnThemAll
class Cursor(QtWidgets.QGraphicsItemGroup):
"""A cursor that shows the vertical
as well as the horizontal position
@ -67,6 +75,10 @@ class Cursor(QtWidgets.QGraphicsItemGroup):
api.callbacks.setCursor.append(self.setCursor)
self.setEnabled(False)
def boundingRect(self, *args):
return oneRectToReturnThemAll
def clearItemHighlight(self):
"""Gets called before a track changes. Most of the time when a new item is inserted/deleted.
This means the gui track will be recreated and a current highlight on an item might get
@ -93,7 +105,7 @@ class Cursor(QtWidgets.QGraphicsItemGroup):
x = cursorExportObject["tickindex"] / constantsAndConfigs.ticksToPixelRatio
#Finally shift the Position to the correct track. Trackindex from 0, naturally.
#self.setPos(x, constantsAndConfigs.timeLineOffsetNoteEditor + cursorExportObject["trackIndex"] * constantsAndConfigs.trackHeight)
#self.setPos(x, constantsAndConfigs.timeLineOffsetNoteEditor + cursorExportObject["trackIndex"] * constantsAndConfigs.trackHeight)
currentGuiTrack = self.scene().tracks[cursorExportObject["trackId"]]
self.setPos(x, currentGuiTrack.y() )
@ -142,6 +154,10 @@ class Playhead(QtWidgets.QGraphicsLineItem):
#self.hide()
#self.maxHeight = QtWidgets.QDesktopWidget().geometry().height() #we really hope the screen resolution does not change during the session.
def boundingRect(self, *args):
return oneRectToReturnThemAll
def setCursorPosition(self, tickindex:int, playbackStatus:bool):
"""Set the playhead to the right position, but keep the viewport stable.
Shift the entire "page" if the cursor becomes invisible because its steps outside the viewport"""
@ -215,6 +231,9 @@ class Selection(QtWidgets.QGraphicsRectItem):
self.setEnabled(False)
api.callbacks.setSelection.append(self.setSelection)
def boundingRect(self, *args):
return oneRectToReturnThemAll
def setSelection(self, tupleOfCursorExportObjects):
if tupleOfCursorExportObjects:
validSelection, topleftCursorObject, bottomRightCursorObject = tupleOfCursorExportObjects

22
qtgui/graphs.py

@ -25,6 +25,8 @@ from .constantsAndConfigs import constantsAndConfigs
from template.qtgui.helper import stringToColor, removeInstancesFromScene, callContextMenu, stretchLine, stretchRect
import engine.api as api
oneRectToReturnThemAll = QtCore.QRectF(0,0,0,0) #prevent the annoying "NotImplementError" from Qt for boundingRect. For items that don't need any collision detection.
class CCPath(QtWidgets.QGraphicsRectItem):
"""
A CCPath only exists when the backend track has a cc-part activated.
@ -66,6 +68,8 @@ class CCPath(QtWidgets.QGraphicsRectItem):
self.blockdictCache = {} #blockId:guiBlock updated through self.updateGraphBlockTrack
self.transparentBlockHandles = [] #transparentBlockHandles in correct order. updated through self.updateGraphBlockTrack
def boundingRect(self, *args): return oneRectToReturnThemAll
def itemChange(self, changeEnum, value):
if changeEnum == QtWidgets.QGraphicsItem.ItemVisibleHasChanged: #12
if self.isVisible():
@ -76,7 +80,7 @@ class CCPath(QtWidgets.QGraphicsRectItem):
return super().itemChange(changeEnum, value)
def mousePressEvent(self, event):
if event.button() == 1: #QtCore.Qt.MouseButton.LeftButton
if event.button() == 1: #QtCore.Qt.LeftButton
self.add(event.pos())
@property
@ -253,6 +257,8 @@ class CCGraphTransparentBlock(QtWidgets.QGraphicsRectItem):
self.posBeforeMove = None
self.cursorPosOnMoveStart = None
def boundingRect(self, *args): return oneRectToReturnThemAll
def stretchXCoordinates(self, factor):
"""Reposition the items on the X axis.
Call goes through all parents/children, starting from ScoreView._stretchXCoordinates.
@ -359,6 +365,8 @@ class CCGraphBlockEndMarker(QtWidgets.QGraphicsLineItem):
self.activePen = QtGui.QPen(pen)
self.activePen.setColor(QtGui.QColor("cyan"))
def boundingRect(self, *args): return oneRectToReturnThemAll
def allItemsRightOfMe(self):
for item in self.parentCCPath.items:
if item.x() > self.x():
@ -376,7 +384,7 @@ class CCGraphBlockEndMarker(QtWidgets.QGraphicsLineItem):
"""After moving a point around
send an update to the backend"""
super(CCGraphBlockEndMarker, self).mouseReleaseEvent(event)
if event.button() == 1: #QtCore.Qt.MouseButton.LeftButton
if event.button() == 1: #QtCore.Qt.LeftButton
x = event.scenePos().x()
#x = self.x()
x = x * constantsAndConfigs.ticksToPixelRatio
@ -390,7 +398,7 @@ class CCGraphBlockEndMarker(QtWidgets.QGraphicsLineItem):
def mousePressEvent(self, event):
super(CCGraphBlockEndMarker, self).mousePressEvent(event)
if event.button() == 1: #QtCore.Qt.MouseButton.LeftButton
if event.button() == 1: #QtCore.Qt.LeftButton
for i in self.allItemsRightOfMe():
i.hide()
@ -422,6 +430,8 @@ class CCInterpolatedPoint(QtWidgets.QGraphicsEllipseItem):
self.setEnabled(False)
self.setZValue(1)
def boundingRect(self, *args): return oneRectToReturnThemAll
class CCUserPoint(QtWidgets.QGraphicsEllipseItem):
"""the position is set by the parent"""
def __init__(self, parentCCPath, staticExportItem):
@ -439,6 +449,8 @@ class CCUserPoint(QtWidgets.QGraphicsEllipseItem):
self.interpolatedItemsLeft = []
self.setZValue(9)
def boundingRect(self, *args): return oneRectToReturnThemAll
def shape(self):
"""Return a more accurate shape for this item so that
mouse hovering is more accurate"""
@ -450,7 +462,7 @@ class CCUserPoint(QtWidgets.QGraphicsEllipseItem):
super().mousePressEvent(event)
self.lastPos = self.pos()
if event.button() == 1: #QtCore.Qt.MouseButton.LeftButton
if event.button() == 1: #QtCore.Qt.LeftButton
self.setCursor(QtCore.Qt.BlankCursor)
for i in self.interpolatedItemsLeft + self.interpolatedItemsRight:
i.hide()
@ -480,7 +492,7 @@ class CCUserPoint(QtWidgets.QGraphicsEllipseItem):
send an update to the backend"""
super(CCUserPoint, self).mouseReleaseEvent(event)
self.setCursor(QtCore.Qt.SizeAllCursor)
if event.button() == 1: #QtCore.Qt.MouseButton.LeftButton
if event.button() == 1: #QtCore.Qt.LeftButton
api.changeGraphItem(self.staticExportItem["id"], self.getXDifferenceAsBackendValue(), self.getYAsBackendValue()) #send update to the backend, don't wait for callback.
def mouseMoveEvent(self, event):

21
qtgui/grid.py

@ -21,15 +21,32 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging; logger = logging.getLogger(__name__); logger.info("import")
#Standard Library
#Third Party
from PyQt5 import QtCore, QtGui, QtWidgets
#Our Template Modules
from template.engine.sequencer import MAXIMUM_TICK_DURATION
#Client Modules
from .constantsAndConfigs import constantsAndConfigs
import engine.api as api
oneRectToReturnThemAll = QtCore.QRectF(0,0,0,0) #prevent the annoying "NotImplementError" from Qt for boundingRect. For items that don't need any collision detection.
masterLine = QtCore.QLineF(0, 0, 0, 128*constantsAndConfigs.stafflineGap) # (x1, y1, x2, y2)
class RhythmLine(QtWidgets.QGraphicsLineItem):
def __init__(self, parentGrid):
super().__init__(masterLine)
self.setEnabled(False)
self.setParentItem(parentGrid)
self.setAcceptedMouseButtons(QtCore.Qt.NoButton) #we still need this otherwise no rubberband.
class GuiGrid(QtWidgets.QGraphicsItemGroup):
"""The grid consists of vertical and horizontal lines.
@ -49,7 +66,7 @@ class GuiGrid(QtWidgets.QGraphicsItemGroup):
A complete clean and redraw only happens when the tick rhythm changes.
"""
def __init__(self, parent, horizontalSize=None):
def __init__(self, parent, horizontalSize=None):
super(GuiGrid, self).__init__()
self.parent = parent #QGraphicsScene
@ -81,6 +98,8 @@ class GuiGrid(QtWidgets.QGraphicsItemGroup):
gridPen = QtGui.QPen(QtCore.Qt.DotLine)
gridPen.setCosmetic(True)
def boundingRect(self, *args): return oneRectToReturnThemAll
def reactToHorizontalScroll(self, value):
if not self.initialGridExists:
return

9
qtgui/items.py

@ -60,6 +60,9 @@ class GuiTieCurveGraphicsItem(QtWidgets.QGraphicsPathItem):
self.noteExportObject = noteExportObject
self.draw()
def boundingRect(self, *args):
return oneRectToReturnThemAll
def draw(self):
lengthInPixel = self.noteExportObject["tieDistanceInTicks"] / constantsAndConfigs.ticksToPixelRatio
path = QtGui.QPainterPath()
@ -756,13 +759,13 @@ class GuiMetricalInstruction(GuiItem):
displayString = "Metrical " + r
markerPosition = -2
markerHeight = 4
#A metrical instruction is by definition at the beginning of a measure
#We therefore need to place the text above the barnumber
self.text = QtWidgets.QGraphicsSimpleTextItem(displayString)
self.text.setParentItem(self)
self.text.setPos(0, -7 * constantsAndConfigs.stafflineGap)
self.text.setPos(0, -7 * constantsAndConfigs.stafflineGap)
self.marker = GuiPositionMarker(markerHeight, markerPosition)
self.marker.setParentItem(self)
@ -913,6 +916,6 @@ def staticItem2Item(staticItem):
elif typ is "BlockEndMarker":
return GuiBlockEndMarker(staticItem)
elif typ in ("InstrumentChange", "ChannelChange", "LilypondText"):
return GuiGenericText(staticItem)
return GuiGenericText(staticItem)
else:
raise ValueError("Unknown Item Type:", staticItem)

54
qtgui/mainwindow.py

@ -60,7 +60,7 @@ class MainWindow(TemplateMainWindow):
#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 = [
About.didYouKnow = [
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>"),
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."),
translate("About", "<p>Spread/shrink the space between notes with Ctrl+Shift+Mousewheel or Ctrl+Shift with Plus and Minus.</p>"),
@ -74,19 +74,19 @@ class MainWindow(TemplateMainWindow):
translate("About", "<p>There is no key-rebinding except numpad-shortcuts.</p>"),
translate("About", "<p>Hidden tracks still output sound.</p>"),
translate("About", "<p>Non-audible tracks still output instrument changes and CCs so that they can be switched on again in the middle of playback.</p>"),
] + About.didYouKnow
] + About.didYouKnow
super().__init__()
#New menu entries and template-menu overrides
self.menu.addMenuEntry("menuDebug", "actionRedrawAllTracks", "Redraw all Tracks")
self.menu.connectMenuEntry("actionSave", api.save)
self.menu.hideSubmenu("menuFile")
self.menu.hideSubmenu("menuGeneric")
api.callbacks.setCursor.append(self.updateStatusBar) #returns a dict. This get's called after loading the file so the status bar is filled on self.show
#New menu entries and template-menu overrides
self.menu.addMenuEntry("menuDebug", "actionRedrawAllTracks", "Redraw all Tracks")
self.menu.connectMenuEntry("actionSave", api.save)
self.menu.hideSubmenu("menuFile")
self.menu.hideSubmenu("menuGeneric")
api.callbacks.setCursor.append(self.updateStatusBar) #returns a dict. This get's called after loading the file so the status bar is filled on self.show
#Create the Main Widgets in the Stacked Widget
self.scoreView = ScoreView(self)
self.ui.mainStackWidget.addWidget(self.scoreView)
@ -99,8 +99,8 @@ class MainWindow(TemplateMainWindow):
self.ui.actionData_Editor.setChecked(False)
self.ui.mainStackWidget.addWidget(self.trackEditor)
#Bind shortcuts to actions (as init effect)
#TODO: Integrate better into template menu system.
#Bind shortcuts to actions (as init effect)
#TODO: Integrate better into template menu system.
self.menuActionDatabase = MenuActionDatabase(self) #The menu needs to be started before api.startEngine
#Make toolbars unclosable
@ -111,34 +111,34 @@ class MainWindow(TemplateMainWindow):
#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.scoreView.setFocus() #So the user can start typing from moment 0.
self.scoreView.setFocus() #So the user can start typing from moment 0.
self.start() #Inherited from template main window #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.
stepMidiInput.start() #imported directly. Handles everything else internally, we just need to start it after the engine somehow. Which is here.
stepMidiInput.start() #imported directly. Handles everything else internally, we just need to start it after the engine somehow. Which is here.
#Populate the left toolbar. The upper toolbar is created in menu.py
#Populate the left toolbar. The upper toolbar is created in menu.py
self.ui.leftToolBar.addWidget(LeftToolBarPrevailingDuration(self)) #needs stepmidiinput started
#Now all tracks and items from a loaded backend-file are created. We can setup the initial editMode and viewPort.
#Now all tracks and items from a loaded backend-file are created. We can setup the initial editMode and viewPort.
self.scoreView.updateMode() #hide CCs at program start and other stuff
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.
#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)
self.nsmClient.announceSaveStatus(isClean = True)
def zoom(self, scaleFactor:float):
"""Scale factor is absolute"""
"""Scale factor is absolute"""
self.scoreView.zoom(scaleFactor)
def stretchXCoordinates(self, factor:float):
self.scoreView.stretchXCoordinates(factor)
def stretchXCoordinates(self, factor:float):
self.scoreView.stretchXCoordinates(factor)
def updateStatusBar(self, exportCursorDict):
"""Every cursor movement updates the statusBar message"""
c = exportCursorDict
try:
try:
i = c["item"]
except:
print (c)
@ -182,7 +182,7 @@ class LeftToolBarPrevailingDuration(QtWidgets.QLabel):
api.callbacks.prevailingBaseDurationChanged.append(self.changed)
def makeText(self, baseDuration):
if not stepMidiInput.midiInIsActive:
if not stepMidiInput.midiInIsActive:
return ""
labelText = "<font size=6>"

26
qtgui/menu.py

@ -113,7 +113,7 @@ class MenuActionDatabase(object):
def __init__(self, mainWindow):
self.mainWindow = mainWindow
self.modalKeys = ModalKeys()
self.modalKeys = ModalKeys()
modes = QtWidgets.QActionGroup(self.mainWindow)
modes.addAction(self.mainWindow.ui.actionNotation_Mode)
@ -275,7 +275,7 @@ class MenuActionDatabase(object):
self.mainWindow.ui.actionDuplicateItem : api.duplicate,
self.mainWindow.ui.actionUndo : api.undo,
self.mainWindow.ui.actionRedo : api.redo,
self.mainWindow.ui.actionRedrawAllTracks : api.updateCallbackAllTracks,
#Toolbox
@ -293,15 +293,15 @@ class MenuActionDatabase(object):
self.mainWindow.ui.actionReverse: api.reorderReverse,
self.mainWindow.ui.actionAscending: api.reorderAscending,
self.mainWindow.ui.actionDescending: api.reoderdDescending,
#Midi
self.mainWindow.ui.actionInstrument_Change: SecondaryProgramChangeMenu(self.mainWindow), #no lambda for submenus. They get created here once and have a __call__ option that executes them. There is no internal state in these menus.
self.mainWindow.ui.actionChannel_Change: SecondaryChannelChangeMenu(self.mainWindow), #no lambda for submenus. They get created here once and have a __call__ option that executes them. There is no internal state in these menus.
#Lilypond
#Print and Export is in self.actions
self.mainWindow.ui.actionLyBarline: ChooseOne(self.mainWindow, translate("menu", "Choose a Barline"), api.getLilypondBarlineList()),
self.mainWindow.ui.actionLyRepeat: ChooseOne(self.mainWindow, translate("menu", "Choose a Repeat"), api.getLilypondRepeatList()),
self.mainWindow.ui.actionLyRepeat: ChooseOne(self.mainWindow, translate("menu", "Choose a Repeat"), api.getLilypondRepeatList()),
self.mainWindow.ui.actionLyFree_Instruction: lambda: forwardText(self.mainWindow, translate("menu", "Enter Instruction"), api.lilypondText),
}
@ -434,7 +434,7 @@ class MenuActionDatabase(object):
if boolean:
#Switch off midi input
if stepMidiInput.midiInIsActive:
self.rememberMidi = stepMidiInput.midiInIsActive
self.rememberMidi = stepMidiInput.midiInIsActive
stepMidiInput.toggleMidiIn()
assert not stepMidiInput.midiInIsActive
self.mainWindow.ui.actionPrevailingRest.setEnabled(stepMidiInput.midiInIsActive)
@ -477,14 +477,14 @@ class MenuActionDatabase(object):
self.mainWindow.ui.actionRedo.setText(translate("menu", "Redo"))
self.mainWindow.ui.actionRedo.setEnabled(False)
def exportLy(self):
def exportLy(self):
lastExportDirectory = api.session.guiSharedDataToSave["lastExportDirectory"] if "lastExportDirectory" in api.session.guiSharedDataToSave else str(Path.home())
filename = QtWidgets.QFileDialog.getSaveFileName(self.mainWindow, translate("menu", "Export Lilypond Source File"), lastExportDirectory, translate("menu", "Lilypond Source (*.ly)"))
filename = filename[0] #(path, filter)
if filename:
if not os.path.splitext(filename)[1]: #no file extension given?
filename = filename + ".ly"
api.session.guiSharedDataToSave["lastExportDirectory"] = os.path.dirname(filename)
api.session.guiSharedDataToSave["lastExportDirectory"] = os.path.dirname(filename)
api.exportLilypond(filename)
class ToolBarCCType(QtWidgets.QSpinBox):
@ -556,7 +556,7 @@ class ToolBarMetronome(QtWidgets.QCheckBox):
return False
def updateFromCallback(self, exportDict):
"""Gets the metronome dict"""
"""Gets the metronome dict"""
self.blockSignals(True)
self.setStatus()
assert self.isChecked() == exportDict["enabled"], (self.isChecked(), exportDict["enabled"])
@ -576,8 +576,8 @@ class ToolBarPlaybackSpeed(QtWidgets.QDoubleSpinBox):
self.setSingleStep(0.1)
self.setPrefix(translate("menu", "Tempo ×")) #yes, this is the unicode multiplication sign × and not an x
api.callbacks.tempoScalingChanged.append(self.updateFromCallback)
self.valueChanged.connect(self.changed)
self.setLineEdit(ToolBarPlaybackSpeed.CustomLineEdit())
self.valueChanged.connect(self.changed)
self.setLineEdit(ToolBarPlaybackSpeed.CustomLineEdit())
class CustomLineEdit(QtWidgets.QLineEdit):
def mousePressEvent(self, event):
@ -601,5 +601,5 @@ class ToolBarPlaybackSpeed(QtWidgets.QDoubleSpinBox):
self.setValue(newValue)
self.blockSignals(False)
def changed(self):
api.changeTempoScaling(self.value())
def changed(self):
api.changeTempoScaling(self.value())

20
qtgui/musicstructures.py

@ -43,6 +43,8 @@ from .submenus import BlockPropertiesEdit
cosmeticPen = QtGui.QPen()
cosmeticPen.setCosmetic(True)
oneRectToReturnThemAll = QtCore.QRectF(0,0,0,0) #prevent the annoying "NotImplementError" from Qt for boundingRect. For items that don't need any collision detection.
class GuiBlockHandle(QtWidgets.QGraphicsRectItem):
"""A simplified version of a Block. Since we don't use blocks in the GUI, only in the backend
we still need them sometimes as macro strutures, where we don't care about the content.
@ -54,7 +56,7 @@ class GuiBlockHandle(QtWidgets.QGraphicsRectItem):
"""
def __init__(self, parent, staticExportItem, x, y, w, h):
super().__init__(x, y, w, h)
self.setFlag(QtWidgets.QGraphicsItem.ItemHasNoContents, True) #only child items. Without this we get notImplementedError: QGraphicsItem.paint() is abstract and must be overridden
self.setFlag(QtWidgets.QGraphicsItem.ItemHasNoContents, True) #only child items. Without this we get notImplementedError: QGraphicsItem.paint() is abstract and must be overridden
self.setFlag(QtWidgets.QGraphicsItem.ItemContainsChildrenInShape, True)
self.parent = parent #GuiTrack instance
self.color = None #inserted by the creating function in GuiTrack
@ -93,6 +95,8 @@ class GuiBlockHandle(QtWidgets.QGraphicsRectItem):
self.startLabel = QtWidgets.QGraphicsSimpleTextItem("")
self.endLabel = QtWidgets.QGraphicsSimpleTextItem("")
def boundingRect(self, *args): return oneRectToReturnThemAll
def stretchXCoordinates(self, factor):
"""Reposition the items on the X axis.
Call goes through all parents/children, starting from ScoreView._stretchXCoordinates.
@ -188,9 +192,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
self.setFlag(QtWidgets.QGraphicsItem.ItemHasNoContents, True) #only child items. Without this we get notImplementedError: QGraphicsItem.paint() is abstract and must be overridden
self.setFlag(QtWidgets.QGraphicsItem.ItemContainsChildrenInShape, True)
self.parentScore = parentScore
self.staticExportItem = staticExportItem #This is not the notes but the track meta data. The notes are called staticRepresentationList
self.items = [] #this is used for stretching and processing of the current items. scene clear is done diffently. See self.createGraphicItemsFromData
@ -221,6 +225,8 @@ class GuiTrack(QtWidgets.QGraphicsItem):
#self.secondStageInitNowThatWeHaveAScene gets called by the ScoreScene.redraw(), where new tracks get created. After it was inserted into the scene.
def boundingRect(self, *args): return oneRectToReturnThemAll
class NameGraphic(QtWidgets.QGraphicsSimpleTextItem):
def __init__(self, text, parent):
super().__init__(text)
@ -237,6 +243,8 @@ class GuiTrack(QtWidgets.QGraphicsItem):
if result[1]:
api.setTrackName(self.parent.staticExportItem["id"], nameString = result[0], initialInstrumentName = self.parent.staticExportItem["initialInstrumentName"], initialShortInstrumentName = self.parent.staticExportItem["initialShortInstrumentName"]) #keep the old lilypond names
#def boundingRect(self, *args): return oneRectToReturnThemAll
def contextMenuEvent(self, event):
listOfLabelsAndFunctions = [ (translate("musicstructures", "edit name"), self._editName), ]
callContextMenu(listOfLabelsAndFunctions)
@ -392,13 +400,15 @@ class GuiTrack(QtWidgets.QGraphicsItem):
class TrackAnchor(QtWidgets.QGraphicsItem):
"""Handling all items as individuals when deleting a track to redraw it is too much.
Better let Qt handle it all at once."""
def __init__(self, parent):
super().__init__()
self.parent = parent
self.setFlag(QtWidgets.QGraphicsItem.ItemHasNoContents, True) #only child items. Without this we get notImplementedError: QGraphicsItem.paint() is abstract and must be overridden
self.setFlag(QtWidgets.QGraphicsItem.ItemHasNoContents, True) #only child items. Without this we get notImplementedError: QGraphicsItem.paint() is abstract and must be overridden
self.setFlag(QtWidgets.QGraphicsItem.ItemContainsChildrenInShape, True)
def boundingRect(self, *args): return oneRectToReturnThemAll
def createGraphicItemsFromData(self, staticRepresentationList):
"""Create staff objects including simple barlines"""

45
qtgui/scorescene.py

@ -43,8 +43,8 @@ class GuiScore(QtWidgets.QGraphicsScene):
def __init__(self, parentView):
super().__init__()
self.parentView = parentView
self.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex)
self.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex)
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.
@ -69,7 +69,7 @@ class GuiScore(QtWidgets.QGraphicsScene):
self.backColor.setNamedColor("#fdfdff")
self.setBackgroundBrush(self.backColor)
self.grid = GuiGrid(parent=self)
self.grid = Grid(parentScene=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)
@ -129,9 +129,9 @@ class GuiScore(QtWidgets.QGraphicsScene):
#hidden track.
def updateGraphTrackCC(self, trackId, ccNumber, staticRepresentationList):
"""TrackId is a real notation track which has a dict of CCs"""
"""TrackId is a real notation track which has a dict of CCs"""
if trackId in self.tracks:
track = self.tracks[trackId]
track = self.tracks[trackId]
ccPath = track.ccPaths[ccNumber]
ccPath.createGraphicItemsFromData(staticRepresentationList)
@ -170,8 +170,8 @@ class GuiScore(QtWidgets.QGraphicsScene):
for cc in guiCCs:
self.removeWhenIdle(self.tracks[trackId].ccPaths[cc])
del self.tracks[trackId].ccPaths[cc]
def redraw(self, listOfStaticTrackRepresentations):
"""The order of guiTracks depends on the backend index.
This way it is a no-brainer, we don't need to maintain our own
@ -182,7 +182,7 @@ class GuiScore(QtWidgets.QGraphicsScene):
through self.updateTrack which has its own api-callback
called by callbacksDatabase.tracksChanged"""
for track in self.tracks.values():
track.hide()
@ -278,22 +278,31 @@ class GuiScore(QtWidgets.QGraphicsScene):
return None
def wheelEvent(self, event):
"""We MUST handle the event somehow. Otherwise background grid items will block the views(!)
def notTrueAnymore_wheelEvent(self, event):
"""
This docstring was either wrong in the first place or something changed in my code.
However, we do not need to eat wheelEvent here anymore. On the contrary: It will block
items, like the tempoItem from receiving wheelEvents.
The commented out if/else for item detection also has a chance to work, but we don't need
to test for that at all. Standard Qt-behavoiour is fine.
What follows is the old docstring, for legacy documentation reasons:
We MUST handle the event somehow. Otherwise background grid items will block the views(!)
wheel scrolling, even when disabled and setting accepting mouse events to none.
This is a qt bug that won't be fixed because API stability over correctnes (according to the
This is a qt bug that won't be fixed because API stability over correctnes (according to the
bugtracker.
Contrary to other parts of the system event.ignore and accept actually mean something.
ignore will tell the caller to use the event itself, e.g. scroll.
This event gets the wheel BEFORE the main window (zoom)
"""
This event gets the wheel BEFORE the main window (zoom)
"""
#item = self.itemAt(event.scenePos(), self.parentView.transform())
#if type(item) is items.Note:
# super().wheelEvent(event) #send to child item
#else:
event.ignore() #so the view scrolls or we zoom
#super().wheelEvent(event) #send to child item
#else:
event.ignore() #so the view scrolls or we zoom
def stretchXCoordinates(self, factor):
"""Reposition the items on the X axis.

16
qtgui/scoreview.py

@ -36,8 +36,8 @@ import engine.api as api
class ScoreView(QtWidgets.QGraphicsView):
def __init__(self, mainWindow):
super().__init__()
self.mainWindow = mainWindow
super().__init__()
self.mainWindow = mainWindow
self.scoreScene = GuiScore(parentView=self)
self.setScene(self.scoreScene)
@ -83,9 +83,9 @@ class ScoreView(QtWidgets.QGraphicsView):
self.setStyleSheet(style)
def wheelEvent(self, event):
if QtWidgets.QApplication.keyboardModifiers() in (QtCore.Qt.ControlModifier, QtCore.Qt.ControlModifier|QtCore.Qt.ShiftModifier): #a workaround for a qt bug. see score.wheelEvent docstring.
if QtWidgets.QApplication.keyboardModifiers() in (QtCore.Qt.ControlModifier, QtCore.Qt.ControlModifier|QtCore.Qt.ShiftModifier): #a workaround for a qt bug. see score.wheelEvent docstring.
event.ignore() #do not send to scene, but tell the mainWindow to use it.
else:
else:
super().wheelEvent(event) #send to scene
def centerOnCursor(self, cursorExportObject):
@ -101,10 +101,10 @@ class ScoreView(QtWidgets.QGraphicsView):
def stretchXCoordinates(self, factor):
self.scoreScene.stretchXCoordinates(factor)
self.centerOnCursor(None)
def zoom(self, scaleFactor:float):
"""Scale factor is absolute"""
self.resetTransform()
"""Scale factor is absolute"""
self.resetTransform()
self.scale(scaleFactor, scaleFactor)
def toggleNoteheadsRectangles(self):
@ -144,7 +144,7 @@ class ScoreView(QtWidgets.QGraphicsView):
raise ValueError("Edit Mode unknown")
def resizeEvent(self, event):
self.scoreScene.grid.reactToresizeEventOrZoom()
#self.scoreScene.grid.reactToresizeEventOrZoom()
super().resizeEvent(event)
def changeGridRhythm(self):

28
qtgui/submenus.py

@ -31,7 +31,7 @@ translate = QtCore.QCoreApplication.translate
#Template
import template.engine.pitch as pitch
from template.qtgui.helper import QHLine
from template.qtgui.submenus import *
from template.qtgui.submenus import *
#Our own files
import engine.api as api
@ -380,7 +380,7 @@ class TransposeMenu(Submenu):
self.fromNote = QtWidgets.QComboBox()
self.fromNote.addItems(pitch.sortedNoteNameList)
self.fromNote.setCurrentIndex(pitch.sortedNoteNameList.index("c'"))
self.layout.addRow("from", self.fromNote)
@ -417,11 +417,11 @@ class SecondaryProperties(Submenu):
importantKeys = ("title", "composer", "instrument", "copyright")
#Draw important metadata widgets first
for k in importantKeys:
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:
@ -452,7 +452,7 @@ class SecondaryProperties(Submenu):
elif typ == QtWidgets.QSpinBox or typ == QtWidgets.QDoubleSpinBox:
return widget.value()
def process(self):
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.
@ -471,7 +471,7 @@ class SecondaryProgramChangeMenu(Submenu):
self.msb = QtWidgets.QSpinBox()
self.msb.setValue(type(self).lastMsbValue)
self.lsb = QtWidgets.QSpinBox()
self.lsb.setValue(type(self).lastLsbValue)
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)):
@ -479,7 +479,7 @@ class SecondaryProgramChangeMenu(Submenu):
spinbox.setMaximum(127)
spinbox.setSingleStep(1)
self.layout.addRow(label, spinbox)
self.layout.addRow(translate("submenus", "Short Name"), self.shortInstrumentName)
self.insert = QtWidgets.QPushButton(translate("submenus", "Insert"))
@ -544,8 +544,8 @@ class GridRhytmEdit(Submenu):
def process(self):
constantsAndConfigs.gridRhythm = self.duration.value()
constantsAndConfigs.gridOpacity = self.opacity.value() / 100
api.session.guiSharedDataToSave["grid_opacity"] = constantsAndConfigs.gridOpacity
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)
@ -572,15 +572,15 @@ def pedalNoteChooser(mainWindow):
if v == rhythmString[0]:
api.pedalNotes(baseDuration)
def forwardText(mainWindow, title, function):
def forwardText(mainWindow, title, function):
text, status = QtWidgets.QInputDialog.getText(mainWindow, title, title)
if status:
function(text)

6
qtgui/trackEditor.py

@ -59,7 +59,7 @@ class TrackWidget(QtWidgets.QGroupBox):
self.ui.nameLineEdit.editingFinished.connect(self.nameChanged) #only user changes, not through setText() etc.
self.ui.deleteButton.clicked.connect(lambda: api.deleteTrack(self.trackExportObject["id"]))
self.ui.midiChannelSpinBox.valueChanged.connect(self.dataChanged)
self.ui.midiChannelSpinBox.valueChanged.connect(self.dataChanged)
self.ui.midiProgramSpinBox.valueChanged.connect(self.dataChanged)
self.ui.midiBankMsbSpinBox.valueChanged.connect(self.dataChanged)
self.ui.midiBankLsbSpinBox.valueChanged.connect(self.dataChanged)
@ -138,7 +138,7 @@ class TrackWidget(QtWidgets.QGroupBox):
api.unhideTrack(self.trackExportObject["id"])
else:
api.hideTrack(self.trackExportObject["id"])
def audibleToggled(self, signal):
assert signal == bool(self.ui.audibleCheckbox.checkState())
api.trackAudible(self.trackExportObject["id"], signal)
@ -299,7 +299,7 @@ class TrackWidget(QtWidgets.QGroupBox):
self.ui.doubleTrackCheckbox.setChecked(trackExportObject["double"])
self.ui.audibleCheckbox.setChecked(trackExportObject["audible"])
for i in range(0,16): #without 16
for i in range(0,16): #without 16
#Engine from 0 to 15, GUI from 1 to 16.
self.ccChannels[i+1].setChecked(i in trackExportObject["ccChannels"]) #a checkbox widget.

Loading…
Cancel
Save