예제 #1
0
    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)
예제 #2
0
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
예제 #3
0
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
예제 #4
0
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)
예제 #5
0
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()
예제 #6
0
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)
예제 #7
0
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)
예제 #8
0
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)
예제 #9
0
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
예제 #10
0
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)
예제 #11
0
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)
예제 #12
0
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)
예제 #13
0
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)