Web · Wiki · Activities · Blog · Lists · Chat · Meeting · Bugs · Git · Translate · Archive · People · Donate

Commit 4f54959d3a7fb67b5f2299221c5a9160904b2520

  • avatar
  • rdeaton
  • Wed Sep 19 12:33:37 EDT 2012
Move everything up one directory. Beyond this change, we should keep in sync with the main repository.

Signed-off-by: Robert Deaton <rdeaton@udel.edu>
README.txt
(0 / 137)
  
1== Sugargame ==
2
3Sugargame is a Python package which allows [http://www.pygame.org/ Pygame]
4programs to run well under Sugar.
5It is fork of the olcpgames framework, which is no longer maintained.
6
7http://git.sugarlabs.org/projects/sugargame
8
9What it does:
10
11* Wraps a Sugar activity around an existing Pygame program with few changes
12* Allows Sugar toolbars and other widgets to be added to the activity UI
13* Provides hooks for saving to and restoring from the Journal
14
15==== Differences between Sugargame and olpcgames ====
16
17The olpcgames framework provides a wrapper around Pygame which attempts to
18allow a Pygame program to run mostly unmodified under Sugar. To this end,
19the Pygame program is run in a separate thread with its own Pygame message
20loop while the main thread runs the GTK message loop. Also, olpcgames wraps
21Sugar APIs such as the journal and mesh into a Pygame-like API.
22
23Sugargame takes a simpler approach; it provides a way to embed Pygame into a
24GTK widget. The Sugar APIs are used to interact with Sugar, the Pygame APIs
25are used for the game.
26
27Sugargame advantages:
28
29* Simpler code
30* More elegant interface between Pygame and GTK
31* Runs as a single thread: no thread related segfaults
32* Possible to use Sugar widgets with Pygame
33
34Sugargame limitations:
35
36* No support for Pango or SVG sprites (yet)
37
38== Using Sugargame ==
39
40See also [[Development Team/Sugargame/Examples]].
41
42==== Wrapping a Pygame program ====
43
44To use Sugargame to Sugarize a Pygame program, set up an activity directory and
45copy the Sugargame package to it.
46
47The activity directory should look something like this:
48
49 activity/ - Activity directory: activity.info, SVG icon, etc.
50 sugargame/ - Sugargame package
51 MyActivity.py - Activity class
52 mygame.py - Pygame code
53 setup.py - Install script
54
55To make the Activity class, start with test/TestActivity.py from the Sugargame
56distribution.
57
58The activity should create a single PygameCanvas widget and call run_pygame on it.
59Pass the main loop function of the Pygame program.
60
61 self._canvas = sugargame.canvas.PygameCanvas(self)
62 self.set_canvas(self._canvas)
63
64 # Start the game running.
65 self._canvas.run_pygame(self.game.run)
66
67In your Pygame main loop, pump the GTK message loop:
68
69 while gtk.events_pending():
70 gtk.main_iteration()
71
72==== Adding Pygame to a PyGTK activity ====
73
74To add Pygame to an existing Sugar activity, create a PygameCanvas widget and call
75run_pygame on it.
76
77 widget = sugargame.canvas.PygameCanvas(self)
78 vbox.pack_start(widget)
79
80 widget.run_pygame(self.game.run)
81
82Due to limitations of Pygame and SDL, there can only be one PygameCanvas in the
83entire activity.
84
85The argument to run_pygame is a function structured like a Pygame program. In the
86main loop, remember to dispatch GTK messages using gtk.main_iteration().
87
88 def main_loop():
89 clock = pygame.time.Clock()
90 screen = pygame.display.get_surface()
91
92 while self.running:
93 # Pump GTK messages.
94 while gtk.events_pending():
95 gtk.main_iteration()
96
97 # Pump PyGame messages.
98 for event in pygame.event.get():
99 if event.type == pygame.QUIT:
100 return
101 elif event.type == pygame.VIDEORESIZE:
102 pygame.display.set_mode(event.size, pygame.RESIZABLE)
103
104 # Check the mouse position
105 x, y = pygame.mouse.get_pos()
106
107 # Clear Display
108 screen.fill((255,255,255)) #255 for white
109
110 # Draw stuff here
111 .................
112
113 # Flip Display
114 pygame.display.flip()
115
116 # Try to stay at 30 FPS
117 self.clock.tick(30)
118
119== Support ==
120
121For help with Sugargame, please email the Sugar Labs development list:
122
123: sugar-devel@lists.sugarlabs.org
124
125Sugargame is developed by Wade Brainerd <wadetb@gmail.com>.
126
127It is loosely based on the source code to the olpcgames framework, developed by
128the One Laptop Per Child project.
129
130=== Changelog ===
131
132====v1.1====
133* Fix bugs in event handling. (Pablo Moleri)
134* Remove reference to gtk.Socket.get_window() method, which is missing in older versions of PyGTK.
135
136====v1.0====
137* Initial version of Sugargame
  
1__version__ = '1.1'
canvas.py
(62 / 0)
  
1import os
2import gtk
3import gobject
4import pygame
5import event
6
7CANVAS = None
8
9class PygameCanvas(gtk.EventBox):
10
11 """
12 mainwindow is the activity intself.
13 """
14 def __init__(self, mainwindow, pointer_hint = True):
15 gtk.EventBox.__init__(self)
16
17 global CANVAS
18 assert CANVAS == None, "Only one PygameCanvas can be created, ever."
19 CANVAS = self
20
21 # Initialize Events translator before widget gets "realized".
22 self.translator = event.Translator(mainwindow, self)
23
24 self._mainwindow = mainwindow
25
26 self.set_flags(gtk.CAN_FOCUS)
27
28 self._socket = gtk.Socket()
29 self.add(self._socket)
30 self.show_all()
31
32 def run_pygame(self, main_fn):
33 # Run the main loop after a short delay. The reason for the delay is that the
34 # Sugar activity is not properly created until after its constructor returns.
35 # If the Pygame main loop is called from the activity constructor, the
36 # constructor never returns and the activity freezes.
37 gobject.idle_add(self._run_pygame_cb, main_fn)
38
39 def _run_pygame_cb(self, main_fn):
40 assert pygame.display.get_surface() is None, "PygameCanvas.run_pygame can only be called once."
41
42 # Preinitialize Pygame with the X window ID.
43 assert pygame.display.get_init() == False, "Pygame must not be initialized before calling PygameCanvas.run_pygame."
44 os.environ['SDL_WINDOWID'] = str(self._socket.get_id())
45 pygame.init()
46
47 # Restore the default cursor.
48 self._socket.window.set_cursor(None)
49
50 # Initialize the Pygame window.
51 r = self.get_allocation()
52 pygame.display.set_mode((r.width, r.height), pygame.RESIZABLE)
53
54 # Hook certain Pygame functions with GTK equivalents.
55 self.translator.hook_pygame()
56
57 # Run the Pygame main loop.
58 main_fn()
59 return False
60
61 def get_pygame_widget(self):
62 return self._socket
event.py
(274 / 0)
  
1import gtk
2import gobject
3import pygame
4import pygame.event
5
6class _MockEvent(object):
7 def __init__(self, keyval):
8 self.keyval = keyval
9
10class Translator(object):
11 key_trans = {
12 'Alt_L': pygame.K_LALT,
13 'Alt_R': pygame.K_RALT,
14 'Control_L': pygame.K_LCTRL,
15 'Control_R': pygame.K_RCTRL,
16 'Shift_L': pygame.K_LSHIFT,
17 'Shift_R': pygame.K_RSHIFT,
18 'Super_L': pygame.K_LSUPER,
19 'Super_R': pygame.K_RSUPER,
20 'KP_Page_Up' : pygame.K_KP9,
21 'KP_Page_Down' : pygame.K_KP3,
22 'KP_End' : pygame.K_KP1,
23 'KP_Home' : pygame.K_KP7,
24 'KP_Up' : pygame.K_KP8,
25 'KP_Down' : pygame.K_KP2,
26 'KP_Left' : pygame.K_KP4,
27 'KP_Right' : pygame.K_KP6,
28 'numbersign' : pygame.K_HASH,
29 'percent' : ord('%'),
30 'exclam' : pygame.K_EXCLAIM,
31 'asciicircum' : pygame.K_CARET,
32 'parenleft' : pygame.K_LEFTPAREN,
33 'parenright' : pygame.K_RIGHTPAREN,
34 'braceleft' : ord('{'),
35 'braceright' : ord('}'),
36 'bracketleft' : pygame.K_LEFTBRACKET,
37 'bracketright' : pygame.K_RIGHTBRACKET,
38 'apostrophe' : ord('\''),
39 'equal' : pygame.K_EQUALS,
40 'grave' : pygame.K_BACKQUOTE,
41 'Caps_Lock' : pygame.K_CAPSLOCK,
42 'Page_Up' : pygame.K_PAGEUP,
43 'Page_Down' : pygame.K_PAGEDOWN,
44 'Num_Lock' : pygame.K_NUMLOCK,
45 'Bar' : ord('|')
46 }
47
48 mod_map = {
49 pygame.K_LALT: pygame.KMOD_LALT,
50 pygame.K_RALT: pygame.KMOD_RALT,
51 pygame.K_LCTRL: pygame.KMOD_LCTRL,
52 pygame.K_RCTRL: pygame.KMOD_RCTRL,
53 pygame.K_LSHIFT: pygame.KMOD_LSHIFT,
54 pygame.K_RSHIFT: pygame.KMOD_RSHIFT,
55 }
56
57 def __init__(self, mainwindow, inner_evb):
58 """Initialise the Translator with the windows to which to listen"""
59 self._mainwindow = mainwindow
60 self._inner_evb = inner_evb
61
62 # Enable events
63 # (add instead of set here because the main window is already realized)
64 self._mainwindow.add_events(
65 gtk.gdk.KEY_PRESS_MASK | \
66 gtk.gdk.KEY_RELEASE_MASK | \
67 gtk.gdk.VISIBILITY_NOTIFY_MASK
68 )
69
70 self._inner_evb.set_events(
71 gtk.gdk.POINTER_MOTION_MASK | \
72 gtk.gdk.POINTER_MOTION_HINT_MASK | \
73 gtk.gdk.BUTTON_MOTION_MASK | \
74 gtk.gdk.BUTTON_PRESS_MASK | \
75 gtk.gdk.BUTTON_RELEASE_MASK
76 )
77
78 self._mainwindow.set_flags(gtk.CAN_FOCUS)
79 self._inner_evb.set_flags(gtk.CAN_FOCUS)
80
81 # Callback functions to link the event systems
82 self._mainwindow.connect('unrealize', self._quit_cb)
83 self._mainwindow.connect('visibility_notify_event', self._visibility)
84 self._inner_evb.connect('key_press_event', self._keydown_cb)
85 self._inner_evb.connect('key_release_event', self._keyup_cb)
86 self._inner_evb.connect('button_press_event', self._mousedown_cb)
87 self._inner_evb.connect('button_release_event', self._mouseup_cb)
88 self._inner_evb.connect('motion-notify-event', self._mousemove_cb)
89 self._inner_evb.connect('expose-event', self._expose_cb)
90 self._inner_evb.connect('configure-event', self._resize_cb)
91 self._inner_evb.connect('screen-changed', self._screen_changed_cb)
92
93 # Internal data
94 self.__stopped = False
95 self.__keystate = [0] * 323
96 self.__button_state = [0,0,0]
97 self.__mouse_pos = (0,0)
98 self.__repeat = (None, None)
99 self.__held = set()
100 self.__held_time_left = {}
101 self.__held_last_time = {}
102 self.__held_last_value = {}
103 self.__tick_id = None
104
105 def hook_pygame(self):
106 pygame.key.get_pressed = self._get_pressed
107 pygame.key.set_repeat = self._set_repeat
108 pygame.mouse.get_pressed = self._get_mouse_pressed
109 pygame.mouse.get_pos = self._get_mouse_pos
110
111 def _visibility(self, widget, event):
112 if pygame.display.get_init():
113 pygame.event.post(pygame.event.Event(pygame.VIDEOEXPOSE))
114 return False
115
116 def _expose_cb(self, event, widget):
117 if pygame.display.get_init():
118 pygame.event.post(pygame.event.Event(pygame.VIDEOEXPOSE))
119 return True
120
121 def _resize_cb(self, widget, event):
122 evt = pygame.event.Event(pygame.VIDEORESIZE,
123 size=(event.width,event.height), width=event.width, height=event.height)
124 pygame.event.post(evt)
125 return False # continue processing
126
127 def _screen_changed_cb(self, widget, event):
128 if pygame.display.get_init():
129 pygame.event.post(pygame.event.Event(pygame.VIDEOEXPOSE))
130
131 def _quit_cb(self, data=None):
132 self.__stopped = True
133 pygame.event.post(pygame.event.Event(pygame.QUIT))
134
135 def _keydown_cb(self, widget, event):
136 key = event.hardware_keycode
137 keyval = event.keyval
138 if key in self.__held:
139 return True
140 else:
141 if self.__repeat[0] is not None:
142 self.__held_last_time[key] = pygame.time.get_ticks()
143 self.__held_time_left[key] = self.__repeat[0]
144 self.__held_last_value[key] = keyval
145 self.__held.add(key)
146 return self._keyevent(widget, event, pygame.KEYDOWN)
147
148 def _keyup_cb(self, widget, event):
149 key = event.hardware_keycode
150 if self.__repeat[0] is not None:
151 if key in self.__held:
152 # This is possibly false if set_repeat() is called with a key held
153 del self.__held_time_left[key]
154 del self.__held_last_time[key]
155 del self.__held_last_value[key]
156 self.__held.discard(key)
157
158 return self._keyevent(widget, event, pygame.KEYUP)
159
160 def _keymods(self):
161 mod = 0
162 for key_val, mod_val in self.mod_map.iteritems():
163 mod |= self.__keystate[key_val] and mod_val
164 return mod
165
166 def _keyevent(self, widget, event, type):
167 key = gtk.gdk.keyval_name(event.keyval)
168 if key is None:
169 # No idea what this key is.
170 return False
171
172 keycode = None
173 if key in self.key_trans:
174 keycode = self.key_trans[key]
175 elif hasattr(pygame, 'K_'+key.upper()):
176 keycode = getattr(pygame, 'K_'+key.upper())
177 elif hasattr(pygame, 'K_'+key.lower()):
178 keycode = getattr(pygame, 'K_'+key.lower())
179 elif key == 'XF86Start':
180 # view source request, specially handled...
181 self._mainwindow.view_source()
182 else:
183 print 'Key %s unrecognized' % key
184
185 if keycode is not None:
186 if type == pygame.KEYDOWN:
187 mod = self._keymods()
188 self.__keystate[keycode] = type == pygame.KEYDOWN
189 if type == pygame.KEYUP:
190 mod = self._keymods()
191 ukey = unichr(gtk.gdk.keyval_to_unicode(event.keyval))
192 if ukey == '\000':
193 ukey = ''
194 evt = pygame.event.Event(type, key=keycode, unicode=ukey, mod=mod)
195 self._post(evt)
196
197 return True
198
199 def _get_pressed(self):
200 return self.__keystate
201
202 def _get_mouse_pressed(self):
203 return self.__button_state
204
205 def _mousedown_cb(self, widget, event):
206 self.__button_state[event.button-1] = 1
207 return self._mouseevent(widget, event, pygame.MOUSEBUTTONDOWN)
208
209 def _mouseup_cb(self, widget, event):
210 self.__button_state[event.button-1] = 0
211 return self._mouseevent(widget, event, pygame.MOUSEBUTTONUP)
212
213 def _mouseevent(self, widget, event, type):
214 evt = pygame.event.Event(type, button=event.button, pos=(event.x, event.y))
215 self._post(evt)
216 return True
217
218 def _mousemove_cb(self, widget, event):
219 # From http://www.learningpython.com/2006/07/25/writing-a-custom-widget-using-pygtk/
220 # if this is a hint, then let's get all the necessary
221 # information, if not it's all we need.
222 if event.is_hint:
223 x, y, state = event.window.get_pointer()
224 else:
225 x = event.x
226 y = event.y
227 state = event.state
228
229 rel = (x - self.__mouse_pos[0], y - self.__mouse_pos[1])
230 self.__mouse_pos = (x, y)
231
232 self.__button_state = [
233 state & gtk.gdk.BUTTON1_MASK and 1 or 0,
234 state & gtk.gdk.BUTTON2_MASK and 1 or 0,
235 state & gtk.gdk.BUTTON3_MASK and 1 or 0,
236 ]
237
238 evt = pygame.event.Event(pygame.MOUSEMOTION,
239 pos=self.__mouse_pos, rel=rel, buttons=self.__button_state)
240 self._post(evt)
241 return True
242
243 def _tick_cb(self):
244 cur_time = pygame.time.get_ticks()
245 for key in self.__held:
246 delta = cur_time - self.__held_last_time[key]
247 self.__held_last_time[key] = cur_time
248
249 self.__held_time_left[key] -= delta
250 if self.__held_time_left[key] <= 0:
251 self.__held_time_left[key] = self.__repeat[1]
252 self._keyevent(None, _MockEvent(self.__held_last_value[key]), pygame.KEYDOWN)
253
254 return True
255
256 def _set_repeat(self, delay=None, interval=None):
257 if delay is not None and self.__repeat[0] is None:
258 self.__tick_id = gobject.timeout_add(10, self._tick_cb)
259 elif delay is None and self.__repeat[0] is not None:
260 gobject.source_remove(self.__tick_id)
261 self.__repeat = (delay, interval)
262
263 def _get_mouse_pos(self):
264 return self.__mouse_pos
265
266 def _post(self, evt):
267 try:
268 pygame.event.post(evt)
269 except pygame.error, e:
270 if str(e) == 'Event queue full':
271 print "Event queue full!"
272 pass
273 else:
274 raise e
  
1__version__ = '1.1'
  
1import os
2import gtk
3import gobject
4import pygame
5import event
6
7CANVAS = None
8
9class PygameCanvas(gtk.EventBox):
10
11 """
12 mainwindow is the activity intself.
13 """
14 def __init__(self, mainwindow, pointer_hint = True):
15 gtk.EventBox.__init__(self)
16
17 global CANVAS
18 assert CANVAS == None, "Only one PygameCanvas can be created, ever."
19 CANVAS = self
20
21 # Initialize Events translator before widget gets "realized".
22 self.translator = event.Translator(mainwindow, self)
23
24 self._mainwindow = mainwindow
25
26 self.set_flags(gtk.CAN_FOCUS)
27
28 self._socket = gtk.Socket()
29 self.add(self._socket)
30 self.show_all()
31
32 def run_pygame(self, main_fn):
33 # Run the main loop after a short delay. The reason for the delay is that the
34 # Sugar activity is not properly created until after its constructor returns.
35 # If the Pygame main loop is called from the activity constructor, the
36 # constructor never returns and the activity freezes.
37 gobject.idle_add(self._run_pygame_cb, main_fn)
38
39 def _run_pygame_cb(self, main_fn):
40 assert pygame.display.get_surface() is None, "PygameCanvas.run_pygame can only be called once."
41
42 # Preinitialize Pygame with the X window ID.
43 assert pygame.display.get_init() == False, "Pygame must not be initialized before calling PygameCanvas.run_pygame."
44 os.environ['SDL_WINDOWID'] = str(self._socket.get_id())
45 pygame.init()
46
47 # Restore the default cursor.
48 self._socket.window.set_cursor(None)
49
50 # Initialize the Pygame window.
51 r = self.get_allocation()
52 pygame.display.set_mode((r.width, r.height), pygame.RESIZABLE)
53
54 # Hook certain Pygame functions with GTK equivalents.
55 self.translator.hook_pygame()
56
57 # Run the Pygame main loop.
58 main_fn()
59 return False
60
61 def get_pygame_widget(self):
62 return self._socket
  
1import gtk
2import gobject
3import pygame
4import pygame.event
5
6class _MockEvent(object):
7 def __init__(self, keyval):
8 self.keyval = keyval
9
10class Translator(object):
11 key_trans = {
12 'Alt_L': pygame.K_LALT,
13 'Alt_R': pygame.K_RALT,
14 'Control_L': pygame.K_LCTRL,
15 'Control_R': pygame.K_RCTRL,
16 'Shift_L': pygame.K_LSHIFT,
17 'Shift_R': pygame.K_RSHIFT,
18 'Super_L': pygame.K_LSUPER,
19 'Super_R': pygame.K_RSUPER,
20 'KP_Page_Up' : pygame.K_KP9,
21 'KP_Page_Down' : pygame.K_KP3,
22 'KP_End' : pygame.K_KP1,
23 'KP_Home' : pygame.K_KP7,
24 'KP_Up' : pygame.K_KP8,
25 'KP_Down' : pygame.K_KP2,
26 'KP_Left' : pygame.K_KP4,
27 'KP_Right' : pygame.K_KP6,
28 'numbersign' : pygame.K_HASH,
29 'percent' : ord('%'),
30 'exclam' : pygame.K_EXCLAIM,
31 'asciicircum' : pygame.K_CARET,
32 'parenleft' : pygame.K_LEFTPAREN,
33 'parenright' : pygame.K_RIGHTPAREN,
34 'braceleft' : ord('{'),
35 'braceright' : ord('}'),
36 'bracketleft' : pygame.K_LEFTBRACKET,
37 'bracketright' : pygame.K_RIGHTBRACKET,
38 'apostrophe' : ord('\''),
39 'equal' : pygame.K_EQUALS,
40 'grave' : pygame.K_BACKQUOTE,
41 'Caps_Lock' : pygame.K_CAPSLOCK,
42 'Page_Up' : pygame.K_PAGEUP,
43 'Page_Down' : pygame.K_PAGEDOWN,
44 'Num_Lock' : pygame.K_NUMLOCK,
45 'Bar' : ord('|')
46 }
47
48 mod_map = {
49 pygame.K_LALT: pygame.KMOD_LALT,
50 pygame.K_RALT: pygame.KMOD_RALT,
51 pygame.K_LCTRL: pygame.KMOD_LCTRL,
52 pygame.K_RCTRL: pygame.KMOD_RCTRL,
53 pygame.K_LSHIFT: pygame.KMOD_LSHIFT,
54 pygame.K_RSHIFT: pygame.KMOD_RSHIFT,
55 }
56
57 def __init__(self, mainwindow, inner_evb):
58 """Initialise the Translator with the windows to which to listen"""
59 self._mainwindow = mainwindow
60 self._inner_evb = inner_evb
61
62 # Enable events
63 # (add instead of set here because the main window is already realized)
64 self._mainwindow.add_events(
65 gtk.gdk.KEY_PRESS_MASK | \
66 gtk.gdk.KEY_RELEASE_MASK | \
67 gtk.gdk.VISIBILITY_NOTIFY_MASK
68 )
69
70 self._inner_evb.set_events(
71 gtk.gdk.POINTER_MOTION_MASK | \
72 gtk.gdk.POINTER_MOTION_HINT_MASK | \
73 gtk.gdk.BUTTON_MOTION_MASK | \
74 gtk.gdk.BUTTON_PRESS_MASK | \
75 gtk.gdk.BUTTON_RELEASE_MASK
76 )
77
78 self._mainwindow.set_flags(gtk.CAN_FOCUS)
79 self._inner_evb.set_flags(gtk.CAN_FOCUS)
80
81 # Callback functions to link the event systems
82 self._mainwindow.connect('unrealize', self._quit_cb)
83 self._mainwindow.connect('visibility_notify_event', self._visibility)
84 self._inner_evb.connect('key_press_event', self._keydown_cb)
85 self._inner_evb.connect('key_release_event', self._keyup_cb)
86 self._inner_evb.connect('button_press_event', self._mousedown_cb)
87 self._inner_evb.connect('button_release_event', self._mouseup_cb)
88 self._inner_evb.connect('motion-notify-event', self._mousemove_cb)
89 self._inner_evb.connect('expose-event', self._expose_cb)
90 self._inner_evb.connect('configure-event', self._resize_cb)
91 self._inner_evb.connect('screen-changed', self._screen_changed_cb)
92
93 # Internal data
94 self.__stopped = False
95 self.__keystate = [0] * 323
96 self.__button_state = [0,0,0]
97 self.__mouse_pos = (0,0)
98 self.__repeat = (None, None)
99 self.__held = set()
100 self.__held_time_left = {}
101 self.__held_last_time = {}
102 self.__held_last_value = {}
103 self.__tick_id = None
104
105 def hook_pygame(self):
106 pygame.key.get_pressed = self._get_pressed
107 pygame.key.set_repeat = self._set_repeat
108 pygame.mouse.get_pressed = self._get_mouse_pressed
109 pygame.mouse.get_pos = self._get_mouse_pos
110
111 def _visibility(self, widget, event):
112 if pygame.display.get_init():
113 pygame.event.post(pygame.event.Event(pygame.VIDEOEXPOSE))
114 return False
115
116 def _expose_cb(self, event, widget):
117 if pygame.display.get_init():
118 pygame.event.post(pygame.event.Event(pygame.VIDEOEXPOSE))
119 return True
120
121 def _resize_cb(self, widget, event):
122 evt = pygame.event.Event(pygame.VIDEORESIZE,
123 size=(event.width,event.height), width=event.width, height=event.height)
124 pygame.event.post(evt)
125 return False # continue processing
126
127 def _screen_changed_cb(self, widget, event):
128 if pygame.display.get_init():
129 pygame.event.post(pygame.event.Event(pygame.VIDEOEXPOSE))
130
131 def _quit_cb(self, data=None):
132 self.__stopped = True
133 pygame.event.post(pygame.event.Event(pygame.QUIT))
134
135 def _keydown_cb(self, widget, event):
136 key = event.hardware_keycode
137 keyval = event.keyval
138 if key in self.__held:
139 return True
140 else:
141 if self.__repeat[0] is not None:
142 self.__held_last_time[key] = pygame.time.get_ticks()
143 self.__held_time_left[key] = self.__repeat[0]
144 self.__held_last_value[key] = keyval
145 self.__held.add(key)
146 return self._keyevent(widget, event, pygame.KEYDOWN)
147
148 def _keyup_cb(self, widget, event):
149 key = event.hardware_keycode
150 if self.__repeat[0] is not None:
151 if key in self.__held:
152 # This is possibly false if set_repeat() is called with a key held
153 del self.__held_time_left[key]
154 del self.__held_last_time[key]
155 del self.__held_last_value[key]
156 self.__held.discard(key)
157
158 return self._keyevent(widget, event, pygame.KEYUP)
159
160 def _keymods(self):
161 mod = 0
162 for key_val, mod_val in self.mod_map.iteritems():
163 mod |= self.__keystate[key_val] and mod_val
164 return mod
165
166 def _keyevent(self, widget, event, type):
167 key = gtk.gdk.keyval_name(event.keyval)
168 if key is None:
169 # No idea what this key is.
170 return False
171
172 keycode = None
173 if key in self.key_trans:
174 keycode = self.key_trans[key]
175 elif hasattr(pygame, 'K_'+key.upper()):
176 keycode = getattr(pygame, 'K_'+key.upper())
177 elif hasattr(pygame, 'K_'+key.lower()):
178 keycode = getattr(pygame, 'K_'+key.lower())
179 elif key == 'XF86Start':
180 # view source request, specially handled...
181 self._mainwindow.view_source()
182 else:
183 print 'Key %s unrecognized' % key
184
185 if keycode is not None:
186 if type == pygame.KEYDOWN:
187 mod = self._keymods()
188 self.__keystate[keycode] = type == pygame.KEYDOWN
189 if type == pygame.KEYUP:
190 mod = self._keymods()
191 ukey = unichr(gtk.gdk.keyval_to_unicode(event.keyval))
192 if ukey == '\000':
193 ukey = ''
194 evt = pygame.event.Event(type, key=keycode, unicode=ukey, mod=mod)
195 self._post(evt)
196
197 return True
198
199 def _get_pressed(self):
200 return self.__keystate
201
202 def _get_mouse_pressed(self):
203 return self.__button_state
204
205 def _mousedown_cb(self, widget, event):
206 self.__button_state[event.button-1] = 1
207 return self._mouseevent(widget, event, pygame.MOUSEBUTTONDOWN)
208
209 def _mouseup_cb(self, widget, event):
210 self.__button_state[event.button-1] = 0
211 return self._mouseevent(widget, event, pygame.MOUSEBUTTONUP)
212
213 def _mouseevent(self, widget, event, type):
214 evt = pygame.event.Event(type, button=event.button, pos=(event.x, event.y))
215 self._post(evt)
216 return True
217
218 def _mousemove_cb(self, widget, event):
219 # From http://www.learningpython.com/2006/07/25/writing-a-custom-widget-using-pygtk/
220 # if this is a hint, then let's get all the necessary
221 # information, if not it's all we need.
222 if event.is_hint:
223 x, y, state = event.window.get_pointer()
224 else:
225 x = event.x
226 y = event.y
227 state = event.state
228
229 rel = (x - self.__mouse_pos[0], y - self.__mouse_pos[1])
230 self.__mouse_pos = (x, y)
231
232 self.__button_state = [
233 state & gtk.gdk.BUTTON1_MASK and 1 or 0,
234 state & gtk.gdk.BUTTON2_MASK and 1 or 0,
235 state & gtk.gdk.BUTTON3_MASK and 1 or 0,
236 ]
237
238 evt = pygame.event.Event(pygame.MOUSEMOTION,
239 pos=self.__mouse_pos, rel=rel, buttons=self.__button_state)
240 self._post(evt)
241 return True
242
243 def _tick_cb(self):
244 cur_time = pygame.time.get_ticks()
245 for key in self.__held:
246 delta = cur_time - self.__held_last_time[key]
247 self.__held_last_time[key] = cur_time
248
249 self.__held_time_left[key] -= delta
250 if self.__held_time_left[key] <= 0:
251 self.__held_time_left[key] = self.__repeat[1]
252 self._keyevent(None, _MockEvent(self.__held_last_value[key]), pygame.KEYDOWN)
253
254 return True
255
256 def _set_repeat(self, delay=None, interval=None):
257 if delay is not None and self.__repeat[0] is None:
258 self.__tick_id = gobject.timeout_add(10, self._tick_cb)
259 elif delay is None and self.__repeat[0] is not None:
260 gobject.source_remove(self.__tick_id)
261 self.__repeat = (delay, interval)
262
263 def _get_mouse_pos(self):
264 return self.__mouse_pos
265
266 def _post(self, evt):
267 try:
268 pygame.event.post(evt)
269 except pygame.error, e:
270 if str(e) == 'Event queue full':
271 print "Event queue full!"
272 pass
273 else:
274 raise e
  
1from gettext import gettext as _
2
3import sys
4import gtk
5import pygame
6
7import sugar.activity.activity
8import sugar.graphics.toolbutton
9
10sys.path.append('..') # Import sugargame package from top directory.
11import sugargame.canvas
12
13import TestGame
14
15class TestActivity(sugar.activity.activity.Activity):
16 def __init__(self, handle):
17 super(TestActivity, self).__init__(handle)
18
19 self.paused = False
20
21 # Create the game instance.
22 self.game = TestGame.TestGame()
23
24 # Build the activity toolbar.
25 self.build_toolbar()
26
27 # Build the Pygame canvas.
28 self._pygamecanvas = sugargame.canvas.PygameCanvas(self)
29
30 # Note that set_canvas implicitly calls read_file when resuming from the Journal.
31 self.set_canvas(self._pygamecanvas)
32
33 # Start the game running (self.game.run is called when the activity constructor returns).
34 self._pygamecanvas.run_pygame(self.game.run)
35
36 def build_toolbar(self):
37 stop_play = sugar.graphics.toolbutton.ToolButton('media-playback-stop')
38 stop_play.set_tooltip(_("Stop"))
39 stop_play.set_accelerator(_('<ctrl>space'))
40 stop_play.connect('clicked', self._stop_play_cb)
41
42 toolbar = gtk.Toolbar()
43 toolbar.insert(stop_play, 0)
44
45 toolbox = sugar.activity.activity.ActivityToolbox(self)
46 toolbox.add_toolbar(_("Pygame"), toolbar)
47
48 toolbox.show_all()
49 self.set_toolbox(toolbox)
50
51 def _stop_play_cb(self, button):
52 # Pause or unpause the game.
53 self.paused = not self.paused
54 self.game.set_paused(self.paused)
55
56 # Update the button to show the next action.
57 if self.paused:
58 button.set_icon('media-playback-start')
59 button.set_tooltip(_("Start"))
60 else:
61 button.set_icon('media-playback-stop')
62 button.set_tooltip(_("Stop"))
63
64 def read_file(self, file_path):
65 self.game.read_file(file_path)
66
67 def write_file(self, file_path):
68 self.game.write_file(file_path)
  
1#!/usr/bin/python
2import pygame
3import gtk
4
5class TestGame:
6 def __init__(self):
7 # Set up a clock for managing the frame rate.
8 self.clock = pygame.time.Clock()
9
10 self.x = -100
11 self.y = 100
12
13 self.vx = 10
14 self.vy = 0
15
16 self.paused = False
17
18 def set_paused(self, paused):
19 self.paused = paused
20
21 # Called to save the state of the game to the Journal.
22 def write_file(self, file_path):
23 pass
24
25 # Called to load the state of the game from the Journal.
26 def read_file(self, file_path):
27 pass
28
29 # The main game loop.
30 def run(self):
31 self.running = True
32
33 screen = pygame.display.get_surface()
34
35 while self.running:
36 # Pump GTK messages.
37 while gtk.events_pending():
38 gtk.main_iteration()
39
40 # Pump PyGame messages.
41 for event in pygame.event.get():
42 if event.type == pygame.QUIT:
43 return
44 elif event.type == pygame.VIDEORESIZE:
45 pygame.display.set_mode(event.size, pygame.RESIZABLE)
46
47 # Move the ball
48 if not self.paused:
49 self.x += self.vx
50 if self.x > screen.get_width() + 100:
51 self.x = -100
52
53 self.y += self.vy
54 if self.y > screen.get_height() - 100:
55 self.y = screen.get_height() - 100
56 self.vy = -self.vy
57
58 self.vy += 5;
59
60 # Clear Display
61 screen.fill((255,255,255)) #255 for white
62
63 # Draw the ball
64 pygame.draw.circle(screen, (255,0,0), (self.x, self.y), 100)
65
66 # Flip Display
67 pygame.display.flip()
68
69 # Try to stay at 30 FPS
70 self.clock.tick(30)
71
72# This function is called when the game is run directly from the command line:
73# ./TestGame.py
74def main():
75 pygame.init()
76 pygame.display.set_mode((0, 0), pygame.RESIZABLE)
77 game = TestGame()
78 game.run()
79
80if __name__ == '__main__':
81 main()
  
1<?xml version="1.0" ?><!-- Created with Inkscape (http://www.inkscape.org/) --><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
2 <!ENTITY stroke_color "#ff0000">
3 <!ENTITY fill_color "#000000">
4]><svg height="55" id="svg2" inkscape:output_extension="org.inkscape.output.svg.inkscape" inkscape:version="0.46+devel" sodipodi:docname="activity-generic.svg" sodipodi:version="0.32" style="" version="1.0" width="55" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg">
5 <metadata id="metadata20">
6 <rdf:RDF>
7 <cc:Work rdf:about="">
8 <dc:format>image/svg+xml</dc:format>
9 <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
10 </cc:Work>
11 </rdf:RDF>
12 </metadata>
13 <sodipodi:namedview bordercolor="#666666" borderopacity="1" gridtolerance="10" guidetolerance="10" id="namedview18" inkscape:current-layer="svg2" inkscape:cx="-15.963983" inkscape:cy="27.5" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-height="1125" inkscape:window-width="1920" inkscape:window-x="0" inkscape:window-y="25" inkscape:zoom="4.2909091" objecttolerance="10" pagecolor="#ffffff" showgrid="true">
14 <inkscape:grid id="grid796" type="xygrid"/>
15 </sodipodi:namedview>
16 <defs id="defs4" style="">
17 <inkscape:perspective id="perspective22" inkscape:persp3d-origin="27.5 : 18.333333 : 1" inkscape:vp_x="0 : 27.5 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="55 : 27.5 : 1" sodipodi:type="inkscape:persp3d"/>
18 </defs>
19 <g id="layer1" style="fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-opacity:1;stroke-width:3.002554;stroke-miterlimit:4;stroke-dasharray:none" transform="matrix(1.1689037,0,0,1.1624538,-4.6448521,-4.3634813)">
20 <rect height="35" id="rect16" style="fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:3.002554;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" width="35" x="10" y="10"/>
21 <text id="text790" style="font-size:40px;font-style:normal;font-weight:normal;fill:&stroke_color;;fill-opacity:1;stroke:none;stroke-opacity:1;font-family:Bitstream Vera Sans;stroke-width:3.00255399999999995;stroke-miterlimit:4;stroke-dasharray:none" x="17.911133" xml:space="preserve" y="40"><tspan id="tspan792" style="font-size:36px;fill:&stroke_color;;fill-opacity:1;stroke:none;stroke-opacity:1;stroke-width:3.00255399999999995;stroke-miterlimit:4;stroke-dasharray:none" x="17.911133" y="40">?</tspan></text>
22 </g>
23</svg>
  
1[Activity]
2name = SugargameTest
3service_name = org.sugarlabs.SugargameTest
4class = TestActivity.TestActivity
5icon = activity-generic
6activity_version = 1
  
1<?xml version="1.0" encoding="UTF-8"?>
2<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
3 <mime-type type="application/x-physics-activity">
4 <comment xml:lang="en">Physics Activity</comment>
5 <glob pattern="*.physics"/>
6 </mime-type>
7</mime-info>
  
1#!/usr/bin/env python
2from sugar.activity import bundlebuilder
3bundlebuilder.start()