class DigitalInstrumentWidget(QGraphicsView): def __init__(self): super(DigitalInstrumentWidget, self).__init__() self.keyboard = Keyboard(self.getShortcutMappings()) self.initUI() def getShortcutMappings(self): return { Qt.Key_T: self.keyboardTypeButtonEvent, Qt.Key_R: self.resetButtonEvent, Qt.Key_S: self.saveButtonEvent, Qt.Key_O: self.loadButtonEvent, Qt.Key_L: self.loadButtonEvent, Qt.Key_D: self.deleteButtonEvent, } def createButton(self, text, event): button = QPushButton() button.setText(text) button.show() button.clicked.connect(event) self.boxLayout.addWidget(button, 100, Qt.AlignCenter) def initButtons(self): button_text_events = [ ('Set Keyboard Type', self.keyboardTypeButtonEvent), ('Reset Mappings', self.resetButtonEvent), ('Save Mappings', self.saveButtonEvent), ('Load Mappings', self.loadButtonEvent), ('Delete Mappings', self.deleteButtonEvent), ] for text, event in button_text_events: self.createButton(text, event) self.boxLayout.addSpacerItem(QSpacerItem(100, 500)) self.settingsLayout = QVBoxLayout() # new layouts and buttons: button = QPushButton() button.setText('Settings') button.show() button.clicked.connect(self.settingsButtonEvent) self.settingsLayout.addWidget(button, 100, Qt.AlignCenter) self.settingsLayout.addSpacerItem(QSpacerItem(100, 600)) def initMappingLayout(self): self.mappingButtonList = [] self.mappingLabelList = [] self.playingMappingButtonNotes = [] self.leftLayout = QVBoxLayout() self.mappingsLayout = QGridLayout() self.leftLayout.addLayout(self.mappingsLayout) self.leftLayout.addSpacerItem(QSpacerItem(100, 500)) # new layouts and buttons: label = QLabel() label.setText('Key Mappings:') label.show() self.mappingsLayout.addWidget(label, 0, 0) self.layout.addLayout(self.leftLayout, 0, 0) def createTextItem(self, scene, text, x, y): text_item = QGraphicsTextItem(text) text_item.setZValue(100) text_item.setPos(x, y) text_item.adjustSize() scene.addItem(text_item) return text_item def initText(self, scene): self.chordMappings = self.createTextItem( scene, "Key Mappings:" + '\n' + "None", 0, -300) self.chordMappings.setVisible(False) self.octaveLeft = self.createTextItem( scene, "Octave: " + str(self.keyboard.octave), 150, -30) self.octaveRight = self.createTextItem( scene, "Octave: " + str(self.keyboard.octave + 1), 475, -30) def drawWhiteKey(self, i): key = PianoKeyItem(self.keyAreaBounds.x() + i * self.whiteKeyWidth, self.keyAreaBounds.y(), self.whiteKeyWidth, self.keyAreaBounds.height()) key.setBrush(Qt.white) key.mappingLabel = QGraphicsTextItem() key.mappingLabel.setDefaultTextColor(Qt.black) return key def drawBlackKey(self, i): startX = self.keyAreaBounds.x( ) + 2 * i * self.blackKeyWidth + self.blackKeyWidth * 1.5 if i > 6: startX += 3 * self.whiteKeyWidth elif i > 4: startX += 2 * self.whiteKeyWidth elif i > 1: startX += self.whiteKeyWidth key = PianoKeyItem(startX, self.keyAreaBounds.y(), self.blackKeyWidth, self.keyAreaBounds.height() * 0.6) key.setBrush(Qt.black) key.mappingLabel = QGraphicsTextItem() key.mappingLabel.setDefaultTextColor(Qt.white) return key def drawKeys(self, scene, keyIndices, drawKeyFunction): keyAreaBounds = QRect(0, 0, self.size().width() * .85, self.size().height() * 0.4) keys = [] for i in range(len(keyIndices)): key = drawKeyFunction(i) key.instrument_widget = self key.note = constants.DiscreteNotes(keyIndices[i]) font = key.mappingLabel.font() font.setBold(True) key.mappingLabel.setFont(font) key.mappingLabel.setZValue(100) key.mappingLabel.setPlainText('A') key.mappingLabel.setPos( key.boundingRect().x() + key.boundingRect().width() / 2 - key.mappingLabel.boundingRect().width() / 2, key.boundingRect().y() + key.boundingRect().height() * 0.8) scene.addItem(key.mappingLabel) scene.addItem(key) keys.append(key) return keys def initUI(self): windowWidth = 800 windowHeight = 500 self.resize(windowWidth, windowHeight) self.move(100, 100) self.setWindowTitle('Digital Keyboard') self.show() # Set up graphics stuff scene = QGraphicsScene() self.layout = QGridLayout() self.boxLayout = QVBoxLayout() self.initButtons() self.initMappingLayout() self.layout.addLayout(self.boxLayout, 0, 1) self.layout.addLayout(self.settingsLayout, 0, 2) self.setLayout(self.layout) self.initText(scene) self.keyAreaBounds = QRect(0, 0, windowWidth * .85, windowHeight * 0.4) self.whiteKeyWidth = self.keyAreaBounds.width() / 14 self.whiteKeyIndices = [ 0, 2, 4, 5, 7, 9, 11, 12, 14, 16, 17, 19, 21, 22 ] self.whiteKeys = self.drawKeys(scene, self.whiteKeyIndices, self.drawWhiteKey) self.blackKeyWidth = self.whiteKeyWidth / 2 self.blackKeyIndices = [1, 3, 6, 8, 10, 13, 15, 18, 20, 23] self.blackKeys = self.drawKeys(scene, self.blackKeyIndices, self.drawBlackKey) self.setScene(scene) self.updateUI() def updateMappingLayout(self): for i in range(0, len(self.mappingButtonList)): self.mappingLabelList[i].hide() self.mappingButtonList[i].hide() self.mappingsLayout.removeWidget(self.mappingLabelList[i]) self.mappingsLayout.removeWidget(self.mappingButtonList[i]) self.mappingLabelList[i].deleteLater() self.mappingButtonList[i].deleteLater() self.mappingButtonList = [] self.mappingLabelList = [] customMapping = self.keyboard.customMapping if customMapping: i = 0 for key in customMapping: i = i + 1 labelText = QKeySequence(key).toString() buttonStrings = [] for note in customMapping[key]: buttonStrings.append(note.name) buttonText = ', '.join(buttonStrings) label = QLabel() label.setText(labelText) label.show() button = QPushButton() button.setText(buttonText) button.show() button.pressed.connect( partial(self.mappingButtonEvent, notes=customMapping[key])) self.mappingsLayout.addWidget(label, i, 1) self.mappingsLayout.addWidget(button, i, 2) self.mappingLabelList.append(label) self.mappingButtonList.append(button) def updateKeys(self, keys, keyIndices, defaultColor): # inverts dict keyMappings = { val: key for key, val in self.keyboard.noteDict.iteritems() } for i in range(len(keys)): key = keys[i] curNote = key.note if curNote in self.keyboard.mapping_notes: key.setBrush(QColor(constants.highlighted_key_color)) else: if self.pressedKeys[keyIndices[i]]: key.setBrush(Qt.gray) elif curNote in self.playingMappingButtonNotes: key.setBrush(Qt.gray) else: key.setBrush(defaultColor) # Update key mapping string note = constants.DiscreteNotes(keyIndices[i]) key.mappingLabel.setPlainText( QKeySequence(keyMappings[note]).toString()) for k, v in self.keyboard.customMapping.iteritems(): if str(note) in str(v): # purposfully commented: set text to new mapping when button pressed # key.mappingLabel.setPlainText(QKeySequence(k).toString()) break elif keyMappings[note] == k: key.mappingLabel.setPlainText("") def updateUI(self): # Make sure the pressedKeys exists if not hasattr(self, 'pressedKeys') or self.pressedKeys is None: self.pressedKeys = [False] * 24 self.updateMappingLayout() #update octaves seen on screen self.octaveLeft.setPlainText("Octave: " + str(self.keyboard.octave)) self.octaveRight.setPlainText("Octave: " + str(self.keyboard.octave + 1)) self.updateKeys(self.whiteKeys, self.whiteKeyIndices, Qt.white) self.updateKeys(self.blackKeys, self.blackKeyIndices, Qt.black) self.scene().update(self.scene().sceneRect()) def keyPressEvent(self, event): if event.isAutoRepeat(): return #if the key pressed is a command, return #command mapper takes care of the command's actions res = self.keyboard.commandMapper(event.key(), event.modifiers()) if res: # TODO: only used for updateOctave(), refactor self.updateUI() return elif res == -1: return #note mapper maps a key to a note #returns false if key is not maped to a note notes = self.keyboard.noteMapper(event.key()) #if key is mapped to a note, start the note for note in notes: print 'Printing notes:' + str(note) self.keyboard.startNote(note) # Mark the key as pressed for the UI self.pressedKeys[note.value] = True self.updateUI() if not notes: #else the key pressed does nothing currently print("key not mapped") def keyReleaseEvent(self, event): if event.isAutoRepeat(): return #key release only matters for notes #because notes can be held notes = self.keyboard.noteMapper(event.key()) #if the key is mapped, end the note for note in notes: self.keyboard.endNote(note) # Mark the key as released for the UI self.pressedKeys[note.value] = False self.updateUI() def keyboardTypeButtonEvent(self): dialog_output = QInputDialog().getItem(self, 'Select Keyboard Type', '', constants.keyboard_types.keys()) if self.keyboard.defaultButton(dialog_output): self.updateUI() def saveButtonEvent(self): if not self.keyboard.customMapping: return False # Save popup dialog_output = QInputDialog().getText(self, 'Save Key Mapping', 'Enter key mapping name here') self.keyboard.saveButton(dialog_output) def resetButtonEvent(self): if self.keyboard.resetButton(): self.updateUI() def loadButtonEvent(self): mapping_names = self.keyboard.getMappingNames() dropdown_options = [' - '] + [i[0] for i in mapping_names] dialog_output = QInputDialog().getItem(self, 'Load Key Mapping', 'Select key mapping', dropdown_options) if self.keyboard.loadButton(dialog_output): self.updateUI() def deleteButtonEvent(self): mapping_names = self.keyboard.getMappingNames() dropdown_options = [' - '] + [i[0] for i in mapping_names] dialog_output = QInputDialog().getItem( self, 'Delete Saved Key Mapping', 'Delete key mapping (PERMANENT)', dropdown_options) self.keyboard.deleteButton(dialog_output) def settingsButtonEvent(self): dropdown_options = ['orange', 'cyan', 'yellow', 'green'] colors = { 'orange': constants.orange, 'cyan': constants.cyan, 'yellow': constants.yellow, 'green': constants.green, } dialog_output = QInputDialog().getItem(self, 'Settings', 'Choose a colorshceme', dropdown_options) constants.highlighted_key_color = colors[dialog_output[0]] def mappingButtonEvent(self, notes): if self.playingMappingButtonNotes: for note in self.playingMappingButtonNotes: self.keyboard.endNote(note) self.playingMappingButtonNotes = [] else: self.playingMappingButtonNotes = notes for note in notes: print "asdfasdfasdf: {}".format(note) self.keyboard.startNote(note) self.updateUI()