# HG changeset patch # User Radek Brich # Date 1409764483 -7200 # Node ID b055add74b18a941fb88970eff161787ed0caee6 # Parent cf3d49cdd6e26e9520645c5f6a997eab8db478ee Refactor events. diff -r cf3d49cdd6e2 -r b055add74b18 demos/03_application.py --- 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) diff -r cf3d49cdd6e2 -r b055add74b18 tests/test_event_class.py --- /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()) diff -r cf3d49cdd6e2 -r b055add74b18 tuikit/core/application.py --- 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 ===') diff -r cf3d49cdd6e2 -r b055add74b18 tuikit/core/container.py --- 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 ## diff -r cf3d49cdd6e2 -r b055add74b18 tuikit/core/events.py --- /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) diff -r cf3d49cdd6e2 -r b055add74b18 tuikit/core/widget.py --- 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 ## diff -r cf3d49cdd6e2 -r b055add74b18 tuikit/core/window.py --- 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 diff -r cf3d49cdd6e2 -r b055add74b18 tuikit/driver/cursesw.py --- 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: diff -r cf3d49cdd6e2 -r b055add74b18 tuikit/widgets/textbox.py --- 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 diff -r cf3d49cdd6e2 -r b055add74b18 tuikit/widgets/textfield.py --- 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):