view mamba/habitats/editor.py @ 270:3c95ba7408f1

Add protected level name list. Add load & new buttons
author Neil Muller <drnlmuller@gmail.com>
date Thu, 15 Sep 2011 13:25:00 +0200
parents 1e8dca95c48a
children a061dd62127c
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.toollist import ToolListWidget
from mamba.level import Level, TILE_MAP, THING_MAP
from mamba.data import check_level_exists
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.do_edit, 'Edit Tileset',
                self.level.tileset.name, self.check_tileset)
        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
        self.level.save_level()

    def new(self, ev, widget):
        pass

    def load(self, ev, widget):
        pass

    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 check_tileset(self, new_name):
        return False

    def check_file(self, new_name):
        if new_name == self.level.level_name:
            return True  # No-op change
        if check_level_exists(new_name):
            # TODO: Popup warning
            return False
        self.level.level_name = new_name
        self.clear_toolbar()
        self.setup_toolbar()
        return True