Esempio n. 1
0
class TextCell(Cell):
    def __init__(self, app, row, column):
        super(TextCell, self).__init__(app, row, column)
        textAlign = self.styleGet('textAlign')
        self.textElement = TextElement(
            self.app, '', self.styleGet('font'),
            Location(CellAttachedPoint((0, 0), self, textAlign), textAlign),
            colour=self.styleGet('foreColour'))
        self.elements = [self.textElement]
        self._oldText = ''

    def setText(self, text):
        if text != self._oldText:
            self.textElement.setText(text)
            self._styleChanged = True
            self._oldText = text

    def _update(self):
        self.textElement.setFont(self.styleGet('font'))
        self.textElement.setColour(self.styleGet('foreColour'))
        textAlign = self.styleGet('textAlign')
        self.textElement.pos.anchor = textAlign
        self.textElement.pos.point.attachedAt = textAlign
        self.textElement.setShadow(self.styleGet('hasShadow'))
        self.textElement.setShadowColour(self.styleGet('shadowColour'))
Esempio n. 2
0
class ConnectingScreen(framework.CompoundElement):
    def __init__(self, app, serverName='server', onCancel=None):
        super(ConnectingScreen, self).__init__(app)
        colours = app.theme.colours

        self.text = TextElement(self.app,
                                'Connecting to %s...' % serverName,
                                self.app.screenManager.fonts.bigMenuFont,
                                ScaledLocation(512, 384, 'center'),
                                colour=colours.connectingColour)

        button = TextButton(
            self.app,
            Location(ScaledScreenAttachedPoint(ScaledSize(0, 300), 'center'),
                     'center'),
            'cancel',
            self.app.screenManager.fonts.bigMenuFont,
            colours.mainMenuColour,
            colours.white,
            onClick=onCancel)
        self.onCancel = button.onClick

        self.elements = [button, self.text]

    def setServer(self, serverName):
        self.text.setText('Connecting to %s...' % serverName)
        self.text.setFont(self.app.screenManager.fonts.bigMenuFont)
Esempio n. 3
0
class UpgradeDisplay(framework.CompoundElement):

    def __init__(self, app):
        super(UpgradeDisplay, self).__init__(app)
        self.player = None
        self.upgrade = None
        self.coinsText = TextElement(
            self.app, '', self.app.screenManager.fonts.coinsDisplayFont,
            Location(Screen(0.65, 0.01), 'midtop'),
            self.app.theme.colours.coinsDisplayColour,
            shadow=True)
        self.elements = [self.coinsText]

    def refresh(self):
        self.setUpgrade(self.upgrade, self.player)

    def tick(self, deltaT):
        super(UpgradeDisplay, self).tick(deltaT)
        if self.player:
            self.coinsText.setText('${}'.format(self.player.coins))
        else:
            self.coinsText.setText('')

    def setUpgrade(self, upgradeType, player):
        self.player = player
        self.upgrade = upgradeType
        if player is None or upgradeType is None:
            self.elements = [self.coinsText]
        else:
            pos = Location(Screen(0.6, 0), 'midtop')
            image = self.app.theme.sprites.upgradeImage(upgradeType)
            area = Area(
                RelativePoint(Screen(0.6, 0), (0, 52)),
                ScaledSize(50, 10), 'midtop')
            self.elements = [
                PictureElement(self.app, image, pos),
                self.coinsText,
            ]

            if upgradeType.enabled:
                self.elements.append(
                    CoinGauge(self.app, area, player, upgradeType))
            else:
                self.elements.append(
                    TextElement(self.app, 'DISABLED',
                        self.app.screenManager.fonts.ingameMenuFont,
                        Location(CanvasX(620, 68), 'midbottom'),
                        self.app.theme.colours.errorMessageColour))
Esempio n. 4
0
class WinnerMsg(framework.CompoundElement):
    def __init__(self, app):
        super(WinnerMsg, self).__init__(app)
        self.winnerMsg = TextElement(app, '',
                                     app.screenManager.fonts.winMessageFont,
                                     Location(Screen(0.5, 0.05),
                                              'midtop'), (64, 64, 64))
        self.background = SolidRect(
            app, (128, 128, 128), 150,
            PaddedRegion(self.winnerMsg, ScaledScalar(15)))
        self.elements = []

    def show(self, text, colour):
        self.winnerMsg.setText(text)
        self.background.colour = colour
        self.background.border = colour
        self.background.refresh()
        self.elements = [self.background, self.winnerMsg]

    def hide(self):
        self.elements = []
Esempio n. 5
0
class PasswordGUI(DialogBox):
    def __init__(self, app):
        size = Canvas(512, 384)
        DialogBox.__init__(self, app, size, 'Please authenticate')
        self._deferred = None
        self._host = None

        font = app.screenManager.fonts.defaultTextBoxFont
        btnColour = app.theme.colours.dialogButtonColour
        highlightColour = app.theme.colours.black
        errorTextColour = app.theme.colours.errorColour

        self.tabContainer = TabContainer(
            app,
            Region(topleft=self.Relative(0, 0), size=self.Relative(1, 0.75)),
            font, app.theme.colours.tabContainerColour)
        self.tabContainer.addTab(LoginTab(app))
        self.tabContainer.addTab(CreateAccountTab(app))

        self.errorText = TextElement(
            app, '', font, Location(self.Relative(0.5, 0.8), 'center'),
            errorTextColour)

        font = app.screenManager.fonts.bigMenuFont
        self.elements = [
            self.tabContainer,
            self.errorText,
            TextButton(app,
                       Location(self.Relative(0.3, 0.9), 'center'),
                       'Ok',
                       font,
                       btnColour,
                       highlightColour,
                       onClick=self.okClicked),
            TextButton(app,
                       Location(self.Relative(0.7, 0.9), 'center'),
                       'Cancel',
                       font,
                       btnColour,
                       highlightColour,
                       onClick=self.cancelClicked),
        ]
        self.cancelled = False

    def setCancelled(self, cancelled):
        self.cancelled = cancelled

    def processEvent(self, event):
        if event.type == pygame.KEYDOWN and event.key in (pygame.K_KP_ENTER,
                                                          pygame.K_RETURN):
            self.okClicked()
            return None
        else:
            return DialogBox.processEvent(self, event)

    def cancelClicked(self, element=None):
        self.close()
        self._deferred.callback(None)

    def okClicked(self, element=None):
        if self.tabContainer.selectedIndex == 1:
            create = True
            # Check that passwords match.
            tab = self.tabContainer.tabs[1]
            if tab.passwordField.value != tab.passwordField2.value:
                self.setErrorText('Passwords do not match!')
                return
        else:
            create = False
            tab = self.tabContainer.tabs[0]

        username = tab.usernameField.value
        password = tab.passwordField.value

        if len(username) == 0:
            self.setErrorText('You must give a username!')
            return
        if len(password) == 0:
            self.setErrorText('Password cannot be blank!')
            return

        self.close()
        self.app.identitySettings.usernames[self._host] = username
        self._deferred.callback((create, username, password))

    def getPassword(self, host, errorMsg=''):
        if self.showing:
            raise PasswordGUIError('PasswordGUI already showing')
        if self.cancelled:
            self.cancelled = False
            result = self._deferred = defer.Deferred()
            WeakCallLater(0.1, result, 'callback', None)
            return result
        self.setCaption(host)
        self.tabContainer.tabs[0].reset(host)
        self.tabContainer.tabs[1].reset()
        self.setErrorText(errorMsg)
        self.show()
        self._host = host
        result = self._deferred = defer.Deferred()
        return result

    def setErrorText(self, text):
        self.errorText.setText(text)
