Propagate "quit" event, do not just terminate application. Resize: flag widgets to be resized, do resizes only once before draw. Draw: flag widgets to be redrawn, do not draw everything on any event.
--- a/demo_anchorlayout.py Sat Feb 02 12:54:27 2013 +0100
+++ b/demo_anchorlayout.py Sun Feb 03 16:38:41 2013 +0100
@@ -51,7 +51,7 @@
align = self.win.get_hint(align_type)
align.select_next()
ev.originator.label = '%s: %s' % (align_type, align.selected)
- self.top.emit('resize')
+ self.top.need_resize()
return True
def on_label_margin_draw(self, ev):
--- a/demo_input.py Sat Feb 02 12:54:27 2013 +0100
+++ b/demo_input.py Sun Feb 03 16:38:41 2013 +0100
@@ -19,12 +19,12 @@
scroll.add(self.editbox)
self.top.add(scroll, halign='fill', valign='fill')
- self.editbox.add_handler('keypress', self.on_any_input)
- self.editbox.add_handler('mousedown', self.on_any_input)
- self.editbox.add_handler('mouseup', self.on_any_input)
- self.editbox.add_handler('mousewheel', self.on_any_input)
- self.editbox.add_handler('mousemove', self.on_any_input)
- self.editbox.add_handler('mousehover', self.on_any_input)
+ scroll.add_handler('keypress', self.on_any_input)
+ scroll.add_handler('mousedown', self.on_any_input)
+ scroll.add_handler('mouseup', self.on_any_input)
+ scroll.add_handler('mousewheel', self.on_any_input)
+ scroll.add_handler('mousemove', self.on_any_input)
+ scroll.add_handler('mousehover', self.on_any_input)
def on_any_input(self, ev):
if ev.event_name == 'keypress' and ev.keyname == 'escape':
--- a/demo_menu.py Sat Feb 02 12:54:27 2013 +0100
+++ b/demo_menu.py Sun Feb 03 16:38:41 2013 +0100
@@ -11,6 +11,7 @@
def __init__(self):
Application.__init__(self)
self.top.add_handler('keypress', self.on_top_keypress, last=True)
+ self.top.add_handler('quit', lambda ev: self.terminate())
helpwin = Window()
helpwin.title = 'About'
--- a/tuikit/application.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/application.py Sun Feb 03 16:38:41 2013 +0100
@@ -64,15 +64,15 @@
self._load_conf('tuikit.conf')
self._setup_logging()
+ #: Driver class instance (render + input), e.g. DriverCurses.
+ self.driver = self.get_driver_instance(self.cfg['driver'])
+
# Top widget
self._top = None
self._timer = Timer()
self.top = top_layout()
- self.quit = False
-
- #: Driver class instance (render + input), e.g. DriverCurses.
- self.driver = self.get_driver_instance(self.cfg['driver'])
+ self._quit = False
def _load_conf(self, file_name):
try:
@@ -111,16 +111,16 @@
def terminate(self):
'''Terminate application.'''
- self.quit = True
+ self._quit = True
def main_loop(self):
'''The main loop.'''
self.startup()
self._top._size = self.driver.size # link top widget size to screen size
- self._top.emit('resize')
timer = self._timer
- while True:
+ while not self._quit:
+ self._top.complete_requests()
self._top.draw(self.driver, 0, 0)
self.driver.commit()
@@ -129,13 +129,7 @@
timer.process_timeouts()
for event in events:
- if event[0] == 'quit':
- self.quit = True
- else:
- self._top.emit(event[0], *event[1:])
-
- if self.quit:
- break
+ self._top.emit(event[0], *event[1:])
self.log.info('=== quit ===')
def startup(self):
@@ -153,7 +147,7 @@
drv.defcolor('window:normal', 'lightgray on blue')
drv.defcolor('window:controls', 'white on blue, bold')
drv.defcolor('window:controls-active', 'cyan on blue, bold')
- drv.defcolor('button', 'black on white')
+ drv.defcolor('button', 'black on lightgray')
drv.defcolor('button-active', 'black on cyan')
drv.defcolor('menu', 'black on cyan')
drv.defcolor('menu-active', 'white on cyan, bold')
--- a/tuikit/checkbox.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/checkbox.py Sun Feb 03 16:38:41 2013 +0100
@@ -25,4 +25,5 @@
else:
self.checked = True
self.prefix = '[x] '
+ self.redraw()
--- a/tuikit/container.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/container.py Sun Feb 03 16:38:41 2013 +0100
@@ -26,8 +26,6 @@
#: Child widgets are placed within borders.
self.borders = Borders()
- self._layout = None
-
self.widthrequest = (None, None)
self.heightrequest = (None, None)
@@ -60,17 +58,6 @@
self.children.remove(child)
self.children.append(child)
- @property
- def layout(self):
- return self._layout
-
- @layout.setter
- def layout(self, value):
- """Layout manager for placing child widgets."""
- self._layout = value
- self._layout.container = self
-
-
def move_child(self, child, x, y):
pass
@@ -131,6 +118,11 @@
if self.focuschild:
self.focuschild.emit('unfocus', ev)
+ def redraw(self):
+ Widget.redraw(self)
+ for child in self.children:
+ child.redraw()
+
def draw(self, driver, x, y):
"""Draw the container and its children.
@@ -251,3 +243,8 @@
self.mousechild = child
return True
+ def complete_requests(self):
+ Widget.complete_requests(self)
+ for child in self.children:
+ child.complete_requests()
+
--- a/tuikit/driver.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/driver.py Sun Feb 03 16:38:41 2013 +0100
@@ -41,6 +41,11 @@
for i in range(h):
self.putch(x, y+i, c)
+ def fill_clip(self, c=' '):
+ """Fill current clip region."""
+ rect = self.clipstack.top()
+ self.fill(rect.x, rect.y, rect.w, rect.h, c)
+
def fill(self, x, y, w, h, c=' '):
'''Fill rectangular area.'''
for i in range(h):
--- a/tuikit/driver_curses.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/driver_curses.py Sun Feb 03 16:38:41 2013 +0100
@@ -195,9 +195,10 @@
## cursor ##
def showcursor(self, x, y):
- if not self.clipstack.test(x, y):
- return
- self.cursor = (y, x)
+ if self.clipstack.test(x, y):
+ self.cursor = (y, x)
+ else:
+ self.cursor = None
def hidecursor(self):
curses.curs_set(False)
--- a/tuikit/editbox.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/editbox.py Sun Feb 03 16:38:41 2013 +0100
@@ -49,6 +49,7 @@
def on_draw(self, ev):
ev.driver.pushcolor('normal')
+ ev.driver.fill_clip()
end_y = min(len(self.lines), ev.exposed.y + ev.exposed.h)
for j in range(ev.exposed.y, end_y):
line = self.lines[j]
@@ -83,6 +84,7 @@
y = ev.wy
x = min(ev.wx, len(self.lines[y]))
self._spot.update(x=x, y=y)
+ self.redraw()
def on_mousewheel(self, ev):
if ev.button == 4:
--- a/tuikit/layout.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/layout.py Sun Feb 03 16:38:41 2013 +0100
@@ -21,8 +21,11 @@
widget.add_handler('show', self._on_child_size_change)
widget.add_handler('hide', self._on_child_size_change)
+ def on_resize(self, ev):
+ self.redraw()
+
def _on_child_size_change(self, ev):
- self.emit('resize')
+ self.need_resize()
def _get_children(self):
return [child for child in self.children
@@ -225,6 +228,7 @@
for child in self.children:
x, y = child.hint_value('position')
child._pos.update(x=x+ox, y=y+oy)
+ self.redraw()
class GridLayout(Layout):
--- a/tuikit/scrollview.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/scrollview.py Sun Feb 03 16:38:41 2013 +0100
@@ -15,6 +15,9 @@
def add(self, widget, **kwargs):
self._inner.add(widget, **kwargs)
+ def on_draw(self, ev):
+ ev.driver.fill_clip()
+
class Scrolling:
def __init__(self):
@@ -94,7 +97,7 @@
self.vscroll.hide()
else:
self.vscroll.show()
- self._inner.need_resize()
+ # self._inner.need_resize()
class ScrollView(OffsetView, Scrolling):
--- a/tuikit/tableview.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/tableview.py Sun Feb 03 16:38:41 2013 +0100
@@ -161,6 +161,7 @@
def on_draw(self, ev):
ev.driver.pushcolor('normal')
+ ev.driver.fill_clip()
self.rowcount = self.model.getcount()
numrows = min(self.rowcount - self.offset.y, self.height - self.headsize)
rows = self.model.getrows(self.offset.y, self.offset.y + numrows)
@@ -185,8 +186,8 @@
'pagedown': self.move_pagedown}
if ev.keyname in key_map:
key_map[ev.keyname]()
+ self.redraw()
return True
- self.redraw()
def set_yofs(self, yofs):
if yofs > self.rowcount - (self.height - self.headsize):
--- a/tuikit/treeview.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/treeview.py Sun Feb 03 16:38:41 2013 +0100
@@ -251,6 +251,7 @@
def on_draw(self, ev):
ev.driver.pushcolor('normal')
+ ev.driver.fill_clip()
lines = 0 # bit array, bit 0 - draw vertical line on first column, etc.
y = ev.y
@@ -292,8 +293,8 @@
'right': self.move_right}
if ev.keyname in key_map:
key_map[ev.keyname]()
+ self.redraw()
return True
- self.redraw()
def prev_node(self, node):
# previous sibling
--- a/tuikit/widget.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/widget.py Sun Feb 03 16:38:41 2013 +0100
@@ -28,7 +28,6 @@
self._pos = Coords()
#: Actual size. Modified only by layout manager.
self._size = Size(10, 10)
- self._size.add_handler('change', lambda ev: self.emit('resize'))
#: Size of visible part of widget. Used in OffsetLayout. Modified only by layout manager.
self._view_size = Size(10, 10)
#: Default (natural) size of Widget.
@@ -73,6 +72,7 @@
self.add_events(
'resize', Event,
'draw', DrawEvent,
+ 'quit', Event,
'keypress', KeyboardEvent,
'mousedown', MouseEvent,
'mouseup', MouseEvent,
@@ -111,6 +111,14 @@
def height(self):
return self._size.h
+ @property
+ def view_width(self):
+ return self._view_size.w
+
+ @property
+ def view_height(self):
+ return self._view_size.h
+
def resize(self, w=None, h=None):
"""Set size request.
@@ -120,14 +128,6 @@
self._sizereq.update(w, h)
@property
- def view_width(self):
- return self._view_size.w
-
- @property
- def view_height(self):
- return self._view_size.h
-
- @property
def sizereq(self):
"""Size request.
@@ -144,6 +144,16 @@
logging.getLogger('tuikit').info('xy')
self._size.update(self._sizereq)
+ def need_resize(self):
+ self._need_resize = True
+
+ def on_resize(self, ev):
+ self._need_resize = False
+
+ def complete_requests(self):
+ if self._need_resize:
+ self.emit('resize')
+
### misc
@property
@@ -170,6 +180,8 @@
"""Real setter for top. Allows override."""
self._top = value
+ ### hints
+
def reset_hints(self):
"""Reset all hints to their initial value.
@@ -205,13 +217,8 @@
### events
- def need_resize(self):
- self._need_resize = True
-
- def redraw(self, parent=False):
+ def redraw(self):
self._need_draw = True
- if parent and self.parent:
- self.parent._redraw = True
def draw(self, driver, x, y):
"""Draw the widget.
@@ -220,7 +227,7 @@
use on_draw method instead.
"""
- if self.hidden:
+ if self.hidden or not self._need_draw:
return True
driver.clipstack.push(x, y, self.width, self.height)
@@ -233,6 +240,7 @@
driver.showcursor(x + cx, y + cy)
else:
driver.hidecursor()
+ self._need_draw = False
def on_mousedown(self, ev):
self.grab_focus()
@@ -240,11 +248,9 @@
### focus
-
def can_focus(self):
return not self.hidden and self.allow_focus
-
def has_focus(self):
if self.parent is None:
return True
@@ -271,7 +277,9 @@
self.parent.focuschild = self
if oldfocuschild:
oldfocuschild.emit('unfocus', new=self)
+ oldfocuschild.redraw()
self.emit('focus', old=oldfocuschild)
+ self.redraw()
def grab_focus(self):
"""Focus the widget and its parents."""
@@ -314,6 +322,8 @@
self._hidden = True
self.emit('hide')
self.redraw()
+ if self.floater and self.top:
+ self.top.redraw()
def show(self):
'''Show widget. Convenience method.'''
--- a/tuikit/window.py Sat Feb 02 12:54:27 2013 +0100
+++ b/tuikit/window.py Sun Feb 03 16:38:41 2013 +0100
@@ -40,6 +40,7 @@
self.colorprefix = 'window:'
self._inner = inner_layout()
+ self._inner.add_handler('draw', self._on_inner_draw)
Container.add(self, self._inner, halign='fill', valign='fill', margin=Borders(1,1,1,1))
def add(self, widget, **kwargs):
@@ -55,7 +56,6 @@
self._closebutton = value
self.closebtn.hidden = not value
-
def on_draw(self, ev):
ev.driver.pushcolor('normal')
ev.driver.frame(ev.x, ev.y, self.width, self.height)
@@ -84,23 +84,30 @@
ev.driver.fill(ev.x+1, ev.y+1, self.width-2, self.height-2)
ev.driver.popcolor()
+ def _on_inner_draw(self, ev):
+ ev.driver.pushcolor('normal')
+ ev.driver.fill_clip()
+ ev.driver.popcolor()
+
+ def on_mousedown(self, ev):
+ self.bring_up()
def after_mousedown(self, ev):
if self.resizable and ev.wx >= self.width - 1 and ev.wy >= self.height - 1:
self._resizing = True
elif self.movable:
self._moving = True
- self.redraw(True)
+ self.parent.redraw()
def after_mouseup(self, ev):
self._resize_or_move(ev)
self._resizing = False
self._moving = False
- self.redraw(True)
+ self.parent.redraw()
def after_mousemove(self, ev):
self._resize_or_move(ev)
- self.redraw(True)
+ self.parent.redraw()
def _resize_or_move(self, ev):
if self._resizing: