def add_fields_to_component(component: Component, fields_widget: QListWidget): """ Adds fields from a list widget to a component. :param component: Component to add the field to. :param fields_widget: The field list widget to extract field information such the name and value of each field. """ for i in range(fields_widget.count()): widget = fields_widget.itemWidget(fields_widget.item(i)) try: component.set_field(name=widget.name, value=widget.value, dtype=widget.dtype) except ValueError as error: show_warning_dialog( f"Warning: field {widget.name} not added", title="Field invalid", additional_info=str(error), parent=fields_widget.parent().parent(), )
class Ui_MainWindow(object): image_stack=[None] current_effect="" def resize(self): self.timer.stop() temp=QDialog() temp.ui=Ui_Dialog_Resize(self.image_stack[-1]) temp.ui.setupUi(temp) temp.show() temp.exec_() self.image_stack.append(temp.ui.image) self.timer.start(1) pass def cropping(self): if type(self.image_stack[-1])==type(None): print("lol") return self.timer.stop() temp=QDialog() temp.ui=Ui_Dialog(self.image_stack[-1]) temp.ui.setupUi(temp) temp.show() temp.exec_() self.image_stack.append(temp.ui.image) self.timer.start(1) pass def effectFuctions(self,effect,image,amount): if effect=="Brightness": return brightness(image, amount=amount) elif effect=="Saturation": return saturation(image, amount) elif effect=="Sharpen": return sharpness(image, amount) elif effect=="Sepia Effect": return sepia(image, amount) elif effect=="Warm": return warm(image, amount) elif effect == "Cold": return cold(image, amount) elif effect == "Equalize": return equalise(image, amount) elif effect== "Cartoon": return cartoon(image, amount) elif effect== "Blurring": return blurring(image, amount) elif effect== "Pencil Sketch": return pencil_sketch(image, amount) elif effect== "Noise Reduction": return noise_reduction(image, amount) elif effect== "Negetive" : return negative(image, amount) elif effect== "Vignette": return vignette(image, amount) elif effect== "Emboss": return emboss(image, amount) elif effect== "Redden": # lal panni return redden(image, amount) elif effect== "Greenify": # hari panni return greenify(image, amount) elif effect== "Bloom Blue": # nili panni return nili_panni(image, amount) elif effect== "HDR": return hdr(image, amount) elif effect== "Yellow": return yellow_panni(image, amount) def showFrame(self,frame): if type(frame)==type(None): self.label.setText(QCoreApplication.translate("MainWindow", u"<html><head/><body style=\"background-color:powderblue;\"><p align=\"center\">Your Image Here</p></body></html>", None)) return if self.listWidget.selectedItems()!=[]: effect=self.listWidget.selectedItems()[0].text() if effect!=self.current_effect: print("LOL") self.current_effect=effect clearTemp() temp=self.effectFuctions(effect,frame.copy(),self.horizontalSlider.value()) frame= temp if type(temp)!=type(None) else frame frame=cv2.cvtColor(frame,cv2.COLOR_BGR2RGB) image=qimage2ndarray.array2qimage(frame) self.label.setPixmap(QPixmap.fromImage(image)) pass def addImage(self): # self.image_stack=[None] filePath,_=QFileDialog.getOpenFileName(QMainWindow(), 'Open file') self.image_stack.append(cv2.imread(filePath)) pass def saveImage(self): #print("lol") filePath,_=QFileDialog.getSaveFileName(QMainWindow(),"Choose the save location") self.label.pixmap().save(filePath,"jpg",100) #self.cv2.imwrite(filePath,self.image_stack[-1]) #pass def commit(self): frame=self.image_stack[-1] if self.listWidget.selectedItems()==[]: return effect=self.listWidget.selectedItems()[0].text() temp=self.effectFuctions(effect,frame,self.horizontalSlider.value()) #frame= temp if type(temp)!=type(None) else None if type(frame)!=type(None): self.image_stack.append(temp) self.horizontalSlider.setValue(0) self.listWidget.setCurrentItem(None) def cancle(self): self.horizontalSlider.setValue(0) self.listWidget.setCurrentItem(None) def undo(self): if type(self.image_stack)!=type(None): self.image_stack.pop() def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName(u"MainWindow") MainWindow.resize(1131, 555) self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName(u"centralwidget") self.label = QLabel(self.centralwidget) self.label.setObjectName(u"label") self.label.setGeometry(QRect(10, 60, 781, 431)) self.label.setStyleSheet(u"background-color: rgb(85, 255, 255)") self.label.setScaledContents(True) self.listWidget = QListWidget(self.centralwidget) no_of_widgets=19 for i in range(no_of_widgets): QListWidgetItem(self.listWidget) self.listWidget.setObjectName(u"listWidget") self.listWidget.setGeometry(QRect(850, 160, 256, 201)) self.horizontalSlider = QSlider(self.centralwidget) self.horizontalSlider.setObjectName(u"horizontalSlider") self.horizontalSlider.setGeometry(QRect(870, 70, 211, 22)) self.horizontalSlider.setOrientation(Qt.Horizontal) #print(self.horizontalSlider.value()) self.label_2 = QLabel(self.centralwidget) self.label_2.setObjectName(u"label_2") self.label_2.setGeometry(QRect(930, 10, 101, 51)) self.label_2.setMinimumSize(QSize(0, 31)) self.label_2.setScaledContents(True) self.label_2.setWordWrap(True) self.label_2.setMargin(10) # ✅ commit button self.pushButton = QPushButton(self.centralwidget) self.pushButton.setObjectName(u"pushButton") self.pushButton.setGeometry(QRect(892, 110, 61, 28)) self.pushButton.clicked.connect(lambda : self.commit()) # ❌ cancle button self.pushButton_2 = QPushButton(self.centralwidget) self.pushButton_2.setObjectName(u"pushButton_2") self.pushButton_2.setGeometry(QRect(990, 110, 61, 28)) self.pushButton_2.clicked.connect(lambda : self.cancle()) # ↩️ Undo button self.pushButton_3 = QPushButton(self.centralwidget) self.pushButton_3.setObjectName(u"pushButton_3") self.pushButton_3.setGeometry(QRect(370, 20, 61, 28)) self.pushButton_3.clicked.connect(lambda : self.undo()) #crop self.pushButton_4 = QPushButton(self.centralwidget) self.pushButton_4.setObjectName(u"pushButton_4") self.pushButton_4.setGeometry(QRect(910, 380, 61, 28)) self.pushButton_4.clicked.connect(self.cropping) # Resize self.pushButton_5 = QPushButton(self.centralwidget) self.pushButton_5.setObjectName(u"pushButton_5") self.pushButton_5.setGeometry(QRect(980, 380, 61, 28)) self.pushButton_5.clicked.connect(self.resize) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(MainWindow) self.menubar.setObjectName(u"menubar") self.menubar.setGeometry(QRect(0, 0, 1131, 26)) self.menuNew_File = QMenu(self.menubar) self.menuNew_File.setObjectName(u"menuNew_File") #New File self.actionNew_File = QAction("NewFile") self.actionNew_File.triggered.connect(self.addImage) self.menuNew_File.addAction(self.actionNew_File) #Save File self.actionSave_File = QAction("SaveFile") self.actionSave_File.triggered.connect(self.saveImage) self.menuNew_File.addAction(self.actionSave_File) MainWindow.setMenuBar(self.menubar) self.statusbar = QStatusBar(MainWindow) self.statusbar.setObjectName(u"statusbar") self.timer=QTimer() self.timer.timeout.connect(lambda : self.showFrame(self.image_stack[-1]) ) self.timer.start(1) MainWindow.setStatusBar(self.statusbar) self.menubar.addAction(self.menuNew_File.menuAction()) #self.menubar.addAction(self.menuSave.menuAction()) self.retranslateUi(MainWindow) QMetaObject.connectSlotsByName(MainWindow) # setupUi def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None)) self.label.setText(QCoreApplication.translate("MainWindow", u"<html><head/><body style=\"background-color:powderblue;\"><p align=\"center\">Your Image Here</p></body></html>", None)) __sortingEnabled = self.listWidget.isSortingEnabled() self.listWidget.setSortingEnabled(False) ___qlistwidgetitem = self.listWidget.item(0) ___qlistwidgetitem.setText(QCoreApplication.translate("MainWindow", u"Brightness", None)); ___qlistwidgetitem1 = self.listWidget.item(1) ___qlistwidgetitem1.setText(QCoreApplication.translate("MainWindow", u"Saturation", None)); ___qlistwidgetitem2 = self.listWidget.item(2) ___qlistwidgetitem2.setText(QCoreApplication.translate("MainWindow", u"Sharpen", None)); ___qlistwidgetitem3 = self.listWidget.item(3) ___qlistwidgetitem3.setText(QCoreApplication.translate("MainWindow", u"Sepia Effect", None)); ___qlistwidgetitem4 = self.listWidget.item(4) ___qlistwidgetitem4.setText(QCoreApplication.translate("MainWindow", u"Warm", None)); ___qlistwidgetitem5 = self.listWidget.item(5) ___qlistwidgetitem5.setText(QCoreApplication.translate("MainWindow", u"Cold", None)); ___qlistwidgetitem6 = self.listWidget.item(6) ___qlistwidgetitem6.setText(QCoreApplication.translate("MainWindow", u"Equalize", None)); ___qlistwidgetitem7 = self.listWidget.item(7) ___qlistwidgetitem7.setText(QCoreApplication.translate("MainWindow", u"Cartoon", None)); ___qlistwidgetitem8 = self.listWidget.item(8) ___qlistwidgetitem8.setText(QCoreApplication.translate("MainWindow", u"Blurring", None)); ___qlistwidgetitem9 = self.listWidget.item(9) ___qlistwidgetitem9.setText(QCoreApplication.translate("MainWindow", u"Pencil Sketch", None)); ___qlistwidgetitem10 = self.listWidget.item(10) ___qlistwidgetitem10.setText(QCoreApplication.translate("MainWindow", u"Noise Reduction", None)); ___qlistwidgetitem11 = self.listWidget.item(11) ___qlistwidgetitem11.setText(QCoreApplication.translate("MainWindow", u"Negetive", None)); ___qlistwidgetitem12 = self.listWidget.item(12) ___qlistwidgetitem12.setText(QCoreApplication.translate("MainWindow", u"Vignette", None)); #"Redden" "Greenify" "Bloom Blue" "HDR" "Bass" ___qlistwidgetitem13 = self.listWidget.item(13) ___qlistwidgetitem13.setText(QCoreApplication.translate("MainWindow", u"Emboss", None)); ___qlistwidgetitem14 = self.listWidget.item(14) ___qlistwidgetitem14.setText(QCoreApplication.translate("MainWindow", u"Redden", None)); ___qlistwidgetitem15 = self.listWidget.item(15) ___qlistwidgetitem15.setText(QCoreApplication.translate("MainWindow", u"Greenify", None)); ___qlistwidgetitem16 = self.listWidget.item(16) ___qlistwidgetitem16.setText(QCoreApplication.translate("MainWindow", u"Bloom Blue", None)); ___qlistwidgetitem17 = self.listWidget.item(17) ___qlistwidgetitem17.setText(QCoreApplication.translate("MainWindow", u"HDR", None)); ___qlistwidgetitem18 = self.listWidget.item(18) ___qlistwidgetitem18.setText(QCoreApplication.translate("MainWindow", u"Yellow", None)); self.listWidget.setSortingEnabled(__sortingEnabled) self.label_2.setText(QCoreApplication.translate("MainWindow", u"<html><head/><body><p><span style=\" font-size:11pt;\">Amount%</span></p></body></html>", None)) self.pushButton.setText(QCoreApplication.translate("MainWindow", u"\u2705 ", None)) self.pushButton_2.setText(QCoreApplication.translate("MainWindow", u"\u274c", None)) self.pushButton_3.setText(QCoreApplication.translate("MainWindow", u"\u21a9\ufe0f", None)) self.pushButton_4.setText(QCoreApplication.translate("MainWindow", u"Crop", None)) self.pushButton_5.setText(QCoreApplication.translate("MainWindow", u"Resize", None)) self.menuNew_File.setTitle(QCoreApplication.translate("MainWindow", u"File", None))
class EditCommentBankWindow(QMainWindow): def __init__(self, subject_name): QMainWindow.__init__(self) self.setWindowTitle("Edit Comment Bank: {} - {} {}".format( subject_name, config.APP_NAME, config.APP_VERSION)) self.setMinimumWidth(1200) self.setStyleSheet(config.STYLESHEET) self.subject = could_try_harder.load(subject_name) self.saved_list = could_try_harder.get_saved_list() # Widgets self.intro_comment_label = QLabel("Introductory Comment:") self.intro_comment_label.setProperty("styleClass", "heading") self.intro_comment_textedit = QTextEdit() self.comment_bank_label = QLabel("Comment Bank") self.comment_bank_label.setProperty("styleClass", "heading") self.comment_bank_listwidget = QListWidget() self.placeholder_instructions_label = QLabel( config.PLACEHOLDER_INSTRUCTIONS) self.add_comment_label = QLabel("Add Comment:") self.add_comment_entry = QLineEdit() self.add_comment_button = QPushButton("Add") self.update_comment_label = QLabel("Update Comment:") self.update_comment_entry = QLineEdit() self.update_comment_button = QPushButton("Update") self.delete_comment_button = QPushButton("Delete Comment") self.import_comments_combo = QComboBox() self.import_comments_button = QPushButton("Import...") self.cancel_button = QPushButton("Cancel") self.save_button = QPushButton("Save") # Layout self.layout = QVBoxLayout() self.top_layout = QHBoxLayout() self.intro_comment_layout = QVBoxLayout() self.intro_comment_layout.addWidget(self.intro_comment_label) self.intro_comment_layout.addWidget(self.intro_comment_textedit) self.top_layout.addLayout(self.intro_comment_layout) self.top_layout.addWidget(self.placeholder_instructions_label) self.layout.addLayout(self.top_layout) self.middle_layout = QVBoxLayout() self.middle_layout.addWidget(self.comment_bank_label) self.middle_layout.addWidget(self.comment_bank_listwidget) self.comment_actions_layout = QHBoxLayout() self.comment_actions_layout.addWidget(self.delete_comment_button, 0, Qt.AlignLeft) self.comment_actions_layout.addWidget(self.import_comments_combo, 1, Qt.AlignRight) self.comment_actions_layout.addWidget(self.import_comments_button, 0, Qt.AlignRight) self.middle_layout.addLayout(self.comment_actions_layout) self.update_comment_layout = QGridLayout() self.update_comment_layout.addWidget(self.update_comment_label, 0, 0) self.update_comment_layout.addWidget(self.update_comment_entry, 0, 1) self.update_comment_layout.addWidget(self.update_comment_button, 0, 2) self.update_comment_layout.addWidget(self.add_comment_label, 1, 0) self.update_comment_layout.addWidget(self.add_comment_entry, 1, 1) self.update_comment_layout.addWidget(self.add_comment_button, 1, 2) self.middle_layout.addLayout(self.update_comment_layout) self.layout.addLayout(self.middle_layout) self.bottom_layout = QHBoxLayout() self.bottom_layout.addWidget(self.cancel_button, 0, Qt.AlignLeft) self.bottom_layout.addWidget(self.save_button, 0, Qt.AlignRight) self.layout.addLayout(self.bottom_layout) # Slot connections self.comment_bank_listwidget.itemSelectionChanged.connect( self.do_update_comment_bank_selection) self.import_comments_button.clicked.connect(self.do_import_comments) self.update_comment_button.clicked.connect(self.do_update_comment) self.update_comment_entry.returnPressed.connect(self.do_update_comment) self.add_comment_button.clicked.connect(self.do_add_comment) self.add_comment_entry.returnPressed.connect(self.do_add_comment) self.delete_comment_button.clicked.connect(self.do_delete_comment) self.cancel_button.clicked.connect(self.do_cancel) self.save_button.clicked.connect(self.do_save) # Initial UI update self.update_ui() self.widget = QWidget() self.widget.setLayout(self.layout) self.setCentralWidget(self.widget) def update_ui(self): self.update_import_comments_list() self.update_intro_comment() self.update_comment_bank() def update_import_comments_list(self): self.import_comments_combo.clear() self.import_comments_combo.insertItems(0, self.saved_list) def update_intro_comment(self): self.intro_comment_textedit.clear() self.intro_comment_textedit.insertPlainText( self.subject['intro_comment']) def update_comment_bank(self): self.comment_bank_listwidget.clear() self.comment_bank_listwidget.addItems(self.subject['comment_bank']) self.do_update_comment_bank_selection() @Slot() def do_import_comments(self): # TODO confirm dialog first confirm_msg = QMessageBox(self) confirm_msg.setWindowTitle("Confirm") confirm_msg.setText("This will override current comments.") confirm_msg.setInformativeText("Do you want to continue?") confirm_msg.setStandardButtons(QMessageBox.No | QMessageBox.Yes) confirm_msg.setDefaultButton(QMessageBox.Yes) confirm = confirm_msg.exec() if confirm == QMessageBox.Yes: if self.import_comments_combo.count() > 0: new_subject = could_try_harder.load( self.import_comments_combo.currentText()) if new_subject: self.subject['intro_comment'] = new_subject[ 'intro_comment'] self.subject['comment_bank'] = new_subject['comment_bank'] self.update_ui() else: # TODO better error handling here print('Tried to import empty subject.') return return @Slot() def do_update_comment_bank_selection(self): if self.comment_bank_listwidget.selectedItems(): state = True else: state = False self.delete_comment_button.setEnabled(state) self.update_comment_button.setEnabled(state) # Update the text in the update comment line edit self.update_comment_entry.clear() if self.comment_bank_listwidget.currentItem(): self.update_comment_entry.insert( self.comment_bank_listwidget.currentItem().text()) @Slot() def do_update_comment(self): if self.update_comment_entry.text(): self.comment_bank_listwidget.currentItem().setText( could_try_harder.do_style( self.update_comment_entry.text().strip())) self.do_update_comment_bank_selection() @Slot() def do_add_comment(self): if self.add_comment_entry.text(): self.comment_bank_listwidget.addItem( could_try_harder.do_style( self.add_comment_entry.text().strip())) self.add_comment_entry.clear() self.do_update_comment_bank_selection() @Slot() def do_delete_comment(self): self.comment_bank_listwidget.takeItem( self.comment_bank_listwidget.currentRow()) self.do_update_comment_bank_selection() @Slot() def do_cancel(self): self.close() @Slot() def do_save(self): self.subject['intro_comment'] = could_try_harder.do_style( self.intro_comment_textedit.toPlainText().strip()) self.subject['comment_bank'] = [] for i in range(self.comment_bank_listwidget.count()): self.subject['comment_bank'].append( self.comment_bank_listwidget.item(i).text()) if could_try_harder.save(self.subject): self.close() else: # TODO better error handling here print("Save failed.")
class FieldAttrsDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setLayout(QGridLayout()) self.setWindowTitle("Edit Attributes") self.list_widget = QListWidget() self.list_widget.setMinimumSize(800, 600) self.add_button = QPushButton("Add attr") self.add_button.clicked.connect(self.__add_attr) self.remove_button = QPushButton("Remove attr") self.remove_button.clicked.connect(self._remove_attrs) self.layout().addWidget(self.list_widget, 0, 0, 2, 1) self.layout().addWidget(self.add_button, 0, 1) self.layout().addWidget(self.remove_button, 1, 1) def fill_existing_attrs(self, existing_dataset: Dataset): for attr in existing_dataset.attributes: if attr.name not in ATTRS_EXCLUDELIST: frame = FieldAttrFrame(attr) self._add_attr(existing_frame=frame) def __add_attr(self): """ Only used for button presses. Any additional arguments from the signal are ignored. """ self._add_attr() def _add_attr(self, existing_frame=None): item = QListWidgetItem() self.list_widget.addItem(item) frame = existing_frame if existing_frame is not None else FieldAttrFrame( ) item.setSizeHint(frame.sizeHint()) self._setup_attribute_name_validator(frame) self.list_widget.setItemWidget(item, frame) def _remove_attrs(self): for index in self.list_widget.selectedIndexes(): self.list_widget.takeItem(index.row()) def get_attrs(self): attrs_list = [] for index in range(self.list_widget.count()): item = self.list_widget.item(index) widget = self.list_widget.itemWidget(item) if widget: attrs_list.append((widget.name, widget.value, widget.dtype)) return attrs_list def get_attr_names(self): return [item[0] for item in self.get_attrs()] def _setup_attribute_name_validator(self, frame): frame.attr_name_lineedit.setValidator( AttributeNameValidator(self.get_attr_names)) frame.attr_name_lineedit.validator().is_valid.connect( partial( validate_line_edit, frame.attr_name_lineedit, tooltip_on_accept="Attribute name is valid.", tooltip_on_reject="Attribute name is not valid", ))
class Ui_Dialog(object): final_image = None def __init__(self, image): super().__init__() self.image = image def showFrame(self): if len(self.listWidget.selectedItems()) > 0: self.imageWidget.selectedMode = self.listWidget.selectedItems( )[0].text() else: self.imageWidget.selectedMode = None image = cv2.cvtColor(self.imageWidget.tempImage, cv2.COLOR_BGR2RGB) image = qimage2ndarray.array2qimage(image) self.imageWidget.setPixmap(QPixmap.fromImage(image)) pass def commitCrop(self, Dialog): start = self.imageWidget.start end = self.imageWidget.current if start != end: print(start, end) #self.image=self.image[start[0]:end[0],start[1]:end[1]] self.image = self.image[start[1]:end[1], start[0]:end[0]] print(self.image.shape) Dialog.close() def cancle(self): #print("Lol") self.listWidget.setCurrentItem(None) self.imageWidget.tempImage = self.image def setupUi(self, Dialog): if not Dialog.objectName(): Dialog.setObjectName(u"Dialog") Dialog.resize(1104, 481) self.pushButton_2 = QPushButton(Dialog) self.pushButton_2.setObjectName(u"pushButton_2") self.pushButton_2.setGeometry(QRect(970, 90, 61, 28)) self.pushButton_2.clicked.connect(self.cancle) self.pushButton = QPushButton(Dialog) self.pushButton.setObjectName(u"pushButton") self.pushButton.setGeometry(QRect(880, 90, 61, 28)) self.pushButton.clicked.connect(lambda: self.commitCrop(Dialog)) self.listWidget = QListWidget(Dialog) QListWidgetItem(self.listWidget) QListWidgetItem(self.listWidget) QListWidgetItem(self.listWidget) QListWidgetItem(self.listWidget) QListWidgetItem(self.listWidget) QListWidgetItem(self.listWidget) QListWidgetItem(self.listWidget) self.listWidget.setObjectName(u"listWidget") self.listWidget.setGeometry(QRect(830, 150, 256, 192)) """ self.label = QLabel(Dialog) self.label.setObjectName(u"label") self.label.setGeometry(QRect(20, 20, 781, 431)) self.label.setStyleSheet(u"background-color: rgb(85, 255, 255)") self.label.setScaledContents(True) """ self.imageWidget = ImageLable(Dialog, self.image) self.timer = QTimer() self.timer.timeout.connect(self.showFrame) self.timer.start(1) self.retranslateUi(Dialog) QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): Dialog.setWindowTitle( QCoreApplication.translate("Dialog", u"Image Crop", None)) self.pushButton_2.setText( QCoreApplication.translate("Dialog", u"\u274c", None)) self.pushButton.setText( QCoreApplication.translate("Dialog", u"\u2705 ", None)) __sortingEnabled = self.listWidget.isSortingEnabled() self.listWidget.setSortingEnabled(False) ___qlistwidgetitem = self.listWidget.item(0) ___qlistwidgetitem.setText( QCoreApplication.translate("Dialog", u"Free", None)) ___qlistwidgetitem1 = self.listWidget.item(1) ___qlistwidgetitem1.setText( QCoreApplication.translate("Dialog", u"Square", None)) ___qlistwidgetitem2 = self.listWidget.item(2) ___qlistwidgetitem2.setText( QCoreApplication.translate("Dialog", u"3:2", None)) ___qlistwidgetitem3 = self.listWidget.item(3) ___qlistwidgetitem3.setText( QCoreApplication.translate("Dialog", u"4:3", None)) ___qlistwidgetitem4 = self.listWidget.item(4) ___qlistwidgetitem4.setText( QCoreApplication.translate("Dialog", u"5:4", None)) ___qlistwidgetitem5 = self.listWidget.item(5) ___qlistwidgetitem5.setText( QCoreApplication.translate("Dialog", u"7:5", None)) ___qlistwidgetitem6 = self.listWidget.item(6) ___qlistwidgetitem6.setText( QCoreApplication.translate("Dialog", u"16:9", None)) self.listWidget.setSortingEnabled(__sortingEnabled)
class _ViewSwitcherWidget(QWidget): """Object that handles displaying of Enigma model wikis and images""" def __init__(self, master, regen_plug): """ :param master: Qt parent object :param regen_plug: {callable} Regenerates settings view to new contents """ super().__init__(master) layout = QHBoxLayout() self.setLayout(layout) # LIST OF AVAILABLE MODELS ============================================= self.model_list = QListWidget() self.model_list.setMaximumWidth(150) self.model_list.setMinimumWidth(150) self.model_list.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.model_list.currentRowChanged.connect(self.select_model) self.regen_plug = regen_plug # STACKED MODEL VIEWS ================================================== self.stacked_wikis = QStackedWidget() for i, model in enumerate(VIEW_DATA): self.model_list.insertItem(i, model) description = VIEW_DATA[model]["description"] self.stacked_wikis.addWidget( _EnigmaViewWidget(self, model, description)) self.total_models = len(VIEW_DATA) layout.addWidget(self.model_list) layout.addWidget(self.stacked_wikis) # Sets initially viewed self.currently_selected = None def select_model(self, i): """Called when the "Use this model" button is pressed :param i: {str} Newly selected model index """ logging.info('Changing settings view to model "%s"' % list(VIEW_DATA.keys())[i]) model = list(VIEW_DATA.keys())[i] self.regen_plug(model) self.stacked_wikis.setCurrentIndex(i) self.model_list.blockSignals(True) self.model_list.setCurrentRow(i) self.model_list.blockSignals(False) self.currently_selected = model def highlight(self, i): """Highlights an option with Blue color, indicating that it is currently selected in EnigmaAPI :param i: {int} Index from list options """ for index in range(self.total_models): item = self.model_list.item(index) item.setForeground(Qt.black) item.setToolTip(None) selected = self.model_list.item(i) selected.setBackground(Qt.gray) # .setForeground(Qt.blue) selected.setToolTip("Currently used Enigma model")
class Widget(QWidget): def __init__(self): QWidget.__init__(self) # Data for plotting and marker data storage self.data = {} self.slice_index = { 'ind1': 0, 'ind2': 0 } self.marker_id = 0 self.marker_ind = [] self.marker_setpoint = { 'Marker1': 0, 'Marker2': 0, } # Error message dialog widget self.error_popup = QErrorMessage() self.error_popup.setWindowTitle('Snap file error') # Left (List of Checkboxes) self.list_widget = QListWidget() #Resize width and height self.list_widget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.list_widget.setMinimumWidth(200) self.list_widget.setMaximumWidth(400) # self.list_widget.setMinimumHeight(300) self.list_widget.setMaximumHeight(500) # Signal groupbox self.signal_groupbox = QGroupBox('Available Signals') self.signal_groupbox.setMinimumWidth(200) self.signal_groupbox.setMaximumWidth(350) self.signal_groupbox.setMinimumHeight(100) self.sig_group_layout = QVBoxLayout() self.signal_groupbox.setLayout(self.sig_group_layout) # Statistics groupbox self.stats_groupbox = QGroupBox('Statistics') self.stats_groupbox.setMinimumWidth(200) self.stats_groupbox.setMaximumWidth(350) self.stats_groupbox.setMinimumHeight(240) self.stats_group_layout = QFormLayout() # Label initiation # Marker Time 1 self.mark_one_time_label = QLabel('Marker1_time: ') self.mark_one_time_value = QLabel() # Marker Time 2 self.mark_two_time_label = QLabel('Marker2_time: ') self.mark_two_time_value = QLabel() # On/Off labels for 0/1 signals counter self.on_off_label = QLabel('On/Off: ') self.on_off_value = QLabel() # Mean value self.mean_label = QLabel('Mean: ') self.mean_value = QLabel() # Standard deviation self.std_label = QLabel('Sigma(STD): ') self.std_value = QLabel() # Minimal value self.min_label = QLabel('Min: ') self.min_value = QLabel() # Maximual value self.max_label = QLabel('Max: ') self.max_value = QLabel() # Max - Min value self.val_diff_label = QLabel('Max-Min: ') self.val_diff_value = QLabel() # Time difference (X-axis) self.time_diff_label = QLabel('Time_diff: ') self.time_diff_value = QLabel('') # Row addition of labels self.stats_group_layout.addRow(self.mark_one_time_label, self.mark_one_time_value) self.stats_group_layout.addRow(self.mark_two_time_label, self.mark_two_time_value) self.stats_group_layout.addRow(self.time_diff_label, self.time_diff_value) self.stats_group_layout.addRow(self.on_off_label, self.on_off_value) self.stats_group_layout.addRow(self.mean_label, self.mean_value) self.stats_group_layout.addRow(self.std_label, self.std_value) self.stats_group_layout.addRow(self.min_label, self.min_value) self.stats_group_layout.addRow(self.max_label, self.max_value) self.stats_group_layout.addRow(self.val_diff_label, self.val_diff_value) self.stats_groupbox.setLayout(self.stats_group_layout) # Set markers section of the application (bottom left) self.marker_grid = QGridLayout() self.marker_one_notice = QLabel() self.marker_two_notice = QLabel() self.set_marker_one_label = QLabel('Set Marker1:') self.set_marker_two_label = QLabel('Set Marker2:') self.set_marker_one_value = QLineEdit() self.set_marker_one_value.setMaximumWidth(100) self.set_marker_two_value = QLineEdit() self.set_marker_two_value.setMaximumWidth(100) self.marker_grid.addWidget(self.set_marker_one_label) self.marker_grid.addWidget(self.set_marker_one_value) self.marker_grid.addWidget(self.marker_one_notice) self.marker_grid.addWidget(self.set_marker_two_label) self.marker_grid.addWidget(self.set_marker_two_value) self.marker_grid.addWidget(self.marker_two_notice) # Leftside app layout self.v_layout = QVBoxLayout() self.v_layout.addWidget(self.list_widget) self.v_layout.addWidget(self.signal_groupbox) self.v_layout.addWidget(self.stats_groupbox) self.v_layout.addLayout(self.marker_grid) # Matplotlib figure self.fig = Figure(figsize=(5, 3)) self.canvas = FigureCanvas(self.fig) self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.ax = self.canvas.figure.subplots() self.ax.grid() self.ax.set_xlabel('Time[s]') self.fig.suptitle('Parameter Plot') # QWidget Layout self.h_layout = QHBoxLayout() self.h_layout.addLayout(self.v_layout) self.h_layout.addWidget(self.canvas) # Set the layout to the QWidget self.setLayout(self.h_layout) # ListWidget and plot connections self.list_widget.itemChanged.connect(self.item_changed) self.click_event = self.fig.canvas.mpl_connect('button_press_event', self.on_click) self.set_marker_one_value.returnPressed.connect( lambda: self.add_marker('one')) self.set_marker_two_value.returnPressed.connect( lambda: self.add_marker('two')) # Add radio button when signal is checked for plotting def add_radio_button(self, name): self.rad_btn = QRadioButton(name) self.rad_btn.toggled.connect(self.calculate_signal_stats) self.sig_group_layout.addWidget(self.rad_btn) # Remove radio button when signal is unchecked for plotting def remove_radio_button(self, name): for item in self.signal_groupbox.children(): try: if item.text() == name: item.setParent(None) except AttributeError: pass # Remove all radiobuttons on new data load def clear_signals(self): count = 0 for item in self.signal_groupbox.children(): if count == 0: count = 1 continue else: item.setParent(None) # Check state of all radiobuttons, if none is checked remove stats values def check_signals(self): count = 0 num_of_check = 0 for item in self.signal_groupbox.children(): if count == 0: count = 1 continue else: if item.isChecked(): num_of_check += 1 # If no radiobuttons are checked, remove stats if num_of_check == 0: self.mean_value.setText('') self.std_value.setText('') self.max_value.setText('') self.min_value.setText('') self.val_diff_value.setText('') self.on_off_value.setText('') # Item additon of listWidget def fill_list(self, list_items): self.list_widget.clear() for column in list_items: item = QListWidgetItem(column) item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) item.setCheckState(Qt.Unchecked) self.list_widget.addItem(item) self.show() # If new data is loaded, replace the old one def replace_data(self, temp): if not temp == self.data: self.data = temp self.clear_signals() @Slot() # Item state changed in listWidget event handler def item_changed(self, item): if item.checkState() == Qt.Unchecked: self.remove_plot(item.text()) self.remove_radio_button(item.text()) self.check_signals() else: self.add_plot(self.data['Time'], self.data[item.text()], item.text()) self.add_radio_button(item.text()) # Method for plotting data def add_plot(self, x_data, y_data, name): self.ax.plot(x_data, y_data, label=name, picker=3) self.ax.grid(True) self.ax.relim() self.ax.set_xlabel('Time[s]') self.ax.autoscale_view() self.ax.legend(loc='upper right') self.canvas.draw() # Method for marker addition via QLineEdit def add_marker(self, label): # Check if any signal is plotted sig_count = 0 for i in range(self.list_widget.count()): if self.list_widget.item(i).checkState() == Qt.Checked: sig_count += 1 if sig_count == 0: self.marker_one_notice.setText('No active signal!') self.marker_two_notice.setText('No active signal!') return try: max_time = self.data['Time'][-1] min_time = self.data['Time'][0] except KeyError: self.marker_one_notice.setText('Signal data not loaded!') self.marker_two_notice.setText('Signal data not loaded!') if label == 'one': try: mark1_value = float(self.set_marker_one_value.text()) if mark1_value < max_time and mark1_value > min_time: if self.marker_id == 0: self.marker_id += 1 label_id = self.marker_id elif self.marker_id == 1: self.marker_id += 1 label_id = self.marker_id self.remove_marker('first') else: self.remove_marker('first') label_id = 1 self.marker_one_notice.setText('') self.marker_setpoint['Marker1'] = mark1_value self.mark_one_time_value.setText( self.set_marker_one_value.text()) self.calculate_marker_stats() self.calculate_signal_stats() # Draw the marker L = self.ax.axvline( x=float(self.set_marker_one_value.text()), linestyle='dashed', color='red', label='_Marker' + str(label_id)) self.fig.canvas.draw() else: self.marker_one_notice.setText('Marker1 out of bounds') except ValueError: self.marker_one_notice.setText('Non-Valid value entered!') else: try: mark2_value = float(self.set_marker_two_value.text()) if mark2_value < max_time and mark2_value > min_time: if self.marker_id == 1: self.marker_id += 1 label_id = self.marker_id elif self.marker_id == 2: label_id = 2 self.remove_marker('second') else: self.marker_two_notice.setText('Marker1 not placed') self.marker_two_notice.setText('') self.marker_setpoint['Marker2'] = mark2_value self.mark_two_time_value.setText( self.set_marker_two_value.text()) self.calculate_marker_stats() self.calculate_signal_stats() # Draw the marker L = self.ax.axvline( x=float(self.set_marker_two_value.text()), linestyle='dashed', color='red', label='_Marker' + str(label_id)) self.fig.canvas.draw() else: self.marker_two_notice.setText('Marker2 out of bounds') except: self.marker_two_notice.setText('Non-Valid value entered!') # Marker removal method def remove_marker(self, label): for item in self.ax.lines: if 'Marker' in item.get_label(): self.marker_ind.append(item) # If there are two markers remove them from plot and adjust marker # time labels if label == 'both': self.marker_ind[0].remove() self.marker_ind[1].remove() self.marker_ind = [] self.marker_setpoint['Marker1'] = 0 self.marker_setpoint['Marker2'] = 0 self.mark_one_time_value.setText('') self.mark_two_time_value.setText('') self.time_diff_value.setText('') self.marker_id = 0 # Remove only marker1 elif label == 'first': self.marker_ind[0].remove() self.marker_ind = [] self.marker_setpoint['Marker1'] = 0 self.mark_one_time_value.setText('') self.marker_id -= 1 elif label == 'second': self.marker_ind[1].remove() self.marker_ind = [] self.marker_setpoint['Marker2'] = 0 self.mark_two_time_value.setText('') self.marker_id -= 1 self.ax.set_xlabel('Time[s]') self.canvas.draw() # Method for plot removal def remove_plot(self, name): cnt = 0 for item in self.ax.lines: if item.get_label() == name: self.ax.lines[cnt].remove() cnt += 1 self.ax.relim() self.ax.autoscale_view() self.ax.legend(loc='upper right') self.ax.set_xlabel('Time[s]') self.canvas.draw() # Check if all elements are unticked counter = 0 for i in range(self.list_widget.count()): if self.list_widget.item(i).checkState() == Qt.Checked: counter +=1 if counter == 0: self.remove_marker('both') # On click event for plot, only two markers can be active at the time def on_click(self, event): try: # Catch left click event if event.button == 1: x = event.xdata if self.marker_id < 2: if self.marker_id == 0: self.marker_setpoint['Marker1'] = round(x) self.mark_one_time_value.setText( str(self.marker_setpoint['Marker1'])) self.calculate_marker_stats() self.calculate_signal_stats() else: self.marker_setpoint['Marker2'] = round(x) self.mark_two_time_value.setText( str(self.marker_setpoint['Marker2'])) self.calculate_marker_stats() self.calculate_signal_stats() self.marker_id += 1 L = self.ax.axvline(x=x, linestyle='dashed', color='red', label='_Marker' + str(self.marker_id)) self.fig.canvas.draw() # Catch right click event elif event.button == 3: self.remove_marker('both') except TypeError: pass # Marker analysis method def calculate_marker_stats(self): if self.marker_setpoint['Marker2'] == 0: diff = self.data['Time'][-1] - self.marker_setpoint['Marker1'] self.time_diff_value.setText(str(diff)) else: diff = self.marker_setpoint['Marker2'] - \ self.marker_setpoint['Marker1'] self.time_diff_value.setText(convert_seconds(diff)) # Signal analysis method def calculate_signal_stats(self): self.check_signals() selected_signal = '' signal_data = [] num_off, num_on = 0, 0 for item in self.signal_groupbox.children(): try: if item.isChecked(): # Signal extraction block selected_signal = item.text() # If only one marker, Marker1 is placed on graph if self.marker_setpoint['Marker2'] == 0 and self.marker_setpoint['Marker1'] != 0: for i in range(len(self.data['Time'])): if self.data['Time'][i] > self.marker_setpoint['Marker1']: self.slice_index['ind1'] = i break signal_data = np.asarray( self.data[selected_signal][self.slice_index['ind1']:], dtype=np.float32) # Both markers, Marker1 and Marker2 are present on graph elif self.marker_setpoint['Marker1'] != 0 and self.marker_setpoint['Marker2'] != 0: for i in range(len(self.data['Time'])): if self.data['Time'][i] > self.marker_setpoint['Marker1']: self.slice_index['ind1'] = i break for i in range(len(self.data['Time'])): if self.data['Time'][len(self.data['Time']) - i - 1] < self.marker_setpoint['Marker2']: self.slice_index['ind2'] = len(self.data['Time']) - i break signal_data = np.asarray( self.data[selected_signal][self.slice_index['ind1']:self.slice_index['ind2'] - 1], dtype=np.float32) # No markers present, whole signal stats are showed else: signal_data = np.asarray(self.data[selected_signal], dtype=np.float32) try: # Signal mean calculation self.mean_value.setText(str(np.mean(signal_data))) # Standard deviation self.std_value.setText(str(np.std(signal_data))) # Maximum value self.max_value.setText(str(np.max(signal_data))) # Minimum value self.min_value.setText(str(np.min(signal_data))) # Max - Min self.val_diff_value.setText(str(np.max(signal_data) - (np.min(signal_data)))) if np.max(signal_data) == 1.0: for i in range(len(signal_data)): if i != len(signal_data) - 1: temp = signal_data[i] - signal_data[i+1] if temp == 1: num_off += 1 elif temp == -1: num_on += 1 self.on_off_value.setText(str(num_on) + '\\' + str(num_off)) except ValueError: err_line1 = 'Missing data, result is empty array!' err_line2 = '\n Please check snap file.' self.error_popup.showMessage(err_line1 + err_line2) except AttributeError: pass
class VODCutter(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.twitch_client_id = config.TWITCH_API_CLIENT_ID self.twitch_oauth_token = config.TWITCH_API_OAUTH_TOKEN self.twitch_interface = TwitchInterface( api_client_id=config.TWITCH_API_CLIENT_ID, api_oauth_token=config.TWITCH_API_OAUTH_TOKEN, browser_client_id=config.TWITCH_BROWSER_OAUTH_TOKEN, browser_oauth_token=config.TWITCH_BROWSER_OAUTH_TOKEN) self.vlc_interface = VLCInterface(config.VLC_PATH) self.loaded_video = None self.main_layout = QVBoxLayout() self.launch_vlc_btn = QPushButton("Launch VLC") self.info_layout = QGridLayout() self.file_picker_layout = QHBoxLayout() self.file_path_field = QLineEdit() self.file_browser_btn = QPushButton(text="...") self.file_picker_layout.addWidget(self.file_path_field) self.file_picker_layout.addWidget(self.file_browser_btn) vod_filepath_label = QLabel("VOD Filepath") id_twitch_label = QLabel("ID Twitch") created_at_label = QLabel("Created at") duration_label = QLabel("Duration") title_label = QLabel("Title") streamer_label = QLabel("Streamer") self.id_twitch_field = QLineEdit() self.created_at_field = QLineEdit() self.duration_field = QLineEdit() self.title_field = QLineEdit() self.streamer_field = QLineEdit() self.id_twitch_field.setEnabled(False) self.created_at_field.setEnabled(False) self.duration_field.setEnabled(False) self.title_field.setEnabled(False) self.streamer_field.setEnabled(False) self.info_layout.addWidget(vod_filepath_label, 0, 0) self.info_layout.addWidget(id_twitch_label, 1, 0) self.info_layout.addWidget(created_at_label, 2, 0) self.info_layout.addWidget(duration_label, 3, 0) self.info_layout.addWidget(title_label, 4, 0) self.info_layout.addWidget(streamer_label, 5, 0) self.info_layout.addLayout(self.file_picker_layout, 0, 1) self.info_layout.addWidget(self.id_twitch_field, 1, 1) self.info_layout.addWidget(self.created_at_field, 2, 1) self.info_layout.addWidget(self.duration_field, 3, 1) self.info_layout.addWidget(self.title_field, 4, 1) self.info_layout.addWidget(self.streamer_field, 5, 1) self.segments_create_btn = QPushButton("Import Chapters") self.download_thumbnails_btn = QPushButton("Download Thumbnails") self.download_chatlog_btn = QPushButton("Download Chat Log") self.segments_list = QListWidget() self.segments_add_btn = QPushButton(text="+") self.segments_delete_btn = QPushButton(text="-") self.jump_start_btn = QPushButton(text="Jump To Start") self.jump_end_btn = QPushButton(text="Jump To End") self.set_start_btn = QPushButton(text="Set Start") self.set_end_btn = QPushButton(text="Set End") self.split_btn = QPushButton(text="Split") self.process_selected_btn = QPushButton( text="Process Selected Segment") self.process_all_btn = QPushButton(text="Process All Segments") self.jump_layout = QHBoxLayout() self.jump_layout.addWidget(self.jump_start_btn) self.jump_layout.addWidget(self.jump_end_btn) self.set_layout = QHBoxLayout() self.set_layout.addWidget(self.set_start_btn) self.set_layout.addWidget(self.set_end_btn) self.main_layout.addWidget(self.launch_vlc_btn) self.main_layout.addLayout(self.file_picker_layout) self.main_layout.addLayout(self.info_layout) self.main_layout.addWidget(self.segments_create_btn) self.main_layout.addWidget(self.download_thumbnails_btn) self.main_layout.addWidget(self.download_chatlog_btn) self.main_layout.addWidget(self.segments_list) self.main_layout.addWidget(self.segments_add_btn) self.main_layout.addWidget(self.segments_delete_btn) self.main_layout.addLayout(self.jump_layout) self.main_layout.addLayout(self.set_layout) self.main_layout.addWidget(self.split_btn) self.main_layout.addWidget(self.process_selected_btn) self.main_layout.addWidget(self.process_all_btn) self.main_widget = QWidget() self.main_widget.setLayout(self.main_layout) self.setCentralWidget(self.main_widget) self.segments_list.itemDoubleClicked.connect( self.on_segments_list_doubleclick) self.jump_start_btn.clicked.connect(self.jump_to_segment_start) self.jump_end_btn.clicked.connect(self.jump_to_segment_end) self.set_start_btn.clicked.connect(self.set_segment_start) self.set_end_btn.clicked.connect(self.set_segment_end) self.download_thumbnails_btn.clicked.connect(self.download_thumbnails) self.segments_add_btn.clicked.connect(self.create_segment) self.segments_delete_btn.clicked.connect(self.delete_segment) self.split_btn.clicked.connect(self.split_selected_segment) self.launch_vlc_btn.clicked.connect(self.on_launch_vlc) self.file_path_field.returnPressed.connect(self.on_video_url_changed) self.file_browser_btn.clicked.connect(self.on_filebrowse_btn_click) self.process_selected_btn.clicked.connect( self.process_selected_segment) self.process_all_btn.clicked.connect(self.process_all_segments) def on_launch_vlc(self): self.vlc_interface.launch() def on_filebrowse_btn_click(self): filename = QFileDialog.getOpenFileName(self, "Select a video file") if filename[0]: self.set_video_file(filename[0]) def on_video_url_changed(self): self.set_video_file(self.file_path_field.text()) def on_segments_list_doubleclick(self, item): current_segment = item.get_segment() if current_segment: self.vlc_interface.set_current_time(int( current_segment.start_time)) def set_video_file(self, filepath=None): self.file_path_field.setText("" if filepath is None else filepath) if filepath: self.loaded_video = InputVideo() if re.search(r"^(?:/|[a-z]:[\\/])", filepath, re.I): file_url = "file://" + filepath self.loaded_video.is_local = True else: file_url = filepath if not self.loaded_video.is_local: streams = streamlink.streams(file_url) if streams: self.loaded_video.filepath = streams["best"].url else: self.loaded_video.filepath = file_url else: self.loaded_video.filepath = file_url try: self.update_twitch_metadatas() except requests.exceptions.ConnectionError: print("<!!> Can't connect to Twitch API.") try: self.vlc_interface.open_url(self.loaded_video.filepath) except requests.exceptions.ConnectionError: print("<!!> Can't connect to local VLC instance.") def get_twitch_id_from_filepath(self): filename = self.file_path_field.text() parsed_filename = re.search("([0-9]+)\.mp4$", filename, re.I) if parsed_filename: video_id = parsed_filename.group(1) return int(video_id) else: parsed_url = re.search("videos/([0-9]+)", filename, re.I) if parsed_url: video_id = parsed_url.group(1) return int(video_id) else: raise Exception( f"<!!> Can't find video Twitch id in video filename ({filename})" ) def create_segment_before(self, segment_obj): pass def create_segment_after(self, segment_obj): pass def update_twitch_metadatas(self): twitch_video_id = self.get_twitch_id_from_filepath() metadatas = self.twitch_interface.get_twitch_metadatas(twitch_video_id) self.loaded_video.metadatas = metadatas duration = parse_duration(metadatas["duration"]) self.id_twitch_field.setText(metadatas["id"]) self.created_at_field.setText(str(metadatas["created_at"])) self.duration_field.setText(format_time(duration.seconds)) self.title_field.setText(metadatas["title"]) self.streamer_field.setText(metadatas["user_login"]) for moment in self.twitch_interface.get_video_games_list( metadatas["id"]): s = Segment() s.name = f"{moment['description']} ({moment['type']})" s.start_time = moment['positionMilliseconds'] / 1000 s.end_time = (moment['positionMilliseconds'] + moment['durationMilliseconds']) / 1000 self.segments_list.addItem(SegmentListItem(s)) def create_segment(self): s = Segment() s.name = f"Segment {self.segments_list.count()}" s.start_time = 0 s.end_time = self.vlc_interface.get_duration() self.segments_list.addItem(SegmentListItem(s)) def delete_segment(self): for item in self.segments_list.selectedItems(): idx = self.segments_list.indexFromItem(item) item = self.segments_list.takeItem(idx.row()) del item def split_selected_segment(self): current_time = self.vlc_interface.get_current_time() for segment_item in self.segments_list.selectedItems(): current_segment = segment_item.get_segment() if current_segment: new_segment = segment_item.split( current_time, name="Splitted " + current_segment.name, split_mode=SPLIT_MODE.ABSOLUTE) self.segments_list.addItem(SegmentListItem(new_segment)) def get_selected_segments(self): return list( map(lambda item: item.get_segment(), self.segments_list.selectedItems())) def jump_to_segment_start(self): selected_segments = self.get_selected_segments() if selected_segments: self.vlc_interface.set_current_time( math.floor(selected_segments[0].start_time)) def jump_to_segment_end(self): selected_segments = self.get_selected_segments() if selected_segments: self.vlc_interface.set_current_time( math.floor(selected_segments[0].end_time)) def set_segment_start(self): current_time = self.vlc_interface.get_current_time() selected_segments = self.segments_list.selectedItems() if selected_segments: selected_segments[0].get_segment().start_time = current_time selected_segments[0].update() def set_segment_end(self): current_time = self.vlc_interface.get_current_time() selected_segments = self.segments_list.selectedItems() if selected_segments: selected_segments[0].get_segment().end_time = current_time selected_segments[0].update() def process_selected_segment(self): for segment in self.get_selected_segments(): self.process_segment(segment) def process_all_segments(self): for idx in range(self.segments_list.count()): segment_item = self.segments_list.item(idx) self.process_segment(segment_item.get_segment()) def process_segment(self, segment_obj): if not self.loaded_video: raise Exception("<!!> No video loaded") video_id = self.loaded_video.metadatas.get("id", None) created_at = self.loaded_video.metadatas.get("created_at", None) user_login = self.loaded_video.metadatas.get("user_login", None) if not (video_id and created_at and user_login): raise Exception("<!!> Missing video metadatas") created_at_timestamp = int(datetime.datetime.timestamp(created_at)) if self.loaded_video.is_local: cmd = f'ffmpeg -i "{self.loaded_video.filepath}" -ss {segment_obj.start_time} -to {segment_obj.end_time} -c:v copy -c:a copy "{user_login}_{created_at_timestamp}_{video_id}.mp4"' else: cmd = f'streamlink -f --hls-start-offset {format_time(segment_obj.start_time)} --hls-duration {format_time(segment_obj.end_time - segment_obj.start_time)} --player-passthrough hls "{self.loaded_video.filepath}" best -o "{user_login}_{created_at_timestamp}_{video_id}.mp4"' print(cmd) os.system(cmd) def download_thumbnails(self): twitch_video_id_str = self.id_twitch_field.text() if twitch_video_id_str: thumbnails_manifest_url = self.twitch_interface.get_video_thumbnails_manifest_url( int(twitch_video_id_str)) thumbnails_manifest, images_url_list = self.twitch_interface.get_thumbnails_url_from_manifest( thumbnails_manifest_url) for img in images_url_list: r = requests.get(images_url_list[img]) fp = open(img, "wb") fp.write(r.content) fp.close()
class PiecesPlayer(QWidget): """ main widget of application (used as widget inside PiecesMainWindow) """ def __init__(self, parent): """ standard constructor: set up class variables, ui elements and layout """ # TODO: split current piece info into separate lineedits for title, album name and length # TODO: make time changeable by clicking next to the slider (not only # by dragging the slider) # TODO: add "about" action to open info dialog in new "help" menu # TODO: add option to loop current piece (?) # TODO: more documentation # TODO: add some "whole piece time remaining" indicator? (complicated) # TODO: implement a playlist of pieces that can be edited and enable # going back to the previous piece (also un- and re-shuffling?) # TODO: implement debug dialog as menu action (if needed) if not isinstance(parent, PiecesMainWindow): raise ValueError('Parent widget must be a PiecesMainWindow') super(PiecesPlayer, self).__init__(parent=parent) # -- declare and setup variables for storing information -- # various data self._set_str = '' # string of currently loaded directory sets self._pieces = {} # {<piece1>: [<files piece1 consists of>], ...} self._playlist = [] # list of keys of self._pieces (determines order) self._shuffled = True # needed for (maybe) reshuffling when looping # doc for self._history: # key: timestamp ('HH:MM:SS'), # value: info_str of piece that started playing at that time self._history = {} self._status = 'Paused' self._current_piece = {'title': '', 'files': [], 'play_next': 0} self._default_volume = 60 # in percent from 0 - 100 self._volume_before_muted = self._default_volume # set to true by self.__event_movement_ended and used by self.__update self._skip_to_next = False # vlc-related variables self._vlc_instance = VLCInstance() self._vlc_mediaplayer = self._vlc_instance.media_player_new() self._vlc_mediaplayer.audio_set_volume(self._default_volume) self._vlc_medium = None self._vlc_events = self._vlc_mediaplayer.event_manager() # -- create and setup ui elements -- # buttons self._btn_play_pause = QPushButton(QIcon(get_icon_path('play')), '') self._btn_previous = QPushButton(QIcon(get_icon_path('previous')), '') self._btn_next = QPushButton(QIcon(get_icon_path('next')), '') self._btn_volume = QPushButton(QIcon(get_icon_path('volume-high')), '') self._btn_loop = QPushButton(QIcon(get_icon_path('loop')), '') self._btn_loop.setCheckable(True) self._btn_play_pause.clicked.connect(self.__action_play_pause) self._btn_previous.clicked.connect(self.__action_previous) self._btn_next.clicked.connect(self.__action_next) self._btn_volume.clicked.connect(self.__action_volume_clicked) # labels self._lbl_current_piece = QLabel('Current piece:') self._lbl_movements = QLabel('Movements:') self._lbl_time_played = QLabel('00:00') self._lbl_time_left = QLabel('-00:00') self._lbl_volume = QLabel('100%') # needed so that everything has the same position # independent of the number of digits of volume self._lbl_volume.setMinimumWidth(55) # sliders self._slider_time = QSlider(Qt.Horizontal) self._slider_volume = QSlider(Qt.Horizontal) self._slider_time.sliderReleased.connect( self.__event_time_changed_by_user) self._slider_volume.valueChanged.connect(self.__event_volume_changed) self._slider_time.setRange(0, 100) self._slider_volume.setRange(0, 100) self._slider_volume.setValue(self._default_volume) self._slider_volume.setMinimumWidth(100) # other elements self._checkbox_loop_playlist = QCheckBox('Loop playlist') self._lineedit_current_piece = QLineEdit() self._lineedit_current_piece.setReadOnly(True) self._lineedit_current_piece.textChanged.connect( self.__event_piece_text_changed) self._listwidget_movements = QListWidget() self._listwidget_movements.itemClicked.connect( self.__event_movement_selected) # -- create layout and insert ui elements-- self._layout = QVBoxLayout(self) # row 0 (name of current piece) self._layout_piece_name = QHBoxLayout() self._layout_piece_name.addWidget(self._lbl_current_piece) self._layout_piece_name.addWidget(self._lineedit_current_piece) self._layout.addLayout(self._layout_piece_name) # rows 1 - 5 (movements of current piece) self._layout.addWidget(self._lbl_movements) self._layout.addWidget(self._listwidget_movements) # row 6 (time) self._layout_time = QHBoxLayout() self._layout_time.addWidget(self._lbl_time_played) self._layout_time.addWidget(self._slider_time) self._layout_time.addWidget(self._lbl_time_left) self._layout.addLayout(self._layout_time) # row 7 (buttons and volume) self._layout_buttons_and_volume = QHBoxLayout() self._layout_buttons_and_volume.addWidget(self._btn_play_pause) self._layout_buttons_and_volume.addWidget(self._btn_previous) self._layout_buttons_and_volume.addWidget(self._btn_next) self._layout_buttons_and_volume.addWidget(self._btn_loop) self._layout_buttons_and_volume.addSpacing(40) # distance between loop and volume buttons: min. 40, but stretchable self._layout_buttons_and_volume.addStretch() self._layout_buttons_and_volume.addWidget(self._btn_volume) self._layout_buttons_and_volume.addWidget(self._slider_volume) self._layout_buttons_and_volume.addWidget(self._lbl_volume) self._layout.addLayout(self._layout_buttons_and_volume) # -- setup hotkeys -- self._KEY_CODES_PLAY_PAUSE = [269025044] self._KEY_CODES_NEXT = [269025047] self._KEY_CODES_PREVIOUS = [269025046] self._keyboard_listener = keyboard.Listener(on_press=self.__on_press) self._keyboard_listener.start() QShortcut(QKeySequence('Space'), self, self.__action_play_pause) # -- various setup -- self._timer = QTimer(self) self._timer.timeout.connect(self.__update) self._timer.start(100) # update every 100ms self.setMinimumWidth(900) self.setMinimumHeight(400) # get directory set(s) input and set up self._pieces # (exec_ means we'll wait for the user input before continuing) DirectorySetChooseDialog(self, self.set_pieces_and_playlist).exec_() # skip to next movement / next piece when current one has ended self._vlc_events.event_attach(VLCEventType.MediaPlayerEndReached, self.__event_movement_ended) def __action_next(self): """ switches to next file in self._current_piece['files'] or to the next piece, if the current piece has ended """ reset_pause_after_current = False # current movement is last of the current piece if self._current_piece['play_next'] == -1: if len(self._playlist) == 0: # reached end of playlist if self._btn_loop.isChecked(): self._playlist = list(self._pieces.keys()) if self._shuffled: shuffle(self._playlist) return if self._status == 'Playing': self.__action_play_pause() self._current_piece['title'] = '' self._current_piece['files'] = [] self._current_piece['play_next'] = -1 self._lineedit_current_piece.setText('') self.__update_movement_list() self.parentWidget().update_status_bar( self._status, 'End of playlist reached.') return else: if self.parentWidget().get_exit_after_current(): self.parentWidget().exit() if self.parentWidget().get_pause_after_current(): self.__action_play_pause() reset_pause_after_current = True # reset of the menu action will be at the end of this # function, or else we won't stay paused self._current_piece['title'] = self._playlist.pop(0) self._current_piece['files'] = [ p[1:-1] for p in self._pieces[self._current_piece['title']] ] # some pieces only have one movement self._current_piece['play_next'] = \ 1 if len(self._current_piece['files']) > 1 else -1 self.__update_vlc_medium(0) self._lineedit_current_piece.setText( create_info_str(self._current_piece['title'], self._current_piece['files'])) self.__update_movement_list() self._history[datetime.now().strftime('%H:%M:%S')] = \ self._lineedit_current_piece.text() else: self.__update_vlc_medium(self._current_piece['play_next']) # next is last movement if self._current_piece['play_next'] == \ len(self._current_piece['files']) - 1: self._current_piece['play_next'] = -1 else: # there are at least two movements of current piece left self._current_piece['play_next'] += 1 if self._status == 'Paused' and not reset_pause_after_current: self.__action_play_pause() elif reset_pause_after_current: self.parentWidget().set_pause_after_current(False) else: self._vlc_mediaplayer.play() self.parentWidget().update_status_bar( self._status, f'{len(self._pieces) - len(self._playlist)}/{len(self._pieces)}') def __action_play_pause(self): """ (gets called when self._btn_play_pause is clicked) toggles playing/pausing music and updates everything as needed """ # don't do anything now (maybe end of playlist reached?) if self._current_piece['title'] == '': return if self._status == 'Paused': if not self._vlc_medium: self.__action_next() self._vlc_mediaplayer.play() self._btn_play_pause.setIcon(QIcon(get_icon_path('pause'))) self._status = 'Playing' else: self._vlc_mediaplayer.pause() self._btn_play_pause.setIcon(QIcon(get_icon_path('play'))) self._status = 'Paused' self.parentWidget().update_status_bar( self._status, f'{len(self._pieces) - len(self._playlist)}/{len(self._pieces)}') def __action_previous(self): """ (called when self._btn_previous ist clicked) goes back one movement of the current piece, if possible (cannot go back to previous piece) """ # can't go back to previous piece, but current one has no or one movement if len(self._current_piece['files']) <= 1: pass # currently playing first movement, so nothing to do as well elif self._current_piece['play_next'] == 1: pass else: # we can go back one movement # currently at last movement if self._current_piece['play_next'] == -1: # set play_next to last movement self._current_piece['play_next'] = \ len(self._current_piece['files']) - 1 else: # currently before last movement # set play_next to current movement self._current_piece['play_next'] -= 1 self._vlc_mediaplayer.stop() self.__update_vlc_medium(self._current_piece['play_next'] - 1) self._vlc_mediaplayer.play() def __action_volume_clicked(self): """ (called when self._btn_volume is clicked) (un)mutes volume """ if self._slider_volume.value() == 0: # unmute volume self._slider_volume.setValue(self._volume_before_muted) else: # mute volume self._volume_before_muted = self._slider_volume.value() self._slider_volume.setValue(0) def __event_movement_ended(self, event): """ (called when self._vlc_media_player emits a MediaPlayerEndReached event) sets self._skip_to_next to True so the next self.__update call will trigger self.__action_next """ self._skip_to_next = True def __event_movement_selected(self): """ (called when self._listwidget_movements emits itemClicked) skips to the newly selected movement """ index = self._listwidget_movements.indexFromItem( self._listwidget_movements.currentItem()).row() # user selected a movement different from the current one if index != self.__get_current_movement_index(): self._current_piece['play_next'] = index self.__action_next() def __event_piece_text_changed(self): """ (called when self._lineedit_current_piece emits textChanged) ensures that the user sees the beginning of the text in self._lineedit_current_piece (if text is too long, the end will be cut off and the user must scroll manually to see it) """ self._lineedit_current_piece.setCursorPosition(0) def __event_volume_changed(self): """ (called when value of self._slider_volume changes) updates text of self._lbl_volume to new value of self._slider_value and sets icon of self._btn_volume to a fitting one """ volume = self._slider_volume.value() self._lbl_volume.setText(f'{volume}%') if volume == 0: self._btn_volume.setIcon(QIcon(get_icon_path('volume-muted'))) elif volume < 34: self._btn_volume.setIcon(QIcon(get_icon_path('volume-low'))) elif volume < 67: self._btn_volume.setIcon(QIcon(get_icon_path('volume-medium'))) else: self._btn_volume.setIcon(QIcon(get_icon_path('volume-high'))) self._vlc_mediaplayer.audio_set_volume(volume) def __event_time_changed_by_user(self): """ (called when user releases self._slider_time) synchronizes self._vlc_mediaplayer's position to the new value of self._slider_time """ self._vlc_mediaplayer.set_position(self._slider_time.value() / 100) def __get_current_movement_index(self): """ returns the index of the current movement in self._current_piece['files'] """ play_next = self._current_piece['play_next'] if play_next == -1: return len(self._current_piece['files']) - 1 else: return play_next - 1 def __on_press(self, key): """ (called by self._keyboard_listener when a key is pressed) looks up key code corresponding to key and calls the appropriate action function """ try: # key is not always of the same type (why would it be?!) key_code = key.vk except AttributeError: key_code = key.value.vk if key_code in self._KEY_CODES_PLAY_PAUSE: self.__action_play_pause() elif key_code in self._KEY_CODES_NEXT: self.__action_next() elif key_code in self._KEY_CODES_PREVIOUS: self.__action_previous() def __update_movement_list(self): """ removes all items currently in self._listwidget_movements and adds everything in self._current_piece['files] """ # TODO: use ID3 title instead of filename while self._listwidget_movements.count() > 0: self._listwidget_movements.takeItem(0) files = self._current_piece['files'] if os_name == 'nt': # windows paths look different than posix paths # remove path to file, title number and .mp3 ending files = [i[i.rfind('\\') + 3:-4] for i in files] else: files = [i[i.rfind('/') + 4:-4] for i in files] self._listwidget_movements.addItems(files) def __update(self): """ (periodically called when self._timer emits timeout signal) updates various ui elements""" # -- select currently playing movement in self._listwidget_movements -- if self._listwidget_movements.count() > 0: self._listwidget_movements.item( self.__get_current_movement_index()).setSelected(True) # -- update text of self._lbl_time_played and self._lbl_time_left, # if necessary -- if self._vlc_medium: try: time_played = self._vlc_mediaplayer.get_time() medium_duration = self._vlc_medium.get_duration() # other values don't make sense (but do occur) if (time_played >= 0) and (time_played <= medium_duration): self._lbl_time_played.setText( get_time_str_from_ms(time_played)) else: self._lbl_time_played.setText(get_time_str_from_ms(0)) self._lbl_time_left.setText( f'-{get_time_str_from_ms(medium_duration - time_played)}') except OSError: # don't know why that occurs sometimes pass # -- update value of self._slider_time -- # don't reset slider to current position if user is dragging it if not self._slider_time.isSliderDown(): try: self._slider_time.setValue( self._vlc_mediaplayer.get_position() * 100) except OSError: # don't know why that occurs sometimes pass if self._skip_to_next: self._skip_to_next = False self.__action_next() def __update_vlc_medium(self, files_index): old_medium = self._vlc_medium self._vlc_medium = self._vlc_instance.media_new( self._current_piece['files'][files_index]) self._vlc_medium.parse() self._vlc_mediaplayer.set_media(self._vlc_medium) if old_medium: # only release if not None old_medium.release() def get_history(self): """ getter function for parent widget """ return self._history def get_set_str(self): """ getter function for parent widget """ return self._set_str if self._set_str != '' \ else 'No directory set loaded.' def set_pieces_and_playlist(self, pieces, playlist, set_str, shuffled): """ needed so that DirectorySetChooseDialog can set our self._pieces and self._playlist """ # just to be sure if isinstance(pieces, dict) and isinstance(playlist, list): self._vlc_mediaplayer.stop() self._set_str = set_str self._pieces = pieces self._playlist = playlist self._shuffled = shuffled self._current_piece['title'] = self._playlist.pop(0) self._current_piece['files'] = [ p.replace('"', '') for p in self._pieces[self._current_piece['title']] ] self._current_piece['play_next'] = \ 1 if len(self._current_piece['files']) > 1 else -1 self._lineedit_current_piece.setText( create_info_str(self._current_piece['title'], self._current_piece['files'])) self.__update_movement_list() self.__update_vlc_medium(0) self._history[datetime.now().strftime('%H:%M:%S')] = \ self._lineedit_current_piece.text() def exit(self): """ exits cleanly """ try: # don't know why that occurs sometimes self._vlc_mediaplayer.stop() self._vlc_mediaplayer.release() self._vlc_instance.release() except OSError: pass self._keyboard_listener.stop()
class SynthPdfWidget(QWidget): def __init__(self, status_bar): super(SynthPdfWidget, self).__init__() self.status_bar = status_bar layout = QHBoxLayout() self.list_view = QListWidget() self.list_view.setSelectionMode(QAbstractItemView.ExtendedSelection) self.list_view.setAlternatingRowColors(True) self.list_view.itemClicked.connect(self.click_item_signal) self.list_view.itemEntered.connect(self.click_item_signal) self.list_view.itemSelectionChanged.connect( self.change_selection_signal) controls_layout = QVBoxLayout() controls_layout.setAlignment(Qt.AlignTop) select_zone = SelectWidget(self.click_move_up, self.click_move_down, self.click_invert, self.click_delete) select_zone.setMinimumWidth(250) add_pages_button = QPushButton("Add Pages From PDF") add_pages_button.clicked.connect(self.add_pdf) controls_layout.addWidget(select_zone) controls_layout.addWidget(add_pages_button) layout.addWidget(self.list_view) layout.addLayout(controls_layout) self.setLayout(layout) def _add_pages_from_pdf(self, pdf_path): with open(pdf_path, "rb") as file: reader = PdfFileReader(file) file_name = os.path.basename(pdf_path) pages_count = reader.getNumPages() for i in range(pages_count): new_item = ImageListItem( "page " + str(i + 1) + " (" + file_name + ")", (pdf_path, i)) self.list_view.addItem(new_item) self.status_bar.showMessage("Add " + str(pages_count) + " pages") # ----------external methods from create command def extern_get_files_and_pages( self ): # return selected pages in the form {file1: [p1, p2, ...], file2: [p1, p2, ...], ...} to_return = {} if len(self.list_view.selectedItems() ) == 0: # nothing selected, add all pages items_count = self.list_view.count() for item_index in range(items_count): item = self.list_view.item(item_index) item_data = item.get_data() file_name = item_data[0] page_index = item_data[1] if file_name in to_return: to_return[file_name].append(page_index) else: to_return[file_name] = [page_index] else: for s in self.list_view.selectedItems(): s_data = s.get_data() file_name = s_data[0] page_index = s_data[1] if file_name in to_return: to_return[file_name].append(page_index) else: to_return[file_name] = [page_index] return to_return # ----------add button----------------------- def add_pdf(self): files_dialog = QFileDialog() files_dialog.setNameFilter("PDF (*.pdf)") files_dialog.setFileMode(QFileDialog.ExistingFiles) if files_dialog.exec_(): files = files_dialog.selectedFiles() for f_path in files: self._add_pages_from_pdf(f_path) # ----------List_view signals---------------- def click_item_signal(self, item): self.status_bar.showMessage("Select " + str(item.text())) def change_selection_signal(self): if len(self.list_view.selectedItems()) == 0: # self._set_preview(None) # nothing selected pass # ----------list_view commands--------------- def click_move_up(self): selected = self.list_view.selectedItems() selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in selected ] selected_indexes.sort() if len(selected_indexes) > 0 and selected_indexes[0] > 0: for index in selected_indexes: prev_item = self.list_view.takeItem(index - 1) self.list_view.insertItem(index, prev_item) self.status_bar.showMessage("Move " + str(len(selected_indexes)) + " items") else: self.status_bar.showMessage("Nothing to move") def click_move_down(self): selected = self.list_view.selectedItems() selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in selected ] selected_indexes.sort() sel_count = len(selected_indexes) if len(selected_indexes) > 0 and selected_indexes[ sel_count - 1] < self.list_view.count() - 1: for i_index in range(sel_count): next_item = self.list_view.takeItem( selected_indexes[sel_count - i_index - 1] + 1) self.list_view.insertItem( selected_indexes[sel_count - i_index - 1], next_item) self.status_bar.showMessage("Move " + str(len(selected_indexes)) + " items") else: self.status_bar.showMessage("Nothing to move") def click_invert(self): selected = self.list_view.selectedItems() selected_indexes = [] for sel in selected: selected_indexes.append(self.list_view.indexFromItem(sel).row()) total_indexes = [i for i in range(self.list_view.count())] new_indexes = [] for i in total_indexes: if i not in selected_indexes: new_indexes.append(i) self.list_view.clearSelection() for i in new_indexes: self.list_view.item(i).setSelected(True) self.status_bar.showMessage("Invert selection: " + str(new_indexes)) def click_delete(self): selected = self.list_view.selectedItems() delete_names = [] for s in selected: s_index = self.list_view.indexFromItem(s).row() del_item = self.list_view.takeItem(s_index) delete_names.append(del_item.text()) if len(delete_names) == 0: self.status_bar.showMessage("Nothing to delete") else: self.status_bar.showMessage("Delete items: " + ", ".join(delete_names))
class Window(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Network Designer") self.setGeometry(300, 200, 840, 720) self.current_id = 1 self.createLayout() self.couple = [] self.show() def makeButtonsLayout(self): self.button = QPushButton("Add Node", self) self.button.clicked.connect(self.addNode) self.btn_connection = QPushButton("Add Connection:", self) self.btn_connection.clicked.connect(self.addConnection) self.button3 = QPushButton("Export Network", self) self.button3.clicked.connect(self.file_save) self.lbl_connection = QLabel("Connection") self.l_btns = QHBoxLayout() self.l_btns.addWidget(self.button3) self.l_btns.addStretch() self.l_btns.addWidget(self.btn_connection) self.l_btns.addWidget(self.lbl_connection) self.l_btns.addStretch() self.l_btns.addWidget(self.button) self.btns = QWidget() self.btns.setLayout(self.l_btns) self.btns.setFixedHeight(40) def initializeGview(self): self.scene = GraphicsScene() self.scene.setSceneRect(0, 0, 480, 480) self.scene.click.connect(self.keepNode) self.addNode() self.view = QGraphicsView(self.scene) self.view.setGeometry(0, 0, 500, 500) self.view.scale(1, 1) def createOrderList(self): self.orderList = QListWidget() # Enable drag & drop ordering of items. self.orderList.setDragDropMode(QAbstractItemView.InternalMove) def createLayout(self): self.makeButtonsLayout() self.initializeGview() self.createOrderList() l_network = QHBoxLayout() l_network.addWidget(self.view) l_network.addStretch() l_network.addWidget(self.orderList) self.l_root = QVBoxLayout() self.l_root.addLayout(l_network) self.l_root.addStretch() self.l_root.addWidget(self.btns) # self.l_root.addWidget(self.view) self.setLayout(self.l_root) def addNode(self): greenBrush = QBrush(Qt.green) blackPen = QPen(Qt.black) # blueBrush = QBrush(Qt.blue) blackPen.setWidth(5) ellipse = GraphicsEllipse(str(self.current_id), blackPen, greenBrush, 100, 100, NODE_D, NODE_D) self.scene.addItem(ellipse) self.current_id += 1 def keepNode(self, node): if len(self.couple) < 2: self.couple.append(node) else: self.couple.pop(0) self.couple.append(node) if len(self.couple) == 2: self.lbl_connection.setText(self.couple[0].label + " --> " + self.couple[1].label) def addConnection(self): line = GraphicsLine(self.couple[0], self.couple[1], NODE_R) self.scene.addItem(line) for v in self.couple: v.add_connection(line) self.orderList.addItem(self.lbl_connection.text()) def getNodes(self): positions = {} for i in self.scene.items(): if type(i) is GraphicsEllipse: positions[int(i.label)] = i.getPosition() return positions def getConnections(self): connections = [] for i in range(self.orderList.count()): conn = self.orderList.item(i).text().split(" --> ") connections.append((int(conn[0]), int(conn[1]), {"label": str(i + 1)})) return connections def file_save(self): positions = self.getNodes() connections = self.getConnections() network = {} network["labels"] = {i: i for i in sorted(list(positions.keys()))} network["edges"] = connections network["pos"] = positions text = json.dumps(network) name = QFileDialog.getSaveFileName(self, 'Save File') file = open(name[0], 'w') # text = "something" file.write(text) file.close()
class ClientWindow(QDialog): def __init__(self): super(ClientWindow, self).__init__() self.resize(823,511) self.setWindowTitle('用户客户端') self.friendList = QListWidget() self.friendList.doubleClicked.connect(self.changeFriendText) self.friendList.clicked.connect(self.changeFriendText) self.portLine = QLineEdit() self.portLine.setText('12345') self.connectBtn = QPushButton('连接') self.connectBtn.clicked.connect(self.setupFun) self.messageText = QTextEdit() self.messageLine = QLineEdit() self.sendBtn = QPushButton('发送') self.sendBtn.clicked.connect(self.sendFun) self.text = '' self.userText = {} self.initUI() self.palette = QPalette() self.palette.setBrush(QPalette.Background, QBrush(QPixmap('./image/background.jpg'))) self.setPalette(self.palette) self.client = Client() self.client.trigger.connect(self.updateTextFun) self.ininData() def changeFriendText(self): currentItem = self.friendList.currentItem().text() self.text = self.userText[currentItem] self.messageText.setText(self.text) def ininData(self): self.friendList.addItem('broadcast') self.userText['broadcast'] = '' self.friendList.setCurrentItem(self.friendList.item(0)) def initUI(self): mainLayout = QVBoxLayout() mainWidget = QWidget() widget1 = QWidget() layout1 = QHBoxLayout() layout1.addWidget(self.portLine) layout1.addWidget(self.connectBtn) widget1.setLayout(layout1) mainLayout.addWidget(widget1) widget2 = QWidget() layout2 = QHBoxLayout() layout2.addWidget(self.messageText) layout2.addWidget(self.friendList) layout2.setStretch(0,2) layout2.setStretch(0,1) widget2.setLayout(layout2) mainLayout.addWidget(widget2) # mainLayout.addStretch(1) widget3 = QWidget() layout3 = QHBoxLayout() layout3.addWidget(self.messageLine) layout3.addWidget(self.sendBtn) widget3.setLayout(layout3) mainLayout.addWidget(widget3) self.setLayout(mainLayout) def setupFun(self): port = int(self.portLine.text()) self.client.setupFun(port) self.client.start() def sendFun(self): addr = self.friendList.currentItem().text() message = self.messageLine.text() if message != 'add' and message != 'del': self.userText[addr] += '我:' + message + '\n' self.changeFriendText() if addr != 'broadcast': addr = ('localhost',int(addr)) self.client.sendFun(message,addr) self.messageLine.setText('') def updateTextFun(self,data): currentItem = self.friendList.currentItem().text() data = json.loads(data) if 'cmd' in data.keys(): if data['cmd'] == 'add': fromUser = str(data['from']) addr = ('127.0.0.1',int(fromUser)) item = self.friendList.findItems(fromUser,Qt.MatchExactly) if fromUser not in self.userText.keys(): self.userText[fromUser] = '' if len(item) == 0: self.friendList.addItem(fromUser) self.client.sendFun('add',addr) # 已添加 elif data['cmd'] == 'del': fromUser = str(data['from']) rows = self.friendList.count() for row in range(rows): if fromUser == self.friendList.item(row).text(): self.friendList.takeItem(row) else: message = data['message'] fromUser = str(data['from']) if fromUser != 'broadcast': addr = ('127.0.0.1', int(fromUser)) item = self.friendList.findItems(fromUser, Qt.MatchExactly) if fromUser not in self.userText.keys(): self.userText[fromUser] = '' if len(item) == 0: self.friendList.addItem(fromUser) self.client.sendFun('add', addr) # 已添加 if message != 'add' and message != 'del': self.userText[fromUser] += fromUser + ':' + message + '\n' if fromUser == currentItem: self.text = self.userText[fromUser] self.messageText.setText(self.text) def closeEvent(self, event:PySide2.QtGui.QCloseEvent): self.client.closeFun()
class WetSand(QWidget): def __init__(self): super().__init__() # Init list self.list = QListWidget() self.list.addItem(WetListItem("You don't form in the wet sand")) self.list.addItem(WetListItem("You don't form at all")) # Init buttons self.btns = [ WetButton('johs'), WetButton('jon'), WetButton('feel'), WetButton('chat'), WetButton('tony') ] # Freeze and unfreeze buttons self.freeze_btn = QPushButton('Freeze me') self.unfreeze_btn = QPushButton('Unfreeze me') # Layout stuff self.btn_lyt = QVBoxLayout() for btn in self.btns: self.btn_lyt.addWidget(btn) self.top_lyt = QHBoxLayout() self.top_lyt.addWidget(self.list) self.top_lyt.addLayout(self.btn_lyt) self.bottom_lyt = QHBoxLayout() self.bottom_lyt.addWidget(self.freeze_btn) self.bottom_lyt.addWidget(self.unfreeze_btn) self.main_lyt = QVBoxLayout() self.main_lyt.addLayout(self.top_lyt) self.main_lyt.addLayout(self.bottom_lyt) # Signals and slots # Use functools.partial to send arguments self.freeze_btn.clicked.connect(partial(self.freeze, True)) self.unfreeze_btn.clicked.connect(partial(self.freeze, False)) # Don't forget me self.setLayout(self.main_lyt) self.show() @Slot() def freeze(self, yes=True): # Freeze buttons print(yes) btns = (self.btn_lyt.itemAt(i).widget() for i in range(self.btn_lyt.count())) for btn in btns: btn.set_clickable(not yes) # Freeze list items list_items = [self.list.item(i) for i in range(self.list.count())] for list_item in list_items: list_item.set_selectable(not yes)
class Widgets(QWidget): def __init__(self, gui, app): super(Widgets, self).__init__() self.gui = gui self.app = app self.setWindowTitle("Dark Souls Boss Tracker") self.setGeometry(800, 400, 250, 200) self.new_run_label = QLabel("Run name:") self.new_run_field = QLineEdit(self) self.new_run_button = QPushButton("Start New Run", self) self.new_run_button.clicked.connect(self.new_run) self.previous_label = QLabel("Previous runs:") self.previous_runs = QListWidget(self) self.previous_runs.itemClicked.connect(self.select_run) self.selected = None self.resume_button = QPushButton("Resume Run", self) self.resume_button.clicked.connect(self.resume) self.delete_button = QPushButton("Delete Run", self) self.delete_button.clicked.connect(self.delete_run) self.layout = QGridLayout() self.layout.addWidget(self.new_run_label, 0, 0) self.layout.addWidget(self.new_run_field, 1, 0) self.layout.addWidget(self.new_run_button, 1, 1) self.layout.addWidget(self.previous_label, 2, 0) self.layout.addWidget(self.previous_runs, 3, 0) self.layout.addWidget(self.resume_button, 4, 0) self.layout.addWidget(self.delete_button, 4, 1) self.get_tables() self.setLayout(self.layout) def get_tables(self): self.previous_runs.clear() my_list = boss_tracker.get_tables() if my_list is not None: for i in my_list: self.previous_runs.addItem(i[0]) # print(my_list) def select_run(self, item): self.selected = item.text() def new_run(self): new_run_pattern = re.compile(r"[^a-zA-Z0-9_-]") error = new_run_pattern.search(self.new_run_field.text()) for i in range(self.previous_runs.count()): if self.new_run_field.text() == self.previous_runs.item(i).text(): error = True if not error and len(self.new_run_field.text()) > 3: Order().show() boss_tracker.start_new_run(self.new_run_field.text(), self.app) self.previous_runs.addItem(self.new_run_field.text()) self.gui.close() else: ErrorWindow( "Username too short has special characters or already in use.") def resume(self): if self.selected is not None: boss_tracker.resume_run(self.selected) self.gui.close() def delete_run(self): print(self.selected) if self.selected is not None: boss_tracker.delete_table(self.selected) self.get_tables()
class CreateSequenceWindow(QDialog): """ Window for creating a new sequence """ def __init__(self, motors={}, listOfSequenceHandler=None, sequence=None, modifySequence=False): """ Initializtion of the window for creating a new sequence :param motors: The dictionary of all the motors :param listOfSequenceHandler: The handler of the list of sequence """ QDialog.__init__(self) # Set the window icon appIcon = QIcon(icon) self.setWindowIcon(appIcon) ## Flag if the sequence is a modified one or a new one self.__modifySequence = modifySequence ## The handler of the list of sequence self.__listOfSequenceHandler = listOfSequenceHandler ## The dictionary of all the motors self.__motors = motors ## The new sequence self.__sequence = sequence ## A dictionary of the positions of the new sequence self.__wantedPositions = {} ## The layout of the create sequence window self.__layout = QVBoxLayout(self) ## The widget for the name of the sequenc self.nameEntry = QLineEdit() self.nameEntry.setText(self.__sequence.getName()) ## The label for the widget in which the name of the sequence is written self.__nameLabel = QLabel("Sequence Name") ## The list of the different moves that forms the sequence self.__listOfMoveLabels = QListWidget() moveNumber = 1 for move in self.__sequence.getMoves(): # Set text for the move label labelText = "move " + str(moveNumber) + ": " moveNumber += 1 for motor in self.__motors: labelText += self.__motors[motor].getName() + " " + \ str(move.getMotorPosition(self.__motors[motor].getName())) + ", " label = moveLabel(move, labelText, self.__motors) # insert label to the head of the list self.__listOfMoveLabels.insertItem(0, label) # Put the sliders of the create sequence window in a list ## List of sliders in the create sequence window self.listOfSliders = [] dictOfSlider = dict() for motor in self.__motors: dictOfSlider[motor] = QSlider(Qt.Horizontal) dictOfSlider[motor].setMaximum(4095) dictOfSlider[motor].setValue( self.__motors[motor].getCurrentPosition()) dictOfSlider[motor].sliderMoved.connect( self.__motors[motor].setGoalPosition) self.listOfSliders.append(dictOfSlider[motor]) ## Message to make the user put a name to the sequence self.__noNameMessage = QMessageBox() self.__noNameMessage.setIcon(QMessageBox.Warning) self.__noNameMessage.setWindowIcon(appIcon) self.__noNameMessage.setText( "Please name your sequence before saving it") self.__noNameMessage.setStandardButtons(QMessageBox.Ok) # Renable the create sequence window and closes the message self.__noNameMessage.accepted.connect(self.enableWindow) ## Warning message to make sure the user doen't want to save the sequence self.__warningMessage = QMessageBox() self.__warningMessage.setIcon(QMessageBox.Warning) self.__warningMessage.setWindowIcon(appIcon) self.__warningMessage.setText( "Are you sure you want to close this window? Your sequence will not be saved" ) self.__warningMessage.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) # Close the create sequence window and the message self.__warningMessage.accepted.connect(self.reject) # Renable the create sequence window and closes the message self.__warningMessage.rejected.connect(self.enableWindow) # Set the text for the labels ## Labels for the motors in the UI self.__motorLabels = [] for motorNumber in range(0, len(motors)): self.__motorLabels.append( QLabel("Motor " + str(motorNumber + 1) + " position")) ## Button to add a move to the sequence and procede to the next move self.nextMoveButton = QPushButton("Save Move") ## Buttons to accept or cancel the creation of a sequence self.buttonBox = QDialogButtonBox() self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) # If ok pressed add the sequence to the list self.buttonBox.accepted.connect( lambda: self.addSequenceToList(self.__modifySequence)) # If cancel pressed close the create sequence window self.buttonBox.rejected.connect(self.__warningMessage.exec) # Renable the main window when the create sequence closes self.rejected.connect(self.__listOfSequenceHandler.enableUi) self.accepted.connect(self.__listOfSequenceHandler.enableUi) self.nextMoveButton.clicked.connect(self.addMovetoSequence) self.__listOfMoveLabels.itemDoubleClicked.connect( self.moveDoubleClicked) # Build the vertical layout with the different widgets self.__layout.addWidget(self.__nameLabel) self.__layout.addWidget(self.nameEntry) self.__layout.addWidget(self.__listOfMoveLabels) for motorNumber in range(len(self.__motors)): self.__layout.addWidget(self.__motorLabels[motorNumber]) self.__layout.addWidget(self.listOfSliders[motorNumber]) self.__layout.addWidget(self.nextMoveButton) self.__layout.addWidget(self.buttonBox) # Connect the qwidgetlist to the custom right click menu self.__listOfMoveLabels.setContextMenuPolicy(Qt.CustomContextMenu) self.__listOfMoveLabels.customContextMenuRequested.connect( self.rightClickMenu) def setName(self, name): """ Sets the name of the sequence with the user input :param name: The name of the sequence :return: No return """ self.__sequence.setName(name) def getSequence(self): """ Accessor of the sequence (for tests) :return: the sequence """ return self.__sequence def getListofMoveLabels(self): """ Accessor of the list of move labels (for tests) :return: the list of move labels """ return self.__listOfMoveLabels def addSequenceToList(self, modifySequence=False): """ Add the sequence to the list of sequence :param modifySequence: bool, if true there's a selected sequence that needs to be modified if false it's a new sequence :return: No return """ # TODO: look to move this method to the list of sequence handler # TODO: don't let the user enter a sequence that has the same name as an old one self.setName(self.nameEntry.text()) if self.__sequence.getName() != "": # Load previously saved sequences try: with open('SaveSequence.json') as save: savedListOfSequences = json.load(save) except FileNotFoundError: savedListOfSequences = [] if modifySequence: # Get the item that needs to be modified # selectedSequence = self.__listOfSequenceHandler.getSelectedItems() # Find the selected sequence in the list of saved ones for sequence in savedListOfSequences: if self.__sequence.getName() in sequence: indexOfTheSequence = savedListOfSequences.index( sequence) # remove the unmodified sequence to insert the modified sequence savedListOfSequences.remove(sequence) self.__listOfSequenceHandler.addItem(self.__sequence) # Make the sequence json seriable newSequence = dict() newSequence[self.__sequence.getName()] = [] for moveNumber in range(len( self.__sequence.getMoves())): newSequence[self.__sequence.getName()].append( self.__sequence.getMoves() [moveNumber].getMovePositions()) # Append new sequence to the old ones savedListOfSequences.insert(indexOfTheSequence, newSequence) # Write the sequences to the file with open('SaveSequence.json', 'w') as outfile: json.dump(savedListOfSequences, outfile) self.accept() else: self.__listOfSequenceHandler.addItem(self.__sequence) # Make the sequence json seriable newSequence = dict() newSequence[self.__sequence.getName()] = [] for moveNumber in range(len(self.__sequence.getMoves())): newSequence[self.__sequence.getName()].append( self.__sequence.getMoves() [moveNumber].getMovePositions()) # Append new sequence to the old ones savedListOfSequences.append(newSequence) # Write the sequences to the file with open('SaveSequence.json', 'w') as outfile: json.dump(savedListOfSequences, outfile) self.accept() else: self.setEnabled(False) self.__noNameMessage.exec_() def addMovetoSequence(self): """ Add the last move to the sequence :return: No return """ move = None labelToModify = None # Check if there's a move in modifying state for row in range(self.__listOfMoveLabels.count()): if not self.__listOfMoveLabels.item(row).getMove().isNew: move = self.__listOfMoveLabels.item(row).getMove() labelToModify = self.__listOfMoveLabels.item(row) break # verify if the move is a new one if move is None: # Create the new move and set his positions move = Move(self.__motors) i = 0 for motorName in self.__motors: move.setMotorPosition(motorName, self.listOfSliders[i].value()) i += 1 self.__sequence.addMove(move) # Set text for the move label labelText = "move " + str( self.__sequence.getNumberofMoves()) + ": " i = 0 for motor in self.__motors: labelText += self.__motors[motor].getName() + " " +\ str(self.listOfSliders[i].value()) + ", " i += 1 label = moveLabel(move, labelText, self.__motors) # insert label to the head of the list self.__listOfMoveLabels.insertItem(0, label) else: # modify the move i = 0 for motorName in self.__motors: move.setMotorPosition(motorName, self.listOfSliders[i].value()) i += 1 # modify the label of the move textToEdit = labelToModify.text() listOfTextToEdit = textToEdit.split(' ') labelText = listOfTextToEdit[0] + " " + listOfTextToEdit[1] + " " i = 0 for motor in self.__motors: labelText += self.__motors[motor].getName() + " " + \ str(self.listOfSliders[i].value()) + ", " i += 1 labelToModify.setText(labelText) labelToModify.setSelected(False) labelToModify.setBackground(Qt.white) # reset the state of the move move.isNew = True # Access the move positions when double clicked on def moveDoubleClicked(self, moveItem): """ Called when a move in the sequence is double clicked :param moveItem: the move that was double clicked :return: No return """ moveItem.goToMoveOfTheLabel() self.updateSlidersPositions() def updateSlidersPositions(self): counterMotors = 0 for motor in self.__motors: self.listOfSliders[counterMotors].setValue( self.__motors[motor].getGoalPosition()) counterMotors += 1 def enableWindow(self): """ Enable the create sequence window :return: """ self.setEnabled(True) def rightClickMenu(self, event): """ The right click menu of the move list :param event: The event (here right click) that makes the menu come up :return: No return """ menu = QMenu() # Add a button in the menu that when clicked, it puts a move in modifying state menu.addAction( "Modify Move", lambda: self.modifyMove(self.__listOfMoveLabels. selectedItems()[0])) # Add a button in the menu that when clicked, it deletes a move in the list menu.addAction( "Delete Move", lambda: self.deleteMove(self.__listOfMoveLabels. selectedItems()[0])) menu.exec_(self.__listOfMoveLabels.mapToGlobal(event)) def deleteMove(self, label): """ Delete a move and its label of the sequence :param label: label of the move :return: No return """ # remove the label from the list self.__listOfMoveLabels.takeItem(self.__listOfMoveLabels.row(label)) # remove the move from the sequence self.__sequence.deleteMove(label.getMove()) # rename the labels in the list of moves for index in range(self.__sequence.getNumberofMoves() - 1, -1, -1): labelToModify = self.__listOfMoveLabels.item(index) textToEdit = labelToModify.text() listOfTextToEdit = textToEdit.split(' ') listOfTextToEdit[1] = str(self.__sequence.getNumberofMoves() - index) + ':' textToEdit = ' '.join(listOfTextToEdit) self.__listOfMoveLabels.item(index).setText(textToEdit) def modifyMove(self, label): """ Put a move to a modified state :param label: label of the move :return: No return """ # Check if there's a move in modifying state for row in range(self.__listOfMoveLabels.count()): if not self.__listOfMoveLabels.item(row).getMove().isNew: self.__listOfMoveLabels.item(row).getMove().isNew = True self.__listOfMoveLabels.item(row).setBackground( QBrush(Qt.white)) moveToModify = label.getMove() moveToModify.isNew = False label.setBackground(QBrush(Qt.darkCyan)) label.goToMoveOfTheLabel() self.updateSlidersPositions()
class ReportListComponent(QGroupBox): currentAnalysisChanged = Signal(object) def __init__(self): super().__init__() self.setTitle("Rapports disponibles") main_layout = QVBoxLayout(self) self._list = QListWidget() self._list.setContextMenuPolicy(Qt.CustomContextMenu) self._list.customContextMenuRequested.connect(self._showItemMenu) self._list.currentRowChanged.connect(self._currentAnalysisChanged) self._list.itemDoubleClicked.connect(lambda item: self._renameItem()) self._analysis = None main_layout.addWidget(self._list) def reset(self, analysis: Analysis): self._current_analysis_file = None self._analysis = analysis self._list.clear() for analysis in HistoryManager.analysisList(): item = QListWidgetItem("%s (%s)" % (analysis["name"], analysis["date"])) item.setData(Qt.UserRole, analysis["file"]) item.setData(Qt.UserRole + 1, analysis["name"]) self._list.addItem(item) self._list.setCurrentRow(0) @Slot(int) def _currentAnalysisChanged(self, row: int): if row < 0: return new_analysis_file = self._list.item(row).data(Qt.UserRole) if self._current_analysis_file == new_analysis_file: return if self._current_analysis_file is None: self._current_analysis_file = new_analysis_file return self._current_analysis_file = new_analysis_file self._analysis = HistoryManager.loadAnalysis(new_analysis_file) self.currentAnalysisChanged.emit(self._analysis) @Slot(QPoint) def _showItemMenu(self, pos: QPoint): globalPos = self._list.mapToGlobal(pos) actions_menu = QMenu() actions_menu.addAction("Renommer", self._renameItem) actions_menu.addAction("Supprimer", self._eraseItem) actions_menu.exec_(globalPos) @Slot() def _renameItem(self): item = self._list.currentItem() input_dialog = QInputDialog(self.parentWidget(), Qt.WindowSystemMenuHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint) font = input_dialog.font() font.setPixelSize(16) input_dialog.setFont(font) input_dialog.setMinimumWidth(300) input_dialog.setInputMode(QInputDialog.TextInput) input_dialog.setWindowTitle("Renommer l'analyse") input_dialog.setLabelText("Nouveau nom pour '%s' :" % item.data(Qt.UserRole + 1)) input_dialog.setTextValue(item.data(Qt.UserRole + 1)) input_dialog.setOkButtonText("OK") input_dialog.setCancelButtonText("Annuler") if not input_dialog.exec_(): return new_name = input_dialog.textValue() if self._analysis is None: return if new_name == self._analysis.parameters().name(): return regexp = QRegExp("^[a-zA-Z0-9_-#éèêëàîï ]{5,30}$") if not regexp.exactMatch(new_name): QMessageBox.warning(self, "Nouveau nom invalide", "Caractères autorisés : alphanumérique, espace, #, - et _ avec une longueur maximale de 30 caractères") return self._analysis.parameters().setName(new_name) HistoryManager.renameAnalysis(item.data(Qt.UserRole), self._analysis) current_row = self._list.currentRow() self.reset(self._analysis) self._list.setCurrentRow(current_row) self.currentAnalysisChanged.emit(self._analysis) @Slot() def _eraseItem(self): item = self._list.currentItem() message_box = QMessageBox() message_box.setIcon(QMessageBox.Warning) message_box.setWindowTitle("Supprimer une analyse ?") message_box.setText("Voulez vous vraiment supprimer l'analyse '%s' de façon définitive ?" % item.data(Qt.UserRole + 1)) message_box.setInformativeText("Assurez vous d'avoir exportez toutes les données dont vous avez besoin.") message_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) ret = message_box.exec_() if ret == QMessageBox.Yes: HistoryManager.deleteAnalysis(item.data(Qt.UserRole)) self._list.takeItem(self._list.currentRow()) if self._list.currentRow() == -1: self.currentAnalysisChanged.emit(None)
class ImageToPdfWidget(QWidget): def __init__(self, status_link): super(ImageToPdfWidget, self).__init__() LABEL_WIDTH = 80 self.last_selected_items = [] self.options_mode = 0 self.update_status_combobox = False layout = QHBoxLayout() self.status_bar = status_link self.list_view = QListWidget() self.list_view.setSelectionMode(QAbstractItemView.ExtendedSelection) self.list_view.setAlternatingRowColors(True) self.list_view.itemClicked.connect(self.click_item_signal) self.list_view.itemEntered.connect(self.click_item_signal) self.list_view.itemSelectionChanged.connect( self.change_selection_signal) controls_layout = QVBoxLayout() controls_layout.setAlignment(Qt.AlignTop) select_zone = SelectWidget(self.click_move_up, self.click_move_down, self.click_invert, self.click_delete) # options zone ------------------------------------- options_zone = QGroupBox("Options") self.options_zone_layout = QVBoxLayout() self.options_mode_combobox = QComboBox() self._add_items_to_mode_combobox(self.options_mode_combobox) options_mode_label = QLabel("Mode") options_mode_label.setMaximumWidth(LABEL_WIDTH) options_mode_layout = QHBoxLayout() options_mode_layout.addWidget(options_mode_label) options_mode_layout.addWidget(self.options_mode_combobox) self.options_zone_layout.addLayout(options_mode_layout) self.option_source_widget = OptionsFromSourceWidget( label_width=LABEL_WIDTH, status_bar=self.status_bar) self.options_a_widget = OptionsAWidget(label_width=LABEL_WIDTH, status_bar=self.status_bar) self.options_mode_combobox.currentIndexChanged.connect( self.change_options_mode_signal) self.change_options_mode_signal(self.options_mode) options_zone.setLayout(self.options_zone_layout) # Add files button and final structures --------------------------- add_file_button = QPushButton("Add Files") add_file_button.clicked.connect(self.click_add_files) controls_layout.addWidget(select_zone) controls_layout.addWidget(options_zone) controls_layout.addWidget(add_file_button) # image preview --------------------------------------------------- image_prev_layout = QVBoxLayout() image_prev_layout.setContentsMargins(0, 0, 4, 0) self.IMG_PREVIEW_WIDTH = 256 self.img_label = QLabel() self.img_label.setAlignment(Qt.AlignCenter) self.select_text = "Click item to preview" self.last_created_pix_path = "" self.img_label.setText(self.select_text) image_prev_layout.addWidget(self.img_label) # slider for the preview scale self.img_scale_slider = QSlider() self.img_scale_slider.setMinimum(6) self.img_scale_slider.setMaximum(2048) self.img_scale_slider.setValue(self.IMG_PREVIEW_WIDTH) self.img_scale_slider.setOrientation(Qt.Horizontal) self.img_scale_slider.valueChanged.connect( self.change_scale_slider_signal) image_prev_layout.addWidget(self.img_scale_slider) self._update_preview() layout.addLayout(image_prev_layout) layout.addWidget(self.list_view) layout.addLayout(controls_layout) self.setLayout(layout) self.update_status_combobox = True def _pillow_to_pixmap(self, img): if img.mode == "RGB": r, g, b = img.split() img = Image.merge("RGB", (b, g, r)) elif img.mode == "RGBA": r, g, b, a = img.split() img = Image.merge("RGBA", (b, g, r, a)) elif img.mode == "L": img = img.convert("RGBA") img2 = img.convert("RGBA") data = img2.tobytes("raw", "RGBA") qim = QImage(data, img.size[0], img.size[1], QImage.Format_ARGB32) pixmap = QPixmap.fromImage(qim) return pixmap def _update_preview(self): self.img_label.setMinimumWidth(self.IMG_PREVIEW_WIDTH) self.img_label.setMaximumWidth( max(self.IMG_PREVIEW_WIDTH, self.img_scale_slider.width())) if len(self.last_created_pix_path) > 0: img = Image.open(self.last_created_pix_path) img_pix = self._pillow_to_pixmap(img) img_pix = img_pix.scaled( QSize(self.IMG_PREVIEW_WIDTH, self.IMG_PREVIEW_WIDTH), Qt.KeepAspectRatio) self.img_label.setPixmap(img_pix) def _set_preview(self, img_path): if img_path is None: self.last_created_pix_path = "" self.img_label.setText(self.select_text) else: if img_path != self.last_created_pix_path: self.last_created_pix_path = img_path self._update_preview() def _add_items_to_mode_combobox(self, combobox): combobox.addItem("From Source") combobox.addItem("A4") # combobox.addItem("A5") # combobox.addItem("A6") # combobox.addItem("Letter") def _get_filtered_string(self, string): to_return_array = [] for s in string: if s.isdigit(): to_return_array.append(s) return "".join(to_return_array) def get_images_to_save(self): path_array = [] for i in range(self.list_view.count()): path_array.append(self.list_view.item(i).get_data()) return path_array def get_image_parameters(self): # return as dictionary if self.options_mode == 0: return { "mode": 0, "pixels": self.option_source_widget.get_pixel_value(), "margin": self.option_source_widget.get_margin_value(), "background": self.option_source_widget.get_background_value() } else: return { "mode": self.options_mode, "align": self.options_a_widget.get_align_value(), "margin": self.options_a_widget.get_margin_value(), "background": self.options_a_widget.get_background_value() } def add_items(self, array): added_names = [] for a in array: new_name = os.path.basename(a) new_item = ImageListItem(new_name, a) added_names.append(new_name) self.list_view.addItem(new_item) self.status_bar.showMessage("Add items: " + ", ".join(added_names)) def change_scale_slider_signal(self, value): self.IMG_PREVIEW_WIDTH = value self._update_preview() self.status_bar.showMessage("Set preview scale to " + str(value)) def click_item_signal(self, item): pass # self._set_preview(item.get_data()) # self.status_bar.showMessage("Select " + str(item.text())) def _get_first_new_index(self, current, last): for v in current: if v not in last: return v return current[0] def change_selection_signal(self): if len(self.list_view.selectedItems()) == 0: self._set_preview(None) # nothing selected else: selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in self.list_view.selectedItems() ] item = self.list_view.item( self._get_first_new_index(selected_indexes, self.last_selected_items)) self._set_preview(item.get_data()) self.status_bar.showMessage("Select " + str(item.text())) self.last_selected_items = selected_indexes def change_options_mode_signal(self, index): self.options_mode = index if self.options_mode == 0: self.options_zone_layout.removeWidget(self.options_a_widget) self.options_a_widget.setParent(None) self.options_zone_layout.addWidget(self.option_source_widget) else: self.options_zone_layout.removeWidget(self.option_source_widget) self.option_source_widget.setParent(None) self.options_zone_layout.addWidget(self.options_a_widget) if self.update_status_combobox: self.status_bar.showMessage( "Set combine mode to \"" + self.options_mode_combobox.itemText(index) + "\"") def resizeEvent(self, size): # self._update_preview() pass def click_move_up(self): selected = self.list_view.selectedItems() selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in selected ] selected_indexes.sort() if len(selected_indexes) > 0 and selected_indexes[0] > 0: for index in selected_indexes: prev_item = self.list_view.takeItem(index - 1) self.list_view.insertItem(index, prev_item) self.status_bar.showMessage("Move " + str(len(selected_indexes)) + " items") else: self.status_bar.showMessage("Nothing to move") def click_move_down(self): selected = self.list_view.selectedItems() selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in selected ] selected_indexes.sort() sel_count = len(selected_indexes) if len(selected_indexes) > 0 and selected_indexes[ sel_count - 1] < self.list_view.count() - 1: for i_index in range(sel_count): next_item = self.list_view.takeItem( selected_indexes[sel_count - i_index - 1] + 1) self.list_view.insertItem( selected_indexes[sel_count - i_index - 1], next_item) self.status_bar.showMessage("Move " + str(len(selected_indexes)) + " items") else: self.status_bar.showMessage("Nothing to move") def click_invert(self): selected = self.list_view.selectedItems() selected_indexes = [] for sel in selected: selected_indexes.append(self.list_view.indexFromItem(sel).row()) total_indexes = [i for i in range(self.list_view.count())] new_indexes = [] for i in total_indexes: if i not in selected_indexes: new_indexes.append(i) self.list_view.clearSelection() for i in new_indexes: self.list_view.item(i).setSelected(True) self.status_bar.showMessage("Invert selection: " + str(new_indexes)) def click_delete(self): selected = self.list_view.selectedItems() delete_names = [] for s in selected: s_index = self.list_view.indexFromItem(s).row() del_item = self.list_view.takeItem(s_index) delete_names.append(del_item.text()) if len(delete_names) == 0: self.status_bar.showMessage("Nothing to delete") else: self.status_bar.showMessage("Delete items: " + ", ".join(delete_names)) def click_add_files(self): files_dialog = QFileDialog() files_dialog.setNameFilter("Images (*.jpg *.jpeg *.bmp *.png *.tiff)") files_dialog.setFileMode(QFileDialog.ExistingFiles) if files_dialog.exec_(): files = files_dialog.selectedFiles() self.add_items(files)
class AddMovieDialog(QDialog): client = Client() def __init__(self, parent): super(AddMovieDialog, self).__init__(parent) self.setWindowTitle("Add Movie") main_layout = QVBoxLayout(self) self.selected_movies = None search_layout = QHBoxLayout() main_layout.addLayout(search_layout) self.search_field = QLineEdit() self.search_field.returnPressed.connect(self.find_action) self.search_field.setPlaceholderText("Search movies...") search_layout.addWidget(self.search_field) self.find_all_checkbx = QCheckBox("Find All") search_layout.addWidget(self.find_all_checkbx) self.result_list = QListWidget() self.result_list.setSelectionMode(QListWidget.ExtendedSelection) main_layout.addWidget(self.result_list) button_layout = QHBoxLayout() main_layout.addLayout(button_layout) add_bttn = QPushButton("Add Movie") add_bttn.clicked.connect(self.accept) add_all_bttn = QPushButton("Add All Movies") add_all_bttn.clicked.connect(self.add_all_action) cancel_bttn = QPushButton("Cancel") cancel_bttn.clicked.connect(self.reject) button_layout.addWidget(add_bttn) button_layout.addWidget(add_all_bttn) button_layout.addWidget(cancel_bttn) def keyPressEvent(self, event): event.ignore() def add_all_action(self): for i in range(self.result_list.count()): self.result_list.setItemSelected(self.result_list.item(i), True) self.accept() def accept(self): selected_items = self.result_list.selectedItems() if not selected_items: return self.selected_movies = [ i.movie_data for i in selected_items if not self.client.find_movie(i.movie_data["id"]) ] super(AddMovieDialog, self).accept() def find_action(self): movie_title = self.search_field.text() if len(movie_title): self.result_list.clear() for item in find_movie( movie_title, all_pages=self.find_all_checkbx.isChecked()): MovieItem(self.result_list, item)
from PySide2 import QtCore from PySide2.QtWidgets import QApplication, QListWidget, QComboBox if __name__ == '__main__': """ Two views using each one a instance of our data When the data is change in QListWidget(), the data in QComboBox will not be changed """ app = QApplication(sys.argv) # Let's make the QListWidget show this data data = ["ONE", "TWO", "THREE", "FOUR", "FIVE"] list_widget = QListWidget() list_widget.show() list_widget.addItems(data) # Let's make elements on QListWidget editable for index in range(list_widget.count()): item = list_widget.item(index) item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable) # A comboBox showing the same data comboBox = QComboBox() comboBox.show() comboBox.addItems(data) sys.exit(app.exec_())
def get_attribute_widget(index: int, list_widget: QListWidget) -> FieldAttrFrame: item = list_widget.item(index) return list_widget.itemWidget(item)
class PersonaUI(QWidget): """ Widget for Persona creation view. :param MainFrame mainframe: application mainframe :param QWidget op: parent widget """ def __init__(self, mainframe, op): QWidget.__init__(self) self.mainframe = mainframe self.op = op self.grid = QGridLayout() self.setLayout(self.grid) self.listP = None self.listLS = None self.listEL1 = None self.listEL2 = None self.nameT = None self.levelT = None self.textT = None self.strT = None self.magT = None self.endT = None self.agiT = None self.luckT = None self.createFrame = None self.buttonFrame = None self.bfgrid = None # Actual create frame variables. self.cfgrid = None self.lsdic = None self.slashO = None self.strikeO = None self.pierceO = None self.fireO = None self.iceO = None self.windO = None self.elecO = None self.darkO = None self.lightO = None self.arcO = None self.iSpellOs = None self.lsSpellO = None self.lslevel = None self.initUI(True) def initUI(self, infoDump): """ Initializes the basic UI showing the list of Personas. Does a lot of stuff. :param dict infoDump: not sure lol """ self.mainframe.setWindowTitle("Persona Creator") if not infoDump: self.createFrameDraw() self.initButtonFrame(infoDump) self.listP = QListWidget(self) self.grid.addWidget(self.listP, 0, 3, 2, 1) temp = json_reader.readPerNames() self.listP.addItems(temp) def initButtonFrame(self, infoDump): """ Initializes the buttonframes that are present in all Persona creator views. :param dict infoDump: not sure lol """ self.buttonFrame = QWidget(self) self.bfgrid = QGridLayout() self.buttonFrame.setLayout(self.bfgrid) self.grid.addWidget(self.buttonFrame, 3, 0, 1, 4) new = QPushButton(self.buttonFrame, text="New") new.clicked.connect(self.new) self.bfgrid.addWidget(new, 4, 0) back = QPushButton(self.buttonFrame, text="Back") back.clicked.connect(self.back) self.bfgrid.addWidget(back, 4, 4) remove = QPushButton(self.buttonFrame, text="Remove") remove.clicked.connect(self.remove) self.bfgrid.addWidget(remove, 4, 3) edit = QPushButton(self.buttonFrame, text="Edit") edit.clicked.connect(self.edit) self.bfgrid.addWidget(edit, 4, 2) if not infoDump: save = QPushButton(self.buttonFrame, text="Save") save.clicked.connect(self.save) self.bfgrid.addWidget(save, 4, 1) def createFrameDraw(self): """ Initializes the GUI of the actual creation frame view. Does a LOT of stuff. """ self.createFrame = QWidget(self) self.cfgrid = QGridLayout() self.createFrame.setLayout(self.cfgrid) self.grid.addWidget(self.createFrame, 0, 0, 2, 2) self.lsdic = {} nameL = QLabel(self.createFrame, text="Name:") self.cfgrid.addWidget(nameL, 0, 0) self.nameT = QLineEdit(self.createFrame) self.nameT.setFixedSize(100, 20) self.cfgrid.addWidget(self.nameT, 0, 1) strL = QLabel(self.createFrame, text="Str") self.cfgrid.addWidget(strL, 0, 2) self.strT = QLineEdit(self.createFrame) self.strT.setFixedSize(20, 20) self.cfgrid.addWidget(self.strT, 0, 3) magL = QLabel(self.createFrame, text="Mag") self.cfgrid.addWidget(magL, 1, 2) self.magT = QLineEdit(self.createFrame) self.magT.setFixedSize(20, 20) self.cfgrid.addWidget(self.magT, 1, 3) endL = QLabel(self.createFrame, text="End") self.cfgrid.addWidget(endL, 2, 2) self.endT = QLineEdit(self.createFrame) self.endT.setFixedSize(20, 20) self.cfgrid.addWidget(self.endT, 2, 3) agiL = QLabel(self.createFrame, text="Agi") self.cfgrid.addWidget(agiL, 3, 2) self.agiT = QLineEdit(self.createFrame) self.agiT.setFixedSize(20, 20) self.cfgrid.addWidget(self.agiT, 3, 3) luckL = QLabel(self.createFrame, text="Luck") self.cfgrid.addWidget(luckL, 4, 2) self.luckT = QLineEdit(self.createFrame) self.luckT.setFixedSize(20, 20) self.cfgrid.addWidget(self.luckT, 4, 3) resList = json_reader.data_list("resistances") resL = QLabel(self.createFrame, text="Resistance:") self.cfgrid.addWidget(resL, 0, 5) slashL = QLabel(self.createFrame, text="Slash") self.cfgrid.addWidget(slashL, 1, 5) self.slashO = QComboBox(self.createFrame) self.slashO.addItems(resList) self.slashO.setCurrentIndex(1) self.cfgrid.addWidget(self.slashO, 1, 6) strikeL = QLabel(self.createFrame, text="Strike") self.cfgrid.addWidget(strikeL, 2, 5) self.strikeO = QComboBox(self.createFrame) self.strikeO.addItems(resList) self.strikeO.setCurrentIndex(1) self.cfgrid.addWidget(self.strikeO, 2, 6) pierceL = QLabel(self.createFrame, text="Pierce") self.cfgrid.addWidget(pierceL, 3, 5) self.pierceO = QComboBox(self.createFrame) self.pierceO.addItems(resList) self.pierceO.setCurrentIndex(1) self.cfgrid.addWidget(self.pierceO, 3, 6) fireL = QLabel(self.createFrame, text="Fire") self.cfgrid.addWidget(fireL, 4, 5) self.fireO = QComboBox(self.createFrame) self.fireO.addItems(resList) self.fireO.setCurrentIndex(1) self.cfgrid.addWidget(self.fireO, 4, 6) iceL = QLabel(self.createFrame, text="Ice") self.cfgrid.addWidget(iceL, 5, 5) self.iceO = QComboBox(self.createFrame) self.iceO.addItems(resList) self.iceO.setCurrentIndex(1) self.cfgrid.addWidget(self.iceO, 5, 6) elecL = QLabel(self.createFrame, text="Elec") self.cfgrid.addWidget(elecL, 6, 5) self.elecO = QComboBox(self.createFrame) self.elecO.addItems(resList) self.elecO.setCurrentIndex(1) self.cfgrid.addWidget(self.elecO, 6, 6) windL = QLabel(self.createFrame, text="Wind") self.cfgrid.addWidget(windL, 7, 5) self.windO = QComboBox(self.createFrame) self.windO.addItems(resList) self.windO.setCurrentIndex(1) self.cfgrid.addWidget(self.windO, 7, 6) lightL = QLabel(self.createFrame, text="Light") self.cfgrid.addWidget(lightL, 8, 5) self.lightO = QComboBox(self.createFrame) self.lightO.addItems(resList) self.lightO.setCurrentIndex(1) self.cfgrid.addWidget(self.lightO, 8, 6) darkL = QLabel(self.createFrame, text="Dark") self.cfgrid.addWidget(darkL, 9, 5) self.darkO = QComboBox(self.createFrame) self.darkO.addItems(resList) self.darkO.setCurrentIndex(1) self.cfgrid.addWidget(self.darkO, 9, 6) spellList = json_reader.data_list("spells") self.listLS = QListWidget(self.createFrame) self.listLS.setFixedSize(200, 300) self.cfgrid.addWidget(self.listLS, 3, 7, 8, 2) newLS = QPushButton(self.createFrame, text="+") newLS.clicked.connect(self.addLS) self.cfgrid.addWidget(newLS, 2, 7) delLS = QPushButton(self.createFrame, text="DEL") delLS.clicked.connect(self.delLS) self.cfgrid.addWidget(delLS, 2, 8) lsl = QLabel(self.createFrame, text="Learned Spells:") self.cfgrid.addWidget(lsl, 0, 7, 1, 2) arcanaL = QLabel(self.createFrame, text="Arcana:") self.cfgrid.addWidget(arcanaL, 1, 0) arc_list = json_reader.data_list("arcanas") self.arcO = QComboBox(self.createFrame) self.arcO.addItems(arc_list) self.arcO.setCurrentIndex(0) self.cfgrid.addWidget(self.arcO, 1, 1) levelL = QLabel(self.createFrame, text="Level:") self.cfgrid.addWidget(levelL, 2, 0) self.levelT = QLineEdit(self.createFrame) self.levelT.setFixedSize(20, 20) self.cfgrid.addWidget(self.levelT, 2, 1) heritageL = QLabel(self.createFrame, text="Inherits:") self.cfgrid.addWidget(heritageL, 3, 0, 1, 2) elements = json_reader.data_list("elements") elements.append("Support") self.listEL1 = QComboBox(self.createFrame) self.listEL1.addItems(elements) self.cfgrid.addWidget(self.listEL1, 4, 0) self.listEL2 = QComboBox(self.createFrame) self.listEL2.addItems(elements) self.cfgrid.addWidget(self.listEL2, 4, 1) iSpellL = QLabel(self.createFrame, text="Initial Spells:") self.cfgrid.addWidget(iSpellL, 5, 0, 1, 2) self.iSpellOs = [] for i in range(6, 9): temp = QComboBox(self.createFrame) temp.addItems(spellList) temp2 = QComboBox(self.createFrame) temp2.addItems(spellList) self.cfgrid.addWidget(temp, i, 0, 1, 2) self.cfgrid.addWidget(temp2, i, 2, 1, 2) self.iSpellOs.extend([temp, temp2]) textL = QLabel(self.createFrame, text="Info:") self.cfgrid.addWidget(textL, 10, 0) self.textT = QTextEdit(self.createFrame) self.textT.setFixedSize(300, 100) self.cfgrid.addWidget(self.textT, 10, 1, 1, 5) self.lslevel = QLineEdit(self.createFrame) self.lslevel.setFixedSize(40, 20) self.lsSpellO = QComboBox(self.createFrame) self.lsSpellO.addItems(spellList) self.cfgrid.addWidget(self.lsSpellO, 1, 7) self.cfgrid.addWidget(self.lslevel, 1, 8) def addLS(self): """ Add a learned spell to the list, based on what was entered. """ print("Adding learned spell") chosenSpell = self.lsSpellO.currentText() if (int)(self.lslevel.text()) <= (int)(self.levelT.text()): popup("You cannot add a spell at an earlier level than the Persona's base level", "Critical") return if chosenSpell != "": print("Ok") self.lsdic[chosenSpell] = self.lslevel.text() self.listLS.addItem(chosenSpell + " at level " + self.lslevel.text()) self.lslevel.setText("") self.lsSpellO.setCurrentIndex(0) return popup("You must choose a spell", "Critical") def delLS(self): """ Remove the selected learned spell from the list """ print("Deleting learned spell") key = "" i = 0 while len(self.listLS.currentItem().text()) > i: if self.listLS.currentItem().text()[i] == " " and \ self.listLS.currentItem().text()[i+1] == "a" and \ self.listLS.currentItem().text()[i+2] == "t": # TODO EWWWWWW break key += self.listLS.currentItem().text()[i] i = i + 1 print(key) print(self.lsdic.pop(key)) self.listLS.takeItem(self.listLS.currentRow()) def loadPer(self, name): """ Load a certain Persona from file. :param str name: name of Persona to load """ data = json_reader.readOne(name, 'pers') self.nameT.setText(data["name"]) self.textT.setText(data["desc"]) self.strT.setText(data["stats"][0]) self.magT.setText(data["stats"][1]) self.endT.setText(data["stats"][2]) self.agiT.setText(data["stats"][3]) self.luckT.setText(data["stats"][4]) self.levelT.setText(data["level"]) self.arcO.setCurrentIndex( [self.arcO.itemText(i) for i in range(self.arcO.count())].index(data["arcana"]) ) self.listEL1.setCurrentIndex( [self.listEL1.itemText(i) for i in range(self.listEL1.count())].index(data["heritage"][0]) ) self.listEL2.setCurrentIndex( [self.listEL2.itemText(i) for i in range(self.listEL2.count())].index(data["heritage"][1]) ) self.slashO.setCurrentIndex( [self.slashO.itemText(i) for i in range(self.slashO.count())].index(data["resistance"][0]) ) self.strikeO.setCurrentIndex( [self.strikeO.itemText(i) for i in range(self.strikeO.count())].index(data["resistance"][1]) ) self.pierceO.setCurrentIndex( [self.pierceO.itemText(i) for i in range(self.pierceO.count())].index(data["resistance"][2]) ) self.fireO.setCurrentIndex( [self.fireO.itemText(i) for i in range(self.fireO.count())].index(data["resistance"][3]) ) self.iceO.setCurrentIndex( [self.iceO.itemText(i) for i in range(self.iceO.count())].index(data["resistance"][4]) ) self.elecO.setCurrentIndex( [self.elecO.itemText(i) for i in range(self.elecO.count())].index(data["resistance"][5]) ) self.windO.setCurrentIndex( [self.windO.itemText(i) for i in range(self.windO.count())].index(data["resistance"][6]) ) self.lightO.setCurrentIndex( [self.lightO.itemText(i) for i in range(self.lightO.count())].index(data["resistance"][7]) ) self.darkO.setCurrentIndex( [self.darkO.itemText(i) for i in range(self.darkO.count())].index(data["resistance"][8]) ) i = 0 for combobox in self.iSpellOs: combobox.setCurrentIndex( [combobox.itemText(j) for j in range(combobox.count()-1)].index(data["spellDeck"][i]) ) i += 1 self.lsdic = data["spellLearn"] self.listLS.clear() for spell, level in self.lsdic.items(): self.listLS.addItem(spell + " at level " + level) print("Loaded " + data["name"]) def edit(self): """ Switch to edit view, also loads the selected Persona. """ try: if self.listP.currentItem().text() != "": if self.createFrame and not popup("Override any unsaved changes?", "Warning"): return self.loadPer(self.listP.currentItem().text()) except AttributeError: # To initialize createFrame UI before load if self.listP.currentItem().text() != "": temp = self.listP.currentItem().text() self.buttonFrame.close() self.initUI(False) self.loadPer(temp) else: return self.createFrame.show() self.mainframe.center() print("Changed to edit frame") def save(self): """ Validate all info and save to file on disk. """ if os.path.exists(json_reader.buildPath("data/pers/"+self.nameT.text()+".json")): if not popup("Override existing Persona "+self.nameT.text()+"?", "Question"): return print("Saving") spellDeck = [] for combobox in self.iSpellOs: spellDeck.append(combobox.currentText()) stats = [self.strT.text(), self.magT.text(), self.endT.text(), self.agiT.text(), self.luckT.text()] res = [self.slashO.currentText(), self.strikeO.currentText(), self.pierceO.currentText(), self.fireO.currentText(), self.iceO.currentText(), self.elecO.currentText(), self.windO.currentText(), self.lightO.currentText(), self.darkO.currentText()] try: (int)(self.levelT.text()) (int)(self.strT.text()) (int)(self.magT.text()) (int)(self.endT.text()) (int)(self.agiT.text()) (int)(self.luckT.text()) except ValueError: popup("There is a number entry that isn't valid.\nEntries requiring numbers are:\nLEVEL\nSTR" "\nMAG\nEND\nAGI\nLUCK", "Critical") print("Not Saved") return if not (self.nameT.text() and not self.nameT.text().isspace()): popup("No name entered for your Persona. Name is a required field.", "Critical") print("No Name, not saved") return toWrite = Persona( self.nameT.text(), self.arcO.currentText(), self.levelT.text(), self.textT.toPlainText(), spellDeck, self.lsdic, stats, res, [self.listEL1.currentText(), self.listEL2.currentText()] ) json_reader.writeOne(toWrite, 'pers') temp = self.nameT.text() if (temp not in [self.listP.item(i).text() for i in range(self.listP.count())]): self.listP.addItem(temp) self.loadPer(temp) print("Saved Persona") def remove(self): """ Remove a created Persona from the list and delete the file on disk. """ if self.listP.currentItem().text() == "": return if not popup( "Are you certain you want to completely remove this Persona?\n(Cannot be undone)", "Warning" ): return print("Removing Persona " + self.listP.currentItem().text()) json_reader.deletePer(self.listP.currentItem().text()) self.listP.takeItem( [self.listP.item(i).text() for i in range(self.listP.count())].index( self.listP.currentItem().text()) ) def new(self): """ Open an empty Persona edit view. """ if self.createFrame and not popup("Override any unsaved changes?", "Warning"): return if self.createFrame: self.createFrame.close() self.buttonFrame.close() self.initUI(False) self.createFrame.show() self.mainframe.center() print("Created") def back(self): """ Return to the parent widget. """ print("Returned to main screen") self.mainframe.changeState(self.op)
class MainFrame(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): # Define buttons # Button to calculate lunar dates self.calculate_lunar = QPushButton('음력날짜 계산', self) self.calculate_lunar.clicked.connect(self.calculate_lunar_date) self.calculate_lunar.setGeometry(20, 260, 130, 35) self.calculate_lunar.setStatusTip('음력 날짜를 계산합니다.') self.calculate_lunar.setShortcut('Return') # Button to save ICS file to local directory self.ICS_save_button = QPushButton('ICS 파일 저장', self) self.ICS_save_button.clicked.connect(self.create_ics_file) self.ICS_save_button.setGeometry(175, 260, 130, 35) self.ICS_save_button.setStatusTip('ICS 파일을 컴퓨터에 저장합니다.') # Define labels # Define label for lunar date to convert lunar_date_text = QLabel(self) lunar_date_text.setText('계산할 음력 날짜') lunar_date_text.setGeometry(25, 15, 240, 25) # Define label for name of event event_name_text = QLabel(self) event_name_text.setText('이벤트 이름 입력') event_name_text.setGeometry(25, 50, 240, 25) # Define label for repetition event_name_text = QLabel(self) event_name_text.setText('몇년치나 할까요?') event_name_text.setGeometry(25, 85, 240, 25) # Define ListWidget to display results self.result_console = QListWidget(self) self.result_console.setGeometry(25, 118, 275, 133) self.result_console.setStatusTip('올해부터 매년 양력날짜가 출력됩니다.') # Define user input areas # Define lunar date to convert to solar date self.user_date_input = QLineEdit(self) self.user_date_input.setGeometry(180, 15, 120, 27) self.user_date_input.setAlignment(Qt.AlignCenter) self.user_date_input.setPlaceholderText('YYYYMMDD') self.user_date_input.setStatusTip('날짜를 YYYYMMDD로 입력하세요.') # Define name of event to use in ICS file self.user_event_name = QLineEdit(self) self.user_event_name.setGeometry(180, 50, 120, 27) self.user_event_name.setAlignment(Qt.AlignCenter) self.user_event_name.setPlaceholderText('이벤트 이름') self.user_event_name.setStatusTip('이벤트 이름을 입력하세요.') # Define number of years to convert self.user_repetition = QLineEdit(self) self.user_repetition.setGeometry(180, 84, 120, 27) self.user_repetition.setAlignment(Qt.AlignCenter) self.user_repetition.setText('10') self.user_repetition.setStatusTip('생성할 햇수를 입력하세요.') # Define size of main window self.setGeometry(200, 320, 325, 330) self.setWindowTitle('날짜') self.statusBar() self.show() # Define functions # Function to parse lunar date from openAPI website using user input def calculate_lunar_date(self): if len(self.user_date_input.text()) != 8: reply = QMessageBox.question(self, 'Error', "YYYYMMDD로 정확한 날짜를 입력해 주십시오.", QMessageBox.Close) return url = 'http://apis.data.go.kr/B090041/openapi/service/LrsrCldInfoService/getSolCalInfo' personal_key = 'UrEdHGIOCJr600RsRQ%2BnoL2wma3HT9JXmYn0uhHwmxImsnE2GHKYfn1RUfiEK9RIHXPJ3FBRnONxXMjplU3%2F7g%3D%3D' lunar_input = self.user_date_input.text() lunar_month = lunar_input[4:6] lunar_day = lunar_input[6:] repeat = int(self.user_repetition.text()) + 1 for i in range(0, repeat): lunar_year = int(lunar_input[:4]) + int(i) # Limit search at lunar year 2050. if lunar_year > 2050: break query_params = '?lunYear={}&lunMonth={}&lunDay={}&ServiceKey={}'.format( lunar_year, lunar_month, lunar_day, personal_key) session = XMLSession() r = session.get(url + query_params) solar_day = r.xml.xpath('//solDay', first=True).text solar_month = r.xml.xpath('//solMonth', first=True).text solar_year = r.xml.xpath('//solYear', first=True).text solar_week = r.xml.xpath('//solWeek', first=True).text solar_date_text = ' {}년 {}월 {}일 {}요일 '.format( solar_year, solar_month, solar_day, solar_week) QListWidgetItem(solar_date_text, self.result_console) def create_ics_file(self): event_name = self.user_event_name.text() ics_content = 'BEGIN:VCALENDAR\nVERSION:2.0\nCALSCALE:GREGORIAN\nBEGIN:VTIMEZONE\nTZID:Asia/Tokyo\n' \ 'TZURL:http://tzurl.org/zoneinfo-outlook/Asia/Tokyo\nX-LIC-LOCATION:Asia/Tokyo\n' \ 'BEGIN:STANDARD\nTZOFFSETFROM:+0900\nTZOFFSETTO:+0900\nTZNAME:JST\n' \ 'DTSTART:19700101T000000\nEND:STANDARD\nEND:VTIMEZONE\n' if len(self.user_event_name.text()) == 0: reply = QMessageBox.question(self, 'Error', "이벤트 이름을 입력해 주십시오.", QMessageBox.Close) return elif self.result_console.count() == 0: reply = QMessageBox.question(self, 'Error', "날짜 계산을 먼저 해주십시오.", QMessageBox.Close) return # Iterate through QListWidget items: https://stackoverflow.com/a/34479509 converted_dates = [ str(self.result_console.item(i).text()) for i in range(self.result_console.count()) ] for i in converted_dates: # Extract digits from string: https://stackoverflow.com/a/26825833 date_string = (''.join(filter(str.isdigit, i))) event_string = 'BEGIN:VEVENT\nDTSTAMP:20180802T115053z\nDTSTART;TZID="Asia/Tokyo":{0}T120000' \ '\nDTEND;TZID="Asia/Tokyo":{0}T120000\nSUMMARY:{1}\nBEGIN:VALARM\n' \ 'TRIGGER:-PT14H\nREPEAT:1\nACTION:DISPLAY\nDESCRIPTION:Reminder\nEND:VALARM\nEND:VEVENT\n' ics_content += event_string.format(date_string, event_name) ics_content += 'END:VCALENDAR' # This program cannot read existing .ics files, so if user creates a new ics event with existing file name, # the program would crash. new_ics = open(event_name.replace(' ', '') + '.ics', 'w') new_ics.write(ics_content) new_ics.close() success = QMessageBox.question(self, 'Success', "ICS 파일 생성 완료!", QMessageBox.Close)
class Window(QMainWindow): def __init__(self): super(Window, self).__init__() self.lastProjectDirectory = None self.view = None self.items = dict() self.loadSettings() self.setWindowTitle("2D Tagger") self.createActions() self.createMenus() self.createFileList() self.createContainer() self.createStatusBar() def loadSettings(self): try: with io.open(Path(__file__).parent / 'app.json', 'r') as f: data = json.load(f) if 'lastProjectDirectory' in data: self.lastProjectDirectory = data['lastProjectDirectory'] except: pass def saveSettings(self): data = dict() data['lastProjectDirectory'] = self.lastProjectDirectory with io.open(Path(__file__).parent / 'app.json', 'w') as f: json.dump(data, f, indent=' ') def createActions(self): # root = QFileInfo(__file__).absolutePath() self.openAct = QAction( # QIcon(root + '/icons/open.png'), "&Open", self, shortcut=QKeySequence.Open, statusTip="Open project", triggered=self.openProject) self.closeAct = QAction( # QIcon(root + '/icons/close.png'), "&Close", self, shortcut=QKeySequence.Close, statusTip="Close project", triggered=self.closeProject, enabled=False) self.exitAct = QAction( # QIcon(root + '/icons/quit.png'), "&Quit", self, shortcut=QKeySequence.Quit, statusTip="Close the application", triggered=self.close) self.aboutAct = QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) def createMenus(self): fileMenu = self.menuBar().addMenu("&File") fileMenu.addAction(self.openAct) fileMenu.addAction(self.closeAct) fileMenu.addSeparator() fileMenu.addAction(self.exitAct) self.menuBar().addSeparator() helpMenu = self.menuBar().addMenu("&Help") helpMenu.addAction(self.aboutAct) def createFileList(self): self.files = QListWidget() self.files.setSelectionMode(QAbstractItemView.SingleSelection) self.files.setSortingEnabled(False) self.files.itemSelectionChanged.connect(self.onSelect) self.files.itemDoubleClicked.connect(self.onToggle) self.files.setEnabled(False) dock = QDockWidget("Images", self) dock.setAllowedAreas(Qt.LeftDockWidgetArea) dock.setFixedWidth(320) dock.setFeatures(QDockWidget.NoDockWidgetFeatures) dock.setWidget(self.files) self.addDockWidget(Qt.LeftDockWidgetArea, dock) def createContainer(self): self.container = QWidget(self) self.container.setStyleSheet("View { background: black; }") self.container.setLayout(QVBoxLayout()) self.setCentralWidget(self.container) def createStatusBar(self): self.statusBar().showMessage("Initialized") def enableProjectActions(self, enabled): actions = [self.closeAct, self.files] for action in actions: action.setEnabled(enabled) def closeEvent(self, event): event.accept() def openProject(self, path=None): if not path: path = QFileDialog.getExistingDirectory( self, "Choose image directory", dir=self.lastProjectDirectory) if path: self.closeProject() self.view = View(self) self.view.previous.connect(self.onPrevious) self.view.next.connect(self.onNext) self.container.layout().addWidget(self.view) filename = Path(path) / "items.json" if filename.exists(): with io.open(filename, 'r') as f: self.items = json.load(f) else: self.items = dict() for filename in find_images(Path(path)): if filename in self.items: continue self.items[filename] = dict({"active": True}) self.refreshItems() self.files.setItemSelected(self.files.item(0), True) self.enableProjectActions(True) self.lastProjectDirectory = path self.saveProject() self.saveSettings() def saveProject(self): if not self.view: return with io.open(Path(self.lastProjectDirectory) / "items.json", 'w') as f: json.dump(self.items, f, indent=' ') def closeProject(self): self.enableProjectActions(False) if self.view: self.container.layout().removeWidget(self.view) self.view.close() self.view = None self.items = dict() self.refreshItems() def selection(self): selection = self.files.selectedItems() if len(selection) > 0: return selection[0].text() return None def refreshItems(self): filenames = sorted(self.items.keys()) for i in range(len(filenames)): filename = filenames[i] item = self.items[filename] file = self.files.item(i) if not file: file = QListWidgetItem(filenames[i]) self.files.insertItem(i, file) if item['active']: file.setTextColor(QColor.fromRgbF(0.0, 0.5, 0.0)) else: file.setTextColor(QColor.fromRgbF(0.5, 0.0, 0.0)) while self.files.count() > len(filenames): self.files.takeItem(len(filenames)) @Slot() def onToggle(self, item): self.items[ item.text()]['active'] = not self.items[item.text()]['active'] self.refreshItems() self.saveProject() @Slot() def onSelect(self): selection = self.selection() if self.view: self.view.save() if selection: self.view.load(Path(self.lastProjectDirectory) / selection) @Slot() def onPrevious(self): if self.files.count() == 0: return index = 0 selection = self.selection() if selection: for i in range(self.files.count()): item = self.files.item(i) if item.text() == selection: index = i - 1 break if index < 0: index = self.files.count() - 1 self.files.setItemSelected(self.files.item(index), True) @Slot() def onNext(self): if self.files.count() == 0: return index = 0 selection = self.selection() if selection: for i in range(self.files.count()): item = self.files.item(i) if item.text() == selection: index = i + 1 break if index >= self.files.count(): index = 0 self.files.setItemSelected(self.files.item(index), True) @Slot(str) def showMessage(self, message): self.statusBar().showMessage(message) def about(self): QMessageBox.about( self, "About Application", "The <b>2D Tagger</b> can load images, manually tag/label images and export result." )
def _remove_addr(self, qlist: QListWidget, addr): for i in range(qlist.count()): qitem = qlist.item(i) if int(qitem.text(), 16) == addr: qlist.takeItem(i) return
class QtEpsInfo(QtWidgets.QWidget, Ui_EpsInfo): def __init__(self, owner): super(self.__class__, self).__init__() Ui_EpsInfo.__init__(self) self.setupUi(self) self.owner = weakref.ref(owner) self.epsListWidget = QListWidget() self.epsListWidget.setFlow(self.epsListWidget.LeftToRight) self.epsListWidget.setWrapping(True) self.epsListWidget.setFrameShape(self.epsListWidget.NoFrame) self.epsListWidget.setResizeMode(self.epsListWidget.Adjust) self.epsListWidget.itemClicked.connect(self.SelectEps) self.gridLayout_2.addWidget(self.epsListWidget, 1, 0) self.closeFlag = self.__class__.__name__ self.bookId = "" self.loadingForm = QtLoading(self) self.setWindowTitle("章节列表") self.greed = QColor(18, 161, 130) self.blue = QColor(97, 154, 195) self.white = QColor(0, 0, 0, 0) def OpenEpsInfo(self, bookId): self.show() self.loadingForm.show() self.bookId = bookId self.epsListWidget.clear() if bookId not in BookMgr().books: self.owner().qtTask.AddHttpTask(lambda x: BookMgr().AddBookById(self.bookId, x), self.OpenBookInfoBack, cleanFlag=self.closeFlag) else: self.owner().qtTask.AddHttpTask(lambda x: BookMgr().AddBookEpsInfo(self.bookId, x), self.OpenEpsInfoBack, cleanFlag=self.closeFlag) def OpenBookInfoBack(self, msg): if msg == Status.Ok: self.owner().qtTask.AddHttpTask(lambda x: BookMgr().AddBookEpsInfo(self.bookId, x), self.OpenEpsInfoBack, cleanFlag=self.closeFlag) else: self.loadingForm.close() def OpenEpsInfoBack(self, msg): self.loadingForm.close() self.epsListWidget.clear() if msg == Status.Ok: self.UpdateEpsInfo() return def UpdateEpsInfo(self): self.epsListWidget.clear() info = BookMgr().books.get(self.bookId) if not info: return downloadEpsId = self.owner().downloadForm.GetDownloadEpsId(self.bookId) for index, epsInfo in enumerate(info.eps): label = QLabel(epsInfo.title) label.setContentsMargins(20, 10, 20, 10) item = QListWidgetItem(self.epsListWidget) item.setSizeHint(label.sizeHint()) if index in downloadEpsId: item.setBackground(self.greed) else: item.setBackground(self.white) self.epsListWidget.setItemWidget(item, label) def SelectEps(self, item): if item.background().color() == self.greed: return elif item.background().color() == self.blue: item.setBackground(self.white) else: item.setBackground(self.blue) return def SelectAll(self): for i in range(self.epsListWidget.count()): item = self.epsListWidget.item(i) if item.background().color() == self.greed: continue item.setBackground(self.blue) return def CancleSelect(self): for i in range(self.epsListWidget.count()): item = self.epsListWidget.item(i) if item.background().color() == self.greed: continue item.setBackground(self.white) return def StartDownload(self): downloadIds = [] for i in range(self.epsListWidget.count()): item = self.epsListWidget.item(i) if item.background().color() == self.blue: downloadIds.append(i) if not downloadIds: return self.owner().downloadForm.AddDownload(self.bookId, downloadIds) self.UpdateEpsInfo() return
def create_file_list(self, path, selected=None, up=False, update_list=None): '''Return a file list with objects populated from files/dirs in given path. path -- path of directory to create list elements selected -- name of the cwd to select in parent list up -- create a link to one level up update_list -- (QListWidget) update the given list with new path elements rather than returning a new list ''' if not update_list: file_list = QListWidget(self) else: update_list.clear() file_list = update_list if not path and not update_list: # if empty return file_list elif not path and update_list: if len(self.drives) > 0: for letter in self.drives: try: icon = QIcon(convert_to_icon(letter)) except Exception as e: print(e) traceback.print_tb(e.__traceback__) update_list.addItem(QListWidgetItem(icon, letter)) else: update_list.addItem(QListWidgetItem('((root))')) return # cache read contents of path to save some time and processing power? # TODO: could maybe also save actual QListWIdgetItems? to save on Icon creation time # could also copy QIcons to cached_dirs = {... 'dir_icons': [], 'file_icons': []} if not any(c['path'] == path for c in self.cached_dirs): files, dirs, dirpath = get_files(path) cache = { 'path': dirpath, 'dirs': dirs.copy(), 'files': files.copy() } self.cached_dirs.append(cache) # dirs cache limit if len(self.cached_dirs) > 15: del self.cached_dirs[0] else: for c in self.cached_dirs: if c['path'] == path: files, dirs, dirpath = c['files'].copy(), c['dirs'].copy( ), c['path'] if up: dirs.insert(0, os.path.abspath(os.path.join(path))) selected_index = -1 if len(files) > 0: for i in range(len(files)): try: icon = QIcon( convert_to_icon(os.path.join(dirpath, files[i]))) except Exception as e: print(e) traceback.print_tb(e.__traceback__) icon = QIcon() files[i] = QListWidgetItem(icon, files[i]) if len(dirs) > 0: for i in range(len(dirs)): if dirs[i] == selected: selected_index = i try: icon = QIcon( convert_to_icon( os.path.abspath(os.path.join(dirpath, dirs[i])))) except Exception as e: print(e) traceback.print_tb(e.__traceback__) icon = QIcon() dirs[i] = QListWidgetItem(icon, dirs[i]) if up: dirs[0].setText('..') if len(dirs) > 0: for d in dirs: file_list.addItem(d) if len(files) > 0: for f in files: file_list.addItem(f) if len(dirs) == 0 and len(files) == 0: file_list.addItem(QListWidgetItem('((empty))')) if selected_index >= 0: file_list.item(selected_index).setSelected(True) file_list.scrollToItem(file_list.item(selected_index)) else: file_list.item(0).setSelected(True) if update_list: return return file_list
class QtBookInfo(QtWidgets.QWidget, Ui_BookInfo): def __init__(self, owner): super(self.__class__, self).__init__() Ui_BookInfo.__init__(self) self.setupUi(self) self.owner = weakref.ref(owner) self.loadingForm = QtLoading(self) self.bookId = "" self.url = "" self.path = "" self.bookName = "" self.lastEpsId = -1 self.msgForm = QtBubbleLabel(self) self.picture.installEventFilter(self) self.title.setGeometry(QRect(328, 240, 329, 27 * 4)) self.title.setWordWrap(True) self.title.setAlignment(Qt.AlignTop) self.title.setContextMenuPolicy(Qt.CustomContextMenu) self.title.customContextMenuRequested.connect(self.CopyTitle) # self.autor.setContextMenuPolicy(Qt.CustomContextMenu) # self.autor.customContextMenuRequested.connect(self.OpenAutor) layouy = self.horizontalLayout_4 self.autorList = QtCategoryList(self) layouy.addWidget(QLabel("作者:")) layouy.addWidget(self.autorList) self.autorList.itemClicked.connect(self.ClickTagsItem) self.description.setContextMenuPolicy(Qt.CustomContextMenu) self.description.customContextMenuRequested.connect( self.CopyDescription) self.description.setGeometry(QRect(328, 240, 329, 27 * 4)) self.description.setWordWrap(True) self.description.setAlignment(Qt.AlignTop) # self.categories.setGeometry(QRect(328, 240, 329, 27 * 4)) # self.categories.setWordWrap(True) # self.categories.setAlignment(Qt.AlignTop) layouy = self.horizontalLayout_6 self.categoriesList = QtCategoryList(self) layouy.addWidget(QLabel("分类:")) layouy.addWidget(self.categoriesList) self.categoriesList.itemClicked.connect(self.ClickCategoriesItem) # self.tags.setGeometry(QRect(328, 240, 329, 27 * 4)) # self.tags.setWordWrap(True) # self.tags.setAlignment(Qt.AlignTop) layouy = self.horizontalLayout_7 self.tagsList = QtCategoryList(self) layouy.addWidget(QLabel("Tags:")) layouy.addWidget(self.tagsList) self.tagsList.itemClicked.connect(self.ClickTagsItem) self.epsListWidget = QListWidget(self) self.epsListWidget.setFlow(self.epsListWidget.LeftToRight) self.epsListWidget.setWrapping(True) self.epsListWidget.setFrameShape(self.epsListWidget.NoFrame) self.epsListWidget.setResizeMode(self.epsListWidget.Adjust) self.epsLayout.addWidget(self.epsListWidget) self.listWidget = QtBookList(self, self.__class__.__name__) self.listWidget.InitUser(self.LoadNextPage) self.listWidget.doubleClicked.connect(self.OpenCommentInfo) self.childrenListWidget = QtBookList(None, self.__class__.__name__) self.childrenListWidget.InitUser(self.LoadChildrenNextPage) self.childrenWidget = QtWidgets.QWidget() layout = QHBoxLayout(self.childrenWidget) label = QLabel() label.setMinimumWidth(100) layout.addWidget(label) layout3 = QVBoxLayout() layout2 = QHBoxLayout() self.commentLine2 = QLineEdit() self.commentButton2 = QPushButton("回复") self.commentButton2.clicked.connect(self.SendCommentChildren) layout2.addWidget(self.commentLine2) layout2.addWidget(self.commentButton2) layout3.addLayout(layout2) layout3.addWidget(self.childrenListWidget) layout.addLayout(layout3) self.commentLayout.addWidget(self.listWidget) layout = QHBoxLayout() self.commentLine = QLineEdit() layout.addWidget(self.commentLine) self.commentButton = QPushButton("发送评论") layout.addWidget(self.commentButton) self.commentLayout.addLayout(layout, 1, 0) self.commentButton.clicked.connect(self.SendComment) # self.stackedWidget.addWidget(self.qtReadImg) self.epsListWidget.clicked.connect(self.OpenReadImg) self.closeFlag = self.__class__.__name__ + "-close" # 切换book时,取消加载 def closeEvent(self, a0: QtGui.QCloseEvent) -> None: if self.stackedWidget.currentIndex() == 1: self.stackedWidget.setCurrentIndex(0) self.owner().qtReadImg.AddHistory() self.LoadHistory() a0.ignore() else: a0.accept() def CopyTitle(self): clipboard = QApplication.clipboard() clipboard.setText(self.title.text()) self.msgForm.ShowMsg("复制标题") return # def OpenAutor(self): # text = self.autor.text() # self.owner().userForm.listWidget.setCurrentRow(0) # self.owner().searchForm.searchEdit.setText(text) # self.owner().searchForm.Search() # return def Clear(self): self.stackedWidget.setCurrentIndex(0) self.owner().qtTask.CancelTasks(self.closeFlag) self.epsListWidget.clear() self.ClearCommnetList() def CopyDescription(self): clipboard = QApplication.clipboard() clipboard.setText(self.description.text()) self.msgForm.ShowMsg("复制描述") return def OpenBook(self, bookId): self.bookId = bookId self.setWindowTitle(self.bookId) # if self.bookId in self.owner().downloadForm.downloadDict: # self.download.setEnabled(False) # else: # self.download.setEnabled(True) self.Clear() self.show() self.loadingForm.show() self.owner().qtTask.AddHttpTask( lambda x: BookMgr().AddBookById(bookId, x), self.OpenBookBack) def close(self): super(self.__class__, self).close() def OpenBookBack(self, msg): self.loadingForm.close() self.listWidget.UpdatePage(1, 1) self.childrenListWidget.UpdatePage(1, 1) self.childrenListWidget.UpdateState() self.listWidget.UpdateState() self.categoriesList.clear() self.tagsList.clear() self.autorList.clear() info = BookMgr().books.get(self.bookId) if msg == Status.Ok and info: # self.autor.setText(info.author) self.autorList.AddItem(info.author) self.title.setText(info.title) self.bookName = info.title self.description.setText(info.description) self.isFinished.setText("完本" if info.finished else "未完本") for name in info.categories: self.categoriesList.AddItem(name) # self.categories.setText(','.join(info.categories)) # self.tags.setText(','.join(info.tags)) for name in info.tags: self.tagsList.AddItem(name) self.likes.setText(str(info.totalLikes)) self.views.setText(str(info.totalViews)) if info.isFavourite: self.favorites.setEnabled(False) else: self.favorites.setEnabled(True) self.picture.setText("图片加载中...") fileServer = info.thumb.get("fileServer") path = info.thumb.get("path") name = info.thumb.get("originalName") self.url = fileServer self.path = path timeArray, day = ToolUtil.GetDateStr(info.updated_at) self.updateTick.setText(str(day) + "天前更新") if config.IsLoadingPicture: self.owner().qtTask.AddDownloadTask( fileServer, path, completeCallBack=self.UpdatePicture, cleanFlag=self.closeFlag) self.owner().qtTask.AddHttpTask(lambda x: Server().Send( req.GetComments(self.bookId), bakParam=x), self.GetCommnetBack, cleanFlag=self.closeFlag) self.owner().qtTask.AddHttpTask( lambda x: BookMgr().AddBookEpsInfo(self.bookId, x), self.GetEpsBack, cleanFlag=self.closeFlag) self.startRead.setEnabled(False) else: # QtWidgets.QMessageBox.information(self, '加载失败', msg, QtWidgets.QMessageBox.Yes) self.msgForm.ShowError(msg) self.hide() return def UpdatePicture(self, data, status): if status == Status.Ok: pic = QtGui.QPixmap() pic.loadFromData(data) pic.scaled(self.picture.size(), QtCore.Qt.KeepAspectRatio) self.picture.setPixmap(pic) # self.picture.setScaledContents(True) self.update() else: self.picture.setText("图片加载失败") return # 加载评论 def GetCommnetBack(self, data): try: self.loadingForm.close() self.listWidget.UpdateState() msg = json.loads(data) if msg.get("code") == 200: comments = msg.get("data", {}).get("comments", {}) topComments = msg.get("data", {}).get("topComments", []) page = int(comments.get("page", 1)) pages = int(comments.get("pages", 1)) limit = int(comments.get("limit", 1)) self.listWidget.UpdatePage(page, pages) total = comments.get("total", 0) self.tabWidget.setTabText(1, "评论({})".format(str(total))) if page == 1: for index, info in enumerate(topComments): floor = "置顶" content = info.get("content") name = info.get("_user", {}).get("name") avatar = info.get("_user", {}).get("avatar", {}) createdTime = info.get("created_at") commentsCount = info.get("commentsCount") commnetId = info.get('_id') likesCount = info.get("likesCount") self.listWidget.AddUserItem(commnetId, commentsCount, likesCount, content, name, createdTime, floor, avatar.get("fileServer"), avatar.get("path"), avatar.get("originalName")) for index, info in enumerate(comments.get("docs")): floor = total - ((page - 1) * limit + index) content = info.get("content") name = info.get("_user", {}).get("name") avatar = info.get("_user", {}).get("avatar", {}) createdTime = info.get("created_at") commentsCount = info.get("commentsCount") commnetId = info.get('_id') likesCount = info.get("likesCount") self.listWidget.AddUserItem(commnetId, commentsCount, likesCount, content, name, createdTime, floor, avatar.get("fileServer"), avatar.get("path"), avatar.get("originalName")) return except Exception as es: Log.Error(es) def GetEpsBack(self, st): if st == Status.Ok: self.UpdateEpsData() self.lastEpsId = -1 self.LoadHistory() return return def UpdateEpsData(self): self.epsListWidget.clear() info = BookMgr().books.get(self.bookId) if not info: return self.startRead.setEnabled(True) downloadIds = self.owner().downloadForm.GetDownloadCompleteEpsId( self.bookId) for index, epsInfo in enumerate(info.eps): label = QLabel(epsInfo.title) label.setContentsMargins(20, 10, 20, 10) item = QListWidgetItem(self.epsListWidget) if index in downloadIds: item.setBackground(QColor(18, 161, 130)) else: item.setBackground(QColor(0, 0, 0, 0)) item.setSizeHint(label.sizeHint()) self.epsListWidget.setItemWidget(item, label) self.tabWidget.setTabText(0, "章节({})".format(str(len(info.eps)))) return def AddDownload(self): self.owner().epsInfoForm.OpenEpsInfo(self.bookId) # if self.owner().downloadForm.AddDownload(self.bookId): # QtBubbleLabel.ShowMsgEx(self, "添加下载成功") # else: # QtBubbleLabel.ShowMsgEx(self, "已在下载列表") # self.download.setEnabled(False) def AddFavority(self): User().AddAndDelFavorites(self.bookId) QtBubbleLabel.ShowMsgEx(self, "添加收藏成功") self.favorites.setEnabled(False) def LoadNextPage(self): self.loadingForm.show() self.owner().qtTask.AddHttpTask(lambda x: Server( ).Send(req.GetComments(self.bookId, self.listWidget.page + 1), bakParam=x), self.GetCommnetBack, cleanFlag=self.closeFlag) return def OpenReadImg(self, modelIndex): index = modelIndex.row() self.OpenReadIndex(index) def OpenReadIndex(self, index): item = self.epsListWidget.item(index) if not item: return widget = self.epsListWidget.itemWidget(item) if not widget: return name = widget.text() self.hide() self.owner().qtReadImg.OpenPage(self.bookId, index, name) # self.stackedWidget.setCurrentIndex(1) def StartRead(self): if self.lastEpsId >= 0: self.OpenReadIndex(self.lastEpsId) else: self.OpenReadIndex(0) return def LoadHistory(self): info = self.owner().historyForm.GetHistory(self.bookId) if not info: self.startRead.setText("观看第{}章".format(str(1))) return if self.lastEpsId == info.epsId: self.startRead.setText("观看第{}章".format(str(self.lastEpsId + 1))) return if self.lastEpsId >= 0: item = self.epsListWidget.item(self.lastEpsId) if item: downloadIds = self.owner( ).downloadForm.GetDownloadCompleteEpsId(self.bookId) if self.lastEpsId in downloadIds: item.setBackground(QColor(18, 161, 130)) else: item.setBackground(QColor(0, 0, 0, 0)) item = self.epsListWidget.item(info.epsId) if not item: return item.setBackground(QColor(238, 162, 164)) self.epsListWidget.update() self.lastEpsId = info.epsId self.startRead.setText("观看第{}章".format(str(self.lastEpsId + 1))) def ClickCategoriesItem(self, item): text = item.text() self.owner().userForm.listWidget.setCurrentRow(1) self.owner().searchForm.searchEdit.setText("") self.owner().searchForm.OpenSearchCategories(text) return def ClickTagsItem(self, item): text = item.text() self.owner().userForm.listWidget.setCurrentRow(1) self.owner().searchForm.searchEdit.setText(text) self.owner().searchForm.Search() return def SendComment(self): data = self.commentLine.text() if not data: return self.commentLine.setText("") self.loadingForm.show() self.owner().qtTask.AddHttpTask(lambda x: Server().Send( req.SendComment(self.bookId, data), bakParam=x), callBack=self.SendCommentBack) def SendCommentBack(self, msg): try: data = json.loads(msg) if data.get("code") == 200: self.ClearCommnetList() self.owner().qtTask.AddHttpTask(lambda x: Server().Send( req.GetComments(self.bookId), bakParam=x), self.GetCommnetBack, cleanFlag=self.closeFlag) else: self.loadingForm.close() QtBubbleLabel.ShowErrorEx(self, data.get("message", "错误")) self.commentLine.setText("") except Exception as es: self.loadingForm.close() Log.Error(es) def OpenCommentInfo(self, modelIndex): index = modelIndex.row() item = self.listWidget.item(index) if not item: return widget = self.listWidget.itemWidget(item) if not widget: return self.childrenListWidget.clear() self.childrenListWidget.UpdatePage(1, 1) self.childrenListWidget.UpdateState() if self.childrenListWidget.parentId == index: # self.childrenWidget.hide() self.childrenWidget.setParent(None) widget.gridLayout.removeWidget(self.childrenWidget) self.childrenListWidget.parentId = -1 item.setSizeHint(widget.sizeHint()) return if self.childrenListWidget.parentId >= 0: item2 = self.listWidget.item(self.childrenListWidget.parentId) widget2 = self.listWidget.itemWidget(item2) self.childrenWidget.setParent(None) widget2.gridLayout.removeWidget(self.childrenWidget) self.childrenListWidget.parentId = -1 item2.setSizeHint(widget2.sizeHint()) self.loadingForm.show() self.owner().qtTask.AddHttpTask(lambda x: Server().Send( req.GetCommentsChildrenReq(widget.id), bakParam=x), self.LoadCommentInfoBack, backParam=index, cleanFlag=self.closeFlag) def LoadCommentInfoBack(self, msg, index): try: self.loadingForm.close() item = self.listWidget.item(index) if not item: return widget = self.listWidget.itemWidget(item) if not widget: return self.childrenListWidget.UpdateState() data = json.loads(msg) self.childrenListWidget.parentId = index widget.gridLayout.addWidget(self.childrenWidget, 1, 0, 1, 1) if data.get("code") == 200: comments = data.get("data", {}).get("comments", {}) page = int(comments.get("page", 1)) total = int(comments.get("total", 1)) pages = int(comments.get("pages", 1)) limit = int(comments.get("limit", 1)) self.childrenListWidget.UpdatePage(page, pages) for index, info in enumerate(comments.get("docs")): floor = total - ((page - 1) * limit + index) content = info.get("content") name = info.get("_user", {}).get("name") avatar = info.get("_user", {}).get("avatar", {}) createdTime = info.get("created_at") commentsCount = info.get("commentsCount") likesCount = info.get("likesCount") commnetId = info.get('_id') self.childrenListWidget.AddUserItem( commnetId, commentsCount, likesCount, content, name, createdTime, floor, avatar.get("fileServer"), avatar.get("path"), avatar.get("originalName")) pass self.listWidget.scrollToItem( item, self.listWidget.ScrollHint.PositionAtTop) size = self.listWidget.size() item.setSizeHint(size) except Exception as es: Log.Error(es) def SendCommentChildren(self): data = self.commentLine2.text() if not data: return index = self.childrenListWidget.parentId item = self.listWidget.item(index) if not item: return widget = self.listWidget.itemWidget(item) if not widget: return self.commentLine2.setText("") commentId = widget.id self.loadingForm.show() self.childrenListWidget.clear() self.owner().qtTask.AddHttpTask(lambda x: Server().Send( req.SendCommentChildrenReq(commentId, data), bakParam=x), callBack=self.SendCommentChildrenBack, backParam=index) def SendCommentChildrenBack(self, msg, index): try: item = self.listWidget.item(index) if not item: self.loadingForm.close() return widget = self.listWidget.itemWidget(item) if not widget: self.loadingForm.close() return data = json.loads(msg) if data.get("code") == 200: self.owner().qtTask.AddHttpTask(lambda x: Server().Send( req.GetCommentsChildrenReq(widget.id), bakParam=x), self.LoadCommentInfoBack, backParam=index, cleanFlag=self.closeFlag) else: self.loadingForm.close() QtBubbleLabel.ShowErrorEx(self, data.get("message", "错误")) self.commentLine.setText("") except Exception as es: self.loadingForm.close() Log.Error(es) def LoadChildrenNextPage(self): index = self.childrenListWidget.parentId item = self.listWidget.item(index) if not item: return widget = self.listWidget.itemWidget(item) if not widget: return self.loadingForm.show() self.owner().qtTask.AddHttpTask( lambda x: Server().Send(req.GetCommentsChildrenReq( widget.id, self.childrenListWidget.page + 1), bakParam=x), self.LoadCommentInfoBack, backParam=index, cleanFlag=self.closeFlag) return def ClearCommnetList(self): if self.childrenListWidget.parentId >= 0: item2 = self.listWidget.item(self.childrenListWidget.parentId) widget2 = self.listWidget.itemWidget(item2) self.childrenWidget.setParent(None) widget2.gridLayout.removeWidget(self.childrenWidget) self.childrenListWidget.parentId = -1 item2.setSizeHint(widget2.sizeHint()) self.childrenListWidget.clear() self.listWidget.clear() def eventFilter(self, obj, event): if event.type() == QEvent.MouseButtonPress: if event.button() == Qt.LeftButton: if obj.pixmap() and not obj.text(): QtImgMgr().ShowImg(obj.pixmap()) return True else: return False else: return super(self.__class__, self).eventFilter(obj, event)
class MainWidget(QWidget): # CONSTANTS EMPTY_STRING = "" # TOGGLE BUTTON CONSTANTS BUTTON_CLOSED_ICON_PATH = 'resources/menu_closed_button_icon.png' BUTTON_OPENED_ICON_PATH = 'resources/menu_opened_button_icon.png' TOOGLE_BUTTON_CSS_PROPERTY = "QPushButton {background-color: rgb(1,150,250); border: none ; qproperty-iconSize: 80px}" CURRENT_PATH_LINE_EDIT_PROPERTY = "QLineEdit {background-color: rgba(240, 240, 240, 1);}" TOOGLE_CLOSED_COLOR = "background-color: rgb(1,150,250);" TOOGLE_OPENED_COLOR = "background-color: rgba(44, 53, 57, 0.2);" WHITE = "background-color: rgb(255, 255, 255);" FRAME_BUTTON_STYLE = "background-color: rgb(0, 191, 255); color: rgb(255, 255, 255);" FRAME_LINE_EDIT_STYLE = "background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);" FRAME_LABEL_STYLE = "QLabel { background-color : rgba(44, 53, 57, 0); }" SEARCH_ICON_STYLE = "QPushButton {background-color: rgb(1,150,250);}" BACK_ICON_STYLE = "QPushButton {background-color: rgb(1,150,250);} QPushButton:pressed {background-color: rgb(40,170,250);}" WIDTH = 1440 HEIGHT = 900 # Size of the operations widget buttons OPERATION_BUTTON_WIDTH = 40 OPERATION_BUTTON_HEIGHT = 40 FILES_LIST_VIEW_WIDTH = 820 FILES_LIST_VIEW_HEIGHT = 680 TOGGLE_BUTTON_ANIMATION_DURATION = 200 RIGHT_MENU_ANIMATION_DURATION = 250 # ICONS PATHS # Actions icons ADD_FILE_ICON_PATH = "resources/add_file_icon.png" ADD_DIRECTORY_ICON_PATH = "resources/add_directory_icon.png" COPY_ELEMENT_ICON_PATH = "resources/copy_element_icon.png" MOVE_ELEMENT_ICON_PATH = "resources/move_element_icon.png" DELETE_ELEMENT_ICON_PATH = "resources/delete_element_icon.png" SEARCH_ICON_PATH = "resources/search_icon_white.png" CREATE_ARCHIVE_ICON_PATH = "resources/create_archive_icon.png" UNARCHIVE_FILE_ICON_PATH = "resources/unarchive_file_icon.png" RENAME_ELEMENT_ICON_PATH = "resources/rename_icon_white.png" BACK_ICON_PATH = "resources/back_icon.png" # Elements icons FILE_ICON_PATH = "resources/file_icon.png" FOLDER_ICON_PATH = "resources/folder_icon.png" ZIP_ICON_PATH = "resources/zip_icon.png" # Tooltips COPY_TOOLTIP = "Copy files / folders" MOVE_TOOLTIP = "Move files / folders" DELETE_TOOLTIP = "Delete files / folders" ARCHIVE_TOOLTIP = "Archive files / folders" UNARCHIVE_TOOLTIP = "Unarchive files / folders" CREATE_FILE_TOOLTIP = "Create a new text file" CREATE_DIRECTORY_TOOLTIP = "Create a new folder" RENAME_TOOLTIP = "Rename a file / folder" BACK_TOOLTIP = "Move up one directory" # Buttons name COPY = "Copy" MOVE = "Move" DELETE = "Delete" ARCHIVE = "Archive" UNARCHIVE = "Unarchive" RENAME = "Rename" CREATE_FILE = "Create file" CREATE_FOLDER = "Create folder" # Labels SELECTED_ITEMS_TEXT = "Selected items:" ARCHIVE_NAME_TEXT = "Archive name:" CREATE_FILE_NAME_TEXT = "File name:" CREATE_FOLDER_NAME_TEXT = "Folder name:" RENAME_ELEMENT_TEXT = "New name:" def __init__(self, parent, model, controller): super(MainWidget, self).__init__(parent) self._model = model self._controller = controller # FILES LIST VIEW self.filesListView = FilesListView(self.FILES_LIST_VIEW_WIDTH, self.FILES_LIST_VIEW_HEIGHT, self._model, self._controller, self) self.filesListView.move(230, 120) # TREE VIEW FOR SYSTEM DIRECTORY HIERARCHY self.treeView = TreeView(self._model, self._controller, self) self.treeView.setFixedSize(200, 820) self.treeView.move(0, 60) # DISC SELECTION COMBO BOX self.discSelectionComboBox = QComboBox(self) self.discSelectionComboBox.setFixedSize(100, 30) self.discSelectionComboBox.move(230, 60) self.discSelectionComboBox.addItems(self._model.combo_box_list) # CONNECT WIDGETS TO CONTROLLER self.discSelectionComboBox.currentTextChanged.connect( self._controller.change_combo_box_selection) # LISTEN FOR MODEL EVENT SIGNALS self._model.combo_box_selection_changed.connect( self.on_combo_box_selection_changed) self.frameRightMenu = QWidget(self) self.frameRightMenu.setFixedSize(360, self.HEIGHT) self.frameRightMenu.move(1450, 15) self.frameRightMenu.setStyleSheet(self.TOOGLE_CLOSED_COLOR) # BUTTON WHICH TOOGLE ON/OFF THE TREE VIEW CONTAINING THE SELECTED ITEMS TREE VIEW self.toggleButton = QPushButton(QIcon(self.BUTTON_CLOSED_ICON_PATH), self.EMPTY_STRING, self) self.toggleButton.setFixedSize(100, 70) self.toggleButton.move(1300, 0) self.toggleButton.setStyleSheet(self.TOOGLE_BUTTON_CSS_PROPERTY) self._enable = True self.toggleButton.clicked.connect( lambda: Animations.toggleMenu(self, self._enable)) # Label that shows "Selected items:" self.selectedItemsLabel = QLabel(self.SELECTED_ITEMS_TEXT, self.frameRightMenu) self.selectedItemsLabel.move(100, 20) self.selectedItemsLabel.setStyleSheet(self.FRAME_LABEL_STYLE) # The list with selected elements from FilesListView self.selectedFilesListWidget = QListWidget(self.frameRightMenu) self.selectedFilesListWidget.setFixedSize(320, 500) self.selectedFilesListWidget.move(23, 60) self.selectedFilesListWidget.setStyleSheet(self.WHITE) # ACTIONS BUTTONS # Copy button self.copyElementButton = OperationsWidgetButton( QIcon(self.COPY_ELEMENT_ICON_PATH), self.EMPTY_STRING, self) self.copyElementButton.clicked.connect(self.doCopy) self.copyElementButton.move(230, 0) self.copyElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.copyElementButton.setToolTip(self.COPY_TOOLTIP) # Move button self.moveElementButton = OperationsWidgetButton( QIcon(self.MOVE_ELEMENT_ICON_PATH), self.EMPTY_STRING, self) self.moveElementButton.clicked.connect(self.doMove) self.moveElementButton.move(290, 0) self.moveElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.moveElementButton.setToolTip(self.MOVE_TOOLTIP) # Delete button self.deleteElementButton = OperationsWidgetButton( QIcon(self.DELETE_ELEMENT_ICON_PATH), self.EMPTY_STRING, self) self.deleteElementButton.clicked.connect(self.doDelete) self.deleteElementButton.move(350, 0) self.deleteElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.deleteElementButton.setToolTip(self.DELETE_TOOLTIP) # Archive button self.archiveElementButton = OperationsWidgetButton( QIcon(self.CREATE_ARCHIVE_ICON_PATH), self.EMPTY_STRING, self) self.archiveElementButton.clicked.connect(self.doArchive) self.archiveElementButton.move(410, 0) self.archiveElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.archiveElementButton.setToolTip(self.ARCHIVE_TOOLTIP) # Unarchive button self.unarchiveElementButton = OperationsWidgetButton( QIcon(self.UNARCHIVE_FILE_ICON_PATH), self.EMPTY_STRING, self) self.unarchiveElementButton.clicked.connect(self.doUnarchive) self.unarchiveElementButton.move(470, 0) self.unarchiveElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.unarchiveElementButton.setToolTip(self.UNARCHIVE_TOOLTIP) # Add file button self.addFileButton = OperationsWidgetButton( QIcon(self.ADD_FILE_ICON_PATH), self.EMPTY_STRING, self) self.addFileButton.clicked.connect(self.doCreateFile) self.addFileButton.move(530, 0) self.addFileButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.addFileButton.setToolTip(self.CREATE_FILE_TOOLTIP) # Add directory button self.addDirectoryButton = OperationsWidgetButton( QIcon(self.ADD_DIRECTORY_ICON_PATH), self.EMPTY_STRING, self) self.addDirectoryButton.clicked.connect(self.doCreateFolder) self.addDirectoryButton.move(590, 0) self.addDirectoryButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.addDirectoryButton.setToolTip(self.CREATE_DIRECTORY_TOOLTIP) # Move button self.renameElementButton = OperationsWidgetButton( QIcon(self.RENAME_ELEMENT_ICON_PATH), self.EMPTY_STRING, self) self.renameElementButton.clicked.connect(self.doRename) self.renameElementButton.move(650, 0) self.renameElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.renameElementButton.setToolTip(self.RENAME_TOOLTIP) # Text field needed for displaying the current path self.currentPathLineEdit = QLineEdit(self.EMPTY_STRING, self) self.currentPathLineEdit.move(350, 80) self.currentPathLineEdit.setFixedSize(400, 27) self.currentPathLineEdit.setStyleSheet( self.CURRENT_PATH_LINE_EDIT_PROPERTY) self.currentPathLineEdit.setReadOnly(True) self.currentPathLineEdit.setText(self._model.current_path) self.currentPathLineEdit.textChanged.connect( self._controller.change_current_path_text) self._model.current_path_changed.connect(self.on_current_path_changed) # Text field needed for searching file / folder by the name self.searchLineEdit = QLineEdit(self.EMPTY_STRING, self) self.searchLineEdit.move(810, 80) self.searchLineEdit.setFixedSize(200, 27) self.searchLineEdit.textChanged.connect( self._controller.change_search_text) self._model.current_search_changed.connect( self.on_current_search_changed) self.searchIconButton = OperationsWidgetButton( QIcon(self.SEARCH_ICON_PATH), self.EMPTY_STRING, self) self.searchIconButton.move(1015, 78) self.searchIconButton.setFixedSize(30, 30) self.searchIconButton.setStyleSheet(self.SEARCH_ICON_STYLE) self.searchIconButton.setEnabled(False) self.backButton = OperationsWidgetButton(QIcon(self.BACK_ICON_PATH), self.EMPTY_STRING, self) self.backButton.clicked.connect(self.doBack) self.backButton.move(765, 80) self.backButton.setFixedSize(25, 25) self.backButton.setStyleSheet(self.BACK_ICON_STYLE) self.backButton.setToolTip(self.BACK_TOOLTIP) self.backButton.setEnabled(True) # ACTIONS LABELS self.archiveLabel = QLabel(self.ARCHIVE_NAME_TEXT, self.frameRightMenu) self.createFolderLabel = QLabel(self.CREATE_FOLDER_NAME_TEXT, self.frameRightMenu) self.createFileLabel = QLabel(self.CREATE_FILE_NAME_TEXT, self.frameRightMenu) self.renameElementLabel = QLabel(self.RENAME_ELEMENT_TEXT, self.frameRightMenu) # ACTIONS LINE EDITS self.archiveNameEditLine = QLineEdit(self.EMPTY_STRING, self.frameRightMenu) self.createFileEditLine = QLineEdit(self.EMPTY_STRING, self.frameRightMenu) self.createFolderEditLine = QLineEdit(self.EMPTY_STRING, self.frameRightMenu) self.renameElementEditLine = QLineEdit(self.EMPTY_STRING, self.frameRightMenu) # ACTIONS BUTTONS self.copyButton = ToggleMenuButton(self.COPY, self.frameRightMenu) self.moveButton = ToggleMenuButton(self.MOVE, self.frameRightMenu) self.deleteButton = ToggleMenuButton(self.DELETE, self.frameRightMenu) self.archiveButton = ToggleMenuButton(self.ARCHIVE, self.frameRightMenu) self.unarchiveButton = ToggleMenuButton(self.UNARCHIVE, self.frameRightMenu) self.createFileButton = ToggleMenuButton(self.CREATE_FILE, self.frameRightMenu) self.createFolderButton = ToggleMenuButton(self.CREATE_FOLDER, self.frameRightMenu) self.renameElementButton = ToggleMenuButton(self.RENAME, self.frameRightMenu) self.__createFrameLayoutElements() @Slot(str) def on_current_path_changed(self, path): self._model.elements_list.clear() self._model.selected_items.clear() self.selectedFilesListWidget.clear() self._model.elements_list = Directory.get_all_subelements(path) self.filesListView.model().populateList() @Slot(str) def on_current_search_changed(self, name): print(name) def removeFromSelectedItems(self, item): Animations.toggleMenu(self, True) count = self.selectedFilesListWidget.count() index = 0 for i in range(count): if item.text() == self.selectedFilesListWidget.item(i).text(): index = i break self.selectedFilesListWidget.takeItem(index) def appendToSelectedItems(self, item): Animations.toggleMenu(self, True) listItem = ListWidgetItem(item) self.selectedFilesListWidget.insertItem(0, listItem) def setCurrentPath(self, path): self.currentPathLineEdit.setText(path) @Slot(str) def on_combo_box_selection_changed(self, value): index = self.discSelectionComboBox.findText(value) self.discSelectionComboBox.setCurrentIndex(index) Slot() def doBack(self): path = self.currentPathLineEdit.text() parentPath = os.path.dirname(path) self.setCurrentPath(parentPath) @Slot() def doCopy(self): self.__setCopyLayout(True) Animations.toggleMenu(self, True) @Slot() def doMove(self): self.__setMoveLayout(True) Animations.toggleMenu(self, True) @Slot() def doDelete(self): self.__setDeleteLayout(True) Animations.toggleMenu(self, True) @Slot() def doArchive(self): self.__setArchiveLayout(True) Animations.toggleMenu(self, True) @Slot() def doUnarchive(self): self.__setUnarchiveLayout(True) Animations.toggleMenu(self, True) @Slot() def doCreateFile(self): self.__setCreateFileLayout(True) Animations.toggleMenu(self, True) @Slot() def doCreateFolder(self): self.__setCreateFolderLayout(True) Animations.toggleMenu(self, True) @Slot() def doRename(self): self.__setRenameLayout(True) Animations.toggleMenu(self, True) # Method that creates all layout object from the frame layout def __createFrameLayoutElements(self): # ================= COPY ACTION ======================= # Copy button on right frame self.copyButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.copyButton.move(120, 600) self.copyButton.setFixedSize(120, 32) self.copyButton.setVisible(False) # ================= MOVE ACTION ======================= # Move button on right frame self.moveButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.moveButton.move(120, 600) self.moveButton.setFixedSize(120, 32) self.moveButton.setVisible(False) # ================= DELETE ACTION ======================= # Delete button on right frame self.deleteButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.deleteButton.move(120, 600) self.deleteButton.setFixedSize(120, 32) self.deleteButton.setVisible(False) # ================= UNARCHIVE ACTION ======================= # Unarchive button on right frame self.unarchiveButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.unarchiveButton.move(120, 600) self.unarchiveButton.setFixedSize(120, 32) self.unarchiveButton.setVisible(False) # ================= ARCHIVE ACTION ======================= self.archiveLabel.move(100, 590) self.archiveLabel.setStyleSheet(self.FRAME_LABEL_STYLE) self.archiveLabel.setVisible(False) self.archiveNameEditLine.move(55, 620) self.archiveNameEditLine.setFixedSize(250, 30) self.archiveNameEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE) self.archiveNameEditLine.setVisible(False) self.archiveButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.archiveButton.move(120, 700) self.archiveButton.setFixedSize(120, 32) self.archiveButton.setVisible(False) # ================= CREATE NEW FILE ACTION ======================= self.createFileLabel.move(120, 590) self.createFileLabel.setStyleSheet(self.FRAME_LABEL_STYLE) self.createFileLabel.setVisible(False) self.createFileEditLine.move(55, 620) self.createFileEditLine.setFixedSize(250, 30) self.createFileEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE) self.createFileEditLine.setVisible(False) self.createFileButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.createFileButton.move(120, 700) self.createFileButton.setFixedSize(120, 32) self.createFileButton.setVisible(False) # ================= CREATE NEW FOLDER ACTION ======================= self.createFolderLabel.move(120, 590) self.createFolderLabel.setStyleSheet(self.FRAME_LABEL_STYLE) self.createFolderLabel.setVisible(False) self.createFolderEditLine.move(55, 620) self.createFolderEditLine.setFixedSize(250, 30) self.createFolderEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE) self.createFolderEditLine.setVisible(False) self.createFolderButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.createFolderButton.move(120, 700) self.createFolderButton.setFixedSize(120, 32) self.createFolderButton.setVisible(False) # ================= RENAME ELEMENT ACTION ======================= self.renameElementLabel.move(120, 590) self.renameElementLabel.setStyleSheet(self.FRAME_LABEL_STYLE) self.renameElementLabel.setVisible(False) self.renameElementEditLine.move(55, 620) self.renameElementEditLine.setFixedSize(250, 30) self.renameElementEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE) self.renameElementEditLine.setVisible(False) self.renameElementButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.renameElementButton.move(120, 700) self.renameElementButton.setFixedSize(120, 32) self.renameElementButton.setVisible(False) # Method that sets the frame layout for rename operation def __setRenameLayout(self, shown): if shown == True: self.renameElementLabel.setVisible(True) self.renameElementEditLine.setVisible(True) self.renameElementButton.setVisible(True) self.__setCopyLayout(False) self.__setDeleteLayout(False) self.__setMoveLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.renameElementLabel.setVisible(False) self.renameElementEditLine.setVisible(False) self.renameElementButton.setVisible(False) # Method that sets the frame layout for archive operation def __setCreateFileLayout(self, shown): if shown == True: self.createFileLabel.setVisible(True) self.createFileEditLine.setVisible(True) self.createFileButton.setVisible(True) self.__setCopyLayout(False) self.__setDeleteLayout(False) self.__setMoveLayout(False) self.__setRenameLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.createFileLabel.setVisible(False) self.createFileEditLine.setVisible(False) self.createFileButton.setVisible(False) # Method that sets the frame layout for archive operation def __setCreateFolderLayout(self, shown): if shown == True: self.createFolderLabel.setVisible(True) self.createFolderEditLine.setVisible(True) self.createFolderButton.setVisible(True) self.__setCopyLayout(False) self.__setDeleteLayout(False) self.__setMoveLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.createFolderLabel.setVisible(False) self.createFolderEditLine.setVisible(False) self.createFolderButton.setVisible(False) # Method that sets the frame layout for archive operation def __setArchiveLayout(self, shown): if shown == True: self.archiveLabel.setVisible(True) self.archiveNameEditLine.setVisible(True) self.archiveButton.setVisible(True) self.__setCopyLayout(False) self.__setDeleteLayout(False) self.__setMoveLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setUnarchiveLayout(False) else: self.archiveLabel.setVisible(False) self.archiveNameEditLine.setVisible(False) self.archiveButton.setVisible(False) # Method that sets the frame layout for copy operation def __setCopyLayout(self, shown): if shown == True: self.copyButton.setVisible(True) self.__setMoveLayout(False) self.__setDeleteLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.copyButton.setVisible(False) # Method that sets the frame layout for move operation def __setMoveLayout(self, shown): if shown == True: self.moveButton.setVisible(True) self.__setDeleteLayout(False) self.__setCopyLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.moveButton.setVisible(False) # Method that sets the frame layout for delete operation def __setDeleteLayout(self, shown): if shown == True: self.deleteButton.setVisible(True) self.__setCopyLayout(False) self.__setMoveLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.deleteButton.setVisible(False) # Method that sets the frame layout for unarchive operation def __setUnarchiveLayout(self, shown): if shown == True: self.unarchiveButton.setVisible(True) self.__setCopyLayout(False) self.__setMoveLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setDeleteLayout(False) else: self.unarchiveButton.setVisible(False)