def __init__( self, engine_manager, package, version ): super( QMainWindow, self ).__init__() self._engine_manager = engine_manager self.setupUi( self ) self.setWindowTitle( "{0} v{1}".format( package, version ) ) self.loopListViewModel = LoopListModel() self.loopListView.setModel( self.loopListViewModel ) self.mappingTableViewModel = MappingTableModel() self.mappingTableView.setModel( self.mappingTableViewModel ) # PyUIC doesn't generate code for word wrap :( self.mappingTableView.setWordWrap( True ) self.mappingTableView.resizeRowsToContents() tableHeader = self.mappingTableView.horizontalHeader() tableHeader.setSectionResizeMode( QtWidgets.QHeaderView.Stretch ) # Only update the model on the GUI thread - thread-safe. self.loopUpdated.connect( self._loop_update_handler, type=QtCore.Qt.QueuedConnection ) self.mappingUpdated.connect( self._mapping_update_handler, type=QtCore.Qt.QueuedConnection ) self._engine_manager.subscribe( "loops", self.signal_loop_update ) self._engine_manager.subscribe( "mappings", self.signal_mapping_update ) QtCore.QTimer.singleShot( 0, self.mappingTableView.resizeRowsToContents )
class _LooperWindow( QMainWindow, Ui_MainWindow ): loopUpdated = QtCore.pyqtSignal( str, str ) mappingUpdated = QtCore.pyqtSignal( str, MIDIMappingInfo ) def __init__( self, engine_manager, package, version ): super( QMainWindow, self ).__init__() self._engine_manager = engine_manager self.setupUi( self ) self.setWindowTitle( "{0} v{1}".format( package, version ) ) self.loopListViewModel = LoopListModel() self.loopListView.setModel( self.loopListViewModel ) self.mappingTableViewModel = MappingTableModel() self.mappingTableView.setModel( self.mappingTableViewModel ) # PyUIC doesn't generate code for word wrap :( self.mappingTableView.setWordWrap( True ) self.mappingTableView.resizeRowsToContents() tableHeader = self.mappingTableView.horizontalHeader() tableHeader.setSectionResizeMode( QtWidgets.QHeaderView.Stretch ) # Only update the model on the GUI thread - thread-safe. self.loopUpdated.connect( self._loop_update_handler, type=QtCore.Qt.QueuedConnection ) self.mappingUpdated.connect( self._mapping_update_handler, type=QtCore.Qt.QueuedConnection ) self._engine_manager.subscribe( "loops", self.signal_loop_update ) self._engine_manager.subscribe( "mappings", self.signal_mapping_update ) QtCore.QTimer.singleShot( 0, self.mappingTableView.resizeRowsToContents ) def signal_loop_update( self, change, data ): self.loopUpdated.emit( change, data ) def signal_mapping_update( self, change, data ): self.mappingUpdated.emit( change, data ) def _loop_update_handler( self, change, data ): if change == "add": self.loopListViewModel.insertLoopRow( self.loopListViewModel.rowCount(), data ) elif change == "remove": self.loopListViewModel.removeLoop( data ) else: raise ValueError( "Invalid loop update!" ) def _mapping_update_handler( self, change, data ): if change == "add": self.mappingTableViewModel.insertMappingRow( self.mappingTableViewModel.rowCount(), data ) self.mappingTableView.resizeRowsToContents() # HACK elif change == "remove": self.mappingTableViewModel.removeMapping( data ) else: raise ValueError( "Invalid mapping update!" ) # Slots are named in camelcase for consistency with the rest of Qt. def newLoop( self ): new_loop_name, ok = QtWidgets.QInputDialog.getText( self, "New Loop", "Provide the name for the new loop." ) if ok: self._engine_manager.new_loop( new_loop_name ) def removeLoops( self ): # Gets the names because a normal iterative removal would invalidate the # index list at each step. This is not particularly efficient. selected = [self.loopListViewModel.data( x ) for x in self.loopListView.selectedIndexes()] self._engine_manager.remove_loops( selected ) def newMapping( self ): loops = [ self.loopListViewModel.data( self.loopListViewModel.createIndex( x, 0 ) ) for x in range( 0, self.loopListViewModel.rowCount() ) ] if not loops: QtWidgets.QMessageBox.warning( self, "No loops", "You must add a loop before defining mappings." ) return mapping_dialog = _MappingDialog( loops, self ) if mapping_dialog.exec_(): channel, midi_type, value, name, action = mapping_dialog.getMappingData() self._engine_manager.new_mapping( MIDIMappingInfo( channel, midi_type, value, name, action ) ) def removeMappings( self ): mappings = [self.mappingTableViewModel.dataRow( x.row() ) for x in self.mappingTableView.selectionModel().selectedRows()] self._engine_manager.remove_mappings( mappings )