Fixed a little GUI error.
[krufty_fps.git] / pygame_gui / DerGUI.py
blob3c59c137723f449ece6024c18e0c2e60e7ac109d
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 = 20
25 FONT_COLOR = (255, 255, 255)
27 BLINK_DELAY = 3.0
28 BLINK_SPEED = .05
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 self.hit = 0
58 def parse_gui_def(self, gui_def):
59 results = {}
61 dom = parse(gui_def)
63 if dom.childNodes[0].nodeName == 'widgets':
65 widgets = {}
67 for node in dom.childNodes[0].childNodes:
69 image_list = []
71 if node.nodeName == 'images':
73 for sub_node in node.childNodes:
74 if sub_node.nodeName == 'image':
76 image = {'filename': '', name: ''}
78 for sub_sub_node in sub_node.childNodes:
80 if sub_sub_node.nodeName == 'filename':
81 image['filename'] = sub_sub_node.childNodes[0].nodeValue
82 if sub_sub_node.nodeName == 'name':
83 image['name'] = sub_sub_node.childNodes[0].nodeValue
85 if 'posix' in image:
86 del image['posix']
87 image_list.append(image)
89 results['image_list'] = image_list
91 if node.nodeName == 'widget':
93 widget = {}
95 widget['parameters'] = {'direct': 0}
96 widget['parts'] = {}
97 widget['behaviors'] = {}
99 for sub_node in node.childNodes:
100 if sub_node.nodeName == 'name' and len(sub_node.childNodes):
101 widget['name'] = sub_node.childNodes[0].nodeValue
103 if sub_node.nodeName == 'parameter':
105 parameter = {}
106 parameter['name'] = sub_node.attributes['name'].value
108 if sub_node.attributes.has_key('type'):
109 if sub_node.attributes['type'].value == 'int':
110 try:
111 widget['parameters'][parameter['name']] = int(sub_node.attributes['default'].value)
112 except:
113 widget['parameters'][parameter['name']] = sub_node.attributes['default'].value
115 else:
116 widget['parameters'][parameter['name']] = sub_node.attributes['default'].value
118 if sub_node.nodeName == 'part':
120 part_name = sub_node.getElementsByTagName('name')[0].childNodes[0].nodeValue
121 widget['parts'][part_name] = {}
123 for sub_sub_node in sub_node.childNodes:
125 if sub_sub_node.nodeName == 'type':
126 widget['parts'][part_name]['type'] = sub_sub_node.childNodes[0].nodeValue.encode()
127 if widget['parts'][part_name]['type'].find(':direct') != -1:
128 widget['parameters']['direct'] = 1
129 if widget['parts'][part_name]['type'] == 'text':
130 widget['parts'][part_name]['prerender'] = ''
131 widget['parts'][part_name]['old_text'] = ''
133 if sub_sub_node.nodeName == 'source':
134 widget['parts'][part_name]['source'] = sub_sub_node.childNodes[0].nodeValue.encode()
136 if sub_sub_node.nodeName == 'position':
137 widget['parts'][part_name]['position'] = sub_sub_node.childNodes[0].nodeValue.encode()
139 if sub_sub_node.nodeName == 'size':
140 widget['parts'][part_name]['size'] = sub_sub_node.childNodes[0].nodeValue.encode()
142 if sub_sub_node.nodeName == 'zindex':
143 widget['parts'][part_name]['zindex'] = int(sub_sub_node.childNodes[0].nodeValue.encode())
145 if not widget['parts'][part_name].has_key('zindex'):
146 widget['parts'][part_name]['zindex'] = 1
148 if sub_node.nodeName == 'behavior':
150 event_type = sub_node.getElementsByTagName('on_event')[0].childNodes[0].nodeValue
151 the_do = sub_node.getElementsByTagName('do')[0].childNodes[0].nodeValue
153 widget['behaviors'][event_type] = the_do
155 widgets[widget['name']] = widget
157 results['widgets'] = widgets
159 return results
161 def getImages(self):
163 image_list = self.definitions['image_list']
164 name_list = []
166 name_list = self.zipfile.namelist()
168 for image in image_list:
170 if image['filename'] not in name_list:
171 return 0
173 else:
174 the_string_io = StringIO.StringIO()
175 print >>the_string_io, self.zipfile.read(image['filename'])
176 the_string_io.seek(0)
178 self.images[image['name']] = pygame.image.load(the_string_io).convert_alpha()
180 return 1
182 def event(self, the_event):
184 if not len(self.widgets):
185 return
187 new_event = self.convertEvent(the_event)
188 count = 0
190 if new_event['type'] == 'NOEVENT':
192 if self.last_time == -1:
193 self.last_time = time.time()
195 else:
197 temp_time = time.time()
199 for key in self.keys:
201 if not self.keys[key].has_key('first_time'):
202 if temp_time - BLINK_SPEED > self.last_time:
203 self.last_time = temp_time
204 self.focus.event({'type': 'KEYSTILLDOWN', 'data': self.keys[key]})
205 count += 1
206 else:
207 if temp_time - (BLINK_SPEED + BLINK_DELAY) > self.last_time:
209 self.last_time = temp_time
210 del self.keys[key]['first_time']
211 self.focus.event({'type': 'KEYSTILLDOWN', 'data': self.keys[key]})
212 count += 1
214 if not new_event['type'].find('MOUSE') == -1:
216 for widget in self.widgets:
218 widget_rect = widget.getRect()
219 if new_event['type'] != 'MOUSEBUTTONUP':
220 if widget_rect.collidepoint(new_event['data']['pos']):
221 if new_event['type'] != 'MOUSEMOTION' and widget.is_visible():
222 self.focus = widget
223 self.focus.event(new_event)
224 count += 1
225 self.hit = 1
226 else:
227 if self.hit:
228 self.focus.event(new_event)
229 count += 1
230 self.hit = 0
231 else:
232 if new_event['type'] == 'KEYDOWN':
233 self.keys[new_event['data']['key']] = new_event['data']
234 self.keys[new_event['data']['key']]['first_time'] = 1
236 if new_event['type'] == 'KEYUP' and self.keys.has_key(new_event['data']['key']):
237 del self.keys[new_event['data']['key']]
239 self.focus.event(new_event)
241 return count
243 def convertEvent(self, e):
245 data = {}
247 if e.type == QUIT:
248 data['none'] = ''
250 if e.type == ACTIVEEVENT:
251 data['gain'] = e.gain
252 data['state'] = e.state
254 if e.type == KEYDOWN:
255 data['unicode'] = e.unicode
256 data['key'] = e.key
257 data['mod'] = e.mod
259 if e.type == KEYUP:
260 data['key'] = e.key
261 data['mod'] = e.mod
263 if e.type == MOUSEMOTION:
264 data['pos'] = e.pos
265 data['rel'] = e.rel
266 data['buttons'] = e.buttons
268 if e.type == MOUSEBUTTONUP:
269 data['pos'] = e.pos
270 data['button'] = e.button
272 if e.type == MOUSEBUTTONDOWN:
273 data['pos'] = e.pos
274 data['button'] = e.button
276 if e.type == JOYAXISMOTION:
277 data['joy'] = e.joy
278 data['axis'] = e.axis
279 data['value'] = e.value
281 if e.type == JOYBALLMOTION:
282 data['joy'] = e.joy
283 data['ball'] = e.ball
284 data['rel'] = e.rel
286 if e.type == JOYHATMOTION:
287 data['joy'] = e.joy
288 data['hat'] = e.hat
289 data['value'] = e.value
291 if e.type == JOYBUTTONUP:
292 data['joy'] = e.joy
293 data['button'] = e.button
295 if e.type == JOYBUTTONDOWN:
296 data['joy'] = e.joy
297 data['button'] = e.button
299 if e.type == VIDEORESIZE:
300 data['size'] = e.size
301 data['w'] = e.w
302 data['h'] = e.h
304 if e.type == VIDEOEXPOSE:
305 data['none'] = ''
307 if e.type == USEREVENT:
308 data['code'] = e.code
310 type = ''
312 if e.type == QUIT: type = "QUIT"
313 if e.type == NOEVENT: type = "NOEVENT"
314 if e.type == ACTIVEEVENT: type = "ACTIVEEVENT"
315 if e.type == KEYDOWN: type = "KEYDOWN"
316 if e.type == KEYUP: type = "KEYUP"
317 if e.type == MOUSEMOTION : type = "MOUSEMOTION"
318 if e.type == MOUSEBUTTONUP: type = "MOUSEBUTTONUP"
319 if e.type == MOUSEBUTTONDOWN: type = "MOUSEBUTTONDOWN"
320 if e.type == JOYAXISMOTION: type = "JOYAXISMOTION"
321 if e.type == JOYBALLMOTION: type = "JOYBALLMOTION"
322 if e.type == JOYHATMOTION: type = "JOYHATMOTION"
323 if e.type == JOYBUTTONUP: type = "JOYBUTTONUP"
324 if e.type == JOYBUTTONDOWN: type = "JOYBUTTONDOWN"
325 if e.type == VIDEORESIZE: type = "VIDEORESIZE"
326 if e.type == VIDEOEXPOSE: type = "VIDEOEXPOSE"
327 if e.type == USEREVENT: type = "USEREVENT"
329 new_event = {}
331 new_event['type'] = type
332 new_event['data'] = data
334 return new_event
336 def draw(self, dest_surface):
338 for widget in self.widgets:
340 if widget.params['parameters']['visible']:
341 widget.draw(dest_surface)
343 return
345 def makeWidget(self, widget_name, nparams):
347 params = copy.deepcopy(nparams)
349 if self.definitions['widgets'].has_key(widget_name):
351 for param in self.definitions['widgets'][widget_name]['parameters']:
352 if not params.has_key(param):
353 if self.definitions['widgets'][widget_name]['parameters'][param] == 'kill':
354 print "GUISystem.makeWidget() Not all required parameters were passed."
355 assert 0
356 else:
357 params[param] = self.definitions['widgets'][widget_name]['parameters'][param]
359 new_params = copy.deepcopy(self.definitions['widgets'][widget_name])
360 new_params['parameters'] = params
362 the_widget = Widget(self, widget_name, new_params)
364 self.widgets.append(the_widget)
366 if len(self.widgets) == 1:
367 self.focus = the_widget
369 return the_widget
371 class Widget:
373 def __init__(self, the_gui_system, widget_name, params):
375 self.name = widget_name
376 self.params = params
377 self.the_gui_system = the_gui_system
379 assert self.params['parameters'].has_key('x')
380 assert self.params['parameters'].has_key('y')
381 assert self.params['parameters'].has_key('width')
382 assert self.params['parameters'].has_key('height')
384 if not self.params['parameters'].has_key('visible'):
385 self.params['parameters']['visible'] = 1
387 self.surf = pygame.Surface((int(self.params['parameters']['width']), int(self.params['parameters']['height'])), SRCALPHA)
388 self.surf.convert_alpha()
390 self.callbacks = {}
392 return
394 def move(self, (new_x, new_y)):
396 self.params['parameters']['x'], self.params['parameters']['y'] = new_x, new_y
398 return
400 def hide(self):
402 self.params['parameters']['visible'] = 0
404 return
406 def show(self):
408 self.params['parameters']['visible'] = 1
410 return
412 def is_visible(self):
414 return self.params['parameters']['visible']
416 def connect(self, event, function, params={}):
418 self.callbacks[event] = {'function': function, 'params': params}
420 return
422 def getRect(self):
424 coords = (self.params['parameters']['x'], self.params['parameters']['y'])
425 dimensions = (self.params['parameters']['width'], self.params['parameters']['height'])
427 return pygame.Rect(coords, dimensions)
429 def event(self, the_event):
431 if self.params['behaviors'].has_key(the_event['type']):
433 the_value = self.params['behaviors'][the_event['type']]
435 #try:
436 exec(the_value)
437 #except:
438 #print "Widget.event(): Error running behavior."
440 return
442 def setPart(self, old_part, new_part):
444 self.params['parts'][old_part]['source'] = new_part
445 return
447 def raiseEvent(self, the_event, parameters={}):
449 if not self.callbacks.has_key(the_event):
450 return
452 the_function = self.callbacks[the_event]['function']
454 #try:
455 the_function(self.callbacks[the_event]['params'], parameters)
456 #except:
457 # print "Widget.raiseEvent(): Error in callback."
459 return
461 def draw(self, dest_surface):
463 code = ''
465 for image in self.the_gui_system.images:
466 code = ''.join([code, '\n', image, ' = self.the_gui_system.images["', image,'"]'])
468 try:
469 exec(code)
470 except:
471 assert 0
473 width = self.params['parameters']['width']
474 height = self.params['parameters']['height']
476 zindex_list = []
477 for part in self.params['parts']:
478 if not self.params['parts'][part]['zindex'] in zindex_list:
479 zindex_list.append(self.params['parts'][part]['zindex'])
481 if not self.params['parts'][part].has_key('old_text'):
482 self.params['parts'][part]['old_text'] = ''
484 zindex_list.sort()
486 #self.surf.fill(pygame.color.Color('0x00000000'))
488 for zindex in zindex_list:
489 for part in self.params['parts']:
491 cur_part = self.params['parts'][part]
493 # here be dragons
494 if cur_part['type'].find('text') != -1:
495 try:
496 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"]], True, FONT_COLOR).convert_alpha(self.surf)\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']))
497 except:
498 assert 0
500 position = list(eval(cur_part['position']))
501 size = list(eval(cur_part['size']))
503 for i in size:
504 size[size.index(i)] = int(i)
506 position = [position[0], position[1]]
508 if cur_part['zindex'] == zindex:
510 if cur_part['type'] == 'image':
511 the_source = pygame.transform.scale(self.the_gui_system.images[cur_part['source']], size)
512 self.surf.blit(the_source, position)
514 if cur_part['type'] == 'text':
515 the_source.convert_alpha(dest_surface)
516 self.surf.blit(the_source, position)
518 if cur_part['type'] == 'text:direct':
519 position = [position[0] + self.params['parameters']['x'],
520 position[1] + self.params['parameters']['y']]
521 dest_surface.blit(the_source, position)
523 if cur_part['type'] == 'widget':
524 pass # implement
526 if self.params['parameters'].has_key('direct') and self.params['parameters']['direct']:
527 pass
528 else:
529 dest_surface.blit(self.surf, (self.params['parameters']['x'], self.params['parameters']['y']))
530 return
532 # end