tuikit/core/container.py
changeset 109 105b1affc3c2
parent 97 0c2e0c09ba5c
child 111 b055add74b18
equal deleted inserted replaced
97:0c2e0c09ba5c 109:105b1affc3c2
    12     """
    12     """
    13 
    13 
    14     def __init__(self, layout_class=FixedLayout):
    14     def __init__(self, layout_class=FixedLayout):
    15         Widget.__init__(self)
    15         Widget.__init__(self)
    16         #: List of child widgets.
    16         #: List of child widgets.
    17         self.children = []
    17         self._widgets = []
    18         self.focus_child = None
    18         #: Widget with keyboard focus
       
    19         self.focus_widget = None
       
    20         #: If True, tab cycles inside container
       
    21         self.trap_focus = False
    19         self.layout = layout_class()
    22         self.layout = layout_class()
    20 
    23 
    21     def add(self, widget):
    24     def add(self, widget):
    22         """Add widget into container."""
    25         """Add widget into container."""
    23         self.children.append(widget)
    26         self._widgets.append(widget)
    24         widget.parent = self
    27         widget.parent = self
    25         widget.window = self.window
    28         widget.window = self.window
    26         widget.set_theme(self.theme)
    29         widget.set_theme(self.theme)
    27         self.layout.add(widget)
    30         self.layout.add(widget)
    28         if self.focus_child is None:
    31         if self.focus_widget is None and widget.can_focus():
    29             self.focus_child = widget
    32             self.focus_widget = widget
    30 
    33 
    31     def resize(self, w, h):
    34     def resize(self, w, h):
    32         Widget.resize(self, w, h)
    35         Widget.resize(self, w, h)
    33         self.layout.resize()
    36         self.layout.resize()
    34 
    37 
    35     def draw(self, buffer):
    38     def draw(self, buffer):
    36         """Draw child widgets."""
    39         """Draw child widgets."""
    37         Widget.draw(self, buffer)
    40         Widget.draw(self, buffer)
    38         for child in self.children:
    41         for child in self._widgets:
    39             with buffer.moved_origin(child.x, child.y):
    42             with buffer.moved_origin(child.x, child.y):
    40                 with buffer.clip(buffer.origin.x, buffer.origin.y,
    43                 with buffer.clip(buffer.origin.x, buffer.origin.y,
    41                                  child.width, child.height):
    44                                  child.width, child.height):
    42                     child.draw(buffer)
    45                     child.draw(buffer)
    43 
    46 
    44     def set_theme(self, theme):
    47     def set_theme(self, theme):
    45         Widget.set_theme(self, theme)
    48         Widget.set_theme(self, theme)
    46         for child in self.children:
    49         for child in self._widgets:
    47             child.set_theme(theme)
    50             child.set_theme(theme)
    48 
    51 
    49     @property
    52     @property
    50     def cursor(self):
    53     def cursor(self):
    51         if self.focus_child:
    54         if self.focus_widget:
    52             cursor = self.focus_child.cursor
    55             cursor = self.focus_widget.cursor
    53             if cursor is not None:
    56             if cursor is not None:
    54                 return cursor.moved(*self.focus_child.pos)
    57                 return cursor.moved(*self.focus_widget.pos)
    55         else:
    58         else:
    56             if self._cursor is not None:
    59             if self._cursor is not None:
    57                 return Point(self._cursor)
    60                 return Point(self._cursor)
    58 
    61 
    59     ## input events ##
    62     ## input events ##
    60 
    63 
    61     def keypress(self, keyname, char, mod=0):
    64     def keypress(self, keyname, char, mod):
    62         if self.focus_child:
    65         # First, handle the keypress event to focused child widget
    63             self.focus_child.keypress(keyname, char, mod)
    66         if self.focus_widget is not None:
       
    67             if self.focus_widget.keypress(keyname, char, mod):
       
    68                 return True
       
    69         # Next, handle default key behaviour by Container
       
    70         if keyname == 'tab':
       
    71             return self.focus_next(-1 if 'shift' in mod else 1)
       
    72         # Finally, handle default keys by Widget
       
    73         # and send keypress signal
       
    74         if Widget.keypress(self, keyname, char, mod):
       
    75             return True
       
    76 
       
    77     ## focus ##
       
    78 
       
    79     def focus_next(self, step=1):
       
    80         """Focus next child.
       
    81 
       
    82         Sets focus to next child, if there is one
       
    83         which can be focused. Cycles from last child
       
    84         to first when needed. Return value depends on
       
    85         this cycling:
       
    86 
       
    87          * False means there wasn't any child to focus
       
    88            before end of list. Focus was either not changed
       
    89            or first child was focused.
       
    90 
       
    91          * True when focus is set to next child in normal
       
    92            way or when self.trap_focus is set.
       
    93 
       
    94         Return value is supposed to be returned from keypress
       
    95         event - in that case, True stops event propagation.
       
    96 
       
    97         """
       
    98         if self.focus_widget is None:
       
    99             idx_current = 0
       
   100         else:
       
   101             idx_current = self._widgets.index(self.focus_widget)
       
   102         idx_new = idx_current
       
   103         cycled = False
       
   104         while True:
       
   105             idx_new += step
       
   106             if idx_new >= len(self._widgets):
       
   107                 idx_new = 0
       
   108                 cycled = True
       
   109             if idx_new < 0:  # for focus_previous
       
   110                 idx_new = len(self._widgets) - 1
       
   111                 cycled = True
       
   112             if idx_current == idx_new:
       
   113                 return False
       
   114             if self._widgets[idx_new].can_focus():
       
   115                 self.focus_widget = self._widgets[idx_new]
       
   116                 return self.trap_focus or not cycled
       
   117 
       
   118     def focus_previous(self):
       
   119         """Focus previous child."""
       
   120         self.focus_next(-1)