Esempio n. 6
0
class ThemeTab(Tab, framework.TabFriendlyCompoundElement):
    def __init__(self, app, onClose=None, onRestart=None):
        super(ThemeTab, self).__init__(app, 'Themes')

        self.onClose = Event()
        if onClose is not None:
            self.onClose.addListener(onClose)
        self.onRestart = Event()
        if onRestart is not None:
            self.onRestart.addListener(onRestart)

        font = self.app.screenManager.fonts.menuFont
        colours = self.app.theme.colours

        self.inactiveTheme = False
        self.originalTheme = app.theme.name

        # Static text
        self.staticText = [
            TextElement(self.app, 'theme information:', font,
                        ScaledLocation(960, 250, 'topright'),
                        colours.headingColour),
            TextElement(self.app, 'theme contents:', font,
                        ScaledLocation(960, 390, 'topright'),
                        colours.headingColour)
        ]

        # Dynamic text
        self.feedbackText = TextElement(
            self.app, 'Your current theme: %s' % (app.theme.name, ), font,
            ScaledLocation(512, 200, 'midtop'), colours.startButton)
        self.listHeaderText = TextElement(self.app, 'available themes:', font,
                                          ScaledLocation(70, 250),
                                          colours.headingColour)
        self.themeNameText = TextElement(self.app, 'Default Theme', font,
                                         ScaledLocation(960, 290, 'topright'),
                                         colours.startButton)
        self.themeAuthorText = TextElement(
            self.app, 'created by: Trosnoth Team', font,
            ScaledLocation(960, 330, 'topright'), colours.startButton)

        self.contents = []

        numContents = 4
        for yPos in range(430, 430 + numContents * 40 + 1, 40):
            self.contents.append(
                TextElement(self.app, '', font,
                            ScaledLocation(960, yPos, 'topright'),
                            colours.startButton))

        self.dynamicText = [
            self.feedbackText, self.listHeaderText, self.themeNameText,
            self.themeAuthorText
        ] + self.contents

        # Theme list
        self.themeList = ListBox(self.app, ScaledArea(70, 290, 400, 290), [],
                                 font, colours.listboxButtons)
        self.themeList.onValueChanged.addListener(self.updateSidebar)

        # Text buttons
        self.useThemeButton = button(app, 'use selected theme',
                                     self.applyTheme, (0, -125), 'midbottom')
        self.refreshButton = button(app, 'refresh', self.populateList,
                                    (-100, -75), 'midbottom')
        self.cancelButton = button(app, 'cancel', self.backToMain, (100, -75),
                                   'midbottom')
        self.restartButton = button(app, 'restart Trosnoth', self.restart,
                                    (0, -125), 'midbottom')

        self.buttons = [
            self.useThemeButton, self.refreshButton, self.cancelButton,
            self.restartButton
        ]

        # Combine the elements
        self.elements = self.staticText + self.dynamicText + self.buttons + [
            self.themeList
        ]

        self.contentTypes = {
            "sprites": "sprite",
            "blocks": "map block",
            "fonts": "font",
            "startupMenu": "backdrop"
        }

        # Populate the list of replays
        self.populateList()

    def populateList(self):

        defaultTheme = {
            "name": "Default Theme",
            "filename": "default",
            "author": "Trosnoth Team",
            "content": None,
            "source": "internal"
        }

        # Clear out the sidebar
        self.themeNameText.setText('')
        self.themeAuthorText.setText('')
        for element in self.contents:
            element.setText('')
        self.useThemeButton.setText('')
        self.restartButton.setText('')
        self.listHeaderText.setText('available themes:')
        self.themeList.index = -1

        userThemeDir = getPath(user, 'themes')
        internalThemeDir = getPath(themes)
        makeDirs(userThemeDir)

        themeList = []

        # Get a list of internal themes
        for dirName in os.listdir(internalThemeDir):
            if os.path.isdir(os.path.join(internalThemeDir, dirName)):
                themeList.append("i/%s" % dirName)

        # Get a list of user-defined themes
        for dirName in os.listdir(userThemeDir):
            if os.path.isdir(os.path.join(userThemeDir, dirName)):
                # Internal themes overrule user-defined themes
                if "i/" + dirName not in themeList and dirName != "default":
                    themeList.append("u/%s" % dirName)

        # Assume all themes are valid for now
        validThemes = themeList[:]

        self.themeInfo = {}

        for themeName in themeList:
            themeInfo = {"content": {}}

            if themeName.startswith("i/"):
                themeInfo['source'] = 'internal'
                directory = internalThemeDir
            else:
                themeInfo['source'] = 'user-defined'
                directory = userThemeDir

            themeNameList = themeName
            themeName = themeName[2:]

            themeInfo['filename'] = themeName[2:]

            anyContent = False

            for contentType in list(self.contentTypes.keys()):
                if themeInfo['source'] == 'internal':
                    contentDir = os.path.join(directory, themeName,
                                              contentType)
                else:
                    contentDir = os.path.join(directory, themeName,
                                              contentType)

                if not os.path.isdir(contentDir):
                    continue
                else:
                    fileCount = len([
                        f for f in os.listdir(contentDir)
                        if os.path.isfile(os.path.join(contentDir, f))
                    ])
                    if fileCount > 0:
                        anyContent = True
                        themeInfo["content"][contentType] = fileCount

            if not anyContent:
                validThemes.remove(themeNameList)
                continue

            infoFile = os.path.join(directory, themeName, "info.txt")
            if os.path.isfile(infoFile):
                infoFile = open(infoFile)
                infoContents = infoFile.readlines()
            else:
                infoContents = []

            if len(infoContents) >= 2:
                themeInfo["author"] = infoContents[1].strip()
            else:
                themeInfo["author"] = None

            if len(infoContents) >= 1:
                themeInfo["name"] = infoContents[0].strip()
            else:
                themeInfo["name"] = themeName

            self.themeInfo[themeName] = themeInfo

        self.themeInfo["default"] = defaultTheme

        # Sort the themes alphabetically
        items = [(v['filename'], n) for n, v in self.themeInfo.items()]
        items.sort()
        items = [n for v, n in items]
        self.themeList.setItems(items)

        if len(self.themeInfo) == 1:
            self.listHeaderText.setText("1 available theme:")
            self.themeList.index = 0
            self.updateSidebar(0)
        else:
            self.listHeaderText.setText("%d available themes:" %
                                        len(self.themeInfo))

    def updateSidebar(self, listID):
        # Update the details on the sidebar
        displayName = self.themeList.getItem(listID)

        themeInfo = self.themeInfo[displayName]

        if themeInfo['source'] == "internal":
            self.themeNameText.setText(themeInfo['name'] + " (built-in)")
        else:
            self.themeNameText.setText(themeInfo['name'])
        if themeInfo['author'] is not None:
            self.themeAuthorText.setText("by " + themeInfo['author'])
        else:
            self.themeAuthorText.setText("(creator unknown)")

        if themeInfo['content'] is None:
            for element in self.contents:
                element.setText('')
            self.contents[0].setText('N/A')
        else:
            count = 0
            for k, v in themeInfo['content'].items():
                suffix = ""
                if v != 1:
                    suffix = "s"

                text = "%d %s%s" % (v, self.contentTypes[k], suffix)
                self.contents[count].setText(text)
                count += 1

        self.restartButton.setText("")
        if self.app.displaySettings.theme != displayName:
            if displayName == self.originalTheme:
                self.useThemeButton.setText("revert back to this theme")
            else:
                self.useThemeButton.setText("use this theme")
        else:
            self.useThemeButton.setText("")

            if self.inactiveTheme:
                self.restartButton.setText('restart Trosnoth')

    def applyTheme(self):
        themeName = self.themeList.getItem(self.themeList.index)

        self.app.displaySettings.theme = themeName
        self.app.displaySettings.save()

        self.useThemeButton.setText("")

        if themeName != self.originalTheme:
            self.feedbackText.setText("You must restart Trosnoth for the "
                                      "'%s' theme to take effect." % themeName)
            self.restartButton.setText('restart Trosnoth')
            self.inactiveTheme = True
        else:
            self.feedbackText.setText('Your current theme: %s' %
                                      (self.app.theme.name, ))
            self.restartButton.setText("")
            self.inactiveTheme = False

    def restart(self):
        self.onRestart.execute()

    def backToMain(self):
        if self.inactiveTheme:
            self.feedbackText.setText("Your current theme: %s "
                                      "(restart required)" %
                                      self.app.displaySettings.theme)

        self.onClose.execute()

    def draw(self, surface):
        super(ThemeTab, self).draw(surface)
        width = max(int(3 * self.app.screenManager.scaleFactor), 1)
        scalePoint = self.app.screenManager.placePoint
        pygame.draw.line(surface, self.app.theme.colours.mainMenuColour,
                         scalePoint((512, 260)), scalePoint((512, 580)), width)
