class Wyrmy(QWidget): def __init__(self, outside): super(Wyrmy, self).__init__() # get/set basic information self.app_control = outside screen_res = self.app_control.desktop().screenGeometry() self.screen_width, self.screen_height = screen_res.width( ), screen_res.height() self.setWindowIcon(QIcon(':/resources/wyrmytheworm.png')) # get images to use self.worms = {} self.index = 0 self.file_names = [] self.images = {} self.load_images() # create first image, determine all dimensions self.label, self.panel_height, self.width, self.height = QLabel( self), 0, 0, 0 self.alive, self.dead = QLabel(), QLabel() self.percent = QLabel() self.open, self.save, self.export = QPushButton(), QPushButton( ), QPushButton() self.curr_img_disp = QLabel() self.alive.setText('Alive: 0') self.dead.setText('Dead: 0') self.percent.setText('Percent: 0%') self.open.setText('Open') self.open.setToolTip('Load a data file') self.save.setText('Save') self.save.setToolTip('Save a data file') self.export.setText('Export') self.export.setToolTip('Export data as CSV') self.open.setMaximumWidth(100) self.save.setMaximumWidth(100) self.export.setMaximumWidth(100) self.open.clicked.connect(self.open_file) self.save.clicked.connect(self.save_file) self.export.clicked.connect(self.export_data) self.layout = QGridLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.layout) self.panel_layout = QGridLayout(self.layout.widget()) self.panel_layout.setContentsMargins(15, 0, 15, 0) self.orig = QtGui.QPixmap(self.file_names[self.index]) scale_by = self.screen_height * 0.75 / self.orig.height() self.img = self.orig.scaled(self.orig.width() * scale_by, self.orig.height() * scale_by, QtCore.Qt.KeepAspectRatio) self.panel_height = self.screen_height * 0.1 self.width, self.height = self.img.width( ), self.img.height() + self.panel_height # self.panel = QGroupBox() # self.layout.addWidget(self.panel) # self.panel.move(0, self.img.height()) # self.panel.setFixedWidth(self.width) # self.panel.setFixedHeight(self.panel_height) self.layout.addLayout(self.panel_layout, 1, 0) self.panel_layout.addWidget(self.alive, 0, 0) self.panel_layout.addWidget(self.dead, 1, 0) self.panel_layout.addWidget(self.percent, 2, 0) self.panel_layout.addWidget(self.curr_img_disp, 1, 1) self.panel_layout.addWidget(self.open, 0, 2) self.panel_layout.addWidget(self.save, 1, 2) self.panel_layout.addWidget(self.export, 2, 2) startX = int((self.screen_width / 2) - (self.width / 2)) startY = int(((self.screen_height - 100) / 2) - (self.height / 2)) self.move(startX, startY) self.label.mousePressEvent = self.image_clicked self.dead_pic = QtGui.QPixmap(':/resources/red_target_scaled.png') self.alive_pic = QtGui.QPixmap(':/resources/green_target_scaled.png') self.layout.addWidget(self.label, 0, 0) self.markers = QBoxLayout(QBoxLayout.LeftToRight) self.layout.addChildLayout(self.markers) self.refresh() self.show() def load_images(self): file_names_import = QFileDialog.getOpenFileNames( self, "Open Image", "/", "Image Files (*.png *.jpg *.bmp *.tiff *.tif)") self.file_names = file_names_import[0] for name in self.file_names: self.worms[Wyrmy.pic_name(name)] = WormPic( filename=Wyrmy.pic_name(name)) def refresh(self): # take care of index wraparounds if len(self.file_names) == 0: self.app_control.quit() if self.index > len(self.file_names) - 1: self.index = 0 if self.index < 0: self.index = len(self.file_names) - 1 curr_img_name = self.file_names[self.index] # self.panel.setTitle(Wyrmy.pic_name(self.file_names[self.index])) orig = QtGui.QPixmap(self.file_names[self.index]) scale_by = self.screen_height * 0.75 / orig.height() self.img = orig.scaled(orig.width() * scale_by, orig.height() * scale_by, QtCore.Qt.KeepAspectRatio) self.label.setPixmap(self.img) self.setWindowTitle('Wyrmy - ' + curr_img_name) curr_pic = self.worms[Wyrmy.pic_name(self.file_names[self.index])] self.curr_img_disp.setText(Wyrmy.pic_name(curr_img_name)) num_dead = len(curr_pic.dead) num_alive = len(curr_pic.alive) alive_text = 'Alive: ' + str(num_alive) self.alive.setText(alive_text) dead_text = 'Dead: ' + str(num_dead) self.dead.setText(dead_text) if num_dead + num_alive > 0: percent_text = '% Dead: ' + str(100 * num_dead / (num_dead + num_alive)) else: percent_text = '% Dead: 0' self.percent.setText(percent_text) for ind in reversed(range(self.markers.count())): widget = self.markers.takeAt(ind).widget() if widget is not None: widget.deleteLater() for coords in curr_pic.dead: curr_dead = QLabel(self) curr_dead.setPixmap(self.dead_pic) self.markers.addWidget(curr_dead) curr_dead.move(coords.x * self.img.width() - 25, coords.y * self.img.height() - 12.5) # print(coords.x, ', ', coords.y) for coords in curr_pic.alive: curr_alive = QLabel(self) curr_alive.setPixmap(self.alive_pic) self.markers.addWidget(curr_alive) curr_alive.move(coords.x * self.img.width() - 25, coords.y * self.img.height() - 12.5) # print(coords.x, ', ', coords.y) def safe_index(self, index): if index < 0: new_ind = len(self.file_names) + index elif index > len(self.file_names) - 1: new_ind = index - len(self.file_names) else: new_ind = index if new_ind < 0: new_ind = 0 elif new_ind > len(self.file_names) - 1: new_ind = len(self.file_names) - 1 return new_ind @staticmethod def pic_name(file_name): last_index = file_name.rfind('/') return file_name[last_index + 1:last_index + 4] def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_W: self.index -= 1 if event.key() == QtCore.Qt.Key_S: self.index += 1 if event.key() == QtCore.Qt.Key_A: start = QWidget.mapToGlobal(self.label, self.label.pos()) click_x = (QtGui.QCursor.pos().x() - start.x()) / self.img.width() click_y = (QtGui.QCursor.pos().y() - start.y()) / self.img.height() click = Pair(click_x, click_y) self.worms[Wyrmy.pic_name( self.file_names[self.index])].alive.append(click) if event.key() == QtCore.Qt.Key_D: start = QWidget.mapToGlobal(self.label, self.label.pos()) click_x = (QtGui.QCursor.pos().x() - start.x()) / self.img.width() click_y = (QtGui.QCursor.pos().y() - start.y()) / self.img.height() click = Pair(click_x, click_y) self.worms[Wyrmy.pic_name( self.file_names[self.index])].dead.append(click) if event.key() == QtCore.Qt.Key_X: curr_pic = self.worms[Wyrmy.pic_name(self.file_names[self.index])] curr_pic.alive = [] curr_pic.dead = [] self.refresh() event.accept() def image_clicked(self, event): click = Pair(event.x() / self.img.width(), event.y() / self.img.height()) if event.button() == QtCore.Qt.LeftButton: self.worms[Wyrmy.pic_name( self.file_names[self.index])].alive.append(click) if event.button() == QtCore.Qt.RightButton: self.worms[Wyrmy.pic_name( self.file_names[self.index])].dead.append(click) # if event.button() == QtCore.Qt.MidButton: # curr_pic = self.worms[Wyrmy.pic_name(self.file_names[self.index])] # max_diff_x = 25/self.img.width() # max_diff_y = 25/self.img.height() # for ind, coords in enumerate(curr_pic.alive): # if abs(coords.x-click.x) < max_diff_x and abs(coords.y-click.y) < max_diff_y: # del curr_pic.alive[ind] # break # for ind, coords in enumerate(curr_pic.dead): # if abs(coords.x-click.x) < max_diff_x and abs(coords.y-click.y) < max_diff_y: # del curr_pic.dead[ind] # break self.refresh() event.accept() @pyqtSlot() def open_file(self): input_from = QFileDialog.getOpenFileName(self, caption='Open File', filter='Wyrmy Data (*.wyrm)') if len(input_from[0]) > 0: with open(input_from[0], 'rb') as reading: self.worms = pickle.load(reading) reading.close() self.refresh() @pyqtSlot() def save_file(self): output_at = QFileDialog.getSaveFileName(self, caption='Save File', filter='Wyrmy Data (*.wyrm)') if len(output_at[0]) > 0: with open(output_at[0], 'wb') as out: pickle.dump(self.worms, out) out.close() @pyqtSlot() def export_data(self): output_at = QFileDialog.getSaveFileName( self, caption='Save File', filter='CSV (Comma delimited) (*.csv)') if len(output_at[0]) > 0: out = open(output_at[0], 'a') out.write('Name,Alive,Dead\n') for name in self.file_names: curr = self.worms[Wyrmy.pic_name(name)] this_pic = str(curr.filename) + ',' + str(len( curr.alive)) + ',' + str(len(curr.dead)) + '\n' out.write(this_pic) out.close()
class MainWindow(QMainWindow): shortcuts = { "QUIT": "Ctrl+W", "ADD": "Ctrl+N", "EDIT": "Ctrl+I", "OPEN": "Ctrl+O", "OPEN-LEGACY": "Ctrl+Shift+O", "CREATE": "Ctrl+Shift+N", "SETTINGS": "Ctrl+Alt+S", "MANAGE-SCHEDULES": "" } icons = { "QUIT": ":/small/quit", "ADD": ":/medium/add", "EDIT": ":/medium/edit", "OPEN": ":/small/open", "OPEN-LEGACY": ":/small/open", "CREATE": ":/small/create", "SETTINGS": ":/small/settings", "MANAGE-SCHEDULES": ":/small/manage", "REMOVE": ":/medium/remove", "WINDOW": ":/small/window" } def __init__(self): super().__init__(flags=Qt.Window) # setup actions self.status_bar = self.statusBar() self.tool_bar = self.addToolBar("Video") # TODO: icon sizes self.tool_bar.setIconSize(QSize(36, 36)) # add the following 3 lines back in if you want the buttons to be right aligned # spacer = QWidget() # spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # self.tool_bar.addWidget(spacer) self.action_quit = QAction("Quit") self.action_quit.setShortcut(self.shortcuts["QUIT"]) self.action_quit.setIcon(QIcon(QPixmap(self.icons["QUIT"]))) self.action_quit.triggered.connect(self.close) self.action_add = QAction("Add Video") self.action_add.setShortcut(self.shortcuts["ADD"]) self.action_add.setIcon(QIcon(QPixmap(self.icons["ADD"]))) self.action_add.triggered.connect(self.add_video) self.action_edit = QAction("Edit Video Options") self.action_edit.setShortcut(self.shortcuts["EDIT"]) self.action_edit.setIcon(QIcon(QPixmap(self.icons["EDIT"]))) self.action_edit.triggered.connect(lambda: print("Action Edit Video")) self.action_open = QAction("Open") self.action_open.setShortcut(self.shortcuts["OPEN"]) self.action_open.setIcon(QIcon(QPixmap(self.icons["OPEN"]))) self.action_open.triggered.connect(lambda: print("Action Open")) self.action_open_legacy = QAction("Open Legacy File(.vst)") self.action_open_legacy.setShortcut(self.shortcuts["OPEN-LEGACY"]) self.action_open_legacy.setIcon(QIcon(QPixmap(self.icons["OPEN-LEGACY"]))) self.action_open_legacy.triggered.connect(lambda: print("Action Open Legacy")) self.action_create = QAction("Create Schedule") self.action_create.setShortcut(self.shortcuts["CREATE"]) self.action_create.setIcon(QIcon(QPixmap(self.icons["CREATE"]))) self.action_create.triggered.connect(self.create_schedule) self.action_settings = QAction("Settings") self.action_settings.setShortcut(self.shortcuts["SETTINGS"]) self.action_settings.setIcon(QIcon(QPixmap(self.icons["SETTINGS"]))) self.action_settings.triggered.connect(lambda: print("Action Settings")) self.action_remove = QAction("Remove Video") # self.action_remove.setShortcut(self.shortcuts["REMOVE"]) self.action_remove.setIcon(QIcon(QPixmap(self.icons["REMOVE"]))) self.action_remove.triggered.connect(self.table_right_clicked) # build views self.central_widget = QWidget(self, Qt.Widget) self.main_layout = QGridLayout() self.central_widget.setLayout(self.main_layout) self.schedule_layout = QHBoxLayout() picker_text = QLabel() picker_text.setText("Select Schedule:") self.schedule_picker = QComboBox() self.schedule_picker.currentIndexChanged.connect(lambda x: print("Picker!")) self.schedule_picker.addItems(["Item 1", "Item 2", "Item 3"]) self.schedule_layout.addWidget(self.schedule_picker) self.main_layout.addWidget(picker_text, 0, 0) self.main_layout.addChildLayout(self.schedule_layout) self.main_layout.addWidget(self.schedule_picker, 0, 1) self.video_table_view = QTableView(self) self.video_table_view.hideColumn(0) self.video_table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.main_layout.addWidget(self.video_table_view, 1, 0, 1, 4) self.video_table_view.customContextMenuRequested.connect(lambda: "right click") self.inspect_video_window = QDockWidget() lbl = QLabel() lbl.setText("I am a dock window label!") self.inspect_video_window.setWidget(lbl) self.addDockWidget(Qt.BottomDockWidgetArea, self.inspect_video_window) self.setCentralWidget(self.central_widget) self.init_ui() def add_video(self): # when add video event is clicked # does nothing - child will override this method pass def create_schedule(self): # when create schedule event is clicked # does nothing - child will override this method pass def table_right_clicked(self, position): print("Right clicked") menu = QMenu() menu.addAction(self.action_remove) menu.exec_(self.ui.table_videos.viewport().mapToGlobal(position)) pass @staticmethod def default_event(): # this is what all the onClicks, menu buttons, etc. get connected to by default # it does nothing - is just a placeholder pass def init_ui(self): self.setWindowTitle("Video Scheduler") self.setWindowIcon(QIcon(QPixmap(self.icons["WINDOW"]))) #with open("../darkstyle.qss") as f: # self.setStyleSheet(f.read()) self.resize(800, 600) self.setup_menu_bar() self.setup_toolbar() self.post_status_message() def setup_menu_bar(self): menu_bar = self.menuBar() file_menu = menu_bar.addMenu("File") file_menu.addAction(self.action_create) file_menu.addAction(self.action_open) file_menu.addAction(self.action_open_legacy) file_menu.addSeparator() file_menu.addAction(self.action_settings) file_menu.addSeparator() file_menu.addAction(self.action_quit) edit_menu = menu_bar.addMenu("Edit") edit_menu.addAction(self.action_add) edit_menu.addAction(self.action_edit) def setup_toolbar(self): self.tool_bar.show() self.tool_bar.addAction(self.action_add) self.tool_bar.addAction(self.action_edit) self.tool_bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) def post_status_message(self): # status_bar_layout = self.status_bar.layout() now_playing = QLabel() now_playing.setText("Now playing: video1.mp4") time_left = QLabel() time_left.setText("Time left: 5:05") line = QFrame(self, Qt.Widget) # line.setObjectName(QString.fromUtf8("line")) # line.setGeometry(QRect(320, 150, 118, 3)) # line.setSiz line.setFrameShape(QFrame.VLine) line.setFrameShadow(QFrame.Sunken) # status_bar_layout.addWidget(now_playing) self.status_bar.addWidget(now_playing) self.status_bar.addWidget(line) self.status_bar.addWidget(time_left) @staticmethod def table_double_clicked(index): print(index.column()) if index.column() == 0: # we want to open a file dialog to choose new video filename, status = QFileDialog.getOpenFileName(caption="Choose Video File") print(filename) else: return