Finally, some OpenGL work.
[krufty_fps.git] / pygame_gui / DerCrapGUI.py
blob4fa4883dd55f7323ce4e1170d5f9d5e5fa99d364
1 #!/usr/bin/python
3 import os, sys
4 from os import *
5 from os.path import *
7 from xml.dom.minidom import parse, parseString
9 from zipfile import *
11 import pygame
12 from pygame import *
14 import StringIO
15 from string import *
17 import copy
19 import time
21 import array
23 FONT_NAME = 'serif'
24 FONT_SIZE = 30
25 FONT_COLOR = (255, 255, 255)
27 BLINK_DELAY = 1.5
28 BLINK_SPEED = .2
30 class GUISystem:
32 def __init__(self, gui_def, theme):
34 assert is_zipfile(theme)
35 assert exists(gui_def)
37 self.zipfile = ZipFile(theme)
39 self.definitions = self.parse_gui_def(gui_def)
41 pygame.init()
43 assert pygame.font.get_init()
45 self.the_font = pygame.font.SysFont(FONT_NAME, FONT_SIZE)
47 self.images = {}
49 assert self.getImages()
51 self.widgets = []
53 self.keys = {}
54 self.last_time = -1
56 def parse_gui_def(self, gui_def):
57 results = {}
59 dom = parse(gui_def)
61 if dom.childNodes[0].nodeName == 'widgets':
63 widgets = {}
65 for node in dom.childNodes[0].childNodes:
67 image_list = []
69 if node.nodeName == 'images':
71 for sub_node in node.childNodes:
72 if sub_node.nodeName == 'image':
74 image = {'filename': '', name: ''}
76 for sub_sub_node in sub_node.childNodes:
78 if sub_sub_node.nodeName == 'filename':
79 image['filename'] = sub_sub_node.childNodes[0].nodeValue
80 if sub_sub_node.nodeName == 'name':
81 image['name'] = sub_sub_node.childNodes[0].nodeValue
83 if 'posix' in image:
84 del image['posix']
85 image_list.append(image)
87 results['image_list'] = image_list
89 if node.nodeName == 'widget':
91 widget = {}
93 widget['parameters'] = {}
94 widget['parts'] = {}
95 widget['behaviors'] = {}
97 for sub_node in node.childNodes:
98 if sub_node.nodeName == 'name' and len(sub_node.childNodes):
99 widget['name'] = sub_node.childNodes[0].nodeValue
101 if sub_node.nodeName == 'parameter':
103 parameter = {}
104 parameter['name'] = sub_node.attributes['name'].value
106 if sub_node.attributes.has_key('type'):
107 if sub_node.attributes['type'].value == 'int':
108 try:
109 widget['parameters'][parameter['name']] = int(sub_node.attributes['default'].value)
110 except:
111 widget['parameters'][parameter['name']] = sub_node.attributes['default'].value
113 else:
114 widget['parameters'][parameter['name']] = sub_node.attributes['default'].value
116 if sub_node.nodeName == 'part':
118 part_name = sub_node.getElementsByTagName('name')[0].childNodes[0].nodeValue
119 widget['parts'][part_name] = {}
121 for sub_sub_node in sub_node.childNodes:
123 if sub_sub_node.nodeName == 'type':
124 widget['parts'][part_name]['type'] = sub_sub_node.childNodes[0].nodeValue.encode()
125 if widget['parts'][part_name]['type'] == 'text':
126 widget['parts'][part_name]['prerender'] = ''
127 widget['parts'][part_name]['old_text'] = ''
129 if sub_sub_node.nodeName == 'source':
130 widget['parts'][part_name]['source'] = sub_sub_node.childNodes[0].nodeValue.encode()
132 if sub_sub_node.nodeName == 'position':
133 widget['parts'][part_name]['position'] = sub_sub_node.childNodes[0].nodeValue.encode()
135 if sub_sub_node.nodeName == 'size':
136 widget['parts'][part_name]['size'] = sub_sub_node.childNodes[0].nodeValue.encode()
138 if sub_sub_node.nodeName == 'zindex':
139 widget['parts'][part_name]['zindex'] = int(sub_sub_node.childNodes[0].nodeValue.encode())
141 if not widget['parts'][part_name].has_key('zindex'):
142 widget['parts'][part_name]['zindex'] = 1
144 if sub_node.nodeName == 'behavior':
146 event_type = sub_node.getElementsByTagName('on_event')[0].childNodes[0].nodeValue
147 the_do = sub_node.getElementsByTagName('do')[0].childNodes[0].nodeValue
149 widget['behaviors'][event_type] = the_do
151 widgets[widget['name']] = widget
153 results['widgets'] = widgets
155 return results
157 def getImages(self):
159 image_list = self.definitions['image_list']
160 name_list = []
162 name_list = self.zipfile.namelist()
164 for image in image_list:
166 if image['filename'] not in name_list:
167 return 0
169 else:
170 the_string_io = StringIO.StringIO()
171 print >>the_string_io, self.zipfile.read(image['filename'])
172 the_string_io.seek(0)
174 self.images[image['name']] = pygame.image.load(the_string_io).convert_alpha()
176 return 1
178 def event(self, the_event):
180 new_event = self.convertEvent(the_event)
182 if new_event['type'] == 'NOEVENT':
184 if self.last_time == -1:
185 self.last_time = time.time()
187 else:
189 temp_time = time.time()
191 for key in self.keys:
193 if not self.keys[key].has_key('first_time'):
194 if temp_time - BLINK_SPEED > self.last_time:
195 self.last_time = temp_time
196 self.focus.event({'type': 'KEYSTILLDOWN', 'data': self.keys[key]})
197 else:
198 if temp_time - (BLINK_SPEED + BLINK_DELAY) > self.last_time:
200 self.last_time = temp_time
201 del self.keys[key]['first_time']
202 self.focus.event({'type': 'KEYSTILLDOWN', 'data': self.keys[key]})
204 if not new_event['type'].find('MOUSE') == -1:
206 for widget in self.widgets:
208 widget_rect = widget.getRect()
209 if widget_rect.collidepoint(new_event['data']['pos']):
210 if new_event['type'] != 'MOUSEMOTION':
211 self.focus = widget
212 self.focus.event(new_event)
213 else:
214 if new_event['type'] == 'KEYDOWN':
215 self.keys[new_event['data']['key']] = new_event['data']
216 self.keys[new_event['data']['key']]['first_time'] = 1
218 if new_event['type'] == 'KEYUP' and self.keys.has_key(new_event['data']['key']):
219 del self.keys[new_event['data']['key']]
221 self.focus.event(new_event)
223 return
225 def convertEvent(self, e):
227 data = {}
229 if e.type == QUIT:
230 data['none'] = ''
232 if e.type == ACTIVEEVENT:
233 data['gain'] = e.gain
234 data['state'] = e.state
236 if e.type == KEYDOWN:
237 data['unicode'] = e.unicode
238 data['key'] = e.key
239 data['mod'] = e.mod
241 if e.type == KEYUP:
242 data['key'] = e.key
243 data['mod'] = e.mod
245 if e.type == MOUSEMOTION:
246 data['pos'] = e.pos
247 data['rel'] = e.rel
248 data['buttons'] = e.buttons
250 if e.type == MOUSEBUTTONUP:
251 data['pos'] = e.pos
252 data['button'] = e.button
254 if e.type == MOUSEBUTTONDOWN:
255 data['pos'] = e.pos
256 data['button'] = e.button
258 if e.type == JOYAXISMOTION:
259 data['joy'] = e.joy
260 data['axis'] = e.axis
261 data['value'] = e.value
263 if e.type == JOYBALLMOTION:
264 data['joy'] = e.joy
265 data['ball'] = e.ball
266 data['rel'] = e.rel
268 if e.type == JOYHATMOTION:
269 data['joy'] = e.joy
270 data['hat'] = e.hat
271 data['value'] = e.value
273 if e.type == JOYBUTTONUP:
274 data['joy'] = e.joy
275 data['button'] = e.button
277 if e.type == JOYBUTTONDOWN:
278 data['joy'] = e.joy
279 data['button'] = e.button
281 if e.type == VIDEORESIZE:
282 data['size'] = e.size
283 data['w'] = e.w
284 data['h'] = e.h
286 if e.type == VIDEOEXPOSE:
287 data['none'] = ''
289 if e.type == USEREVENT:
290 data['code'] = e.code
292 type = ''
294 if e.type == QUIT: type = "QUIT"
295 if e.type == NOEVENT: type = "NOEVENT"
296 if e.type == ACTIVEEVENT: type = "ACTIVEEVENT"
297 if e.type == KEYDOWN: type = "KEYDOWN"
298 if e.type == KEYUP: type = "KEYUP"
299 if e.type == MOUSEMOTION : type = "MOUSEMOTION"
300 if e.type == MOUSEBUTTONUP: type = "MOUSEBUTTONUP"
301 if e.type == MOUSEBUTTONDOWN: type = "MOUSEBUTTONDOWN"
302 if e.type == JOYAXISMOTION: type = "JOYAXISMOTION"
303 if e.type == JOYBALLMOTION: type = "JOYBALLMOTION"
304 if e.type == JOYHATMOTION: type = "JOYHATMOTION"
305 if e.type == JOYBUTTONUP: type = "JOYBUTTONUP"
306 if e.type == JOYBUTTONDOWN: type = "JOYBUTTONDOWN"
307 if e.type == VIDEORESIZE: type = "VIDEORESIZE"
308 if e.type == VIDEOEXPOSE: type = "VIDEOEXPOSE"
309 if e.type == USEREVENT: type = "USEREVENT"
311 new_event = {}
313 new_event['type'] = type
314 new_event['data'] = data
316 return new_event
318 def draw(self, dest_surface):
320 for widget in self.widgets:
322 if widget.params['parameters']['visible']:
323 widget.draw(dest_surface)
325 return
327 def makeWidget(self, widget_name, params):
329 if self.definitions['widgets'].has_key(widget_name):
331 for param in self.definitions['widgets'][widget_name]['parameters']:
332 if not params.has_key(param):
333 if self.definitions['widgets'][widget_name]['parameters'][param] == 'kill':
334 print "GUISystem.makeWidget() Not all required parameters were passed."
335 assert 0
336 else:
337 params[param] = self.definitions['widgets'][widget_name]['parameters'][param]
339 new_params = copy.deepcopy(self.definitions['widgets'][widget_name])
340 new_params['parameters'] = params
342 the_widget = Widget(self, widget_name, new_params)
344 self.widgets.append(the_widget)
346 if len(self.widgets) == 1:
347 self.focus = the_widget
349 return the_widget
351 class Widget:
353 def __init__(self, the_gui_system, widget_name, params):
355 self.name = widget_name
356 self.params = params
357 self.the_gui_system = the_gui_system
359 assert self.params['parameters'].has_key('x')
360 assert self.params['parameters'].has_key('y')
362 if not self.params['parameters'].has_key('visible'):
363 self.params['parameters']['visible'] = 1
365 self.callbacks = {}
367 return
369 def move(self, (new_x, new_y)):
371 self.params['parameters']['x'], self.params['parameters']['y'] = new_x, new_y
373 return
375 def hide(self):
377 self.params['parameters']['visible'] = 0
379 return
381 def show(self):
383 self.params['parameters']['visible'] = 1
385 return
387 def connect(self, event, function, params={}):
389 self.callbacks[event] = {'function': function, 'params': params}
391 return
393 def getRect(self):
395 coords = (self.params['parameters']['x'], self.params['parameters']['y'])
396 dimensions = (self.params['parameters']['width'], self.params['parameters']['height'])
398 return pygame.Rect(coords, dimensions)
400 def event(self, the_event):
402 if self.params['behaviors'].has_key(the_event['type']):
404 the_value = self.params['behaviors'][the_event['type']]
406 try:
407 exec(the_value)
408 except:
409 print "Widget.event(): Error running behavior."
411 return
413 def setPart(self, old_part, new_part):
415 self.params['parts'][old_part]['source'] = new_part
416 return
418 def raiseEvent(self, the_event, parameters={}):
420 if not self.callbacks.has_key(the_event):
421 return
423 the_function = self.callbacks[the_event]['function']
425 try:
426 the_function(self.callbacks[the_event]['params'], parameters)
427 except:
428 print "Widget.raiseEvent(): Error in callback."
430 return
432 def draw(self, dest_surface):
434 code = ''
436 for image in self.the_gui_system.images:
438 code = ''.join([code, '\n', image, ' = self.the_gui_system.images["', image, '"]'])
440 try:
441 exec(code)
442 except:
443 assert 0
445 zindex_list = []
446 for part in self.params['parts']:
447 if not self.params['parts'][part] in zindex_list:
448 zindex_list.append(self.params['parts'][part]['zindex'])
449 zindex_list.sort()
451 for zindex in zindex_list:
452 for part in self.params['parts']:
454 if self.params['parts'][part]['type'] == 'text':
456 # here be dragons
457 try:
458 exec(''.join(['if self.params["parts"][part]["old_text"] != self.params["parameters"][self.params["parts"][part]["source"]]:\n ', part, ' = self.the_gui_system.the_font.render(self.params["parameters"][self.params["parts"][part]["source"]], FONT_SIZE, FONT_COLOR)\n the_source = ', part, '\n self.params["parts"][part]["prerender"] = ', part, '\n self.params["parts"][part]["old_text"] = self.params["parameters"][self.params["parts"][part]["source"]]\nelse:\n the_source = self.params["parts"][part]["prerender"]\n', part, ' = the_source']))
459 except:
460 assert 0
462 width = self.params['parameters']['width']
463 height = self.params['parameters']['height']
465 position = eval(self.params['parts'][part]['position'])
466 size = eval(self.params['parts'][part]['size'])
468 position = [position[0], position[1]]
470 position[0] += self.params['parameters']['x']
471 position[1] += self.params['parameters']['y']
473 if self.params['parts'][part]['zindex'] == zindex:
474 if self.params['parts'][part]['type'] == 'image':
476 if size[0] > 0 and size[1] > 0:
477 the_source = pygame.transform.scale(self.the_gui_system.images[self.params['parts'][part]['source']], size)
478 dest_surface.blit(the_source, position)
480 if self.params['parts'][part]['type'] == 'text':
482 dest_surface.blit(the_source, position, pygame.Rect((0, 0), size))
484 if self.params['parts'][part]['type'] == 'widget':
486 pass # implement nested widgets
488 return
490 # end