Some GUI work.
[krufty_fps.git] / pygame_gui / DerGUI.py
blob76db65bd2fd59d368062be4cfb64be16c0cd733b
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 = 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 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')
361 assert self.params['parameters'].has_key('width')
362 assert self.params['parameters'].has_key('height')
364 if not self.params['parameters'].has_key('visible'):
365 self.params['parameters']['visible'] = 1
367 self.surf = pygame.Surface((self.params['parameters']['width'], self.params['parameters']['height']), SRCALPHA)
368 self.surf.convert_alpha()
370 self.callbacks = {}
372 return
374 def move(self, (new_x, new_y)):
376 self.params['parameters']['x'], self.params['parameters']['y'] = new_x, new_y
378 return
380 def hide(self):
382 self.params['parameters']['visible'] = 0
384 return
386 def show(self):
388 self.params['parameters']['visible'] = 1
390 return
392 def connect(self, event, function, params={}):
394 self.callbacks[event] = {'function': function, 'params': params}
396 return
398 def getRect(self):
400 coords = (self.params['parameters']['x'], self.params['parameters']['y'])
401 dimensions = (self.params['parameters']['width'], self.params['parameters']['height'])
403 return pygame.Rect(coords, dimensions)
405 def event(self, the_event):
407 if self.params['behaviors'].has_key(the_event['type']):
409 the_value = self.params['behaviors'][the_event['type']]
411 #try:
412 exec(the_value)
413 #except:
414 # print "Widget.event(): Error running behavior."
416 return
418 def setPart(self, old_part, new_part):
420 self.params['parts'][old_part]['source'] = new_part
421 return
423 def raiseEvent(self, the_event, parameters={}):
425 if not self.callbacks.has_key(the_event):
426 return
428 the_function = self.callbacks[the_event]['function']
430 try:
431 the_function(self.callbacks[the_event]['params'], parameters)
432 except:
433 print "Widget.raiseEvent(): Error in callback."
435 return
437 def draw(self, dest_surface):
439 code = ''
441 for image in self.the_gui_system.images:
442 code = ''.join([code, '\n', image, ' = self.the_gui_system.images["', image,'"]'])
444 try:
445 exec(code)
446 except:
447 assert 0
449 width = self.params['parameters']['width']
450 height = self.params['parameters']['height']
452 zindex_list = []
453 for part in self.params['parts']:
454 if not self.params['parts'][part]['zindex'] in zindex_list:
455 zindex_list.append(self.params['parts'][part]['zindex'])
457 if not self.params['parts'][part].has_key('old_text'):
458 self.params['parts'][part]['old_text'] = ''
460 zindex_list.sort()
462 self.surf.fill(pygame.color.Color('0x00000000'))
464 for zindex in zindex_list:
465 for part in self.params['parts']:
467 cur_part = self.params['parts'][part]
469 # here be dragons
470 if cur_part['type'].find('text') != -1:
471 #try:
472 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"]], False, 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']))
473 #except:
474 #assert 0
476 position = eval(cur_part['position'])
477 size = eval(cur_part['size'])
479 position = [position[0], position[1]]
481 if cur_part['zindex'] == zindex:
483 if cur_part['type'] == 'image':
484 the_source = pygame.transform.scale(self.the_gui_system.images[cur_part['source']], size)
485 self.surf.blit(the_source, position)
487 if cur_part['type'] == 'text':
488 the_source.convert_alpha(dest_surface)
489 self.surf.blit(the_source, position)
491 if cur_part['type'] == 'text:direct':
492 position = [position[0] + self.params['parameters']['x'],
493 position[1] + self.params['parameters']['y']]
494 the_source.convert()
495 the_source.set_colorkey((0, 0, 0))
496 dest_surface.blit(the_source, position)
498 if cur_part['type'] == 'widget':
499 pass # implement
501 self.surf.convert_alpha(dest_surface)
503 print "Debug, bitsize", self.surf.get_bytesize(), "flags", self.surf.get_flags()
504 dest_surface.blit(self.surf, (self.params['parameters']['x'], self.params['parameters']['y']))
505 return
507 # end