class GameProgressBar(framework.CompoundElement):
    def __init__(self, app, world, gameViewer):
        super(GameProgressBar, self).__init__(app)
        self.world = world
        self.gameViewer = gameViewer
        self.app = app
        self.disrupt = False
        self.disruptTick = 0

        colours = app.theme.colours
        self.black = colours.black
        self.blue = colours.team1Mn_zone
        self.red = colours.team2Mn_zone
        self.grey = colours.zoneBarNeutral

        self.barFont = app.screenManager.fonts.zoneBarFont

        # Define a few constants to make things easier
        self.triangleLength = 25
        self.sideDistance = 0
        self.barHeight = self.gameViewer.zoneBarHeight
        self.textSpace = 130
        self.neutralTextSpace = 15

        self._oldRect = None
        self._oldScale = None
        self.width = None
        self.mapLeft = None
        self.mapRight = None
        self.mapBottom = None
        self.xFarLeft = None
        self.xFarRight = None
        self.xLeft = None
        self.xRight = None
        self.yTop = None
        self.yBottom = None
        self.disruptAnimation = None
        self.calculateSize()

    def calculateSize(self):
        minimapRect = self.gameViewer.miniMap.getRect()
        scaleFactor = self.app.screenManager.scaleFactor
        if minimapRect == self._oldRect and scaleFactor == self._oldScale:
            return
        self._oldRect = minimapRect
        self._oldScale = scaleFactor

        # Width will always be between 1 and 2 inclusive
        self.width = min(max(int(3 * scaleFactor), 1), 2)

        self.mapLeft = minimapRect.left
        self.mapRight = minimapRect.right
        self.mapBottom = minimapRect.bottom
        self.xFarLeft = self.mapLeft + self.sideDistance
        self.xFarRight = self.mapRight - self.sideDistance

        self.xLeft = self.xFarLeft + self.triangleLength
        self.xRight = self.xFarRight - self.triangleLength

        self.yTop = self.mapBottom - 1
        self.yBottom = self.yTop + self.barHeight

        # Create the disrupted animation
        self.disruptAnimation = self.createDisrupted()

    def draw(self, surface):
        if not self.world.map:
            return
        self.calculateSize()
        super(GameProgressBar, self).draw(surface)

        if self.disrupt and random.random() < 0.2:
            disrupt = True
        else:
            disrupt = False

        # Automatically generated constants
        yTop = self.yTop
        yBottom = self.yBottom
        yText = yTop

        xFarLeft = self.xFarLeft
        xFarRight = self.xFarRight

        xLeft = self.xLeft
        xRight = self.xRight

        # Define the coordinates for the static shapes
        border = [
            (xFarLeft, yTop),
            (xFarRight, yTop),
            (xRight, yBottom),
            (xLeft, yBottom),
        ]

        blueTriangle = [
            (xFarLeft, yTop),
            (xLeft, yTop),
            (xLeft, yBottom),
        ]

        redTriangle = [
            (xFarRight, yTop),
            (xRight, yTop),
            (xRight, yBottom),
        ]

        # Get the information we need
        blueScore = self.getBlueScore()
        blueProportion = self.getBlueProportion()
        redScore = self.getRedScore()
        redProportion = self.getRedProportion()
        neutralScore = self.getNeutralScore()
        neutralProportion = self.getNeutralProportion()

        gameOver = self.isGameOver()

        # Define the coordinates for the dynamic shapes
        mutableBarLength = xRight - xLeft
        if redProportion > 0:
            blueBarLength = int(round(mutableBarLength * blueProportion))
        else:
            blueBarLength = mutableBarLength
        if blueProportion > 0:
            redBarLength = int(round(mutableBarLength * redProportion))
        else:
            redBarLength = mutableBarLength

        xNeutral = ((xLeft + blueBarLength) + (xRight - redBarLength)) / 2

        xFirstBar = xLeft + blueBarLength
        xSecondBar = xRight - redBarLength

        blueBar = [
            (xLeft, yTop),
            (xLeft + blueBarLength, yTop),
            (xLeft + blueBarLength, yBottom),
            (xLeft, yBottom),
        ]
        redBar = [
            (xRight - redBarLength, yTop),
            (xRight, yTop),
            (xRight, yBottom),
            (xRight - redBarLength, yBottom),
        ]
        greyBar = [
            (xLeft + blueBarLength + 1, yTop),
            (xRight - redBarLength - 1, yTop),
            (xRight - redBarLength - 1, yBottom),
            (xLeft + blueBarLength + 1, yBottom),
        ]

        # Draw the two triangles on the sides
        if blueProportion > 0:
            pygame.draw.polygon(surface, self.blue, blueTriangle, 0)
        elif redProportion > 0:
            pygame.draw.polygon(surface, self.red, blueTriangle, 0)
        else:
            pygame.draw.polygon(surface, self.grey, blueTriangle, 0)

        if redProportion > 0:
            pygame.draw.polygon(surface, self.red, redTriangle, 0)
        elif blueProportion > 0:
            pygame.draw.polygon(surface, self.blue, redTriangle, 0)
        else:
            pygame.draw.polygon(surface, self.grey, redTriangle, 0)

        # Draw the team colours
        if blueProportion > 0:
            pygame.draw.polygon(surface, self.blue, blueBar, 0)
        if redProportion > 0:
            pygame.draw.polygon(surface, self.red, redBar, 0)
        if neutralProportion > 0 and (blueScore > 0) == (redScore > 0):
            allNeutral = True
            pygame.draw.polygon(surface, self.grey, greyBar, 0)
        else:
            allNeutral = False

        # Draw the black seperator line(s)
        if not gameOver:
            pygame.draw.line(surface, self.black, (xFirstBar, yTop),
                             (xFirstBar, yBottom), self.width)
            if neutralScore != 0:
                pygame.draw.line(surface, self.black, (xSecondBar, yTop),
                                 (xSecondBar, yBottom), self.width)

        # Draw the disruption
        if disrupt:
            surface.blit(self.disruptAnimation.getImage(),
                         (self.xFarLeft, self.yTop))

        # Draw the border last so that it goes on top
        colours = self.app.theme.colours
        pygame.draw.polygon(surface, self.black, border, self.width)
        pygame.draw.line(surface, colours.minimapBorder,
                         (self.mapLeft, self.mapBottom - 1),
                         (self.mapRight, self.mapBottom - 1), 2)

        # Define the necessary text
        self.blueText = TextElement(self.app,
                                    '',
                                    self.barFont,
                                    Location((xFirstBar - 5, yText),
                                             'topright'),
                                    colour=colours.black)
        self.neutralText = TextElement(self.app,
                                       '',
                                       self.barFont,
                                       Location((xNeutral, yText), 'midtop'),
                                       colour=colours.black)
        self.redText = TextElement(self.app,
                                   '',
                                   self.barFont,
                                   Location((xSecondBar + 7, yText),
                                            'topleft'),
                                   colour=colours.black)

        if not disrupt:
            blueString = self.getScoreText(blueScore)
            redString = self.getScoreText(redScore)

            if xSecondBar - xFirstBar > self.neutralTextSpace or allNeutral:
                neutralString = self.getScoreText(neutralScore)
            else:
                neutralString = ''

            self.blueText.setText(blueString)
            self.redText.setText(redString)
            self.neutralText.setText(neutralString)
        else:
            self.blueText.setText('')
            self.redText.setText('')
            self.neutralText.setText('')

        # Draw the text
        self.blueText.draw(surface)
        self.redText.draw(surface)
        self.neutralText.draw(surface)

    def createDisrupted(self):
        screens = []
        for a in range(0, 4):
            screen = (pygame.surface.Surface((self.xFarRight - self.xFarLeft,
                                              self.gameViewer.zoneBarHeight)))
            x = y = 0
            xL = 1
            xR = self.xFarRight - self.xFarLeft - 1
            rect = pygame.rect.Rect(0, 0, 2, 2)
            disruptColours = [self.red, self.blue]
            while y < self.gameViewer.zoneBarHeight:
                while x < xR:
                    rect.left = x
                    rect.top = y
                    pygame.draw.rect(screen, random.choice(disruptColours),
                                     rect, 0)
                    x += 2
                xL += 2
                xR -= 2
                x = xL
                y += 2
            screen.set_colorkey((0, 0, 0))
            screens.append(screen)
        return Animation(0.1, timeNow, *screens)

    def getScoreText(self, score):
        raise NotImplementedError

    def getBlueScore(self):
        raise NotImplementedError

    def getRedScore(self):
        raise NotImplementedError

    def getNeutralScore(self):
        raise NotImplementedError

    def getBlueProportion(self):
        raise NotImplementedError

    def getNeutralProportion(self):
        raise NotImplementedError

    def getRedProportion(self):
        raise NotImplementedError

    def isGameOver(self):
        raise NotImplementedError
