Use Point for mouse events, add them to Container and Widget.
--- a/demos/04_texteditor.py Mon Sep 01 08:55:40 2014 +0200
+++ b/demos/04_texteditor.py Wed Sep 03 08:53:44 2014 +0200
@@ -8,6 +8,7 @@
class MyApplication(Application):
+
def __init__(self):
Application.__init__(self)
#self.top.add_handler('keypress', self.on_top_keypress)
--- a/tuikit/core/container.py Mon Sep 01 08:55:40 2014 +0200
+++ b/tuikit/core/container.py Wed Sep 03 08:53:44 2014 +0200
@@ -16,6 +16,7 @@
#: List of child widgets.
self.children = []
self.focus_child = None
+ self.mouse_child = None
self.layout = layout_class()
def add(self, widget):
@@ -67,3 +68,20 @@
def keypress(self, keyname, char, mod=0):
if self.focus_child:
self.focus_child.keypress(keyname, char, mod)
+
+ def mousedown(self, button, pos):
+ self.mouse_child = None
+ for child in reversed(self.children):
+ if pos in child.boundaries:
+ child.mousedown(button, pos - child.pos)
+ self.mouse_child = child
+
+ def mouseup(self, button, pos):
+ if self.mouse_child:
+ self.mouse_child.mouseup(button, pos - self.mouse_child.pos)
+
+ def mousemove(self, button, pos, relpos):
+ if self.mouse_child:
+ self.mouse_child.mousemove(button,
+ pos - self.mouse_child.pos, relpos)
+
--- a/tuikit/core/coords.py Mon Sep 01 08:55:40 2014 +0200
+++ b/tuikit/core/coords.py Wed Sep 03 08:53:44 2014 +0200
@@ -1,3 +1,4 @@
+
class Point:
"""Point in cartesian space.
@@ -11,12 +12,6 @@
self.y = 0
self.update(*args, **kwargs)
- def __getitem__(self, key):
- return (self.x, self.y)[key]
-
- def __repr__(self):
- return 'Point(x={0.x},y={0.y})'.format(self)
-
def move(self, relx, rely):
self.x += relx
self.y += rely
@@ -46,6 +41,48 @@
else:
raise ValueError('Bad keyword arg: %r' % key)
+ # sequence interface
+
+ def __len__(self):
+ return 2
+
+ def __getitem__(self, key):
+ return (self.x, self.y)[key]
+
+ # point arithmetics
+
+ def __add__(self, other):
+ return Point(self.x + other[0], self.y + other[1])
+
+ def __sub__(self, other):
+ return Point(self.x - other[0], self.y - other[1])
+
+ def __eq__(self, other):
+ """Comparison operator.
+
+ Point can be compared to any sequence of at least two elements:
+
+ >>> p = Point(1, 2)
+ >>> p == Point(1, 2)
+ True
+ >>> p == (1, 2)
+ True
+ >>> p == (0, 0)
+ False
+ >>> p == None
+ False
+
+ """
+ try:
+ return self.x == other[0] and self.y == other[1]
+ except (TypeError, IndexError):
+ return False
+
+ # string representation
+
+ def __repr__(self):
+ return 'Point(x={0.x},y={0.y})'.format(self)
+
class Size:
--- a/tuikit/core/widget.py Mon Sep 01 08:55:40 2014 +0200
+++ b/tuikit/core/widget.py Wed Sep 03 08:53:44 2014 +0200
@@ -70,6 +70,10 @@
def resize(self, w, h):
self._size.update(w, h)
+ @property
+ def boundaries(self):
+ return Rect._make(self.pos, self._size)
+
## drawing, looks ##
def draw(self, buffer):
@@ -105,6 +109,18 @@
self._log.debug('keypress(keyname=%r, char=%r, mod=%r)',
keyname, char, mod)
+ def mousedown(self, button, pos):
+ self._log.debug('mousedown(btn=%r, pos=%r)',
+ button, pos)
+
+ def mouseup(self, button, pos):
+ self._log.debug('mouseup(btn=%r, pos=%r)',
+ button, pos)
+
+ def mousemove(self, button, pos, relpos):
+ self._log.debug('mousemove(btn=%r, pos=%r, relpos=%r)',
+ button, pos, relpos)
+
## timeouts ##
def add_timeout(self, delay, callback, *args):
--- a/tuikit/driver/curses.py Mon Sep 01 08:55:40 2014 +0200
+++ b/tuikit/driver/curses.py Wed Sep 03 08:53:44 2014 +0200
@@ -3,6 +3,7 @@
import logging
from tuikit.driver.driver import Driver
+from tuikit.core.coords import Point
class CursesDriver(Driver):
@@ -87,7 +88,7 @@
self.colorstack = [] # pushcolor/popcolor puts or gets attributes from this
self.inputqueue = []
self.mbtnstack = []
- self._mouse_last_pos = (None, None)
+ self._mouse_last_pos = None # Point
self._mouse_last_bstate = None
## initialization, finalization ##
@@ -279,15 +280,15 @@
except curses.error:
return []
+ pos = Point(x, y)
out = []
if bstate & curses.REPORT_MOUSE_POSITION:
- if self._mouse_last_pos != (x, y):
- if self._mouse_last_pos[0] is not None:
- relx = x - (self._mouse_last_pos[0] or 0)
- rely = y - (self._mouse_last_pos[1] or 0)
- out += [('mousemove', 0, x, y, relx, rely)]
- self._mouse_last_pos = (x, y)
+ if self._mouse_last_pos != pos:
+ if self._mouse_last_pos:
+ relpos = pos - self._mouse_last_pos
+ out += [('mousemove', 0, pos, relpos)]
+ self._mouse_last_pos = pos
# we are interested only in changes, not buttons already pressed before event
if self._mouse_last_bstate is not None:
@@ -299,21 +300,21 @@
self._mouse_last_bstate = bstate
if bstate & curses.BUTTON1_PRESSED:
- out += [('mousedown', 1, x, y)]
+ out += [('mousedown', 1, pos)]
if bstate & curses.BUTTON2_PRESSED:
- out += [('mousedown', 2, x, y)]
+ out += [('mousedown', 2, pos)]
if bstate & curses.BUTTON3_PRESSED:
- out += [('mousedown', 3, x, y)]
+ out += [('mousedown', 3, pos)]
if bstate & curses.BUTTON1_RELEASED:
- out += [('mouseup', 1, x, y)]
+ out += [('mouseup', 1, pos)]
if bstate & curses.BUTTON2_RELEASED:
- out += [('mouseup', 2, x, y)]
+ out += [('mouseup', 2, pos)]
if bstate & curses.BUTTON3_RELEASED:
- out += [('mouseup', 3, x, y)]
+ out += [('mouseup', 3, pos)]
# reset last pos when pressed/released
if len(out) > 0 and out[-1][0] in ('mousedown', 'mouseup'):
- self._mouse_last_pos = (None, None)
+ self._mouse_last_pos = None
return out
@@ -394,6 +395,7 @@
t = self._inputqueue_get_wait()
x = self._inputqueue_get_wait() - 0x21
y = self._inputqueue_get_wait() - 0x21
+ pos = Point(x, y)
out = []
@@ -402,25 +404,24 @@
btn = t - 0x1f
if not btn in self.mbtnstack:
self.mbtnstack.append(btn)
- self._mouse_last_pos = (None, None)
- out += [('mousedown', btn, x, y)]
+ self._mouse_last_pos = None
+ out += [('mousedown', btn, pos)]
else:
# mouse move
- if self._mouse_last_pos != (x, y):
- if self._mouse_last_pos[0] is not None:
- relx = x - self._mouse_last_pos[0]
- rely = y - self._mouse_last_pos[1]
- out += [('mousemove', btn, x, y, relx, rely)]
- self._mouse_last_pos = (x, y)
+ if self._mouse_last_pos != pos:
+ if self._mouse_last_pos:
+ relpos = pos - self._mouse_last_pos
+ out += [('mousemove', btn, pos, relpos)]
+ self._mouse_last_pos = pos
elif t == 0x23:
# button release
btn = self.mbtnstack.pop()
self._mouse_last_pos = (None, None)
- out += [('mouseup', btn, x, y)]
+ out += [('mouseup', btn, pos)]
elif t in (0x60, 0x61):
# wheel up, down
btn = 4 + t - 0x60
- out += [('mousewheel', btn, x, y)]
+ out += [('mousewheel', btn, pos)]
else:
raise Exception('Unknown mouse event: %x' % t)