glyph for return
[naja.git] / naja / widgets / base.py
1 from collections import defaultdict
2
3 import pygame
4 from pygame import locals as pgl
5
6 from naja.events import InvalidateTheWorld, SelectEvent
7
8
9 class Widget(object):
10     _is_selectable_func = None
11
12     def __init__(self, pos, size=None):
13         self.pos = pos
14         self.size = size or (0, 0)
15         self._prepared = False
16         self.callbacks = defaultdict(list)
17
18     @property
19     def rect(self):
20         return pygame.Rect(self.pos, self.size)
21
22     def render(self, surface):
23         '''Draw the widget onto surface'''
24         if not self._prepared:
25             self.prepare()
26             self._prepared = True
27         self.draw(surface)
28
29     def draw(self, surface):
30         '''The overrideable bit of widget drawing'''
31         raise NotImplemented()
32
33     def prepare(self):
34         '''Prepare the widget for drawing. This usually caches a surface.'''
35
36     def handle_event(self, ev):
37         '''Return True if the event has been handled'''
38         if InvalidateTheWorld.matches(ev):
39             # Invalidate has special handling. Widgets should never return
40             # True for for this event
41             self._prepared = False
42             return False
43         if SelectEvent.matches(ev) or ev.type == pgl.MOUSEBUTTONDOWN:
44             return self.callback('click')
45         return False
46
47     def add_callback(self, event, callback):
48         self.callbacks[event].append(callback)
49
50     def callback(self, event):
51         for callback in self.callbacks[event]:
52             callback(event)
53         return bool(self.callbacks[event])
54
55     def set_selectable_callback(self, func):
56         self._is_selectable_func = func
57
58     def is_selectable(self):
59         """Return False if this widget isn't selectable by SelectorWidget."""
60         if self._is_selectable_func is not None:
61             return self._is_selectable_func()
62         else:
63             return True
64
65
66 class Container(object):
67     def __init__(self, *widgets):
68         self.widgets = []
69         for widget in widgets:
70             self.add(widget)
71
72     def add(self, widget):
73         self.widgets.append(widget)
74
75     def render(self, surface):
76         for widget in self.widgets:
77             widget.render(surface)
78
79     def handle_event(self, ev):
80         if hasattr(ev, 'pos'):
81             for widget in self.widgets:
82                 if isinstance(widget, Container):
83                     if widget.handle_event(ev):
84                         return True
85                 elif widget.rect.collidepoint(ev.pos):
86                     if widget.handle_event(ev):
87                         return True
88         else:
89             for widget in self.widgets:
90                 if widget.handle_event(ev):
91                     return True
92         return False