Пример #1
0
class ICChatWidget(QDockWidget):
    def __init__(self, mainWindow):
        super(QDockWidget, self).__init__(mainWindow)
        self.setToolTip(self.tr("A widget for in-character chat."))
        self.setWindowTitle(self.tr("IC Chat"))
        self.widgetEditor = QTextBrowser(mainWindow)
        self.widgetLineInput = chatLineEdit(mainWindow)
        self.widgetLineInput.setToolTip(
            self.tr(
                "Type text here and press Enter or Return to transmit it."))
        self.widget = QWidget(mainWindow)
        self.widgetEditor.setReadOnly(True)
        self.widgetEditor.setOpenLinks(False)
        self.characterPreview = QLabel(mainWindow)
        self.characterSelector = QComboBox(mainWindow)
        self.characterSelector.setToolTip(
            self.
            tr("Select the character to be displayed as the speaker of entered text."
               ))
        self.characterAddButton = QPushButton(self.tr("Add New"), mainWindow)
        self.characterAddButton.setToolTip(
            self.tr("Add a new in-character chat character via a dialog box."))
        self.characterDeleteButton = QPushButton(self.tr("Delete"), mainWindow)
        self.characterDeleteButton.setToolTip(
            self.tr(
                "Delete the currently selected in-character chat character."))
        self.characterClearButton = QPushButton(self.tr("Clear"), mainWindow)
        self.characterClearButton.setToolTip(
            self.tr("Deletes all in-character chat characters."))
        self.layout = QGridLayout()
        self.layout.addWidget(self.widgetEditor, 0, 0, 1, 4)
        self.layout.addWidget(self.widgetLineInput, 1, 1, 1, 3)
        self.layout.addWidget(self.characterPreview, 1, 0, 2, 1)
        self.layout.addWidget(self.characterDeleteButton, 2, 3, 1, 1)
        self.layout.addWidget(self.characterClearButton, 3, 3, 1, 1)
        self.layout.addWidget(self.characterAddButton, 2, 2, 1, 1)
        self.layout.addWidget(self.characterSelector, 2, 1, 1, 1)
        self.widget.setLayout(self.layout)
        self.setWidget(self.widget)
        self.setObjectName("IC Chat Widget")
        self.messageCache = []

        self.setAcceptDrops(True)

        mainWindow.addDockWidget(Qt.LeftDockWidgetArea, self)

        #TODO: Store and access characters in a better fashion.
        try:
            self.load(jsonload(ospath.join(CHAR_DIR, "autosave.rgc")))
        except:
            self.characters = []

        self.widgetLineInput.returnPressed.connect(self.processInput)
        self.characterAddButton.clicked.connect(self.newCharacter)
        self.characterDeleteButton.clicked.connect(self.deleteCharacter)
        self.characterClearButton.clicked.connect(self.clearCharacters)
        self.characterSelector.currentIndexChanged.connect(
            self.setCharacterPreview)

        self.updateDeleteButton()

        self.setCharacterPreview()

    def toggleDarkBackgroundSupport(self, dark):
        if dark:
            self.widgetEditor.document().setDefaultStyleSheet(
                "a {color: cyan; }")
        else:
            self.widgetEditor.document().setDefaultStyleSheet(
                "a {color: blue; }")
        self.refreshMessages()

    def refreshMessages(self):
        '''Clear the text display and re-add all messages with current style settings etc.'''
        self.widgetEditor.clear()
        for message in self.messageCache:
            self.widgetEditor.append(message)

    def updateDeleteButton(self):
        self.characterDeleteButton.setEnabled(self.hasCharacters())
        self.characterClearButton.setEnabled(self.hasCharacters())
        self.characterSelector.setEnabled(self.hasCharacters())
        self.widgetLineInput.setEnabled(self.hasCharacters())

    def setCharacterPreview(self, newIndex=-1):
        try:
            preview = QPixmap(
                ospath.join(
                    UNICODE_STRING(PORTRAIT_DIR),
                    UNICODE_STRING(self.characters[
                        self.characterSelector.currentIndex()].portrait)))
            if preview.isNull(
            ):  #Sadly, we have to check ahead, because Qt is dumb and prints an error about the scaling instead of raising one we can catch.
                raise TypeError
            preview = preview.scaled(min(preview.width(), 64),
                                     min(preview.height(), 64))
            self.characterPreview.setPixmap(preview)
        except:
            self.characterPreview.clear()

    def insertMessage(self, mes):
        self.scroll = (self.widgetEditor.verticalScrollBar().value() ==
                       self.widgetEditor.verticalScrollBar().maximum())
        self.messageCache.append(mes)
        self.widgetEditor.append(mes)
        if self.scroll:
            self.widgetEditor.verticalScrollBar().setValue(
                self.widgetEditor.verticalScrollBar().maximum())
        try:
            try:
                self.logfile = open(
                    ospath.join(LOG_DIR, strftime("%b_%d_%Y.log",
                                                  localtime())), 'a')
                self.logfile.write(mes + "\n")
            finally:
                self.logfile.close()
        except:
            pass

    def dragEnterEvent(self, event):
        if event.mimeData().hasImage():
            event.acceptProposedAction()

    def dropEvent(self, event):
        if event.mimeData().hasImage():
            dat = event.mimeData().imageData()
            img = QImage(dat)
            filename = promptSaveFile('Save Portrait',
                                      'Portrait files (*.png)', PORTRAIT_DIR)
            if filename is not None:
                img.save(filename, "PNG")
            event.acceptProposedAction()

    def newCharacter(self):
        dialog = newCharacterDialog()

        def accept():
            valid = dialog.is_valid()
            if not valid:
                showErrorMessage(dialog.error)
            return valid

        if dialog.exec_(self.parentWidget(), accept):
            newchardat = dialog.save()
            newchar = ICChar(*newchardat)
            self.characterSelector.addItem(newchar.id)
            self.characters.append(newchar)
            jsondump(self.dump(), ospath.join(CHAR_DIR, "autosave.rgc"))
            self.characterSelector.setCurrentIndex(
                self.characterSelector.count() - 1)
            self.updateDeleteButton()
            self.setCharacterPreview()

    def _newChar(self, char):
        self.characterSelector.addItem(char.id)
        self.characters.append(char)
        jsondump(self.dump(), ospath.join(CHAR_DIR, "autosave.rgc"))

    def deleteCharacter(self):
        if self.hasCharacters():
            self.characters.pop(self.characterSelector.currentIndex())
            self.characterSelector.removeItem(
                self.characterSelector.currentIndex())
            jsondump(self.dump(), ospath.join(CHAR_DIR, "autosave.rgc"))
            self.updateDeleteButton()

    def clearCharacters(self):
        if promptYesNo('Really clear all characters?') == 16384:
            self.characters = []
            self.characterSelector.clear()
            jsondump(self.dump(), ospath.join(CHAR_DIR, "autosave.rgc"))
            self.updateDeleteButton()
            self.setCharacterPreview()

    def processTags(self, message):
        message = message.replace("<", "&lt;").replace(">", "&gt;")
        for validTag in ("i", "b", "u", "s"):
            message = message.replace("".join(("[", validTag, "]")), "".join(
                ("<", validTag, ">")))
            message = message.replace("".join(("[", "/", validTag, "]")),
                                      "".join(("<", "/", validTag, ">")))
        return message

    def processInput(self):
        self.newmes = UNICODE_STRING(self.widgetLineInput.text())
        self.newmes = self.processTags(self.newmes)
        self.widgetLineInput.clear()
        self.widgetLineInput.addMessage(self.newmes)
        self.ICChatInput.emit(
            self.newmes,
            UNICODE_STRING(
                self.characters[self.characterSelector.currentIndex()].name),
            UNICODE_STRING(self.characters[
                self.characterSelector.currentIndex()].portrait))

    def hasCharacters(self):
        return len(self.characters) > 0

    def dump(self):
        """Serialize to an object valid for JSON dumping."""

        return dict(chars=dict([(i, char.dump())
                                for i, char in enumerate(self.characters)]))

    def load(self, obj):
        """Deserialize set of IC characters from a dictionary."""

        self.characters = []
        self.characterSelector.clear()

        chars = loadObject('ICChatWidget.chars', obj.get('chars'))
        chartemp = [None] * len(list(chars.keys()))
        for ID, char in list(chars.items()):
            chartemp[int(ID)] = char
        for char in chartemp:
            loaded = ICChar.load(char)
            self._newChar(loaded)
        self.updateDeleteButton()
        self.setCharacterPreview()

    ICChatInput = signal(
        BASE_STRING,
        BASE_STRING,
        BASE_STRING,
        doc="""Called when in-character chat input is received.

		charname -- the character name currently selected
		text -- the message entered
		portrait -- the portrait path, relative to data/portraits

		""")
