Mercurial > mamba
view mamba/habitats/editor.py @ 337:170d4a43c00e
Don't edit the level when interacting with dialogs
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Fri, 16 Sep 2011 21:47:56 +0200 |
parents | 00c36ff53de9 |
children | 5bf35267ddc0 |
line wrap: on
line source
"""Habitat for editing levels.""" import pygame.display from pygame.locals import SWSURFACE, KEYDOWN, K_1, K_2 from mamba.engine import Habitat, NewHabitatEvent from mamba.widgets.level import EditLevelWidget from mamba.widgets.text import TextWidget, TextButton from mamba.widgets.imagebutton import ImageButtonWidget from mamba.widgets.messagebox import MessageBox from mamba.widgets.entrybox import EntryBox from mamba.widgets.listbox import ListBox from mamba.widgets.toollist import ToolListWidget from mamba.level import Level, Tileset, TILE_MAP, THING_MAP, InvalidMapError from mamba.data import (check_level_exists, get_level_list, get_tileset_list, get_track_list) from mamba.constants import (SCREEN, EDIT_SCREEN, NAME, ESCAPE_KEYS, RESERVED_NAMES) MAX_TOOLS = 6 MODE_HEIGHT = 500 class EditorHabitat(Habitat): def __init__(self, level): super(EditorHabitat, self).__init__(EDIT_SCREEN) self.level = level self.container.paused = False self.edit_widget = EditLevelWidget(self.level) self.container.add(self.edit_widget) self.container.add_callback(KEYDOWN, self.keydown_event) self.mode = 'Tiles' self.sprite_mode = 'Add' def on_enter(self): # We need to juggle the display to the correct size # This is a horrible hack pygame.display.quit() pygame.display.init() pygame.display.set_mode(EDIT_SCREEN, SWSURFACE) pygame.display.set_caption('%s Level editor' % NAME) super(EditorHabitat, self).on_enter() self.setup_toolbar() def on_exit(self): # We need to juggle the display to the correct size # This is a horrible hack super(EditorHabitat, self).on_exit() pygame.display.quit() pygame.display.init() pygame.display.set_mode(SCREEN, SWSURFACE) pygame.display.set_caption(NAME) def keydown_event(self, ev, widget): if ev.key in ESCAPE_KEYS: from mamba.habitats.mainmenu import MainMenu NewHabitatEvent.post(MainMenu()) return True elif ev.key == K_1: # Activate floor button self.floor_button.forced_click() return True def setup_toolbar(self): """Draw the editor toolbar""" button_height = 5 button_left = 820 button_padding = 2 filename = TextButton( (button_left, button_height), 'File: %s' % self.level.level_name, color='white') filename.add_callback('clicked', self.do_edit, 'Specify filename', self.level.level_name, self.check_file) self.container.add(filename) button_height += filename.rect.height + button_padding levelname = TextButton((button_left, button_height), 'Level: %s' % self.level.name, color='white') levelname.add_callback('clicked', self.do_edit, 'Edit Level Title', self.level.name, self.update_name) self.container.add(levelname) button_height += levelname.rect.height + button_padding tilesetname = TextButton((button_left, button_height), 'Tileset: %s' % self.level.tileset.name, color='white') tilesetname.add_callback('clicked', self.list_tilesets) self.container.add(tilesetname) button_height += tilesetname.surface.get_height() + button_padding trackname = TextButton((button_left, button_height), 'Music: %s' % self.level.background_track, color='white') trackname.add_callback('clicked', self.list_tracks) self.container.add(trackname) button_height += trackname.surface.get_height() + button_padding # TODO: Add Image widget for the current tool if self.mode != 'Sprites': self.current_tool = TextWidget((button_left, button_height), 'Tool: Floor', color='white') else: self.current_tool = TextWidget((button_left, button_height), '%s Sprite' % self.sprite_mode, color='white') self.container.add(self.current_tool) button_height += self.current_tool.surface.get_height() button_height += button_padding if self.mode != 'Sprites': self.floor_button = ImageButtonWidget( (button_left, button_height), self.level.tileset.floor, 'Floor', color='white') self.container.add(self.floor_button) self.floor_button.add_callback('clicked', self.change_tool, '.', 'Floor') self.edit_widget.set_tool('.') button_height += (self.floor_button.surface.get_height() + button_padding) if self.mode == 'Tiles': tile_map = TILE_MAP elif self.mode == 'Things': tile_map = THING_MAP else: tile_map = [] tool_list = [] for tile_char in sorted(tile_map): try: tile = self.level.tileset[tile_char] except pygame.error: # Ignore stuff we can't load for now continue if tile is None: continue if tile.name: text = tile.name else: text = 'Tile' tile_button = ImageButtonWidget((0, 0), tile.image, text, color='white') tile_button.add_callback('clicked', self.change_tool, tile_char, text) tool_list.append(tile_button) if self.mode == "Sprites": for name in ['Add', 'Edit', 'Delete']: tile_button = TextButton((0, 0), '%s Sprite' % name) tile_button.add_callback('clicked', self.sprite_tool, name) tool_list.append(tile_button) self.tool_widget = ToolListWidget((button_left, button_height), tool_list, MAX_TOOLS, start_key=K_2) self.container.add(self.tool_widget) button_height = self.container.rect.top + MODE_HEIGHT if self.mode == 'Tiles': mode_button1 = TextButton((button_left, button_height), 'Things') mode_button1.add_callback('clicked', self.change_toolbar, 'Things') mode_button2 = TextButton((button_left + 100, button_height), 'Sprites') mode_button2.add_callback('clicked', self.change_toolbar, 'Sprites') elif self.mode == 'Things': mode_button1 = TextButton((button_left, button_height), 'Tiles') mode_button1.add_callback('clicked', self.change_toolbar, 'Tiles') mode_button2 = TextButton((button_left + 100, button_height), 'Sprites') mode_button2.add_callback('clicked', self.change_toolbar, 'Sprites') elif self.mode == 'Sprites': mode_button1 = TextButton((button_left, button_height), 'Tiles') mode_button1.add_callback('clicked', self.change_toolbar, 'Tiles') mode_button2 = TextButton((button_left + 100, button_height), 'Things') mode_button2.add_callback('clicked', self.change_toolbar, 'Things') self.container.add(mode_button1) self.container.add(mode_button2) button_height += mode_button1.rect.height + button_padding button_height += 2 new = TextButton((button_left, button_height), "New") new.add_callback('clicked', self.new) self.container.add(new) load = TextButton((button_left + 60, button_height), "Load") load.add_callback('clicked', self.load) self.container.add(load) save = TextButton((button_left + 120, button_height), "Save") save.add_callback('clicked', self.save) self.container.add(save) def change_tool(self, ev, widget, new_tool, text): self.edit_widget.set_tool(new_tool) self.current_tool.text = 'Tool: %s' % text self.current_tool.prepare() return True def save(self, ev, widget): message = None if not self.level.level_name: message = MessageBox((300, 300), 'Please enter a name') elif self.level.level_name in RESERVED_NAMES: message = MessageBox((300, 300), 'Reserved level name') if message: self.container.paused = True self.container.add(message) message.grab_focus() return self.level.save_level() return True def new(self, ev, widget): self.load_level(ev, widget, 'blank') return True def load(self, ev, widget): self.container.paused = True levels = get_level_list() load_list = [] for level_name in levels: if level_name in RESERVED_NAMES: continue load_button = TextButton((0, 0), level_name) load_button.add_callback('clicked', self.load_level, level_name) load_list.append(load_button) load_dialog = ListBox((200, 200), 'Select Level', load_list) self.container.add(load_dialog) load_dialog.grab_focus() return True def load_level(self, ev, widget, level_name): try: new_level = Level(level_name) except (IOError, InvalidMapError, pygame.error), error: message = MessageBox((300, 300), 'Loading Level Failed: %s' % error, color='red') self.container.paused = True self.container.add(message) message.grab_focus() return False self.container.remove(self.edit_widget) self.level = new_level if level_name in RESERVED_NAMES: self.level.level_name = '' # Special case for new level self.container.paused = False self.edit_widget = EditLevelWidget(self.level) self.container.add(self.edit_widget) self.clear_toolbar() self.setup_toolbar() def change_toolbar(self, ev, widget, new_mode): self.mode = new_mode self.edit_widget.tile_mode = (self.mode != 'Sprites') self.clear_toolbar() self.setup_toolbar() return True def clear_toolbar(self): """Remove every non-edit widget from the container""" for widget in self.container.children[:]: if widget is not self.edit_widget: self.container.remove(widget) def do_edit(self, ev, widget, message, init_value, callback): self.container.paused = True editbox = EntryBox((200, 200), message, init_value, callback) self.container.add(editbox) editbox.grab_focus() return True def update_name(self, new_name): self.container.paused = False self.level.name = new_name self.clear_toolbar() self.setup_toolbar() return True def list_tilesets(self, ev, widget): self.container.paused = True tilesets = get_tileset_list() load_list = [] for name in tilesets: if name == 'common': continue load_button = TextButton((0, 0), name) load_button.add_callback('clicked', self.change_tileset, name) load_list.append(load_button) load_dialog = ListBox((200, 200), 'Select Level', load_list) self.container.add(load_dialog) load_dialog.grab_focus() return True def list_tracks(self, ev, widget): self.container.paused = True tracks = get_track_list() load_list = [] for name in tracks: load_button = TextButton((0, 0), name) load_button.add_callback('clicked', self.change_track, name) load_list.append(load_button) load_dialog = ListBox((200, 200), 'Select Level', load_list, 6) self.container.add(load_dialog) load_dialog.grab_focus() return True def change_tileset(self, ev, widget, new_name): self.level.update_tiles_ascii() old_tileset = self.level.tileset try: self.level.tileset = Tileset(new_name) self.level.restart() except pygame.error, error: self.level.tileset = old_tileset message = MessageBox((300, 300), 'Unable to change tileset:: %s' % error, self.refresh_display, color='red') self.container.paused = True self.container.add(message) message.grab_focus() return True self.container.paused = False self.clear_toolbar() self.setup_toolbar() return True def change_track(self, ev, widget, new_name): self.container.paused = False self.level.background_track = new_name self.clear_toolbar() self.setup_toolbar() return True def refresh_display(self): self.level.restart() self.clear_toolbar() self.setup_toolbar() return True def check_file(self, new_name): message = None if new_name == self.level.level_name: return True # No-op change if not new_name: message = MessageBox((300, 300), 'Please enter a name') if new_name in RESERVED_NAMES: # This case is caught by the existance check, but the # importance of the reserved names means we use a different # message message = MessageBox((300, 300), 'Reserved level name') elif check_level_exists(new_name): message = MessageBox((300, 300), 'Name already in use') if message: self.container.paused = True self.container.add(message) message.grab_focus() return False self.container.paused = False self.level.level_name = new_name self.clear_toolbar() self.setup_toolbar() return True def sprite_tool(self, ev, widget, sprite_mode): """Handle sprite stuff""" self.sprite_mode = sprite_mode self.clear_toolbar() self.setup_toolbar() return True