view mamba/habitats/editor.py @ 276:9c57025781e7

Warn on enter filename results
author Neil Muller <drnlmuller@gmail.com>
date Thu, 15 Sep 2011 17:57:28 +0200
parents 51bec5e6191e
children 82aa91664e27
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
from mamba.data import check_level_exists, list_levels, list_tilesets
from mamba.constants import (SCREEN, EDIT_SCREEN, NAME, ESCAPE_KEYS,
        RESERVED_NAMES)

MAX_TOOLS = 6


class EditorHabitat(Habitat):
    def __init__(self, level_name):
        super(EditorHabitat, self).__init__(EDIT_SCREEN)
        self.level = Level(level_name)
        self.edit_widget = EditLevelWidget(self.level)
        self.container.add(self.edit_widget)
        self.container.add_callback(KEYDOWN, self.keydown_event)
        self.mode = 'Tile'

    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())
        elif ev.key == K_1:
            # Activate floor button
            self.floor_button.forced_click()

    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
        # TODO: Add Image widget for the current tool
        self.current_tool = TextWidget((button_left, button_height),
                'Tool: Floor', color='white')
        self.container.add(self.current_tool)
        button_height += self.current_tool.surface.get_height()
        button_height += button_padding
        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 == 'Tile':
            tile_map = TILE_MAP
            change_mode_text = 'Switch to Things'
        elif self.mode == 'Thing':
            tile_map = THING_MAP
            change_mode_text = 'Switch to Tiles'
        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)
        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.tool_widget.rect.height + 2

        mode_button = TextButton((button_left, button_height),
                change_mode_text)
        mode_button.add_callback('clicked', self.change_toolbar)
        self.container.add(mode_button)
        button_height += mode_button.surface.get_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()

    def save(self, ev, widget):
        if self.level.level_name in RESERVED_NAMES:
            print "Can't save over reserved name"
            return
        if not self.level:
            print "Need a level name"
            return
        self.level.save_level()

    def new(self, ev, widget):
        self.load_level(ev, widget, 'blank')

    def load(self, ev, widget):
        levels = list_levels()
        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()

    def load_level(self, ev, widget, level_name):
        self.container.remove(self.edit_widget)
        self.level = Level(level_name)
        if level_name in RESERVED_NAMES:
            self.level.level_name = ''  # Special case for new level
        self.edit_widget = EditLevelWidget(self.level)
        self.container.add(self.edit_widget)
        self.clear_toolbar()
        self.setup_toolbar()

    def change_toolbar(self, ev, widget):
        if self.mode == 'Tile':
            self.mode = 'Thing'
        elif self.mode == 'Thing':
            self.mode = 'Tile'
        self.clear_toolbar()
        self.setup_toolbar()

    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):
        editbox = EntryBox((200, 200), message, init_value, callback)
        self.container.add(editbox)
        editbox.grab_focus()

    def update_name(self, new_name):
        self.level.name = new_name
        self.clear_toolbar()
        self.setup_toolbar()
        return True

    def list_tilesets(self, ev, widget):
        tilesets = list_tilesets()
        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()

    def change_tileset(self, ev, widget, new_name):
        self.level.tileset = Tileset(new_name)
        self.level.update_tiles_ascii()
        self.level.restart()
        self.clear_toolbar()
        self.setup_toolbar()
        return True

    def check_file(self, new_name):
        messagebox = None
        if new_name == self.level.level_name:
            return True  # No-op change
        if not new_name:
            messagebox = MessageBox((300, 300), 'Please enter a name')
        if check_level_exists(new_name):
            messagebox = MessageBox((300, 300), 'Name already in use')
        if messagebox:
            self.container.add(messagebox)
            messagebox.grab_focus()
            return False
        self.level.level_name = new_name
        self.clear_toolbar()
        self.setup_toolbar()
        return True