changeset 77:2aa652b92449

Focus
author Stefano Rivera <stefano@rivera.za.net>
date Sun, 11 Sep 2011 18:30:19 +0200
parents a2694a024c83
children b1019923cb12
files mamba/engine.py mamba/widgets/base.py
diffstat 2 files changed, 58 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/mamba/engine.py	Sun Sep 11 18:26:55 2011 +0200
+++ b/mamba/engine.py	Sun Sep 11 18:30:19 2011 +0200
@@ -42,7 +42,7 @@
 
     def __init__(self):
         self.surface = None
-        self.container = Container(pygame.Rect((0, 0), SCREEN))
+        self.container = Container(pygame.Rect((0, 0), SCREEN), root=True)
 
     def on_enter(self):
         """Called when this becomes the current habitat."""
--- a/mamba/widgets/base.py	Sun Sep 11 18:26:55 2011 +0200
+++ b/mamba/widgets/base.py	Sun Sep 11 18:30:19 2011 +0200
@@ -1,6 +1,7 @@
 import collections
 
 import pygame
+from pygame.constants import K_UP, K_DOWN
 from pygame.locals import MOUSEMOTION, MOUSEBUTTONUP, MOUSEBUTTONDOWN, KEYDOWN
 
 
@@ -11,6 +12,7 @@
             rect = pygame.Rect(rect, (0, 0))
         self.rect = rect
         self.focussable = False
+        self.focussed = False
         self.callbacks = collections.defaultdict(list)
 
     def add_callback(self, eventtype, callback, *args):
@@ -18,7 +20,9 @@
 
     def event(self, ev):
         for callback, args in self.callbacks[ev.type]:
-            callback(ev, self, *args)
+            if callback(ev, self, *args):
+                return True
+        return False
 
     def draw(self, surface):
         "Override me"
@@ -27,23 +31,71 @@
 
 class Container(Widget):
 
-    def __init__(self, rect):
+    def __init__(self, rect, root=False):
         super(Container, self).__init__(rect)
         self.children = []
+        self.root = root
+        self.focussed = root
+        self.focussable = True
+        self.focussed_child = None
 
     def event(self, ev):
+        """Push an event down through the tree, and fire our own event as a
+        last resort
+        """
         if ev.type in (MOUSEMOTION, MOUSEBUTTONUP, MOUSEBUTTONDOWN):
             for child in self.children:
                 if child.rect.collidepoint(ev.pos):
-                    child.event(ev)
+                    if child.event(ev):
+                        return True
         if ev.type == KEYDOWN:
             for child in self.children:
-                child.event(ev)
-        super(Container, self).event(ev)
+                if child.focussed:
+                    if child.event(ev):
+                        return True
+        if super(Container, self).event(ev):
+            return True
+        if self.root and ev.type == KEYDOWN and ev.key in (K_UP, K_DOWN):
+            self.adjust_focus(1 if ev.key == K_DOWN else -1)
 
     def add(self, widget):
+        widget.parent = self
         self.children.append(widget)
 
+    def adjust_focus(self, direction):
+        """Try and adjust focus in direction (integer)
+        """
+        if self.focussed_child is not None:
+            child = self.children[self.focussed_child]
+            if isinstance(child, Container):
+                if child.adjust_focus(direction):
+                    return True
+            child.focussed = False
+
+        current = self.focussed_child
+        if current is None:
+            current = -1 if direction > 0 else len(self.children)
+        if direction > 0:
+            possibles = list(enumerate(self.children))[current + 1:]
+        else:
+            possibles = list(enumerate(self.children))[:current]
+            possibles.reverse()
+        for i, child in possibles:
+            if child.focussable:
+                child.focussed = True
+                if isinstance(child, Container):
+                    if child.adjust_focus(direction):
+                        self.focussed_child = i
+                        return True
+                    child.focussed = False
+                    continue
+                else:
+                    self.focussed_child = i
+                    child.focussed = True
+                    return True
+        else:
+            return False
+
     def draw(self, surface):
         for child in self.children:
             child.draw(surface)