class PlotMainWindow(QWidget): """Base class for plot main windows.""" def __init__(self, U, plot, length=1, title=None): super(PlotMainWindow, self).__init__() layout = QVBoxLayout() if title: title = QLabel('<b>' + title + '</b>') title.setAlignment(Qt.AlignHCenter) layout.addWidget(title) layout.addWidget(plot) plot.set(U, 0) if length > 1: hlayout = QHBoxLayout() self.slider = QSlider(Qt.Horizontal) self.slider.setMinimum(0) self.slider.setMaximum(length - 1) self.slider.setTickPosition(QSlider.TicksBelow) hlayout.addWidget(self.slider) lcd = QLCDNumber(m.ceil(m.log10(length))) lcd.setDecMode() lcd.setSegmentStyle(QLCDNumber.Flat) hlayout.addWidget(lcd) layout.addLayout(hlayout) hlayout = QHBoxLayout() toolbar = QToolBar() self.a_play = QAction(self.style().standardIcon(QStyle.SP_MediaPlay), 'Play', self) self.a_play.setCheckable(True) self.a_rewind = QAction(self.style().standardIcon(QStyle.SP_MediaSeekBackward), 'Rewind', self) self.a_toend = QAction(self.style().standardIcon(QStyle.SP_MediaSeekForward), 'End', self) self.a_step_backward = QAction(self.style().standardIcon(QStyle.SP_MediaSkipBackward), 'Step Back', self) self.a_step_forward = QAction(self.style().standardIcon(QStyle.SP_MediaSkipForward), 'Step', self) self.a_loop = QAction(self.style().standardIcon(QStyle.SP_BrowserReload), 'Loop', self) self.a_loop.setCheckable(True) toolbar.addAction(self.a_play) toolbar.addAction(self.a_rewind) toolbar.addAction(self.a_toend) toolbar.addAction(self.a_step_backward) toolbar.addAction(self.a_step_forward) toolbar.addAction(self.a_loop) if hasattr(self, 'save'): self.a_save = QAction(self.style().standardIcon(QStyle.SP_DialogSaveButton), 'Save', self) toolbar.addAction(self.a_save) self.a_save.triggered.connect(self.save) hlayout.addWidget(toolbar) self.speed = QSlider(Qt.Horizontal) self.speed.setMinimum(0) self.speed.setMaximum(100) hlayout.addWidget(QLabel('Speed:')) hlayout.addWidget(self.speed) layout.addLayout(hlayout) self.timer = QTimer() self.timer.timeout.connect(self.update_solution) self.slider.valueChanged.connect(self.slider_changed) self.slider.valueChanged.connect(lcd.display) self.speed.valueChanged.connect(self.speed_changed) self.a_play.toggled.connect(self.toggle_play) self.a_rewind.triggered.connect(self.rewind) self.a_toend.triggered.connect(self.to_end) self.a_step_forward.triggered.connect(self.step_forward) self.a_step_backward.triggered.connect(self.step_backward) self.speed.setValue(50) elif hasattr(self, 'save'): hlayout = QHBoxLayout() toolbar = QToolBar() self.a_save = QAction(self.style().standardIcon(QStyle.SP_DialogSaveButton), 'Save', self) toolbar.addAction(self.a_save) hlayout.addWidget(toolbar) layout.addLayout(hlayout) self.a_save.triggered.connect(self.save) self.setLayout(layout) self.plot = plot self.U = U self.length = length def slider_changed(self, ind): self.plot.set(self.U, ind) def speed_changed(self, val): self.timer.setInterval(val * 20) def update_solution(self): ind = self.slider.value() + 1 if ind >= self.length: if self.a_loop.isChecked(): ind = 0 else: self.a_play.setChecked(False) return self.slider.setValue(ind) def toggle_play(self, checked): if checked: if self.slider.value() + 1 == self.length: self.slider.setValue(0) self.timer.start() else: self.timer.stop() def rewind(self): self.slider.setValue(0) def to_end(self): self.a_play.setChecked(False) self.slider.setValue(self.length - 1) def step_forward(self): self.a_play.setChecked(False) ind = self.slider.value() + 1 if ind == self.length and self.a_loop.isChecked(): ind = 0 if ind < self.length: self.slider.setValue(ind) def step_backward(self): self.a_play.setChecked(False) ind = self.slider.value() - 1 if ind == -1 and self.a_loop.isChecked(): ind = self.length - 1 if ind >= 0: self.slider.setValue(ind)
class MainWindow(QWidget): def __init__(self, grid, U): assert isinstance(U, Communicable) super(MainWindow, self).__init__() U = U.data layout = QVBoxLayout() plotBox = QHBoxLayout() plot = GlumpyPatchWidget(self, grid, vmin=np.min(U), vmax=np.max(U), bounding_box=bounding_box, codim=codim) bar = ColorBarWidget(self, vmin=np.min(U), vmax=np.max(U)) plotBox.addWidget(plot) plotBox.addWidget(bar) layout.addLayout(plotBox) if len(U) == 1: plot.set(U.ravel()) else: plot.set(U[0]) hlayout = QHBoxLayout() self.slider = QSlider(Qt.Horizontal) self.slider.setMinimum(0) self.slider.setMaximum(len(U) - 1) self.slider.setTickPosition(QSlider.TicksBelow) hlayout.addWidget(self.slider) lcd = QLCDNumber(m.ceil(m.log10(len(U)))) lcd.setDecMode() lcd.setSegmentStyle(QLCDNumber.Flat) hlayout.addWidget(lcd) layout.addLayout(hlayout) hlayout = QHBoxLayout() toolbar = QToolBar() self.a_play = QAction(self.style().standardIcon(QStyle.SP_MediaPlay), 'Play', self) self.a_play.setCheckable(True) self.a_rewind = QAction(self.style().standardIcon(QStyle.SP_MediaSeekBackward), 'Rewind', self) self.a_toend = QAction(self.style().standardIcon(QStyle.SP_MediaSeekForward), 'End', self) self.a_step_backward = QAction(self.style().standardIcon(QStyle.SP_MediaSkipBackward), 'Step Back', self) self.a_step_forward = QAction(self.style().standardIcon(QStyle.SP_MediaSkipForward), 'Step', self) self.a_loop = QAction(self.style().standardIcon(QStyle.SP_BrowserReload), 'Loop', self) self.a_loop.setCheckable(True) toolbar.addAction(self.a_play) toolbar.addAction(self.a_rewind) toolbar.addAction(self.a_toend) toolbar.addAction(self.a_step_backward) toolbar.addAction(self.a_step_forward) toolbar.addAction(self.a_loop) hlayout.addWidget(toolbar) self.speed = QSlider(Qt.Horizontal) self.speed.setMinimum(0) self.speed.setMaximum(100) hlayout.addWidget(QLabel('Speed:')) hlayout.addWidget(self.speed) layout.addLayout(hlayout) self.timer = QTimer() self.timer.timeout.connect(self.update_solution) self.slider.valueChanged.connect(self.slider_changed) self.slider.valueChanged.connect(lcd.display) self.speed.valueChanged.connect(self.speed_changed) self.a_play.toggled.connect(self.toggle_play) self.a_rewind.triggered.connect(self.rewind) self.a_toend.triggered.connect(self.to_end) self.a_step_forward.triggered.connect(self.step_forward) self.a_step_backward.triggered.connect(self.step_backward) self.speed.setValue(50) self.setLayout(layout) self.plot = plot self.U = U def slider_changed(self, ind): self.plot.set(self.U[ind]) def speed_changed(self, val): self.timer.setInterval(val * 20) def update_solution(self): ind = self.slider.value() + 1 if ind >= len(self.U): if self.a_loop.isChecked(): ind = 0 else: self.a_play.setChecked(False) return self.slider.setValue(ind) def toggle_play(self, checked): if checked: if self.slider.value() + 1 == len(self.U): self.slider.setValue(0) self.timer.start() else: self.timer.stop() def rewind(self): self.slider.setValue(0) def to_end(self): self.a_play.setChecked(False) self.slider.setValue(len(self.U) - 1) def step_forward(self): self.a_play.setChecked(False) ind = self.slider.value() + 1 if ind == len(self.U) and self.a_loop.isChecked(): ind = 0 if ind < len(self.U): self.slider.setValue(ind) def step_backward(self): self.a_play.setChecked(False) ind = self.slider.value() - 1 if ind == -1 and self.a_loop.isChecked(): ind = len(self.U) - 1 if ind >= 0: self.slider.setValue(ind)
class MainWindow(QMainWindow): start_acq = Signal(str) start_rec = Signal(str) collect_frame = Signal(object) collect_threshed = Signal(object) def __init__(self, parent=None): ''' sets up the whole main window ''' #standard init super(MainWindow, self).__init__(parent) #set the window title self.setWindowTitle('Open Ephys Control GUI') self.window_height = 700 self.window_width = 1100 self.screen2 = QDesktopWidget().screenGeometry(0) self.move( self.screen2.left() + (self.screen2.width() - self.window_width) / 2., self.screen2.top() + (self.screen2.height() - self.window_height) / 2.) self.get_info() self.noinfo = True while self.noinfo: loop = QEventLoop() QTimer.singleShot(500., loop.quit) loop.exec_() subprocess.Popen('start %s' % open_ephys_path, shell=True) self.collect_frame.connect(self.update_frame) self.collect_threshed.connect(self.update_threshed) self.acquiring = False self.recording = False self.video_height = self.window_height * .52 self.video_width = self.window_width * .48 self.resize(self.window_width, self.window_height) #create QTextEdit window 'terminal' for receiving stdout and stderr self.terminal = QTextEdit(self) #set the geometry self.terminal.setGeometry( QRect(self.window_width * .02, self.window_height * .15 + self.video_height, self.video_width * .96, 150)) #make widgets self.setup_video_frames() self.setup_thresh_buttons() self.overlay = True #create thread and worker for video processing self.videoThread = QThread(self) self.videoThread.start() self.videoproc_worker = VideoWorker(self) self.videoproc_worker.moveToThread(self.videoThread) self.vt_file = None """""" """""" """""" """""" """""" """""" """""" """ set up menus """ """""" """""" """""" """""" """""" """""" """""" #create a QMenuBar and set geometry self.menubar = QMenuBar(self) self.menubar.setGeometry( QRect(0, 0, self.window_width * .5, self.window_height * .03)) #set the QMenuBar as menu bar for main window self.setMenuBar(self.menubar) #create a QStatusBar statusbar = QStatusBar(self) #set it as status bar for main window self.setStatusBar(statusbar) #create icon toolbar with default image iconToolBar = self.addToolBar("iconBar.png") #create a QAction for the acquire button self.action_Acq = QAction(self) #make it checkable self.action_Acq.setCheckable(True) #grab an icon for the button acq_icon = self.style().standardIcon(QStyle.SP_MediaPlay) #set the icon for the action self.action_Acq.setIcon(acq_icon) #when the button is pressed, call the Acquire function self.action_Acq.triggered.connect(self.Acquire) #create a QAction for the record button self.action_Record = QAction(self) #make it checkable self.action_Record.setCheckable(True) #grab an icon for the button record_icon = self.style().standardIcon(QStyle.SP_DialogYesButton) #set the icon for the action self.action_Record.setIcon(record_icon) #when the button is pressed, call advanced_settings function self.action_Record.triggered.connect(self.Record) #create QAction for stop button action_Stop = QAction(self) #grab close icon stop_icon = self.style().standardIcon(QStyle.SP_MediaStop) #set icon for action action_Stop.setIcon(stop_icon) #when button pressed, close window action_Stop.triggered.connect(self.Stop) #show tips for each action in the status bar self.action_Acq.setStatusTip("Start acquiring") self.action_Record.setStatusTip("Start recording") action_Stop.setStatusTip("Stop acquiring/recording") #add actions to icon toolbar iconToolBar.addAction(self.action_Acq) iconToolBar.addAction(self.action_Record) iconToolBar.addAction(action_Stop) # self.sort_button = QPushButton('Sort Now',self) # self.sort_button.setGeometry(QRect(self.window_width*.85,0,self.window_width*.15,self.window_height*.05)) # self.sort_button.clicked.connect(self.sort_now) #show the window if minimized by windows self.showMinimized() self.showNormal() """""" """""" """""" """""" """""" """""" """""" """""" """""" """""" "" """""" """""" """""" """""" """""" """""" """""" """""" """""" """""" "" #this function acts as a slot to accept 'message' signal @Slot(str) def print_message(self, message): ''' print stdout and stderr to terminal window ''' #move terminal cursor to end self.terminal.moveCursor(QTextCursor.End) #write message to terminal self.terminal.insertPlainText(message) def setup_thresh_buttons(self): ''' set up buttons for overlay/clearing thresh view ''' self.button_frame = QFrame(self) self.button_frame.setGeometry( QRect(self.window_width * .52, self.window_height * .13 + self.video_height, self.video_width * .98, 50)) button_layout = QHBoxLayout() self.button_frame.setLayout(button_layout) self.clear_button = QPushButton('Clear') self.overlay_button = QPushButton('Overlay') button_layout.addWidget(self.clear_button) button_layout.addWidget(self.overlay_button) self.clear_button.setEnabled(False) self.clear_button.clicked.connect(self.clear_threshed) self.overlay_button.setEnabled(False) self.overlay_button.clicked.connect(self.overlay_threshed) def setup_video_frames(self): ''' set up spots for playing video frames ''' filler_frame = np.zeros((360, 540, 3)) filler_frame = qimage2ndarray.array2qimage(filler_frame) self.raw_frame = QFrame(self) self.raw_label = QLabel() self.raw_label.setText('raw') self.raw_frame.setGeometry( QRect(self.window_width * .01, self.window_height * .15, self.video_width, self.video_height)) self.raw_frame raw_layout = QVBoxLayout() self.raw_frame.setLayout(raw_layout) raw_layout.addWidget(self.raw_label) self.threshed_frame = QFrame(self) self.threshed_label = QLabel() self.threshed_label.setText('Threshed') self.threshed_frame.setGeometry( QRect(self.window_width * .51, self.window_height * .15, self.video_width, self.video_height)) threshed_layout = QVBoxLayout() self.threshed_frame.setLayout(threshed_layout) threshed_layout.addWidget(self.threshed_label) self.label_frame = QFrame(self) self.label_frame.setGeometry( QRect(self.window_width * .01, self.window_height * .11, self.video_width * 2, 50)) self.label_rawlabel = QLabel() self.label_rawlabel.setText('Raw Video') self.label_threshedlabel = QLabel() self.label_threshedlabel.setText('Threshold View') label_layout = QHBoxLayout() self.label_frame.setLayout(label_layout) label_layout.addWidget(self.label_rawlabel) label_layout.addWidget(self.label_threshedlabel) self.raw_label.setPixmap(QPixmap.fromImage(filler_frame)) self.threshed_label.setPixmap(QPixmap.fromImage(filler_frame)) def Acquire(self): if self.action_Acq.isChecked(): self.vidbuffer = [] if self.recording: while 1: try: self.sock.send('StopRecord') self.sock.recv() except: continue break self.recording = False else: #create and start a thread to transport a worker to later self.workerThread = QThread(self) self.workerThread.start() #create a worker object based on Worker class and move it to our #worker thread self.worker = Worker(self) self.worker.moveToThread(self.workerThread) try: self.start_acq.disconnect() except: pass while 1: try: self.sock.send('StartAcquisition') self.sock.recv() except: continue break self.acquiring = True self.start_acq.connect(self.worker.acquire) self.start_acq.emit('start!') self.action_Acq.setEnabled(False) self.action_Record.setChecked(False) self.action_Record.setEnabled(True) record_icon = self.style().standardIcon(QStyle.SP_DialogYesButton) #set the icon for the action self.action_Record.setIcon(record_icon) def Record(self): if self.action_Record.isChecked(): if not self.acquiring: self.workerThread = QThread(self) self.workerThread.start() self.worker = Worker(self) self.worker.moveToThread(self.workerThread) try: self.start_rec.disconnect() except: pass while 1: try: self.sock.send('StartAcquisition') self.sock.recv() except: continue break while 1: try: self.sock.send('StartRecord') self.sock.recv() except: continue break self.vidbuffer = [] self.start_rec.connect(self.worker.acquire) self.recording = True self.start_rec.emit('start!') else: while 1: try: self.sock.send('StartRecord') self.sock.recv() except: continue break self.vidbuffer = [] self.recording = True record_icon = self.style().standardIcon(QStyle.SP_DialogNoButton) #set the icon for the action self.action_Record.setIcon(record_icon) self.action_Record.setEnabled(False) self.action_Acq.setChecked(False) self.action_Acq.setEnabled(True) def Stop(self): self.acquiring = False self.recording = False while 1: try: self.sock.send('isRecording') rec = self.sock.recv() except: continue break if rec == '1': while 1: try: self.sock.send('StopRecord') self.sock.recv() except: continue break self.action_Record.setEnabled(True) self.action_Record.setChecked(False) while 1: try: self.sock.send('isAcquiring') acq = self.sock.recv_string() except: continue break if acq == '1': while 1: try: self.sock.send('StopAcquisition') self.sock.recv() except: continue break self.action_Acq.setEnabled(True) self.action_Acq.setChecked(False) try: #open a csv file for saving tracking data with open(self.vt_file, 'a') as csvfile: #create a writer vidwriter = csv.writer(csvfile, dialect='excel-tab') #check if it's an empty file for row in self.vidbuffer: vidwriter.writerow(row) except: pass record_icon = self.style().standardIcon(QStyle.SP_DialogYesButton) #set the icon for the action self.action_Record.setIcon(record_icon) def update_frame(self, image): self.raw_label.setPixmap(QPixmap.fromImage(image)) def update_threshed(self, threshed_image): self.threshed_label.setPixmap(QPixmap.fromImage(threshed_image)) def clear_threshed(self): self.green_frame = np.zeros_like(self.green_frame) self.red_frame = np.zeros_like(self.red_frame) def overlay_threshed(self): if self.overlay: self.overlay = False elif not self.overlay: self.overlay = True # def sort_now(self): # # if self.recdir is not None: # os.chdir('./kilosort_control') # #create and show the main window # self.sort_frame = kilosort_control.sort_gui.MainWindow() # self.sort_frame.show() # # #set up stream for stdout and stderr based on outputStream class # self.outputStream = kilosort_control.sort_gui.outputStream() # #when outputStream sends messages, connect to appropriate function for # #writing to terminal window # self.outputStream.message.connect(self.sort_frame.print_message) # # #connect stdout and stderr to outputStream # sys.stdout = self.outputStream # sys.stderr = self.outputStream # # self.sort_frame.run_now(self.recdir) # # self.close() def get_info(self): self.info_window = QWidget() self.info_window.resize(400, 350) #set title self.info_window.setWindowTitle('Session Info') #give layout info_layout = QVBoxLayout(self.info_window) with open('info_fields.pickle', 'rb') as f: default_fields = pickle.load(f) f.close() #set label for pic_resolution setting experimenter_label = QLabel('Experimenter:') #make a QLineEdit box for displaying/editing settings experimenter = QComboBox(self.info_window) experimenter.setEditable(True) experimenter.addItems(default_fields['experimenter']) #add label and box to current window info_layout.addWidget(experimenter_label) info_layout.addWidget(experimenter) #set label for pic_resolution setting whose_animal_label = QLabel('Whose animal?') #make a QLineEdit box for displaying/editing settings whose_animal = QComboBox(self.info_window) whose_animal.setEditable(True) whose_animal.addItems(default_fields['whose_animal']) #add label and box to current window info_layout.addWidget(whose_animal_label) info_layout.addWidget(whose_animal) animal_number_label = QLabel('Animal number:') animal_number = QComboBox(self.info_window) animal_number.setEditable(True) animal_number.addItems(default_fields['animal_number']) info_layout.addWidget(animal_number_label) info_layout.addWidget(animal_number) session_number_label = QLabel('Session number:') session_number = QTextEdit(self.info_window) session_number.setText('1') info_layout.addWidget(session_number_label) info_layout.addWidget(session_number) session_type_label = QLabel('Session type:') session_type = QComboBox(self.info_window) session_type.setEditable(True) session_type.addItems(default_fields['session_type']) info_layout.addWidget(session_type_label) info_layout.addWidget(session_type) def save_info(self): info_fields = {} info_fields['experimenter'] = [ experimenter.itemText(i) for i in range(experimenter.count()) ] info_fields['whose_animal'] = [ whose_animal.itemText(i) for i in range(whose_animal.count()) ] info_fields['animal_number'] = [ animal_number.itemText(i) for i in range(animal_number.count()) ] info_fields['session_type'] = [ session_type.itemText(i) for i in range(session_type.count()) ] with open('info_fields.pickle', 'wb') as f: pickle.dump(info_fields, f, protocol=2) f.close() current_experimenter = str(experimenter.currentText()) current_whose_animal = str(whose_animal.currentText()) current_animal_number = str(animal_number.currentText()) current_session_number = str(session_number.toPlainText()) current_session_type = str(session_type.currentText()) recdir = data_save_dir + current_whose_animal + '/' + current_animal_number if not os.path.exists(recdir): os.makedirs(recdir) self.experiment_info = '###### Experiment Info ######\r\n' self.experiment_info += 'Experimenter: %s\r\n' % current_experimenter self.experiment_info += 'Whose animal? %s\r\n' % current_whose_animal self.experiment_info += 'Animal number: %s\r\n' % current_animal_number self.experiment_info += 'Session number: %s\r\n' % current_session_number self.experiment_info += 'Session type: %s\r\n' % current_session_type self.experiment_info = self.experiment_info.encode() config_file = config_path + '/' + current_animal_number + '.xml' if not os.path.exists(config_file): shutil.copy(default_config, config_file) tree = et.parse(config_file) root = tree.getroot() for child in root: if child.tag == 'CONTROLPANEL': child.attrib['recordPath'] = recdir.replace('/', '\\') tree.write(config_file) tree.write(default_config) self.info_window.close() self.noinfo = False ready_button = QPushButton('Ready!') ready_button.clicked.connect(lambda: save_info(self)) info_layout.addWidget(ready_button) self.info_window.show()
class PlotMainWindow(QWidget): """Base class for plot main windows.""" def __init__(self, U, plot, length=1, title=None): super().__init__() layout = QVBoxLayout() if title: title = QLabel('<b>' + title + '</b>') title.setAlignment(Qt.AlignHCenter) layout.addWidget(title) layout.addWidget(plot) plot.set(U, 0) if length > 1: hlayout = QHBoxLayout() self.slider = QSlider(Qt.Horizontal) self.slider.setMinimum(0) self.slider.setMaximum(length - 1) self.slider.setTickPosition(QSlider.TicksBelow) hlayout.addWidget(self.slider) lcd = QLCDNumber(m.ceil(m.log10(length))) lcd.setDecMode() lcd.setSegmentStyle(QLCDNumber.Flat) hlayout.addWidget(lcd) layout.addLayout(hlayout) hlayout = QHBoxLayout() toolbar = QToolBar() self.a_play = QAction( self.style().standardIcon(QStyle.SP_MediaPlay), 'Play', self) self.a_play.setCheckable(True) self.a_rewind = QAction( self.style().standardIcon(QStyle.SP_MediaSeekBackward), 'Rewind', self) self.a_toend = QAction( self.style().standardIcon(QStyle.SP_MediaSeekForward), 'End', self) self.a_step_backward = QAction( self.style().standardIcon(QStyle.SP_MediaSkipBackward), 'Step Back', self) self.a_step_forward = QAction( self.style().standardIcon(QStyle.SP_MediaSkipForward), 'Step', self) self.a_loop = QAction( self.style().standardIcon(QStyle.SP_BrowserReload), 'Loop', self) self.a_loop.setCheckable(True) toolbar.addAction(self.a_play) toolbar.addAction(self.a_rewind) toolbar.addAction(self.a_toend) toolbar.addAction(self.a_step_backward) toolbar.addAction(self.a_step_forward) toolbar.addAction(self.a_loop) if hasattr(self, 'save'): self.a_save = QAction( self.style().standardIcon(QStyle.SP_DialogSaveButton), 'Save', self) toolbar.addAction(self.a_save) self.a_save.triggered.connect(self.save) hlayout.addWidget(toolbar) self.speed = QSlider(Qt.Horizontal) self.speed.setMinimum(0) self.speed.setMaximum(100) hlayout.addWidget(QLabel('Speed:')) hlayout.addWidget(self.speed) layout.addLayout(hlayout) self.timer = QTimer() self.timer.timeout.connect(self.update_solution) self.slider.valueChanged.connect(self.slider_changed) self.slider.valueChanged.connect(lcd.display) self.speed.valueChanged.connect(self.speed_changed) self.a_play.toggled.connect(self.toggle_play) self.a_rewind.triggered.connect(self.rewind) self.a_toend.triggered.connect(self.to_end) self.a_step_forward.triggered.connect(self.step_forward) self.a_step_backward.triggered.connect(self.step_backward) self.speed.setValue(50) elif hasattr(self, 'save'): hlayout = QHBoxLayout() toolbar = QToolBar() self.a_save = QAction( self.style().standardIcon(QStyle.SP_DialogSaveButton), 'Save', self) toolbar.addAction(self.a_save) hlayout.addWidget(toolbar) layout.addLayout(hlayout) self.a_save.triggered.connect(self.save) self.setLayout(layout) self.plot = plot self.U = U self.length = length def slider_changed(self, ind): self.plot.set(self.U, ind) def speed_changed(self, val): self.timer.setInterval(val * 20) def update_solution(self): ind = self.slider.value() + 1 if ind >= self.length: if self.a_loop.isChecked(): ind = 0 else: self.a_play.setChecked(False) return self.slider.setValue(ind) def toggle_play(self, checked): if checked: if self.slider.value() + 1 == self.length: self.slider.setValue(0) self.timer.start() else: self.timer.stop() def rewind(self): self.slider.setValue(0) def to_end(self): self.a_play.setChecked(False) self.slider.setValue(self.length - 1) def step_forward(self): self.a_play.setChecked(False) ind = self.slider.value() + 1 if ind == self.length and self.a_loop.isChecked(): ind = 0 if ind < self.length: self.slider.setValue(ind) def step_backward(self): self.a_play.setChecked(False) ind = self.slider.value() - 1 if ind == -1 and self.a_loop.isChecked(): ind = self.length - 1 if ind >= 0: self.slider.setValue(ind)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.debug = debug self.progset = QSettings("ADLMIDI-pyGUI", "ADLMIDI-pyGUI") self.about_window = None self.settings_window = None self.paused = False self.MaxRecentFiles = int(self.progset.value("file/MaxRecentFiles", 5)) self.recentList = self.progset.value("file/recent", []) if type(self.recentList) is unicode: self.recentList = [self.recentList] self.banks = [ " 0 = AIL (Star Control 3, Albion, Empire 2, Sensible Soccer, Settlers 2, many others)", "01 = Bisqwit (selection of 4op and 2op)", "02 = HMI (Descent, Asterix)", "03 = HMI (Descent:: Int)", "04 = HMI (Descent:: Ham)", "05 = HMI (Descent:: Rick)", "06 = HMI (Descent 2)", "07 = HMI (Normality)", "08 = HMI (Shattered Steel)", "09 = HMI (Theme Park)", "10 = HMI (3d Table Sports, Battle Arena Toshinden)", "11 = HMI (Aces of the Deep)", "12 = HMI (Earthsiege)", "13 = HMI (Anvil of Dawn)", "14 = DMX (Doom :: partially pseudo 4op)", "15 = DMX (Hexen, Heretic :: partially pseudo 4op)", "16 = DMX (MUS Play :: partially pseudo 4op)", "17 = AIL (Discworld, Grandest Fleet, Pocahontas, Slob Zone 3d, Ultima 4, Zorro)", "18 = AIL (Warcraft 2)", "19 = AIL (Syndicate)", "20 = AIL (Guilty, Orion Conspiracy, Terra Nova Strike Force Centauri :: 4op)", "21 = AIL (Magic Carpet 2)", "22 = AIL (Nemesis)", "23 = AIL (Jagged Alliance)", "24 = AIL (When Two Worlds War :: 4op, MISSING INSTRUMENTS)", "25 = AIL (Bards Tale Construction :: MISSING INSTRUMENTS)", "26 = AIL (Return to Zork)", "27 = AIL (Theme Hospital)", "28 = AIL (National Hockey League PA)", "29 = AIL (Inherit The Earth)", "30 = AIL (Inherit The Earth, file two)", "31 = AIL (Little Big Adventure :: 4op)", "32 = AIL (Wreckin Crew)", "33 = AIL (Death Gate)", "34 = AIL (FIFA International Soccer)", "35 = AIL (Starship Invasion)", "36 = AIL (Super Street Fighter 2 :: 4op)", "37 = AIL (Lords of the Realm :: MISSING INSTRUMENTS)", "38 = AIL (SimFarm, SimHealth :: 4op)", "39 = AIL (SimFarm, Settlers, Serf City)", "40 = AIL (Caesar 2 :: partially 4op, MISSING INSTRUMENTS)", "41 = AIL (Syndicate Wars)", "42 = AIL (Bubble Bobble Feat. Rainbow Islands, Z)", "43 = AIL (Warcraft)", "44 = AIL (Terra Nova Strike Force Centuri :: partially 4op)", "45 = AIL (System Shock :: partially 4op)", "46 = AIL (Advanced Civilization)", "47 = AIL (Battle Chess 4000 :: partially 4op, melodic only)", "48 = AIL (Ultimate Soccer Manager :: partially 4op)", "49 = AIL (Air Bucks, Blue And The Gray, America Invades, Terminator 2029)", "50 = AIL (Ultima Underworld 2)", "51 = AIL (Kasparov's Gambit)", "52 = AIL (High Seas Trader :: MISSING INSTRUMENTS)", "53 = AIL (Master of Magic, Master of Orion 2 :: 4op, std percussion)", "54 = AIL (Master of Magic, Master of Orion 2 :: 4op, orchestral percussion)", "55 = SB (Action Soccer)", "56 = SB (3d Cyberpuck :: melodic only)", "57 = SB (Simon the Sorcerer :: melodic only)", "58 = OP3 (The Fat Man 2op set)", "59 = OP3 (The Fat Man 4op set)", "60 = OP3 (JungleVision 2op set :: melodic only)", "61 = OP3 (Wallace 2op set, Nitemare 3D :: melodic only)", "62 = TMB (Duke Nukem 3D)", "63 = TMB (Shadow Warrior)", "64 = DMX (Raptor)" ] self.openicon = QIcon.fromTheme('document-open', QIcon('img/load.png')) self.saveicon = QIcon.fromTheme('document-save', QIcon('img/save.png')) self.playicon = QIcon.fromTheme('media-playback-start', QIcon('img/play.png')) self.pauseicon = QIcon.fromTheme('media-playback-pause', QIcon('img/pause.png')) self.stopicon = QIcon.fromTheme('media-playback-stop', QIcon('img/stop.png')) self.quiticon = QIcon.fromTheme('application-exit', QIcon('img/quit.png')) self.abouticon = QIcon.fromTheme('help-about', QIcon('img/about.png')) self.setticon = QIcon.fromTheme('preferences-desktop', QIcon('img/settings.png')) self.winsetup() def addWorker(self, worker): worker.message.connect(self.update) worker.finished.connect(self.workerFinished) self.threads.append(worker) def workerFinished(self): pass #barf('MSG', 'Thread completed the task!') def killWorkers(self): pass #for worker in self.threads: # worker.terminate() def winsetup(self): self.setWindowIcon(QIcon('img/note.png')) openFile = QAction(self.openicon, 'Open', self) openFile.setShortcut('Ctrl+O') openFile.triggered.connect(self.load) saveFile = QAction(self.saveicon, 'Save', self) saveFile.setShortcut('Ctrl+S') saveFile.triggered.connect(self.save) playFile = QAction(self.playicon, 'Play', self) playFile.setShortcut('Ctrl+P') playFile.triggered.connect(self.play) pausePlayb = QAction(self.pauseicon, 'Pause', self) pausePlayb.setShortcut('Ctrl+R') pausePlayb.triggered.connect(self.pause) stopPlay = QAction(self.stopicon, 'Stop', self) stopPlay.setShortcut('Ctrl+Z') stopPlay.triggered.connect(self.stop) exitAction = QAction(self.quiticon, 'Quit', self) exitAction.setShortcut('Ctrl+X') exitAction.triggered.connect(self.quit) aboutdlg = QAction(self.abouticon, 'About', self) aboutdlg.setShortcut('Ctrl+A') aboutdlg.triggered.connect(self.about) showSett = QAction(self.setticon, 'Settings', self) showSett.triggered.connect(self.settings) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') configMenu = menubar.addMenu('&Options') configMenu.setStyleSheet("border: 1px solid black;") self.setLooped = QAction('Loop', configMenu, checkable=True) if self.progset.value("sound/Looped") == 'true': self.setLooped.setChecked(True) else: self.setLooped.setChecked(False) self.setLooped.setShortcut('Ctrl+L') self.setAutoplay = QAction('Autoplay', configMenu, checkable=True) if self.progset.value("sound/Autoplay") == 'true': self.setAutoplay.setChecked(True) else: self.setAutoplay.setChecked(False) self.setAutoplay.setShortcut('Ctrl+K') configMenu.addAction(self.setAutoplay) configMenu.addAction(self.setLooped) fileMenu.setStyleSheet("border: 1px solid black;") fileMenu.addAction(openFile) fileMenu.addAction(saveFile) fileMenu.addSeparator() self.recentMenu = fileMenu.addMenu('Recent') self.rfUpdate() fileMenu.addSeparator() fileMenu.addAction(showSett) fileMenu.addSeparator() fileMenu.addAction(exitAction) helpMenu = menubar.addMenu('&Help') helpMenu.setStyleSheet("border: 1px solid black;") helpMenu.addAction(aboutdlg) self.numCards = QSpinBox() numCards_text = QLabel(" OPL : ") self.numCards.setRange(1, 100) self.numCards.setValue(int(self.progset.value("sound/numCards", 3))) self.numCards.valueChanged.connect(self.updateMax4ops) self.fourOps = QSpinBox() fourOps_text = QLabel(" 4op Ch : ") self.fourOps.setRange(0, self.numCards.value()*6) self.fourOps.setValue(int(self.progset.value("sound/fourOps", self.numCards.value()*6))) self.twoOps = QSpinBox() twoOps_text = QLabel(" 2op Ch : ") self.twoOps.setValue((self.numCards.value()*12 - self.fourOps.value())) self.twoOps.setRange(self.twoOps.value(), self.twoOps.value()) toolbar = self.addToolBar('Media') toolbar.addAction(playFile) toolbar.addAction(pausePlayb) toolbar.addAction(stopPlay) toolbar.setMovable(False) toolbar.addSeparator() toolbar.addWidget(numCards_text) toolbar.addWidget(self.numCards) toolbar.addSeparator() toolbar.addWidget(fourOps_text) toolbar.addWidget(self.fourOps) #toolbar.addSeparator() #toolbar.addWidget(twoOps_text) #toolbar.addWidget(self.twoOps) self.statusBar() self.setFixedSize(380, 90) self.center() self.setWindowTitle('ADLMIDI pyGUI') self.show() if self.debug: barf("MSG", "Loaded Main Window", True, False) self.update("ready") self.threads = [] self.addWorker(AdlMidi(1)) self.addWorker(AdlMidiSave(2)) def rfUpdate(self): self.recentMenu.clear() def recentfile(f2l): return lambda: self.load2(f2l) self.recentFileActs = [] recentLength = len(self.recentList) for i in range(self.MaxRecentFiles): try: if i >= recentLength: break rev = (recentLength-1)-i filetoload = self.recentList[rev] filename = path.split(filetoload)[1] self.fileact = QAction(filename, self.recentMenu) self.fileact.triggered.connect(recentfile(filetoload)) self.recentFileActs.append(self.fileact) except Exception: pass for i in range(self.MaxRecentFiles): try: self.recentMenu.addAction(self.recentFileActs[i]) except Exception: pass def get_bank(self): try: selection = self.settings_window.combo.currentText() selection = str(selection[0])+str(selection[1]) return int(selection) except Exception: return 1 def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def about(self): if self.about_window is None: window = QMessageBox(self) self.about_window = window else: window = self.about_window window = self.about_window window.setWindowIcon(QIcon(self.abouticon)) window.setWindowTitle('About ADLMIDI pyGUI') credits = "<center><b>ADLMIDI pyGUI v%s (%s)</b><br>Developed by Tristy H. \"KittyTristy\"<br>[<a href=\"https://github.com/KittyTristy/ADLMIDI-pyGUI\">Website</a>] [<a href=\"mailto:[email protected]\">Email</a>] <br><br><br>" % (__version__, system()) title = "<b>ADLMIDI pyGUI</b> is a GUI wrapper<br>written in Python for use with..<br><br><b>ADLMIDI: MIDI Player<br>for Linux and Windows with OPL3 emulation</b><br>" cw = "(C) -- <a href=\"http://iki.fi/bisqwit/source/adlmidi.html\">http://iki.fi/bisqwit/source/adlmidi.html</a></center>" credits = credits + title + cw window.setText(credits) window.show() window.activateWindow() window.raise_() def settings(self): if self.settings_window is None: window = QDialog(self) self.settings_window = window else: window = self.settings_window window = self.settings_window window.setWindowTitle('Settings') window.notelabel = QLabel("Currently these settings are only guaranteed to work prior to loading the first MIDI!\nYou'll have to restart ADLMIDI pyGui to change them again if they stop working. \n\nSorry! This will be fixed soon!") window.notelabel.setWordWrap(True) window.notelabel.setStyleSheet("font-size: 8pt; border-style: dotted; border-width: 1px; padding: 12px;") window.banklabel = QLabel("<B>Choose Instrument Bank</B>") window.space = QLabel("") window.optlabel = QLabel("<B>Options</B>") window.combo = QComboBox() window.combo.addItems(self.banks) #window.combo.setMaximumWidth(350) window.combo.setMaxVisibleItems(12) window.combo.setStyleSheet("combobox-popup: 0;") window.combo.setCurrentIndex(int(self.progset.value("sound/bank", 1))) window.combo.currentIndexChanged.connect(self.saveSettings) window.perc = QCheckBox("Adlib Percussion Instrument Mode") #window.perc.stateChanged.connect(self.checkOpts) window.tremamp = QCheckBox("Tremolo Amplification Mode") #window.tremamp.stateChanged.connect(self.checkOpts) window.vibamp = QCheckBox("Vibrato Amplification Mode") #window.vibamp.stateChanged.connect(self.checkOpts) window.modscale = QCheckBox("Scaling of Modulator Volume") #window.modscale.stateChanged.connect(self.checkOpts) window.okButton = QPushButton('OK') window.okButton.clicked.connect(window.hide) vbox = QVBoxLayout() vbox.addWidget(window.space) vbox.addWidget(window.banklabel) vbox.addWidget(window.combo) vbox.addWidget(window.space) vbox.addWidget(window.optlabel) vbox.addWidget(window.perc) vbox.addWidget(window.tremamp) vbox.addWidget(window.vibamp) vbox.addWidget(window.modscale) vbox.addWidget(window.notelabel) hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(window.okButton) vbox.addLayout(hbox) window.setLayout(vbox) window.setFixedSize(530, 369) window.show() window.activateWindow() window.raise_() def updateMax4ops(self): self.fourOps.setMaximum(self.numCards.value()*6) self.fourOps.setValue(self.numCards.value()*6) barf("DBG", "Updating Maximum of 4ops Chs to %s" % (self.numCards.value()*6), True, False) #self.twoOps.setValue(self.numCards.value()*12 - self.fourOps.value()) #self.twoOps.setRange(self.twoOps.value(), self.twoOps.value()) def checkOpts(self): global arglist #barf("ACT", "Checking if Options have changed..", True, False) arglist = [] try: if QAbstractButton.isChecked(self.settings_window.perc) and not ('-p' in arglist): arglist.append('-p') elif not QAbstractButton.isChecked(self.settings_window.perc) and ('-p' in arglist): arglist.remove('-p') except Exception: pass try: if QAbstractButton.isChecked(self.settings_window.tremamp) and not ('-t' in arglist): arglist.append('-t') elif not QAbstractButton.isChecked(self.settings_window.tremamp) and ('-t' in arglist): arglist.remove('-t') except Exception: pass try: if QAbstractButton.isChecked(self.settings_window.vibamp) and not ('-v' in arglist): arglist.append('-v') elif not QAbstractButton.isChecked(self.settings_window.vibamp) and ('-v' in arglist): arglist.remove('-v') except Exception: pass try: if QAbstractButton.isChecked(self.settings_window.modscale) and not ('-s' in arglist): arglist.append('-s') elif not QAbstractButton.isChecked(self.settings_window.modscale) and ('-s' in arglist): arglist.remove('-s') except Exception: pass self.sel_bank = self.get_bank() def saveSettings(self): self.progset.setValue("sound/Autoplay", self.setAutoplay.isChecked()) self.progset.setValue("sound/Looped", self.setLooped.isChecked()) self.progset.setValue("sound/numCards", self.numCards.value()) self.progset.setValue("sound/fourOps", self.fourOps.value()) try: self.progset.setValue("sound/bank", self.settings_window.combo.currentIndex()) except Exception: pass if len(self.recentList) >= 1: self.progset.setValue("file/recent", self.recentList[-self.MaxRecentFiles:]) self.progset.setValue("file/MaxRecentFiles", self.MaxRecentFiles) #allkeys = self.progset.allKeys() #for key in allkeys: # barf('DBG', str(key) + " " + str(self.progset.value(key))) def closeEvent(self, event): self.stop() #self.pkill() self.saveSettings() barf("DBG", "Quitting", True, False) def quit(self): self.stop() #self.pkill() self.saveSettings() barf("DBG", "Quitting", True, False) exit(0) def pkill(self): try: p.kill() except Exception: pass ############################################################## ##### Statusbar Functions #################################### ############################################################## def clear(self): try: self.statusBar().removeWidget(self.playStatus) except Exception: pass @Slot(str) def update(self, status=''): self.clear() if status == "ready": text = " <B>Ready</b>" elif status == "play": text = " <B>Now Playing: </B>" + path.split(f.name)[1] elif status == "loop": text = " <B>Looping: </B>" + path.split(f.name)[1] elif status == "stop": text = " <B>Stopped: </B>" + path.split(f.name)[1] elif status == "pause": text = " <B>Paused: </B>" + path.split(f.name)[1] elif status == "loading": text = " <B>Loading.. </B>" elif status == "load": text = " <B>Loaded: </B>" + path.split(f.name)[1] elif status == "saving": text = " <B>Saving.. </B>" elif status == "saved": text = " <B>Saved as: </B>" + "saved/" + path.splitext(path.split(f.name)[1])[0] + ".wav" self.playStatus = QLabel(text) self.statusBar().addPermanentWidget(self.playStatus, 1) ############################################################## ####### Sound Functions ###################################### ############################################################## def play(self): global Paused, arglist if f != None and Paused == False: Paused = False self.stop() self.checkOpts() if not self.setLooped.isChecked(): arglist.append('-nl') arglist.append(str(self.progset.value("sound/bank", 1))) arglist.append(str(self.numCards.value())) arglist.append(str(self.fourOps.value())) for worker in self.threads: if worker.id == 1: worker.start() elif f != None and Paused == True: os.kill(p.pid, signal.SIGCONT) self.update("play") Paused = False def pause(self): global p, Paused if f != None: try: if Paused == False: os.kill(p.pid, signal.SIGSTOP) self.update("pause") Paused = True elif Paused == True: os.kill(p.pid, signal.SIGCONT) self.update("play") Paused = False except Exception: pass def stop(self): global Paused if f != None: Paused = False self.pkill() self.killWorkers() self.update("stop") ############################################################## ##### Load/Save Functions #################################### ############################################################## def load(self): global f lastdir = str(self.progset.value("file/lastdir", "")) fname, _ = QFileDialog.getOpenFileName(None, 'Open File', lastdir, "MIDI Audio File (*.mid *.MID)") if fname != "": f = file(fname, 'r') if not f.name in self.recentList: self.recentList.append(f.name) else: self.recentList.remove(f.name) self.recentList.append(f.name) self.progset.setValue("file/lastdir", path.split(f.name)[0]) self.rfUpdate() self.update("load") self.pkill() if self.debug: barf("SAV", "Loaded %s" % path.split(f.name)[1], True, False) if self.setAutoplay.isChecked(): self.play() else: self.update("load") def load2(self, r_file=None): global f f = file(r_file, 'r') self.recentList.remove(f.name) self.recentList.append(f.name) self.rfUpdate() self.update("load") self.pkill() if self.debug: barf("SAV", "Loaded %s" % path.split(f.name)[1], True, False) if self.setAutoplay.isChecked(): self.play() else: self.update("load") def save(self): if f != None: self.stop() for worker in self.threads: if worker.id == 2: worker.start()