+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):
- raise NotImplemented()
+ '''Prepare the widget for drawing. This usually caches a surface.'''
+
+ 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