Mercurial > nagslang
changeset 251:611370331bd1
Add framework of edit object dialog
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Wed, 04 Sep 2013 23:46:06 +0200 |
parents | d9a54f152ac3 |
children | 73d6abf5ba22 |
files | tools/area_editor.py |
diffstat | 1 files changed, 133 insertions(+), 25 deletions(-) [+] |
line wrap: on
line diff
--- a/tools/area_editor.py Wed Sep 04 23:42:09 2013 +0200 +++ b/tools/area_editor.py Wed Sep 04 23:46:06 2013 +0200 @@ -26,14 +26,15 @@ from albow.controls import Button, Label, CheckBox from albow.dialogs import alert, Dialog from albow.layout import Row +from albow.fields import TextField from albow.table_view import TableView, TableColumn from nagslang.options import parse_args from nagslang.constants import SCREEN from nagslang.level import Level, POLY_COLORS, LINE_COLOR -from nagslang.enemies import Enemy, get_editable_enemies -from nagslang.game_object import get_editable_game_objects -from nagslang.puzzle import get_editable_puzzlers, PuzzleGlue +import nagslang.enemies as ne +import nagslang.game_object as ngo +import nagslang.puzzle as np # layout constants MENU_BUTTON_HEIGHT = 35 @@ -175,12 +176,40 @@ # Reset the object state - needed when changing stuff self.drawables = [] self.overlay_drawables = [] - self._glue = PuzzleGlue() + self._glue = np.PuzzleGlue() for game_object_dict in self._game_objects: self._create_game_object(pymunk.Space(), **game_object_dict) for enemy_dict in self._enemies: self._create_enemy(pymunk.Space(), **enemy_dict) + def get_class(self, classname, mod=None): + # Get the class given the classname + modules = { + 'game_object': ngo, + 'enemies': ne, + 'puzzle': np, + } + if '.' in classname: + modname, classname = classname.split('.') + mod = modules[modname] + if mod is None: + mod = ngo + return getattr(mod, classname) + + def try_new_object(self, target, new, old=None): + if old in target: + target.remove(old) + try: + target.append(new) + self.reset_objs() + return True + except Exception: + target.remove(new) + if old is not None: + target.append(old) + self.reset_objs() + return False + class ObjectTable(TableView): @@ -212,6 +241,50 @@ return None +class EditClassDialog(Dialog): + + def __init__(self, classname, cls, data): + super(EditClassDialog, self).__init__() + self.rect = pygame.rect.Rect(0, 0, 800, 550) + title = Label("Editing %s" % classname) + title.rect = pygame.rect.Rect(100, 10, 600, 25) + self.add(title) + requires = cls.requires() + y = 40 + self.fields = {} + index = 0 + for requirement, hint in requires: + label = Label(requirement) + label.rect = pygame.rect.Rect(40, y, 200, 25) + self.add(label) + field = TextField() + field.rect = pygame.rect.Rect(220, y, 400, 25) + self.add(field) + if data is not None: + if requirement in data: + field.set_text('%s' % data[requirement]) + elif 'args' in data: + # NB: The ordering assumptions in requires should make + # this safe, but it's really, really, really fragile + field.set_text('%s' % data['args'][index]) + index += 1 + self.fields[requirement] = field + hintlabel = Label(hint) + hintlabel.rect = pygame.rect.Rect(640, y, 100, 25) + self.add(hintlabel) + y += 30 + buttons = [] + for text in ['OK', 'Cancel']: + but = Button(text, action=lambda x=text: self.dismiss(x)) + buttons.append(but) + row = Row(buttons) + row.rect = pygame.rect.Rect(250, 500, 700, 50) + self.add(row) + + def get_data(self): + return '' + + class LevelWidget(Widget): def __init__(self, level): @@ -270,11 +343,11 @@ self._draw_lines, self._start_pos) if self._draw_objects: for thing in self.level.drawables: - if not isinstance(thing, Enemy): + if not isinstance(thing, ne.Enemy): thing.render(level_surface) if self._draw_enemies: for thing in self.level.drawables: - if isinstance(thing, Enemy): + if isinstance(thing, ne.Enemy): thing.render(level_surface) surface_area = pygame.rect.Rect(self.pos, SCREEN) surface.blit(level_surface, (0, 0), surface_area) @@ -375,6 +448,13 @@ else: alert("Failed to close the polygon") + def _edit_class(self, classname, cls, data): + # Dialog for class properties + dialog = EditClassDialog(classname, cls, data) + if dialog.present() == 'OK': + return dialog.get_data() + return None + def _make_edit_dialog(self, entries): # Dialog to hold the editor edit_box = Dialog() @@ -386,7 +466,7 @@ but = Button(text, action=lambda x=text: edit_box.dismiss(x)) buttons.append(but) row = Row(buttons) - row.rect = pygame.rect.Rect(0, 450, 700, 50) + row.rect = pygame.rect.Rect(250, 450, 700, 50) edit_box.add(row) edit_box.get_selection = lambda: table.get_selection() return edit_box @@ -398,8 +478,13 @@ if choice is None: return if res == 'OK': - # Edit object stuff goes here - pass + cls = self.level.get_class(choice['classname']) + edited = self._edit_class(choice['classname'], cls, choice) + if edited is not None: + if not self.level.try_new_object(self.level._game_objects, + edited, choice): + alert('Failed to update GameObject %s' + % choice['classname']) elif res == 'Delete': self.level._game_objects.remove(choice) self.level.reset_objs() @@ -411,8 +496,13 @@ if choice is None: return if res == 'OK': - # Edit object stuff goes here - pass + cls = self.level.get_class(choice['classname'], ne) + edited = self._edit_class(choice['classname'], cls, choice) + if edited is not None: + if not self.level.try_new_object(self.level._enemies, + edited, choice): + alert('Failed to update Enemy %s' + % choice['classname']) elif res == 'Delete': self.level._enemies.remove(choice) self.level.reset_objs() @@ -431,34 +521,52 @@ but = Button(text, action=lambda x=text: choice_box.dismiss(x)) buttons.append(but) row = Row(buttons) - row.rect = pygame.rect.Rect(0, 450, 700, 50) + row.rect = pygame.rect.Rect(250, 450, 700, 50) choice_box.add(row) choice_box.get_selection = lambda: table.get_selection() return choice_box def add_game_object(self): - classes = get_editable_game_objects() + classes = ngo.get_editable_game_objects() + choose = self._make_choice_dialog(classes) + res = choose.present() + choice = choose.get_selection() + if res == 'OK' and choice is not None: + classname = choice['classname'] + cls = choice['class'] + new_cls = self._edit_class(classname, cls, None) + if new_cls is not None: + if not self.level.try_new_object(self.level._game_objects, + new_cls, None): + alert('Failed to add GameObject %s' % classname) + + def add_enemy(self): + classes = ne.get_editable_enemies() choose = self._make_choice_dialog(classes) res = choose.present() choice = choose.get_selection() if res == 'OK' and choice is not None: - pass + classname = choice['classname'] + cls = choice['class'] + new_cls = self._edit_class(classname, cls, None) + if new_cls is not None: + if not self.level.try_new_object(self.level._enemies, + new_cls, None): + alert('Failed to add Enemy %s' % classname) - def add_enemy(self): - classes = get_editable_enemies() + def add_puzzler(self): + classes = np.get_editable_puzzlers() choose = self._make_choice_dialog(classes) res = choose.present() choice = choose.get_selection() if res == 'OK' and choice is not None: - pass - - def add_puzzler(self): - classes = get_editable_puzzlers() - choose = self._make_choice_dialog(classes) - res = choose.present() - choice = choose.get_selection() - if res == 'OK' and choice is not None: - pass + classname = choice['classname'] + cls = choice['class'] + new_cls = self._edit_class(classname, cls, None) + if new_cls is not None: + if not self.level.try_new_object(self.level._game_objects, + new_cls, None): + alert('Failed to add Puzzler %s' % classname) class PolyButton(Button):