tuikit/application.py
author Radek Brich <radek.brich@devl.cz>
Tue, 08 Jan 2013 23:59:55 +0100
changeset 59 729fcdfe6b57
parent 57 911927edbdde
child 62 2f61931520c9
permissions -rw-r--r--
Cleanup timeouts.

# -*- coding: utf-8 -*-

import logging
import time

from tuikit.container import Container


class Timer:
    def __init__(self):
        self.timeouts = []
        self.timelast = None

    def add_timeout(self, delay, callback):
        """Register callback to be called after delay seconds.

        delay -- in seconds, float
        callback -- function to be called with no parameters

        """
        if not len(self.timeouts):
            self.timelast = time.time()
        self.timeouts += [[delay, callback]]

    def remove_timeout(self, callback):
        """Unregister callback previously registered with add_timeout."""
        for timeout in self.timeouts[:]:
            if timeout[1] == callback:
                self.timeouts.remove(timeout)

    def has_timeout(self):
        return len(self.timeouts) > 0

    def nearest_timeout(self):
        if not self.has_timeout():
            return None
        return min(self.timeouts)[0]

    def process_timeouts(self):
        if not self.has_timeout():
            return
        now = time.time()
        lasted = now - self.timelast
        self.timelast = now
        for timeout in self.timeouts[:]:
            adjusted_delay = timeout[0] - lasted
            if adjusted_delay <= 0.0:
                timeout[1]()
                self.timeouts.remove(timeout)
            else:
                timeout[0] = adjusted_delay


class TopWindow(Container):

    '''Top window of an application. Covers entire screen.'''

    def __init__(self):
        '''Create top window.'''
        Container.__init__(self)
        self.top = self
        self.timer = Timer()

    def draw(self, driver, x=0, y=0):
        """Draw the top window and its children.

        This is entry point for full screen redraw.

        """
        driver.erase()
        Container.draw(self, driver, x, y)


class Application:

    '''Application class. Defines main loop.'''

    def __init__(self, driver = 'sdl'):
        '''Create application.'''

        self.top = TopWindow()
        '''Top window.'''

        self.quit = False

        self.driver = self.get_driver_instance(driver)
        '''Driver class instance (render + input), e.g. DriverCurses.'''

        self.log = logging.getLogger('tuikit')
        self.log.setLevel(logging.DEBUG)
        handler = logging.FileHandler('./tuikit.log')
        formatter = logging.Formatter('%(asctime)s %(levelname)-5s %(message)s', '%y-%m-%d %H:%M:%S')
        handler.setFormatter(formatter)
        self.log.addHandler(handler)
        self.log.info('=== start ===')

    def start(self):
        '''Start application. Runs main loop.'''
        self.driver.start(self.mainloop)

    def terminate(self):
        '''Terminate application.'''
        self.quit = True

    def mainloop(self):
        '''The main loop.'''
        self.applytheme()
        self.top.size = self.driver.size  # link top widget size to screen size
        self.top.emit('resize')
        timer = self.top.timer

        while True:
            self.top.draw(self.driver)
            self.driver.commit()

            timeout = timer.nearest_timeout()
            events = self.driver.getevents(timeout)
            timer.process_timeouts()

            for event in events:
                if event[0] == 'quit':
                    self.quit = True
                else:
                    self.top.emit(event[0], *event[1:])

            if self.quit:
                break


    def applytheme(self):
        #TODO: allow custom colors:
        #    e.g. "blue (#2020FF) on black (#101010), underline"
        #    color in brackets is used when driver supports custom colors
        driver = self.driver
        driver.setcolor('normal',                  'white on black')
        driver.setcolor('strong',                  'white on black, bold')
        driver.setcolor('active',                  'black on cyan')
        driver.setcolor('window:normal',           'white on blue')
        driver.setcolor('window:controls',         'white on blue, bold')
        driver.setcolor('window:controls-active',  'cyan on blue, bold')
        driver.setcolor('button',                  'black on white')
        driver.setcolor('button-active',           'black on cyan')
        driver.setcolor('menu',                    'black on cyan')
        driver.setcolor('menu-active',             'white on cyan, bold')
        driver.setcolor('combo:normal',            'black on green')


    def get_driver_instance(self, name):
        module = __import__('tuikit.driver_' + name, fromlist=['driverclass'])
        return module.driverclass()