view mamba/habitats/editor.py @ 240:f0c14d9abd84

Hack in multi-page toolbar
author Neil Muller <drnlmuller@gmail.com>
date Wed, 14 Sep 2011 23:57:00 +0200
parents 9498b259c248
children 74ae1645df6e
line wrap: on
line source

"""Habitat for editing levels."""

import pygame.display
from pygame.locals import SWSURFACE, KEYDOWN

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.level import Level, TILE_MAP, THING_MAP
from mamba.data import check_level_exists
from mamba.constants import SCREEN, EDIT_SCREEN, NAME, ESCAPE_KEYS

MAX_TOOLS = 8


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'
        self.tool_page = 0

    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())

    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
        floor_button = ImageButtonWidget(
                (button_left, button_height), self.level.tileset.floor,
                'Floor', color='white')
        self.container.add(floor_button)
        floor_button.add_callback('clicked', self.change_tool,
                '.', 'Floor')
        self.edit_widget.set_tool('.')
        button_height += 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'
        total_tools = len(tile_map)
        start_page = MAX_TOOLS * self.tool_page
        end_page = start_page + MAX_TOOLS
        tile_map = sorted(tile_map)[start_page:end_page]
        for tile_char in 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(
                    (button_left, button_height), tile.image,
                    text, color='white')
            tile_button.add_callback('clicked', self.change_tool,
                    tile_char, text)
            self.container.add(tile_button)
            button_height += \
                    tile_button.surface.get_height() + button_padding
        button_height += 2

        prev_page = None
        next_page = None
        if start_page > 0:
            prev_page = TextButton((button_left, button_height),
                    'Prev')
            prev_page.add_callback('clicked', self.change_page, -1)
            self.container.add(prev_page)
        if end_page < total_tools:
            next_page = TextButton((button_left + 100, button_height),
                    'Next')
            next_page.add_callback('clicked', self.change_page, +1)
            self.container.add(next_page)
        if prev_page:
            button_height += prev_page.rect.height
        elif next_page:
            button_height += next_page.rect.height
        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

        save_button = TextButton((button_left, button_height), "Save Level")
        save_button.add_callback('clicked', self.save)
        self.container.add(save_button)

    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):
        self.level.save_level()

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

    def change_page(self, ev, widget, change):
        self.tool_page += change
        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