Mercurial > mamba
annotate mamba/widgets/base.py @ 601:915de6c7d342 default tip
Add support for making the editor fullscreen too.
author | Simon Cross <hodgestar@gmail.com> |
---|---|
date | Sat, 14 Jan 2023 19:34:26 +0100 |
parents | 2d3dee657638 |
children |
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 |
417 | 4 from pygame.locals import (KEYDOWN, K_DOWN, K_LEFT, K_RETURN, K_RIGHT, K_UP, |
5 K_KP_ENTER, MOUSEBUTTONDOWN, MOUSEBUTTONUP, | |
6 MOUSEMOTION, SRCALPHA, USEREVENT) | |
209
51d54026b153
Support UserEvents in callbacks
Stefano Rivera <stefano@rivera.za.net>
parents:
189
diff
changeset
|
7 |
338
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
8 from mamba.constants import UP, DOWN, LEFT, RIGHT |
209
51d54026b153
Support UserEvents in callbacks
Stefano Rivera <stefano@rivera.za.net>
parents:
189
diff
changeset
|
9 from mamba.engine import UserEvent |
23 | 10 |
11 | |
12 class Widget(object): | |
13 | |
14 def __init__(self, rect): | |
38 | 15 if not isinstance(rect, pygame.Rect): |
41
3f44c30a1c39
Correct Text placement
Stefano Rivera <stefano@rivera.za.net>
parents:
38
diff
changeset
|
16 rect = pygame.Rect(rect, (0, 0)) |
3f44c30a1c39
Correct Text placement
Stefano Rivera <stefano@rivera.za.net>
parents:
38
diff
changeset
|
17 self.rect = rect |
58 | 18 self.focussable = False |
77 | 19 self.focussed = False |
210
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
20 self.modal = False |
106 | 21 self.parent = None |
440
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
22 self.disabled = False |
55
671d027f1b71
Callbacks for events in widgets
Stefano Rivera <stefano@rivera.za.net>
parents:
43
diff
changeset
|
23 self.callbacks = collections.defaultdict(list) |
671d027f1b71
Callbacks for events in widgets
Stefano Rivera <stefano@rivera.za.net>
parents:
43
diff
changeset
|
24 |
671d027f1b71
Callbacks for events in widgets
Stefano Rivera <stefano@rivera.za.net>
parents:
43
diff
changeset
|
25 def add_callback(self, eventtype, callback, *args): |
671d027f1b71
Callbacks for events in widgets
Stefano Rivera <stefano@rivera.za.net>
parents:
43
diff
changeset
|
26 self.callbacks[eventtype].append((callback, args)) |
23 | 27 |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
28 def event(self, ev): |
209
51d54026b153
Support UserEvents in callbacks
Stefano Rivera <stefano@rivera.za.net>
parents:
189
diff
changeset
|
29 "Don't override this without damn good reason" |
440
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
30 if self.disabled: |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
31 return True |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
32 |
209
51d54026b153
Support UserEvents in callbacks
Stefano Rivera <stefano@rivera.za.net>
parents:
189
diff
changeset
|
33 type_ = ev.type |
51d54026b153
Support UserEvents in callbacks
Stefano Rivera <stefano@rivera.za.net>
parents:
189
diff
changeset
|
34 if type_ == USEREVENT: |
590
2d3dee657638
Game runs, although weirdly
Neil Muller <drnlmuller@gmail.com>
parents:
457
diff
changeset
|
35 for k in self.callbacks.keys(): |
209
51d54026b153
Support UserEvents in callbacks
Stefano Rivera <stefano@rivera.za.net>
parents:
189
diff
changeset
|
36 if (isinstance(k, type) and issubclass(k, UserEvent) |
51d54026b153
Support UserEvents in callbacks
Stefano Rivera <stefano@rivera.za.net>
parents:
189
diff
changeset
|
37 and k.matches(ev)): |
51d54026b153
Support UserEvents in callbacks
Stefano Rivera <stefano@rivera.za.net>
parents:
189
diff
changeset
|
38 type_ = k |
51d54026b153
Support UserEvents in callbacks
Stefano Rivera <stefano@rivera.za.net>
parents:
189
diff
changeset
|
39 break |
51d54026b153
Support UserEvents in callbacks
Stefano Rivera <stefano@rivera.za.net>
parents:
189
diff
changeset
|
40 |
51d54026b153
Support UserEvents in callbacks
Stefano Rivera <stefano@rivera.za.net>
parents:
189
diff
changeset
|
41 for callback, args in self.callbacks[type_]: |
77 | 42 if callback(ev, self, *args): |
43 return True | |
44 return False | |
23 | 45 |
24
30d4f3e62bcf
Refactor widgets *again*, add container to Habitat
Stefano Rivera <stefano@rivera.za.net>
parents:
23
diff
changeset
|
46 def draw(self, surface): |
23 | 47 "Override me" |
48 pass | |
49 | |
189 | 50 def grab_focus(self): |
210
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
51 if self.focussable: |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
52 # Find the root and current focus |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
53 root = self |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
54 while root.parent is not None: |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
55 root = root.parent |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
56 focus = root |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
57 focus_modal_base = None |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
58 while (isinstance(focus, Container) |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
59 and focus.focussed_child is not None): |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
60 if focus.modal: |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
61 focus_modal_base = focus |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
62 focus = focus.children[focus.focussed_child] |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
63 |
423
8558b2219688
Improve multi-modal hirarchy behavior (but not very usefully)
Stefano Rivera <stefano@rivera.za.net>
parents:
417
diff
changeset
|
64 # Don't leave a modal heirarchy |
8558b2219688
Improve multi-modal hirarchy behavior (but not very usefully)
Stefano Rivera <stefano@rivera.za.net>
parents:
417
diff
changeset
|
65 if focus_modal_base: |
8558b2219688
Improve multi-modal hirarchy behavior (but not very usefully)
Stefano Rivera <stefano@rivera.za.net>
parents:
417
diff
changeset
|
66 widget = self |
8558b2219688
Improve multi-modal hirarchy behavior (but not very usefully)
Stefano Rivera <stefano@rivera.za.net>
parents:
417
diff
changeset
|
67 while widget.parent is not None: |
8558b2219688
Improve multi-modal hirarchy behavior (but not very usefully)
Stefano Rivera <stefano@rivera.za.net>
parents:
417
diff
changeset
|
68 if widget == focus_modal_base: |
8558b2219688
Improve multi-modal hirarchy behavior (but not very usefully)
Stefano Rivera <stefano@rivera.za.net>
parents:
417
diff
changeset
|
69 break |
8558b2219688
Improve multi-modal hirarchy behavior (but not very usefully)
Stefano Rivera <stefano@rivera.za.net>
parents:
417
diff
changeset
|
70 widget = widget.parent |
8558b2219688
Improve multi-modal hirarchy behavior (but not very usefully)
Stefano Rivera <stefano@rivera.za.net>
parents:
417
diff
changeset
|
71 else: |
8558b2219688
Improve multi-modal hirarchy behavior (but not very usefully)
Stefano Rivera <stefano@rivera.za.net>
parents:
417
diff
changeset
|
72 return False |
210
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
73 |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
74 root.defocus() |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
75 widget = self |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
76 while widget.parent is not None: |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
77 parent = widget.parent |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
78 if isinstance(parent, Container): |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
79 idx = parent.children.index(widget) |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
80 parent.focussed_child = idx |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
81 widget = parent |
189 | 82 self.focussed = True |
210
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
83 return True |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
84 return False |
189 | 85 |
440
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
86 def disable(self): |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
87 if not self.disabled: |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
88 self.disabled = True |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
89 self._focussable_when_enabled = self.focussable |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
90 self.focussable = False |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
91 if hasattr(self, 'prepare'): |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
92 self.prepare() |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
93 |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
94 def enable(self): |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
95 if self.disabled: |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
96 self.disabled = False |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
97 self.focussable = self._focussable_when_enabled |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
98 if hasattr(self, 'prepare'): |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
99 self.prepare() |
93ba8c966cb9
Disableable text buttons
Stefano Rivera <stefano@rivera.za.net>
parents:
423
diff
changeset
|
100 |
23 | 101 |
115
d5aa5f805f00
Add Button class that buttons inherit from. It implements a 'clicked' callback
Stefano Rivera <stefano@rivera.za.net>
parents:
109
diff
changeset
|
102 class Button(Widget): |
137
7fbeeb402685
PEP8 tidy mamba.widgets
Stefano Rivera <stefano@rivera.za.net>
parents:
115
diff
changeset
|
103 |
115
d5aa5f805f00
Add Button class that buttons inherit from. It implements a 'clicked' callback
Stefano Rivera <stefano@rivera.za.net>
parents:
109
diff
changeset
|
104 def event(self, ev): |
d5aa5f805f00
Add Button class that buttons inherit from. It implements a 'clicked' callback
Stefano Rivera <stefano@rivera.za.net>
parents:
109
diff
changeset
|
105 if super(Button, self).event(ev): |
d5aa5f805f00
Add Button class that buttons inherit from. It implements a 'clicked' callback
Stefano Rivera <stefano@rivera.za.net>
parents:
109
diff
changeset
|
106 return True |
d5aa5f805f00
Add Button class that buttons inherit from. It implements a 'clicked' callback
Stefano Rivera <stefano@rivera.za.net>
parents:
109
diff
changeset
|
107 if (ev.type == MOUSEBUTTONDOWN |
417 | 108 or (ev.type == KEYDOWN and ev.key in (K_RETURN, K_KP_ENTER))): |
115
d5aa5f805f00
Add Button class that buttons inherit from. It implements a 'clicked' callback
Stefano Rivera <stefano@rivera.za.net>
parents:
109
diff
changeset
|
109 for callback, args in self.callbacks['clicked']: |
d5aa5f805f00
Add Button class that buttons inherit from. It implements a 'clicked' callback
Stefano Rivera <stefano@rivera.za.net>
parents:
109
diff
changeset
|
110 if callback(ev, self, *args): |
d5aa5f805f00
Add Button class that buttons inherit from. It implements a 'clicked' callback
Stefano Rivera <stefano@rivera.za.net>
parents:
109
diff
changeset
|
111 return True |
d5aa5f805f00
Add Button class that buttons inherit from. It implements a 'clicked' callback
Stefano Rivera <stefano@rivera.za.net>
parents:
109
diff
changeset
|
112 return False |
d5aa5f805f00
Add Button class that buttons inherit from. It implements a 'clicked' callback
Stefano Rivera <stefano@rivera.za.net>
parents:
109
diff
changeset
|
113 |
266
190aa1481908
Add forced_click method to buttons
Neil Muller <drnlmuller@gmail.com>
parents:
210
diff
changeset
|
114 def forced_click(self): |
190aa1481908
Add forced_click method to buttons
Neil Muller <drnlmuller@gmail.com>
parents:
210
diff
changeset
|
115 """Force calling the clicked handler""" |
290
a0c60e0c1ef2
Make forced_click grab the focus as well
Neil Muller <drnlmuller@gmail.com>
parents:
283
diff
changeset
|
116 self.grab_focus() |
266
190aa1481908
Add forced_click method to buttons
Neil Muller <drnlmuller@gmail.com>
parents:
210
diff
changeset
|
117 for callback, args in self.callbacks['clicked']: |
190aa1481908
Add forced_click method to buttons
Neil Muller <drnlmuller@gmail.com>
parents:
210
diff
changeset
|
118 if callback(None, self, *args): |
190aa1481908
Add forced_click method to buttons
Neil Muller <drnlmuller@gmail.com>
parents:
210
diff
changeset
|
119 return True |
190aa1481908
Add forced_click method to buttons
Neil Muller <drnlmuller@gmail.com>
parents:
210
diff
changeset
|
120 return False |
190aa1481908
Add forced_click method to buttons
Neil Muller <drnlmuller@gmail.com>
parents:
210
diff
changeset
|
121 |
115
d5aa5f805f00
Add Button class that buttons inherit from. It implements a 'clicked' callback
Stefano Rivera <stefano@rivera.za.net>
parents:
109
diff
changeset
|
122 |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
123 class Container(Widget): |
23 | 124 |
338
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
125 def __init__(self, rect=None): |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
126 if rect is None: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
127 rect = pygame.Rect(0, 0, 0, 0) |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
128 super(Container, self).__init__(rect) |
23 | 129 self.children = [] |
77 | 130 self.focussed_child = None |
23 | 131 |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
132 def event(self, ev): |
77 | 133 """Push an event down through the tree, and fire our own event as a |
134 last resort | |
135 """ | |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
136 if ev.type in (MOUSEMOTION, MOUSEBUTTONUP, MOUSEBUTTONDOWN): |
283
11cf3a259eaa
Iterate over copies, to avoid some issues with children changing in the loop
Neil Muller <drnlmuller@gmail.com>
parents:
266
diff
changeset
|
137 for child in self.children[:]: |
59
3cc917814579
Container subclasses Widget
Stefano Rivera <stefano@rivera.za.net>
parents:
58
diff
changeset
|
138 if child.rect.collidepoint(ev.pos): |
109
dc0b0be7e2f6
Move mouse focussing to within Container
Stefano Rivera <stefano@rivera.za.net>
parents:
106
diff
changeset
|
139 if ev.type == MOUSEBUTTONDOWN and child.focussable: |
347
0a2c686a8b14
Make modal containers affect the mouse too
Stefano Rivera <stefano@rivera.za.net>
parents:
339
diff
changeset
|
140 if not child.grab_focus(): |
416
30ce046d08c3
Fix clicking in dead dialog bug
Stefano Rivera <stefano@rivera.za.net>
parents:
382
diff
changeset
|
141 continue |
77 | 142 if child.event(ev): |
143 return True | |
109
dc0b0be7e2f6
Move mouse focussing to within Container
Stefano Rivera <stefano@rivera.za.net>
parents:
106
diff
changeset
|
144 |
184
5f286cbb15e3
Pass other events to container children as well
Neil Muller <drnlmuller@gmail.com>
parents:
179
diff
changeset
|
145 elif ev.type == KEYDOWN: |
210
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
146 for i, child in enumerate(self.children): |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
147 if child.focussed or i == self.focussed_child: |
77 | 148 if child.event(ev): |
149 return True | |
184
5f286cbb15e3
Pass other events to container children as well
Neil Muller <drnlmuller@gmail.com>
parents:
179
diff
changeset
|
150 else: |
5f286cbb15e3
Pass other events to container children as well
Neil Muller <drnlmuller@gmail.com>
parents:
179
diff
changeset
|
151 # Other events go to all children first |
283
11cf3a259eaa
Iterate over copies, to avoid some issues with children changing in the loop
Neil Muller <drnlmuller@gmail.com>
parents:
266
diff
changeset
|
152 for child in self.children[:]: |
184
5f286cbb15e3
Pass other events to container children as well
Neil Muller <drnlmuller@gmail.com>
parents:
179
diff
changeset
|
153 if child.event(ev): |
5f286cbb15e3
Pass other events to container children as well
Neil Muller <drnlmuller@gmail.com>
parents:
179
diff
changeset
|
154 return True |
77 | 155 if super(Container, self).event(ev): |
156 return True | |
106 | 157 if (self.parent is None and ev.type == KEYDOWN |
158 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
|
159 return self.adjust_focus(1 if ev.key == K_DOWN else -1) |
23 | 160 |
161 def add(self, widget): | |
77 | 162 widget.parent = self |
23 | 163 self.children.append(widget) |
106 | 164 self.rect = self.rect.union(widget.rect) |
165 | |
179
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
166 def remove(self, widget): |
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
167 widget.parent = None |
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
168 if self.focussed_child is not None: |
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
169 child = self.children[self.focussed_child] |
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
170 self.children.remove(widget) |
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
171 # We don't update the rect, for reasons of simplificty and laziness |
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
172 if self.focussed_child is not None and child in self.children: |
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
173 # Fix focus index |
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
174 self.focussed_child = self.children.index(child) |
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
175 else: |
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
176 self.focussed_child = None |
79fdae806ca5
Add remove method to containers
Neil Muller <drnlmuller@gmail.com>
parents:
137
diff
changeset
|
177 |
106 | 178 def defocus(self): |
179 if self.focussed_child is not None: | |
180 child = self.children[self.focussed_child] | |
181 if isinstance(child, Container): | |
210
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
182 if not child.defocus(): |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
183 return False |
106 | 184 child.focussed = False |
210
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
185 self.focussed_child = None |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
186 return True |
23 | 187 |
77 | 188 def adjust_focus(self, direction): |
189 """Try and adjust focus in direction (integer) | |
190 """ | |
191 if self.focussed_child is not None: | |
192 child = self.children[self.focussed_child] | |
193 if isinstance(child, Container): | |
194 if child.adjust_focus(direction): | |
195 return True | |
210
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
196 elif child.modal: |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
197 # We're modal, go back |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
198 if child.adjust_focus(-direction): |
b92f705bd8ea
Modal dialogs, and focus stealing bugfixes
Stefano Rivera <stefano@rivera.za.net>
parents:
209
diff
changeset
|
199 return True |
106 | 200 else: |
201 child.focussed = False | |
77 | 202 |
203 current = self.focussed_child | |
204 if current is None: | |
205 current = -1 if direction > 0 else len(self.children) | |
206 if direction > 0: | |
207 possibles = list(enumerate(self.children))[current + 1:] | |
208 else: | |
209 possibles = list(enumerate(self.children))[:current] | |
210 possibles.reverse() | |
211 for i, child in possibles: | |
212 if child.focussable: | |
213 child.focussed = True | |
106 | 214 self.focussed_child = i |
215 return True | |
216 if isinstance(child, Container): | |
217 if child.adjust_focus(direction): | |
77 | 218 self.focussed_child = i |
219 return True | |
220 else: | |
106 | 221 if self.parent is None: |
222 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
|
223 # 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
|
224 child = self.children[self.focussed_child] |
2b6626f417f2
Handle root containers where nothing is focussable
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
225 if isinstance(child, Container): |
2b6626f417f2
Handle root containers where nothing is focussable
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
226 if child.adjust_focus(-direction): |
2b6626f417f2
Handle root containers where nothing is focussable
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
227 return True |
106 | 228 else: |
229 child.focussed = True | |
230 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
|
231 else: |
7a17c5b74148
Correctly handle nested Containers. Set focus on root container at first draw
Stefano Rivera <stefano@rivera.za.net>
parents:
77
diff
changeset
|
232 self.focussed_child = None |
77 | 233 return False |
234 | |
23 | 235 def draw(self, surface): |
106 | 236 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
|
237 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
|
238 self.adjust_focus(1) |
23 | 239 for child in self.children: |
24
30d4f3e62bcf
Refactor widgets *again*, add container to Habitat
Stefano Rivera <stefano@rivera.za.net>
parents:
23
diff
changeset
|
240 child.draw(surface) |
338
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
241 |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
242 |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
243 class GridContainer(Container): |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
244 """Hacky container that only supports grids, won't work with Container |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
245 children, or modal children. |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
246 """ |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
247 |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
248 def __init__(self, width, rect=None): |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
249 super(GridContainer, self).__init__(rect) |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
250 self.width = width |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
251 |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
252 def event(self, ev): |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
253 if (ev.type == KEYDOWN and ev.key in (K_UP, K_DOWN, K_LEFT, K_RIGHT)): |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
254 direction = None |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
255 if ev.key == K_UP: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
256 direction = UP |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
257 elif ev.key == K_DOWN: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
258 direction = DOWN |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
259 elif ev.key == K_LEFT: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
260 direction = LEFT |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
261 elif ev.key == K_RIGHT: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
262 direction = RIGHT |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
263 return self.adjust_focus(direction) |
339
c7d7accca022
Don't forget to super().event(...), especially when you shout at other people about it...
Stefano Rivera <stefano@rivera.za.net>
parents:
338
diff
changeset
|
264 super(GridContainer, self).event(ev) |
338
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
265 |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
266 def add(self, widget): |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
267 assert not isinstance(widget, Container) |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
268 assert not widget.modal |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
269 super(GridContainer, self).add(widget) |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
270 |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
271 def adjust_focus(self, direction): |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
272 if isinstance(direction, int): |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
273 direction = (direction, 0) |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
274 |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
275 if len(self.children) == 0: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
276 return False |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
277 |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
278 if self.focussed_child is None: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
279 if sum(direction) > 0: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
280 self.focussed_child = 0 |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
281 else: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
282 self.focussed_child = len(self.children) - 1 |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
283 else: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
284 self.children[self.focussed_child].focussed = False |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
285 if direction[0] != 0: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
286 self.focussed_child += direction[0] |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
287 if direction[1] != 0: |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
288 self.focussed_child += self.width * direction[1] |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
289 if not 0 <= self.focussed_child < len(self.children): |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
290 self.focussed_child = None |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
291 return False |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
292 self.children[self.focussed_child].focussed = True |
2cadc8a427f0
a hackful GridContainer for the LevelMenu
Stefano Rivera <stefano@rivera.za.net>
parents:
290
diff
changeset
|
293 return True |
382 | 294 |
295 | |
296 class Box(Container): | |
297 """A container that draws a filled background with a border""" | |
298 padding = 4 | |
299 | |
300 def draw(self, surface): | |
301 expandrect = self.rect.move((-self.padding, -self.padding)) | |
302 expandrect.width = self.rect.width + 2 * self.padding | |
303 expandrect.height = self.rect.height + 2 * self.padding | |
304 border = pygame.Surface(expandrect.size, SRCALPHA) | |
305 border.fill(pygame.Color('black')) | |
306 surface.blit(border, expandrect) | |
307 background = pygame.Surface(self.rect.size, SRCALPHA) | |
308 background.fill(pygame.Color('gray')) | |
309 surface.blit(background, self.rect) | |
310 super(Box, self).draw(surface) |