Esempio n. 8
0
    def __init__(self, app, onClose=None):
        super(SoundSettingsTab, self).__init__(app, 'Sounds')

        self.onClose = Event()
        if onClose is not None:
            self.onClose.addListener(onClose)

        font = self.app.screenManager.fonts.bigMenuFont
        colours = app.theme.colours

        text = [
            TextElement(self.app, 'Music Volume', font,
                        ScaledLocation(400, 285, 'topright'),
                        colours.headingColour),
            TextElement(self.app, 'Enable Music', font,
                        ScaledLocation(400, 355, 'topright'),
                        colours.headingColour),
            TextElement(self.app, 'Sound Volume', font,
                        ScaledLocation(400, 425, 'topright'),
                        colours.headingColour),
            TextElement(self.app, 'Enable Sound', font,
                        ScaledLocation(400, 495, 'topright'),
                        colours.headingColour),
        ]

        initVolume = app.soundSettings.musicVolume
        musicVolumeLabel = TextElement(self.app, '%d' % (initVolume, ), font,
                                       ScaledLocation(870, 280, 'topleft'),
                                       colours.headingColour)

        self.musicVolumeSlider = Slider(self.app,
                                        ScaledArea(450, 280, 400, 40))
        onSlide = lambda volume: musicVolumeLabel.setText('%d' % volume)
        self.musicVolumeSlider.onSlide.addListener(onSlide)
        self.musicVolumeSlider.onValueChanged.addListener(onSlide)
        self.musicVolumeSlider.setVal(initVolume)

        self.musicBox = CheckBox(self.app,
                                 ScaledLocation(450, 360),
                                 text='',
                                 font=font,
                                 colour=(192, 192, 192),
                                 initValue=app.soundSettings.musicEnabled)

        initSndVolume = app.soundSettings.soundVolume
        soundVolumeLabel = TextElement(self.app,
                                       '%d' % (initSndVolume, ), font,
                                       ScaledLocation(870, 420, 'topleft'),
                                       colours.headingColour)

        self.soundVolumeSlider = Slider(self.app,
                                        ScaledArea(450, 420, 400, 40))
        onSlide = lambda volume: soundVolumeLabel.setText('%d' % volume)
        self.soundVolumeSlider.onSlide.addListener(onSlide)
        self.soundVolumeSlider.onValueChanged.addListener(onSlide)
        self.soundVolumeSlider.setVal(initSndVolume)

        self.soundBox = CheckBox(self.app,
                                 ScaledLocation(450, 500),
                                 text='',
                                 font=font,
                                 colour=(192, 192, 192),
                                 initValue=app.soundSettings.soundEnabled)

        self.buttons = [
            button(app,
                   'save',
                   self.saveSettings, (-100, -75),
                   'midbottom',
                   secondColour=app.theme.colours.white),
            button(app,
                   'cancel',
                   self.onClose.execute, (100, -75),
                   'midbottom',
                   secondColour=app.theme.colours.white)
        ]

        self.elements = text + [
            musicVolumeLabel, self.musicVolumeSlider, self.musicBox,
            soundVolumeLabel, self.soundVolumeSlider, self.soundBox
        ] + self.buttons
Esempio n. 9
0
class AchievementBox(framework.CompoundElement):
    achievementDefs = availableAchievements

    def __init__(self, app, player, achievementId):
        super(AchievementBox, self).__init__(app)
        self.app = app
        self.player = player

        self.achievements = [achievementId]

        self.width = 453
        self.height = 75

        self._setColours()

        self.area = Area(
            FullScreenAttachedPoint(ScaledSize(0, -100), 'midbottom'),
            ScaledSize(self.width, self.height), 'midbottom')

        self.smlBox = Area(
            FullScreenAttachedPoint(ScaledSize(-self.width / 2 + 6,
                                               -104), 'midbottom'),
            ScaledSize(66, 66), 'bottomleft')

        self.titleText = TextElement(
            self.app, "ACHIEVEMENT UNLOCKED!", self.fonts.achievementTitleFont,
            Location(
                FullScreenAttachedPoint(
                    ScaledSize(73 / 2, -100 - self.height + 10), 'midbottom'),
                'midtop'), self.borderColour)

        self.nameText = TextElement(
            self.app,
            self.achievementDefs.getAchievementDetails(achievementId)[0],
            self.fonts.achievementNameFont,
            Location(
                FullScreenAttachedPoint(ScaledSize(73 / 2, -100 - 13),
                                        'midbottom'),
                'midbottom'), self.colours.black)

        self.elements = [self.titleText, self.nameText]
        self._updateImage()

        self.cycler = WeakLoopingCall(self, 'cycleAchievements')
        self.cycler.start(5.0, now=False)

    def addAchievement(self, achievementId):
        self.achievements.append(achievementId)
        self.titleText.setText("%d ACHIEVEMENTS UNLOCKED!" %
                               len(self.achievements))

    def _updateImage(self):
        try:
            filepath = self.app.theme.getPath('achievements',
                                              '%s.png' % self.achievements[0])
        except IOError:
            filepath = self.app.theme.getPath('achievements', 'default.png')

        image = pygame.image.load(filepath).convert()
        image = pygame.transform.smoothscale(
            image,
            ScaledSize(64, 64).getSize(self.app))

        if type(self.elements[-1]) == PictureElement:
            self.elements.pop()

        self.image = PictureElement(
            self.app, image,
            Location(
                FullScreenAttachedPoint(ScaledSize(-self.width / 2 + 7, -105),
                                        'midbottom'), 'bottomleft'))

        self.elements.append(self.image)

    def cycleAchievements(self):
        del self.achievements[0]

        if len(self.achievements) == 0:
            self.cycler.stop()
            return
        elif len(self.achievements) == 1:
            self.titleText.setText("ACHIEVEMENT UNLOCKED!")
        else:
            self.titleText.setText("%d ACHIEVEMENTS UNLOCKED!" %
                                   len(self.achievements))

        self.nameText.setText(
            self.achievementDefs.getAchievementDetails(
                self.achievements[0])[0])
        self._updateImage()

    def _setColours(self):
        self.colours = self.app.theme.colours
        self.fonts = self.app.screenManager.fonts

        if self.player.teamId == 'A':
            self.borderColour = self.colours.achvBlueBorder
            self.bgColour = self.colours.achvBlueBackground
        else:
            self.borderColour = self.colours.achvRedBorder
            self.bgColour = self.colours.achvRedBackground

    def _getRect(self, area):
        return area.getRect(self.app)

    def draw(self, surface):
        mainRect = self._getRect(self.area)
        boxRect = self._getRect(self.smlBox)

        surface.fill(self.bgColour, mainRect)
        pygame.draw.rect(surface, self.borderColour, mainRect, 2)

        surface.fill(self.colours.white, boxRect)
        pygame.draw.rect(surface, self.borderColour, boxRect, 1)

        super(AchievementBox, self).draw(surface)
