Refactor events.
--- a/demos/03_application.py Wed Sep 03 19:13:37 2014 +0200
+++ b/demos/03_application.py Wed Sep 03 19:14:43 2014 +0200
@@ -25,8 +25,8 @@
app.root_window.add(field)
app.root_window.focus_widget = field
-def on_keypress(keyname, char, mod):
- if keyname == 'escape':
+def on_keypress(ev):
+ if ev.keyname == 'escape':
app.stop()
app.window_manager.sig_keypress.connect(on_keypress)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test_event_class.py Wed Sep 03 19:14:43 2014 +0200
@@ -0,0 +1,13 @@
+#!/usr/bin/env python3
+
+import sys
+sys.path.append('..')
+
+from tuikit.core.events import KeypressEvent
+
+x = KeypressEvent('tab', '\t', set(['shift', 'ctrl']))
+print(repr(x))
+print(x.mod_key())
+
+x = KeypressEvent(None, 'c', set(['shift', 'ctrl']))
+print(x.mod_key())
--- a/tuikit/core/application.py Wed Sep 03 19:13:37 2014 +0200
+++ b/tuikit/core/application.py Wed Sep 03 19:14:43 2014 +0200
@@ -2,6 +2,7 @@
from tuikit.core.theme import default_theme
from tuikit.core.timer import Timer
from tuikit.core.buffer import ProxyBuffer
+from tuikit.core.events import ResizeEvent
import logging
@@ -56,7 +57,7 @@
def main_loop(self):
"""The main loop."""
self._started = True
- self.window_manager.handle_event('resize', *self.driver.size)
+ self.window_manager.handle_event(ResizeEvent(*self.driver.size))
screen = ProxyBuffer(self.driver)
while not self._quit:
@@ -69,7 +70,7 @@
self.timer.process_timeouts()
for event in events:
- self.window_manager.handle_event(event[0], *event[1:])
+ self.window_manager.handle_event(event)
self._started = False
self.log.info('=== End ===')
--- a/tuikit/core/container.py Wed Sep 03 19:13:37 2014 +0200
+++ b/tuikit/core/container.py Wed Sep 03 19:14:43 2014 +0200
@@ -61,17 +61,17 @@
## input events ##
- def keypress(self, keyname, char, mod):
+ def keypress_event(self, ev):
# First, handle the keypress event to focused child widget
if self.focus_widget is not None:
- if self.focus_widget.keypress(keyname, char, mod):
+ if self.focus_widget.keypress_event(ev):
return True
# Next, handle default key behaviour by Container
- if keyname == 'tab':
- return self.focus_next(-1 if 'shift' in mod else 1)
+ if ev.keyname == 'tab':
+ return self.focus_next(-1 if 'shift' in ev.mods else 1)
# Finally, handle default keys by Widget
# and send keypress signal
- if Widget.keypress(self, keyname, char, mod):
+ if Widget.keypress_event(self, ev):
return True
## focus ##
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tuikit/core/events.py Wed Sep 03 19:14:43 2014 +0200
@@ -0,0 +1,53 @@
+from collections import OrderedDict
+
+
+class Event:
+
+ """Base class for events."""
+
+ def __init__(self, event_name=None, arg_names=(), arg_values=()):
+ self.name = event_name
+ self.args = OrderedDict(zip(arg_names, arg_values))
+
+ def __getattr__(self, item):
+ if item in self.args:
+ return self.args[item]
+ else:
+ raise AttributeError(item)
+
+ def __getitem__(self, key):
+ return self.args[key]
+
+ def __repr__(self):
+ return '{}({})'.format(self.__class__.__name__,
+ ', '.join("%s=%r" % (k,v) for k,v
+ in self.args.items()))
+
+
+class ResizeEvent(Event):
+
+ def __init__(self, w, h):
+ Event.__init__(self, 'resize', ('w', 'h'), (w, h))
+
+
+class KeypressEvent(Event):
+
+ def __init__(self, keyname, char, mods):
+ Event.__init__(self, 'keypress',
+ ('keyname', 'char', 'mods'),
+ (keyname, char, mods))
+
+ def mod_key(self, sep='+'):
+ """Return combined key with modifiers.
+
+ E.g. "shift+tab"
+
+ Order of modifiers is fixed: ctrl, alt, meta, shift
+
+ """
+ res = []
+ for mod in ('ctrl', 'alt', 'meta', 'shift'):
+ if mod in self.mods:
+ res.append(mod)
+ res.append(self.keyname or self.char)
+ return sep.join(res)
--- a/tuikit/core/widget.py Wed Sep 03 19:13:37 2014 +0200
+++ b/tuikit/core/widget.py Wed Sep 03 19:14:43 2014 +0200
@@ -103,9 +103,12 @@
if self._cursor is not None:
return Point(self._cursor)
- ## input events ##
+ ## events ##
- def keypress(self, keyname, char, mod):
+ def resize_event(self, ev):
+ self.resize(ev.w, ev.h)
+
+ def keypress_event(self, ev):
"""Keypress event handler.
Override to accept keyboard input.
@@ -116,9 +119,9 @@
if it does not consume the event.
"""
- if self.sig_keypress(keyname, char, mod):
+ if self.sig_keypress(ev):
return True
- self.log.debug('Not consumed: keypress(%r, %r, %r)', keyname, char, mod)
+ self.log.debug('Not consumed: %s', ev)
## timeouts ##
--- a/tuikit/core/window.py Wed Sep 03 19:13:37 2014 +0200
+++ b/tuikit/core/window.py Wed Sep 03 19:14:43 2014 +0200
@@ -66,17 +66,17 @@
def resize(self, w, h):
self._widgets[0].resize(w, h)
- def keypress(self, keyname, char, mod):
- self.log.debug('keypress(%r, %r, %r)', keyname, char, mod)
- return Container.keypress(self, keyname, char, mod)
+ def keypress_event(self, ev):
+ self.log.debug('%s', ev)
+ return Container.keypress_event(self, ev)
- def handle_event(self, event_name, *args):
+ def handle_event(self, event):
"""Handle input event to managed windows."""
- handler = getattr(self, event_name, None)
+ handler = getattr(self, event.name + '_event', None)
if handler:
- handler(*args)
+ handler(event)
else:
- raise Exception('Unknown event: %r %r' % (event_name, args))
+ raise Exception('Unknown event: %r' % event)
def get_focused_widget(self):
"""Traverse the widget hierarchy to bottom
--- a/tuikit/driver/cursesw.py Wed Sep 03 19:13:37 2014 +0200
+++ b/tuikit/driver/cursesw.py Wed Sep 03 19:14:43 2014 +0200
@@ -3,6 +3,7 @@
import logging
from tuikit.driver.driver import Driver
+from tuikit.core.events import ResizeEvent, KeypressEvent
class CursesWDriver(Driver):
@@ -187,13 +188,13 @@
res += self._process_mouse()
elif c == curses.KEY_RESIZE:
self.size.h, self.size.w = self.stdscr.getmaxyx()
- res += [('resize', self.size.w, self.size.h)]
+ res.append(ResizeEvent(self.size.w, self.size.h))
elif isinstance(c, int):
- keyname, mod = self._split_keyname_mod(self.key_map[c])
- res += [('keypress', keyname, None, mod)]
+ keyname, mods = self._split_keyname_mods(self.key_map[c])
+ res.append(KeypressEvent(keyname, None, mods))
else:
keyname = self.key_names.get(c)
- res += [('keypress', keyname, c, set())]
+ res.append(KeypressEvent(keyname, c, set()))
return res
@@ -240,7 +241,7 @@
return out
- def _split_keyname_mod(self, keyname):
+ def _split_keyname_mods(self, keyname):
"""Parse keynames in form "shift+tab", return (keyname, mod)."""
mod_set = set()
if '+' in keyname:
--- a/tuikit/widgets/textbox.py Wed Sep 03 19:13:37 2014 +0200
+++ b/tuikit/widgets/textbox.py Wed Sep 03 19:14:43 2014 +0200
@@ -60,28 +60,38 @@
buffer.puts(line, 0, j)
#self.cursor = (self._spot.x, self._spot.y)
- def keypress(self, keyname, char, mod=0):
- if keyname:
- if keyname == 'left': self.move_left()
- if keyname == 'right': self.move_right()
- if keyname == 'home': self.move_home()
- if keyname == 'end': self.move_end()
- if keyname == 'up': self.move_up()
- if keyname == 'down': self.move_down()
- if keyname == 'pageup': self.move_pageup()
- if keyname == 'pagedown': self.move_pagedown()
- if keyname == 'backspace': self.backspace()
- if keyname == 'delete': self.del_char()
- if keyname == 'enter': self.add_newline(move=True)
- if mod == MOD_CTRL:
- if keyname == 'home': self.move_top()
- if keyname == 'end': self.move_bottom()
+ def keypress_event(self, ev):
+ if ev.keyname and not ev.mods:
+ consumed = True
+ if ev.keyname == 'left': self.move_left()
+ elif ev.keyname == 'right': self.move_right()
+ elif ev.keyname == 'home': self.move_home()
+ elif ev.keyname == 'end': self.move_end()
+ elif ev.keyname == 'up': self.move_up()
+ elif ev.keyname == 'down': self.move_down()
+ elif ev.keyname == 'pageup': self.move_pageup()
+ elif ev.keyname == 'pagedown': self.move_pagedown()
+ elif ev.keyname == 'backspace': self.backspace()
+ elif ev.keyname == 'delete': self.del_char()
+ elif ev.keyname == 'enter': self.add_newline(move=True)
+ else:
+ consumed = False
+ if consumed:
+ return True
+ if ev.mods:
+ consumed = True
+ mk = ev.mod_key()
+ if mk == 'ctrl+home': self.move_top()
+ elif mk == 'ctrl+end': self.move_bottom()
+ else:
+ consumed = False
+ if consumed:
+ return True
- if char:
- self.add_char(char)
+ if ev.char and not ev.keyname:
+ self.add_char(ev.char)
self.move_right()
-
- #self.redraw()
+ return True
def on_mousedown(self, ev):
y = ev.wy
--- a/tuikit/widgets/textfield.py Wed Sep 03 19:13:37 2014 +0200
+++ b/tuikit/widgets/textfield.py Wed Sep 03 19:14:43 2014 +0200
@@ -45,30 +45,30 @@
self._cursor = (1 + self.curspos - self.ofs, 0)
- def keypress(self, keyname, char, mod=0):
+ def keypress_event(self, ev):
consumed = True
- if keyname == 'left':
+ if ev.keyname == 'left':
self.move_left()
- elif keyname == 'right':
+ elif ev.keyname == 'right':
self.move_right()
- elif keyname == 'backspace':
+ elif ev.keyname == 'backspace':
if self.curspos > 0:
self.move_left()
self.del_char()
- elif keyname == 'delete':
+ elif ev.keyname == 'delete':
self.del_char()
else:
consumed = False
- if not keyname and char:
- self.add_char(char)
+ if not ev.keyname and ev.char:
+ self.add_char(ev.char)
self.move_right()
consumed = True
if consumed:
#self.redraw()
return True
- Widget.keypress(self, keyname, char, mod)
+ Widget.keypress_event(self, ev)
def move_left(self):
if self.curspos - self.ofs > 1 or (self.ofs == 0 and self.curspos == 1):