Return True when we called a callback
[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     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 SelectEvent.matches(ev) or ev.type == pgl.MOUSEBUTTONDOWN:
42             return 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         return bool(self.callbacks[event])
52
53
54 class Container(object):
55     def __init__(self, *widgets):
56         self.widgets = []
57         for widget in widgets:
58             self.add(widget)
59
60     def add(self, widget):
61         self.widgets.append(widget)
62
63     def render(self, surface):
64         for widget in self.widgets:
65             widget.render(surface)
66
67     def handle_event(self, ev):
68         if hasattr(ev, 'pos'):
69             for widget in self.widgets:
70                 if isinstance(widget, Container):
71                     if widget.handle_event(ev):
72                         return True
73                 elif widget.rect.collidepoint(ev.pos):
74                     if widget.handle_event(ev):
75                         return True
76         else:
77             for widget in self.widgets:
78                 if widget.handle_event(ev):
79                     return True
80         return False