~jtaylor/ubuntu/natty/singularity/fix-576504

« back to all changes in this revision

Viewing changes to code/graphics/button.py

  • Committer: Bazaar Package Importer
  • Author(s): Kari Pahula
  • Date: 2009-02-16 14:29:19 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20090216142919-ukn5iy0slrjh3zul
Tags: 0.30-1
* New upstream release (Closes: #514199)
  * Supports setting arbitrary resolutions. (Closes: #439602)
  * No more per base tasks, only power states. (Closes: #490563, #482734)
  * Finance screen accounts to job done via CPU pool. (Closes: #490561)
* Added a lintian override to disable warning about acknowtt.ttf (ours
  has local modifications).
* Updated debian/copyright.
* Bumped Standards-Version to 3.8.0 (no changes necessary).
* Removed Ana from Uploaders.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#file: button.py
 
2
#Copyright (C) 2008 FunnyMan3595
 
3
#This file is part of Endgame: Singularity.
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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
 
18
 
 
19
#This file contains the Button class.
 
20
 
 
21
import pygame
 
22
 
 
23
import constants
 
24
import g
 
25
import widget
 
26
import text
 
27
import image
 
28
 
 
29
class Button(text.SelectableText):
 
30
    hotkey = widget.causes_rebuild("_hotkey")
 
31
    force_underline = widget.causes_rebuild("_force_underline")
 
32
 
 
33
    # A second layer of property wraps .hotkey, to update key handlers.
 
34
    __hotkey = ""
 
35
    def _on_set_hotkey(self, value):
 
36
        if self.parent and value != self.__hotkey:
 
37
            if self.__hotkey:
 
38
                self.parent.remove_key_handler(self.__hotkey, self.handle_event)
 
39
            if value:
 
40
                self.parent.add_key_handler(value, self.handle_event)
 
41
        self.__hotkey = value
 
42
 
 
43
    _hotkey = property(lambda self: self.__hotkey, _on_set_hotkey)
 
44
 
 
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):
 
48
        self.parent = parent
 
49
        self.hotkey = hotkey
 
50
        self.priority = priority
 
51
 
 
52
        super(Button, self).__init__(parent, pos, size, **kwargs)
 
53
 
 
54
        self.base_font = base_font or g.font[1]
 
55
        self.borders = borders
 
56
        self.shrink_factor = text_shrink_factor
 
57
 
 
58
        self.force_underline = force_underline
 
59
 
 
60
        self.selected = False
 
61
 
 
62
    def add_hooks(self):
 
63
        super(Button, self).add_hooks()
 
64
        self.parent.add_handler(constants.MOUSEMOTION, self.watch_mouse,
 
65
                                self.priority)
 
66
        self.parent.add_handler(constants.CLICK, self.handle_event,
 
67
                                self.priority)
 
68
        if self.hotkey:
 
69
            self.parent.add_key_handler(self.hotkey, self.handle_event,
 
70
                                        self.priority)
 
71
 
 
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)
 
76
        if self.hotkey:
 
77
            self.parent.remove_key_handler(self.hotkey, self.handle_event)
 
78
 
 
79
    def rebuild(self):
 
80
        old_underline = self.underline
 
81
        self.calc_underline()
 
82
        if self.underline != old_underline:
 
83
            self.needs_redraw = True
 
84
 
 
85
        super(Button, self).rebuild()
 
86
 
 
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())
 
95
        else:
 
96
            self.underline = -1
 
97
 
 
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
 
105
 
 
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)
 
113
 
 
114
    def activate_with_sound(self, event):
 
115
        """Called when the button is pressed or otherwise triggered.
 
116
 
 
117
           This method is called directly by the GUI handler, and should be
 
118
           overwrited only to remove the click it plays."""
 
119
 
 
120
        from code.g import play_sound
 
121
        play_sound("click")
 
122
        self.activated(event)
 
123
 
 
124
 
 
125
    def activated(self, event):
 
126
        """Called when the button is pressed or otherwise triggered."""
 
127
        raise constants.Handled
 
128
 
 
129
 
 
130
class ImageButton(Button):
 
131
    def __init__(self, *args, **kwargs):
 
132
        image_surface = kwargs.pop("image", None)
 
133
 
 
134
        super(ImageButton, self).__init__(*args, **kwargs)
 
135
 
 
136
        self.image = image.Image(self, (-.5, -.5), (-.9, -.9),
 
137
                                 anchor = constants.MID_CENTER,
 
138
                                 image = image_surface)
 
139
 
 
140
 
 
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)
 
147
 
 
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
 
153
 
 
154
 
 
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
 
162
 
 
163
    def add_hooks(self):
 
164
        super(ExitDialogButton, self).add_hooks()
 
165
        self.parent.add_key_handler(pygame.K_ESCAPE, self.activate_default)
 
166
 
 
167
    def remove_hooks(self):
 
168
        super(ExitDialogButton, self).remove_hooks()
 
169
        self.parent.remove_key_handler(pygame.K_ESCAPE, self.activate_default)
 
170
 
 
171
    def activate_default(self, event):
 
172
        if event.type != pygame.KEYDOWN or not self.default:
 
173
            return
 
174
 
 
175
        return self.activate_with_sound(event)
 
176
 
 
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()
 
181
        else:
 
182
            raise constants.ExitDialog, self.exit_code
 
183
 
 
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
 
189
 
 
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."""
 
193
        if not self.dialog:
 
194
            raise constants.Handled
 
195
        else:
 
196
            import dialog
 
197
            raise constants.Handled, dialog.call_dialog(self.dialog, self)
 
198
 
 
199
TOGGLE_VALUE = object()
 
200
class ToggleButton(Button):
 
201
    active = False
 
202
    button_group = None
 
203
 
 
204
    def replace_toggle(self, value):
 
205
        if value is TOGGLE_VALUE:
 
206
            return self.active
 
207
        else:
 
208
            return value
 
209
    def get_args(self):
 
210
        return tuple(self.replace_toggle(value) for value in self._args)
 
211
    def set_args(self, args):
 
212
        self._args = args
 
213
    args = property(get_args, set_args)
 
214
 
 
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)
 
220
        else:
 
221
            self.set_active(not self.active)
 
222
 
 
223
    def set_active(self, active):
 
224
        self.active = active
 
225
        self.selected = active
 
226
        if hasattr(self, "_collision_rect"):
 
227
            self.watch_mouse(None)
 
228
 
 
229
    def activated(self, event):
 
230
        self.chosen_one()
 
231
        super(ToggleButton, self).activated(event)
 
232
 
 
233
    def watch_mouse(self, event):
 
234
        if not self.active:
 
235
            super(ToggleButton, self).watch_mouse(event)
 
236
 
 
237
class ButtonGroup(list):
 
238
    def add(self, button):
 
239
        button.button_group = self
 
240
        super(ButtonGroup, self).append(button)
 
241
 
 
242
    def remove(self, button):
 
243
        button.button_group = None
 
244
        super(ButtonGroup, self).remove(button)
 
245