# HG changeset patch # User Radek Brich # Date 1395258172 -3600 # Node ID 781774a8d5684ed9417bb69c10c62c484aba4a20 # Parent 94f5baef19ac7c04ce508b46c80cbea3263ff47c Add timer, adjust inheritance of Widget, Container, Window. diff -r 94f5baef19ac -r 781774a8d568 tuikit/core/application.py --- a/tuikit/core/application.py Wed Mar 19 00:32:38 2014 +0100 +++ b/tuikit/core/application.py Wed Mar 19 20:42:52 2014 +0100 @@ -1,5 +1,6 @@ from tuikit.core.window import WindowManager, Window from tuikit.core.theme import default_theme +from tuikit.core.timer import Timer import logging @@ -14,12 +15,10 @@ """ def __init__(self, driver='curses'): - # logger self.log = logging.getLogger('tuikit') - # Driver self.driver = None - # Window Manager and root Window - self.window_manager = WindowManager() + self.timer = Timer() + self.window_manager = WindowManager(timer=self.timer) self.root_window = Window() # flags self._started = False @@ -57,18 +56,18 @@ """The main loop.""" self._started = True self.window_manager.handle_event('resize', *self.driver.size) -# timer = self._timer while not self._quit: self.window_manager.draw(self.driver) self.driver.flush() - #timeout = timer.nearest_timeout() - events = self.driver.getevents()#timeout) - #timer.process_timeouts() + timeout = self.timer.nearest_timeout() + events = self.driver.getevents(timeout) + self.timer.process_timeouts() for event in events: self.window_manager.handle_event(event[0], *event[1:]) + self._started = False self.log.info('=== quit ===') diff -r 94f5baef19ac -r 781774a8d568 tuikit/core/buffer.py --- a/tuikit/core/buffer.py Wed Mar 19 00:32:38 2014 +0100 +++ b/tuikit/core/buffer.py Wed Mar 19 20:42:52 2014 +0100 @@ -107,7 +107,7 @@ @property def size(self): - return self._size + return self._size.readonly() def resize(self, w, h): """Resize buffer.""" diff -r 94f5baef19ac -r 781774a8d568 tuikit/core/container.py --- a/tuikit/core/container.py Wed Mar 19 00:32:38 2014 +0100 +++ b/tuikit/core/container.py Wed Mar 19 20:42:52 2014 +0100 @@ -1,30 +1,34 @@ -from tuikit.core.theme import default_theme +from tuikit.core.widget import Widget -class Container: +class Container(Widget): + + """Container widget. - """Container for widgets.""" + Can contain other widgets to create hierarchical structure. + + """ def __init__(self): + Widget.__init__(self) #: List of child widgets. self.children = [] - self.theme = default_theme - def add(self, widget, **kwargs): + def add(self, widget): """Add widget into container.""" self.children.append(widget) widget.parent = self - widget.window = self.window if hasattr(self, 'window') else self + widget.window = self.window widget.set_theme(self.theme) - def set_theme(self, theme): - self.theme = theme - for child in self.children: - child.set_theme(theme) - def draw(self, buffer, x=0, y=0): """Draw child widgets.""" for child in self.children: child.draw(buffer, x + child.x, y + child.y) + + def set_theme(self, theme): + Widget.set_theme(self, theme) + for child in self.children: + child.set_theme(theme) diff -r 94f5baef19ac -r 781774a8d568 tuikit/core/timer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tuikit/core/timer.py Wed Mar 19 20:42:52 2014 +0100 @@ -0,0 +1,81 @@ +import time + + +class TimerEvent: + + __slots__ = ('time', 'callback', 'args') + + def __init__(self, delay, callback, args): + self.time = time.time() + delay + self.callback = callback + self.args = args + + def execute(self): + self.callback(*self.args) + + def __lt__(self, other): + return self.time < other.time + + def __str__(self): + return '{:.2f}s {} {}'.format( + self.time - time.time(), self.callback, self.args) + + +class Timer: + + def __init__(self): + #: Each timeout + self.events = [] + + def add_timeout(self, delay, callback, *args): + """Register `callback` to be called after `delay` seconds.""" + self.events.append(TimerEvent(delay, callback, args)) + self.events.sort(reverse=True) + + def remove_timeout(self, callback, *args): + """Unregister callback previously registered with add_timeout. + + Removes all timeouts with the `callback` and `args`. + + """ + for event in self.events[:]: + if event.callback == callback and event.args == args: + self.events.remove(event) + + def nearest_timeout(self): + """Get interval in seconds when next timeout expires. + + Returns None when no timeout is registered. + + """ + if not len(self.events): + return None + timeout = self.events[-1].time - time.time() + return max(0, timeout) + + def process_timeouts(self): + """Execute all expired timeouts.""" + now = time.time() + while len(self.events) and self.events[-1].time <= now: + self.events[-1].execute() + self.events.pop() + + def __str__(self): + return '\n'.join(str(event) for event in self.events) + + +if __name__ == '__main__': + # Self Test + t = Timer() + t.process_timeouts() + t.add_timeout(1, print, 'timeout 1') + t.add_timeout(3, print, 'timeout 3') + t.add_timeout(2, print, 'timeout 2') + print(t) + print('Nearest: %.2f' % t.nearest_timeout()) + t.process_timeouts() + time.sleep(1) + t.process_timeouts() + print(t) + time.sleep(2) + t.process_timeouts() diff -r 94f5baef19ac -r 781774a8d568 tuikit/core/widget.py --- a/tuikit/core/widget.py Wed Mar 19 00:32:38 2014 +0100 +++ b/tuikit/core/widget.py Wed Mar 19 20:42:52 2014 +0100 @@ -22,11 +22,11 @@ #: Theme self.theme = default_theme - ### placing and size #: Position inside parent widget. Modified by layout manager. self.pos = Point() #: Actual size. Modified by layout manager. self.size = Size(10, 10) + #: Requested size. Layout manager will use this when placing the widget. self.sizereq = Size(1, 1) #: Minimal size of widget. Widget will never be sized smaller than this. @@ -35,7 +35,7 @@ #: None means no maximum size (infinite). self.sizemax = Size(None, None) - ## placing and size ## + ## position and size ## @property def x(self): @@ -53,10 +53,24 @@ def height(self): return self.size.h - ## drawing ## + ## appearance ## - def draw(self, buffer, x, y): + def draw(self, buffer, x=0, y=0): pass def set_theme(self, theme): self.theme = theme + + ## timeouts ## + + def add_timeout(self, delay, callback, *args): + """Register `callback` to be called after `delay` seconds.""" + self.parent.add_timeout(self, delay, callback, *args) + + def remove_timeout(self, callback, *args): + """Unregister callback previously registered with add_timeout. + + Removes all timeouts with the `callback` and `args`. + + """ + self.parent.remove_timeout(self, callback, *args) diff -r 94f5baef19ac -r 781774a8d568 tuikit/core/window.py --- a/tuikit/core/window.py Wed Mar 19 00:32:38 2014 +0100 +++ b/tuikit/core/window.py Wed Mar 19 20:42:52 2014 +0100 @@ -1,8 +1,6 @@ from tuikit.core.buffer import Buffer from tuikit.core.signal import Signal from tuikit.core.container import Container -from tuikit.core.coords import Point -from tuikit.core.theme import default_theme class Window(Container): @@ -17,40 +15,22 @@ """New buffer for the window will be created unless given existing `buffer` as parameter.""" Container.__init__(self) - self.pos = Point() self._buffer = None - self.sig_resized = Signal() self.buffer = buffer or Buffer() @property - def x(self): - return self.pos.x - - @property - def y(self): - return self.pos.y - - @property def buffer(self): return self._buffer @buffer.setter def buffer(self, buffer): - # disconnect signals from old buffer - if self._buffer: - self.sig_resized.disconnect(self._buffer.resize) # replace the buffer self._buffer = buffer - # resize buffer when window gets resized - self.sig_resized.connect(buffer.resize) - - @property - def size(self): - return self.buffer.size.readonly() + self.size = buffer.size def resize(self, w, h): + """Resize buffer when window gets resized.""" self.buffer.resize(w, h) - self.sig_resized(w, h) self.redraw() def redraw(self): @@ -63,29 +43,14 @@ buffer.draw(self.buffer, x, y) -class WindowManager: - - def __init__(self, theme=default_theme): - self.windows = [] - self.theme = theme +class WindowManager(Container): - def add(self, window): - self.windows.append(window) - window.set_theme(self.theme) - - def set_theme(self, theme): - self.theme = theme - for window in self.windows: - window.set_theme(theme) + def __init__(self, timer): + Container.__init__(self) + self.timer = timer def resize(self, w, h): - self.windows[0].resize(w, h) - - def draw(self, buffer, x=0, y=0): - for window in self.windows: - window.draw(buffer, - x + window.x, - y + window.y) + self.children[0].resize(w, h) # def keypress(self, keyname, char, mod=0):