Esempio n. 10
0
class ChatBox(framework.CompoundElement):
    def __init__(self, app, world, interface):
        super(ChatBox, self).__init__(app)

        self.world = world
        self.app = app
        self.interface = interface

        self.font = self.app.screenManager.fonts.newChatFont

        self.frameColour = self.app.theme.colours.chatFrameColour
        self.insideColour = self.app.theme.colours.chatInsideColour
        self.textColour = self.app.theme.colours.chatNormalColour

        self.sayToTeam = TextElement(
            self.app,
            text="Say to team:",
            font=self.font,
            pos=Location(FullScreenAttachedPoint((20, 501), 'topleft'),
                         'topleft'),
            colour=self.textColour,
            shadow=True,
        )

        self.inputPosition = Area(
            FullScreenAttachedPoint((145, 500), 'topleft'), (370, 20),
            'topleft')
        self.input = InputBox(self.app, self.inputPosition, font=self.font)
        self.input.onEnter.addListener(
            lambda sender: self.hitEnter(sender.value))
        self.input.onEsc.addListener(lambda sender: self.close())
        self.input.onClick.addListener(self.setFocus)

        self.messages = MessageBank(
            self.app, 10, 100,
            Location(FullScreenAttachedPoint((20, 470), 'topleft'), 'topleft'),
            'left', 'bottom', self.font)

        self._chatOpen = False
        self.teamChat = True
        self.player = None

        self.messageBuffer = []

        self.MESSAGE_GAP = self.font.getHeight(self.app)

        self.elements = [self.messages]

    def setPlayer(self, player):
        self.player = player
        if self.player.team is None:
            self.refreshMode()

    def canTeamChat(self):
        return self.player and self.player.team is not None

    def switchModes(self):
        self.teamChat = not self.teamChat
        self.refreshMode()

    def refreshMode(self):
        self.teamChat = self.teamChat and self.canTeamChat()
        if self.teamChat:
            self.sayToTeam.setText('Say to team:')
        else:
            self.sayToTeam.setText('Say to all:')

    def hitEnter(self, senderValue):
        if senderValue.strip() != '':
            self.sendChat(senderValue)
        self.input.clear()

    def sendChat(self, senderValue):
        # Interpret lines with initial hash.
        if senderValue.startswith('#'):
            i = 1
            while senderValue[i:i + 1].isdigit():
                i += 1
            try:
                playerId = bytes([int(senderValue[1:i])])
            except ValueError:
                pass
            else:
                self.interface.sendPrivateChat(self.player, playerId,
                                               senderValue[i:].lstrip())
                return

        if self.teamChat:
            self.interface.sendTeamChat(self.player, senderValue)
        else:
            self.interface.sendPublicChat(self.player, senderValue)

    def refresh(self):
        if not self.isOpen():
            return
        self.elements = [self.sayToTeam, self.input]

        initialY = 470
        count = 0
        for text, nick, colour, firstLine in reversed(self.messageBuffer):
            currentY = initialY - count * self.MESSAGE_GAP
            if currentY < 200 or count >= 10:
                break

            if firstLine and nick is not None:
                person = TextElement(
                    self.app,
                    text=nick,
                    font=self.font,
                    pos=Location(
                        FullScreenAttachedPoint((20, currentY), 'topleft'),
                        'topleft'),
                    colour=colour,
                    shadow=True,
                )

                xOffset = person._getRect().width
                self.elements.append(person)

                text = text[len(nick):]

            else:
                xOffset = 0

            if nick is None:
                colour = self.app.theme.colours.serverChat
            else:
                colour = self.textColour

            message = TextElement(
                self.app,
                text=text,
                font=self.font,
                pos=Location(
                    FullScreenAttachedPoint((20 + xOffset, currentY),
                                            'topleft'), 'topleft'),
                colour=colour,
                shadow=True,
            )
            self.elements.append(message)
            count += 1

    def open(self):
        self._chatOpen = True
        self.refresh()
        self.setFocus(self.input)
        self.input.clear()

    def close(self):
        self._chatOpen = False
        self.elements = [self.messages]
        pygame.key.set_repeat()

    def isOpen(self):
        return self._chatOpen

    def newMessage(self, message, nick, colour):

        message = nick + message

        wrappedMessage = wrapline(message, self.font._getFont(self.app), 480)

        # Update the "box open" message elements
        firstLine = True
        for line in wrappedMessage:
            self.messageBuffer.append((line, nick, colour, firstLine))
            firstLine = False

        while len(self.messageBuffer) > 100:
            self.messageBuffer.pop(0)

        # Update the "box closed" message elements
        firstLine = wrappedMessage.pop(0)[len(nick):]
        parts = [(nick, colour), (firstLine, self.textColour)]

        self.messages.newColourMessage(parts)

        for line in wrappedMessage:
            self.messages.newMessage(line, self.textColour)

        self.refresh()

    def newServerMessage(self, message):
        '''Server messages don't follow the format of normal messages and
        require special attention to display.'''

        colour = self.app.theme.colours.serverChat
        wrappedMessage = wrapline("SERVER" + message,
                                  self.font._getFont(self.app), 480)

        # Update the "box open" message elements
        firstLine = True
        for line in wrappedMessage:
            self.messageBuffer.append((line, None, colour, firstLine))
            firstLine = False

        while len(self.messageBuffer) > 100:
            self.messageBuffer.remove(0)

        # Update the "box closed" message elements
        for line in wrappedMessage:
            self.messages.newMessage(line, colour)

        self.refresh()

    def _getRect(self):
        return self.area.getRect(self.app)

    def draw(self, surface):

        if self._chatOpen:

            pointX = 5
            pointY = 300

            # Draw the frame first
            frame = pygame.Surface((520, 230))
            frame.fill(self.frameColour)

            mainBox = pygame.Surface((500, 180))
            mainBox.fill(self.insideColour)

            sayBox = pygame.Surface((120, 20))
            sayBox.fill(self.insideColour)

            if self.app.displaySettings.alphaOverlays:
                mainBox.set_alpha(128)
                sayBox.set_alpha(128)
                frame.set_alpha(128)

            surface.blit(frame, (pointX, pointY))
            surface.blit(mainBox, (pointX + 10, pointY + 10))
            surface.blit(sayBox, (pointX + 10, pointY + 200))

        super(ChatBox, self).draw(surface)

    def processEvent(self, event):
        if not self.isOpen():
            return event

        if event.type == pygame.KEYDOWN and event.key in (pygame.K_LCTRL,
                                                          pygame.K_RCTRL):
            self.switchModes()
        else:
            return self.input.processEvent(event)
