def set_editor_data(editor: QComboBox, index): current_value = index.model().data(index, Qt.EditRole) current_index = 0 for idx in range(0, editor.count()): value = editor.itemText(idx) if value == current_value: current_index = idx editor.setCurrentIndex(current_index)
def init_capitalization_widget(text_item): capitalization_combo_box = QComboBox() capitalization_options = ["None", "All uppercase", "All lowercase", "Small caps", "Capitalize"] for option in capitalization_options: capitalization_combo_box.addItem(option) capitalization_combo_box.setCurrentIndex( text_item.font().capitalization()) capitalization_combo_box.currentIndexChanged.connect( lambda x: set_text_capitalization( capitalization_combo_box.itemText(x), text_item)) return capitalization_combo_box
def init_stretch_layout(text_item): stretch_combo_box = QComboBox() stretch_options = {0: "None", 50: "Ultra condensed", 62: "Extra condensed", 75: "Condensed", 87: "Semi condensed", 100: "Unstretched", 112: "Semi expanded", 125: "Expanded", 150: "Extra expanded", 200: "Ultra expanded"} for option in stretch_options.values(): stretch_combo_box.addItem(option) stretch_combo_box.setCurrentText(stretch_options[text_item.font( ).stretch()]) stretch_combo_box.currentIndexChanged.connect(lambda x: set_text_stretch( stretch_combo_box.itemText( x), text_item)) return stretch_combo_box
class Window(QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) self.iconGroupBox = QGroupBox() self.iconLabel = QLabel() self.iconComboBox = QComboBox() self.showIconCheckBox = QCheckBox() self.messageGroupBox = QGroupBox() self.typeLabel = QLabel() self.durationLabel = QLabel() self.durationWarningLabel = QLabel() self.titleLabel = QLabel() self.bodyLabel = QLabel() self.typeComboBox = QComboBox() self.durationSpinBox = QSpinBox() self.titleEdit = QLineEdit() self.bodyEdit = QTextEdit() self.showMessageButton = QPushButton() self.minimizeAction = QAction() self.maximizeAction = QAction() self.restoreAction = QAction() self.quitAction = QAction() self.trayIcon = QSystemTrayIcon() self.trayIconMenu = QMenu() self.createIconGroupBox() self.createMessageGroupBox() self.iconLabel.setMinimumWidth(self.durationLabel.sizeHint().width()) self.createActions() self.createTrayIcon() self.showMessageButton.clicked.connect(self.showMessage) self.showIconCheckBox.toggled.connect(self.trayIcon.setVisible) self.iconComboBox.currentIndexChanged.connect(self.setIcon) self.trayIcon.messageClicked.connect(self.messageClicked) self.trayIcon.activated.connect(self.iconActivated) self.mainLayout = QVBoxLayout() self.mainLayout.addWidget(self.iconGroupBox) self.mainLayout.addWidget(self.messageGroupBox) self.setLayout(self.mainLayout) self.iconComboBox.setCurrentIndex(1) self.trayIcon.show() self.setWindowTitle("Systray") self.resize(400, 300) def setVisible(self, visible): self.minimizeAction.setEnabled(visible) self.maximizeAction.setEnabled(not self.isMaximized()) self.restoreAction.setEnabled(self.isMaximized() or not visible) super().setVisible(visible) def closeEvent(self, event): if not event.spontaneous() or not self.isVisible(): return if self.trayIcon.isVisible(): QMessageBox.information(self, "Systray", "The program will keep running in the system tray. " "To terminate the program, choose <b>Quit</b> in the context " "menu of the system tray entry.") self.hide() event.ignore() @Slot(int) def setIcon(self, index): icon = self.iconComboBox.itemIcon(index) self.trayIcon.setIcon(icon) self.setWindowIcon(icon) self.trayIcon.setToolTip(self.iconComboBox.itemText(index)) @Slot(str) def iconActivated(self, reason): if reason == QSystemTrayIcon.Trigger: pass if reason == QSystemTrayIcon.DoubleClick: self.iconComboBox.setCurrentIndex( (self.iconComboBox.currentIndex() + 1) % self.iconComboBox.count() ) if reason == QSystemTrayIcon.MiddleClick: self.showMessage() @Slot() def showMessage(self): self.showIconCheckBox.setChecked(True) selectedIcon = self.typeComboBox.itemData(self.typeComboBox.currentIndex()) msgIcon = QSystemTrayIcon.MessageIcon(selectedIcon) if selectedIcon == -1: # custom icon icon = QIcon(self.iconComboBox.itemIcon(self.iconComboBox.currentIndex())) self.trayIcon.showMessage( self.titleEdit.text(), self.bodyEdit.toPlainText(), icon, self.durationSpinBox.value() * 1000, ) else: self.trayIcon.showMessage( self.titleEdit.text(), self.bodyEdit.toPlainText(), msgIcon, self.durationSpinBox.value() * 1000, ) @Slot() def messageClicked(self): QMessageBox.information(None, "Systray", "Sorry, I already gave what help I could.\n" "Maybe you should try asking a human?") def createIconGroupBox(self): self.iconGroupBox = QGroupBox("Tray Icon") self.iconLabel = QLabel("Icon:") self.iconComboBox = QComboBox() self.iconComboBox.addItem(QIcon(":/images/bad.png"), "Bad") self.iconComboBox.addItem(QIcon(":/images/heart.png"), "Heart") self.iconComboBox.addItem(QIcon(":/images/trash.png"), "Trash") self.showIconCheckBox = QCheckBox("Show icon") self.showIconCheckBox.setChecked(True) iconLayout = QHBoxLayout() iconLayout.addWidget(self.iconLabel) iconLayout.addWidget(self.iconComboBox) iconLayout.addStretch() iconLayout.addWidget(self.showIconCheckBox) self.iconGroupBox.setLayout(iconLayout) def createMessageGroupBox(self): self.messageGroupBox = QGroupBox("Balloon Message") self.typeLabel = QLabel("Type:") self.typeComboBox = QComboBox() self.typeComboBox.addItem("None", QSystemTrayIcon.NoIcon) self.typeComboBox.addItem( self.style().standardIcon(QStyle.SP_MessageBoxInformation), "Information", QSystemTrayIcon.Information, ) self.typeComboBox.addItem( self.style().standardIcon(QStyle.SP_MessageBoxWarning), "Warning", QSystemTrayIcon.Warning, ) self.typeComboBox.addItem( self.style().standardIcon(QStyle.SP_MessageBoxCritical), "Critical", QSystemTrayIcon.Critical, ) self.typeComboBox.addItem(QIcon(), "Custom icon", -1) self.typeComboBox.setCurrentIndex(1) self.durationLabel = QLabel("Duration:") self.durationSpinBox = QSpinBox() self.durationSpinBox.setRange(5, 60) self.durationSpinBox.setSuffix(" s") self.durationSpinBox.setValue(15) self.durationWarningLabel = QLabel("(some systems might ignore this hint)") self.durationWarningLabel.setIndent(10) self.titleLabel = QLabel("Title:") self.titleEdit = QLineEdit("Cannot connect to network") self.bodyLabel = QLabel("Body:") self.bodyEdit = QTextEdit() self.bodyEdit.setPlainText("Don't believe me. Honestly, I don't have a clue." "\nClick this balloon for details.") self.showMessageButton = QPushButton("Show Message") self.showMessageButton.setDefault(True) messageLayout = QGridLayout() messageLayout.addWidget(self.typeLabel, 0, 0) messageLayout.addWidget(self.typeComboBox, 0, 1, 1, 2) messageLayout.addWidget(self.durationLabel, 1, 0) messageLayout.addWidget(self.durationSpinBox, 1, 1) messageLayout.addWidget(self.durationWarningLabel, 1, 2, 1, 3) messageLayout.addWidget(self.titleLabel, 2, 0) messageLayout.addWidget(self.titleEdit, 2, 1, 1, 4) messageLayout.addWidget(self.bodyLabel, 3, 0) messageLayout.addWidget(self.bodyEdit, 3, 1, 2, 4) messageLayout.addWidget(self.showMessageButton, 5, 4) messageLayout.setColumnStretch(3, 1) messageLayout.setRowStretch(4, 1) self.messageGroupBox.setLayout(messageLayout) def createActions(self): self.minimizeAction = QAction("Minimize", self) self.minimizeAction.triggered.connect(self.hide) self.maximizeAction = QAction("Maximize", self) self.maximizeAction.triggered.connect(self.showMaximized) self.restoreAction = QAction("Restore", self) self.restoreAction.triggered.connect(self.showNormal) self.quitAction = QAction("Quit", self) self.quitAction.triggered.connect(qApp.quit) def createTrayIcon(self): self.trayIconMenu = QMenu(self) self.trayIconMenu.addAction(self.minimizeAction) self.trayIconMenu.addAction(self.maximizeAction) self.trayIconMenu.addAction(self.restoreAction) self.trayIconMenu.addSeparator() self.trayIconMenu.addAction(self.quitAction) self.trayIcon = QSystemTrayIcon(self) self.trayIcon.setContextMenu(self.trayIconMenu)
class CreationContainer(QWidget): """ Apparently just another level of parent class for social link display. Man I was stupid. Still am luigi2hands :param MainFrame mainframe: application mainframe :param QWidget op: parent widget :param int load: index to load maybe? """ def __init__(self, mainframe, op, load): QWidget.__init__(self) self.mainframe = mainframe self.op = op self.op.cc = self self.load = load # View initializers... self.actions = None self.window = None self.initUI() self.op.grid.addWidget(self, 0, 0, 2, 10) def initUI(self): """ Initialize the GUI. Does lots of stuff. """ self.grid = QGridLayout() self.setLayout(self.grid) self.actions = self.op.link.getIDs() self.actions.append("New element") types = ["Info", "Speak", "Camera Change", "Movement"] self.save = QPushButton(self, text="Save") self.grid.addWidget(self.save, 3, 0) self.existing_connections = QListWidget(self) self.populateExistingConnections() self.grid.addWidget(self.existing_connections, 1, 5, 2, 1) self.next = QComboBox(self) self.next.addItems(self.actions) self.next.setMaximumWidth(150) if self.load != 0: self.next.setCurrentIndex(self.op.i) self.grid.addWidget(self.next, 3, 2) self.window = None self.actOM = QComboBox(self) self.actOM.addItems(types) self.actOM.activated.connect(self.changeFrame) self.grid.addWidget(self.actOM, 0, 0, 1, 2) self.connect() self.next.setCurrentIndex(self.next.count() - 1) self.backB = QPushButton(self, text="Back to List Menu") self.backB.clicked.connect(self.back) self.grid.addWidget(self.backB, 3, 4) self.lead = QLabel(self, text="Leads to:") self.lead.setAlignment(Qt.AlignRight) self.grid.addWidget(self.lead, 3, 1) self.connectB = QPushButton(self, text="Connect") self.connectB.clicked.connect(self.lightConnect) self.grid.addWidget(self.connectB, 3, 3) self.follow_path = QPushButton(self, text="Enter linked element") self.follow_path.clicked.connect(self.follow) self.grid.addWidget(self.follow_path, 0, 6, 2, 1) self.rmvRel = QPushButton(self, text="Remove this connection") self.rmvRel.clicked.connect(self.removeRelation) self.grid.addWidget(self.rmvRel, 1, 6, 2, 1) self.conLab = QLabel(self, text="This action connects to:") self.grid.addWidget(self.conLab, 0, 5) def removeRelation(self): """ Remove a relation, which will also delete the uniquely dependant subtree. """ if not self.existing_connections.currentItem() or \ not popup("Are you sure you want to remove this relation? Any elements with a unique dependancy " "on this relation will also be deleted.\nIt is highly recommended you take a look at " "the graphical view of the tree in order to see the potential effects of the deletion.", "Warning"): return self.op.link.delRelation( self.op.i, self.actions.index(self.existing_connections.currentItem().text())) self.populateExistingConnections() self.updateElementList() self.op.linkstored.save() def populateExistingConnections(self): """ Display all the existing connections of the current node. """ self.existing_connections.clear() for relation in self.op.link.getRelations(self.op.i): self.existing_connections.addItem( self.op.link.getOneID(self.op.link.getItem(relation))) def back(self): """ Return to the higher-level cutscene container view... """ if not popup("Return to list main menu?\n(Lose any unsaved changes)", "Warning"): return self.close() self.op.cc = None self.op.viewF(False) def follow(self): """ Move on to the edit view of the selected relationship. """ if not self.existing_connections.currentItem() or \ self.existing_connections.currentItem().text() == "": return self.next.setCurrentIndex([ self.next.itemText(i) for i in range(self.next.count()) ].index(self.existing_connections.currentItem().text())) self.op.i = self.actions.index(self.next.currentText()) self.connect() self.next.setCurrentIndex(self.next.count() - 1) def lightConnect(self): """ Create a relationship between the current action and another. """ if not self.checkCached(): popup("Please save this action before linking it to a new one", "Information") return if self.next.currentText() == "New element": self.op.link.addRelation(self.op.i, self.op.link.size()) print("Linked to index " + str(self.op.link.size())) self.op.i = self.op.link.size() self.load = 0 self.changeFrame(0) self.updateElementList() else: self.op.link.addRelation( self.op.i, self.actions.index(self.next.currentText())) print("Linked to index " + str(self.actions.index(self.next.currentText()))) self.populateExistingConnections() def connect(self): """ Create a relationship between the current action and another, and enter the edit view of the relationship. :raises Exception: if the requested new action's type can't be processed (should never happen) """ print(self.next.currentText()) if self.next.currentText() == "New element": self.load = 0 self.changeFrame(0) else: if isinstance( self.op.link.getItem( self.actions.index(self.next.currentText())), Info): self.actOM.setCurrentIndex(0) elif isinstance( self.op.link.getItem( self.actions.index(self.next.currentText())), Speak): self.actOM.setCurrentIndex(1) elif isinstance( self.op.link.getItem( self.actions.index(self.next.currentText())), Camera): self.actOM.setCurrentIndex(2) elif isinstance( self.op.link.getItem( self.actions.index(self.next.currentText())), Movement): self.actOM.setCurrentIndex(3) else: raise Exception("Not a type!") self.load = self.op.link.getItem( self.actions.index(self.next.currentText())) self.changeFrame(0) def checkCached(self): """ Check if the current element has been saved before. :returns: if the element has been saved :rtype: bool """ print(len(self.op.link.items) - 1) print(self.op.i) if self.op.link.getItem(self.op.i) == []: return False return True def updateElementList(self): """ Update the relationships list, I think. """ self.next.clear() self.actions = self.op.link.getIDs() self.actions.append("New element") self.next.addItems(self.actions) self.next.setCurrentIndex(len(self.actions) - 1) def changeFrame(self, _): """ Change view to edit a certain type of action. :param objct _: unused, but required by caller """ print("Changed to " + self.actOM.currentText()) try: self.window.close() except AttributeError: pass # No window open if self.actOM.currentText() == "Speak": self.window = SpeakFrame(self, self.load) elif self.actOM.currentText() == "Camera Change": self.window = CameraFrame(self, self.load) elif self.actOM.currentText() == "Movement": self.window = MoveFrame(self, self.load) else: # self.actOM.currentText() == "Info": self.window = InfoFrame(self, self.load) try: self.save.clicked.disconnect() except: #pylint: disable=bare-except pass self.save.clicked.connect(self.window.save) self.populateExistingConnections() self.updateElementList()
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 LinkInfo(QWidget): """ Social Link general information view. :param MainFrame mainframe: the application's mainframe :param QWidget op: parent widget :param SocialLink link: the social link :param int linklevel: the level at which to add level-specific information :param int linkangle: the angle at which to add angle-specific information """ def __init__(self, mainframe, op, link, linklevel=None, linkangle=None): QWidget.__init__(self) self.mainframe = mainframe self.op = op self.link = link self.linklevel = linklevel self.linkangle = linkangle self.reqs = None self.initUI() def initUI(self): """ Initializes the GUI. Does a lot of stuff. """ self.grid = QGridLayout() self.setLayout(self.grid) self.levang = {} elev = [] for key, _ in self.link.cutscenes.items(): if key[:key.index("_")] in self.levang: self.levang[key[:key.index("_")]].append(key[key.index("_") + 1:]) else: self.levang[key[:key.index("_")]] = [key[key.index("_") + 1:]] if key[:key.index("_")] not in elev: elev.append(key[:key.index("_")]) for _, angle in self.levang.items(): angle.sort(key=lambda angle: (int)(angle)) #pylint: disable=unnecessary-lambda elev.sort(key=lambda level: (int)(level)) #pylint: disable=unnecessary-lambda infoL = QLabel(self, text="Social Link Information") self.grid.addWidget(infoL, 0, 0, 1, 12) self.level = QComboBox(self) if len(elev) != 0: elev.insert(0, "") self.level.addItems(elev) self.level.activated.connect(self.recs) if self.linklevel: self.level.setCurrentIndex((int)(self.linklevel)) self.recs() else: self.level.addItems(["No cutscenes have been created"]) self.grid.addWidget(self.level, 1, 1, 1, 1) atlevel = QLabel(self, text="At " + self.link.arcana + " level ") self.grid.addWidget(atlevel, 1, 0, 1, 1) arcanainfo = QLabel(self, text=self.link.arcana + " Social Link info") self.aitext = QTextEdit(self) self.aitext.setText(self.link.info) self.aitext.setFixedSize(300, 100) self.save = QPushButton(self, text="Save") self.back = QPushButton(self, text="Back") self.save.clicked.connect(self.saveinfo) self.back.clicked.connect(self.endedit) if self.linklevel and self.linkangle: self.grid.addWidget(arcanainfo, 4, 0, 1, 6) self.grid.addWidget(self.aitext, 5, 0, 1, 6) thisinfo = QLabel(self, text=self.link.arcana + " info for level: " + self.linklevel + ", angle: " + self.linkangle) self.grid.addWidget(thisinfo, 4, 6, 1, 6) self.titext = QTextEdit(self) self.titext.setFixedSize(300, 100) try: self.titext.setText( self.link.cutinfo[self.level.currentText() + "_" + str(self.linkangle)]) except: #pylint: disable=bare-except # TODO why? Backwards compatibility? pass self.grid.addWidget(self.titext, 5, 6, 1, 6) self.grid.setAlignment(thisinfo, Qt.AlignHCenter) self.grid.setAlignment(self.titext, Qt.AlignHCenter) else: self.grid.addWidget(arcanainfo, 4, 0, 1, 12) self.grid.addWidget(self.aitext, 5, 0, 1, 12) pseudoL = QLabel(self, text="Social Link's Pseudoname") youhave = QLabel(self, text="You have established the ") ofthe = QLabel(self, text="Social Link of the " + self.link.arcana + " arcana!") self.grid.addWidget(pseudoL, 2, 0, 1, 12) self.grid.addWidget(youhave, 3, 0, 1, 5) self.grid.addWidget(ofthe, 3, 7, 1, 6) self.grid.addWidget(self.save, 6, 0, 1, 1) self.grid.addWidget(self.back, 6, 1, 1, 1) self.pseudoname = QLineEdit(self) self.pseudoname.setFixedSize(150, 20) self.pseudoname.setText(self.link.pseudoname) self.grid.addWidget(self.pseudoname, 3, 5, 1, 2) self.grid.setAlignment(infoL, Qt.AlignHCenter) self.grid.setAlignment(self.aitext, Qt.AlignHCenter) self.grid.setAlignment(arcanainfo, Qt.AlignHCenter) self.grid.setAlignment(self.save, Qt.AlignRight) self.grid.setAlignment(self.back, Qt.AlignLeft) self.grid.setAlignment(youhave, Qt.AlignRight) self.grid.setAlignment(ofthe, Qt.AlignLeft) self.grid.setAlignment(pseudoL, Qt.AlignHCenter) self.grid.setAlignment(self.pseudoname, Qt.AlignHCenter) def saveinfo(self): """ Set the info in the social link object and save it. """ try: for angle, data in self.reqs.textboxes.items(): (int)(data.text()) if data.text() != "": if self.level.currentText( ) not in self.link.requiredPoints: self.link.requiredPoints[self.level.currentText()] = {} if angle not in self.link.requiredPoints[ self.level.currentText()]: self.link.requiredPoints[ self.level.currentText()][angle] = {} self.link.requiredPoints[ self.level.currentText()][angle]['points'] = int( data.text()) for angle, data in self.reqs.courages.items(): self.link.requiredPoints[ self.level.currentText()][angle]['courage'] = int( data.currentText()) for angle, data in self.reqs.charms.items(): self.link.requiredPoints[ self.level.currentText()][angle]['charm'] = int( data.currentText()) for angle, data in self.reqs.acads.items(): self.link.requiredPoints[ self.level.currentText()][angle]['acad'] = int( data.currentText()) for angle, data in self.reqs.ultis.items(): self.link.finalpersona[angle] = data.currentText() self.link.pseudoname = self.pseudoname.text() self.link.info = self.aitext.toPlainText() if self.linklevel: if str(self.linklevel) + "_" + str( self.linkangle) not in self.link.cutinfo: self.link.cutinfo[str(self.linklevel) + "_" + str(self.linkangle)] = "" self.link.cutinfo[str(self.linklevel) + "_" + str( self.linkangle)] = self.titext.toPlainText() except ValueError: popup("Points must be integers.\nNot saved.", "Critical") return self.link.save() popup("Saved", "Information") def endedit(self): """ We're done. Return to the calling widget. """ self.mainframe.changeState(self.op) def recs(self): """ Handle addition and removal of requirements window. """ try: self.reqs.close() except Exception as e: #pylint: disable=broad-except print(e) print("Can't close oudated req widget") if self.level.currentText() == "": return if self.level.itemText(0) == "": self.level.removeItem(0) self.reqs = Requirements(self) self.grid.addWidget(self.reqs, 1, 2, 1, 10)
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 TrainWindow(QWidget): ''' The TrainWindow class is a PySide2 Graphical User Interface (GUI) window that is called by MainWindow class in order to configure a custom training session and initiates training for a selected Precision-Level. ''' def __init__(self, debug=False): ''' The constructor. Sets the size of the window and configurations for a training session. Calls setButtons function to populate window with button. ''' super().__init__() self.debug = debug self._TRAIN_WIN_H = 500 self._TRAIN_WIN_W = 500 self.model_name = '' self._model_list = [] self._label_list = [] self._precision_level = 1 self._path_to_dataset = '' self._path_to_label_list = '' self._is_valid_dataset = False self.buttonConnected = False self.label_process = None self._is_model_ready = False self._is_dataset_linked = False self._is_dataset_labelled = False self._is_labellist_linked = False self.label_train_process = None self.label_val_process = None self.setWindowTitle('Train') self.setGeometry(self._TRAIN_WIN_W * 2, 0, self._TRAIN_WIN_W, self._TRAIN_WIN_H) self.setFixedSize(self._TRAIN_WIN_W, self._TRAIN_WIN_H) self.setButtons() def setButtons(self): '''A Mutator function that defines all buttons in TrainWindow.''' self.p1_button = QPushButton('P1', self) self.p1_button.setGeometry(0, 0, 50, 100) self.p1_button.setStyleSheet( 'background-color: rgba(180,180,180,255);') self.p2_button = QPushButton('P2', self) self.p2_button.setGeometry(50, 0, 50, 100) self.p3_button = QPushButton('P3', self) self.p3_button.setGeometry(100, 0, 50, 100) # Model dropdown menu to select Precision Level specific model self.model_selector = QComboBox(self) self.model_selector.setGeometry(self._TRAIN_WIN_W - 150, 0, 150, 100) self.model_selector.setStyleSheet('background-color: red;') self.populateModelSelector() self.model_selector_label = QLabel(self) self.model_selector_label.setText('Choose Model =') self.model_selector_label.move(220, 40) # Labeller button to initiate labelme self.label_button = QPushButton('Label Dataset', self) self.label_button.setIcon(QIcon('img/label.png')) self.label_button.setIconSize(QSize(50, 50)) self.label_button.setGeometry(0, 200, self._TRAIN_WIN_W / 2, 100) self.label_button.setStyleSheet( 'background-color: rgba(0,200,10,255);') if self._precision_level == 1: self.label_button.hide() self.generate_button = QPushButton('Generate Dataset', self) self.generate_button.setIcon(QIcon('img/label.png')) self.generate_button.setIconSize(QSize(50, 50)) self.generate_button.setGeometry(self._TRAIN_WIN_W / 2, 200, self._TRAIN_WIN_W / 2, 100) self.generate_button.setStyleSheet( 'background-color: rgba(0,200,10,255);') if self._precision_level == 1: self.generate_button.hide() # Labeller button to initiate labelme self.validate_button = QPushButton('Validate Dataset', self) self.validate_button.setIcon(QIcon('img/validate.png')) self.validate_button.setIconSize(QSize(50, 50)) self.validate_button.setGeometry(self._TRAIN_WIN_W / 2, 300, self._TRAIN_WIN_W / 2, 100) # Dataset button to prompt input via FileDialogue self.dataset_button = QPushButton('Choose Dataset', self) self.dataset_button.setIcon(QIcon('img/dataset.png')) self.dataset_button.setIconSize(QSize(50, 50)) self.dataset_button.setGeometry(0, 300, self._TRAIN_WIN_W / 2, 100) self.dataset_button.setStyleSheet('background-color: red;') # Start Training button to start and display training process self.train_button = QPushButton('Train', self) self.train_button.setIcon(QIcon('img/train.png')) self.train_button.setIconSize(QSize(75, 75)) self.train_button.setGeometry(0, self._TRAIN_WIN_H - 100, self._TRAIN_WIN_W, 100) self.train_button.setStyleSheet( 'background-color: rgba(180,180,180,255);') # Set Label List self.list_button = QPushButton('Choose Label List', self) self.list_button.setIcon(QIcon('img/label_list.png')) self.list_button.setIconSize(QSize(75, 75)) self.list_button.setGeometry(0, 100, self._TRAIN_WIN_W, 100) self.list_button.setStyleSheet('background-color: rgba(200,10,0,255);') self.p1_button.clicked.connect(self.setP1) self.p2_button.clicked.connect(self.setP2) self.p3_button.clicked.connect(self.setP3) self.model_selector.activated.connect(self.setModel) self.dataset_button.clicked.connect(self.setDataset) self.label_button.clicked.connect(self.runLabelme) self.generate_button.clicked.connect(self.conformDatasetToCOCO) self.validate_button.clicked.connect(self.validateDataset) self.list_button.clicked.connect(self.setLabelList) def setP1(self): '''A function that is triggered by the button labelled, P1.''' self._precision_level = 1 self.populateModelSelector() self.initModel() self.label_button.hide() self.generate_button.hide() self.p1_button.setStyleSheet( 'background-color: rgba(180,180,180,255);') self.p2_button.setStyleSheet('background-color: white;') self.p3_button.setStyleSheet('background-color: white;') self.disconnectTrainingButton() print('Set Precision Level at: ', self._precision_level) def setP2(self): '''A function that is triggered by the button labelled, P2.''' self._precision_level = 2 self.populateModelSelector() self.initModel() self.label_button.show() self.generate_button.show() self.p2_button.setStyleSheet( 'background-color: rgba(180,180,180,255);') self.p1_button.setStyleSheet('background-color: white;') self.p3_button.setStyleSheet('background-color: white;') self.disconnectTrainingButton() print('Set Precision Level at: ', self._precision_level) def setP3(self): '''A function that is triggered by the button labelled, P3.''' self._precision_level = 3 self.populateModelSelector() self.initModel() self.label_button.show() self.generate_button.show() self.p3_button.setStyleSheet( 'background-color: rgba(180,180,180,255);') self.p1_button.setStyleSheet('background-color: white;') self.p2_button.setStyleSheet('background-color: white;') self.disconnectTrainingButton() print('Set Precision Level at: ', self._precision_level) def setModel(self, index): '''A function that is triggered by the DropDown Menu labelled, Model.''' self.model_name = self.model_selector.itemText(index) self.model_selector.setStyleSheet( 'background-color: rgba(0,200,10,255);') self._is_model_ready = True self.validateTraining() print('Set Model to ', self.model_name) def setLabelList(self): '''A function that is triggered by the button labelled, Choose Label List.''' if not self.debug: input_classes_filepath, ok = QFileDialog.getOpenFileName( self, 'Set the .txt to use', os.path.abspath('../data'), 'Text Files (*.txt)') else: input_classes_filepath = '../data/label_list/coco_classes.txt' ok = True if ok: self._path_to_label_list = input_classes_filepath self._label_list = [ line.rstrip('\n') for line in open(input_classes_filepath) ] else: print('No label list set.') return self.list_button.setStyleSheet('background-color: rgba(0,150,10,255);') self._is_labellist_linked = True self.validateTraining() def setDataset(self): '''A function that is triggered by the button labelled, Choose Dataset.''' if not self.debug: new_filepath_to_dataset = (QFileDialog.getExistingDirectory( self, 'Set directory of the dataset', os.path.abspath('../data'), QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)) else: new_filepath_to_dataset = '../data/datasets' if os.path.isdir(new_filepath_to_dataset): self._path_to_dataset = new_filepath_to_dataset # Set button color to green self._is_dataset_linked = True self.dataset_button.setStyleSheet( 'background-color: rgba(0,200,10,255);') else: # Set button color to red print('Dataset path does not exist.') self.dataset_button.setStyleSheet('background-color: red;') self.validateTraining() def runLabelme(self): '''A function that is triggered by the button labelled, Label Dataset.''' self.label_process = subprocess.Popen(['labelme']) self.validateTraining() def initModel(self): ''' A Mutator function that sets the model_name to the first model available whenever the precision level changes. ''' self.model_name = self._model_list[0] self._is_model_ready = True print('Set Model to ', self.model_name) def validateTraining(self): ''' A Mutator function that evaulates necessary boolean flags that are all required to allow proper training given a certain requested precision level. ''' # Perform 4 checks to ensure all data is available for Training to start without issue. if not self._is_model_ready: print('No model provided. Please choose Model.') self.train_button.setStyleSheet( 'background-color: rgba(180,180,180,255);') self.disconnectTrainingButton() return if not self._is_dataset_linked: print('Dataset directory not provided. Please choose Dataset.') self.train_button.setStyleSheet( 'background-color: rgba(180,180,180,255);') self.disconnectTrainingButton() return if not self._is_labellist_linked: print('Label List not provided. Please choose Label List.') self.train_button.setStyleSheet( 'background-color: rgba(180,180,180,255);') self.disconnectTrainingButton() return if not self._is_dataset_labelled: print( 'Dataset not properly restructured. Please restructure Dataset.' ) self.train_button.setStyleSheet( 'background-color: rgba(180,180,180,255);') self.disconnectTrainingButton() return # Precision Level 1 only requires 4 checks. if self._precision_level == 1: print('Precision 1 Training Ready.') self.train_button.setStyleSheet('background-color: white;') self.connectTrainingButton() return if not self._is_dataset_labelled: print('Dataset not labelled properly. Please label Dataset.') self.train_button.setStyleSheet( 'background-color: rgba(180,180,180,255);') self.disconnectTrainingButton() return self.train_button.setStyleSheet('background-color: white;') self.connectTrainingButton() def validateDataset(self): '''A function that is triggered by the button labelled, Validate Dataset.''' if self._precision_level == 1: trainDirExists = os.path.exists(self._path_to_dataset + '/train') valDirExists = os.path.exists(self._path_to_dataset + '/val') # Check if the dataset folder has the following structure if trainDirExists and valDirExists: self._is_dataset_labelled = True self.validate_button.setStyleSheet( 'background-color: rgba(0,200,10,255);') else: self._is_dataset_labelled = False print('[ERROR] - Please ensure there is ' + '/train and /val sub-directories ' + 'in the selected dataset directory.') elif self._precision_level == 2: isDatasetNamedRight = os.path.basename( self._path_to_dataset) == 'custom_dataset' trainDirExists = os.path.exists(self._path_to_dataset + '/train_dataset') valDirExists = os.path.exists(self._path_to_dataset + '/val_dataset') # Check if the dataset folder has the following structure if trainDirExists and valDirExists and isDatasetNamedRight: self._is_dataset_labelled = True self.validate_button.setStyleSheet( 'background-color: rgba(0,200,10,255);') else: self._is_dataset_labelled = False print('[ERROR] - Please ensure there is ' + '/train_dataset and /val_dataset sub-directories' + 'in the selected dataset directory.') elif self._precision_level == 3: isDatasetNamedRight = os.path.basename( self._path_to_dataset) == 'custom_dataset' trainDirExists = os.path.exists(self._path_to_dataset + '/train_dataset') valDirExists = os.path.exists(self._path_to_dataset + '/val_dataset') # Check if the dataset folder has the following structure if trainDirExists and valDirExists and isDatasetNamedRight: self._is_dataset_labelled = True self.validate_button.setStyleSheet( 'background-color: rgba(0,200,10,255);') else: self._is_dataset_labelled = False print('[ERROR] - Please ensure there is ' + '/train_dataset and /val_dataset sub-directories ' + 'in the selected dataset directory.') self.validateTraining() def startTraining(self): '''A function that is triggered by the button labelled, Train.''' self.disconnectTrainingButton() self.train_button.setText('Training In Progress') self.train_button.updateGeometry() if self._precision_level == 1: p1_trainer = P1Trainer(self._path_to_dataset, self.model_name, self._label_list) p1_trainer.train(False) elif self._precision_level == 2: p2_trainer = P2Trainer(self._path_to_dataset, self.model_name, self._label_list) p2_trainer.train(False) else: p3_trainer = P3Trainer(self._path_to_dataset, self.model_name, self._label_list) p3_trainer.train(False) self.train_button.setText('Train') self.train_button.updateGeometry() def conformDatasetToCOCO(self): '''A function that is triggered by the button labelled, Generate Dataset.''' if not self.debug: path_to_labelled = QFileDialog.getExistingDirectory( self, 'Select your labeled dataset.', os.path.abspath('../data'), QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) else: path_to_labelled = '../data/datasets/p2p3_dummy_dataset' # Check if every image in given folder trainDirExists = os.path.exists(path_to_labelled + '/train_dataset') valDirExists = os.path.exists(path_to_labelled + '/val_dataset') outputTrainDir = '../data/datasets/custom_dataset/train_dataset' outputValDir = '../data/datasets/custom_dataset/val_dataset' if trainDirExists and valDirExists: self.label_train_process = subprocess.Popen([ 'python', 'dataset/labelme2coco.py', '--labels', self._path_to_label_list, path_to_labelled + '/train_dataset', outputTrainDir ]) if not self.debug: self.label_train_process.communicate() self.label_val_process = subprocess.Popen([ 'python', 'dataset/labelme2coco.py', '--labels', self._path_to_label_list, path_to_labelled + '/val_dataset', outputValDir ]) if not self.debug: self.label_val_process.communicate() else: print('Faulty labelled dataset detected.') def populateModelSelector(self): ''' A Mutator function that populates the DropDown Menu labelled, Choose Model with all available pretrained models from PyTorch model zoo. ''' # Implement different model list based on different precision level. if self._precision_level == 1: self._model_list = [ line.rstrip('\n') for line in open('./lists/p1_model_list.txt') ] elif self._precision_level == 2: self._model_list = [ line.rstrip('\n') for line in open('./lists/p2_model_list.txt') ] elif self._precision_level == 3: self._model_list = [ line.rstrip('\n') for line in open('./lists/p3_model_list.txt') ] self.model_selector.clear() for model in self._model_list: self.model_selector.addItem(model) def connectTrainingButton(self): ''' A Mutator function that allows the button labelled, Train, to be used by the user. ''' if not self.buttonConnected: self.train_button.clicked.connect(self.startTraining) self.buttonConnected = True def disconnectTrainingButton(self): ''' A Mutator function that disallows the button labelled, Train, to be used by the user. ''' if self.buttonConnected: try: self.train_button.clicked.disconnect(self.startTraining) except Exception: pass self.buttonConnected = False
class CharUI(QWidget): """ Main widget for the Character creator view. :param MainFrame mainframe: the application mainframe :param QWidget op: parent widget """ def __init__(self, mainframe, op): print("Starting...") QWidget.__init__(self) self.mainframe = mainframe self.op = op self.nameT = None self.infoT = None self.importantB = None self.initUI() def initUI(self): """ Initializes the GUI. Does a lot of stuff. """ self.mainframe.setWindowTitle("Character Creator") grid = QGridLayout() self.setLayout(grid) nameL = QLabel(self, text="Name:") grid.addWidget(nameL, 1, 1) self.nameT = QLineEdit(self) self.nameT.setFixedSize(200, 20) grid.addWidget(self.nameT, 1, 2, 1, 2) self.importantB = QCheckBox(self, text="Important?") grid.addWidget(self.importantB, 1, 4) infoL = QLabel(self, text="Info:") grid.addWidget(infoL, 2, 1) self.infoT = QTextEdit(self) self.infoT.setFixedSize(300, 150) grid.addWidget(self.infoT, 2, 2, 1, 3) save = QPushButton(self, text="Save") save.clicked.connect(self.save) grid.addWidget(save, 4, 1) remove = QPushButton(self, text="Remove") remove.clicked.connect(self.remove) grid.addWidget(remove, 4, 2) back = QPushButton(self, text="Back") back.clicked.connect(self.back) grid.addWidget(back, 4, 3) names = json_reader.readCharNames() names.append("New") self.allChars = QComboBox(self) self.allChars.activated.connect((lambda: self.loadChar(self.allChars.currentText()))) self.allChars.addItems(names) self.allChars.setCurrentIndex(self.allChars.count()-1) grid.addWidget(self.allChars, 4, 4) def loadChar(self, name): """ Load one character from file based on the name. :param str name: name of character to load """ print("Loading...") if self.importantB.isChecked(): self.importantB.toggle() self.nameT.clear() self.infoT.clear() if name == "New": return characterL = json_reader.readOne(name, 'chars') charTL = Character(characterL["name"], characterL["desc"], characterL["important"]) if charTL.getImportant(): self.importantB.toggle() self.nameT.setText(charTL.getName()) self.infoT.setText(charTL.getDesc()) print("Loaded character " + self.allChars.currentText()) def remove(self): """ Remove a character from the list, and remove them from disk. """ if not popup("Are you certain you want to completely remove this character?\n(Cannot be undone)", "Warning"): return print("Removing character " + self.allChars.currentText()) json_reader.deleteChar(self.allChars.currentText()) self.allChars.removeItem(self.allChars.currentIndex()) self.allChars.setCurrentIndex(self.allChars.count()-1) self.loadChar("New") def save(self): """ Save a character to disk from the information entered in the GUI. """ if self.nameT.text() in ["New", ""]: popup("Sorry, your character cannot be called \""+self.nameT.text()+"\". That is a reserved " "keyword (and it's also a dumb name)", "Critical") return print("Saving") try: toWrite = Character(self.nameT.text(), self.infoT.toPlainText(), self.importantB.isChecked()) except UnicodeEncodeError as e: print(e) print(type(e)) popup("Sorry, unicode characters are not supported.", "Critical") return json_reader.writeOne(toWrite, 'chars') if toWrite.getName() not in [self.allChars.itemText(i) for i in range(self.allChars.count())]: self.allChars.insertItem(self.allChars.count()-1, self.nameT.text()) self.allChars.setCurrentIndex(self.allChars.count()-2) print("Saved") def back(self): """ Return the view to the calling widget. """ self.mainframe.changeState(self.op)
class TrackEditor(Observation, QWidget, metaclass=FinalMeta): def __init__(self, subject, powermode=False, allowEditBackend=False, confirmUpdate=True): Observation.__init__(self, subject) QWidget.__init__(self) self._template = None self.deleted = False self.shouldSave = False self.powermode = powermode self.allowEditBackend = allowEditBackend self.confirmUpdate = confirmUpdate self.descriptionMaxLen = 1000 self._code = "" layout = QVBoxLayout() layout.setAlignment(Qt.AlignTop) layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) if self.allowEditBackend: self._initForm() self._initCodeEditor() self.setFixedSize(630, 600) self.setAttribute(Qt.WA_StyledBackground) self.setStyleSheet(Theme.templateEditor.style) self.setContextMenuPolicy(Qt.NoContextMenu) self.setWindowModality(Qt.ApplicationModal) self.setWindowFlags(Qt.Tool | Qt.WindowTitleHint | Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowMaximizeButtonHint) self.setWindowFlag(Qt.WindowMinimizeButtonHint, False) self.codeView.closeShortcut.setEnabled(False) QShortcut(QKeySequence(self.tr("Ctrl+w")), self, self.close) def _initForm(self): layout = QFormLayout() self.runCommand = QLineEdit(self, maxLength=200) self.runCommand.setStyleSheet(Theme.templateEditor.inputStyle) self.runCommand.setFont(Theme.templateEditor.inputCodeFont) self.runCommand.setFixedHeight(Theme.templateEditor.inputHeight) if self.powermode: self.backendName = QLineEdit(self, maxLength=20) self.backendName.setStyleSheet(Theme.templateEditor.inputStyle) self.backendName.setFont(Theme.templateEditor.inputFont) self.backendName.setFixedHeight(Theme.templateEditor.inputHeight) self.editorMode = QComboBox() [self.editorMode.addItem(mode) for mode in self._availableModes()] self.editorMode.currentIndexChanged.connect( self.onEditorModeChanged) self.inputRegex = QLineEdit(self, maxLength=100) self.inputRegex.setToolTip("regex") self.inputRegex.setStyleSheet(Theme.templateEditor.inputStyle) self.inputRegex.setFont(Theme.templateEditor.inputCodeFont) self.inputRegex.setFixedHeight(Theme.templateEditor.inputHeight) self.inputReplace = QLineEdit(self, maxLength=100) self.inputReplace.setToolTip("substitution string") self.inputReplace.setStyleSheet(Theme.templateEditor.inputStyle) self.inputReplace.setFont(Theme.templateEditor.inputCodeFont) self.inputReplace.setFixedHeight(Theme.templateEditor.inputHeight) self.outputRegex = QLineEdit(self, maxLength=100) self.outputRegex.setToolTip("regex") self.outputRegex.setStyleSheet(Theme.templateEditor.inputStyle) self.outputRegex.setFont(Theme.templateEditor.inputCodeFont) self.outputRegex.setFixedHeight(Theme.templateEditor.inputHeight) self.outputReplace = QLineEdit(self, maxLength=100) self.outputReplace.setToolTip("substitution string") self.outputReplace.setStyleSheet(Theme.templateEditor.inputStyle) self.outputReplace.setFont(Theme.templateEditor.inputCodeFont) self.outputReplace.setFixedHeight(Theme.templateEditor.inputHeight) self.description = QPlainTextEdit(self, minimumHeight=80) self.description.setStyleSheet( Theme.templateEditor.descriptionStyle) self.description.setFont(Theme.templateEditor.descriptionFont) layout.addRow(self.tr("Run Command:"), self.runCommand) if self.powermode: layout.addRow(self.tr("Backend Name:"), self.backendName) layout.addRow(self.tr("Editor Mode:"), self.editorMode) inputMiddlewareLayout = QHBoxLayout() inputMiddlewareLayout.addWidget(self.inputRegex) inputMiddlewareLayout.addWidget(self.inputReplace) layout.addRow(self.tr("Input Middleware:"), inputMiddlewareLayout) outputMiddlewareLayout = QHBoxLayout() outputMiddlewareLayout.addWidget(self.outputRegex) outputMiddlewareLayout.addWidget(self.outputReplace) layout.addRow(self.tr("Output Middleware:"), outputMiddlewareLayout) layout.addRow(self.tr("Description:"), self.description) layout.setSpacing(10) layout.setContentsMargins(10, 10, 10, 10) self.layout().addLayout(layout) def _initCodeEditor(self): self.codeView = CodeView(self.subject, viewTip=False) self.layout().addWidget(QLabel("Setup Code:", margin=10)) self.layout().addWidget(self.codeView) self.codeView.setDelegate(self) def _availableModes(self): return acePropertyNames("mode-", ".js", False) def onEditorModeChanged(self, e): mode = self.editorMode.itemText(e) self.codeView.setMode(mode) if self._template is not None: self._template.editor_mode = mode def onSave(self): self.shouldSave = True if self.allowEditBackend: self._template.run_command = self.runCommand.text().strip() if self.powermode and self.allowEditBackend: self._template.backend_name = self.backendName.text().strip() self._template.editor_mode = self.editorMode.currentText() self._template.backend_middleware.input.regex = \ self.inputRegex.text() self._template.backend_middleware.input.substitution = \ self.inputReplace.text() self._template.backend_middleware.output.regex = \ self.outputRegex.text() self._template.backend_middleware.output.substitution = \ self.outputReplace.text() self._template.description = self.description.toPlainText( )[:self.descriptionMaxLen] self._template.setup_code = self._code def setTemplate(self, delegate): self._template = delegate self.codeView.setDelegate(self) self.deserialize() def setCode(self, code, notify): if self._template is None: return self._code = code if self.shouldSave: self._template.setup_code = code self.onTemplateUpdate() def onTemplateUpdate(self): pass def code(self): if self._template is None: return "" return self._template.setup_code def codeWindowTitle(self): return "Track Template Editor" def deserialize(self): if self._template is None: return if self.allowEditBackend: self.runCommand.setText(self._template.run_command.strip()) if self.powermode and self.allowEditBackend: self.backendName.setText(self._template.backend_name.strip()) self.editorMode.setCurrentText(self._template.editor_mode) self.inputRegex.setText( self._template.backend_middleware.input.regex) self.inputReplace.setText( self._template.backend_middleware.input.substitution) self.outputRegex.setText( self._template.backend_middleware.output.regex) self.outputReplace.setText( self._template.backend_middleware.output.substitution) self.description.document().setPlainText( self._template.description) else: self.codeView.setMode(self._template.editor_mode) self._code = self._template.setup_code self.setWindowTitle("Track Template Editor") def delete(self): self.deleted = True self.codeView.delete() self.unregister() self.setParent(None) self.deleteLater() def template(self): return self._template def showEvent(self, event): self.shouldSave = False self.codeView.show() super().showEvent(event) def closeEvent(self, event): if self._template is not None and not self.deleted: if self.confirmUpdate: question = "Do you want to save changes in " +\ f"{self._template.backend_name} template?" confirmation = ConfirmationDialog("Update Track Template", question) if confirmation.exec_() == ConfirmationDialog.Yes: self.onSave() else: self.onSave() self.codeView.close() super().closeEvent(event)
class SLUI(QWidget): """ Widget containing all arcanas, descriptions of them, and the level/angles available. :param MainFrame mainframe: application mainframe :param QWidget op: parent widget """ def __init__(self, mainframe, op): QWidget.__init__(self) self.mainframe = mainframe self.op = op # Initialized gui items... self.levelOM = None self.angleOM = None self.addAngB = None self.newAng = None self.go = None self.delang = None self.angs = None self.initUI() def initUI(self): """ Initializes the GUI. Does a lot of stuff. """ self.mainframe.setWindowTitle("Social Link Creator") self.grid = QGridLayout() self.setLayout(self.grid) arcanaList = json_reader.data_list("arcanas") self.arcSel = QComboBox(self) self.arcSel.addItem("Select Arcana") self.arcSel.activated.connect(self.showText) self.arcSel.addItems(arcanaList) self.arcSel.setCurrentIndex(0) self.grid.addWidget(self.arcSel, 1, 1) select = QPushButton(self, text="Select") select.clicked.connect(self.context) self.grid.addWidget(select, 2, 1) info = QPushButton(self, text="Info") info.clicked.connect(self.infoF) self.grid.addWidget(info, 3, 1) back = QPushButton(self, text="Back") back.clicked.connect(self.back) self.grid.addWidget(back, 4, 1) self.card = QLabel(self) defaultCard = QPixmap(json_reader.buildPath("int/cards/card.png")) self.card.setPixmap(defaultCard) self.card.setAlignment(Qt.AlignHCenter) self.grid.addWidget(self.card, 0, 0) self.text = QLabel(self, text="") self.text.setFixedSize(400, 250) self.text.setWordWrap(True) self.text.setAlignment(Qt.AlignHCenter) self.grid.addWidget(self.text, 1, 0, 4, 1) def infoF(self): """ Enter the social link edit gui. """ if self.arcSel.currentText() == "Select Arcana": return self.mainframe.changeState( LinkInfo(self.mainframe, self, SocialLink(self.arcSel.currentText()))) def context(self): """ Once an arcana is selected, spawn this view to add the level/angle information as an additional widget. """ self.destroyContext() if self.arcSel.currentText() == "Select Arcana": return levs = [] for i in range(1, 11): levs.append("Level " + str(i)) self.levelOM = QComboBox(self) self.levelOM.addItems(levs) self.levelOM.setCurrentIndex(0) self.levelOM.activated.connect(self.fetchangles) self.grid.addWidget(self.levelOM, 1, 2, 1, 2) self.angleOM = QComboBox(self) self.fetchangles() self.grid.addWidget(self.angleOM, 2, 2, 1, 2) self.addAngB = QPushButton(self, text="Add Angle") self.addAngB.clicked.connect(self.addAngle) self.grid.addWidget(self.addAngB, 3, 2) self.newAng = QLineEdit(self) self.newAng.setFixedSize(20, 20) self.grid.addWidget(self.newAng, 3, 3) self.go = QPushButton(self, text="Go") self.go.clicked.connect(self.begin) self.grid.addWidget(self.go, 5, 2, 1, 2) def fetchangles(self): """ Fetch the angles at a certain level for the display. """ try: self.delang.close() except: #pylint: disable=bare-except print("Failed to close delang") self.angs = [] try: tempLink = json_reader.readLink(str(self.arcSel.currentText())) for decon in tempLink["cutscenes"]: if str(decon)[:str(decon).index("_")] == \ self.levelOM.currentText()[str(self.levelOM.currentText()).index(" ") + 1:]: self.angs.append("Angle " + str(decon)[str(decon).index("_") + 1:]) except: #pylint: disable=bare-except pass if self.angs: print("There are angles for this level") self.delang = QPushButton(self, text="Delete Angle") self.delang.clicked.connect(self.deleteangle) self.grid.addWidget(self.delang, 4, 2, 1, 2) else: self.angs.append("No angles") self.angleOM.clear() self.angleOM.addItems(self.angs) self.angleOM.setCurrentIndex(0) def addAngle(self): """ Add a potential angle to this link/level. """ try: (int)(self.newAng.text()) if self.angs[0] == "No angles": self.angleOM.clear() self.delang = QPushButton(self, text="Delete Angle") self.delang.clicked.connect(self.deleteangle) self.grid.addWidget(self.delang, 4, 2, 1, 2) self.angleOM.addItem("Angle " + str(self.newAng.text())) self.angleOM.setCurrentIndex(self.angleOM.count() - 1) self.newAng.clear() except ValueError: popup("The Angle must be an integer", "Critical") def deleteangle(self): """ Completely delete a certain level/angle combo. This will remove all info, the cutscene, etc. Dangerous. """ if not popup( "WARNING!!!\n\nThis will COMPLETELY ERASE this cutscene. It is HIGHLY RECOMMENDED that " "you back up your data by going to the Support/Contact page and choose \"Export\".", "Warning"): return link = SocialLink(self.arcSel.currentText()) print(link.cutscenes) key = self.levelOM.currentText()[self.levelOM.currentText().index(" ")+1:] + \ "_" + \ self.angleOM.currentText()[self.angleOM.currentText().index(" ")+1:] print(key) if key in link.cutscenes: link.cutscenes.pop(key) link.save() self.angleOM.removeItem(self.angleOM.currentIndex()) if self.angleOM.count() == 0: self.angleOM.addItem("No angles") self.delang.close() print(link.cutscenes) print("Deleted") def showText(self): """ Show the arcana's descriptive text upon selection. """ temp = [self.arcSel.itemText(i) for i in range(self.arcSel.count())] if "Select Arcana" in temp: self.arcSel.removeItem(temp.index("Select Arcana")) self.text.setText( json_reader.readArcDesc(str(self.arcSel.currentText()))) self.card.setPixmap( QPixmap( json_reader.buildPath("int/cards/" + str(self.arcSel.currentText()) + ".png"))) self.destroyContext() def destroyContext(self): """ Make sure all widgets are close when leaving the context. """ try: self.levelOM.close() self.angleOM.close() self.addAngB.close() self.newAng.close() self.go.close() self.delang.close() except: #pylint: disable=bare-except pass def begin(self): """ Enter the social link cutscene editor. """ if self.angleOM.currentText() == "No angles": popup( "An Angle must be selected.\nCreate angles by entering a number in the text box below and " "clicking \"Add Angle\"", "Critical") return enter_level = str(self.levelOM.currentText() )[str(self.levelOM.currentText()).index(" ") + 1:] enter_angle = str(self.angleOM.currentText() )[str(self.angleOM.currentText()).index(" ") + 1:] print("Entered SL creation mode for arcana " + str(self.arcSel.currentText())) self.mainframe.changeState( SLFrame(self.mainframe, self, str(self.arcSel.currentText()), int(enter_level), int(enter_angle))) def back(self): """ Return to the parent widget. """ print("Returned to main screen") self.mainframe.changeState(self.op)
class mainScreen(QWidget): def __init__(self): QWidget.__init__(self) self.setWindowTitle('PER Lap Timer') self.connectionStatus = 'Disconnected' self.stopEvent = threading.Event() self.lastLapNumber = 0 self.lastLapTime = 0 self.connectionLabel = QLabel(self.connectionStatus) self.connectButton = QPushButton('Connect') self.lapNumberLabel = QLabel('Lap Number') self.lapTimeLabel = QLabel('Lap Time') self.lapNumber = QLabel('') self.lapTime = QLabel('') self.filler = QLabel(' ') self.portBox = QComboBox() self.portBox.addItem('Port') self.layout = QGridLayout() self.layout.addWidget(self.connectionLabel, 0, 0, 1, 2) self.layout.addWidget(self.lapNumberLabel, 1, 0, 1, 1) self.layout.addWidget(self.lapTimeLabel, 1, 4, 1, 1) self.layout.addWidget(self.lapNumber, 2, 0, 1, 1) self.layout.addWidget(self.lapTime, 2, 4, 1, 1) self.layout.addWidget(self.filler, 3, 0, 1, 4) self.layout.addWidget(self.portBox, 5, 0, 1, 3) self.layout.addWidget(self.connectButton, 5, 4, 1, 2) self.setLayout(self.layout) self.connectButton.clicked.connect(self.connect) self.portBox.activated.connect(self.comboHandler) self.findThread = threading.Thread(name='portFind', target=self.findPorts) self.findThread.setDaemon(True) self.findThread.start() def findPorts(self): while True: oldPorts = [] if sys.platform.startswith('win'): ports = ['COM%s' % (i + 1) for i in range(256)] elif sys.platform.startswith('linux') or sys.platform.startswith( 'cygwin'): ports = glob.glob('/dev/tty[A-Za-z]*') elif sys.platform.startswith('darwin'): ports = glob.glob('/dev/tty.*') else: raise EnvironmentError('Unsupported platform') if oldPorts != ports: self.portBox.clear() self.portBox.addItem('Port') for port in ports: self.portBox.addItem(port) try: index = self.portBox.findText(self.port) except: index = 0 self.portBox.setCurrentIndex(index) oldPorts = ports time.sleep(5) def setStatusLabel(self): self.connectionLabel.setText(self.connectionStatus) def connect(self): try: self.serialStream = serial.Serial(self.port, 9600, timeout=10) except: self.connectionLabel.setText('Could not connect to lap timer!') t = Timer(3, self.setStatusLabel) t.start() return None self.connectionStatus = 'Connected' self.connectionLabel.setText(self.connectionStatus) self.connectButton.setText(' Stop ') self.connectButton.clicked.connect(self.stop) self.stopEvent.clear() self.daemonRead = threading.Thread(name='serialRead', target=logSerial, args=(self, )) self.daemonRead.setDaemon(True) self.daemonRead.start() def stop(self): self.stopEvent.set() try: self.serialStream.close() except: None self.connectionStatus = 'Disconnected' self.connectionLabel.setText('Device disconnected') self.connectButton.setText('Connect') self.connectButton.clicked.connect(self.connect) t = Timer(3, self.setStatusLabel) t.start() def comboHandler(self, index): self.port = self.portBox.itemText(index)