CodeSnippets Ingame Console
From PyWiki
Contents |
Ingame Console
Console.py
import ogre.renderer.OGRE as ogre import ogre.io.OIS as OIS import array import code import sys ## PythonOgre Console # Usage: # console = console.Console(self.root) # console.addLocals({'root':self.root}) # console.show() # # Then inject the keys pressed in your keyboard handler # console.keyPressed(evt) # # PythonOgre Console is sort of singleton. All instances of Console objects # share the same state. So simply create a console object anywhere you wish # to use it and they will all point to whichever one was created first. # ## TODO # - Key repeating # - PGUP PGDOWN history viewing # - Linewrap if prompt too long # - Write history to file # - Read history from file # - Make font look better class Console(ogre.FrameListener): CONSOLE_LINE_LENGTH = 85 CONSOLE_LINE_COUNT = 15 __shared_state = {} def __init__(self, root = None): self.__dict__ = self.__shared_state ogre.FrameListener.__init__(self) if root: root.addFrameListener(self) if 'isSetup' not in self.__dict__: self.isSetup = True else: return self.currentInputHistory = 0 self.inputHistory = [] self.outputHistory = [] self.prompt = array.array('b') self.updateOverlay = True self.multiLineInput = False self.interpreter = code.InteractiveConsole({'console':self}) self.keyBinds = { OIS.KC_RETURN: self._runPromptText, OIS.KC_BACK: self._backspaceCharPrompt, OIS.KC_DELETE: self._deleteCharPrompt, OIS.KC_UP: self._prevPromptText, OIS.KC_DOWN: self._nextPromptText, OIS.KC_ESCAPE: self.hide, OIS.KC_LEFT: self._moveCursorLeft, OIS.KC_RIGHT: self._moveCursorRight, OIS.KC_HOME: self._moveCursorHome, OIS.KC_END: self._moveCursorEnd, OIS.KC_TAB: self._tab, } self.height = 0.0 self.hide() self.overlay = ogre.OverlayManager.getSingleton().getByName("Application/ConsoleOverlay") self.overlay.show() self.textbox = ogre.OverlayManager.getSingleton().getOverlayElement("Application/ConsoleText") self.textoverlay = ogre.OverlayManager.getSingleton().getOverlayElement("Application/ConsoleTextOverlay") self.textpanel = ogre.OverlayManager.getSingleton().getOverlayElement("Application/ConsolePanel") self.textpanel.getMaterial().setLightingEnabled(True) self.textpanel.getMaterial().setSceneBlending(ogre.SBT_TRANSPARENT_ALPHA) def addLocals(self, localsDict): for var in localsDict: self.interpreter.locals[var] = localsDict[var] def _tab(self): self.prompt.insert(self.cursorPosition, 32) # WhiteSpace self.cursorPosition += 1 def _moveCursorEnd(self): self.cursorPosition = len(self.prompt) def _moveCursorHome(self): self.cursorPosition = 0 def _moveCursorLeft(self): if self.cursorPosition > 0: self.cursorPosition -= 1 def _moveCursorRight(self): if self.cursorPosition < len(self.prompt): self.cursorPosition += 1 def _deleteCharPrompt(self): if len(self.prompt) > 0 and self.cursorPosition < len(self.prompt): self.prompt.pop(self.cursorPosition) def _backspaceCharPrompt(self): if len(self.prompt) > 0 and self.cursorPosition > 0: self.prompt.pop(self.cursorPosition-1) self.cursorPosition -= 1 def setPrompt(self, byteArray): self._prompt = byteArray self.cursorPosition = len(self._prompt) def getPrompt(self): return self._prompt prompt = property(getPrompt, setPrompt) def _enableSysRedirect(self): self._stderr, self._stdout = sys.stderr, sys.stdout sys.stderr, sys.stdout = self, self def _disableSysRedirect(self): sys.stderr, sys.stdout = self._stderr, self._stdout def _runPromptText(self): if len(self.prompt) > 0 or self.multiLineInput: self.outputHistory += [self.promptCursor + self.prompt.tostring()] self._enableSysRedirect() self.multiLineInput = self.interpreter.push(self.prompt.tostring()) self._disableSysRedirect() self.inputHistory += [self.prompt] self.prompt = self.prompt[0:0] self.currentInputHistory = len(self.inputHistory) def _prevPromptText(self): if self.currentInputHistory > 0: self.currentInputHistory -= 1 self.prompt = self.inputHistory[self.currentInputHistory][:] def _nextPromptText(self): if self.currentInputHistory+1 < len(self.inputHistory): self.currentInputHistory += 1 self.prompt = self.inputHistory[self.currentInputHistory][:] def _getVisible(self): return self._visible visible = property(_getVisible) def hide(self): self._visible = False def show(self): self._visible = True def keyPressed(self, evt): if not self.visible: if evt.key == OIS.KC_GRAVE: self.show() return try: self.keyBinds[evt.key]() except KeyError: if evt.text != 0: self.prompt.insert(self.cursorPosition, evt.text) self.cursorPosition += 1 self.currentInputHistory = len(self.inputHistory) self.updateOverlay = True def _updateConsoleText(self): lines = [""] * (Console.CONSOLE_LINE_COUNT - len(self.outputHistory)) lines += self.outputHistory[-1*Console.CONSOLE_LINE_COUNT:] text = "\n".join(lines) text += u"\n%s%s" % (self.promptCursor, self.prompt.tostring()) self.textbox.setCaption(text) text = "\n".join([""] * (Console.CONSOLE_LINE_COUNT)) text += u"\n%s%s_" % (self.promptCursor, " " * self.cursorPosition) self.textoverlay.setCaption(text) def _appear(self, amt): self.height += amt self.overlay.show() if self.height >= 1.0: self.height = 1.0 def _dissapear(self, amt): self.height -= amt if self.height < 0.0: self.height = 0.0 self.overlay.hide() def _updateConsolePosition(self, time): if self.visible and self.height < 1.0: self._appear(3.5*time) elif not self.visible and self.height > 0.0: self._dissapear(3.5*time) self.textpanel.setPosition(0,(self.height-1.0)*0.5) def frameStarted(self, evt): self._updateConsolePosition(evt.timeSinceLastFrame) if self.updateOverlay: self._updateConsoleText() self.updateOverlay = False return True def _getPromptCursor(self): return '... ' if self.multiLineInput else '>>> ' promptCursor = property(_getPromptCursor) def write(self, text): for line in text.split("\n"): while len(line) > 0: self.outputHistory += [line[:Console.CONSOLE_LINE_LENGTH]] line = line[Console.CONSOLE_LINE_LENGTH:] self.updateOverlay = True
console.material
material console/background { technique { pass { diffuse 1 0 1 0.5 ambient 0.4 0.4 0.4 } } }
console.fontdef
Console { type truetype source console.ttf size 32 resolution 55 }
console.overlay
Application/ConsoleOverlay { zorder 500 container BorderPanel(Application/ConsolePanel) { material console/background metrics_mode relative left 0 top 0 width 1 height 0.5 element TextArea(Application/ConsoleText) { metrics_mode relative left 0 top 0 width 1 height 1 font_name Console char_height 0.031 } element TextArea(Application/ConsoleTextOverlay) { metrics_mode relative left 0 top 0 width 1 height 1 font_name Console char_height 0.031 } } }
console.ttf
Any font can be used. Fixed width (monotype) fonts will display better. You can use this free FixedSys font.
