Refactor events.
from tuikit.core.widget import Widget
from tuikit.core.coords import Point
from tuikit.layouts.fixed import FixedLayout
class Container(Widget):
"""Container widget.
Can contain other widgets to create hierarchical structure.
"""
def __init__(self, layout_class=FixedLayout):
Widget.__init__(self)
#: List of child widgets.
self._widgets = []
#: Widget with keyboard focus
self.focus_widget = None
#: If True, tab cycles inside container
self.trap_focus = False
self.layout = layout_class()
def add(self, widget):
"""Add widget into container."""
self._widgets.append(widget)
widget.parent = self
widget.window = self.window
widget.set_theme(self.theme)
self.layout.add(widget)
if self.focus_widget is None and widget.can_focus():
self.focus_widget = widget
def resize(self, w, h):
Widget.resize(self, w, h)
self.layout.resize()
def draw(self, buffer):
"""Draw child widgets."""
Widget.draw(self, buffer)
for child in self._widgets:
with buffer.moved_origin(child.x, child.y):
with buffer.clip(buffer.origin.x, buffer.origin.y,
child.width, child.height):
child.draw(buffer)
def set_theme(self, theme):
Widget.set_theme(self, theme)
for child in self._widgets:
child.set_theme(theme)
@property
def cursor(self):
if self.focus_widget:
cursor = self.focus_widget.cursor
if cursor is not None:
return cursor.moved(*self.focus_widget.pos)
else:
if self._cursor is not None:
return Point(self._cursor)
## input events ##
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_event(ev):
return True
# Next, handle default key behaviour by Container
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_event(self, ev):
return True
## focus ##
def focus_next(self, step=1):
"""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.
"""
if self.focus_widget is None:
idx_current = 0
else:
idx_current = self._widgets.index(self.focus_widget)
idx_new = idx_current
cycled = False
while True:
idx_new += step
if idx_new >= len(self._widgets):
idx_new = 0
cycled = True
if idx_new < 0: # for focus_previous
idx_new = len(self._widgets) - 1
cycled = True
if idx_current == idx_new:
return False
if self._widgets[idx_new].can_focus():
self.focus_widget = self._widgets[idx_new]
return self.trap_focus or not cycled
def focus_previous(self):
"""Focus previous child."""
self.focus_next(-1)