2
#Copyright (C) 2008 FunnyMan3595
3
#This file is part of Endgame: Singularity.
5
#Endgame: Singularity is free software; you can redistribute it and/or modify
6
#it under the terms of the GNU General Public License as published by
7
#the Free Software Foundation; either version 2 of the License, or
8
#(at your option) any later version.
10
#Endgame: Singularity is distributed in the hope that it will be useful,
11
#but WITHOUT ANY WARRANTY; without even the implied warranty of
12
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
#GNU General Public License for more details.
15
#You should have received a copy of the GNU General Public License
16
#along with Endgame: Singularity; if not, write to the Free Software
17
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
#This file contains the Button class.
29
class Button(text.SelectableText):
30
hotkey = widget.causes_rebuild("_hotkey")
31
force_underline = widget.causes_rebuild("_force_underline")
33
# A second layer of property wraps .hotkey, to update key handlers.
35
def _on_set_hotkey(self, value):
36
if self.parent and value != self.__hotkey:
38
self.parent.remove_key_handler(self.__hotkey, self.handle_event)
40
self.parent.add_key_handler(value, self.handle_event)
43
_hotkey = property(lambda self: self.__hotkey, _on_set_hotkey)
45
def __init__(self, parent, pos, size = (0, .045), base_font = None,
46
borders = constants.ALL, hotkey = "", force_underline = None,
47
text_shrink_factor = .825, priority = 100, **kwargs):
50
self.priority = priority
52
super(Button, self).__init__(parent, pos, size, **kwargs)
54
self.base_font = base_font or g.font[1]
55
self.borders = borders
56
self.shrink_factor = text_shrink_factor
58
self.force_underline = force_underline
63
super(Button, self).add_hooks()
64
self.parent.add_handler(constants.MOUSEMOTION, self.watch_mouse,
66
self.parent.add_handler(constants.CLICK, self.handle_event,
69
self.parent.add_key_handler(self.hotkey, self.handle_event,
72
def remove_hooks(self):
73
super(Button, self).remove_hooks()
74
self.parent.remove_handler(constants.MOUSEMOTION, self.watch_mouse)
75
self.parent.remove_handler(constants.CLICK, self.handle_event)
77
self.parent.remove_key_handler(self.hotkey, self.handle_event)
80
old_underline = self.underline
82
if self.underline != old_underline:
83
self.needs_redraw = True
85
super(Button, self).rebuild()
87
def calc_underline(self):
88
if self.force_underline != None:
89
self.underline = self.force_underline
90
elif self.hotkey and type(self.hotkey) in (str, unicode):
91
if self.hotkey in self.text:
92
self.underline = self.text.index(self.hotkey)
93
elif self.hotkey.lower() in self.text.lower():
94
self.underline = self.text.lower().index(self.hotkey.lower())
98
def watch_mouse(self, event):
99
"""Selects the button if the mouse is over it."""
100
if self.visible and getattr(self, "collision_rect", None):
101
# This gets called a lot, so it's been optimized.
102
select_now = self.is_over(pygame.mouse.get_pos())
103
if (self._selected ^ select_now): # If there's a change.
104
self.selected = select_now
106
def handle_event(self, event):
107
if event.type == pygame.MOUSEBUTTONUP:
108
if self.visible and getattr(self, "collision_rect", None) and self.is_over(event.pos):
109
self.activate_with_sound(event)
110
elif event.type == pygame.KEYDOWN:
111
if self.visible and self.hotkey in (event.unicode, event.key):
112
self.activate_with_sound(event)
114
def activate_with_sound(self, event):
115
"""Called when the button is pressed or otherwise triggered.
117
This method is called directly by the GUI handler, and should be
118
overwrited only to remove the click it plays."""
120
from code.g import play_sound
122
self.activated(event)
125
def activated(self, event):
126
"""Called when the button is pressed or otherwise triggered."""
127
raise constants.Handled
130
class ImageButton(Button):
131
def __init__(self, *args, **kwargs):
132
image_surface = kwargs.pop("image", None)
134
super(ImageButton, self).__init__(*args, **kwargs)
136
self.image = image.Image(self, (-.5, -.5), (-.9, -.9),
137
anchor = constants.MID_CENTER,
138
image = image_surface)
141
class FunctionButton(Button):
142
def __init__(self, *args, **kwargs):
143
self.function = kwargs.pop("function", lambda *args, **kwargs: None)
144
self.args = kwargs.pop("args", ())
145
self.kwargs = kwargs.pop("kwargs", {})
146
super(FunctionButton, self).__init__(*args, **kwargs)
148
def activated(self, event):
149
"""FunctionButton's custom activated menu. Makes the given function
150
call and raises Handled if it returns without incident."""
151
self.function(*self.args, **self.kwargs)
152
raise constants.Handled
155
class ExitDialogButton(FunctionButton):
156
def __init__(self, *args, **kwargs):
157
self.exit_code = kwargs.pop("exit_code", None)
158
self.exit_code_func = kwargs.pop("exit_code_func", None)
159
self.default = kwargs.pop("default", True)
160
super(ExitDialogButton, self).__init__(*args, **kwargs)
161
self.function = self.exit_dialog
164
super(ExitDialogButton, self).add_hooks()
165
self.parent.add_key_handler(pygame.K_ESCAPE, self.activate_default)
167
def remove_hooks(self):
168
super(ExitDialogButton, self).remove_hooks()
169
self.parent.remove_key_handler(pygame.K_ESCAPE, self.activate_default)
171
def activate_default(self, event):
172
if event.type != pygame.KEYDOWN or not self.default:
175
return self.activate_with_sound(event)
177
def exit_dialog(self):
178
"""Closes the dialog with the given exit code."""
179
if self.exit_code_func:
180
raise constants.ExitDialog, self.exit_code_func()
182
raise constants.ExitDialog, self.exit_code
184
class DialogButton(FunctionButton):
185
def __init__(self, *args, **kwargs):
186
self.dialog = kwargs.pop("dialog", None)
187
super(DialogButton, self).__init__(*args, **kwargs)
188
self.function = self.show_dialog
190
def show_dialog(self):
191
"""When the assigned dialog exits, raises Handled with the dialog's
192
exit code as a parameter. Subclass if you care what the code was."""
194
raise constants.Handled
197
raise constants.Handled, dialog.call_dialog(self.dialog, self)
199
TOGGLE_VALUE = object()
200
class ToggleButton(Button):
204
def replace_toggle(self, value):
205
if value is TOGGLE_VALUE:
210
return tuple(self.replace_toggle(value) for value in self._args)
211
def set_args(self, args):
213
args = property(get_args, set_args)
215
def chosen_one(self):
216
if self.button_group is not None:
217
for button in self.button_group:
218
button.set_active(False)
219
self.set_active(True)
221
self.set_active(not self.active)
223
def set_active(self, active):
225
self.selected = active
226
if hasattr(self, "_collision_rect"):
227
self.watch_mouse(None)
229
def activated(self, event):
231
super(ToggleButton, self).activated(event)
233
def watch_mouse(self, event):
235
super(ToggleButton, self).watch_mouse(event)
237
class ButtonGroup(list):
238
def add(self, button):
239
button.button_group = self
240
super(ButtonGroup, self).append(button)
242
def remove(self, button):
243
button.button_group = None
244
super(ButtonGroup, self).remove(button)