--- a/tuikit/core/container.py Fri Mar 28 19:58:59 2014 +0100
+++ b/tuikit/core/container.py Wed Sep 03 19:08:21 2014 +0200
@@ -14,19 +14,22 @@
def __init__(self, layout_class=FixedLayout):
Widget.__init__(self)
#: List of child widgets.
- self.children = []
- self.focus_child = None
+ 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.children.append(widget)
+ self._widgets.append(widget)
widget.parent = self
widget.window = self.window
widget.set_theme(self.theme)
self.layout.add(widget)
- if self.focus_child is None:
- self.focus_child = 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)
@@ -35,7 +38,7 @@
def draw(self, buffer):
"""Draw child widgets."""
Widget.draw(self, buffer)
- for child in self.children:
+ 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):
@@ -43,21 +46,75 @@
def set_theme(self, theme):
Widget.set_theme(self, theme)
- for child in self.children:
+ for child in self._widgets:
child.set_theme(theme)
@property
def cursor(self):
- if self.focus_child:
- cursor = self.focus_child.cursor
+ if self.focus_widget:
+ cursor = self.focus_widget.cursor
if cursor is not None:
- return cursor.moved(*self.focus_child.pos)
+ return cursor.moved(*self.focus_widget.pos)
else:
if self._cursor is not None:
return Point(self._cursor)
## input events ##
- def keypress(self, keyname, char, mod=0):
- if self.focus_child:
- self.focus_child.keypress(keyname, char, mod)
+ def keypress(self, keyname, char, mod):
+ # First, handle the keypress event to focused child widget
+ if self.focus_widget is not None:
+ if self.focus_widget.keypress(keyname, char, mod):
+ return True
+ # Next, handle default key behaviour by Container
+ if keyname == 'tab':
+ return self.focus_next(-1 if 'shift' in mod else 1)
+ # Finally, handle default keys by Widget
+ # and send keypress signal
+ if Widget.keypress(self, keyname, char, mod):
+ 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)