Пример #2
0
class userListWidget(QDockWidget):
    """The list of connected users."""
    def __init__(self, mainWindow):
        """Initializes the user list."""
        super(QDockWidget, self).__init__(mainWindow)
        self.setToolTip(self.tr("People presently playing."))
        self.setWindowTitle(self.tr("Connected Users"))
        self.widget = QWidget(mainWindow)
        self.listOfUsers = userListList(mainWindow, self)
        self.internalList = []
        self.layout = QGridLayout()
        self.layout.addWidget(self.listOfUsers, 0, 0, 1, 2)
        self.widget.setLayout(self.layout)
        self.widget.setMaximumWidth(
            200)  #Arbitrary; keeps it from taking over 1/3 of the screen
        self.setWidget(self.widget)
        self.setObjectName("User List Widget")
        self.gmname = None
        self.localname = None
        mainWindow.addDockWidget(Qt.BottomDockWidgetArea, self)

    def addUser(self, name, host=False):
        self.internalList.append((name, host))
        nametmp = name
        if host:
            if name == self.localname:
                self.kickbutton = QPushButton(self.tr("Kick"))
                self.kickbutton.setToolTip(
                    self.tr("Disconnect the selected user."))
                self.layout.addWidget(self.kickbutton, 1, 0)
                self.kickbutton.clicked.connect(self.requestKick)
                self.banbutton = QPushButton(self.tr("Manage Banlist"))
                self.banbutton.setToolTip(
                    self.tr("View and edit a list of banned IPs."))
                self.layout.addWidget(self.banbutton, 1, 1)
                self.banbutton.clicked.connect(self.openBanDialog)
            nametmp = "[Host] " + nametmp
        if self.gmname == name:
            nametmp = "[GM] " + nametmp
        self.listOfUsers.addItem(nametmp)

    def removeUser(self, name):
        for i, item in enumerate(self.internalList):
            if item[0] == name:
                self.internalList.pop(i)
                self.listOfUsers.takeItem(i)

    def getUsers(self):
        return self.internalList

    def clearUserList(self):
        self.internalList = []
        self.listOfUsers.clear()

    def refreshDisplay(self):
        self.listOfUsers.clear()
        for item in self.internalList:
            nametmp = item[0]
            if item[1]:
                nametmp = "[Host] " + nametmp
            if self.gmname == item[0]:
                nametmp = "[GM] " + nametmp
            self.listOfUsers.addItem(nametmp)

    def setGM(self, new):
        self.gmname = new
        self.refreshDisplay()

    def provideOptions(self, ID):
        if self.gmname != self.localname:
            return
        name = self.internalList[ID][0]
        #self.setGM(name)
        self.selectGM.emit(name)

    def requestKick(self):
        name = self.internalList[self.listOfUsers.currentRow()][0]
        if name == self.localname:
            return
        self.kickPlayer.emit(name)

    def openBanDialog(self):
        banDialog().exec_()
        self.requestBanlistUpdate.emit()

    selectGM = signal(
        BASE_STRING,
        doc=
        """Called to request a menu be summoned containing actions targeting the selected player.
			Sorry for the misleading legacy name.""")

    kickPlayer = signal(BASE_STRING,
                        doc="""Called to request player kicking.""")

    requestBanlistUpdate = signal(
        doc="""Called to request that the banlist be updated.""")
