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