Mercurial > mamba
annotate mamba/widgets/base.py @ 106:d1152f2a0e13
Mouse affects focus
author | Stefano Rivera <stefano@rivera.za.net> |
---|---|
date | Sun, 11 Sep 2011 20:05:35 +0200 |
parents | 2b6626f417f2 |
children | dc0b0be7e2f6 |
rev | line source |
---|---|
55
671d027f1b71
Callbacks for events in widgets
Stefano Rivera <stefano@rivera.za.net>
parents:
43
diff
changeset
|
1 import collections |
671d027f1b71
Callbacks for events in widgets
Stefano Rivera <stefano@rivera.za.net>
parents:
43
diff
changeset
|
2 |
23 | 3 import pygame |
77 | 4 from pygame.constants import K_UP, K_DOWN |
58 | 5 from pygame.locals import MOUSEMOTION, MOUSEBUTTONUP, MOUSEBUTTONDOWN, KEYDOWN |
23 | 6 |
7 | |
8 class Widget(object): | |
9 | |
10 def __init__(self, rect): | |
38 | 11 if not isinstance(rect, pygame.Rect): |
41
3f44c30a1c39
Correct Text placement
Stefano Rivera <stefano@rivera.za.net>
parents:
38
diff
changeset
|
12 rect = pygame.Rect(rect, (0, 0)) |
3f44c30a1c39
Correct Text placement
Stefano Rivera <stefano@rivera.za.net>
parents:
38
diff
changeset
|
13 self.rect = rect |
58 | 14 self.focussable = False |
77 | 15 self.focussed = False |
106 | 16 self.parent = None |
55
671d027f1b71
Callbacks for events in widgets
Stefano Rivera <stefano@rivera.za.net>
parents:
43
diff
changeset
|
17 self.callbacks = collections.defaultdict(list) |
671d027f1b71
Callbacks for events in widgets
Stefano Rivera <stefano@rivera.za.net>
parents:
43
diff
changeset
|
18 |
671d027f1b71
Callbacks for events in widgets
Stefano Rivera <stefano@rivera.za.net>
parents:
43
diff
changeset
|
19 def add_callback(self, eventtype, callback, *args): |
671d027f1b71
Callbacks for events in widgets
Stefano Rivera <stefano@rivera.za.net>
parents:
43
diff
changeset
|
20 self.callbacks[eventtype].append((callback, args)) |
23 | 21 |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
22 def event(self, ev): |
106 | 23 if ev.type == MOUSEBUTTONDOWN and self.focussable: |
24 root = self | |
25 while root.parent is not None: | |
26 root = root.parent | |
27 root.defocus() | |
28 widget = self | |
29 while widget.parent is not None: | |
30 parent = widget.parent | |
31 if isinstance(parent, Container): | |
32 parent.focussed_child = parent.children.index(widget) | |
33 widget = parent | |
34 self.focussed = True | |
35 | |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
36 for callback, args in self.callbacks[ev.type]: |
77 | 37 if callback(ev, self, *args): |
38 return True | |
39 return False | |
23 | 40 |
24
30d4f3e62bcf
Refactor widgets *again*, add container to Habitat
Stefano Rivera <stefano@rivera.za.net>
parents:
23
diff
changeset
|
41 def draw(self, surface): |
23 | 42 "Override me" |
43 pass | |
44 | |
45 | |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
46 class Container(Widget): |
23 | 47 |
106 | 48 def __init__(self, rect): |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
49 super(Container, self).__init__(rect) |
23 | 50 self.children = [] |
77 | 51 self.focussed_child = None |
23 | 52 |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
53 def event(self, ev): |
77 | 54 """Push an event down through the tree, and fire our own event as a |
55 last resort | |
56 """ | |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
57 if ev.type in (MOUSEMOTION, MOUSEBUTTONUP, MOUSEBUTTONDOWN): |
58 | 58 for child in self.children: |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
59 if child.rect.collidepoint(ev.pos): |
77 | 60 if child.event(ev): |
61 return True | |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
62 if ev.type == KEYDOWN: |
58 | 63 for child in self.children: |
77 | 64 if child.focussed: |
65 if child.event(ev): | |
66 return True | |
67 if super(Container, self).event(ev): | |
68 return True | |
106 | 69 if (self.parent is None and ev.type == KEYDOWN |
70 and ev.key in (K_UP, K_DOWN)): | |
97
c65046b5bafd
eat focus adjusting key events
Stefano Rivera <stefano@rivera.za.net>
parents:
95
diff
changeset
|
71 return self.adjust_focus(1 if ev.key == K_DOWN else -1) |
23 | 72 |
73 def add(self, widget): | |
77 | 74 widget.parent = self |
23 | 75 self.children.append(widget) |
106 | 76 self.rect = self.rect.union(widget.rect) |
77 | |
78 def defocus(self): | |
79 if self.focussed_child is not None: | |
80 child = self.children[self.focussed_child] | |
81 if isinstance(child, Container): | |
82 child.defocus() | |
83 child.focussed = False | |
23 | 84 |
77 | 85 def adjust_focus(self, direction): |
86 """Try and adjust focus in direction (integer) | |
87 """ | |
88 if self.focussed_child is not None: | |
89 child = self.children[self.focussed_child] | |
90 if isinstance(child, Container): | |
91 if child.adjust_focus(direction): | |
92 return True | |
106 | 93 else: |
94 child.focussed = False | |
77 | 95 |
96 current = self.focussed_child | |
97 if current is None: | |
98 current = -1 if direction > 0 else len(self.children) | |
99 if direction > 0: | |
100 possibles = list(enumerate(self.children))[current + 1:] | |
101 else: | |
102 possibles = list(enumerate(self.children))[:current] | |
103 possibles.reverse() | |
104 for i, child in possibles: | |
105 if child.focussable: | |
106 child.focussed = True | |
106 | 107 self.focussed_child = i |
108 return True | |
109 if isinstance(child, Container): | |
110 if child.adjust_focus(direction): | |
77 | 111 self.focussed_child = i |
112 return True | |
113 else: | |
106 | 114 if self.parent is None: |
115 if self.focussed_child is not None: | |
99
2b6626f417f2
Handle root containers where nothing is focussable
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
116 # At the end, mark the last one as focussed, again |
2b6626f417f2
Handle root containers where nothing is focussable
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
117 child = self.children[self.focussed_child] |
2b6626f417f2
Handle root containers where nothing is focussable
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
118 if isinstance(child, Container): |
2b6626f417f2
Handle root containers where nothing is focussable
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
119 if child.adjust_focus(-direction): |
2b6626f417f2
Handle root containers where nothing is focussable
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
120 return True |
106 | 121 else: |
122 child.focussed = True | |
123 return True | |
95
7a17c5b74148
Correctly handle nested Containers. Set focus on root container at first draw
Stefano Rivera <stefano@rivera.za.net>
parents:
77
diff
changeset
|
124 else: |
7a17c5b74148
Correctly handle nested Containers. Set focus on root container at first draw
Stefano Rivera <stefano@rivera.za.net>
parents:
77
diff
changeset
|
125 self.focussed_child = None |
77 | 126 return False |
127 | |
23 | 128 def draw(self, surface): |
106 | 129 if self.parent is None and not self.focussed: |
95
7a17c5b74148
Correctly handle nested Containers. Set focus on root container at first draw
Stefano Rivera <stefano@rivera.za.net>
parents:
77
diff
changeset
|
130 self.focussed = True |
7a17c5b74148
Correctly handle nested Containers. Set focus on root container at first draw
Stefano Rivera <stefano@rivera.za.net>
parents:
77
diff
changeset
|
131 self.adjust_focus(1) |
23 | 132 for child in self.children: |
24
30d4f3e62bcf
Refactor widgets *again*, add container to Habitat
Stefano Rivera <stefano@rivera.za.net>
parents:
23
diff
changeset
|
133 child.draw(surface) |