Add timer, adjust inheritance of Widget, Container, Window.
--- 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 ===')
--- 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."""
--- 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)
--- /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()
--- 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)
--- 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):