Пример #3
0
class diceRoller(QDockWidget):
    def __init__(self, mainWindow):
        super(QDockWidget, self).__init__(mainWindow)
        self.setWindowTitle(self.tr("Dice"))
        self.realwidget = QWidget(
            mainWindow
        )  #I messed up on the initial setup and was too lazy to rename everything.
        self.widget = QGridLayout()
        self.diceArea = QListWidget(mainWindow)
        try:
            self.load(jsonload(ospath.join(SAVE_DIR, "dice.rgd")))
        except:
            self.macros = [
                QListWidgetItem(QIcon('data/dice.png'), "Sample: 2d6"),
                QListWidgetItem(QIcon('data/dice.png'), "Sample: 4k2"),
                QListWidgetItem(QIcon('data/dice.png'), "Sample: 1dn3")
            ]
        for m in self.macros:
            self.diceArea.addItem(m)
        self.diceArea.currentRowChanged.connect(self.changeCurrentMacro)
        self.rollbutton = QPushButton(self.tr("Roll"), mainWindow)
        self.rollbutton.setToolTip(
            self.tr("Roll dice according to the selected macro."))
        self.addmacrobutton = QPushButton(self.tr("Add Macro"), mainWindow)
        self.addmacrobutton.setToolTip(
            self.tr("Add a new macro via a dialog box."))
        self.removemacrobutton = QPushButton(self.tr("Delete Macro"),
                                             mainWindow)
        self.removemacrobutton.setToolTip(
            self.tr("Remove the currently selected macro."))
        self.rollbutton.clicked.connect(self.rollDice)
        self.addmacrobutton.clicked.connect(self.summonMacro)
        self.removemacrobutton.clicked.connect(self.removeCurrentMacro)
        self.widget.addWidget(self.diceArea, 0, 0)
        self.widget.addWidget(self.rollbutton, 1, 0)
        self.widget.addWidget(self.addmacrobutton, 2, 0)
        self.widget.addWidget(self.removemacrobutton, 3, 0)
        self.realwidget.setLayout(self.widget)
        self.setWidget(self.realwidget)
        self.setObjectName("Dice Widget")
        mainWindow.addDockWidget(Qt.BottomDockWidgetArea, self)
        self.close()
        self.currentMacro = -1

    def changeCurrentMacro(self, n):
        self.currentMacro = n

    def rollDice(self):
        current = self.diceArea.item(self.currentMacro)
        if current is not None:
            text = UNICODE_STRING(current.text())
            self.rollRequested.emit(text[text.rfind(':') + 1:])

    def _addMacro(self, macro):
        self.macros.append(QListWidgetItem(QIcon('data/dice.png'), macro))
        self.diceArea.addItem(self.macros[len(self.macros) - 1])

    def addMacro(self, mac, macname):
        self.macros.append(
            QListWidgetItem(QIcon('data/dice.png'), macname + ': ' + mac))
        self.diceArea.addItem(self.macros[len(self.macros) - 1])
        jsondump(self.dump(), ospath.join(SAVE_DIR, "dice.rgd"))

    def removeCurrentMacro(self):
        if self.diceArea.item(self.currentMacro) != self.diceArea.currentItem(
        ):  #This SHOULD, probably, only occur if there are two items and the first is deleted. Probably.
            self.diceArea.takeItem(0)
            return
        self.diceArea.takeItem(self.currentMacro)
        jsondump(self.dump(), ospath.join(SAVE_DIR, "dice.rgd"))

    def summonMacro(self):
        self.macroRequested.emit()

    def load(self, obj):
        """Deserialize set of macros from a dictionary."""
        self.macros = []
        macroz = loadObject('diceRoller.macros', obj.get('macros'))
        for ID, macro in list(macroz.items()):
            self._addMacro(macro)

    def dump(self):
        """Serialize to an object valid for JSON dumping."""

        macroz = []
        for i in range(0, self.diceArea.count()):
            macroz.append(UNICODE_STRING(self.diceArea.item(i).text()))

        return dict(macros=dict([(i, macro)
                                 for i, macro in enumerate(macroz)]))

    rollRequested = signal(BASE_STRING,
                           doc="""Called when the roll button is hit.

		roll -- the dice to be rolled

		""")

    macroRequested = signal(
        doc="""Called when the add macro button is pressed.""")