Minor updates. Replace super() with direct class reference. Add demo_colors.
# -*- coding: utf-8 -*-
from tuikit.widget import Widget
from tuikit.common import Borders, Coords
class Container(Widget):
'''Container widget. Base for any widget which can contain other widgets.'''
def __init__(self, width = 10, height = 10):
'''Create container of requested size.'''
Widget.__init__(self, width, height)
#: List of child widgets.
self.children = []
#: Offset for child widgets
self.offset = Coords()
self.focuschild = None
self.mousechild = None
self.allow_focus = True
#: Width of borders (left, top, right, bottom).
#: Child widgets are placed within borders.
self.borders = Borders()
self._layout = None
self.widthrequest = (None, None)
self.heightrequest = (None, None)
self.colorprefix = None
self.trap_focus = False # if True, tab cycles inside container
def add(self, widget, **kwargs):
'''Add widget into this container.'''
self.children.append(widget)
widget.parent = self
widget.top = self.top
widget.hints.update(kwargs)
if self.focuschild is None and widget.can_focus():
self.focuschild = widget
@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 _set_top(self, value):
self._top = value
for child in self.children:
child.top = value
def focus_next(self):
"""Focus next child.
Sets focus to next child, if there is one
which can be focused. Cycles from last child
to first when needed. Return value depends on
this cycling:
* False means there wasn't any child to focus
before end of list. Focus was either not changed
or first child was focused.
* True when focus is set to next child in normal
way or when self.trap_focus is set.
Return value is supposed to be returned from keypress
event - in that case, True stops event propagation.
"""
idx_current = self.children.index(self.focuschild)
idx_new = idx_current
cycled = False
while True:
idx_new += 1
if idx_new >= len(self.children):
idx_new = 0
cycled = True
if idx_current == idx_new:
return False
if self.children[idx_new].can_focus():
self.children[idx_new].set_focus()
return self.trap_focus or not cycled
def draw(self, driver, x, y):
"""Draw the container and its children.
This method should not be overriden by subclasses,
use on_draw instead.
"""
if self.hidden:
return True
driver.clipstack.push(x, y, self.width, self.height)
if self.colorprefix:
driver.pushcolorprefix(self.colorprefix)
Widget.draw(self, driver, x, y)
for child in [ch for ch in self.children if not ch.allow_layout]:
child.draw(driver, x + child.x, y + child.y)
l, t, r, b = self.borders
driver.clipstack.push(x+l, y+t, self.width-l-r, self.height-t-b)
for child in [ch for ch in self.children if ch.allow_layout]:
child.draw(driver,
x + self.offset.x + child.x,
y + self.offset.y + child.y)
driver.clipstack.pop()
if self.colorprefix:
driver.popcolorprefix()
driver.clipstack.pop()
def on_resize(self, ev):
for child in self.children:
child.emit('resize')
def on_keypress(self, ev):
if self.focuschild is not None:
handled = self.focuschild.emit('keypress', ev)
if handled:
return True
if ev.keyname == 'tab':
return self.focus_next()
def on_mousedown(self, ev):
handled = False
for child in reversed(self.children):
if child.enclose(ev.wx, ev.wy):
childev = ev.childevent(child)
child.emit('mousedown', childev)
self.mousechild = child
handled = True
break
return handled
def on_mouseup(self, ev):
if self.mousechild:
childev = ev.childevent(self.mousechild)
self.mousechild.emit('mouseup', childev)
self.mousechild = None
return True
def on_mousemove(self, ev):
if self.mousechild:
childev = ev.childevent(self.mousechild)
self.mousechild.emit('mousemove', childev)
return True
def on_mousewheel(self, ev):
handled = False
for child in reversed(self.children):
if child.enclose(ev.wx, ev.wy):
childev = ev.childevent(child)
child.emit('mousewheel', childev)
handled = True
break
return handled