User:Crond/sandbox/openglEventExample2
Written for CEGUI 0.7
Works with versions 0.7.x (obsolete)
Requires at least version
0.7.5
Introduction
This presents a slightly refined example of using subscriptions to respond to events. The example will generate some text on the console when an Editbox receives input, and when Enter/Return is pressed while the Editbox has focus.
Requirements
- Python 2.6
- PyCEGUI
- PyOpenGL
Notes
The source code uses a modified version of the OpenGL example posted here.
Source
#!/usr/bin/env python # # # example.py # Import: std import sys # Import: PyOpenGL from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * # Import: PyCEGUI import PyCEGUI from PyCEGUIOpenGLRenderer import OpenGLRenderer as Renderer # Constants PATH_RESOURCES = './' # Keymap: ASCII KEYMAP_ASCII = {8 : PyCEGUI.Key.Scan.Backspace, 13 : PyCEGUI.Key.Scan.Return, 27 : PyCEGUI.Key.Scan.Escape, 127 : PyCEGUI.Key.Scan.Delete} # Keymap: GLUT KEYMAP_GLUT = {GLUT_KEY_LEFT : PyCEGUI.Key.Scan.ArrowLeft, GLUT_KEY_RIGHT : PyCEGUI.Key.Scan.ArrowRight, GLUT_KEY_HOME : PyCEGUI.Key.Scan.Home, GLUT_KEY_END : PyCEGUI.Key.Scan.End} # Application class Application(object): # Constructor def __init__(self): super(Application, self).__init__() self.lastFrameTime = 0 self.updateFPS = 0 return # Initialize: OpenGL # - A full list of values for `glutInitDisplayMode` can be found in the GLUT # documentation. def initializeOpenGL(self): glutInit() glutDestroyWindow(glutCreateWindow('')) glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) glutInitWindowSize(1024, 768) glutInitWindowPosition(-1, -1) # Let the windowing system figure it out glutCreateWindow("Crazy Eddie's GUI Mk-2 - glut Base Application") glutSetCursor(GLUT_CURSOR_NONE) return # Initialize: Handlers # - Setup the methods which will be called when events happen. def initializeHandlers(self): glutDisplayFunc(self.handlerDisplay) glutReshapeFunc(self.handlerResize) glutKeyboardFunc(self.handlerKeyboard) glutSpecialFunc(self.handlerKeyboardSpecial) glutMouseFunc(self.handlerMouse) glutMotionFunc(self.handlerMouseMotion) glutPassiveMotionFunc(self.handlerMouseMotion) return # Initialize: PyCEGUI # - Store some components; saves a lot of typing. def initializePyCEGUI(self): Renderer.bootstrapSystem() self.sys = PyCEGUI.System.getSingleton() self.rp = self.sys.getResourceProvider() self.scheme = PyCEGUI.SchemeManager.getSingleton() self.wm = PyCEGUI.WindowManager.getSingleton() return # Initialize: Defaults # - Resource locations. def initializeDefaults(self): self.rp.setResourceGroupDirectory('schemes', './datafiles/schemes') self.rp.setResourceGroupDirectory('imagesets', './datafiles/imagesets') self.rp.setResourceGroupDirectory('fonts', './datafiles/fonts') self.rp.setResourceGroupDirectory('layouts', './datafiles/layouts') self.rp.setResourceGroupDirectory('looknfeels', './datafiles/looknfeel') self.rp.setResourceGroupDirectory('schemas', './datafiles/xml_schemas') PyCEGUI.Imageset.setDefaultResourceGroup('imagesets') PyCEGUI.Font.setDefaultResourceGroup('fonts') PyCEGUI.Scheme.setDefaultResourceGroup('schemes') PyCEGUI.WidgetLookManager.setDefaultResourceGroup('looknfeels') PyCEGUI.WindowManager.setDefaultResourceGroup('layouts') parser = self.sys.getXMLParser() if parser.isPropertyPresent('SchemaDefaultResourceGroup'): parser.setProperty('SchemaDefaultResourceGroup', 'schemas') return # Initialize: GUI # - This is where we are actually setting up the windows we will see. def initializeGUI(self): self.scheme.create('VanillaSkin.scheme') self.scheme.create('TaharezLook.scheme') # GUISheet self.rootWindow = self.wm.loadWindowLayout('VanillaWindows.layout') self.sys.setGUISheet(self.rootWindow) # Cursor self.sys.setDefaultMouseCursor('Vanilla-Images', 'MouseArrow') # An extra window w = self.wm.createWindow('TaharezLook/FrameWindow', 'Demo window') self.rootWindow.addChildWindow(w) return # Initialize: Subscriptions def initializeSubscriptions(self): # In order to be able to access the buttons, we need to get a copy of their parent. self.windowNewNode = self.rootWindow.getChild('Demo/NewNode') # Now, we get the buttons. self.buttonOkay = self.windowNewNode.getChild('Demo/NewNode/Okay') self.buttonCancel = self.windowNewNode.getChild('Demo/NewNode/Cancel') self.editboxText = self.windowNewNode.getChild('Demo/NewNode/Editbox') # And subscribe to the events, telling PyCEGUI what method it should call when the event happens. self.buttonOkay.subscribeEvent(PyCEGUI.PushButton.EventClicked, self, 'buttonOkayClicked') self.buttonCancel.subscribeEvent(PyCEGUI.PushButton.EventClicked, self, 'buttonCancelClicked') self.editboxText.subscribeEvent(PyCEGUI.Editbox.EventTextChanged, self, 'handlerTextChanged') self.editboxText.subscribeEvent(PyCEGUI.Editbox.EventTextAccepted, self, 'handlerTextAccepted') return # Initialize def Initialize(self): self.initializeOpenGL() self.initializeHandlers() self.initializePyCEGUI() self.initializeDefaults() self.initializeGUI() self.initializeSubscriptions() return # Handler: Display def handlerDisplay(self): # Injecting the time allows CEGUI to know how much time has passed, and # use that to coordinate certain activities - fading, animation, tooltips, # etc. now = glutGet(GLUT_ELAPSED_TIME) elapsed = (now - self.lastFrameTime) / 1000.0 self.lastFrameTime = now self.updateFPS = self.updateFPS - elapsed self.sys.injectTimePulse(elapsed) # Actual rendering # - `renderGUI` updates CEGUI's picture of the GUI. # - `glutPostRedisplay` is what actually marks the window as needing to # be redrawn by OpenGL. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) self.sys.renderGUI() glutPostRedisplay() glutSwapBuffers() return # Handler: Resize # - `glViewport` modifies the OpenGL viewport to whatever the window size is. def handlerResize(self, width, height): glViewport(0, 0, width, height) self.sys.notifyDisplaySizeChanged(PyCEGUI.Size(width, height)) return # Handler: Assist keyboard def handlerAssistKeyboard(self, key): try: self.sys.injectKeyDown(KEYMAP_ASCII[key]) except KeyError: return False return True # Handler: Keyboard def handlerKeyboard(self, key, x, y): k = ord(key) if not self.handlerAssistKeyboard(k): self.sys.injectChar(ord(key)) return # Handler: Keyboard special def handlerKeyboardSpecial(self, key, x, y): try: self.sys.injectKeyDown(KEYMAP_GLUT[key]) except KeyError: # Ignore it. pass return # Handler: Mouse buttons def handlerMouse(self, button, state, x, y): if button == GLUT_LEFT_BUTTON: if state == GLUT_UP: self.sys.injectMouseButtonUp(PyCEGUI.LeftButton) else: self.sys.injectMouseButtonDown(PyCEGUI.LeftButton) elif button == GLUT_RIGHT_BUTTON: if state == GLUT_UP: self.sys.injectMouseButtonUp(PyCEGUI.RightButton) else: self.sys.injectMouseButtonDown(PyCEGUI.RightButton) return # Handler: Mouse motion def handlerMouseMotion(self, x, y): self.sys.injectMousePosition(x, y) return # Handler: buttonOkayClicked def buttonOkayClicked(self, args): print('Okay has been clicked.') return # Handler: buttonCancelClicked def buttonCancelClicked(self, args): print('Cancel has been clicked.') return # Handler: Text changed def handlerTextChanged(self, args): print('Text has changed.') return # Handler: Text accepted def handlerTextAccepted(self, args): print('Text [{0}]has been accepted.'.format(self.editboxText.getText())) return # Run def Run(self): self.lastFrameTime = glutGet(GLUT_ELAPSED_TIME) glutMainLoop() return # Main def main(): app = Application() app.Initialize() app.Run() return 0 # Guard if __name__ == '__main__': sys.exit(main())
Demonstration
Enter some text into the Editbox, and/or press Return while the Editbox has focus.
Examination
In the context of the previous examples, this is all pretty straightforward; this simply demonstrates some additional events which are relevant to an Editbox.
As an exercise for the reader, consider the implications of removing the mapping of the return key from `KEYMAP_ASCII`, and why the effects are what they are.