tuikit/core/container.py
author Radek Brich <radek.brich@devl.cz>
Wed, 03 Sep 2014 19:14:43 +0200
changeset 111 b055add74b18
parent 109 105b1affc3c2
child 112 ce2e67e7bbb8
permissions -rw-r--r--
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)