def __init__(self, app):
        size = Canvas(512, 384)
        DialogBox.__init__(self, app, size, 'Select arena')
        self._deferred = None
        self._games = None

        font = app.screenManager.fonts.defaultTextBoxFont
        btnColour = app.theme.colours.dialogButtonColour
        highlightColour = app.theme.colours.black
        labelColour = app.theme.colours.dialogBoxTextColour
        btnFont = app.screenManager.fonts.bigMenuFont
        listboxFont = app.screenManager.fonts.serverListFont
        listboxColour = app.theme.colours.mainMenuColour
        listboxHighlight = app.theme.colours.mainMenuHighlight

        self.gameList = ListBox(
            self.app,
            Region(topleft=self.Relative(0.05, 0.15),
                   size=self.Relative(0.9, 0.65)),
            [],
            listboxFont,
            listboxColour,
            listboxHighlight,
        )

        self.elements = [
            TextElement(app, 'Please select:', font,
                        Location(self.Relative(0.05, 0.05), 'topleft'),
                        labelColour),
            self.gameList,
            TextButton(app,
                       Location(self.Relative(0.3, 0.9), 'center'),
                       'Ok',
                       btnFont,
                       btnColour,
                       highlightColour,
                       onClick=self.okClicked),
            TextButton(app,
                       Location(self.Relative(0.7, 0.9), 'center'),
                       'Cancel',
                       btnFont,
                       btnColour,
                       highlightColour,
                       onClick=self.cancelClicked),
        ]
    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()
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 GameSelectionBox(DialogBox):
    def __init__(self, app):
        size = Canvas(512, 384)
        DialogBox.__init__(self, app, size, 'Select arena')
        self._deferred = None
        self._games = None

        font = app.screenManager.fonts.defaultTextBoxFont
        btnColour = app.theme.colours.dialogButtonColour
        highlightColour = app.theme.colours.black
        labelColour = app.theme.colours.dialogBoxTextColour
        btnFont = app.screenManager.fonts.bigMenuFont
        listboxFont = app.screenManager.fonts.serverListFont
        listboxColour = app.theme.colours.mainMenuColour
        listboxHighlight = app.theme.colours.mainMenuHighlight

        self.gameList = ListBox(
            self.app,
            Region(topleft=self.Relative(0.05, 0.15),
                   size=self.Relative(0.9, 0.65)),
            [],
            listboxFont,
            listboxColour,
            listboxHighlight,
        )

        self.elements = [
            TextElement(app, 'Please select:', font,
                        Location(self.Relative(0.05, 0.05), 'topleft'),
                        labelColour),
            self.gameList,
            TextButton(app,
                       Location(self.Relative(0.3, 0.9), 'center'),
                       'Ok',
                       btnFont,
                       btnColour,
                       highlightColour,
                       onClick=self.okClicked),
            TextButton(app,
                       Location(self.Relative(0.7, 0.9), 'center'),
                       'Cancel',
                       btnFont,
                       btnColour,
                       highlightColour,
                       onClick=self.cancelClicked),
        ]

    def selectGame(self, host, games):
        if self.showing:
            raise RuntimeError('GameSelectionBox already showing')

        self.setCaption(host)
        self._games = list(games)
        self.gameList.setItems([g.name for g in games])
        self.gameList.setIndex(-1)

        self.show()
        self._deferred = defer.Deferred()
        return self._deferred

    def cancelClicked(self, element):
        self._sendResult(None)

    def okClicked(self, element):
        index = self.gameList.getIndex()
        if index >= 0:
            self._sendResult(self._games[index])

    def _sendResult(self, result):
        self.close()
        d, self._deferred = self._deferred, None
        d.callback(result)
Beispiel #5
0
    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()
Beispiel #6
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())