Mercurial > boomslang
comparison pyntnclick/tools/rect_drawer.py @ 854:79b5c1be9a5e default tip
Remove pyntnclick, it's its own library, now
author | Stefano Rivera <stefano@rivera.za.net> |
---|---|
date | Sat, 21 Jun 2014 22:06:09 +0200 |
parents | f95830b58336 |
children |
comparison
equal
deleted
inserted
replaced
852:f95830b58336 | 854:79b5c1be9a5e |
---|---|
1 # Quickly hacked together helper for working out | |
2 # interactive regions in Suspended Sentence | |
3 | |
4 from pygame.locals import (K_LEFT, K_RIGHT, K_UP, K_DOWN, | |
5 K_a, K_t, K_d, K_i, K_r, K_o, K_b, K_z, | |
6 QUIT, MOUSEBUTTONDOWN, MOUSEMOTION, | |
7 MOUSEBUTTONUP, KEYDOWN) | |
8 import pygame | |
9 import os | |
10 | |
11 import pyntnclick.constants | |
12 from pyntnclick.i18n import _ | |
13 from pyntnclick.widgets.text import LabelWidget, TextButton | |
14 from pyntnclick.widgets.base import Container, Button, TranslucentImage | |
15 from pyntnclick.widgets.filechooser import FileChooser | |
16 from pyntnclick.utils import draw_rect_image | |
17 | |
18 DRAW, CYCLE, DELETE, IMAGE = range(4) | |
19 | |
20 | |
21 class RectDrawerError(Exception): | |
22 """Raised when initilaization failed""" | |
23 | |
24 | |
25 class RectDrawerConstants(pyntnclick.constants.GameConstants): | |
26 debug = True | |
27 menu_width = 200 | |
28 menu_button_height = 25 | |
29 zoom = 4 | |
30 zoom_step = 100 | |
31 | |
32 constants = RectDrawerConstants() | |
33 | |
34 | |
35 class ColourButton(Button): | |
36 """Button for selecting a colour""" | |
37 | |
38 sel_colour = pygame.color.Color(255, 255, 255) | |
39 unsel_colour = pygame.color.Color(128, 128, 128) | |
40 | |
41 padding = 2 | |
42 border = 3 | |
43 | |
44 def __init__(self, rect, gd, colour, palette, size=None): | |
45 super(ColourButton, self).__init__(rect, gd, size=size) | |
46 self._colour = pygame.color.Color(colour) | |
47 self._button_rect = self.rect.inflate(-self.padding, -self.padding) | |
48 self._colour_rect = self._button_rect.inflate(-self.border, | |
49 -self.border) | |
50 self.selected = False | |
51 self._palette = palette | |
52 self.add_callback('clicked', self.fix_selection) | |
53 | |
54 def fix_selection(self, ev, widget): | |
55 self._palette.cur_selection.selected = False | |
56 self.selected = True | |
57 self._palette.cur_selection = self | |
58 | |
59 def draw(self, surface): | |
60 if self.visible: | |
61 self.do_prepare() | |
62 surface.fill(pygame.color.Color(0, 0, 0), self.rect) | |
63 if self.selected: | |
64 surface.fill(self.sel_colour, self._button_rect) | |
65 else: | |
66 surface.fill(self.unsel_colour, self._button_rect) | |
67 surface.fill(self._colour, self._colour_rect) | |
68 | |
69 | |
70 class AppPalette(Container): | |
71 | |
72 but_size = 35 | |
73 | |
74 colors = [ | |
75 'red', 'maroon1', 'palevioletred1', 'moccasin', 'orange', | |
76 'honeydew', 'yellow', 'gold', 'goldenrod', 'brown', | |
77 'blue', 'purple', 'darkorchid4', 'thistle', 'skyblue1', | |
78 'green', 'palegreen1', 'darkgreen', 'aquamarine', 'darkolivegreen', | |
79 ] | |
80 | |
81 def __init__(self, pos, gd, app_image, size=None): | |
82 self.image = app_image | |
83 super(AppPalette, self).__init__(pos, gd, size=size) | |
84 self.selection = 0 | |
85 self.image.rect_color = pygame.color.Color(self.colors[self.selection]) | |
86 | |
87 x, y = pos | |
88 for num, col in enumerate(self.colors): | |
89 if (x - self.rect.left + self.but_size) >= self.rect.width: | |
90 x = self.rect.left | |
91 y += self.but_size | |
92 button = ColourButton((x, y), | |
93 gd, col, self, size=(self.but_size, self.but_size)) | |
94 x += self.but_size | |
95 if num == 0: | |
96 self.cur_selection = button | |
97 button.fix_selection(None, None) | |
98 button.add_callback('clicked', self.click_item, num) | |
99 self.add(button) | |
100 # Fix height | |
101 self.rect.height = y + self.but_size - self.rect.top | |
102 | |
103 def click_item(self, ev, widget, number): | |
104 self.selection = number | |
105 self.image.rect_color = pygame.color.Color(self.colors[number]) | |
106 | |
107 | |
108 class AppImage(Container): | |
109 | |
110 rect_thick = 3 | |
111 draw_thick = 1 | |
112 | |
113 def __init__(self, parent, gd, state, scene, detail): | |
114 self.state = state | |
115 super(AppImage, self).__init__((0, 0), gd, size=constants.screen) | |
116 self.mode = DRAW | |
117 self._scene = scene | |
118 self._parent = parent | |
119 self._detail = detail | |
120 self.rects = [] | |
121 self.images = [] | |
122 self.start_pos = None | |
123 self.end_pos = None | |
124 self.rect_color = pygame.color.Color('white') | |
125 self.current_image = None | |
126 self.place_image_menu = None | |
127 self.close_button = LabelWidget((0, 0), gd, _('Close')) | |
128 self.close_button.fg_color = (0, 0, 0) | |
129 self.close_button.bg_color = (0, 0, 0) | |
130 self.draw_rects = True | |
131 self.draw_things = True | |
132 self.draw_thing_rects = True | |
133 self.draw_images = True | |
134 self.trans_images = False | |
135 self.draw_toolbar = True | |
136 self.old_mouse_pos = None | |
137 self.zoom_display = False | |
138 self.draw_anim = False | |
139 self.zoom_offset = (600, 600) | |
140 self.clear_display = False | |
141 self.filechooser = None | |
142 if self._detail: | |
143 w, h = self._scene.get_detail_size() | |
144 rect = pygame.rect.Rect(0, 0, w, h) | |
145 self.close_button.rect.midbottom = rect.midbottom | |
146 self.offset = (0, 0) | |
147 else: | |
148 self.offset = (-self._scene.OFFSET[0], | |
149 -self._scene.OFFSET[1]) | |
150 self.find_existing_intersects() | |
151 self.add_callback(MOUSEBUTTONDOWN, self.mouse_down) | |
152 self.add_callback(MOUSEBUTTONUP, self.mouse_up) | |
153 self.add_callback(MOUSEMOTION, self.mouse_move) | |
154 self.add_callback(KEYDOWN, self.key_down) | |
155 | |
156 def get_mode_name(self): | |
157 """Return the translated mode name""" | |
158 # We do things this way to avoid defining translated strings | |
159 # at import time | |
160 if self.mode == DRAW: | |
161 return _("draw") | |
162 elif self.mode == CYCLE: | |
163 return _("cycle") | |
164 elif self.mode == DELETE: | |
165 return _("delete") | |
166 elif self.mode == IMAGE: | |
167 return _("image") | |
168 else: | |
169 raise RuntimeError("Invalid mode") | |
170 | |
171 def _print_thing(self, thing, interact_name): | |
172 """Helper to avoid repeated translations""" | |
173 print (_("Thing %(thing)s Interact %(interact)s") % | |
174 {'thing': thing.name, 'interact': interact_name}) | |
175 | |
176 def _print_rects(self, rect1, rect2): | |
177 """Helper to avoid repeated translations""" | |
178 print _(" Rects"), rect1, rect2 | |
179 | |
180 def find_existing_intersects(self): | |
181 """Parse the things in the scene for overlaps""" | |
182 scene = self._scene | |
183 # Pylint hates this function | |
184 for thing in scene.things.itervalues(): | |
185 for interact_name in thing.interacts: | |
186 thing._set_interact(interact_name) | |
187 if hasattr(thing.rect, 'collidepoint'): | |
188 thing_rects = [thing.rect] | |
189 else: | |
190 thing_rects = thing.rect | |
191 for thing2 in scene.things.itervalues(): | |
192 if thing is thing2: | |
193 continue | |
194 for interact2_name in thing2.interacts: | |
195 thing2._set_interact(interact2_name) | |
196 if hasattr(thing2.rect, 'collidepoint'): | |
197 thing2_rects = [thing2.rect] | |
198 else: | |
199 thing2_rects = thing2.rect | |
200 for my_rect in thing_rects: | |
201 for other_rect in thing2_rects: | |
202 if my_rect.colliderect(other_rect): | |
203 print _('Existing Intersecting rects') | |
204 self._print_thing(thing, interact_name) | |
205 self._print_thing(thing2, interact2_name) | |
206 self._print_rects(my_rect, other_rect) | |
207 print | |
208 | |
209 def find_intersecting_rects(self, d): | |
210 """Find if any rect collections intersect""" | |
211 # I loath N^X brute search algorithms, but whatever, hey | |
212 scene = self._scene | |
213 for (num, col) in enumerate(d): | |
214 rect_list = d[col] | |
215 for thing in scene.things.itervalues(): | |
216 for interact_name in thing.interacts: | |
217 thing._set_interact(interact_name) | |
218 if hasattr(thing.rect, 'collidepoint'): | |
219 thing_rects = [thing.rect] | |
220 else: | |
221 thing_rects = thing.rect | |
222 for other_rect in thing_rects: | |
223 for my_rect in rect_list: | |
224 if my_rect.colliderect(other_rect): | |
225 print _('Intersecting rects') | |
226 print _(" Object %s") % num | |
227 self._print_thing(thing, interact_name) | |
228 self._print_rects(my_rect, other_rect) | |
229 if thing.INITIAL: | |
230 thing._set_interact(thing.INITIAL) | |
231 print | |
232 for (num2, col2) in enumerate(d): | |
233 if num2 == num: | |
234 continue | |
235 other_list = d[col2] | |
236 for my_rect in rect_list: | |
237 for other_rect in other_list: | |
238 if my_rect.colliderect(other_rect): | |
239 print _('Intersecting rects'), | |
240 print (_(' Object %(object1)s and %(object2)s') % | |
241 {'object1': num, 'object2': num2}) | |
242 self._print_rects(my_rect, other_rect) | |
243 print | |
244 print | |
245 | |
246 def toggle_things(self, ev, widget): | |
247 self.draw_things = not self.draw_things | |
248 | |
249 def toggle_thing_rects(self, ev, widget): | |
250 self.draw_thing_rects = not self.draw_thing_rects | |
251 scene = self._scene | |
252 for thing in scene.things.itervalues(): | |
253 if not self.draw_thing_rects: | |
254 if not hasattr(thing, 'old_colour'): | |
255 thing.old_colour = thing._interact_hilight_color | |
256 thing._interact_hilight_color = None | |
257 else: | |
258 thing._interact_hilight_color = thing.old_colour | |
259 | |
260 def toggle_images(self, ev, widget): | |
261 self.draw_images = not self.draw_images | |
262 for image in self.images: | |
263 image.set_visible(self.draw_images) | |
264 if self.current_image: | |
265 self.current_image.set_visible(self.draw_images) | |
266 self.invalidate() | |
267 | |
268 def toggle_trans_images(self, ev, widget): | |
269 self.trans_images = not self.trans_images | |
270 for image in self.images: | |
271 image.translucent = self.trans_images | |
272 if self.current_image: | |
273 self.current_image.translucent = self.trans_images | |
274 self.invalidate() | |
275 | |
276 def toggle_rects(self, ev, widget): | |
277 self.draw_rects = not self.draw_rects | |
278 | |
279 def toggle_toolbar(self, ev, widget): | |
280 self.draw_toolbar = not self.draw_toolbar | |
281 | |
282 def toggle_zoom(self, ev, widget): | |
283 self.zoom_display = not self.zoom_display | |
284 self.invalidate() | |
285 | |
286 def toggle_anim(self, ev, widget): | |
287 self.draw_anim = not self.draw_anim | |
288 | |
289 def draw_mode(self, ev, widget): | |
290 self.mode = DRAW | |
291 | |
292 def del_mode(self, ev, widget): | |
293 self.mode = DELETE | |
294 self.start_pos = None | |
295 self.end_pos = None | |
296 | |
297 def invalidate(self): | |
298 self.clear_display = True | |
299 | |
300 def draw(self, surface): | |
301 if not self.visible: | |
302 return | |
303 self.do_prepare() | |
304 if self.clear_display: | |
305 surface.fill(pygame.color.Color(0, 0, 0), | |
306 pygame.Rect(0, 0, constants.screen[0], | |
307 constants.screen[1])) | |
308 self.clear_display = False | |
309 | |
310 if self.zoom_display: | |
311 base_surface = surface.copy() | |
312 self.do_unzoomed_draw(base_surface) | |
313 zoomed = pygame.transform.scale(base_surface, | |
314 (constants.zoom * base_surface.get_width(), | |
315 constants.zoom * base_surface.get_height())) | |
316 area = pygame.rect.Rect(self.zoom_offset[0], self.zoom_offset[1], | |
317 constants.screen[0], constants.screen[1]) | |
318 surface.blit(zoomed, (0, 0), area) | |
319 else: | |
320 self.do_unzoomed_draw(surface) | |
321 | |
322 def do_unzoomed_draw(self, surface): | |
323 if self.draw_things: | |
324 self._scene.draw(surface) | |
325 else: | |
326 self._scene.draw_background(surface) | |
327 if self._detail: | |
328 # We duplicate draw logic here, so we zoom the close | |
329 # button correctly | |
330 self.close_button.draw(surface) | |
331 if self.mode == DRAW and self.start_pos and self.draw_rects: | |
332 rect = pygame.rect.Rect(self.start_pos[0], self.start_pos[1], | |
333 self.end_pos[0] - self.start_pos[0], | |
334 self.end_pos[1] - self.start_pos[1]) | |
335 rect.normalize() | |
336 draw_rect_image(surface, self.rect_color, rect, self.draw_thick) | |
337 if self.draw_rects: | |
338 for (col, rect) in self.rects: | |
339 draw_rect_image(surface, col, rect, self.rect_thick) | |
340 for image in self.images: | |
341 image.draw(surface) | |
342 if self.current_image and self.mode == IMAGE: | |
343 self.current_image.draw(surface) | |
344 if self.draw_toolbar: | |
345 tb_surf = surface.subsurface(0, constants.screen[1] | |
346 - constants.button_size, | |
347 constants.screen[0], | |
348 constants.button_size).convert_alpha() | |
349 tb_surf.fill(pygame.color.Color(127, 0, 0, 191)) | |
350 surface.blit(tb_surf, (0, constants.screen[1] | |
351 - constants.button_size)) | |
352 | |
353 def _make_dict(self): | |
354 d = {} | |
355 for col, rect in self.rects: | |
356 col = (col.r, col.g, col.b) | |
357 d.setdefault(col, []) | |
358 d[col].append(rect) | |
359 return d | |
360 | |
361 def print_objs(self, ev, widget): | |
362 d = self._make_dict() | |
363 self.find_intersecting_rects(d) | |
364 for (num, col) in enumerate(d): | |
365 print _('Rect %d : ') % num | |
366 for rect in d[col]: | |
367 r = rect.move(self.offset) | |
368 print ' (%d, %d, %d, %d),' % (r.x, r.y, r.w, r.h) | |
369 print | |
370 for i, image in enumerate(self.images): | |
371 print _('Image %d') % i | |
372 rect = image.rect | |
373 r = rect.move(self.offset) | |
374 print ' (%d, %d, %d, %d),' % (r.x, r.y, r.w, r.h) | |
375 print | |
376 print | |
377 | |
378 def image_load(self, ev, widget): | |
379 if self.filechooser is None: | |
380 self.filechooser = FileChooser((0, 0), self.gd, None, os.curdir, | |
381 self.do_load_image) | |
382 else: | |
383 self.filechooser.refresh() | |
384 self.invalidate() | |
385 self._parent.paused = True | |
386 self._parent.add(self.filechooser) | |
387 | |
388 def do_load_image(self, filename): | |
389 try: | |
390 self.current_image = TranslucentImage((0, 0), self.gd, | |
391 pygame.image.load(filename)) | |
392 if not self.draw_images: | |
393 # Selecting an image makes image visible | |
394 self.toggle_images(None, None) | |
395 self.current_image.translucent = self.trans_images | |
396 self.place_image_menu.enabled = True | |
397 self.current_image.rect = self.current_image.rect.move( | |
398 constants.screen[0] + constants.menu_width, | |
399 constants.screen[1]) | |
400 self.image_mode(None, None) | |
401 except pygame.error, e: | |
402 print 'Unable to load image %s (reason %s)' % (filename, e) | |
403 | |
404 def image_mode(self, ev, widget): | |
405 self.mode = IMAGE | |
406 self.start_pos = None | |
407 self.end_pos = None | |
408 # So we do the right thing for off screen images | |
409 self.old_mouse_pos = None | |
410 | |
411 def cycle_mode(self, ev, widget): | |
412 self.mode = CYCLE | |
413 | |
414 def _conv_pos(self, mouse_pos): | |
415 if self.zoom_display: | |
416 pos = ((mouse_pos[0] + self.zoom_offset[0]) / constants.zoom, | |
417 (mouse_pos[1] + self.zoom_offset[1]) / constants.zoom) | |
418 else: | |
419 pos = mouse_pos | |
420 return pos | |
421 | |
422 def _check_limits(self, offset): | |
423 if offset[0] < 0: | |
424 offset[0] = 0 | |
425 if offset[1] < 0: | |
426 offset[1] = 0 | |
427 width, height = constants.screen | |
428 if offset[0] > constants.zoom * width - width: | |
429 offset[0] = constants.zoom * width - width | |
430 if offset[1] > constants.zoom * height - height: | |
431 offset[1] = constants.zoom * height - height | |
432 | |
433 def _make_zoom_offset(self, pos): | |
434 zoom_pos = (pos[0] * constants.zoom, pos[1] * constants.zoom) | |
435 offset = [zoom_pos[0] - constants.screen[0] / 2, | |
436 zoom_pos[1] - constants.screen[1] / 2] | |
437 self._check_limits(offset) | |
438 self.zoom_offset = tuple(offset) | |
439 | |
440 def _move_zoom(self, x, y): | |
441 offset = list(self.zoom_offset) | |
442 offset[0] += constants.zoom_step * x | |
443 offset[1] += constants.zoom_step * y | |
444 self._check_limits(offset) | |
445 self.zoom_offset = tuple(offset) | |
446 | |
447 def key_down(self, ev, widget): | |
448 if self.mode == IMAGE and self.current_image: | |
449 # Move the image by 1 pixel | |
450 cur_pos = self.current_image.rect.center | |
451 if ev.key == K_LEFT: | |
452 self.current_image.rect.center = (cur_pos[0] - 1, cur_pos[1]) | |
453 elif ev.key == K_RIGHT: | |
454 self.current_image.rect.center = (cur_pos[0] + 1, cur_pos[1]) | |
455 elif ev.key == K_UP: | |
456 self.current_image.rect.center = (cur_pos[0], cur_pos[1] - 1) | |
457 elif ev.key == K_DOWN: | |
458 self.current_image.rect.center = (cur_pos[0], cur_pos[1] + 1) | |
459 elif self.zoom_display: | |
460 if ev.key == K_LEFT: | |
461 self._move_zoom(-1, 0) | |
462 elif ev.key == K_RIGHT: | |
463 self._move_zoom(1, 0) | |
464 elif ev.key == K_UP: | |
465 self._move_zoom(0, -1) | |
466 elif ev.key == K_DOWN: | |
467 self._move_zoom(0, 1) | |
468 | |
469 if ev.key == K_o: | |
470 self.toggle_trans_images(None, None) | |
471 elif ev.key == K_t: | |
472 self.toggle_things(None, None) | |
473 elif ev.key == K_r: | |
474 self.toggle_thing_rects(None, None) | |
475 elif ev.key == K_i: | |
476 self.toggle_images(None, None) | |
477 elif ev.key == K_d: | |
478 self.toggle_rects(None, None) | |
479 elif ev.key == K_b: | |
480 self.toggle_toolbar(None, None) | |
481 elif ev.key == K_z: | |
482 self.toggle_zoom(None, None) | |
483 elif ev.key == K_a: | |
484 self.toggle_anim(None, None) | |
485 | |
486 def mouse_down(self, ev, widget): | |
487 pos = self._conv_pos(ev.pos) | |
488 if self._parent.paused: | |
489 # Ignore this if the filechooser is active | |
490 return False | |
491 if self.mode == DELETE: | |
492 cand = None | |
493 # Images are drawn above rectangles, so search those first | |
494 for image in self.images: | |
495 if image.rect.collidepoint(pos): | |
496 cand = image | |
497 break | |
498 if cand: | |
499 self.images.remove(cand) | |
500 self.invalidate() | |
501 return | |
502 for (col, rect) in self.rects: | |
503 if rect.collidepoint(pos): | |
504 cand = (col, rect) | |
505 break | |
506 if cand: | |
507 self.rects.remove(cand) | |
508 self.invalidate() | |
509 elif self.mode == CYCLE: | |
510 scene = self._scene | |
511 cand = None | |
512 for thing in scene.things.itervalues(): | |
513 if thing.contains(pos): | |
514 cand = thing | |
515 break | |
516 if cand: | |
517 # Find current interacts in this thing | |
518 cur_interact = cand.current_interact | |
519 j = cand.interacts.values().index(cur_interact) | |
520 if j + 1 < len(cand.interacts): | |
521 next_name = cand.interacts.keys()[j + 1] | |
522 else: | |
523 next_name = cand.interacts.keys()[0] | |
524 if cand.interacts[next_name] != cur_interact: | |
525 cand._set_interact(next_name) | |
526 elif self.mode == DRAW: | |
527 self.start_pos = pos | |
528 self.end_pos = pos | |
529 elif self.mode == IMAGE: | |
530 if self.current_image: | |
531 self.images.append(self.current_image) | |
532 self.current_image = None | |
533 self.old_mouse_pos = None | |
534 self.invalidate() | |
535 else: | |
536 cand = None | |
537 for image in self.images: | |
538 if image.rect.collidepoint(pos): | |
539 cand = image | |
540 break | |
541 if cand: | |
542 self.images.remove(cand) | |
543 self.current_image = cand | |
544 # We want to move relative to the current mouse pos, so | |
545 self.old_mouse_pos = pos | |
546 self.invalidate() | |
547 | |
548 def mouse_up(self, ev, widget): | |
549 if self._parent.paused: | |
550 return False | |
551 if self.mode == DRAW: | |
552 if self.start_pos is None: | |
553 # We've come here not via a drawing situation, so bail | |
554 return False | |
555 rect = pygame.rect.Rect(self.start_pos[0], self.start_pos[1], | |
556 self.end_pos[0] - self.start_pos[0], | |
557 self.end_pos[1] - self.start_pos[1]) | |
558 rect.normalize() | |
559 self.rects.append((self.rect_color, rect)) | |
560 self.start_pos = self.end_pos = None | |
561 | |
562 def mouse_move(self, ev, widget): | |
563 # We're only interested in this if left mouse button is down or we've | |
564 # got and image | |
565 if self.mode == IMAGE and self.current_image: | |
566 pos = self._conv_pos(ev.pos) | |
567 if self.old_mouse_pos: | |
568 delta = (pos[0] - self.old_mouse_pos[0], | |
569 pos[1] - self.old_mouse_pos[1]) | |
570 self.current_image.rect.center = ( | |
571 self.current_image.rect.center[0] + delta[0], | |
572 self.current_image.rect.center[1] + delta[1]) | |
573 else: | |
574 self.current_image.rect.center = pos | |
575 self.invalidate() | |
576 self.old_mouse_pos = pos | |
577 return True | |
578 elif ev.buttons[0] == 1 and self.mode == DRAW: | |
579 self.end_pos = self._conv_pos(ev.pos) | |
580 return True | |
581 return False | |
582 | |
583 def animate(self): | |
584 if self.draw_anim: | |
585 self._scene.animate() | |
586 | |
587 | |
588 class ModeLabel(LabelWidget): | |
589 | |
590 def __init__(self, pos, gd, app_image, size=None): | |
591 self.app_image = app_image | |
592 super(ModeLabel, self).__init__(pos, | |
593 gd, _('Mode : '), fontname=constants.bold_font, | |
594 fontsize=15, color=pygame.color.Color(128, 0, 255), | |
595 size=size) | |
596 self.start_rect = self.rect.copy() | |
597 | |
598 def draw(self, surface): | |
599 self.do_prepare() | |
600 text = _('Mode : %s') % self.app_image.get_mode_name() | |
601 if self.text != text: | |
602 self.text = text | |
603 self.is_prepared = False | |
604 self.rect = self.start_rect.copy() | |
605 self.do_prepare() | |
606 super(ModeLabel, self).draw(surface) | |
607 | |
608 | |
609 def make_button(text, gd, action, ypos): | |
610 rect = pygame.rect.Rect(0, 0, constants.menu_width, | |
611 constants.menu_button_height) | |
612 rect.move_ip(805, ypos) | |
613 button = TextButton(rect.topleft, gd, text, size=(constants.menu_width, | |
614 constants.menu_button_height), | |
615 fontname=constants.font, fontsize=12, | |
616 color=pygame.color.Color(255, 255, 0), border=1, padding=3) | |
617 button.add_callback('clicked', action) | |
618 return button | |
619 | |
620 | |
621 class RectApp(Container): | |
622 """The actual rect drawer main app""" | |
623 def __init__(self, rect, gd, detail): | |
624 super(RectApp, self).__init__(rect, gd) | |
625 | |
626 try: | |
627 state = gd.initial_state() | |
628 scene = state.scenes[gd._initial_scene] | |
629 except KeyError: | |
630 raise RectDrawerError(_('Invalid scene: %s') % gd._initial_scene) | |
631 gd.sound.disable_sound() # No sound here | |
632 | |
633 if detail: | |
634 try: | |
635 scene = state.detail_views[detail] | |
636 except KeyError: | |
637 raise RectDrawerError(_('Invalid detail: %s') % detail) | |
638 | |
639 self.paused = False | |
640 | |
641 self.image = AppImage(self, gd, state, scene, detail is not None) | |
642 self.add(self.image) | |
643 mode_label = ModeLabel((805, 0), self.gd, self.image, size=(200, 50)) | |
644 self.add(mode_label) | |
645 y = mode_label.rect.height | |
646 draw = make_button(_('Draw Rect'), gd, self.image.draw_mode, y) | |
647 self.add(draw) | |
648 y += draw.rect.height | |
649 load_image = make_button(_("Load image"), gd, self.image.image_load, y) | |
650 self.add(load_image) | |
651 y += load_image.rect.height | |
652 add_image = make_button(_("Place/Move images"), gd, | |
653 self.image.image_mode, y) | |
654 add_image.enabled = False | |
655 self.add(add_image) | |
656 self.image.place_image_menu = add_image | |
657 y += add_image.rect.height | |
658 cycle = make_button(_("Cycle interacts"), gd, self.image.cycle_mode, y) | |
659 self.add(cycle) | |
660 y += cycle.rect.height | |
661 delete = make_button(_("Delete Objects"), gd, self.image.del_mode, y) | |
662 self.add(delete) | |
663 y += delete.rect.height | |
664 palette = AppPalette((810, y), gd, self.image, size=(200, 0)) | |
665 self.add(palette) | |
666 y += palette.rect.height | |
667 print_rects = make_button(_("Print objects"), gd, | |
668 self.image.print_objs, y) | |
669 self.add(print_rects) | |
670 y += print_rects.rect.height | |
671 toggle_things = make_button(_("Show Things (t)"), gd, | |
672 self.image.toggle_things, y) | |
673 self.add(toggle_things) | |
674 y += toggle_things.rect.height | |
675 toggle_thing_rects = make_button(_("Show Thing Rects (r)"), gd, | |
676 self.image.toggle_thing_rects, y) | |
677 self.add(toggle_thing_rects) | |
678 y += toggle_thing_rects.rect.height | |
679 toggle_images = make_button(_("Show Images (i)"), gd, | |
680 self.image.toggle_images, y) | |
681 self.add(toggle_images) | |
682 y += toggle_images.rect.height | |
683 trans_images = make_button(_("Opaque Images (o)"), gd, | |
684 self.image.toggle_trans_images, y) | |
685 self.add(trans_images) | |
686 y += trans_images.rect.height | |
687 toggle_rects = make_button(_("Show Drawn Rects (d)"), gd, | |
688 self.image.toggle_rects, y) | |
689 self.add(toggle_rects) | |
690 y += toggle_rects.rect.height | |
691 toggle_toolbar = make_button(_("Show Toolbar (b)"), gd, | |
692 self.image.toggle_toolbar, y) | |
693 self.add(toggle_toolbar) | |
694 y += toggle_toolbar.rect.height | |
695 toggle_anim = make_button(_("Show Animations (a)"), gd, | |
696 self.image.toggle_anim, y) | |
697 self.add(toggle_anim) | |
698 y += toggle_anim.rect.height | |
699 toggle_zoom = make_button(_("Zoom (z)"), gd, | |
700 self.image.toggle_zoom, y) | |
701 self.add(toggle_zoom) | |
702 y += toggle_zoom.rect.height | |
703 quit_but = make_button(_("Quit"), gd, self.quit, 570) | |
704 self.add(quit_but) | |
705 | |
706 def quit(self, ev, widget): | |
707 pygame.event.post(pygame.event.Event(QUIT)) | |
708 | |
709 def animate(self): | |
710 self.image.animate() | |
711 | |
712 | |
713 class RectEngine(object): | |
714 """Engine for the rect drawer.""" | |
715 | |
716 def __init__(self, gd, detail): | |
717 self.state = None | |
718 self._gd = gd | |
719 rect = pygame.display.get_surface().get_rect() | |
720 self.app = RectApp(rect.topleft, self._gd, detail) | |
721 | |
722 def run(self): | |
723 """App loop""" | |
724 clock = pygame.time.Clock() | |
725 while True: | |
726 events = pygame.event.get() | |
727 for ev in events: | |
728 if ev.type == QUIT: | |
729 return | |
730 else: | |
731 self.app.event(ev) | |
732 self.app.animate() | |
733 surface = pygame.display.get_surface() | |
734 self.app.draw(surface) | |
735 pygame.display.flip() | |
736 clock.tick(self._gd.constants.frame_rate) | |
737 | |
738 | |
739 def make_rect_display(): | |
740 pygame.display.init() | |
741 pygame.font.init() | |
742 pygame.display.set_mode((constants.screen[0] | |
743 + constants.menu_width, constants.screen[1])) |