Merge branch 'master' of git://ctpug.org.za/naja
[naja.git] / naja / widgets / base.py
index b922b62280a595d61b1e422685add1b87ba9ad6a..815d1d3a3f1cf23fedcc776ff980b5d4b727b051 100644 (file)
@@ -1,23 +1,92 @@
+from collections import defaultdict
+
 import pygame
+from pygame import locals as pgl
+
+from naja.events import InvalidateTheWorld, SelectEvent
 
 
 class Widget(object):
+    _is_selectable_func = None
+
     def __init__(self, pos, size=None):
         self.pos = pos
         self.size = size or (0, 0)
         self._prepared = False
+        self.callbacks = defaultdict(list)
 
     @property
     def rect(self):
         return pygame.Rect(self.pos, self.size)
 
+    def render(self, surface):
+        '''Draw the widget onto surface'''
+        if not self._prepared:
+            self.prepare()
+            self._prepared = True
+        self.draw(surface)
+
     def draw(self, surface):
+        '''The overrideable bit of widget drawing'''
         raise NotImplemented()
 
     def prepare(self):
-        if not self._prepared:
-            self._prepare()
-            self._prepared = True
+        '''Prepare the widget for drawing. This usually caches a surface.'''
 
-    def _prepare(self):
-        raise NotImplemented()
+    def handle_event(self, ev):
+        '''Return True if the event has been handled'''
+        if InvalidateTheWorld.matches(ev):
+            # Invalidate has special handling. Widgets should never return
+            # True for for this event
+            self._prepared = False
+            return False
+        if SelectEvent.matches(ev) or ev.type == pgl.MOUSEBUTTONDOWN:
+            return self.callback('click')
+        return False
+
+    def add_callback(self, event, callback):
+        self.callbacks[event].append(callback)
+
+    def callback(self, event):
+        for callback in self.callbacks[event]:
+            callback(event)
+        return bool(self.callbacks[event])
+
+    def set_selectable_callback(self, func):
+        self._is_selectable_func = func
+
+    def is_selectable(self):
+        """Return False if this widget isn't selectable by SelectorWidget."""
+        if self._is_selectable_func is not None:
+            return self._is_selectable_func()
+        else:
+            return True
+
+
+class Container(object):
+    def __init__(self, *widgets):
+        self.widgets = []
+        for widget in widgets:
+            self.add(widget)
+
+    def add(self, widget):
+        self.widgets.append(widget)
+
+    def render(self, surface):
+        for widget in self.widgets:
+            widget.render(surface)
+
+    def handle_event(self, ev):
+        if hasattr(ev, 'pos'):
+            for widget in self.widgets:
+                if isinstance(widget, Container):
+                    if widget.handle_event(ev):
+                        return True
+                elif widget.rect.collidepoint(ev.pos):
+                    if widget.handle_event(ev):
+                        return True
+        else:
+            for widget in self.widgets:
+                if widget.handle_event(ev):
+                    return True
+        return False