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'))
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)
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))
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()
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()