Esempio n. 11
0
class SavedGameTab(Tab):
    def __init__(self, app, tabContainer, onCancel=None, onReplay=None):
        super(SavedGameTab, self).__init__(app, 'Saved Games')
        self.app = app
        self.tabContainer = tabContainer
        self.onCancel = Event(listener=onCancel)
        self.onReplay = Event(listener=onReplay)

        font = self.app.screenManager.fonts.ampleMenuFont
        smallFont = self.app.screenManager.fonts.menuFont
        colours = app.theme.colours

        # Static text
        self.staticText = [
            TextElement(self.app, 'server details:', font,
                        ScaledLocation(960, 200, 'topright'),
                        colours.headingColour),
            TextElement(self.app, 'date and time:', font,
                        ScaledLocation(960, 370, 'topright'),
                        colours.headingColour),
            TextElement(self.app, 'replay:', font,
                        ScaledLocation(620, 550, 'topleft'),
                        colours.headingColour),
            TextElement(self.app, 'stats:', font,
                        ScaledLocation(620, 605, 'topleft'),
                        colours.headingColour)
        ]

        # Dynamic text
        self.listHeaderText = TextElement(self.app, 'available game files:',
                                          font, ScaledLocation(65, 200),
                                          colours.headingColour)
        self.noFiles1Text = TextElement(self.app, '', font,
                                        ScaledLocation(65, 260),
                                        colours.noGamesColour)
        self.noFiles2Text = TextElement(self.app, '', font,
                                        ScaledLocation(65, 310),
                                        colours.noGamesColour)
        self.serverNameText = TextElement(self.app, '', smallFont,
                                          ScaledLocation(960, 255, 'topright'),
                                          colours.startButton)
        self.serverDetailsText = TextElement(
            self.app, '', smallFont, ScaledLocation(960, 295, 'topright'),
            colours.startButton)
        self.dateText = TextElement(self.app, '', smallFont,
                                    ScaledLocation(960, 425, 'topright'),
                                    colours.startButton)
        self.lengthText = TextElement(self.app, '', smallFont,
                                      ScaledLocation(960, 465, 'topright'),
                                      colours.startButton)
        self.noReplayText = TextElement(self.app, '', smallFont,
                                        ScaledLocation(960, 550, 'topright'),
                                        colours.noGamesColour)
        self.noStatsText = TextElement(self.app, '', smallFont,
                                       ScaledLocation(960, 605, 'topright'),
                                       colours.noGamesColour)

        self.dynamicText = [
            self.listHeaderText, self.noFiles1Text, self.noFiles2Text,
            self.serverNameText, self.serverDetailsText, self.dateText,
            self.lengthText, self.noReplayText, self.noStatsText
        ]

        # Text buttons
        self.watchButton = TextButton(self.app,
                                      ScaledLocation(960, 550,
                                                     'topright'), '', font,
                                      colours.secondMenuColour, colours.white)
        self.watchButton.onClick.addListener(self.watchReplay)

        self.statsButton = TextButton(self.app,
                                      ScaledLocation(960, 605,
                                                     'topright'), '', font,
                                      colours.secondMenuColour, colours.white)
        self.statsButton.onClick.addListener(self.viewStats)

        self.refreshButton = TextButton(self.app,
                                        ScaledLocation(620, 665,
                                                       'topleft'), 'refresh',
                                        font, colours.secondMenuColour,
                                        colours.white)
        self.refreshButton.onClick.addListener(self.populateList)

        self.cancelButton = TextButton(self.app,
                                       ScaledLocation(960, 665, 'topright'),
                                       'cancel', font,
                                       colours.secondMenuColour, colours.white)
        self.cancelButton.onClick.addListener(self._cancel)

        self.loadFileButton = TextButton(
            self.app, ScaledLocation(960, 190, 'bottomright'), 'load file...',
            font, colours.mainMenuColour, colours.mainMenuHighlight)
        self.loadFileButton.onClick.addListener(self.showOpenDialog)

        self.buttons = [
            self.watchButton, self.statsButton, self.refreshButton,
            self.cancelButton, self.loadFileButton
        ]

        # Replay list
        self.gameList = ListBox(self.app, ScaledArea(65, 255, 500, 450), [],
                                smallFont, colours.listboxButtons)
        self.gameList.onValueChanged.addListener(self.updateSidebar)

        # Combine the elements
        self.elementsFiles = (self.staticText + self.dynamicText +
                              self.buttons + [self.gameList])
        self.elementsNoFiles = self.dynamicText + self.buttons

        # Populate the list of replays
        self.populateList()

    def _cancel(self, sender):
        self.onCancel.execute()

    def showOpenDialog(self, sender):
        root = Tk()
        root.withdraw()
        tksupport.install(root)
        filename = askopenfilename(
            defaultextension='.trosrepl',
            filetypes=[
                ('Trosnoth replay', '*.trosrepl'),
            ],
            initialdir=getPath(user, replayDir),
            title='Select replay',
        )
        if filename:
            self.onReplay.execute(filename)

    def populateList(self, sender=None):

        # Clear out the sidebar
        for item in self.dynamicText:
            item.setText('')
        self.listHeaderText.setText('available game files:')
        self.gameList.index = -1
        self.elements = self.elementsFiles[:]

        # Get a list of files with the name '*.tros'
        logDir = getPath(user, gameDir)
        makeDirs(logDir)
        fileList = []

        for fname in os.listdir(logDir):
            if os.path.splitext(fname)[1] == gameExt:
                fileList.append(fname)

        # Assume all files are valid for now
        validFiles = fileList[:]

        self.gameInfo = {}
        oldFound = False

        for fname in fileList:
            try:
                game = RecordedGame(os.path.join(logDir, fname))
            except RecordedGameException:
                validFiles.remove(fname)
                continue
            except:
                log.warning('invalid file: %s', fname)
                continue
            else:
                if game.recordedGameVersion != recordedGameVersion:
                    validFiles.remove(fname)
                    oldFound = True

            self.gameInfo[os.path.splitext(fname)[0]] = game

        # Sort the games with most recent first.
        items = [(v.unixTimestamp, n) for n, v in self.gameInfo.iteritems()]
        items.sort(reverse=True)
        items = [n for v, n in items]
        self.gameList.setItems(items)

        if len(self.gameInfo) == 0:
            self.elements = self.elementsNoFiles[:]
            self.listHeaderText.setText('0 available game files:')
            if oldFound:
                self.noFiles1Text.setText('Some games were found from')
                self.noFiles2Text.setText('previous Trosnoth versions')
            else:
                self.noFiles1Text.setText('You have not yet run any')
                self.noFiles2Text.setText('games on this computer')
        else:
            self.gameList.setIndex(0)
            self.updateSidebar(0)
            if len(self.gameInfo) == 1:
                self.listHeaderText.setText('1 available game file:')
            else:
                self.listHeaderText.setText('{} available game files:'.format(
                    len(self.gameInfo)))

    def updateSidebar(self, listID):
        # Update the details on the sidebar
        displayName = self.gameList.getItem(listID)

        # Server title
        self.serverNameText.setText(self.gameInfo[displayName].alias)

        # Date and time of match
        datePython = map(int, self.gameInfo[displayName].dateTime.split(','))
        dateString = time.strftime('%a %d/%m/%y, %H:%M', datePython)
        self.dateText.setText(dateString)

        # Length of match
        dateUnix = time.mktime(datePython)
        if self.gameInfo[displayName].wasFinished():
            lastUnix = self.gameInfo[displayName].gameFinishedTimestamp

            lengthSeconds = int(lastUnix - dateUnix)
            lengthMinutes, lengthSeconds = divmod(lengthSeconds, 60)

            secPlural = ('s', '')[lengthSeconds == 1]
            minPlural = ('s', '')[lengthMinutes == 1]
            if lengthMinutes == 0:
                lengthString = '{} second{}'.format(lengthSeconds, secPlural)
            else:
                lengthString = '{} min{}, {} sec{}'.format(
                    lengthMinutes, minPlural, lengthSeconds, secPlural)

            self.lengthText.setText(lengthString)
        else:
            self.lengthText.setText('')

        # Enable the replay button
        if (self.gameInfo[displayName].replayFilename is not None
                and os.path.exists(self.gameInfo[displayName].replayFilename)):
            self.watchButton.setText('watch')
            self.noReplayText.setText('')
        else:
            self.watchButton.setText('')
            self.noReplayText.setText('unavailable')

        # Enabled the stats button
        if (self.gameInfo[displayName].statsFilename is not None
                and os.path.exists(self.gameInfo[displayName].statsFilename)):
            self.statsButton.setText('view')
            self.noStatsText.setText('')
        else:
            self.statsButton.setText('')
            self.noStatsText.setText('unavailable')

    def watchReplay(self, sender):
        '''Watch replay button was clicked.'''
        # Try to create a replay server.
        self.onReplay.execute(
            self.gameInfo[self.gameList.getItem()].replayFilename)

    def viewStats(self, sender=None):
        '''View stats button was clicked.'''
        game = self.gameInfo[self.gameList.getItem()]

        self.htmlPath = game.generateHtmlFile()
        browser.openPage(self.app, self.htmlPath)

    def draw(self, surface):
        super(SavedGameTab, self).draw(surface)

        rect = self.tabContainer._getTabRect()
        verLineX = rect.left + (rect.width * 0.6)
        horLineY = rect.top + (rect.height * 0.68)

        colour = self.app.theme.colours.replayTabBorder

        pygame.draw.line(surface, colour, (verLineX, rect.top),
                         (verLineX, rect.bottom),
                         self.tabContainer._getBorderWidth())
        pygame.draw.line(surface, colour, (verLineX, horLineY),
                         (rect.right, horLineY),
                         self.tabContainer._getBorderWidth())
