Mercurial > nagslang
comparison tools/area_editor.py @ 275:2abb61878bb1
Add a 'select object' with pop-up for easier editing
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Thu, 05 Sep 2013 12:04:14 +0200 |
parents | 521f73061872 |
children | 56e42c00da25 |
comparison
equal
deleted
inserted
replaced
274:988cf7c8b402 | 275:2abb61878bb1 |
---|---|
53 | 53 |
54 def __init__(self, name, x=800, y=600): | 54 def __init__(self, name, x=800, y=600): |
55 super(EditorLevel, self).__init__(name) | 55 super(EditorLevel, self).__init__(name) |
56 self.x = x | 56 self.x = x |
57 self.y = y | 57 self.y = y |
58 # Lookup initiliasition info from the objects | |
59 self.lookup = {} | |
58 | 60 |
59 def round_point(self, pos): | 61 def round_point(self, pos): |
60 return (10 * (pos[0] // 10), 10 * (pos[1] // 10)) | 62 return (10 * (pos[0] // 10), 10 * (pos[1] // 10)) |
63 | |
64 def load(self, space): | |
65 super(EditorLevel, self).load(space) | |
66 # Needed to fill in the lookup dict | |
67 self.reset_objs() | |
61 | 68 |
62 def point_to_pymunk(self, pos): | 69 def point_to_pymunk(self, pos): |
63 # inverse of point_to_pygame | 70 # inverse of point_to_pygame |
64 # (this is also the same as point_to_pygame, but a additional | 71 # (this is also the same as point_to_pygame, but a additional |
65 # function for sanity later in pyweek). | 72 # function for sanity later in pyweek). |
177 # Reset the object state - needed when changing stuff | 184 # Reset the object state - needed when changing stuff |
178 self.drawables = [] | 185 self.drawables = [] |
179 self.overlay_drawables = [] | 186 self.overlay_drawables = [] |
180 self._glue = np.PuzzleGlue() | 187 self._glue = np.PuzzleGlue() |
181 for game_object_dict in self._game_objects: | 188 for game_object_dict in self._game_objects: |
182 self._create_game_object(pymunk.Space(), **game_object_dict) | 189 obj = self._create_game_object(pymunk.Space(), **game_object_dict) |
190 self.lookup[obj] = game_object_dict | |
183 for enemy_dict in self._enemies: | 191 for enemy_dict in self._enemies: |
184 self._create_enemy(pymunk.Space(), **enemy_dict) | 192 obj = self._create_enemy(pymunk.Space(), **enemy_dict) |
193 self.lookup[obj] = enemy_dict | |
185 | 194 |
186 def get_class(self, classname, mod=None): | 195 def get_class(self, classname, mod=None): |
187 # Get the class given the classname | 196 # Get the class given the classname |
188 modules = { | 197 modules = { |
189 'game_object': ngo, | 198 'game_object': ngo, |
210 target.append(old) | 219 target.append(old) |
211 self.reset_objs() | 220 self.reset_objs() |
212 alert("Failed to update object %s: %s" % (classname, e)) | 221 alert("Failed to update object %s: %s" % (classname, e)) |
213 return False | 222 return False |
214 | 223 |
224 def find_obj_at_pos(self, mouse_pos): | |
225 pymunk_pos = self.point_to_pymunk(mouse_pos) | |
226 # Search visible objects | |
227 for obj in self.drawables: | |
228 if obj.get_shape().point_query(pymunk_pos): | |
229 return obj | |
230 return None | |
231 | |
215 | 232 |
216 class ObjectTable(TableView): | 233 class ObjectTable(TableView): |
217 | 234 |
218 columns = [TableColumn("Object", 690, 'l', '%r')] | 235 columns = [TableColumn("Object", 690, 'l', '%r')] |
219 | 236 |
243 return None | 260 return None |
244 | 261 |
245 | 262 |
246 class EditClassDialog(Dialog): | 263 class EditClassDialog(Dialog): |
247 | 264 |
248 def __init__(self, classname, cls, data): | 265 def __init__(self, classname, cls, data, delete=False): |
249 super(EditClassDialog, self).__init__() | 266 super(EditClassDialog, self).__init__() |
250 self.classname = classname | 267 self.classname = classname |
251 self.rect = pygame.rect.Rect(0, 0, 800, 550) | 268 self.rect = pygame.rect.Rect(0, 0, 800, 550) |
252 title = Label("Editing %s" % classname) | 269 title = Label("Editing %s" % classname) |
253 title.rect = pygame.rect.Rect(100, 10, 600, 25) | 270 title.rect = pygame.rect.Rect(100, 10, 600, 25) |
279 hintlabel = Label(hint) | 296 hintlabel = Label(hint) |
280 hintlabel.rect = pygame.rect.Rect(640, y, 100, 25) | 297 hintlabel.rect = pygame.rect.Rect(640, y, 100, 25) |
281 self.add(hintlabel) | 298 self.add(hintlabel) |
282 y += 30 | 299 y += 30 |
283 buttons = [] | 300 buttons = [] |
284 for text in ['OK', 'Cancel']: | 301 if delete: |
302 labels = ['OK', 'Delete', 'Cancel'] | |
303 else: | |
304 labels = ['OK', 'Cancel'] | |
305 for text in labels: | |
285 but = Button(text, action=lambda x=text: self.dismiss(x)) | 306 but = Button(text, action=lambda x=text: self.dismiss(x)) |
286 buttons.append(but) | 307 buttons.append(but) |
287 row = Row(buttons) | 308 row = Row(buttons) |
288 row.rect = pygame.rect.Rect(250, 500, 700, 50) | 309 row.rect = pygame.rect.Rect(250, 500, 700, 50) |
289 self.add(row) | 310 self.add(row) |
320 self.cur_poly = None | 341 self.cur_poly = None |
321 self._mouse_drag = False | 342 self._mouse_drag = False |
322 self._draw_objects = False | 343 self._draw_objects = False |
323 self._draw_enemies = False | 344 self._draw_enemies = False |
324 self._draw_lines = False | 345 self._draw_lines = False |
346 self.sel_mode = False | |
325 self._start_pos = None | 347 self._start_pos = None |
326 | 348 |
327 def _level_coordinates(self, pos): | 349 def _level_coordinates(self, pos): |
328 # Move positions to level values | 350 # Move positions to level values |
329 if not pos: | 351 if not pos: |
430 -self.mouse_pos[1] + old_pos[1]) | 452 -self.mouse_pos[1] + old_pos[1]) |
431 self._move_view(diff) | 453 self._move_view(diff) |
432 self.invalidate() | 454 self.invalidate() |
433 | 455 |
434 def mouse_down(self, ev): | 456 def mouse_down(self, ev): |
435 if ev.button == 1: | 457 if self.sel_mode and ev.button == 1: |
458 corrected_pos = ev.pos[0] + self.pos[0], ev.pos[1] + self.pos[1] | |
459 obj = self.level.find_obj_at_pos(corrected_pos) | |
460 if obj is not None: | |
461 self._edit_selected(obj) | |
462 elif ev.button == 1: | |
436 if self._draw_lines: | 463 if self._draw_lines: |
437 if self._start_pos is None: | 464 if self._start_pos is None: |
438 self._start_pos = ev.pos | 465 self._start_pos = ev.pos |
439 else: | 466 else: |
440 self.level.add_line(self._start_pos, ev.pos) | 467 self.level.add_line(self._start_pos, ev.pos) |
476 dialog = EditClassDialog(classname, cls, data) | 503 dialog = EditClassDialog(classname, cls, data) |
477 if dialog.present() == 'OK': | 504 if dialog.present() == 'OK': |
478 return dialog.get_data() | 505 return dialog.get_data() |
479 return None | 506 return None |
480 | 507 |
508 def _edit_selected(self, obj): | |
509 data = self.level.lookup[obj] | |
510 cls = obj.__class__ | |
511 classname = obj.__class__.__name__ | |
512 dialog = EditClassDialog(classname, cls, data, True) | |
513 res = dialog.present() | |
514 if res == 'OK': | |
515 edited = dialog.get_data() | |
516 if edited is not None: | |
517 for target in [self.level._game_objects, self.level._enemies]: | |
518 if data in target: | |
519 self.level.try_new_object(classname, target, | |
520 edited, data) | |
521 break | |
522 elif res == 'Delete': | |
523 for target in [self.level._game_objects, self.level._enemies]: | |
524 if data in target: | |
525 target.remove(data) | |
526 self.level.reset_objs() | |
527 break | |
528 | |
481 def _make_edit_dialog(self, entries): | 529 def _make_edit_dialog(self, entries): |
482 # Dialog to hold the editor | 530 # Dialog to hold the editor |
483 edit_box = Dialog() | 531 edit_box = Dialog() |
484 edit_box.rect = pygame.rect.Rect(0, 0, 700, 500) | 532 edit_box.rect = pygame.rect.Rect(0, 0, 700, 500) |
485 table = ObjectTable(entries) | 533 table = ObjectTable(entries) |
740 add_enemy_but.rect.move_ip(MENU_LEFT, y) | 788 add_enemy_but.rect.move_ip(MENU_LEFT, y) |
741 widgets.append(add_enemy_but) | 789 widgets.append(add_enemy_but) |
742 y += MENU_BUTTON_HEIGHT + MENU_PAD | 790 y += MENU_BUTTON_HEIGHT + MENU_PAD |
743 | 791 |
744 y += MENU_PAD | 792 y += MENU_PAD |
793 sel_mode_but = Button('Select Object', | |
794 action=self.sel_mode) | |
795 sel_mode_but.rect = BUTTON_RECT.copy() | |
796 sel_mode_but.rect.move_ip(MENU_LEFT, y) | |
797 widgets.append(sel_mode_but) | |
798 y += MENU_BUTTON_HEIGHT + MENU_PAD | |
799 | |
800 y += MENU_PAD | |
745 switch_but = Button('Switch to Drawing', action=self.switch_to_draw) | 801 switch_but = Button('Switch to Drawing', action=self.switch_to_draw) |
746 switch_but.rect = BUTTON_RECT.copy() | 802 switch_but.rect = BUTTON_RECT.copy() |
747 switch_but.rect.move_ip(MENU_LEFT, y) | 803 switch_but.rect.move_ip(MENU_LEFT, y) |
748 widgets.append(switch_but) | 804 widgets.append(switch_but) |
749 y += switch_but.rect.height + MENU_PAD | 805 y += switch_but.rect.height + MENU_PAD |
796 for widget in self._dMenus[self._menu_mode]: | 852 for widget in self._dMenus[self._menu_mode]: |
797 self.remove(widget) | 853 self.remove(widget) |
798 | 854 |
799 def _populate_menu(self): | 855 def _populate_menu(self): |
800 self.level_widget.change_poly(None) | 856 self.level_widget.change_poly(None) |
857 self.level_widget.sel_mode = False | |
801 for widget in self._dMenus[self._menu_mode]: | 858 for widget in self._dMenus[self._menu_mode]: |
802 self.add(widget) | 859 self.add(widget) |
803 self.invalidate() | 860 self.invalidate() |
861 | |
862 def sel_mode(self): | |
863 self.level_widget.sel_mode = not self.level_widget.sel_mode | |
804 | 864 |
805 def mouse_move(self, ev): | 865 def mouse_move(self, ev): |
806 self.level_widget.mouse_move(ev) | 866 self.level_widget.mouse_move(ev) |
807 | 867 |
808 def draw(self, surface): | 868 def draw(self, surface): |