diff options
Diffstat (limited to 'src/python/app/app.py')
-rw-r--r-- | src/python/app/app.py | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/src/python/app/app.py b/src/python/app/app.py new file mode 100644 index 0000000..8c7ddda --- /dev/null +++ b/src/python/app/app.py @@ -0,0 +1,385 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# libavg - Media Playback Engine. +# Copyright (C) 2003-2014 Ulrich von Zadow +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Current versions can be found at www.libavg.de +# +# Original author of this file is OXullo Interecans <x at brainrapers dot org> + + +import os +import math +import time + +import libavg +from libavg import avg, Point2D, mtemu + +import settings +from settings import Option +import keyboardmanager +import debugpanel +import flashmessage + + +class MainDiv(libavg.avg.DivNode): + VERSION = 'undef' + + def __init__(self, **kargs): + assert not 'parent' in kargs + super(MainDiv, self).__init__(**kargs) + self.registerInstance(self, None) + + def onArgvParserCreated(self, parser): + pass + + def onArgvParsed(self, options, args, parser): + pass + + def onStartup(self): + pass + + def onInit(self): + pass + + def onExit(self): + pass + + def onFrame(self): + pass + + +class App(object): + def __init__(self): + self._setupInstance() + + self._mainDiv = None + self._appParent = None + self._debugPanel = None + self._overlayPanel = None + self._resolution = None + self._windowSize = None + self._mtEmu = None + + self.__lastFrameTimestamp = 0 + + self._setupSettings() + + def run(self, mainDiv, **kargs): + assert isinstance(mainDiv, MainDiv) + self._mainDiv = mainDiv + + self.mainDiv.settings = self._settings + self._applySettingsExtenders(kargs) + self._setupLogging() + + mainDiv.onStartup() + + self._setupResolution() + self._setupRootNode() + self._setupMouse() + pos, size, angle = self._getAppParentGeometry() + self._setupAppParent(pos, size, angle) + self._setupMainDiv() + self._setupTopPanel() + + self._setupDebugPanel() + self._setupKeyboardManager() + self._setupDebuggingWidgets() + self._applyResolution() + self._setupOnInit() + + self.onBeforeLaunch() + + self.__lastFrameTimestamp = time.time() + + try: + self._runLoop() + except Exception, e: + self._teardownKeyboardManager() + raise + + mainDiv.onExit() + + self._teardownKeyboardManager() + + return 0 + + @property + def mainDiv(self): + return self._mainDiv + + @property + def debugPanel(self): + return self._debugPanel + + @property + def overlayPanel(self): + return self._overlayPanel + + @property + def settings(self): + return self._settings + + def onBeforeLaunch(self): + pass + + def takeScreenshot(self, targetFolder='.'): + screenBmp = libavg.player.screenshot() + + filenameTemplate = os.path.join(targetFolder, '%s-%03d.png') + + i = 1 + while i < 1000: + filename = filenameTemplate % (self.__class__.__name__, i) + if os.path.exists(filename): + i += 1 + else: + break + + if i == 1000: + flashmessage.FlashMessage('Maximum number of screenshots reached', + parent=self._appParent, isError=True) + else: + screenBmp.save(filename) + flashmessage.FlashMessage('Screenshot saved as %s' % filename, + parent=self._appParent) + + def dumpTextObjectCount(self): + objects = libavg.player.getTestHelper().getObjectCount() + savedSeverity = libavg.logger.getCategories()[libavg.logger.Category.APP] + libavg.logger.configureCategory(libavg.logger.Category.APP, + libavg.logger.Severity.INFO) + libavg.logger.info('Dumping objects count') + for key, value in objects.iteritems(): + libavg.logger.info(' %-25s: %s' % (key, value)) + + libavg.logger.configureCategory(libavg.logger.Category.APP, savedSeverity) + + def _setupInstance(self): + import libavg.app + + if libavg.app.instance is not None: + raise RuntimeError('%s has been already instantiated' % + self.__class__.__name__) + + libavg.app.instance = self + + def _setupSettings(self): + self._settings = settings.Settings() + self._settings.addOption(Option('app_resolution', '640x480')) + self._settings.addOption(Option('app_window_size', '')) + self._settings.addOption(Option('app_fullscreen', 'false')) + self._settings.addOption(Option('app_show_cursor', 'true')) + self._settings.addOption(Option('app_rotation', 'normal')) + self._settings.addOption(Option('app_panel_fontsize', '10')) + self._settings.addOption(Option('app_mouse_enabled', 'true')) + self._settings.addOption(Option('multitouch_enabled', 'false')) + self._settings.addOption(Option('multitouch_driver', '')) + self._settings.addOption(Option('multitouch_tuio_port', '')) + self._settings.addOption(Option('multitouch_mtdev_device', '')) + self._settings.addOption(Option('log_avg_categories', '')) + + def _applySettingsExtenders(self, kargs): + self.settings.applyExtender(settings.KargsExtender(kargs)) + argvExtender = settings.ArgvExtender(self.mainDiv.VERSION) + self.mainDiv.onArgvParserCreated(argvExtender.parser) + self.settings.applyExtender(argvExtender) + self.mainDiv.onArgvParsed(argvExtender.parsedArgs[0], argvExtender.parsedArgs[1], + argvExtender.parser) + + def _setupLogging(self): + catMap = self.settings.get('log_avg_categories').strip() + if catMap: + for catPair in catMap.split(' '): + cat, strLevel = catPair.split(':') + level = getattr(avg.logger.Severity, strLevel) + + libavg.avg.logger.configureCategory(cat, level) + + def _setupRootNode(self): + libavg.player.loadString('''<?xml version="1.0"?> + <!DOCTYPE avg SYSTEM "../../libavg/doc/avg.dtd"> + <avg width="%s" height="%s"> + </avg>''' % tuple(self._resolution)) + + def _setupMouse(self): + libavg.player.enableMouse(self.settings.getBoolean('app_mouse_enabled')) + + def _setupMultitouch(self): + if self.settings.getBoolean('multitouch_enabled'): + driver = self.settings.get('multitouch_driver').upper() + if driver: + os.putenv('AVG_MULTITOUCH_DRIVER', driver) + + tuio_port = self.settings.get('multitouch_tuio_port').upper() + if tuio_port: + os.putenv('AVG_TUIO_PORT', tuio_port) + + mtdev_device = self.settings.get('multitouch_mtdev_device').upper() + if mtdev_device: + os.putenv('AVG_LINUX_MULTITOUCH_DEVICE', mtdev_device) + + libavg.player.enableMultitouch() + + def _getAppParentGeometry(self): + rotation = self.settings.get('app_rotation').lower() + size = self._resolution + pos = (0, 0) + angle = 0 + + if rotation == 'left': + angle = -math.pi / 2 + size = (self._resolution.y, self._resolution.x) + pos = ((self._resolution.x - self._resolution.y) / 2, + (self._resolution.y - self._resolution.x) / 2) + elif rotation == 'right': + angle = math.pi / 2 + size = (self._resolution.y, self._resolution.x) + pos = ((self._resolution.x - self._resolution.y) / 2, + (self._resolution.y - self._resolution.x) / 2) + elif rotation == 'inverted': + angle = math.pi + elif rotation != 'normal': + raise TypeError('Invalid rotation %s' % rotation) + + return (pos, size, angle) + + def _setupAppParent(self, pos, size, angle): + self._appParent = libavg.avg.DivNode(parent=libavg.player.getRootNode(), + pos=pos, size=size, angle=angle) + + def _setupMainDiv(self): + self._appParent.appendChild(self.mainDiv) + self.mainDiv.size = self._appParent.size + + def _setupTopPanel(self): + self._overlayPanel = libavg.avg.DivNode(parent=self._appParent, id='overlayPanel') + + def _setupDebugPanel(self): + self._debugPanel = debugpanel.DebugPanel(parent=self._appParent, + size=self._appParent.size, id='debugPanel', + fontsize=self.settings.getFloat('app_panel_fontsize')) + + def _setupDebuggingWidgets(self): + pass + + def _setupResolution(self): + rotation = self.settings.get('app_rotation').lower() + resolutionStr = self.settings.get('app_resolution').lower() + if resolutionStr != '': + resolution = self.settings.getPoint2D('app_resolution') + else: + resolution = libavg.player.getScreenResolution() + + windowSizeStr = self.settings.get('app_window_size') + if windowSizeStr != '': + windowSize = self.settings.getPoint2D('app_window_size') + else: + windowSize = resolution + + if rotation in ('left', 'right'): + resolution = Point2D(resolution.y, resolution.x) + windowSize = Point2D(windowSize.y, windowSize.x) + + self._resolution = resolution + self._windowSize = windowSize + + def _applyResolution(self): + fullscreen = self.settings.getBoolean('app_fullscreen') + + if fullscreen: + resolution = self._resolution + else: + resolution = self._windowSize + + libavg.player.setResolution( + fullscreen, + int(resolution.x), int(resolution.y), + 0 # color depth + ) + + libavg.player.showCursor(self.settings.getBoolean('app_show_cursor')) + + def _setupKeyboardManager(self): + keyboardmanager.init() + keyboardmanager.bindKeyDown( + keystring='d', + handler=self._debugPanel.toggleVisibility, + help='Show/hide the debug panel', + modifiers=libavg.avg.KEYMOD_CTRL) + + keyboardmanager.bindKeyDown( + keystring='h', + handler=lambda: libavg.player.showCursor( + not libavg.player.isCursorShown()), + help='Show/hide cursor', + modifiers=libavg.avg.KEYMOD_CTRL) + + keyboardmanager.bindKeyDown( + keystring='p', + handler=self.takeScreenshot, + help='Take screenshot', + modifiers=libavg.avg.KEYMOD_CTRL) + + keyboardmanager.bindKeyDown( + keystring='b', + handler=self.dumpTextObjectCount, + help='Dump objects count to the console', + modifiers=libavg.avg.KEYMOD_CTRL) + + keyboardmanager.bindKeyDown( + keystring='e', + handler=self._toggleMtEmulation, + help='Toggle multitouch emulation', + modifiers=libavg.avg.KEYMOD_CTRL) + + self.debugPanel.setupKeys() + + def _toggleMtEmulation(self): + if self._mtEmu is None: + self._mtEmu = mtemu.MTemu() + keyboardmanager.bindKeyDown('shift', self._mtEmu.enableDualTouch, + 'Enable pinch gesture emulation') + keyboardmanager.bindKeyUp('shift', self._mtEmu.disableDualTouch, + 'Disable pinch gesture emulation') + + keyboardmanager.bindKeyDown('t', self._mtEmu.toggleSource, + 'Toggle source between TOUCH and TRACK', libavg.avg.KEYMOD_CTRL) + else: + self._mtEmu.deinit() + keyboardmanager.unbindKeyDown('t', libavg.avg.KEYMOD_CTRL) + keyboardmanager.unbindKeyDown('shift') + keyboardmanager.unbindKeyUp('shift') + + del self._mtEmu + self._mtEmu = None + + def _teardownKeyboardManager(self): + keyboardmanager.unbindAll() + + def _setupOnInit(self): + libavg.player.setTimeout(0, self._onInitInternal) + + def _runLoop(self): + libavg.player.play() + + def _onInitInternal(self): + self._setupMultitouch() + self.mainDiv.onInit() + libavg.player.subscribe(libavg.player.ON_FRAME, self.mainDiv.onFrame) |