Esempio n. 12
0
class DisplaySettingsTab(Tab, framework.TabFriendlyCompoundElement):
    def __init__(self, app, onClose=None):
        super(DisplaySettingsTab, self).__init__(app, 'Display')

        self.onClose = Event()
        if onClose is not None:
            self.onClose.addListener(onClose)

        font = self.app.screenManager.fonts.bigMenuFont
        smallNoteFont = self.app.screenManager.fonts.smallNoteFont

        colour = self.app.theme.colours.headingColour

        def mkText(text, x, y, textFont=font, anchor='topright'):
            return TextElement(self.app, text, textFont,
                               ScaledLocation(x, y, anchor), colour)

        self.text = [
            mkText('X', 640, 280),
            mkText('Screen resolution', 430, 280),
            mkText('Fullscreen mode', 430, 360),
            mkText('Graphics detail', 430, 440),
            mkText('low', 460, 475, textFont=smallNoteFont, anchor='midtop'),
            mkText('high', 845, 475, textFont=smallNoteFont, anchor='midtop'),
            mkText('Show timings', 430, 525),
        ]

        self.invalidInputText = TextElement(self.app, '', font,
                                            ScaledLocation(512, 230, 'midtop'),
                                            (192, 0, 0))

        self.widthInput = prompt.InputBox(self.app,
                                          ScaledArea(460, 265, 150, 60),
                                          initValue=str(
                                              self.app.screenManager.size[0]),
                                          font=font,
                                          maxLength=4,
                                          validator=prompt.intValidator)

        self.widthInput.onEnter.addListener(lambda sender: self.saveSettings())
        self.widthInput.onClick.addListener(self.setFocus)
        self.widthInput.onTab.addListener(self.tabNext)

        self.heightInput = prompt.InputBox(self.app,
                                           ScaledArea(652, 265, 150, 60),
                                           initValue=str(
                                               self.app.screenManager.size[1]),
                                           font=font,
                                           maxLength=4,
                                           validator=prompt.intValidator)

        self.heightInput.onEnter.addListener(
            lambda sender: self.saveSettings())
        self.heightInput.onClick.addListener(self.setFocus)
        self.heightInput.onTab.addListener(self.tabNext)

        self.tabOrder = [self.widthInput, self.heightInput]

        self.fullscreenBox = CheckBox(
            self.app,
            ScaledLocation(460, 365),
            text='',
            font=font,
            colour=(192, 192, 192),
            initValue=self.app.screenManager.isFullScreen(),
        )
        self.fullscreenBox.onValueChanged.addListener(self.fullscreenChanged)

        displaySettings = app.displaySettings

        self.detailSlider = Slider(
            self.app,
            ScaledArea(460, 430, 390, 40),
            bounds=(0, len(displaySettings.DETAIL_LEVELS) - 1),
            snap=True)
        self.detailSlider.setVal(
            displaySettings.DETAIL_LEVELS.index(displaySettings.detailLevel))
        self.detailSlider.onValueChanged.addListener(self.detailChanged)

        self.showTimingsBox = CheckBox(
            self.app,
            ScaledLocation(460, 530),
            text='',
            font=font,
            colour=(192, 192, 192),
            initValue=displaySettings.showTimings,
        )

        self.input = [
            self.widthInput, self.heightInput, self.widthInput,
            self.fullscreenBox, self.detailSlider, self.showTimingsBox
        ]

        self.elements = self.text + self.input + [
            self.invalidInputText,
            button(app,
                   'save',
                   self.saveSettings, (-100, -75),
                   'midbottom',
                   secondColour=app.theme.colours.white),
            button(app,
                   'cancel',
                   self.cancelMenu, (100, -75),
                   'midbottom',
                   secondColour=app.theme.colours.white),
        ]
        self.setFocus(self.widthInput)

    def detailChanged(self, newLevel):
        pass

    def cancelMenu(self):
        self.fullscreenBox.setValue(self.app.screenManager.isFullScreen())
        self.showTimingsBox.setValue(self.app.displaySettings.showTimings)
        self.heightInput.setValue(str(self.app.screenManager.size[1]))
        self.widthInput.setValue(str(self.app.screenManager.size[0]))

        self.onClose.execute()

    def saveSettings(self):
        displaySettings = self.app.displaySettings

        height = self.getInt(self.heightInput.value)
        width = self.getInt(self.widthInput.value)
        fullScreen = self.fullscreenBox.value
        detailLevel = displaySettings.DETAIL_LEVELS[self.detailSlider.getVal()]
        showTimings = self.showTimingsBox.value

        # The resolutionList is used when fullScreen is true.
        resolutionList = pygame.display.list_modes()
        resolutionList.sort()
        minResolution = resolutionList[0]
        maxResolution = resolutionList[-1]

        if not fullScreen:
            minResolution = (320, 240)

        # These values are used when fullScreen is false.
        widthRange = (minResolution[0], maxResolution[0])
        heightRange = (minResolution[1], maxResolution[1])

        if not widthRange[0] <= width <= widthRange[1]:
            self.incorrectInput('Screen width must be between %d and %d' %
                                (widthRange[0], widthRange[1]))
            width = None
            return
        if not heightRange[0] <= height <= heightRange[1]:
            self.incorrectInput('Screen height must be between %d and %d' %
                                (heightRange[0], heightRange[1]))
            height = None
            return
        if fullScreen:
            selectedResolution = (width, height)
            if selectedResolution not in resolutionList:
                self.incorrectInput('Selected resolution is not valid for '
                                    'this display')
                height = width = None
                return

        self.incorrectInput('')

        # Save these values.
        displaySettings.fullScreen = fullScreen
        displaySettings.detailLevel = detailLevel
        displaySettings.showTimings = showTimings
        if fullScreen:
            displaySettings.fsSize = (width, height)
        else:
            displaySettings.size = (width, height)

        # Write to file and apply.
        displaySettings.save()
        displaySettings.apply()

        self.onClose.execute()

    def getInt(self, value):
        if value == '':
            return 0
        return int(value)

    def incorrectInput(self, string):
        self.invalidInputText.setText(string)
        self.invalidInputText.setFont(self.app.screenManager.fonts.bigMenuFont)

    def fullscreenChanged(self, element):
        # If the resolution boxes haven't been touched, swap their values to
        # the appropriate resolution for the new mode.

        height = self.getInt(self.heightInput.value)
        width = self.getInt(self.widthInput.value)
        fullScreen = self.fullscreenBox.value

        if fullScreen:
            # Going to full screen mode.
            if (width, height) != self.app.displaySettings.size:
                return
            width, height = self.app.displaySettings.fsSize
        else:
            # Going from full screen mode.
            if (width, height) != self.app.displaySettings.fsSize:
                return
            width, height = self.app.displaySettings.size

        self.heightInput.setValue(str(height))
        self.widthInput.setValue(str(width))
Esempio n. 13
0
class KeymapTab(Tab):
    def __init__(self, app, onClose=None):
        super(KeymapTab, self).__init__(app, 'Controls')
        self.font = app.screenManager.fonts.bigMenuFont

        self.onClose = Event()
        if onClose is not None:
            self.onClose.addListener(onClose)

        # Break things up into categories
        movement = ['jump', 'down', 'left', 'right']
        menus = ['menu', 'more actions']
        actions = [
            'respawn', 'select upgrade', 'activate upgrade', 'change nickname',
            'ready'
        ]
        misc = ['chat', 'follow']
        upgrades = [
            upgradeClass.action for upgradeClass in sorted(
                allUpgrades, key=lambda upgradeClass: upgradeClass.order)
        ]
        upgrades.append('no upgrade')

        display = ['leaderboard', 'toggle interface', 'toggle terminal']

        actionNames = {
            'select upgrade': 'Select upgrade',
            'activate upgrade': 'Activate upgrade',
            'change nickname': 'Change nickname',
            'chat': 'Chat',
            'down': 'Drop down',
            'follow': 'Auto pan (replay)',
            'jump': 'Jump',
            'leaderboard': 'Show leaderboard',
            'left': 'Move left',
            'menu': 'Main menu',
            'more actions': 'Advanced',
            'no upgrade': 'Deselect upgrade',
            'ready': 'Toggle ready',
            'respawn': 'Respawn',
            'right': 'Move right',
            'status bar': 'Status bar',
            'timer': 'Show timer',
            'toggle interface': 'Toggle HUD',
            'toggle terminal': 'Toggle terminal',
            'zone progress': 'Show zone bar',
        }
        actionNames.update((upgradeClass.action, upgradeClass.name)
                           for upgradeClass in allUpgrades)

        # Organise the categories by column
        self.layout = [
            [movement, menus],
            [actions, display],
            [upgrades, misc],
        ]

        self.errorInfo = TextElement(self.app, '', self.font,
                                     ScaledLocation(512, 580, 'center'))
        self.text = [self.errorInfo]
        self.inputLookup = {}
        xPos = 190

        # Lay everything out automatically.
        keymapFont = self.app.screenManager.fonts.keymapFont
        keymapInputFont = self.app.screenManager.fonts.keymapInputFont
        for column in self.layout:  # Each column
            yPos = 200
            for category in column:  # Each category
                for action in category:  # Each action
                    # Draw action name (eg. Respawn)
                    self.text.append(
                        TextElement(self.app, actionNames[action], keymapFont,
                                    ScaledLocation(xPos, yPos + 6, 'topright'),
                                    self.app.theme.colours.headingColour))

                    # Create input box
                    box = prompt.KeycodeBox(self.app,
                                            ScaledArea(xPos + 10, yPos, 100,
                                                       30),
                                            font=keymapInputFont)
                    box.onClick.addListener(self.setFocus)
                    box.onChange.addListener(self.inputChanged)
                    box.__action = action
                    self.inputLookup[action] = box

                    yPos += 35  # Between items
                yPos += 35  # Between categories
            xPos += 320  # Between columns

        self.elements = self.text + self.inputLookup.values() + [
            button(app,
                   'restore default controls',
                   self.restoreDefaults, (0, -125),
                   'midbottom',
                   secondColour=app.theme.colours.white),
            button(app,
                   'save',
                   self.saveSettings, (-100, -75),
                   'midbottom',
                   secondColour=app.theme.colours.white),
            button(app,
                   'cancel',
                   self.cancel, (100, -75),
                   'midbottom',
                   secondColour=app.theme.colours.white),
        ]

        self.populateInputs()

    def inputChanged(self, box):
        # Remove the old key.
        try:
            oldKey = self.keyMapping.getkey(box.__action)
        except KeyError:
            pass
        else:
            del self.keyMapping[oldKey]

        # Set the new key.
        self.keyMapping[box.value] = box.__action

        # Refresh the display.
        self.refreshInputs()

    def populateInputs(self):
        # Set up the keyboard mapping.
        self.keyMapping = keyboard.KeyboardMapping(keymap.default_game_keys)

        try:
            # Try to load keyboard mappings from the user's personal settings.
            config = open(getPath(user, 'keymap'), 'rU').read()
            self.keyMapping.load(config)
        except IOError:
            pass

        # Refresh the display.
        self.refreshInputs()

    def refreshInputs(self):
        for column in self.layout:
            for category in column:
                for action in category:
                    # Get the current key and put it in the box.
                    try:
                        key = self.keyMapping.getkey(action)
                    except KeyError:
                        key = None
                    self.inputLookup[action].value = key

                    # Make the box white
                    self.inputLookup[action].backColour = (255, 255, 255)

    def restoreDefaults(self):
        self.keyMapping = keyboard.KeyboardMapping(keymap.default_game_keys)
        self.refreshInputs()

        self.incorrectInput(
            "Default controls restored: press 'save' to "
            "confirm", (0, 128, 0))

    def clearBackgrounds(self):
        for action in self.inputLookup:
            self.inputLookup[action].backColour = (255, 255, 255)
        self.setFocus(None)

    def saveSettings(self):
        # Perform the save.
        open(getPath(user, 'keymap'), 'w').write(self.keyMapping.save())

        emptyBoxes = []

        for box in self.inputLookup.itervalues():
            if box.value is None:
                emptyBoxes.append(box)

        if len(emptyBoxes) > 0:
            self.populateInputs()
            for box in emptyBoxes:
                box.backColour = self.app.theme.colours.invalidDataColour

            self.incorrectInput('Warning: some actions have no key',
                                (192, 0, 0))
        else:
            self.mainMenu()

    def incorrectInput(self, string, colour):
        self.errorInfo.setColour(colour)
        self.errorInfo.setText(string)
        self.errorInfo.setFont(self.font)

    def cancel(self):
        self.populateInputs()
        self.mainMenu()

    def mainMenu(self):
        self.incorrectInput('', (0, 0, 0))
        self.clearBackgrounds()
        self.onClose.execute()
