Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
--- a/demo_checkbox.py Wed Dec 26 01:00:31 2012 +0100
+++ b/demo_checkbox.py Sat Dec 29 12:16:06 2012 +0100
@@ -10,20 +10,20 @@
class MyApplication(Application):
def __init__(self):
Application.__init__(self)
- self.top.connect('keypress', self.on_keypress)
+ self.top.connect('keypress', self.on_top_keypress)
vert = VerticalLayout(homogeneous=False)
self.top.layout(vert)
-
+
combo = ComboBox(items=['abc', 'xyz'])
self.top.add(combo)
-
+
for i in range(10):
cbox = Checkbox('checkbox ' + str(i))
self.top.add(cbox)
-
- def on_keypress(self, keyname, char):
- if keyname == 'escape' or char == 'q':
+
+ def on_top_keypress(self, ev):
+ if ev.keyname == 'escape' or ev.char == 'q':
self.terminate()
--- a/demo_editor.py Wed Dec 26 01:00:31 2012 +0100
+++ b/demo_editor.py Sat Dec 29 12:16:06 2012 +0100
@@ -17,7 +17,7 @@
class MyApplication(Application):
def __init__(self):
Application.__init__(self)
- self.top.connect('keypress', self.on_keypress)
+ self.top.connect('keypress', self.on_top_keypress)
#edit = EditField(50, 'DlouhyTest12')
#self.top.add(edit)
@@ -48,13 +48,9 @@
self.button.label = 'YES'
- def on_keypress(self, keyname, char):
- if keyname == 'escape':
+ def on_top_keypress(self, ev):
+ if ev.keyname == 'escape':
self.terminate()
- if keyname == 'f1':
- self.textedit.settext('%s' % self.top.focuschild)
- self.textedit.redraw()
-
if __name__ == '__main__':
--- a/demo_input.py Wed Dec 26 01:00:31 2012 +0100
+++ b/demo_input.py Sat Dec 29 12:16:06 2012 +0100
@@ -10,7 +10,7 @@
class MyApplication(Application):
def __init__(self):
Application.__init__(self)
- self.top.connect('keypress', self.globalkeypress)
+ self.top.connect('keypress', self.on_top_keypress)
self.text = ''
textedit = TextEdit(100, 40, self.text)
@@ -19,10 +19,10 @@
self.textedit = textedit
- def globalkeypress(self, keyname, char):
- if char == 'q':
+ def on_top_keypress(self, ev):
+ if ev.char == 'q':
self.terminate()
- self.text += 'keyname: %s char: %s\n' % (keyname, char)
+ self.text += 'keyname: %(keyname)s char: %(char)s\n' % ev
self.textedit.settext(self.text)
self.textedit.scrolltoend()
--- a/demo_layout.py Wed Dec 26 01:00:31 2012 +0100
+++ b/demo_layout.py Sat Dec 29 12:16:06 2012 +0100
@@ -10,13 +10,13 @@
class MyApplication(Application):
def __init__(self):
Application.__init__(self)
- self.top.connect('keypress', self.globalkeypress)
+ self.top.connect('keypress', self.on_top_keypress)
#self.top.borders = (1,1,1,1)
vert = VerticalLayout(homogeneous=False)
self.top.layout(vert)
-
+
self.buildrow()
self.buildrow(expand=True)
self.buildrow(expand=True, fill=True)
@@ -24,7 +24,7 @@
self.buildrow(homogeneous=True, fill=True)
self.buildrow(homogeneous=True, fill=True, spacing=1)
self.buildrow(homogeneous=True, fill=True, spacing=2)
-
+
def buildrow(self, homogeneous=False, spacing=0, expand=False, fill=False):
horz = HorizontalLayout(homogeneous=homogeneous, spacing=spacing)
hbox1 = Container()
@@ -34,9 +34,9 @@
for i in range(5):
btn = Button('Btn' + str(i) * i * i)
hbox1.add(btn, expand=expand, fill=fill)
-
- def globalkeypress(self, keyname, char):
- if keyname == 'escape' or char == 'q':
+
+ def on_top_keypress(self, ev):
+ if ev.keyname == 'escape' or ev.char == 'q':
self.terminate()
--- a/demo_menu.py Wed Dec 26 01:00:31 2012 +0100
+++ b/demo_menu.py Sat Dec 29 12:16:06 2012 +0100
@@ -10,7 +10,7 @@
class MyApplication(Application):
def __init__(self):
Application.__init__(self)
- self.top.connect('keypress', self.globalkeypress)
+ self.top.connect('keypress', self.on_top_keypress)
menubar = MenuBar()
self.top.add(menubar)
@@ -64,8 +64,8 @@
#win.add(subwin)
- def globalkeypress(self, keyname, char):
- if keyname == 'escape':
+ def on_top_keypress(self, ev):
+ if ev.keyname == 'escape':
self.terminate()
--- a/demo_tableview.py Wed Dec 26 01:00:31 2012 +0100
+++ b/demo_tableview.py Sat Dec 29 12:16:06 2012 +0100
@@ -12,7 +12,7 @@
class MyApplication(Application):
def __init__(self):
Application.__init__(self)
- self.top.connect('keypress', self.globalkeypress)
+ self.top.connect('keypress', self.on_top_keypress)
data = []
for y in range(100):
@@ -21,19 +21,19 @@
row.append('r{}:c{}'.format(y, x))
data.append(row)
model = TableModel(data)
-
+
view = TableView(model)
view.addcolumn(header=True, expand=False, sizereq=5)
for x in range(10):
view.addcolumn(title='head'+str(x))
-
+
self.top.add(view, expand=True, fill=True)
vert = VerticalLayout()
self.top.layout(vert)
- def globalkeypress(self, keyname, char):
- if keyname == 'escape':
+ def on_top_keypress(self, ev):
+ if ev.keyname == 'escape':
self.terminate()
--- a/demo_treeview.py Wed Dec 26 01:00:31 2012 +0100
+++ b/demo_treeview.py Sat Dec 29 12:16:06 2012 +0100
@@ -10,7 +10,7 @@
class MyApplication(Application):
def __init__(self):
Application.__init__(self)
- self.top.connect('keypress', self.globalkeypress)
+ self.top.connect('keypress', self.on_top_keypress)
model = TreeModel()
model.add('/', ['a', 'b'])
@@ -32,8 +32,8 @@
vert = VerticalLayout()
self.top.layout(vert)
- def globalkeypress(self, eo, keyname, char):
- if keyname == 'escape':
+ def on_top_keypress(self, ev):
+ if ev.keyname == 'escape':
self.terminate()
--- a/tuikit/button.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/button.py Sat Dec 29 12:16:06 2012 +0100
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from tuikit.widget import Widget
+from tuikit.emitter import Event
class Button(Widget):
@@ -32,29 +33,29 @@
self.sizereq.w = w
self.sizereq.h = h
- self.add_events('click')
+ self.add_events('click', Event)
- def _handle_draw(self, screen, x, y):
- super()._handle_draw(screen, x, y)
+ def _handle_draw(self, ev):
+ super()._handle_draw(ev)
pad = self.width - len(self.label) - len(self.prefix) - len(self.suffix)
lpad, rpad = self._divide_padding(pad)
- screen.pushcolor(self.getcolor())
+ ev.driver.pushcolor(self.getcolor())
# prefix
- screen.puts(x, y, self.prefix)
+ ev.driver.puts(ev.x, ev.y, self.prefix)
pos = len(self.prefix)
# left pad
- screen.puts(x + pos, y, ' ' * lpad)
+ ev.driver.puts(ev.x + pos, ev.y, ' ' * lpad)
pos += lpad
# label
- screen.puts(x + pos, y, self.label)
+ ev.driver.puts(ev.x + pos, ev.y, self.label)
pos += len(self.label)
# right pad
- screen.puts(x + pos, y, ' ' * rpad)
+ ev.driver.puts(ev.x + pos, ev.y, ' ' * rpad)
pos += rpad
# suffix
- screen.puts(x + pos, y, self.suffix)
- screen.popcolor()
+ ev.driver.puts(ev.x + pos, ev.y, self.suffix)
+ ev.driver.popcolor()
def _handle_mousedown(self, ev):
super()._handle_mousedown(ev)
@@ -69,9 +70,9 @@
if self.enclose(ev.px, ev.py):
self.emit('click')
- def _handle_keypress(self, keyname, char):
- super()._handle_keypress(keyname, char)
- if keyname == 'enter':
+ def _handle_keypress(self, ev):
+ super()._handle_keypress(ev)
+ if ev.keyname == 'enter':
self.emit('click')
def getcolor(self):
--- a/tuikit/checkbox.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/checkbox.py Sat Dec 29 12:16:06 2012 +0100
@@ -18,8 +18,8 @@
self.bg = 'normal'
self.bghi = 'active'
- def _handle_click(self):
- super()._handle_click()
+ def _handle_click(self, ev):
+ super()._handle_click(ev)
if self.checked:
self.checked = False
self.prefix = '[ ] '
--- a/tuikit/combobox.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/combobox.py Sat Dec 29 12:16:06 2012 +0100
@@ -28,8 +28,11 @@
self._menu = Menu(items)
self._menu.hide()
self._menu.allow_layout = False
- #self.top.add(self._menu)
- def _on_btn_click(self):
- pass
+ def _set_top(self, value):
+ super()._set_top(value)
+ self.top.add(self._menu)
+ def _on_btn_click(self, ev):
+ self._menu.show()
+
--- a/tuikit/common.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/common.py Sat Dec 29 12:16:06 2012 +0100
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-from tuikit.emitter import Emitter
+from tuikit.emitter import Event, Emitter
class Coords:
@@ -41,7 +41,7 @@
def __init__(self, w=None, h=None):
self._w = w
self._h = h
- self.add_events('change')
+ self.add_events('change', Event)
@property
def w(self):
@@ -197,28 +197,3 @@
LTEE = '├'
RTEE = '┤'
-
-class MouseEvent:
- def __init__(self, x=0, y=0, button=0):
- self.x = x # global coordinates
- self.y = y
- self.wx = x # local widget coordinates
- self.wy = y
- self.px = 0 # parent coordinates
- self.py = 0
- self.button = button
-
-
- def childevent(self, child):
- ev = MouseEvent(self.x, self.y, self.button)
- # original local coordinates are new parent coordinates
- ev.px = self.wx
- ev.py = self.wy
- # update local coordinates
- ev.wx = self.wx - child.x
- ev.wy = self.wy - child.y
- return ev
-
- def __repr__(self):
- return 'MouseEvent(x={0.x},y={0.y},button={0.button})'.format(self)
-
--- a/tuikit/container.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/container.py Sat Dec 29 12:16:06 2012 +0100
@@ -43,7 +43,7 @@
'''Add widget into this container.'''
self.children.append(widget)
widget.parent = self
- widget.settop(self.top)
+ widget.top = self.top
widget.hints.update(kwargs)
if self.focuschild is None and widget.can_focus():
self.focuschild = widget
@@ -55,11 +55,10 @@
layout.container = self
- def settop(self, top):
- '''Set top widget.'''
- self.top = top
+ def _set_top(self, value):
+ self._top = value
for child in self.children:
- child.settop(top)
+ child.top = value
def focus_next(self):
@@ -92,17 +91,17 @@
return self.trap_focus or not cycled
idx_new += 1
- def _handle_keypress(self, keyname, char):
- super()._handle_keypress(keyname, char)
+ def _handle_keypress(self, ev):
+ super()._handle_keypress(ev)
if self.focuschild is not None:
- handled = self.focuschild.emit('keypress', keyname, char)
+ handled = self.focuschild.emit('keypress', ev)
if handled:
return True
- if keyname == 'tab':
+ if ev.keyname == 'tab':
return self.focus_next()
- def _handle_resize(self):
- super()._handle_resize()
+ def _handle_resize(self, ev):
+ super()._handle_resize(ev)
for child in self.children:
child.emit('resize')
--- a/tuikit/driver.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/driver.py Sat Dec 29 12:16:06 2012 +0100
@@ -5,23 +5,23 @@
class Driver:
-
+
'''Abstract driver interface. Use as base for drivers.'''
-
+
def __init__(self):
'''Initialize instance attributes.'''
+ #: Screen size.
self.size = Size()
- '''Screen size.'''
+ #: Clipping region stack.
self.clipstack = ClipStack()
- '''Clipping region stack.'''
+ #: Unicode graphics characters.
self.unigraph = UnicodeGraphics()
- '''Unicode graphics characters.'''
+ #: Stack of color prefixes.
self.colorprefix = []
- '''Stack of color prefixes.'''
## drawing ##
-
+
def puts(self, x, y, s):
'''Output string of characters.'''
for c in s:
@@ -59,7 +59,7 @@
## colors ##
-
+
def pushcolorprefix(self, name):
self.colorprefix.append(name)
--- a/tuikit/driver_curses.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/driver_curses.py Sat Dec 29 12:16:06 2012 +0100
@@ -6,7 +6,6 @@
import logging
from tuikit.driver import Driver
-from tuikit.common import MouseEvent
class DriverCurses(Driver):
@@ -282,28 +281,22 @@
except curses.error:
return []
- ev = MouseEvent(x, y)
-
out = []
if bstate & curses.REPORT_MOUSE_POSITION:
- out += [('mousemove', ev)]
+ out += [('mousemove', x, y)]
if bstate & curses.BUTTON1_PRESSED:
- ev.button = 1
- out += [('mousedown', ev)]
+ out += [('mousedown', x, y, 1)]
if bstate & curses.BUTTON3_PRESSED:
- ev.button = 3
- out += [('mousedown', ev)]
+ out += [('mousedown', x, y, 3)]
if bstate & curses.BUTTON1_RELEASED:
- ev.button = 1
- out += [('mouseup', ev)]
+ out += [('mouseup', x, y, 1)]
if bstate & curses.BUTTON3_RELEASED:
- ev.button = 3
- out += [('mouseup', ev)]
+ out += [('mouseup', x, y, 3)]
return out
@@ -333,7 +326,7 @@
consumed.append(c)
while True:
- # self.log.debug('c=%s len=%s', c, len(codes))
+ #self.log.debug('c=%s len=%s', c, len(codes))
for code in codes:
if c == code[len(consumed)-1]:
if len(code) - 1 == len(consumed):
@@ -341,7 +334,7 @@
else:
matchingcodes += [code]
- # self.log.debug('matching=%s', len(matchingcodes))
+ #self.log.debug('matching=%s', len(matchingcodes))
# match found, or no matching code found -> stop
if len(matchingcodes) == 0:
@@ -385,25 +378,23 @@
x = self.inputqueue_get_wait() - 0x21
y = self.inputqueue_get_wait() - 0x21
- ev = MouseEvent(x, y)
out = []
if t in (0x20, 0x21, 0x22): # button press
btn = t - 0x1f
- ev.button = btn
if not btn in self.mbtnstack:
self.mbtnstack.append(btn)
- out += [('mousedown', ev)]
+ out += [('mousedown', x, y, btn)]
else:
- out += [('mousemove', ev)]
+ out += [('mousemove', x, y, btn)]
elif t == 0x23: # button release
- ev.button = self.mbtnstack.pop()
- out += [('mouseup', ev)]
+ btn = self.mbtnstack.pop()
+ out += [('mouseup', x, y, btn)]
elif t in (0x60, 0x61): # wheel up, down
- ev.button = 4 + t - 0x60
- out += [('mousewheel', ev)]
+ btn = 4 + t - 0x60
+ out += [('mousewheel', x, y, btn)]
else:
raise Exception('Unknown mouse event: %x' % t)
--- a/tuikit/driver_pygame.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/driver_pygame.py Sat Dec 29 12:16:06 2012 +0100
@@ -5,17 +5,17 @@
import logging
from tuikit.driver import Driver
-from tuikit.common import Coords, Size, MouseEvent
+from tuikit.common import Coords, Size
class TerminalScreen:
-
+
'''Provide character-level output to screen SDL surface.
-
+
This is performance bottleneck and should be optimized as much as possible.
-
+
'''
-
+
def __init__(self):
fontselect = 'dejavusansmono,liberationmono,freemono'
self.font = pygame.font.SysFont(fontselect, 14)
@@ -25,13 +25,13 @@
height = self.font.get_height()
self.charsize = Size(advance, height)
self.ascent = self.font.get_ascent()
-
+
# choose self.render() implementation
if hasattr(self.font, 'render_glyph'):
self.render_char = self.render_glyph
else:
self.render_char = self.render_noglyph
-
+
self.chars = None
self.attrs = None
self.default_attr = None
@@ -39,10 +39,10 @@
def set_default_attr(self, fg, bg, flags):
self.default_attr = (fg, bg, flags)
-
+
def set_attr(self, fg, bg, flags):
self.current_attr = (fg, bg, flags)
-
+
def reset_attr(self):
self.current_attr = self.default_attr
@@ -51,18 +51,18 @@
numchars = w * h
self.chars = [' '] * numchars
self.attrs = [self.default_attr] * numchars
-
+
def clear(self):
numchars = self.w * self.h
for pos in range(numchars):
self.chars[pos] = ' '
self.attrs[pos] = self.default_attr
-
+
def putch(self, x, y, c):
pos = y * self.w + x
self.chars[pos] = c
self.attrs[pos] = self.current_attr
-
+
def update(self, surface):
pos = 0
for y in range(self.h):
@@ -77,18 +77,18 @@
def render_glyph(self, screen, x, y, c, fgcolor, bgcolor, flags):
'''Render using render_glyph and metrics.
-
+
This is the correct way, but the output seems same as of render_noglyph
and this implementation requires patching PyGame to work.
-
+
This implements render() method. See render_noglyph for other implementation.
-
- '''
+
+ '''
# draw background
dest = Coords(x * self.charsize.w, y * self.charsize.h)
if bgcolor != self.default_attr[1]:
screen.fill(bgcolor, pygame.Rect(dest.x, dest.y, self.charsize.w, self.charsize.h))
-
+
if not c:
return
@@ -103,7 +103,7 @@
metrics = font.metrics(c)[0]
minx, maxx, miny, maxy, advance = metrics
height, ascent = self.charsize.h, self.ascent
-
+
# clips origin and area of rendered character according to metrics
startx, starty = 0, 0
if minx < 0:
@@ -116,24 +116,24 @@
miny = ascent - height
if maxx > advance:
maxx = advance
-
+
# draw character
dest.x += minx
dest.y += ascent - maxy
area = pygame.Rect(startx, starty, maxx - minx, maxy - miny)
screen.blit(surface, tuple(dest), area)
-
+
def render_noglyph(self, screen, x, y, c, fgcolor, bgcolor, attr):
'''Render character using normal text rendering.
-
+
This implements render() method. See render_glyph for other implementation.
-
+
'''
if attr == 'bold':
font = self.font_bold
else:
font = self.font
-
+
# render character, get metrics
surface = font.render(c, True, fgcolor, bgcolor)
metrics = font.metrics(c)[0]
@@ -141,20 +141,20 @@
startx = 0
if minx < 0:
startx = abs(minx)
-
+
# draw background
dest = Coords(x * self.charsize.w, y * self.charsize.h)
screen.fill(bgcolor, pygame.Rect(dest.x, dest.y, self.charsize.w, self.charsize.h))
-
+
# draw character
area = pygame.Rect(startx, 0, self.charsize.w, self.charsize.h)
screen.blit(surface, tuple(dest), area)
class DriverPygame(Driver):
-
+
'''PyGame driver class.'''
-
+
keymap = {
pygame.K_ESCAPE : 'escape',
pygame.K_TAB : 'tab',
@@ -186,7 +186,7 @@
pygame.K_SCROLLOCK : 'scrollock',
pygame.K_PAUSE : 'pause',
}
-
+
colormap = {
'black' : (0,0,0),
'blue' : (23,23,178),
@@ -205,7 +205,7 @@
'intenseyellow' : (255,255,84),
'intensewhite' : (255,255,255),
}
-
+
def __init__(self):
'''Initialize instance attributes'''
Driver.__init__(self)
@@ -234,21 +234,22 @@
self.term.reset(self.size.w, self.size.h)
## input ##
-
+
def getevents(self, timeout=None):
'''Process input, return list of events.'''
events = []
for ev in pygame.event.get():
# mouse
if ev.type == pygame.MOUSEMOTION:
- evdata = MouseEvent(ev.pos[0] // self.charsize.w, ev.pos[1] // self.charsize.h)
- events.append(('mousemove', evdata))
+ mx = ev.pos[0] // self.charsize.w
+ my = ev.pos[1] // self.charsize.h
+ events.append(('mousemove', mx, my))
elif ev.type in (pygame.MOUSEBUTTONDOWN, pygame.MOUSEBUTTONUP):
- evdata = MouseEvent(ev.pos[0] // self.charsize.w, ev.pos[1] // self.charsize.h)
- evdata.button = ev.button
+ mx = ev.pos[0] // self.charsize.w
+ my = ev.pos[1] // self.charsize.h
evname = {pygame.MOUSEBUTTONDOWN: 'mousedown', pygame.MOUSEBUTTONUP: 'mouseup'}
- events.append((evname[ev.type], evdata))
-
+ events.append((evname[ev.type], mx, my, ev.button))
+
# keyboard
elif ev.type == pygame.KEYDOWN:
keypress = self.keypress_from_pygame_event(ev)
@@ -263,7 +264,7 @@
elif ev.type == pygame.KEYUP:
if ev.key == self.last_key:
pygame.time.set_timer(pygame.USEREVENT, 0)
-
+
# window
elif ev.type == pygame.VIDEORESIZE:
neww, newh = ev.w // self.charsize.w, ev.h // self.charsize.h
@@ -273,7 +274,7 @@
events.append(('resize',))
elif ev.type == pygame.QUIT:
events.append(('quit',))
-
+
else:
self.log.warning('Unknown PyGame event: %r', ev.type)
return events
@@ -289,12 +290,12 @@
return keypress
## drawing ##
-
+
def erase(self):
'''Clear screen.'''
self.term.clear()
self.screen.fill(self.term.default_attr[1])
-
+
def putch(self, x, y, c):
if not self.clipstack.test(x, y):
return
@@ -307,13 +308,13 @@
## colors ##
-
+
def _parsecolor(self, name, attr=None):
name = name.lower().strip()
if attr == 'bold':
name = 'intense' + name
return self.colormap[name]
-
+
def _parseattrs(self, attrs):
res = ''
for a in attrs:
@@ -324,10 +325,10 @@
def setcolor(self, name, desc):
'''Define color name.
-
+
name - name of color (e.g. 'normal', 'active')
desc - color description - foreground, background, attributes (e.g. 'black on white, bold')
-
+
'''
parts = desc.split(',')
fg, bg = parts[0].split(' on ')
@@ -347,7 +348,7 @@
col = self.colors[name]
self.current_color = col
self.colorstack.append(col)
-
+
def popcolor(self):
'''Remove color from top of stack and use new top color for following output.'''
self.colorstack.pop()
--- a/tuikit/editbox.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/editbox.py Sat Dec 29 12:16:06 2012 +0100
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from tuikit.widget import Widget
+from tuikit.emitter import Event
class EditBox(Widget):
@@ -20,13 +21,15 @@
self.sline = 0
self.spos = 0
- self.add_events('scroll', 'areasize')
+ self.add_events(
+ 'scroll', Event,
+ 'areasize', Event)
self.set_text(text)
- def _handle_draw(self, screen, x, y):
- super()._handle_draw(screen, x, y)
+ def _handle_draw(self, ev):
+ super()._handle_draw(ev)
for j in range(self.height):
if self.yofs + j >= len(self.lines):
break
@@ -35,52 +38,52 @@
#line += ' ' * (self.width - len(line))
#else:
#line = line[:self.width]
- screen.puts(x, y + j, line)
+ ev.driver.puts(ev.x, ev.y + j, line)
self.cursor = (self.get_cpos() - self.xofs, self.cline - self.yofs)
- def _handle_keypress(self, keyname, char):
- super()._handle_keypress(keyname, char)
- if keyname:
- if keyname == 'left':
+ def _handle_keypress(self, ev):
+ super()._handle_keypress(ev)
+ if ev.keyname:
+ if ev.keyname == 'left':
self.move_left()
- if keyname == 'right':
+ if ev.keyname == 'right':
self.move_right()
- if keyname == 'home':
+ if ev.keyname == 'home':
self.move_home()
- if keyname == 'end':
+ if ev.keyname == 'end':
self.move_end()
- if keyname == 'up':
+ if ev.keyname == 'up':
self.move_up()
- if keyname == 'down':
+ if ev.keyname == 'down':
self.move_down()
- if keyname == 'pageup':
+ if ev.keyname == 'pageup':
self.move_pageup()
- if keyname == 'pagedown':
+ if ev.keyname == 'pagedown':
self.move_pagedown()
- if keyname == 'backspace':
+ if ev.keyname == 'backspace':
if self.cline > 0 or self.cpos > 0:
self.move_left()
self.del_char()
- if keyname == 'delete':
+ if ev.keyname == 'delete':
self.del_char()
- if keyname == 'enter':
+ if ev.keyname == 'enter':
self.add_newline()
self.move_right()
- if char:
- self.add_char(char)
+ if ev.char:
+ self.add_char(ev.char)
self.move_right()
self.redraw()
@@ -121,8 +124,9 @@
yofs = len(self.lines) - self.height
if yofs < 0:
yofs = 0
- self.yofs = yofs
- self.emit('scroll')
+ if self.yofs != yofs:
+ self.yofs = yofs
+ self.emit('scroll')
def move_left(self):
--- a/tuikit/editfield.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/editfield.py Sat Dec 29 12:16:06 2012 +0100
@@ -22,56 +22,56 @@
self.pos = len(value) # position of cursor in value
self.ofs = 0 # position of value beginning on screen
- def _handle_resize(self):
- super()._handle_resize()
+ def _handle_resize(self, ev):
+ super()._handle_resize(ev)
self.tw = self.width - 2
- def _handle_draw(self, screen, x, y):
- super()._handle_draw(screen, x, y)
- screen.pushcolor('normal')
+ def _handle_draw(self, ev):
+ super()._handle_draw(ev)
+ ev.driver.pushcolor('normal')
# draw value
val = self.value + ' ' * self.tw # add spaces to fill rest of field
val = val[self.ofs : self.ofs + self.tw] # cut value - begin from ofs, limit to tw chars
- screen.puts(x + 1, y, val.encode(self.code))
+ ev.driver.puts(ev.x + 1, ev.y, val.encode(self.code))
# draw arrows if content overflows
c = ' '
if self.ofs > 0:
c = '<'
- screen.putch(x, y, c)
+ ev.driver.putch(ev.x, ev.y, c)
c = ' '
if len(self.value[self.ofs:]) > self.tw:
c = '>'
- screen.putch(x + self.width-1, y, c)
+ ev.driver.putch(ev.x + self.width-1, ev.y, c)
self.cursor = (1 + self.pos - self.ofs, 0)
- screen.popcolor()
+ ev.driver.popcolor()
- def _handle_keypress(self, keyname, char):
- super()._handle_keypress(keyname, char)
+ def _handle_keypress(self, ev):
+ super()._handle_keypress(ev)
handled = False
- if keyname:
+ if ev.keyname:
handled = 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.pos > 0:
self.move_left()
self.del_char()
- elif keyname == 'delete':
+ elif ev.keyname == 'delete':
self.del_char()
else:
handled = False
- if char:
- self.add_char(char)
+ if ev.char:
+ self.add_char(ev.char)
self.move_right()
handled = True
--- a/tuikit/emitter.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/emitter.py Sat Dec 29 12:16:06 2012 +0100
@@ -1,28 +1,116 @@
# -*- coding: utf-8 -*-
+"""Event emitter.
+
+This is simple implementation of signals/slots paradigm.
+We deliberately do not use signal or slot words, as they
+could be misleading (there are __slots__ in Python and
+signals in Unix OS).
+
+"""
import logging
+class Event:
+ def __init__(self):
+ self.originator = None
+
+ def __getitem__(self, key):
+ return self.__dict__[key]
+
+
+class DrawEvent(Event):
+ def __init__(self, driver, x, y):
+ super().__init__()
+ self.driver = driver
+ self.x = x
+ self.y = y
+
+ def __repr__(self):
+ return 'DrawEvent(x={0.x},y={0.y})'.format(self)
+
+
+class FocusEvent(Event):
+ def __init__(self, old=None, new=None):
+ super().__init__()
+ #: Former focused widget.
+ self.old = old
+ #: Current focused widget.
+ self.new = new
+
+ def __repr__(self):
+ return 'FocusEvent(old={0.old},new={0.new})'.format(self)
+
+
+class KeyboardEvent(Event):
+ def __init__(self, keyname, char):
+ super().__init__()
+ self.keyname = keyname
+ self.char = char
+
+ def __repr__(self):
+ return 'KeyboardEvent(keyname={0.keyname},char={0.char})'.format(self)
+
+
+class MouseEvent(Event):
+ def __init__(self, x=0, y=0, button=0):
+ super().__init__()
+ self.x = x # global coordinates
+ self.y = y
+ self.wx = x # local widget coordinates
+ self.wy = y
+ self.px = 0 # parent coordinates
+ self.py = 0
+ self.button = button
+
+ def childevent(self, child):
+ ev = MouseEvent(self.x, self.y, self.button)
+ # original local coordinates are new parent coordinates
+ ev.px = self.wx
+ ev.py = self.wy
+ # update local coordinates
+ ev.wx = self.wx - child.x
+ ev.wy = self.wy - child.y
+ return ev
+
+ def __repr__(self):
+ return 'MouseEvent(x={0.x},y={0.y},button={0.button})'.format(self)
+
+
+class GenericEvent(Event):
+ """Generic event which carries an object with additional data."""
+ def __init__(self, data):
+ self.data = data
+
+
class Emitter:
"""Event emitter mixin class."""
- def add_events(self, *event_names):
- """Add event names which may be registered by user.
+ def add_events(self, *events):
+ """Add events which may be registered by user.
This should be called only by subclasses.
This serves also as initializer, other methods of Emitter
will not work if add_events was not called.
+ *events -- Arguments must be given in pairs.
+
+ Each pair consists of event_name, event_class:
+ event_name -- a string used in connect(), emit()
+ event_class -- class of event payload
+
"""
if not hasattr(self, '_event_handlers'):
self._event_handlers = dict()
- for event_name in event_names:
+ self._event_class = dict()
+ for event_name, event_class in zip(events[::2], events[1::2]):
self._event_handlers[event_name] = []
+ self._event_class[event_name] = event_class
# add default dummy handler if no handler exists for this event
handler_name = '_handle_' + event_name
if not hasattr(Emitter, handler_name):
- setattr(Emitter, handler_name, lambda *args, **kwargs: False)
+ setattr(Emitter, handler_name, lambda self, ev: False)
def connect(self, event_name, handler):
"""Connect event handler to event name.
@@ -69,17 +157,33 @@
Return True when one of the handlers returns True,
False otherwise.
-
+
+ This creates new instance of event_class given to
+ add_events() and passes all arguments after event_name
+ to its __init__ method.
+
+ Unless first of these arguments is Event instance
+ in which case no object is created and the instance
+ is passed to handlers.
+
"""
logging.getLogger('tuikit').debug('Emit "%s" on %s %s',
event_name,
self.__class__.__name__,
getattr(self, 'name', None) or id(self))
- handled = getattr(self, '_handle_' + event_name)(*args, **kwargs)
+ # create event from specified event class, or use first argument
+ if len(args) and isinstance(args[0], Event):
+ event = args[0]
+ else:
+ event = self._event_class[event_name](*args, **kwargs)
+ event.originator = self
+ # try default handler, stop if satisfied
+ handled = getattr(self, '_handle_' + event_name)(event)
if handled:
return True
+ # try custom handlers, stop if satisfied
for handler in self._event_handlers[event_name]:
- handled = handler(self, *args, **kwargs)
+ handled = handler(event)
if handled:
return True
--- a/tuikit/label.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/label.py Sat Dec 29 12:16:06 2012 +0100
@@ -9,9 +9,9 @@
self.label = label
- def _handle_draw(self, screen, x, y):
- super()._handle_draw(screen, x, y)
- screen.pushcolor('normal')
- screen.puts(x, y, self.label)
- screen.popcolor()
+ def _handle_draw(self, ev):
+ super()._handle_draw(ev)
+ ev.driver.pushcolor('normal')
+ ev.driver.puts(ev.x, ev.y, self.label)
+ ev.driver.popcolor()
--- a/tuikit/layout.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/layout.py Sat Dec 29 12:16:06 2012 +0100
@@ -25,7 +25,7 @@
self._container = value
self._container.connect('resize', self._on_container_resize)
- def _on_container_resize(self, eo):
+ def _on_container_resize(self, ev):
self.resize()
def _getchildren(self):
--- a/tuikit/menu.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/menu.py Sat Dec 29 12:16:06 2012 +0100
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from tuikit.widget import Widget
+from tuikit.emitter import GenericEvent
class Menu(Widget):
@@ -17,34 +18,36 @@
self.selected = items[0]
self.menubar = None
- self.add_events('activate')
+ self.add_events('activate', GenericEvent)
- def _handle_draw(self, screen, x, y):
- super()._handle_draw(screen, x, y)
- screen.pushcolor(self.bg)
- screen.frame(x, y, self.width, self.height)
+ def _handle_draw(self, ev):
+ super()._handle_draw(ev)
+ ev.driver.pushcolor(self.bg)
+ ev.driver.frame(ev.x, ev.y, self.width, self.height)
i = 1
for item in self.items:
if item is None:
- screen.puts(x, y + i, screen.unigraph.LTEE + \
- screen.unigraph.HLINE * (self.width - 2) + screen.unigraph.RTEE)
+ ev.driver.puts(ev.x, ev.y + i, ev.driver.unigraph.LTEE + \
+ ev.driver.unigraph.HLINE * (self.width - 2) + ev.driver.unigraph.RTEE)
else:
if self.selected == item:
- screen.pushcolor(self.highlight)
- screen.puts(x + 1, y + i, ' ' + item[0] + ' ' * (self.width - 3 - len(item[0])))
- screen.popcolor()
+ ev.driver.pushcolor(self.highlight)
+ ev.driver.puts(ev.x + 1, ev.y + i,
+ ' ' + item[0] + ' ' * (self.width - 3 - len(item[0])))
+ ev.driver.popcolor()
else:
- screen.puts(x + 1, y + i, ' ' + item[0] + ' ' * (self.width - 3 - len(item[0])))
+ ev.driver.puts(ev.x + 1, ev.y + i,
+ ' ' + item[0] + ' ' * (self.width - 3 - len(item[0])))
i += 1
- screen.popcolor()
+ ev.driver.popcolor()
- def _handle_keypress(self, keyname, char):
- super()._handle_keypress(keyname, char)
- if keyname == 'up':
+ def _handle_keypress(self, ev):
+ super()._handle_keypress(ev)
+ if ev.keyname == 'up':
self.move_selected(-1)
- if keyname == 'down':
+ if ev.keyname == 'down':
self.move_selected(+1)
- if keyname == 'enter':
+ if ev.keyname == 'enter':
self.run_selected()
self.redraw()
--- a/tuikit/menubar.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/menubar.py Sat Dec 29 12:16:06 2012 +0100
@@ -29,33 +29,33 @@
item[1].menubar = self
i += len(item[0]) + 4
- def _handle_draw(self, screen, x, y):
- super()._handle_draw(screen, x, y)
- screen.pushcolor(self.bg)
+ def _handle_draw(self, ev):
+ super()._handle_draw(ev)
+ ev.driver.pushcolor(self.bg)
i = 0
for item in self.items:
if self.selected == item:
- screen.pushcolor(self.highlight)
- screen.puts(x + i, y, ' ' + item[0] + ' ')
- screen.popcolor()
+ ev.driver.pushcolor(self.highlight)
+ ev.driver.puts(ev.x + i, ev.y, ' ' + item[0] + ' ')
+ ev.driver.popcolor()
else:
- screen.puts(x + i, y, ' ' + item[0] + ' ')
+ ev.driver.puts(ev.x + i, ev.y, ' ' + item[0] + ' ')
i += len(item[0]) + 4
if i < self.width:
- screen.puts(x + i, y, ' ' * (self.width - i))
- screen.popcolor()
+ ev.driver.puts(ev.x + i, ev.y, ' ' * (self.width - i))
+ ev.driver.popcolor()
- def _handle_keypress(self, keyname, char):
- super()._handle_draw(keyname, char)
- if keyname == 'left':
+ def _handle_keypress(self, ev):
+ super()._handle_draw(ev)
+ if ev.keyname == 'left':
self.move_selected(-1)
- elif keyname == 'right':
+ elif ev.keyname == 'right':
self.move_selected(+1)
else:
if self.selected:
if isinstance(self.selected[1], Widget):
- self.selected[1].emit('keypress', keyname, char)
+ self.selected[1].emit('keypress', ev.keyname, ev.char)
def move_selected(self, offset):
@@ -68,25 +68,28 @@
def _handle_mousedown(self, ev):
super()._handle_mousedown(ev)
+ self._select_xy(ev.wx, ev.wy)
+
+ def _handle_mousemove(self, ev):
+ super()._handle_mousemove(ev)
+ self._select_xy(ev.wx, ev.wy)
+
+ def _select_xy(self, wx, wy):
i = 0
self.unselect()
for item in self.items:
w = len(item[0]) + 4
- if ev.wx >= i and ev.wx < i + w:
+ if wx >= i and wx < i + w:
self.select(item)
i += w
- def _handle_mousemove(self, ev):
- super()._handle_mousemove(ev)
- self.on_mousedown(ev)
-
- def _handle_unfocus(self, newfocus):
- super()._handle_unfocus()
- if self.selected and newfocus == self.selected[1]:
+ def _handle_unfocus(self, ev):
+ super()._handle_unfocus(ev)
+ if self.selected and ev.new == self.selected[1]:
return
self.unselect()
- def on_submenu_focus(self):
+ def on_submenu_focus(self, ev):
self.set_focus()
def select(self, item):
--- a/tuikit/scrollbar.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/scrollbar.py Sat Dec 29 12:16:06 2012 +0100
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from tuikit.widget import Widget
+from tuikit.emitter import Event
class VScrollbar(Widget):
@@ -16,7 +17,7 @@
self.dragging = False
self.move = None
- self.add_events('change')
+ self.add_events('change', Event)
@property
def max(self):
@@ -39,9 +40,10 @@
@pos.setter
def pos(self, value):
- self._pos = value
- self._update_thumbpos()
- self.emit('change')
+ if self._pos != value:
+ self._pos = value
+ self._update_thumbpos()
+ self.emit('change')
def _update_thumbpos(self):
self._thumbpos = 0
@@ -49,13 +51,13 @@
self._thumbpos = int(round(self._pos / self._max * (self.height - 3)))
self.redraw()
- def _handle_draw(self, screen, x, y):
- super()._handle_draw(screen, x, y)
- screen.putch(x, y, screen.unigraph.UP_ARROW)
- for i in range(y + 1, y + self.height - 1):
- screen.putch(x, i, screen.unigraph.LIGHT_SHADE)
- screen.putch(x, y + 1 + self._thumbpos, screen.unigraph.BLOCK)
- screen.putch(x, y + self.height - 1, screen.unigraph.DOWN_ARROW)
+ def _handle_draw(self, ev):
+ super()._handle_draw(ev)
+ ev.driver.putch(ev.x, ev.y, ev.driver.unigraph.UP_ARROW)
+ for i in range(ev.y + 1, ev.y + self.height - 1):
+ ev.driver.putch(ev.x, i, ev.driver.unigraph.LIGHT_SHADE)
+ ev.driver.putch(ev.x, ev.y + 1 + self._thumbpos, ev.driver.unigraph.BLOCK)
+ ev.driver.putch(ev.x, ev.y + self.height - 1, ev.driver.unigraph.DOWN_ARROW)
def _handle_mousedown(self, ev):
super()._handle_mousedown(ev)
--- a/tuikit/scrollview.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/scrollview.py Sat Dec 29 12:16:06 2012 +0100
@@ -26,16 +26,16 @@
if widget != self.vscroll:
widget.connect('sizereq', self._on_child_sizereq)
- def _handle_resize(self):
- super()._handle_resize()
+ def _handle_resize(self, ev):
+ super()._handle_resize(ev)
self.vscroll.x = self.size.w - 1
self.vscroll.height = self.height
self._update_vscroll_max()
- def _on_vscroll_change(self, eo):
+ def _on_vscroll_change(self, ev):
self.offset.y = - self.vscroll.pos
- def _on_child_sizereq(self, eo):
+ def _on_child_sizereq(self, ev):
self._update_vscroll_max()
def _update_vscroll_max(self):
--- a/tuikit/tableview.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/tableview.py Sat Dec 29 12:16:06 2012 +0100
@@ -3,14 +3,14 @@
import math
import logging
-from tuikit.emitter import Emitter
+from tuikit.emitter import Event, Emitter
from tuikit.widget import Widget
from tuikit.common import Coords
class TableModel(Emitter):
def __init__(self, list_of_lists):
- self.add_events('change')
+ self.add_events('change', Event)
self.data = list_of_lists
def getcount(self):
@@ -82,7 +82,9 @@
self.acell = Coords()
'''Active cell (cursor).'''
- self.add_events('scroll', 'areasize')
+ self.add_events(
+ 'scroll', Event,
+ 'areasize', Event)
def getmodel(self):
return self._model
@@ -156,32 +158,32 @@
screen.popcolor()
x += col.size + self.spacing
- def _handle_draw(self, screen, x, y):
- super()._handle_draw(screen, x, y)
- screen.pushcolor('normal')
+ def _handle_draw(self, ev):
+ super()._handle_draw(ev)
+ ev.driver.pushcolor('normal')
self.rowcount = self.model.getcount()
numrows = min(self.rowcount - self.offset.y, self.size.h - self.headsize)
rows = self.model.getrows(self.offset.y, self.offset.y + numrows)
self.compute_column_sizes()
- self.draw_head(screen, x, y)
- y += self.headsize
+ self.draw_head(ev.driver, ev.x, ev.y)
+ y = ev.y + self.headsize
for row in rows:
highlight = []
if self.offset.y + rows.index(row) == self.acell.y:
highlight.append(self.acell.x)
- self.draw_row(screen, x, y, row, highlight)
+ self.draw_row(ev.driver, ev.x, y, row, highlight)
y += 1
- screen.popcolor()
+ ev.driver.popcolor()
- def _handle_keypress(self, keyname, char):
- super()._handle_keypress(keyname, char)
- if keyname:
- if keyname == 'up': self.move_up()
- if keyname == 'down': self.move_down()
- if keyname == 'left': self.move_left()
- if keyname == 'right': self.move_right()
- if keyname == 'pageup': self.move_pageup()
- if keyname == 'pagedown': self.move_pagedown()
+ def _handle_keypress(self, ev):
+ super()._handle_keypress(ev)
+ if ev.keyname:
+ if ev.keyname == 'up': self.move_up()
+ if ev.keyname == 'down': self.move_down()
+ if ev.keyname == 'left': self.move_left()
+ if ev.keyname == 'right': self.move_right()
+ if ev.keyname == 'pageup': self.move_pageup()
+ if ev.keyname == 'pagedown': self.move_pagedown()
self.redraw()
def set_yofs(self, yofs):
--- a/tuikit/textedit.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/textedit.py Sat Dec 29 12:16:06 2012 +0100
@@ -22,33 +22,28 @@
self.vscroll.y = 1
self.vscroll.connect('change', self.on_vscroll_change)
- self.on_editbox_areasize()
+ self.on_editbox_areasize(None)
def settext(self, text):
self.editbox.set_text(text)
-
def scrolltoend(self):
self.editbox.move_pagelast()
-
- def _handle_draw(self, screen, x, y):
- super()._handle_draw(screen, x, y)
- screen.frame(x, y, self.width, self.height)
-
+ def _handle_draw(self, ev):
+ super()._handle_draw(ev)
+ ev.driver.frame(ev.x, ev.y, self.width, self.height)
- def on_editbox_scroll(self):
- self.vscroll.setpos(self.editbox.yofs)
+ def on_editbox_scroll(self, ev):
+ self.vscroll.pos = self.editbox.yofs
-
- def on_editbox_areasize(self):
+ def on_editbox_areasize(self, ev):
smax = len(self.editbox.lines) - self.editbox.height
if smax < 0:
smax = 0
self.vscroll.max = smax
-
- def on_vscroll_change(self):
+ def on_vscroll_change(self, ev):
self.editbox.set_yofs(self.vscroll.pos)
self.editbox.redraw()
--- a/tuikit/treeview.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/treeview.py Sat Dec 29 12:16:06 2012 +0100
@@ -1,9 +1,13 @@
# -*- coding: utf-8 -*-
-from tuikit.emitter import Emitter
+from tuikit.emitter import Event, Emitter
from tuikit.widget import Widget
-import logging
+
+class TreeEvent(Event):
+ def __init__(self, node):
+ Event.__init__(self)
+ self.node = node
class TreeIter:
@@ -99,7 +103,7 @@
"""
def __init__(self):
- self.add_events('node_added') # node added, arg is the node
+ self.add_events('node_added', TreeEvent)
self.root = TreeNode('', model=self)
def __iter__(self):
@@ -185,8 +189,8 @@
self.collapsed = []
self.add_events(
- 'expand', # node expanded, the affected node is given in args
- 'collapse') # node collapsed, the affected node is given in args
+ 'expand', TreeEvent, # node expanded, event carries the affected node
+ 'collapse', TreeEvent) # node collapsed, event carries the affected node
if model:
self.model = model
@@ -212,9 +216,9 @@
pass
self._update_sizereq()
- def on_model_node_added(self, node):
+ def on_model_node_added(self, ev):
if self.cnode is None:
- self.cnode = node
+ self.cnode = ev.node
self._update_sizereq()
self.redraw()
@@ -235,25 +239,26 @@
pass
self._update_sizereq()
- def _handle_draw(self, driver, x, y):
- super()._handle_draw(driver, x, y)
- driver.pushcolor('normal')
+ def _handle_draw(self, ev):
+ super()._handle_draw(ev)
+ ev.driver.pushcolor('normal')
lines = 0 # bit array, bit 0 - draw vertical line on first column, etc.
+ y = ev.y
for level, index, count, node in self:
# prepare string with vertical lines where they should be
head = []
for l in range(level-1):
if lines & (1 << l):
- head.append(driver.unigraph.VLINE + ' ')
+ head.append(ev.driver.unigraph.VLINE + ' ')
else:
head.append(' ')
# add vertical line if needed
if index < count:
- head.append(driver.unigraph.LTEE)
+ head.append(ev.driver.unigraph.LTEE)
lines |= 1 << level-1
else:
- head.append(driver.unigraph.LLCORNER)
+ head.append(ev.driver.unigraph.LLCORNER)
lines &= ~(1 << level-1)
# draw lines and titles
head = ''.join(head)
@@ -261,23 +266,22 @@
sep = '+'
else:
sep = ' '
- driver.puts(x, y, head + sep + str(node))
+ ev.driver.puts(ev.x, y, head + sep + str(node))
if node is self.cnode:
- driver.pushcolor('active')
- driver.puts(x + len(head), y, sep + str(node) + ' ')
- driver.popcolor()
-
+ ev.driver.pushcolor('active')
+ ev.driver.puts(ev.x + len(head), y, sep + str(node) + ' ')
+ ev.driver.popcolor()
y += 1
- driver.popcolor()
+ ev.driver.popcolor()
- def _handle_keypress(self, keyname, char):
- super()._handle_keypress(keyname, char)
- if keyname:
- if keyname == 'up': self.move_up()
- if keyname == 'down': self.move_down()
- if keyname == 'left': self.move_left()
- if keyname == 'right': self.move_right()
+ def _handle_keypress(self, ev):
+ super()._handle_keypress(ev)
+ if ev.keyname:
+ if ev.keyname == 'up': self.move_up()
+ if ev.keyname == 'down': self.move_down()
+ if ev.keyname == 'left': self.move_left()
+ if ev.keyname == 'right': self.move_right()
self.redraw()
--- a/tuikit/widget.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/widget.py Sat Dec 29 12:16:06 2012 +0100
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-from tuikit.emitter import Emitter
+from tuikit.emitter import Emitter, Event, DrawEvent, FocusEvent, KeyboardEvent, MouseEvent
from tuikit.common import Coords, Size
@@ -16,7 +16,7 @@
self.parent = None
#: Top widget (same for every widget in one application).
- self.top = None
+ self._top = None
# Position inside parent widget. Modified by layout manager.
self.position = Coords()
@@ -34,9 +34,9 @@
self.sizemax = Size(None, None)
#: Size request. This is default size of the widget. Will be fulfilled if possible.
- #: Tuple (w, h). Integers >= 1 or None (meaning use minumal size).
+ #: Size(w, h). Integers >= 1 or None (meaning use minumal size).
self._sizereq = Size(10, 10)
- self._sizereq.connect('change', lambda eo: self.emit('sizereq'))
+ self._sizereq.connect('change', lambda ev: self.emit('sizereq'))
#: When false, the widget is not considered in layout.
self.allow_layout = True
@@ -58,16 +58,16 @@
# event handlers
self.add_events(
- 'resize',
- 'sizereq',
- 'draw',
- 'focus',
- 'unfocus',
- 'keypress',
- 'mousedown',
- 'mouseup',
- 'mousemove',
- 'mousewheel')
+ 'resize', Event,
+ 'sizereq', Event,
+ 'draw', DrawEvent,
+ 'focus', FocusEvent,
+ 'unfocus', FocusEvent,
+ 'keypress', KeyboardEvent,
+ 'mousedown', MouseEvent,
+ 'mouseup', MouseEvent,
+ 'mousemove', MouseEvent,
+ 'mousewheel', MouseEvent)
@property
@@ -107,10 +107,26 @@
@property
def sizereq(self):
+ """Size request.
+
+ This is default size of the widget. Will be fulfilled if possible.
+ Size(w, h). Integers >= 1 or None (meaning use minumal size).
+
+ """
return self._sizereq
- def settop(self, top):
- self.top = top
+ @property
+ def top(self):
+ """Top widget (same for every widget in one application)."""
+ return self._top
+
+ @top.setter
+ def top(self, value):
+ self._set_top(value)
+
+ def _set_top(self, value):
+ """Real setter for top. Allows override."""
+ self._top = value
### events
@@ -124,7 +140,7 @@
"""Draw the widget.
This method should not be overriden by subclasses,
- use on_draw instead.
+ use _handle_draw instead.
"""
if self.hidden:
@@ -171,10 +187,11 @@
"""
if self.has_focus() or not self.can_focus():
return
- if self.parent.focuschild:
- self.parent.focuschild.emit('unfocus', self)
+ oldfocuschild = self.parent.focuschild
self.parent.focuschild = self
- self.emit('focus')
+ if oldfocuschild:
+ oldfocuschild.emit('unfocus', new=self)
+ self.emit('focus', old=oldfocuschild)
def grab_focus(self):
--- a/tuikit/window.py Wed Dec 26 01:00:31 2012 +0100
+++ b/tuikit/window.py Sat Dec 29 12:16:06 2012 +0100
@@ -55,24 +55,24 @@
self.closebtn.hidden = not value
- def _handle_draw(self, screen, x, y):
- super()._handle_draw(screen, x, y)
- screen.pushcolor('normal')
- screen.frame(x, y, self.width, self.height)
+ def _handle_draw(self, ev):
+ super()._handle_draw(ev)
+ ev.driver.pushcolor('normal')
+ ev.driver.frame(ev.x, ev.y, self.width, self.height)
if self.resizable:
if self.resizing:
- screen.pushcolor('controls-active')
+ ev.driver.pushcolor('controls-active')
else:
- screen.pushcolor('controls')
- screen.puts(x + self.width - 2, y + self.height - 1, '─┘') # '━┛'
- screen.popcolor()
+ ev.driver.pushcolor('controls')
+ ev.driver.puts(ev.x + self.width - 2, ev.y + self.height - 1, '─┘') # '━┛'
+ ev.driver.popcolor()
if self.title:
- screen.puts(x + (self.width - len(self.title))//2, y, self.title)
+ ev.driver.puts(ev.x + (self.width - len(self.title))//2, ev.y, self.title)
- screen.fill(x+1, y+1, self.width-2, self.height-2)
- screen.popcolor()
+ ev.driver.fill(ev.x+1, ev.y+1, self.width-2, self.height-2)
+ ev.driver.popcolor()
def _handle_mousedown(self, ev):
@@ -131,12 +131,11 @@
self.redraw(True)
- def _handle_resize(self):
- super()._handle_resize()
+ def _handle_resize(self, ev):
+ super()._handle_resize(ev)
self.closebtn.x = self.width - 5
- def on_closebtn_click(self):
+ def on_closebtn_click(self, ev):
self.hide()
-