81f11b649df9734371017f34891fa3ec6b360505
[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
7
8
9 class Widget(object):
10     def __init__(self, pos, size=None):
11         self.pos = pos
12         self.size = size or (0, 0)
13         self._prepared = False
14         self.callbacks = defaultdict(list)
15
16     @property
17     def rect(self):
18         return pygame.Rect(self.pos, self.size)
19
20     def render(self, surface):
21         '''Draw the widget onto surface'''
22         if not self._prepared:
23             self.prepare()
24             self._prepared = True
25         self.draw(surface)
26
27     def draw(self, surface):
28         '''The overrideable bit of widget drawing'''
29         raise NotImplemented()
30
31     def prepare(self):
32         '''Prepare the widget for drawing. This usually caches a surface.'''
33
34     def handle_event(self, ev):
35         '''Return True if the event has been handled'''
36         if InvalidateTheWorld.matches(ev):
37             # Invalidate has special handling. Widgets should never return
38             # True for for this event
39             self._prepared = False
40             return False
41         if ev.type == pgl.MOUSEBUTTONDOWN:
42             self.callback('click')
43         return False
44
45     def add_callback(self, event, callback):
46         self.callbacks[event].append(callback)
47
48     def callback(self, event):
49         for callback in self.callbacks[event]:
50             callback(event)
51
52
53 class Container(object):
54     def __init__(self, *widgets):
55         self.widgets = []
56         for widget in widgets:
57             self.add(widget)
58
59     def add(self, widget):
60         self.widgets.append(widget)
61
62     def render(self, surface):
63         for widget in self.widgets:
64             widget.render(surface)
65
66     def handle_event(self, ev):
67         if hasattr(ev, 'pos'):
68             for widget in self.widgets:
69                 if isinstance(widget, Container):
70                     if widget.handle_event(ev):
71                         return True
72                 elif widget.rect.collidepoint(ev.pos):
73                     if widget.handle_event(ev):
74                         return True
75         else:
76             for widget in self.widgets:
77                 if widget.handle_event(ev):
78                     return True
79         return False