Esempio n. 14
0
class KeymapTab(Tab):
    def __init__(self, app, onClose=None):
        super(KeymapTab, self).__init__(app, 'Controls')
        self.font = app.screenManager.fonts.bigMenuFont

        self.onClose = Event()
        if onClose is not None:
            self.onClose.addListener(onClose)

        # Break things up into categories
        movement = [
            ACTION_JUMP, ACTION_DOWN, ACTION_LEFT, ACTION_RIGHT, ACTION_HOOK
        ]
        menus = [ACTION_MAIN_MENU, ACTION_MORE_MENU]
        actions = [
            ACTION_UPGRADE_MENU, ACTION_USE_UPGRADE, ACTION_EDIT_PLAYER_INFO,
            ACTION_READY, ACTION_SHOW_TRAJECTORY, ACTION_EMOTE
        ]
        misc = [ACTION_CHAT, ACTION_FOLLOW]
        upgrades = [
            upgradeClass.action for upgradeClass in sorted(
                allUpgrades, key=lambda upgradeClass: upgradeClass.order)
        ]
        upgrades.append(ACTION_CLEAR_UPGRADE)

        display = [
            ACTION_LEADERBOARD_TOGGLE, ACTION_HUD_TOGGLE,
            ACTION_TERMINAL_TOGGLE
        ]

        actionNames = {
            ACTION_EDIT_PLAYER_INFO: 'Change nick / hat',
            ACTION_CHAT: 'Chat',
            ACTION_CLEAR_UPGRADE: 'Deselect upgrade',
            ACTION_DOWN: 'Drop down',
            ACTION_FOLLOW: 'Auto pan (replay)',
            ACTION_HOOK: 'Grappling hook',
            ACTION_HUD_TOGGLE: 'Toggle HUD',
            ACTION_JUMP: 'Jump',
            ACTION_LEADERBOARD_TOGGLE: 'Show leaderboard',
            ACTION_LEFT: 'Move left',
            ACTION_MAIN_MENU: 'Main menu',
            ACTION_MORE_MENU: 'Advanced',
            ACTION_READY: 'Toggle ready',
            ACTION_RIGHT: 'Move right',
            ACTION_TERMINAL_TOGGLE: 'Toggle terminal',
            ACTION_UPGRADE_MENU: 'Select upgrade',
            ACTION_USE_UPGRADE: 'Activate upgrade',
            ACTION_SHOW_TRAJECTORY: 'Show trajectory',
            ACTION_EMOTE: 'Emote',
        }
        actionNames.update((upgradeClass.action, upgradeClass.name)
                           for upgradeClass in allUpgrades)

        # Organise the categories by column
        self.layout = [
            [movement, menus],
            [actions, display],
            [upgrades, misc],
        ]

        self.errorInfo = TextElement(self.app, '', self.font,
                                     ScaledLocation(512, 580, 'center'))
        self.text = [self.errorInfo]
        self.inputLookup = {}
        xPos = 210

        # Lay everything out automatically.
        keymapFont = self.app.screenManager.fonts.keymapFont
        keymapInputFont = self.app.screenManager.fonts.keymapInputFont
        for column in self.layout:  # Each column
            yPos = 200
            for category in column:  # Each category
                for action in category:  # Each action
                    # Draw action name (eg. Respawn)
                    self.text.append(
                        TextElement(self.app, actionNames[action], keymapFont,
                                    ScaledLocation(xPos, yPos + 6, 'topright'),
                                    self.app.theme.colours.headingColour))

                    # Create input box
                    box = prompt.KeycodeBox(self.app,
                                            ScaledArea(xPos + 10, yPos, 100,
                                                       30),
                                            font=keymapInputFont,
                                            acceptMouse=True)
                    box.onClick.addListener(self.setFocus)
                    box.onChange.addListener(self.inputChanged)
                    box.__action = action
                    self.inputLookup[action] = box

                    yPos += 35  # Between items
                yPos += 35  # Between categories
            xPos += 310  # Between columns

        self.elements = self.text + list(self.inputLookup.values()) + [
            button(app,
                   'restore default controls',
                   self.restoreDefaults, (0, -125),
                   'midbottom',
                   secondColour=app.theme.colours.white),
            button(app,
                   'save',
                   self.saveSettings, (-100, -75),
                   'midbottom',
                   secondColour=app.theme.colours.white),
            button(app,
                   'cancel',
                   self.cancel, (100, -75),
                   'midbottom',
                   secondColour=app.theme.colours.white),
        ]

        self.populateInputs()

    def inputChanged(self, box):
        # Remove the old key.
        try:
            oldKey = self.keyMapping.getkey(box.__action)
        except KeyError:
            pass
        else:
            del self.keyMapping[oldKey]

        # Set the new key.
        self.keyMapping[box.value] = box.__action

        # Refresh the display.
        self.refreshInputs()

    def populateInputs(self):
        # Set up the keyboard mapping.
        self.keyMapping = keyboard.KeyboardMapping(keymap.default_game_keys)

        try:
            # Try to load keyboard mappings from the user's personal settings.
            with open(getPath(user, 'keymap'), 'r') as f:
                config = f.read()
            self.keyMapping.load(config)
        except IOError:
            pass

        # Refresh the display.
        self.refreshInputs()

    def refreshInputs(self):
        for column in self.layout:
            for category in column:
                for action in category:
                    # Get the current key and put it in the box.
                    try:
                        key = self.keyMapping.getkey(action)
                    except KeyError:
                        key = None
                    self.inputLookup[action].value = key

                    # Make the box white
                    self.inputLookup[action].backColour = (255, 255, 255)

    def restoreDefaults(self):
        self.keyMapping = keyboard.KeyboardMapping(keymap.default_game_keys)
        self.refreshInputs()

        self.showMessage(
            "Default controls restored: press 'save' to "
            "confirm", (0, 128, 0))

    def clearBackgrounds(self):
        for action in self.inputLookup:
            self.inputLookup[action].backColour = (255, 255, 255)
        self.setFocus(None)

    def saveSettings(self):
        # Perform the save.
        open(getPath(user, 'keymap'), 'w').write(self.keyMapping.save())
        self.mainMenu()

    def showMessage(self, string, colour):
        self.errorInfo.setColour(colour)
        self.errorInfo.setText(string)
        self.errorInfo.setFont(self.font)

    def cancel(self):
        self.populateInputs()
        self.mainMenu()

    def mainMenu(self):
        self.showMessage('', (0, 0, 0))
        self.clearBackgrounds()
        self.onClose.execute()