changeset 854:79b5c1be9a5e default tip

Remove pyntnclick, it's its own library, now
author Stefano Rivera <stefano@rivera.za.net>
date Sat, 21 Jun 2014 22:06:09 +0200
parents f95830b58336
children
files gamelib/version.py pyntnclick/__init__.py pyntnclick/constants.py pyntnclick/cursor.py pyntnclick/data/__init__.py pyntnclick/data/images/pyntnclick/end.png pyntnclick/data/images/pyntnclick/hand.png pyntnclick/data/images/pyntnclick/start.png pyntnclick/data/locale/README.txt pyntnclick/data/po/POTFILES pyntnclick/data/po/af.po pyntnclick/data/po/pyntnclick-tools.pot pyntnclick/data/sources/images/end.xcf pyntnclick/data/sources/images/start.xcf pyntnclick/engine.py pyntnclick/gamescreen.py pyntnclick/i18n.py pyntnclick/image_transforms.py pyntnclick/main.py pyntnclick/menuscreen.py pyntnclick/resources.py pyntnclick/scenewidgets.py pyntnclick/sound.py pyntnclick/speech.py pyntnclick/state.py pyntnclick/tests/__init__.py pyntnclick/tests/game_logic_utils.py pyntnclick/tests/mad_clicker.py pyntnclick/tests/test_resources.py pyntnclick/tools/__init__.py pyntnclick/tools/gen_sound.py pyntnclick/tools/rect_drawer.py pyntnclick/utils.py pyntnclick/version.py pyntnclick/widgets/__init__.py pyntnclick/widgets/base.py pyntnclick/widgets/filechooser.py pyntnclick/widgets/imagebutton.py pyntnclick/widgets/text.py pyntnclick/widgets/toollist.py
diffstat 36 files changed, 1 insertions(+), 4544 deletions(-) [+]
line wrap: on
line diff
--- a/gamelib/version.py	Sat Jun 21 22:04:35 2014 +0200
+++ b/gamelib/version.py	Sat Jun 21 22:06:09 2014 +0200
@@ -72,6 +72,7 @@
 ]
 
 INSTALL_REQUIRES = [
+    'pyntnclick',
 ]
 
 # Install these manually
--- a/pyntnclick/constants.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-# Useful constants
-# copyright boomslang team (see COPYRIGHT file for details)
-
-import os
-
-DEBUG_ENVVAR = 'PYNTNCLICK_DEBUG'
-
-
-def _get_debug():
-    debug = os.getenv(DEBUG_ENVVAR, default=False)
-    if debug in [False, 'False', '0']:
-        return False
-    return True
-
-
-class GameConstants(object):
-    title = None
-    short_name = 'pyntnclick'
-    # Icon for the main window, in the icons basedir
-    icon = None
-
-    screen = (800, 600)
-    snd_freq = 44100
-    snd_bitsize = -16
-    snd_channels = 2
-    snd_buffer = 1024  # no. of samples
-
-    button_size = 50
-    scene_size = (screen[0], screen[1] - button_size)
-    frame_rate = 25
-    debug = _get_debug()
-
-    font = 'DejaVuSans.ttf'
-    bold_font = 'DejaVuSans-Bold.ttf'
-    mono_font = 'DejaVuSans-Mono.ttf'
-    font_size = 16
-    text_color = 'black'
-    label_padding = 10
-    label_border = 3
-    label_bg_color = (180, 180, 180, 220)
-    label_border_color = (0, 0, 0, 0xFF)
-    button_color = (0xFF, 0xFF, 0xFF, 0xFF)
-    button_bg_color = (0x66, 0x66, 0x66, 0xFF)
-    button_disabled_color = (0x66, 0x66, 0x66, 0xFF)
-
-    modal_obscure_color = (0, 0, 0, 0xB0)
--- a/pyntnclick/cursor.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-# cursor.py
-# Copyright Boomslang team, 2010 (see COPYING File)
-# Sprite Cursor
-
-from pygame.sprite import Sprite, RenderUpdates
-import pygame
-import pygame.color
-import pygame.mouse
-
-from pyntnclick.engine import Screen
-from pyntnclick.image_transforms import Colour
-
-
-class CursorSprite(Sprite):
-    "A Sprite that follows the Cursor"
-
-    def __init__(self, filename, x=None, y=None):
-        Sprite.__init__(self)
-        self.filename = filename
-        self.pointer_x = x
-        self.pointer_y = y
-        self.highlighted = False
-        self.highlight_colour = (255, 100, 100, 255)
-
-    def load(self, resources):
-        if not hasattr(self, 'plain_image'):
-            self.highlight_transform = Colour(self.highlight_colour)
-            self.plain_image = resources.get_image('items', self.filename)
-            self.highlighted_image = resources.get_image('items',
-                    self.filename, transforms=(self.highlight_transform,))
-            self.image = self.plain_image
-            self.rect = self.image.get_rect()
-            if self.pointer_x is None:
-                self.pointer_x = self.rect.size[0] // 2
-            if self.pointer_y is None:
-                self.pointer_y = self.rect.size[1] // 2
-
-    def update(self):
-        pos = pygame.mouse.get_pos()
-        self.rect.left = pos[0] - self.pointer_x
-        self.rect.top = pos[1] - self.pointer_y
-
-    def set_highlight(self, enable):
-        self.image = self.highlighted_image if enable else self.plain_image
-
-
-HAND = CursorSprite('hand.png', 12, 0)
-
-
-class CursorScreen(Screen):
-    """A Screen with custom cursors"""
-
-    def setup(self):
-        self._cursor_group = RenderUpdates()
-        self._loaded_cursor = None
-        self.set_cursor(None)
-
-    def on_enter(self):
-        super(CursorScreen, self).on_enter()
-        pygame.mouse.set_visible(0)
-
-    def on_exit(self):
-        super(CursorScreen, self).on_exit()
-        pygame.mouse.set_visible(1)
-
-    def draw(self, surface):
-        super(CursorScreen, self).draw(surface)
-        self.set_cursor(self.game.tool)
-        self._loaded_cursor.set_highlight(self.cursor_highlight())
-        self._cursor_group.update()
-        self._cursor_group.draw(surface)
-
-    def set_cursor(self, item):
-        if item is None or item.CURSOR is None:
-            cursor = HAND
-        else:
-            cursor = item.CURSOR
-        if cursor != self._loaded_cursor:
-            self._loaded_cursor = cursor
-            self._loaded_cursor.load(self.gd.resource)
-            self._cursor_group.empty()
-            self._cursor_group.add(self._loaded_cursor)
-
-    def cursor_highlight(self):
-        return self.container.mouseover_widget.highlight_cursor
Binary file pyntnclick/data/images/pyntnclick/end.png has changed
Binary file pyntnclick/data/images/pyntnclick/hand.png has changed
Binary file pyntnclick/data/images/pyntnclick/start.png has changed
--- a/pyntnclick/data/locale/README.txt	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-This is for mo files for the pyntnclick tools.
-
-We don't want to store the mo files in VCS.
--- a/pyntnclick/data/po/POTFILES	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-pyntnclick/tools/rect_drawer.py
--- a/pyntnclick/data/po/af.po	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-01-29 17:45+0200\n"
-"PO-Revision-Date: 2013-01-27 14:11+0200\n"
-"Last-Translator: Neil Muller <drnlmuller@gmail.com>\n"
-"Language-Team: Afrikaans\n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: pyntnclick/tools/rect_drawer.py:127
-msgid "Close"
-msgstr "Sluit"
-
-#: pyntnclick/tools/rect_drawer.py:161
-msgid "draw"
-msgstr "teken"
-
-#: pyntnclick/tools/rect_drawer.py:163
-msgid "cycle"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:165
-msgid "delete"
-msgstr "verwyder"
-
-#: pyntnclick/tools/rect_drawer.py:167
-msgid "image"
-msgstr "prent"
-
-#: pyntnclick/tools/rect_drawer.py:173
-#, python-format
-msgid "Thing %(thing)s Interact %(interact)s"
-msgstr "Ding %(thing)s Interact %(interact)s"
-
-#: pyntnclick/tools/rect_drawer.py:178
-msgid "     Rects"
-msgstr "    Reghoeke"
-
-#: pyntnclick/tools/rect_drawer.py:203
-msgid "Existing Intersecting rects"
-msgstr "Bestande reghoeke wat krius"
-
-#: pyntnclick/tools/rect_drawer.py:225 pyntnclick/tools/rect_drawer.py:239
-msgid "Intersecting rects"
-msgstr "Reghoeke wat kruis"
-
-#: pyntnclick/tools/rect_drawer.py:226
-#, python-format
-msgid "  Object %s"
-msgstr " Voorwerp %s"
-
-#: pyntnclick/tools/rect_drawer.py:240
-#, python-format
-msgid "  Object %(object1)s and %(object2)s"
-msgstr " Voorwerpe %(object1)s en %(object2)s"
-
-#: pyntnclick/tools/rect_drawer.py:365
-#, python-format
-msgid "Rect %d : "
-msgstr "Reghoek %d : "
-
-#: pyntnclick/tools/rect_drawer.py:371
-#, python-format
-msgid "Image %d"
-msgstr "Prentjie %d"
-
-#: pyntnclick/tools/rect_drawer.py:593
-msgid "Mode : "
-msgstr "Modus : "
-
-#: pyntnclick/tools/rect_drawer.py:600
-#, python-format
-msgid "Mode : %s"
-msgstr "Modus : %s"
-
-#: pyntnclick/tools/rect_drawer.py:630
-#, python-format
-msgid "Invalid scene: %s"
-msgstr "Ongelidge toneel: %s"
-
-#: pyntnclick/tools/rect_drawer.py:637
-#, python-format
-msgid "Invalid detail: %s"
-msgstr "Ongelidge gedeelte toneel: %s"
-
-#: pyntnclick/tools/rect_drawer.py:646
-msgid "Draw Rect"
-msgstr "Teken Reghoek"
-
-#: pyntnclick/tools/rect_drawer.py:649
-msgid "Load image"
-msgstr "Laai prentjie"
-
-#: pyntnclick/tools/rect_drawer.py:652
-msgid "Place/Move images"
-msgstr "Plass/Beweeg prente"
-
-#: pyntnclick/tools/rect_drawer.py:658
-msgid "Cycle interacts"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:661
-msgid "Delete Objects"
-msgstr "Verwyder Voorwerpe"
-
-#: pyntnclick/tools/rect_drawer.py:667
-msgid "Print objects"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:671
-msgid "Show Things (t)"
-msgstr "Wys Dinge (t)"
-
-#: pyntnclick/tools/rect_drawer.py:675
-msgid "Show Thing Rects (r)"
-msgstr "Wys Ding Reghoeke (r)"
-
-#: pyntnclick/tools/rect_drawer.py:679
-msgid "Show Images (i)"
-msgstr "Wys Prentjies (i)"
-
-#: pyntnclick/tools/rect_drawer.py:683
-msgid "Opaque Images (o)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:687
-msgid "Show Drawn Rects (d)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:691
-msgid "Show Toolbar (b)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:695
-msgid "Show Animations (a)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:699
-msgid "Zoom (z)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:703
-msgid "Quit"
-msgstr ""
--- a/pyntnclick/data/po/pyntnclick-tools.pot	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-01-30 17:33+0200\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: pyntnclick/tools/rect_drawer.py:127
-msgid "Close"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:161
-msgid "draw"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:163
-msgid "cycle"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:165
-msgid "delete"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:167
-msgid "image"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:173
-#, python-format
-msgid "Thing %(thing)s Interact %(interact)s"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:178
-msgid "     Rects"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:203
-msgid "Existing Intersecting rects"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:225 pyntnclick/tools/rect_drawer.py:239
-msgid "Intersecting rects"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:226
-#, python-format
-msgid "  Object %s"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:240
-#, python-format
-msgid "  Object %(object1)s and %(object2)s"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:365
-#, python-format
-msgid "Rect %d : "
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:371
-#, python-format
-msgid "Image %d"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:593
-msgid "Mode : "
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:600
-#, python-format
-msgid "Mode : %s"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:630
-#, python-format
-msgid "Invalid scene: %s"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:637
-#, python-format
-msgid "Invalid detail: %s"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:646
-msgid "Draw Rect"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:649
-msgid "Load image"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:652
-msgid "Place/Move images"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:658
-msgid "Cycle interacts"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:661
-msgid "Delete Objects"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:667
-msgid "Print objects"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:671
-msgid "Show Things (t)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:675
-msgid "Show Thing Rects (r)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:679
-msgid "Show Images (i)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:683
-msgid "Opaque Images (o)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:687
-msgid "Show Drawn Rects (d)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:691
-msgid "Show Toolbar (b)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:695
-msgid "Show Animations (a)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:699
-msgid "Zoom (z)"
-msgstr ""
-
-#: pyntnclick/tools/rect_drawer.py:703
-msgid "Quit"
-msgstr ""
Binary file pyntnclick/data/sources/images/end.xcf has changed
Binary file pyntnclick/data/sources/images/start.xcf has changed
--- a/pyntnclick/engine.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-"""Game engine and top-level game loop."""
-
-import pygame
-import pygame.event
-import pygame.display
-import pygame.time
-from pygame.locals import QUIT, USEREVENT
-
-# We can't do this via our usual UserEvent trickey
-# as it gets generated by pygame.music, which only
-# takes an event type
-MUSIC_ENDED = USEREVENT + 1
-
-
-class Engine(object):
-    def __init__(self, gd):
-        self._screen = None
-        self._gd = gd
-        self.screens = {}
-
-    def set_screen(self, screen_name):
-        if self._screen is not None:
-            self._screen.on_exit()
-        self._screen = self.screens[screen_name]
-        if self._screen is not None:
-            self._screen.on_enter()
-
-    def add_screen(self, name, screen):
-        self.screens[name] = screen
-
-    def run(self):
-        """Game loop."""
-
-        get_events = pygame.event.get
-        flip = pygame.display.flip
-        clock = pygame.time.Clock()
-        while True:
-            events = get_events()
-            for ev in events:
-                if ev.type == QUIT:
-                    return
-                elif ev.type == MUSIC_ENDED:
-                    self._gd.sound.music_ended()
-                elif ScreenChangeEvent.matches(ev):
-                    self.set_screen(ev.screen_name)
-                elif ScreenEvent.matches(ev):
-                    self.screens[ev.screen_name].process_event(ev.event_name,
-                                                               ev.data)
-                else:
-                    self._screen.dispatch(ev)
-            # Ping the screen / scene
-            self._screen.animate()
-            surface = pygame.display.get_surface()
-            self._screen.draw(surface)
-            flip()
-            self._fps = 1000.0 / clock.tick(
-                    self._gd.constants.frame_rate)
-
-
-class Screen(object):
-    """A top level object for the screen being displayed"""
-
-    def __init__(self, gd):
-        # Avoid import loop
-        from pyntnclick.widgets.base import Container
-
-        self.gd = gd
-        self.resource = gd.resource
-
-        self.surface_size = gd.constants.screen
-        self.surface = None
-        self.container = Container((0, 0), self.gd, self.surface_size)
-        self.setup()
-
-    def on_enter(self):
-        """Called when this becomes the current screen."""
-        # Create the surface here as flipping between editor and
-        # other things kills pygame.display
-        self.surface = pygame.Surface(self.surface_size)
-
-    def on_exit(self):
-        """Called when this stops being the current screen."""
-        self.surface = None
-
-    def setup(self):
-        """Override for initialization"""
-        pass
-
-    def dispatch(self, ev):
-        self.container.event(ev)
-
-    def animate(self):
-        """Called every tick - used for peroidic events, etc.
-
-           Interested classes are expected to override this"""
-        pass
-
-    def draw_background(self):
-        self.surface.fill(pygame.Color('gray'))
-
-    def draw(self, surface):
-        if self.surface:
-            self.draw_background()
-            self.container.draw(self.surface)
-            surface.blit(self.surface, self.surface.get_rect())
-
-    def display_dialog(self, dialog):
-        self.container.paused = True
-        self.container.add(dialog)
-        dialog.grab_focus()
-
-    def change_screen(self, new_screen_name):
-        ScreenChangeEvent.post(new_screen_name)
-
-    def screen_event(self, screen_name, event_name, data=None):
-        ScreenEvent.post(screen_name, event_name, data)
-
-    def process_event(self, event_name, data):
-        pass
-
-
-class UserEvent(object):
-    """A user event type allowing subclassing,
-       to provide an infinate number of user-defined events
-    """
-
-    TYPE = "UNKNOWN"
-
-    @classmethod
-    def post(cls, **kws):
-        ev = pygame.event.Event(USEREVENT, utype=cls.TYPE, **kws)
-        pygame.event.post(ev)
-
-    @classmethod
-    def matches(cls, ev):
-        return ev.type == USEREVENT and ev.utype == cls.TYPE
-
-
-class ScreenChangeEvent(UserEvent):
-
-    TYPE = "SCREEN_CHANGE"
-
-    @classmethod
-    def post(cls, screen_name):
-        super(ScreenChangeEvent, cls).post(screen_name=screen_name)
-
-
-class ScreenEvent(UserEvent):
-
-    TYPE = "SCREEN_EVENT"
-
-    @classmethod
-    def post(cls, screen_name, event_name, data):
-        super(ScreenEvent, cls).post(screen_name=screen_name,
-                                     event_name=event_name, data=data)
--- a/pyntnclick/gamescreen.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,399 +0,0 @@
-# gamescreen.py
-# Copyright Boomslang team, 2010 (see COPYING File)
-# Main menu for the game
-
-import pygame.draw
-from pygame import Surface
-from pygame.color import Color
-from pygame.locals import MOUSEBUTTONDOWN, MOUSEMOTION, KEYDOWN, K_ESCAPE
-
-from pyntnclick.i18n import _
-from pyntnclick.cursor import CursorScreen
-from pyntnclick.engine import Screen
-from pyntnclick.widgets.base import (
-    Container, ModalStackContainer, ModalWrapper)
-from pyntnclick.widgets.text import TextButton, WrappedTextLabel
-from pyntnclick.widgets.imagebutton import ImageButtonWidget
-
-
-class InventorySlot(ImageButtonWidget):
-    SELECTED_COLOR = Color("yellow")
-    SELECTED_WIDTH = 2
-
-    def __init__(self, pos, gd, size):
-        self.item = None
-        super(InventorySlot, self).__init__(pos, gd, None, size)
-        self.add_callback(MOUSEBUTTONDOWN, self.mouse_down)
-
-    def set_item(self, item):
-        self.item = item
-
-    def draw(self, surface):
-        if self.item:
-            surface.blit(self.item.get_inventory_image(), self.rect)
-            if self.selected:
-                pygame.draw.rect(surface, self.SELECTED_COLOR,
-                                 self.rect, self.SELECTED_WIDTH)
-
-    @property
-    def selected(self):
-        return self.parent.game.tool is self.item
-
-    def mouse_down(self, event, widget):
-        if event.button != 1 or not self.item:
-            return
-        if self.selected:
-            self.parent.select(None)
-        elif self.item.is_interactive(self.parent.game.tool):
-            result = self.item.interact(self.parent.game.tool)
-            self.parent.screen.handle_result(result)
-        else:
-            self.parent.select(self.item)
-
-
-class UpDownButton(TextButton):
-    # TextButton for now.
-    def __init__(self, pos, gd, size=None):
-        super(UpDownButton, self).__init__(pos, gd, self.TEXT, size=size,
-                                           padding=3)
-
-
-class UpButton(UpDownButton):
-    TEXT = u'\N{UPWARDS ARROW}UP'
-
-
-class DownButton(UpDownButton):
-    TEXT = u'\N{DOWNWARDS ARROW}DN'
-
-
-class InventoryView(Container):
-    MIN_UPDOWN_WIDTH = 20
-
-    def __init__(self, pos, gd, size, screen):
-        self.bsize = gd.constants.button_size
-        super(InventoryView, self).__init__(pos, gd, size)
-        self.screen = screen
-        self.game = screen.game
-
-        slots = (self.rect.width - self.MIN_UPDOWN_WIDTH) / self.bsize
-        self.slots = [self.add(self.make_slot(i)) for i in range(slots)]
-        self.inv_offset = 0
-
-        self.updown_width = self.rect.width - slots * self.bsize
-        ud_left = self.rect.right - self.updown_width
-        self.up_button = self.add(UpButton((ud_left, self.rect.top), gd,
-                    (self.updown_width, self.rect.height / 2)))
-        self.up_button.add_callback(MOUSEBUTTONDOWN, self.up_callback)
-        self.down_button = self.add(DownButton(
-                    (ud_left, self.rect.top + self.rect.height / 2), gd,
-                    (self.updown_width, self.rect.height / 2)))
-        self.down_button.add_callback(MOUSEBUTTONDOWN, self.down_callback)
-
-        self.add_callback(MOUSEBUTTONDOWN, self.mouse_down)
-        self.update_slots()
-
-    def make_slot(self, slot):
-        pos = (self.rect.left + slot * self.bsize, self.rect.top)
-        size = (self.bsize, self.rect.height)
-        return InventorySlot(pos, self.gd, size)
-
-    def up_callback(self, event, widget):
-        self.inv_offset = max(self.inv_offset - len(self.slots), 0)
-        self.update_slots()
-
-    def down_callback(self, event, widget):
-        self.inv_offset += len(self.slots)
-        self.update_slots()
-
-    def update_slots(self):
-        items = (self.slot_items + [None] * len(self.slots))[:len(self.slots)]
-        for item, slot in zip(items, self.slots):
-            slot.set_item(item)
-
-        if self.inv_offset <= 0:
-            self.up_button.disable()
-        else:
-            self.up_button.enable()
-
-        max_slot = (self.inv_offset + len(self.slots))
-        if max_slot >= len(self.game.inventory()):
-            self.down_button.disable()
-        else:
-            self.down_button.enable()
-
-    @property
-    def slot_items(self):
-        item_names = self.game.inventory()[self.inv_offset:][:len(self.slots)]
-        return [self.game.get_item(name) for name in item_names]
-
-    def mouse_down(self, event, widget):
-        if event.button != 1:
-            self.game.set_tool(None)
-
-    def select(self, tool):
-        self.game.set_tool(tool)
-
-
-class SceneWidget(Container):
-    DETAIL_BORDER = 4
-    DETAIL_BORDER_COLOR = Color("black")
-
-    def __init__(self, pos, gd, size, scene, screen, is_detail=False):
-        super(SceneWidget, self).__init__(pos, gd, size)
-        self.name = scene.NAME
-        self.scene = scene
-        self.screen = screen
-        self.game = screen.game
-        self.add_callback(MOUSEBUTTONDOWN, self.mouse_down)
-        self.add_callback(MOUSEMOTION, self.mouse_move)
-        self.is_detail = is_detail
-        if is_detail:
-            self.close_button = TextButton((0, 0), self.gd, _("Close"))
-            self.close_button.do_prepare()
-            # TODO: Don't muck around with close_button's rect
-            self.close_button.rect.midbottom = self.rect.midbottom
-            self.close_button.add_callback('clicked', self.close)
-            self.add(self.close_button)
-
-    def draw(self, surface):
-        self.scene.draw(surface.subsurface(self.rect))
-        if self.is_detail:
-            border = self.rect.inflate(self.DETAIL_BORDER, self.DETAIL_BORDER)
-            pygame.draw.rect(
-                surface, self.DETAIL_BORDER_COLOR, border, self.DETAIL_BORDER)
-        if self.parent.is_top(self):
-            self.scene.draw_description(surface)
-        super(SceneWidget, self).draw(surface)
-
-    @property
-    def highlight_cursor(self):
-        return (self.scene.current_thing
-                and self.scene.current_thing.is_interactive())
-
-    def mouse_down(self, event, widget):
-        self.mouse_move(event, widget)
-        if event.button != 1:  # We have a right/middle click
-            if self.game.tool:
-                self.game.set_tool(None)
-            elif self.is_detail:
-                self.close(event, widget)
-        else:
-            pos = self.global_to_local(event.pos)
-            result = self.scene.interact(self.game.tool, pos)
-            self.screen.handle_result(result)
-
-    def animate(self):
-        self.scene.animate()
-
-    def mouse_move(self, event, widget):
-        pos = self.global_to_local(event.pos)
-        self.scene.mouse_move(pos)
-        self.game.old_pos = event.pos
-
-    def close(self, event, widget):
-        self.screen.close_detail(self)
-
-
-class ToolBar(Container):
-    def __init__(self, pos, gd, size, screen):
-        self.screen = screen
-
-        super(ToolBar, self).__init__(pos, gd, size)
-
-        self.bg_color = (31, 31, 31)
-        self.left = self.rect.left
-
-        self.menu_button = self.add_tool(
-            self.rect.height, TextButton, _("Menu"),
-            fontname=gd.constants.bold_font,
-            color="red", padding=1, border=0, bg_color="black")
-        self.menu_button.add_callback(MOUSEBUTTONDOWN, self.menu_callback)
-
-        hand_image = gd.resource.get_image('items', 'hand.png')
-        self.hand_button = self.add_tool(
-            None, ImageButtonWidget, hand_image)
-        self.hand_button.add_callback(MOUSEBUTTONDOWN, self.hand_callback)
-
-        self.inventory = self.add_tool(
-            self.rect.width - self.left, InventoryView, screen=screen)
-
-    def add_tool(self, width, cls, *args, **kw):
-        pos = (self.left, self.rect.top)
-        if width is not None:
-            kw['size'] = (width, self.rect.height)
-        tool = cls(pos, self.gd, *args, **kw)
-        self.add(tool)
-        tool.do_prepare()
-        self.left += tool.rect.width
-        return tool
-
-    def draw(self, surface):
-        bg = Surface(self.rect.size)
-        bg.fill(self.bg_color)
-        surface.blit(bg, self.rect)
-        super(ToolBar, self).draw(surface)
-
-    def hand_callback(self, event, widget):
-        self.inventory.select(None)
-
-    def menu_callback(self, event, widget):
-        self.screen.change_screen('menu')
-
-
-class GameScreen(CursorScreen):
-
-    def setup(self):
-        super(GameScreen, self).setup()
-        self.gd.running = False
-        self.create_initial_state = self.gd.initial_state
-        self.container.add_callback(KEYDOWN, self.key_pressed)
-
-    def _clear_all(self):
-        self._message_queue = []
-        for widget in self.container.children[:]:
-            self.container.remove(widget)
-
-    def process_event(self, event_name, data):
-        getattr(self, 'game_event_%s' % event_name, lambda d: None)(data)
-
-    def game_event_restart(self, data):
-        self.reset_game()
-
-    def get_save_dir(self):
-        return self.gd.get_default_save_location()
-
-    def game_event_load(self, data):
-        state = self.gd.game_state_class().load_game(
-            self.get_save_dir(), 'savegame')
-        # TODO: Handle this better.
-        if state is not None:
-            self.reset_game(state)
-
-    def game_event_save(self, data):
-        self.game.data.save_game(self.get_save_dir(), 'savegame')
-
-    def reset_game(self, game_state=None):
-        self._clear_all()
-        self.game = self.create_initial_state(game_state)
-
-        self.screen_modal = self.container.add(
-            ModalStackContainer(self.container.pos, self.gd,
-                                self.container.size))
-        self.inner_container = self.screen_modal.add(
-            Container(self.container.pos, self.gd, self.container.size))
-
-        toolbar_height = self.gd.constants.button_size
-
-        self.scene_modal = self.inner_container.add(
-            ModalStackContainer((0, 0), self.gd,
-                (self.surface_size[0], self.surface_size[1] - toolbar_height)))
-        self.toolbar = self.inner_container.add(
-            ToolBar((0, self.surface_size[1] - toolbar_height), self.gd,
-                (self.surface_size[0], toolbar_height), self))
-        self.inventory = self.toolbar.inventory
-
-        self.gd.running = True
-
-    def game_event_inventory(self, data):
-        self.inventory.update_slots()
-
-    def game_event_change_scene(self, data):
-        scene_name = data['name']
-        if data['detail']:
-            self.show_detail(scene_name)
-        else:
-            self.change_scene(scene_name)
-
-    def change_scene(self, scene_name):
-        for scene_widget in reversed(self.scene_modal.children[:]):
-            self.scene_modal.remove(scene_widget)
-            scene_widget.scene.leave()
-        self.game.data.set_current_scene(scene_name)
-        self._add_scene(self.game.scenes[scene_name])
-
-    def show_detail(self, detail_name):
-        detail_scene = self.game.detail_views[detail_name]
-        if detail_scene.name == self.scene_modal.top.name:
-            # Don't show the scene if we're already showing it
-            return
-        self._add_scene(detail_scene, True)
-
-    def _add_scene(self, scene, detail=False):
-        pos = self.scene_modal.rect.topleft
-        size = self.scene_modal.rect.size
-        if detail:
-            size = scene.get_detail_size()
-            pos = ((self.scene_modal.rect.width - size[0]) / 2,
-                   (self.scene_modal.rect.height - size[1]) / 2)
-
-        self.scene_modal.add(SceneWidget(pos, self.gd, size, scene, self,
-                                         detail))
-        self.handle_result(scene.enter())
-
-    def close_detail(self, detail=None):
-        if detail is None:
-            detail = self.scene_modal.top
-        self.scene_modal.remove(detail)
-        self.handle_result(detail.scene.leave())
-
-    def animate(self):
-        """Animate the scene widgets"""
-        for scene_widget in self.scene_modal.children:
-            scene_widget.animate()
-
-    def key_pressed(self, event, widget):
-        if event.key == K_ESCAPE:
-            self.change_screen('menu')
-
-    def end_game(self):
-        self.change_screen('end')
-
-    def show_queued_widget(self):
-        if self._message_queue:
-            # Only add a message if there isn't already one up
-            if self.screen_modal.is_top(self.inner_container):
-                widget = self._message_queue.pop(0)
-                self.screen_modal.add(
-                    ModalWrapper(widget, self.show_queued_widget))
-
-    def queue_widget(self, widget):
-        self._message_queue.append(widget)
-        self.show_queued_widget()
-
-    def show_message(self, message):
-        max_width = self.gd.constants.screen[0] - 100
-        widget = WrappedTextLabel((0, 0), self.gd, message,
-                                  max_width=max_width)
-        widget.do_prepare()
-        # TODO: Use the centering API when it exists
-        widget.rect.center = self.container.rect.center
-        self.queue_widget(widget)
-
-    def handle_result(self, resultset):
-        """Handle dealing with result or result sequences"""
-        if resultset:
-            if hasattr(resultset, 'process'):
-                resultset = [resultset]
-            for result in resultset:
-                if result:
-                    result.process(self)
-
-
-class DefEndScreen(Screen):
-    """A placeholder 'Game Over' screen so people can get started easily"""
-
-    def setup(self):
-        self.background = self.resource.get_image('pyntnclick/end.png')
-
-    def draw(self, surface):
-        surface.blit(self.background, (0, 0))
-
-
-class DefMenuScreen(Screen):
-    """A placeholder Start screen so people can get started easily"""
-
-    def setup(self):
-        self.background = self.resource.get_image('pyntnclick/start.png')
-
-    def draw(self, surface):
-        surface.blit(self.background, (0, 0))
--- a/pyntnclick/i18n.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-# internationalization
-
-from gettext import gettext
-from pkg_resources import resource_filename
-
-
-def _(s):
-    return unicode(gettext(s), "utf-8")
-
-
-def get_module_i18n_path(module, path='locale'):
-    """Get the locale data from within the module."""
-    return resource_filename(module, path)
--- a/pyntnclick/image_transforms.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-"""Transforms to apply to images when they're loaded."""
-
-from pygame.transform import rotate
-from pygame.locals import BLEND_RGBA_MULT, SRCALPHA
-from pygame.surface import Surface
-
-
-class Transform(object):
-
-    def __init__(self, func, *args):
-        self._func = func
-        self._args = args
-
-    def __call__(self, image):
-        return self._func(image, *self._args)
-
-    def __hash__(self):
-        return hash((id(self._func), self._args))
-
-    def __eq__(self, other):
-        return (self._func is other._func) and self._args == other._args
-
-    def __repr__(self):
-        return "<%s args=%r>" % (self.__class__.__name__, self._args)
-
-
-# transform that does nothing
-NULL = Transform(lambda x: x)
-
-# base rotation transforms
-R90 = Transform(rotate, 90)
-R180 = Transform(rotate, 180)
-R270 = Transform(rotate, -90)
-
-
-# overlays
-class Overlay(Transform):
-    """Overlay another image on top of the given one."""
-
-    def __init__(self, resources, image_name_fragments, blend=0):
-        super(Overlay, self).__init__(
-            self.overlay, resources, image_name_fragments, blend)
-
-    def overlay(self, image, resources, image_name_fragments, blend):
-        image = image.copy()
-        overlay = resources.load_image(image_name_fragments)
-        image.blit(overlay, (0, 0), None, blend)
-        return image
-
-
-# colour overlays
-class Colour(Transform):
-    """Overlay an image with a colour."""
-
-    def __init__(self, colour, blend=BLEND_RGBA_MULT):
-        super(Colour, self).__init__(self.colour, colour, blend)
-
-    def colour(self, image, colour, blend):
-        image = image.copy()
-        overlay = Surface(image.get_size(), SRCALPHA, image)
-        overlay.fill(colour)
-        image.blit(overlay, (0, 0), None, blend)
-        return image
--- a/pyntnclick/main.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,214 +0,0 @@
-'''Game main module.
-
-Contains the entry point used by the run_game.py script.
-
-'''
-import sys
-import gettext
-import locale
-import os
-from optparse import OptionParser
-
-import pygame
-from pygame.locals import SWSURFACE
-
-from pyntnclick.i18n import _, get_module_i18n_path
-from pyntnclick.engine import Engine
-from pyntnclick.gamescreen import DefMenuScreen, DefEndScreen, GameScreen
-from pyntnclick.constants import GameConstants, DEBUG_ENVVAR
-from pyntnclick.resources import Resources
-from pyntnclick.sound import Sound
-from pyntnclick import state
-
-from pyntnclick.tools.rect_drawer import (RectEngine, RectDrawerError,
-        make_rect_display)
-from pyntnclick.utils import list_scenes
-
-
-class GameDescriptionError(Exception):
-    """Raised when an GameDescription is invalid."""
-
-
-class GameDescription(object):
-
-    # initial scene for start of game (unless overridden by debug)
-    INITIAL_SCENE = None
-
-    # list of game scenes
-    SCENE_LIST = None
-
-    # starting menu
-    SCREENS = {
-        'menu': DefMenuScreen,
-        'end': DefEndScreen,
-        }
-
-    START_SCREEN = 'menu'
-
-    # Modules
-    RESOURCE_MODULE = 'data'
-    SCENE_MODULE = 'gamelib.scenes'
-
-    def __init__(self):
-        if self.INITIAL_SCENE is None:
-            raise GameDescriptionError("A game must have an initial scene.")
-        if not self.SCENE_LIST:
-            raise GameDescriptionError("A game must have a non-empty list"
-                                       " of scenes.")
-        if 'game' in self.SCREENS:
-            raise GameDescriptionError("The 'game' screen is reserved for the"
-                                       " game itself.")
-        self._initial_scene = self.INITIAL_SCENE
-        self._scene_list = self.SCENE_LIST
-        self._resource_module = self.RESOURCE_MODULE
-        self._debug_rects = False
-        self._screens = self.SCREENS.copy()
-        self._screens['game'] = GameScreen
-        self.constants = self.game_constants()
-
-        locale.setlocale(locale.LC_ALL, "")
-        lang = locale.getdefaultlocale(['LANGUAGE', 'LC_ALL', 'LC_CTYPE',
-                                        'LANG'])[0]
-        self.resource = Resources(self._resource_module, lang)
-        locale_path = self.resource.get_resource_path('locale')
-        gettext.bindtextdomain(self.constants.short_name, locale_path)
-        gettext.textdomain(self.constants.short_name)
-
-        popath = self.resource.get_resource_path('po')
-        self._check_translations(popath, locale_path)
-
-        self.sound = Sound(self.resource)
-        self.debug_options = []
-        self.running = False
-
-    def _check_translations(self, popath, locale_path):
-        """Check for outdated mo files"""
-        name = gettext.textdomain()  # only check the current app
-        for candidate in os.listdir(popath):
-            if candidate.endswith('.po'):
-                polang = candidate.split('.', 1)[0]
-                pofile = os.path.join(popath, candidate)
-                mofile = gettext.find(name, locale_path, (polang,))
-                if mofile is None:
-                    print 'Missing mo file for %s' % pofile
-                    continue
-                if os.stat(pofile).st_mtime > os.stat(mofile).st_mtime:
-                    print 'po file %s is newer than mo file %s' % (pofile,
-                            mofile)
-
-    def initial_state(self, game_state=None):
-        """Create a copy of the initial game state."""
-        initial_state = state.Game(self, self.game_state_class()(game_state))
-        initial_state.set_debug_rects(self._debug_rects)
-        for scene in self._scene_list:
-            initial_state.load_scenes(scene)
-        if initial_state.data['current_scene'] is None:
-            initial_state.data.set_current_scene(self._initial_scene)
-        initial_state.change_scene(initial_state.data['current_scene'])
-        return initial_state
-
-    def game_state_class(self):
-        return state.GameState
-
-    def game_constants(self):
-        return GameConstants()
-
-    def option_parser(self):
-        parser = OptionParser()
-        parser.add_option("--no-sound", action="store_false", default=True,
-                dest="sound", help="disable sound")
-        # We flag these, so we can warn the user that these require debug mode
-        self.debug_options = ['--scene', '--no-rects', '--rect-drawer',
-                '--list-scenes', '--details']
-        if self.constants.debug:
-            parser.add_option("--scene", type="str", default=None,
-                dest="scene", help="initial scene")
-            parser.add_option("--no-rects", action="store_false", default=True,
-                dest="rects", help="disable debugging rects")
-            parser.add_option("--rect-drawer", action="store_true",
-                    default=False, dest="rect_drawer",
-                    help="Launch the rect drawing helper tool. Specify the"
-                    " scene with --scene")
-            parser.add_option("--list-scenes", action="store_true",
-                    default=False, dest='list_scenes', help="List all scenes"
-                    " that can be used with --scene and exit.")
-            parser.add_option("--detail", type="str", default=None,
-                    dest="detail", help="Detailed view for rect_drawer")
-        return parser
-
-    def warn_debug(self, option):
-        """Warn the user that he needs debug mode"""
-        print '%s is only valid in debug mode' % option
-        print 'set %s to enable debug mode' % DEBUG_ENVVAR
-        print
-
-    def main(self):
-        parser = self.option_parser()
-        # This is a bit hack'ish, but works
-        if not self.constants.debug:
-            for option in self.debug_options:
-                if option in sys.argv:
-                    self.warn_debug(option)
-        opts, args = parser.parse_args(sys.argv)
-        pygame.display.init()
-        pygame.font.init()
-        if opts.sound:
-            self.sound.enable_sound(self.constants)
-        else:
-            self.sound.disable_sound()
-        if self.constants.debug:
-            if opts.scene is not None:
-                # debug the specified scene
-                self._initial_scene = opts.scene
-            self._debug_rects = opts.rects
-        if self.constants.debug and opts.list_scenes:
-            list_scenes(self.SCENE_MODULE, self._scene_list)
-            sys.exit(0)
-        if self.constants.debug and opts.rect_drawer:
-            if opts.scene is None:
-                print 'Need to supply a scene to use the rect drawer'
-                sys.exit(1)
-            locale_path = get_module_i18n_path(
-                    self.resource.DEFAULT_RESOURCE_MODULE)
-            gettext.bindtextdomain('pyntnclick-tools', locale_path)
-            gettext.textdomain('pyntnclick-tools')
-            popath = get_module_i18n_path(
-                    self.resource.DEFAULT_RESOURCE_MODULE, 'po')
-            self._check_translations(popath, locale_path)
-            make_rect_display()
-            try:
-                self.engine = RectEngine(self, opts.detail)
-            except RectDrawerError, e:
-                print 'RectDrawer failed with: %s' % e
-                sys.exit(1)
-        else:
-            pygame.display.set_mode(self.constants.screen, SWSURFACE)
-            if self.constants.icon:
-                pygame.display.set_icon(self.resource.get_image(
-                    self.constants.icon, basedir='icons'))
-            if self.constants.title:
-                title = _(self.constants.title).encode('utf-8')
-                pygame.display.set_caption(title)
-
-            self.engine = Engine(self)
-            # Initialize the special screens in the engine
-            for name, cls in self._screens.iteritems():
-                screen = cls(self)
-                self.engine.add_screen(name, screen)
-            # Should we allow the menu not to be the opening screen?
-            self.engine.set_screen(self.START_SCREEN)
-        try:
-            self.engine.run()
-        except KeyboardInterrupt:
-            pass
-
-    def get_default_save_location(self):
-        """Return a default save game location."""
-        app = self.constants.short_name
-        if sys.platform.startswith("win"):
-            if "APPDATA" in os.environ:
-                return os.path.join(os.environ["APPDATA"], app)
-            return os.path.join(os.path.expanduser("~"), "." + app)
-        elif 'XDG_DATA_HOME' in os.environ:
-            return os.path.join(os.environ["XDG_DATA_HOME"], app)
-        return os.path.join(os.path.expanduser("~"), ".local", "share", app)
--- a/pyntnclick/menuscreen.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-# menu.py
-# Copyright Boomslang team, 2010 (see COPYING File)
-# Main menu for the game
-
-import pygame.event
-from pygame.locals import QUIT
-from pyntnclick.engine import Screen
-from pyntnclick.widgets.imagebutton import ImageButtonWidget
-from pyntnclick.widgets.text import TextButton
-
-
-class MenuScreen(Screen):
-    BACKGROUND_IMAGE = None
-
-    def setup(self):
-        self._background = None
-        if self.BACKGROUND_IMAGE is not None:
-            self._background = self.resource.get_image(self.BACKGROUND_IMAGE)
-
-        self._add_new_game_button()
-        self._add_load_game_button()
-        self._add_save_game_button()
-        self._add_resume_game_button()
-        self._add_quit_button()
-
-    def on_enter(self):
-        super(MenuScreen, self).on_enter()
-        running = self.check_running()
-        self.set_button_state(self._resume_game_button, running)
-        self.set_button_state(self._load_game_button, self.check_has_saves())
-        self.set_button_state(self._save_game_button, running)
-
-    def set_button_state(self, button, enabled):
-        button.set_visible(enabled)
-        if enabled:
-            button.enable()
-        else:
-            button.disable()
-
-    def make_new_game_button(self):
-        "Override this to customise the new game button."
-        return self.make_text_button((200, 100), 'New game')
-
-    def make_load_game_button(self):
-        "Override this to customise the load game button."
-        return self.make_text_button((200, 200), 'Load game')
-
-    def make_save_game_button(self):
-        "Override this to customise the save game button."
-        return self.make_text_button((200, 300), 'Save game')
-
-    def make_resume_button(self):
-        "Override this to customise the resume game button."
-        return self.make_text_button((200, 400), 'Resume')
-
-    def make_quit_button(self):
-        "Override this to customise the quit button."
-        return self.make_text_button((200, 500), 'Quit')
-
-    def _add_new_game_button(self):
-        self._new_game_button = self.make_new_game_button()
-        self._new_game_button.add_callback('clicked', self.new_game)
-
-    def _add_load_game_button(self):
-        self._load_game_button = self.make_load_game_button()
-        self._load_game_button.add_callback('clicked', self.load_game)
-
-    def _add_save_game_button(self):
-        self._save_game_button = self.make_save_game_button()
-        self._save_game_button.add_callback('clicked', self.save_game)
-
-    def _add_resume_game_button(self):
-        self._resume_game_button = self.make_resume_game_button()
-        self._resume_game_button.add_callback('clicked', self.resume_game)
-
-    def _add_quit_button(self):
-        self._quit_button = self.make_quit_button()
-        self._quit_button.add_callback('clicked', self.quit)
-
-    def make_text_button(self, pos, text):
-        widget = TextButton(pos, self.gd, text)
-        self.container.add(widget)
-        return widget
-
-    def make_image_button(self, pos, image_name):
-        image = self.resource.get_image(image_name)
-        widget = ImageButtonWidget(pos, self.gd, image)
-        self.container.add(widget)
-        return widget
-
-    def draw_background(self):
-        if self._background is not None:
-            self.surface.blit(self._background, self.surface.get_rect())
-
-    def new_game(self, ev, widget):
-        self.screen_event('game', 'restart')
-        self.change_screen('game')
-
-    def load_game(self, ev, widget):
-        self.screen_event('game', 'load')
-        self.change_screen('game')
-
-    def save_game(self, ev, widget):
-        self.screen_event('game', 'save')
-
-    def check_running(self):
-        return self.gd.running
-
-    def check_has_saves(self):
-        import os.path
-        save_dir = self.gd.get_default_save_location()
-        return os.path.exists(
-            self.gd.game_state_class().get_save_fn(save_dir, 'savegame'))
-
-    def resume_game(self, ev, widget):
-        self.change_screen('game')
-
-    def quit(self, ev, widget):
-        pygame.event.post(pygame.event.Event(QUIT))
--- a/pyntnclick/resources.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-# -*- test-case-name: pyntnclick.tests.test_resources -*-
-
-import os
-from pkg_resources import resource_filename
-
-import pygame
-
-
-class ResourceNotFound(Exception):
-    pass
-
-
-class Resources(object):
-    """Resource loader and manager.
-
-    The `CONVERT_ALPHA` flag allows alpha conversions to be disabled so that
-    images may be loaded without having a display initialised. This is useful
-    in unit tests, for example.
-    """
-
-    DEFAULT_RESOURCE_MODULE = "pyntnclick.data"
-    CONVERT_ALPHA = True
-
-    def __init__(self, resource_module, language=None):
-        self.resource_module = resource_module
-        self.lang_dialect = language
-        self.language = language
-        if language:
-            self.language = language.split('_', 1)[0]
-        self._image_cache = {}
-        self._font_cache = {}
-        self._transformed_image_cache = {}
-
-    def get_resource_path(self, *resource_path_fragments):
-        """Find the resource in one of a number of different places.
-
-        The following directories are searched, in order:
-
-         * /<lang>_<dialect>/<resource_module>/
-         * /<lang>/<resource_module>/
-         * <resource_module>/
-         * /<lang>_<dialect>/<default_resource_module>/
-         * /<lang>/<default_resource_module>/
-         * <default_resource_module>/
-
-        If the `language` attribute is `None`, the paths with <lang> in them
-        are skipped.
-        """
-        resource_name = '/'.join(resource_path_fragments)
-        resource_name = os.path.join(*resource_name.split('/'))
-        for path in self.get_paths(resource_name):
-            if os.path.exists(path):
-                return path
-        raise ResourceNotFound(resource_name)
-
-    def get_paths(self, resource_path):
-        """Get list of resource paths to search.
-        """
-        paths = []
-        for module in [self.resource_module, self.DEFAULT_RESOURCE_MODULE]:
-            if self.lang_dialect:
-                fn = os.path.join(self.lang_dialect, resource_path)
-                paths.append(resource_filename(module, fn))
-            if self.language != self.lang_dialect:
-                fn = os.path.join(self.language, resource_path)
-                paths.append(resource_filename(module, fn))
-            paths.append(resource_filename(module, resource_path))
-        return paths
-
-    def get_image(self, *image_name_fragments, **kw):
-        """Load an image and optionally apply mutators.
-
-        All positional params end up in `image_name_fragments` and are joined
-        with the path separator.
-
-        Two keyword parameters are also accepted:
-
-         * `transforms` may contain transforms, which modify an image in-place
-           to apply various effects.
-
-         * `basedir` defaults to 'images', but may be overridden to load images
-           from other places. ('icons', for example.)
-        """
-
-        transforms = kw.get('transforms', ())
-        basedir = kw.get('basedir', 'images')
-
-        image_path = self.get_resource_path(basedir, *image_name_fragments)
-
-        key = (image_path, transforms)
-        if key in self._transformed_image_cache:
-            # We already have this cached, so shortcut the whole process.
-            return self._transformed_image_cache[key]
-
-        if image_path not in self._image_cache:
-            image = pygame.image.load(image_path)
-            if self.CONVERT_ALPHA:
-                image = image.convert_alpha(pygame.display.get_surface())
-            self._image_cache[image_path] = image
-        image = self._image_cache[image_path]
-
-        # Apply any transforms we're given.
-        for transform in transforms:
-            image = transform(image)
-        self._transformed_image_cache[key] = image
-
-        return image
-
-    def get_font(self, file_name, font_size, basedir=None):
-        """Load a a font, cached if possible."""
-        if basedir is None:
-            basedir = 'fonts'
-        key = (basedir, file_name, font_size)
-        if key not in self._font_cache:
-            fontfn = self.get_resource_path(basedir, file_name)
-            self._font_cache[key] = pygame.font.Font(fontfn, font_size)
-        return self._font_cache[key]
--- a/pyntnclick/scenewidgets.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,223 +0,0 @@
-"""Interactive elements within a Scene."""
-
-
-from pygame import Rect
-from pygame.color import Color
-from pygame.colordict import THECOLORS
-from pygame.surface import Surface
-
-from pyntnclick.state import Thing
-from pyntnclick.utils import convert_color, render_text
-from pyntnclick.widgets.text import LabelWidget
-
-
-class Interact(object):
-
-    def __init__(self, image, rect, interact_rect):
-        self.image = image
-        self.rect = rect
-        self.interact_rect = interact_rect
-
-    def set_thing(self, thing):
-        pass
-
-    def draw(self, surface):
-        if self.image is not None:
-            surface.blit(self.image, self.rect, None)
-
-    def animate(self):
-        return False
-
-
-class InteractNoImage(Interact):
-
-    def __init__(self, x, y, w, h):
-        super(InteractNoImage, self).__init__(None, None, Rect(x, y, w, h))
-
-
-class InteractDebugText(Interact):
-    """Display box with text to interact with -- mostly for debugging."""
-
-    def __init__(self, x, y, text, bg_color=None):
-        if bg_color is None:
-            bg_color = (127, 127, 127)
-        label = LabelWidget((0, 0), text)
-        # label.set_margin(5)
-        # label.border_width = 1
-        # label.border_color = (0, 0, 0)
-        # label.bg_color = bg_color
-        # label.fg_color = (0, 0, 0)
-        image = Surface(label.size)
-        rect = Rect((x, y), label.size)
-        label.draw_all(image)
-        super(InteractDebugText, self).__init__(image, rect, rect)
-
-
-class InteractText(Interact):
-    """Display a text string on a transparent background.
-
-       Used so we can easily include translatable strings in the scenes"""
-
-    def __init__(self, x, y, w, h, text, color, max_font_size, font=None,
-            centre=True):
-        self._text = text
-        self._color = convert_color(color)
-        self._max_font_size = max_font_size
-        self._font = font
-        self._centre = centre
-        rect = Rect((x, y), (w, h))
-        super(InteractText, self).__init__(None, rect, rect)
-
-    def set_thing(self, thing):
-        font_size = self._max_font_size
-        if not self._font:
-            # Pull the default font out of constants
-            self._font = thing.gd.constants.font
-        bg_color = Color(0, 0, 0, 0)  # transparent background
-        self.image = render_text(self._text, self._font, font_size,
-                self._color, bg_color, thing.resource, self.rect.size,
-                self._centre)
-
-
-class InteractRectUnion(Interact):
-
-    def __init__(self, rect_list):
-        super(InteractRectUnion, self).__init__(None, None, None)
-        rect_list = [Rect(x) for x in rect_list]
-        self.interact_rect = rect_list
-
-
-class InteractUnion(Interact):
-    """An interact made out of other interacts"""
-
-    def __init__(self, interact_list):
-        super(InteractUnion, self).__init__(None, None, None)
-        self._interact_list = interact_list
-
-    def set_thing(self, thing):
-        interact_list = []
-        for sub_interact in self._interact_list:
-            sub_interact.set_thing(thing)
-            sub_rect = sub_interact.interact_rect
-            if hasattr(sub_rect, 'collidepoint'):
-                interact_list.append(sub_interact.interact_rect)
-            else:
-                interact_list.extend(sub_interact.interact_rect)
-        self.interact_rect = interact_list
-
-    def draw(self, surface):
-        for sub_interact in self._interact_list:
-            sub_interact.draw(surface)
-
-    def animate(self):
-        for sub_interact in self._interact_list:
-            sub_interact.animate()
-
-
-class InteractImage(Interact):
-
-    def __init__(self, x, y, image_name):
-        super(InteractImage, self).__init__(None, None, None)
-        self._pos = (x, y)
-        self._image_name = image_name
-
-    def set_thing(self, thing):
-        self.image = thing.resource.get_image(thing.folder, self._image_name)
-        self.rect = Rect(self._pos, self.image.get_size())
-        self.interact_rect = self.rect
-
-    def __repr__(self):
-        return '<InteractImage: %s>' % self._image_name
-
-
-class InteractImageRect(InteractImage):
-    def __init__(self, x, y, image_name, r_x, r_y, r_w, r_h):
-        super(InteractImageRect, self).__init__(x, y, image_name)
-        self._r_pos = (r_x, r_y)
-        self._r_size = (r_w, r_h)
-
-    def set_thing(self, thing):
-        super(InteractImageRect, self).set_thing(thing)
-        self.interact_rect = Rect(self._r_pos, self._r_size)
-
-
-class InteractAnimated(Interact):
-    """Interactive with an animation rather than an image"""
-
-    # anim_seq - sequence of image names
-    # delay - number of frames to wait between changing images
-
-    def __init__(self, x, y, anim_seq, delay):
-        self._pos = (x, y)
-        self._anim_pos = 0
-        self._names = anim_seq
-        self._frame_count = 0
-        self._anim_seq = None
-        self._delay = delay
-
-    def set_thing(self, thing):
-        self._anim_seq = [thing.resource.get_image(thing.folder, x)
-                          for x in self._names]
-        self.image = self._anim_seq[0]
-        self.rect = Rect(self._pos, self.image.get_size())
-        for image in self._anim_seq:
-            assert image.get_size() == self.rect.size
-        self.interact_rect = self.rect
-
-    def animate(self):
-        if self._anim_seq:
-            self._frame_count += 1
-            if self._frame_count > self._delay:
-                self._frame_count = 0
-                self._anim_pos += 1
-                if self._anim_pos >= len(self._anim_seq):
-                    self._anim_pos = 0
-                self.image = self._anim_seq[self._anim_pos]
-                # queue redraw
-                return True
-        return False
-
-
-class TakeableThing(Thing):
-    "Thing that can be taken."
-
-    INITIAL_DATA = {
-        'taken': False,
-    }
-
-    ITEM = None
-
-    def __init__(self):
-        # In case a subclass replaces INITIAL_DATA and breaks 'taken'.
-        assert self.INITIAL_DATA['taken'] in (True, False)
-        super(TakeableThing, self).__init__()
-
-    def should_add(self):
-        return not self.get_data('taken')
-
-    def take(self):
-        self.set_data('taken', True)
-        self.game.add_inventory_item(self.ITEM)
-        self.scene.remove_thing(self)
-
-
-class GenericDescThing(Thing):
-    "Thing with an InteractiveUnionRect and a description"
-
-    INITIAL = "description"
-
-    def __init__(self, prefix, number, description, areas):
-        super(GenericDescThing, self).__init__()
-        self.description = description
-        self.name = '%s.%s' % (prefix, number)
-        self.interacts = {
-                'description': InteractRectUnion(areas)
-                }
-        # Individual colors to make debugging easier
-        self._interact_hilight_color = Color(THECOLORS.keys()[number])
-
-    def get_description(self):
-        return self.description
-
-    def is_interactive(self, tool=None):
-        return False
--- a/pyntnclick/sound.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-# sound management for pyntnclick
-
-from random import randrange
-
-
-import pygame
-
-try:
-    from pygame.mixer import Sound as pygame_Sound
-    from pygame.mixer import music
-    pygame_import_error = None
-except ImportError, e:
-    # Save error, so we don't crash and can do the right thing later
-    pygame_import_error = e
-    pygame_Sound = None
-    music = None
-
-from pyntnclick.resources import ResourceNotFound
-from pyntnclick.engine import MUSIC_ENDED
-
-
-class PlayList(object):
-    """Hold a playlist of music filenames"""
-
-    def __init__(self, pieces, random, repeat):
-        self._pieces = pieces
-        self._random = random
-        self._repeat = repeat
-
-    def get_next(self):
-        # Get the next piece
-        if self._pieces:
-            if self._random:
-                if not self._repeat or len(self._pieces) < 3:
-                    i = randrange(0, len(self._pieces))
-                else:
-                    # Ignore the last entry, since we possibly just played it
-                    i = randrange(0, len(self._pieces) - 1)
-            else:
-                i = 0
-            result = self._pieces.pop(i)
-            if self._repeat:
-                self._pieces.append(result)
-            return result
-        return None
-
-
-class DummySound(object):
-    """A dummy sound object.
-
-       This is a placeholder object with the same API as
-       pygame.mixer.Sound which does nothing. Used when
-       sounds are disabled so scense don't need to worry
-       about the details.
-
-       Inpsired by the same idea in Albow (by Greg Ewing)"""
-
-    def play(self, *args):
-        pass
-
-    def stop(self):
-        pass
-
-    def get_length(self):
-        return 0.0
-
-    def get_num_channel(self):
-        return 0
-
-    def get_volume(self):
-        return 0.0
-
-    def fadeout(self, *args):
-        pass
-
-
-class Sound(object):
-    """Global sound management and similiar useful things"""
-
-    def __init__(self, resource_finder):
-        self.sound_enabled = False
-        self.sound_cache = {}
-        self._resource_finder = resource_finder
-        self._current_playlist = None
-
-    def enable_sound(self, constants):
-        """Attempt to initialise the sound system"""
-        if pygame_Sound is None:
-            self.disable_sound(pygame_import_error)
-            return
-        try:
-            pygame.mixer.init(constants.snd_freq,
-                              constants.snd_bitsize,
-                              constants.snd_channels,
-                              constants.snd_buffer)
-            self.sound_enabled = True
-            music.set_endevent(MUSIC_ENDED)
-        except pygame.error, exc:
-            self.disable_sound(exc)
-
-    def disable_sound(self, exc=None):
-        """Disable the sound system"""
-        self.sound_enabled = False
-        if exc is not None:
-            print 'Failed to initialise sound system'
-            print 'Error: %s' % exc
-            print 'Sound disabled'
-
-    def get_sound(self, *names):
-        if not self.sound_enabled:
-            return DummySound()
-        sound = None
-        try:
-            path = self._resource_finder.get_resource_path("sounds", *names)
-            sound = self.sound_cache.get(path, None)
-        except ResourceNotFound:
-            print "Sound file not found: %s" % names
-            # Cache failed lookup
-            sound = DummySound()
-            self.sound_cache[path] = sound
-        if sound is None:
-            try:
-                sound = pygame_Sound(path)
-            except pygame.error:
-                print "Sound file not found: %s" % names
-                sound = DummySound()
-            self.sound_cache[path] = sound
-        return sound
-
-    def get_playlist(self, pieces, random=False, repeat=False):
-        return PlayList(pieces, random, repeat)
-
-    def get_music(self, name):
-        if self.sound_enabled:
-            music_file = self._resource_finder.get_resource_path("sounds",
-                    name)
-            return music_file
-        return None
-
-    def music_ended(self):
-        if self._current_playlist:
-            # Try start the next tune
-            self.start_next_music()
-
-    def change_playlist(self, new_playlist):
-        if self.sound_enabled:
-            music.stop()
-            self._current_playlist = new_playlist
-            self.start_next_music()
-
-    def start_next_music(self):
-        if self._current_playlist:
-            tune = self._current_playlist.get_next()
-            if tune:
-                music.load(tune)
-                music.play()
-
-    def get_current_playlist(self):
-        return self._current_playlist
--- a/pyntnclick/speech.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-# speech.py
-# Copyright Boomslang team, 2010 (see COPYING File)
-# Speech playing and cache
-
-import re
-
-from pyntnclick.sound import get_sound
-
-
-# cache of string -> sound object mappings
-_SPEECH_CACHE = {}
-
-# characters not to allow in filenames
-_REPLACE_RE = re.compile(r"[^a-z0-9-]+")
-
-
-class SpeechError(RuntimeError):
-    pass
-
-
-def get_filename(key, text):
-    """Simplify text to filename."""
-    filename = "%s-%s" % (key, text)
-    filename = filename.lower()
-    filename = _REPLACE_RE.sub("_", filename)
-    filename = filename[:30]
-    filename = "%s.ogg" % filename
-    return filename
-
-
-def get_speech(thing_name, text):
-    """Load a sound object from the cache."""
-    key = (thing_name, text)
-    if key in _SPEECH_CACHE:
-        return _SPEECH_CACHE[key]
-    filename = get_filename(thing_name, text)
-    _SPEECH_CACHE[key] = sound = get_sound("speech", filename)
-    return sound
-
-
-def say(thing_name, text):
-    """Play text as speech."""
-    sound = get_speech(thing_name, text)
-    sound.play()
--- a/pyntnclick/state.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,660 +0,0 @@
-"""Utilities and base classes for dealing with scenes."""
-
-import os
-import json
-import copy
-
-from widgets.text import LabelWidget
-from pygame.color import Color
-
-from pyntnclick.engine import ScreenEvent
-from pyntnclick.utils import draw_rect_image
-
-
-class Result(object):
-    """Result of interacting with a thing"""
-
-    def __init__(self, message=None, soundfile=None, detail_view=None,
-                 widget=None, end_game=False):
-        self.message = message
-        self.soundfile = soundfile
-        self.detail_view = detail_view
-        self.widget = widget
-        self.end_game = end_game
-
-    def play_sound(self, screen):
-        if self.soundfile:
-            sound = screen.gd.sound.get_sound(self.soundfile)
-            sound.play()
-
-    def process(self, screen):
-        """Helper function to do the right thing with a result object"""
-        self.play_sound(screen)
-        if self.widget:
-            screen.queue_widget(self.widget)
-        if self.message:
-            screen.show_message(self.message)
-        if self.detail_view:
-            screen.game.show_detail(self.detail_view)
-        if self.end_game:
-            screen.end_game()
-
-
-class GameState(object):
-    """This holds the serializable game state.
-
-       Games wanting to do fancier stuff with the state should
-       sub-class this and feed the subclass into
-       GameDescription via the custom_data parameter."""
-
-    def __init__(self, state_dict=None):
-        if state_dict is None:
-            state_dict = {
-                'inventories': {'main': []},
-                'item_factories': {},
-                'current_scene': None,
-                }
-        self._game_state = copy.deepcopy(state_dict)
-
-    def __getitem__(self, key):
-        return self._game_state[key]
-
-    def __contains__(self, key):
-        return key in self._game_state
-
-    def export_data(self):
-        return copy.deepcopy(self._game_state)
-
-    def get_data(self, state_key, data_key):
-        """Get a single entry"""
-        return self[state_key].get(data_key, None)
-
-    def set_data(self, state_key, data_key, value):
-        """Set a single value"""
-        self[state_key][data_key] = value
-
-    def _initialize_state(self, state_dict, state_key, initial_data):
-        if state_key not in self._game_state:
-            state_dict[state_key] = copy.deepcopy(initial_data)
-
-    def initialize_state(self, state_key, initial_data):
-        """Initialize a gizmo entry"""
-        self._initialize_state(self._game_state, state_key, initial_data)
-
-    def initialize_item_factory_state(self, state_key, initial_data):
-        """Initialize an item factory entry"""
-        self._initialize_state(
-            self._game_state['item_factories'], state_key, initial_data)
-
-    def inventory(self, name='main'):
-        return self['inventories'][name]
-
-    def set_current_scene(self, scene_name):
-        self._game_state['current_scene'] = scene_name
-
-    @classmethod
-    def get_save_fn(cls, save_dir, save_name):
-        return os.path.join(save_dir, '%s.json' % (save_name,))
-
-    @classmethod
-    def load_game(cls, save_dir, save_name):
-        fn = cls.get_save_fn(save_dir, save_name)
-        if os.access(fn, os.R_OK):
-            f = open(fn, 'r')
-            state = json.load(f)
-            f.close()
-            return state
-
-    def save_game(self, save_dir, save_name):
-        fn = self.get_save_fn(save_dir, save_name)
-        if not os.path.isdir(save_dir):
-            os.makedirs(save_dir)
-        f = open(fn, 'w')
-        json.dump(self.export_data(), f)
-        f.close()
-
-
-class Game(object):
-    """Complete game state.
-
-    Game state consists of:
-
-    * items
-    * scenes
-    """
-    def __init__(self, gd, game_state):
-        # game description
-        self.gd = gd
-        # map of scene name -> Scene object
-        self.scenes = {}
-        # map of detail view name -> DetailView object
-        self.detail_views = {}
-        # map of item prefix -> ItemFactory object
-        self.item_factories = {}
-        # list of item objects in inventory
-        self.current_inventory = 'main'
-        # currently selected tool (item)
-        self.tool = None
-        # Global game data
-        self.data = game_state
-        # debug rects
-        self.debug_rects = False
-
-    def get_current_scene(self):
-        scene_name = self.data['current_scene']
-        if scene_name is not None:
-            return self.scenes[scene_name]
-        return None
-
-    def get_item(self, item_name):
-        base_name, _, _suffix = item_name.partition(':')
-        factory = self.item_factories[base_name]
-        return factory.get_item(item_name)
-
-    def create_item(self, base_name):
-        assert ":" not in base_name
-        factory = self.item_factories[base_name]
-        return factory.create_item()
-
-    def inventory(self, name=None):
-        if name is None:
-            name = self.current_inventory
-        return self.data.inventory(name)
-
-    def set_custom_data(self, data_object):
-        self.data = data_object
-
-    def set_debug_rects(self, value=True):
-        self.debug_rects = value
-
-    def add_scene(self, scene):
-        scene.set_game(self)
-        self.scenes[scene.name] = scene
-
-    def add_detail_view(self, detail_view):
-        detail_view.set_game(self)
-        self.detail_views[detail_view.name] = detail_view
-
-    def add_item_factory(self, item_class):
-        name = item_class.NAME
-        assert name not in self.item_factories, (
-           "Factory for %s already added." % (name,))
-        factory = item_class.ITEM_FACTORY(item_class)
-        factory.set_game(self)
-        self.item_factories[name] = factory
-
-    def load_scenes(self, modname):
-        mod = __import__('%s.%s' % (self.gd.SCENE_MODULE, modname),
-                         fromlist=[modname])
-        for scene_cls in mod.SCENES:
-            scene = scene_cls(self)
-            self.add_scene(scene)
-        if hasattr(mod, 'DETAIL_VIEWS'):
-            for scene_cls in mod.DETAIL_VIEWS:
-                scene = scene_cls(self)
-                self.add_detail_view(scene)
-
-    def change_scene(self, name):
-        ScreenEvent.post('game', 'change_scene',
-                         {'name': name, 'detail': False})
-
-    def show_detail(self, name):
-        ScreenEvent.post('game', 'change_scene',
-                         {'name': name, 'detail': True})
-
-    def _update_inventory(self):
-        ScreenEvent.post('game', 'inventory', None)
-
-    def add_inventory_item(self, item_name):
-        item = self.create_item(item_name)
-        self.inventory().append(item.name)
-        self._update_inventory()
-
-    def is_in_inventory(self, name):
-        return name in self.inventory()
-
-    def remove_inventory_item(self, name):
-        self.inventory().remove(name)
-        # Unselect tool if it's removed
-        if self.tool == self.get_item(name):
-            self.set_tool(None)
-        self._update_inventory()
-
-    def replace_inventory_item(self, old_item_name, new_item_name):
-        """Try to replace an item in the inventory with a new one"""
-        try:
-            index = self.inventory().index(old_item_name)
-            new_item = self.create_item(new_item_name)
-            self.inventory()[index] = new_item.name
-            if self.tool == self.get_item(old_item_name):
-                self.set_tool(new_item)
-        except ValueError:
-            return False
-        self._update_inventory()
-        return True
-
-    def set_tool(self, item):
-        self.tool = item
-
-
-class GameDeveloperGizmo(object):
-    """Base class for objects game developers see."""
-
-    def __init__(self):
-        """Set """
-        self.game = None
-        self.gd = None
-        self.resource = None
-        self.sound = None
-
-    def set_game(self, game):
-        self.game = game
-        self.gd = game.gd
-        self.resource = self.gd.resource
-        self.sound = self.gd.sound
-        self.set_state(self.game.data)
-        self.setup()
-
-    def set_state(self, state):
-        """Hack to allow set_state() to be called before setup()."""
-        pass
-
-    def setup(self):
-        """Game developers should override this to do their setup.
-
-        It will be called after all the useful state functions have been
-        set.
-        """
-        pass
-
-
-class StatefulGizmo(GameDeveloperGizmo):
-
-    # initial data (optional, defaults to none)
-    INITIAL_DATA = None
-    STATE_KEY = None
-
-    def __init__(self):
-        GameDeveloperGizmo.__init__(self)
-        self.state_key = self.STATE_KEY
-        self.state = None  # set this with set_state if required
-
-    def set_state(self, state):
-        """Set the state object and initialize if needed"""
-        self.state = state
-        if self.state_key is None:
-            assert self.INITIAL_DATA is None, (
-                "Can't provide self.INITIAL_DATA without self.state_key.")
-        if self.INITIAL_DATA is not None:
-            self.state.initialize_state(self.state_key, self.INITIAL_DATA)
-
-    def set_data(self, key, value):
-        if self.state:
-            self.state.set_data(self.state_key, key, value)
-
-    def get_data(self, key):
-        if self.state:
-            return self.state.get_data(self.state_key, key)
-
-
-class Scene(StatefulGizmo):
-    """Base class for scenes."""
-
-    # sub-folder to look for resources in
-    FOLDER = None
-
-    # name of background image resource
-    BACKGROUND = None
-
-    # name of scene (optional, defaults to folder)
-    NAME = None
-
-    # Offset of the background image
-    OFFSET = (0, 0)
-
-    def __init__(self, state):
-        StatefulGizmo.__init__(self)
-        # scene name
-        self.name = self.NAME if self.NAME is not None else self.FOLDER
-        self.state_key = self.name
-        # map of thing names -> Thing objects
-        self.things = {}
-        self.current_thing = None
-        self._background = None
-
-    def add_item_factory(self, item_factory):
-        self.game.add_item_factory(item_factory)
-
-    def add_thing(self, thing):
-        thing.set_game(self.game)
-        if not thing.should_add():
-            return
-        self.things[thing.name] = thing
-        thing.set_scene(self)
-
-    def remove_thing(self, thing):
-        del self.things[thing.name]
-        if thing is self.current_thing:
-            self.current_thing.leave()
-            self.current_thing = None
-
-    def _get_description(self, dest_rect):
-        text = (self.current_thing and
-                self.current_thing.get_description())
-        if text is None:
-            return None
-        label = LabelWidget((0, 10), self.gd, text)
-        label.do_prepare()
-        # TODO: Centre more cleanly
-        label.rect.left += (dest_rect.width - label.rect.width) / 2
-        return label
-
-    def draw_description(self, surface):
-        description = self._get_description(surface.get_rect())
-        if description is not None:
-            description.draw(surface)
-
-    def _cache_background(self):
-        if self.BACKGROUND and not self._background:
-            self._background = self.resource.get_image(
-                self.FOLDER, self.BACKGROUND)
-
-    def draw_background(self, surface):
-        self._cache_background()
-        if self._background is not None:
-            surface.blit(self._background, self.OFFSET, None)
-        else:
-            surface.fill((200, 200, 200))
-
-    def draw_things(self, surface):
-        for thing in self.things.itervalues():
-            thing.draw(surface)
-
-    def draw(self, surface):
-        self.draw_background(surface)
-        self.draw_things(surface)
-
-    def interact(self, item, pos):
-        """Interact with a particular position.
-
-        Item may be an item in the list of items or None for the hand.
-
-        Returns a Result object to provide feedback to the player.
-        """
-        if self.current_thing is not None:
-            return self.current_thing.interact(item)
-
-    def animate(self):
-        """Animate all the things in the scene.
-
-           Return true if any of them need to queue a redraw"""
-        result = False
-        for thing in self.things.itervalues():
-            if thing.animate():
-                result = True
-        return result
-
-    def enter(self):
-        return None
-
-    def leave(self):
-        return None
-
-    def update_current_thing(self, pos):
-        if self.current_thing is not None:
-            if not self.current_thing.contains(pos):
-                self.current_thing.leave()
-                self.current_thing = None
-        for thing in self.things.itervalues():
-            if thing.contains(pos):
-                thing.enter(self.game.tool)
-                self.current_thing = thing
-                break
-
-    def mouse_move(self, pos):
-        """Call to check whether the cursor has entered / exited a thing.
-
-        Item may be an item in the list of items or None for the hand.
-        """
-        self.update_current_thing(pos)
-
-    def get_detail_size(self):
-        self._cache_background()
-        return self._background.get_size()
-
-    def get_image(self, *image_name_fragments, **kw):
-        return self.resource.get_image(*image_name_fragments, **kw)
-
-    def set_state(self, state):
-        return super(Scene, self).set_state(state)
-
-
-class InteractiveMixin(object):
-    def is_interactive(self, tool=None):
-        return True
-
-    def interact(self, tool):
-        if not self.is_interactive(tool):
-            return None
-        if tool is None:
-            return self.interact_without()
-        handler = getattr(self, 'interact_with_' + tool.tool_name, None)
-        inverse_handler = self.get_inverse_interact(tool)
-        if handler is not None:
-            return handler(tool)
-        elif inverse_handler is not None:
-            return inverse_handler(self)
-        else:
-            return self.interact_default(tool)
-
-    def get_inverse_interact(self, tool):
-        return None
-
-    def interact_without(self):
-        return self.interact_default(None)
-
-    def interact_default(self, item=None):
-        return None
-
-
-class Thing(StatefulGizmo, InteractiveMixin):
-    """Base class for things in a scene that you can interact with."""
-
-    # name of thing
-    NAME = None
-
-    # sub-folder to look for resources in (defaults to scenes folder)
-    FOLDER = None
-
-    # list of Interact objects
-    INTERACTS = {}
-
-    # name first interact
-    INITIAL = None
-
-    # Interact rectangle hi-light color (for debugging)
-    # (set to None to turn off)
-    _interact_hilight_color = Color('red')
-
-    def __init__(self):
-        StatefulGizmo.__init__(self)
-        # name of the thing
-        self.name = self.NAME
-        # folder for resource (None is overridden by scene folder)
-        self.folder = self.FOLDER
-        self.state_key = self.NAME
-        # interacts
-        self.interacts = self.INTERACTS
-        # these are set by set_scene
-        self.scene = None
-        self.current_interact = None
-        self.rect = None
-        self.orig_rect = None
-
-    def _fix_rect(self):
-        """Fix rects to compensate for scene offset"""
-        # Offset logic is to always work with copies, to avoid
-        # flying effects from multiple calls to _fix_rect
-        # See footwork in draw
-        if hasattr(self.rect, 'collidepoint'):
-            self.rect = self.rect.move(self.scene.OFFSET)
-        else:
-            self.rect = [x.move(self.scene.OFFSET) for x in self.rect]
-
-    def should_add(self):
-        return True
-
-    def set_scene(self, scene):
-        assert self.scene is None
-        self.scene = scene
-        if self.folder is None:
-            self.folder = scene.FOLDER
-        self.game = scene.game
-        for interact in self.interacts.itervalues():
-            interact.set_thing(self)
-        self.set_interact()
-
-    def set_interact(self):
-        return self._set_interact(self.select_interact())
-
-    def _set_interact(self, name):
-        self.current_interact = self.interacts[name]
-        self.rect = self.current_interact.interact_rect
-        if self.scene:
-            self._fix_rect()
-        assert self.rect is not None, name
-
-    def select_interact(self):
-        return self.INITIAL
-
-    def contains(self, pos):
-        if hasattr(self.rect, 'collidepoint'):
-            return self.rect.collidepoint(pos)
-        else:
-            for rect in list(self.rect):
-                if rect.collidepoint(pos):
-                    return True
-        return False
-
-    def get_description(self):
-        return None
-
-    def enter(self, item):
-        """Called when the cursor enters the Thing."""
-        pass
-
-    def leave(self):
-        """Called when the cursor leaves the Thing."""
-        pass
-
-    def animate(self):
-        return self.current_interact.animate()
-
-    def draw(self, surface):
-        old_rect = self.current_interact.rect
-        if old_rect:
-            self.current_interact.rect = old_rect.move(self.scene.OFFSET)
-        self.current_interact.draw(surface)
-        self.current_interact.rect = old_rect
-        if self.game.debug_rects and self._interact_hilight_color:
-            if hasattr(self.rect, 'collidepoint'):
-                draw_rect_image(surface, self._interact_hilight_color,
-                        self.rect.inflate(1, 1), 1)
-            else:
-                for rect in self.rect:
-                    draw_rect_image(surface, self._interact_hilight_color,
-                            rect.inflate(1, 1), 1)
-
-
-class ItemFactory(StatefulGizmo):
-    INITIAL_DATA = {
-        'created': [],
-        }
-
-    def __init__(self, item_class):
-        super(ItemFactory, self).__init__()
-        self.item_class = item_class
-        assert self.item_class.NAME is not None, (
-            "%s has no NAME set" % (self.item_class,))
-        self.state_key = self.item_class.NAME + '_factory'
-        self.items = {}
-
-    def get_item(self, item_name):
-        assert item_name in self.get_data('created'), (
-            "Object %s has not been created" % (item_name,))
-        if item_name not in self.items:
-            item = self.item_class(item_name)
-            item.set_game(self.game)
-            self.items[item_name] = item
-        return self.items[item_name]
-
-    def get_item_suffix(self):
-        return ''
-
-    def create_item(self):
-        item_name = '%s:%s' % (self.item_class.NAME, self.get_item_suffix())
-        created_list = self.get_data('created')
-        assert item_name not in created_list, (
-            "Already created object %s" % (item_name,))
-        created_list.append(item_name)
-        self.set_data('created', created_list)
-        return self.get_item(item_name)
-
-
-class Item(GameDeveloperGizmo, InteractiveMixin):
-    """Base class for inventory items."""
-
-    # image for inventory
-    INVENTORY_IMAGE = None
-
-    # Base name of item
-    NAME = None
-
-    # name for interactions (i.e. def interact_with_<TOOL_NAME>)
-    TOOL_NAME = None
-
-    # set to instance of CursorSprite
-    CURSOR = None
-
-    ITEM_FACTORY = ItemFactory
-
-    def __init__(self, name=None):
-        GameDeveloperGizmo.__init__(self)
-        self.name = self.NAME
-        if name is not None:
-            self.name = name
-        self.tool_name = self.NAME
-        if self.TOOL_NAME is not None:
-            self.tool_name = self.TOOL_NAME
-        self.inventory_image = None
-
-    def _cache_inventory_image(self):
-        if not self.inventory_image:
-            self.inventory_image = self.resource.get_image(
-                    'items', self.INVENTORY_IMAGE)
-
-    def get_inventory_image(self):
-        self._cache_inventory_image()
-        return self.inventory_image
-
-    def get_inverse_interact(self, tool):
-        return getattr(tool, 'interact_with_' + self.tool_name, None)
-
-    def is_interactive(self, tool=None):
-        if tool:
-            return True
-        return False
-
-
-class ClonableItemFactory(ItemFactory):
-    def get_item_suffix(self):
-        # Works as long as we never remove anything from our 'created' list.
-        count = len(self.get_data('created'))
-        assert self.item_class.MAX_COUNT is not None
-        assert count <= self.item_class.MAX_COUNT
-        return str(count)
-
-
-class CloneableItem(Item):
-    ITEM_FACTORY = ClonableItemFactory
-    MAX_COUNT = None
--- a/pyntnclick/tests/game_logic_utils.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-import unittest
-
-import pygame.display
-import pygame.event
-
-import pyntnclick.resources
-import pyntnclick.state
-
-
-class GameLogicTestCase(unittest.TestCase):
-    CURRENT_SCENE = None
-    GAME_DESCRIPTION_CLASS = None
-
-    def setUp(self):
-        # Events require us to initialize the display
-        pygame.display.init()
-        # Disable alpha conversion which requires a screen
-        pyntnclick.resources.Resources.CONVERT_ALPHA = False
-
-        self.game_description = self.GAME_DESCRIPTION_CLASS()
-        self.state = self.game_description.initial_state()
-        self.scene_stack = []
-
-        # We aren't handling events, monkey patch change_scene and show_detail
-        def change_scene(name):
-            self.state.data.set_current_scene(name)
-            self.scene_stack = [self.state.get_current_scene()]
-        self.state.change_scene = change_scene
-
-        def show_detail(name):
-            self.scene_stack.append(self.state.detail_views[name])
-        self.state.show_detail = show_detail
-
-        self.state.change_scene(self.CURRENT_SCENE)
-
-    def close_detail(self):
-        self.scene_stack.pop()
-        self.assertTrue(len(self.scene_stack) > 0)
-
-    def clear_event_queue(self):
-        # Since we aren't handling events, we may overflow the pygame
-        # event buffer if we're generating a lot of events
-        pygame.event.clear()
-
-    def clear_inventory(self):
-        # Remove all items from the inventory, ensuring tool is set to None
-        self.state.set_tool(None)
-        self.state.inventory()[:] = []
-
-    def set_game_data(self, key, value, thing=None):
-        gizmo = self.state.get_current_scene()
-        if thing is not None:
-            gizmo = gizmo.things[thing]
-        gizmo.set_data(key, value)
-
-    def assert_game_data(self, key, value, thing=None, scene=None,
-            detail=None):
-        gizmo = self.state.get_current_scene()
-        if scene is not None:
-            gizmo = self.state.scenes[scene]
-        if detail is not None:
-            gizmo = self.state.detail_views[detail]
-        if thing is not None:
-            gizmo = gizmo.things[thing]
-        self.assertEquals(value, gizmo.get_data(key))
-
-    def assert_inventory_item(self, item, in_inventory=True):
-        self.assertEquals(in_inventory, self.state.is_in_inventory(item))
-
-    def assert_scene_thing(self, thing, in_scene=True):
-        self.assertEquals(
-            in_scene, thing in self.state.get_current_scene().things)
-
-    def assert_detail_thing(self, thing, in_detail=True):
-        self.assertEquals(in_detail, thing in self.scene_stack[-1].things)
-
-    def assert_item_exists(self, item, exists=True):
-        try:
-            self.state.get_item(item)
-            self.assertTrue(exists)
-        except:
-            self.assertFalse(exists)
-
-    def assert_current_scene(self, scene):
-        self.assertEquals(scene, self.state.get_current_scene().name)
-
-    def handle_result(self, result):
-        self.clear_event_queue()
-        if result is None:
-            return None
-        if hasattr(result, 'process'):
-            if result.detail_view:
-                self.state.show_detail(result.detail_view)
-            return result
-        return [self.handle_result(r) for r in result]
-
-    def interact_thing(self, thing, item=None, detail=None):
-        item_obj = None
-        if item is not None:
-            self.assert_inventory_item(item)
-            item_obj = self.state.get_item(item)
-        thing_container = self.scene_stack[-1]
-        if detail is not None:
-            self.assertEqual(detail, thing_container.name)
-        result = thing_container.things[thing].interact(item_obj)
-        return self.handle_result(result)
-
-    def interact_item(self, target_item, item):
-        self.assert_inventory_item(target_item)
-        item_obj = self.state.get_item(item)
-        target_obj = self.state.get_item(target_item)
-        result = target_obj.interact(item_obj)
-        return self.handle_result(result)
--- a/pyntnclick/tests/mad_clicker.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-from pyntnclick.tests.game_logic_utils import GameLogicTestCase
-
-
-class MadClickerTestCase(GameLogicTestCase):
-    "Provide a 'mad clicker' test to expose potential undefined behaviour"
-
-    def check_result_obj(self, obj):
-        """Check that the obj is the sort of result obj/seq we expect"""
-        if obj is None:
-            return True
-        if hasattr(obj, 'process'):
-            return True
-        return False
-
-    def check_result(self, obj):
-        """Check that the obj is the sort of result obj/seq we expect"""
-        # We do it this way, because we don't allow seqs to contain seqs
-        if not self.check_result_obj(obj):
-            for subobj in obj:
-                if not self.check_result_obj(subobj):
-                    return False
-        return True
-
-    def _format_item(self, item):
-        return "%s (%s)" % (item.name, item)
-
-    def _format_thing(self, thing):
-        if not hasattr(thing, 'current_interact'):
-            return self._format_item(thing)
-        interact_name = None
-        if thing.current_interact and thing.interacts:
-            for name in thing.interacts:
-                if thing.interacts[name] == thing.current_interact:
-                    interact_name = name
-                    break
-        if interact_name:
-            return "%s:%s (%s %s)" % (thing.name, interact_name,
-                    thing, thing.current_interact)
-        elif thing.current_interact:
-            return "%s:<no name found> (%s %s)" % (thing.name, thing,
-                    thing.current_interact)
-        else:
-            return "%s:<no interact> (%s %s)" % (thing.name, thing)
-
-    def format_error(self, thing, item, exception):
-        if not item:
-            msg = ("Unexpected result for interact with no item for %s"
-                    % self._format_thing(thing))
-        else:
-            msg = ("Unexpected result for interact with item %s with %s" %
-                    (self._format_item(item), self._format_thing(thing)))
-        if exception:
-            return "Exception raised %s:\nTest failed: %s" % (exception, msg)
-        return msg
-
-    def do_thing(self, thing, item):
-        try:
-            if item:
-                # We're interacting with an item in the inventory
-                self.state.add_inventory_item(item.name)
-            self.assertEqual(self.check_result(thing.interact(item)), True,
-                self.format_error(thing, item, None))
-        except self.failureException:
-            raise
-        except Exception, details:
-            raise self.failureException(self.format_error(thing, item,
-                details))
-        self.clear_inventory()
-        self.clear_event_queue()
-
-    def do_item(self, item, item2):
-        try:
-            self.state.add_inventory_item(item.name)
-            if item2:
-                self.state.add_inventory_item(item2.name)
-            self.assertEqual(self.check_result(item.interact(item2)), True,
-                self.format_error(item, item2, None))
-        except self.failureException:
-            raise
-        except Exception, details:
-            raise self.failureException(self.format_error(item, item2,
-                details))
-        self.clear_inventory()
-        self.clear_event_queue()
-
-    def do_mad_clicker(self):
-        """Implement frantic clicking behaviour"""
-        for scene in self.state.scenes.values():
-            self.state.data.set_current_scene(scene.name)
-            for thing in scene.things.values():
-                for interact_name in thing.interacts:
-                    thing._set_interact(interact_name)
-                    self.do_thing(thing, None)
-                    for item in self.state.items.values():
-                        self.do_thing(thing, item)
-        for detail in self.state.detail_views.values():
-            for thing in detail.things.values():
-                for interact_name in thing.interacts:
-                    thing._set_interact(interact_name)
-                    self.do_thing(thing, None)
-                    for item in self.state.items.values():
-                        self.do_thing(thing, item)
-        for item in self.state.items.values():
-            self.do_item(item, None)
-            for item2 in self.state.items.values():
-                self.do_item(item, item2)
--- a/pyntnclick/tests/test_resources.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-import os.path
-from unittest import TestCase
-
-from pygame.surface import Surface
-
-from pyntnclick.resources import Resources, ResourceNotFound
-
-
-TEST_PATH = os.path.dirname(__file__)
-DATA_PATH = os.path.join(os.path.dirname(TEST_PATH), 'data')
-
-test_path = lambda p: os.path.join(TEST_PATH, p)
-data_path = lambda p: os.path.join(DATA_PATH, p)
-
-
-class ResourcesTestCase(TestCase):
-    def setUp(self):
-        self.res = self.get_resource_loader()
-
-    def get_resource_loader(self, *args, **kw):
-        res = Resources('pyntnclick.tests', *args, **kw)
-        res.CONVERT_ALPHA = False  # Because we have no display.
-        return res
-
-    def test_get_paths_no_lang(self):
-        self.assertEqual([test_path('thing'), data_path('thing')],
-                         self.res.get_paths('thing'))
-
-    def test_get_paths_lang(self):
-        res = self.get_resource_loader('en')
-        self.assertEqual([test_path('en/thing'), test_path('thing'),
-                          data_path('en/thing'), data_path('thing')],
-                         res.get_paths('thing'))
-
-    def test_get_paths_lang_dialect(self):
-        res = self.get_resource_loader('en_ZA')
-        self.assertEqual([test_path('en_ZA/thing'), test_path('en/thing'),
-                          test_path('thing'), data_path('en_ZA/thing'),
-                          data_path('en/thing'), data_path('thing')],
-                         res.get_paths('thing'))
-
-    def test_get_resource_path_missing(self):
-        try:
-            self.res.get_resource_path('should_not_exist')
-            self.fail('Expected ResourceNotFound error.')
-        except ResourceNotFound, e:
-            self.assertEqual('should_not_exist', e.args[0])
-
-    def test_get_resource_path_in_test(self):
-        self.assertEqual(test_path('test_resources.py'),
-                         self.res.get_resource_path('test_resources.py'))
-
-    def test_get_resource_path_in_data(self):
-        self.assertEqual(
-            data_path('images/pyntnclick/hand.png'),
-            self.res.get_resource_path('images/pyntnclick/hand.png'))
-
-    def test_get_image(self):
-        image = self.res.get_image('pyntnclick/hand.png')
-        self.assertTrue(isinstance(image, Surface))
-
-    def test_get_image_fragments(self):
-        image = self.res.get_image('pyntnclick', 'hand.png')
-        self.assertTrue(isinstance(image, Surface))
-
-    def test_get_image_different_basedir(self):
-        image = self.res.get_image('hand.png', basedir='images/pyntnclick')
-        self.assertTrue(isinstance(image, Surface))
-
-    def test_load_missing(self):
-        try:
-            self.res.get_image('should_not_exist')
-            self.fail('Expected ResourceNotFound error.')
-        except ResourceNotFound, e:
-            self.assertEqual('images/should_not_exist', e.args[0])
--- a/pyntnclick/tools/gen_sound.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-# Generate 'perfect' sine wave sounds
-
-# Design notes: produces ~= (use requested) s raw CDDA audio - 44100 Hz
-#                           16 bit signed values
-# Input is freq in Hz - 440 for A, etc. - must be an integer
-# Output is written the file beep<freq>.pcm
-# Convert to ogg with oggenc -r <file>
-
-import sys
-import math
-import struct
-
-CDDA_RATE = 44100
-MAX = 105 * 256  # Max value for sine wave
-
-
-def gen_sine(freq, secs):
-    filename = 'beep%s.pcm' % freq
-    # We need to generate freq cycles and sample that CDDA_RATE times
-    samples_per_cycle = CDDA_RATE / freq
-    data = []
-    for x in range(samples_per_cycle):
-        rad = float(x) / samples_per_cycle * 2 * math.pi
-        y = MAX * math.sin(rad)
-        data.append(struct.pack('<i', y))
-    output = open(filename, 'w')
-    for x in range(int(freq * secs)):
-        output.write(''.join(data))
-    output.close()
-    return filename
-
-
-def usage():
-    print 'Unexpected input'
-    print 'Usage: gen_sound.py <freq> [<length>]'
-    print ' where <freq> is the frequency in Hz (integer)'
-    print ' and [<length>] is the time is seconds (float)'
-
-if __name__ == "__main__":
-    try:
-        freq = int(sys.argv[1])
-    except Exception, exc:
-        usage()
-        print 'Error was: %s' % exc
-        sys.exit(1)
-
-    if len(sys.argv) > 2:
-        try:
-            secs = float(sys.argv[2])
-        except Exception, exc:
-            usage()
-            print 'Error was: %s' % exc
-            sys.exit(1)
-    else:
-        secs = 0.25
-    output = gen_sine(freq, secs)
-    print 'Wrote sample to %s' % output
--- a/pyntnclick/tools/rect_drawer.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,743 +0,0 @@
-# Quickly hacked together helper for working out
-# interactive regions in Suspended Sentence
-
-from pygame.locals import (K_LEFT, K_RIGHT, K_UP, K_DOWN,
-                           K_a, K_t, K_d, K_i, K_r, K_o, K_b, K_z,
-                           QUIT, MOUSEBUTTONDOWN, MOUSEMOTION,
-                           MOUSEBUTTONUP, KEYDOWN)
-import pygame
-import os
-
-import pyntnclick.constants
-from pyntnclick.i18n import _
-from pyntnclick.widgets.text import LabelWidget, TextButton
-from pyntnclick.widgets.base import Container, Button, TranslucentImage
-from pyntnclick.widgets.filechooser import FileChooser
-from pyntnclick.utils import draw_rect_image
-
-DRAW, CYCLE, DELETE, IMAGE = range(4)
-
-
-class RectDrawerError(Exception):
-    """Raised when initilaization failed"""
-
-
-class RectDrawerConstants(pyntnclick.constants.GameConstants):
-    debug = True
-    menu_width = 200
-    menu_button_height = 25
-    zoom = 4
-    zoom_step = 100
-
-constants = RectDrawerConstants()
-
-
-class ColourButton(Button):
-    """Button for selecting a colour"""
-
-    sel_colour = pygame.color.Color(255, 255, 255)
-    unsel_colour = pygame.color.Color(128, 128, 128)
-
-    padding = 2
-    border = 3
-
-    def __init__(self, rect, gd, colour, palette, size=None):
-        super(ColourButton, self).__init__(rect, gd, size=size)
-        self._colour = pygame.color.Color(colour)
-        self._button_rect = self.rect.inflate(-self.padding, -self.padding)
-        self._colour_rect = self._button_rect.inflate(-self.border,
-                -self.border)
-        self.selected = False
-        self._palette = palette
-        self.add_callback('clicked', self.fix_selection)
-
-    def fix_selection(self, ev, widget):
-        self._palette.cur_selection.selected = False
-        self.selected = True
-        self._palette.cur_selection = self
-
-    def draw(self, surface):
-        if self.visible:
-            self.do_prepare()
-            surface.fill(pygame.color.Color(0, 0, 0), self.rect)
-            if self.selected:
-                surface.fill(self.sel_colour, self._button_rect)
-            else:
-                surface.fill(self.unsel_colour, self._button_rect)
-            surface.fill(self._colour, self._colour_rect)
-
-
-class AppPalette(Container):
-
-    but_size = 35
-
-    colors = [
-            'red', 'maroon1', 'palevioletred1', 'moccasin', 'orange',
-            'honeydew', 'yellow', 'gold', 'goldenrod', 'brown',
-            'blue', 'purple', 'darkorchid4', 'thistle', 'skyblue1',
-            'green', 'palegreen1', 'darkgreen', 'aquamarine', 'darkolivegreen',
-            ]
-
-    def __init__(self, pos, gd, app_image, size=None):
-        self.image = app_image
-        super(AppPalette, self).__init__(pos, gd, size=size)
-        self.selection = 0
-        self.image.rect_color = pygame.color.Color(self.colors[self.selection])
-
-        x, y = pos
-        for num, col in enumerate(self.colors):
-            if (x - self.rect.left + self.but_size) >= self.rect.width:
-                x = self.rect.left
-                y += self.but_size
-            button = ColourButton((x, y),
-                    gd, col, self, size=(self.but_size, self.but_size))
-            x += self.but_size
-            if num == 0:
-                self.cur_selection = button
-                button.fix_selection(None, None)
-            button.add_callback('clicked', self.click_item, num)
-            self.add(button)
-        # Fix height
-        self.rect.height = y + self.but_size - self.rect.top
-
-    def click_item(self, ev, widget, number):
-        self.selection = number
-        self.image.rect_color = pygame.color.Color(self.colors[number])
-
-
-class AppImage(Container):
-
-    rect_thick = 3
-    draw_thick = 1
-
-    def __init__(self, parent, gd, state, scene, detail):
-        self.state = state
-        super(AppImage, self).__init__((0, 0), gd, size=constants.screen)
-        self.mode = DRAW
-        self._scene = scene
-        self._parent = parent
-        self._detail = detail
-        self.rects = []
-        self.images = []
-        self.start_pos = None
-        self.end_pos = None
-        self.rect_color = pygame.color.Color('white')
-        self.current_image = None
-        self.place_image_menu = None
-        self.close_button = LabelWidget((0, 0), gd, _('Close'))
-        self.close_button.fg_color = (0, 0, 0)
-        self.close_button.bg_color = (0, 0, 0)
-        self.draw_rects = True
-        self.draw_things = True
-        self.draw_thing_rects = True
-        self.draw_images = True
-        self.trans_images = False
-        self.draw_toolbar = True
-        self.old_mouse_pos = None
-        self.zoom_display = False
-        self.draw_anim = False
-        self.zoom_offset = (600, 600)
-        self.clear_display = False
-        self.filechooser = None
-        if self._detail:
-            w, h = self._scene.get_detail_size()
-            rect = pygame.rect.Rect(0, 0, w, h)
-            self.close_button.rect.midbottom = rect.midbottom
-            self.offset = (0, 0)
-        else:
-            self.offset = (-self._scene.OFFSET[0],
-                           -self._scene.OFFSET[1])
-        self.find_existing_intersects()
-        self.add_callback(MOUSEBUTTONDOWN, self.mouse_down)
-        self.add_callback(MOUSEBUTTONUP, self.mouse_up)
-        self.add_callback(MOUSEMOTION, self.mouse_move)
-        self.add_callback(KEYDOWN, self.key_down)
-
-    def get_mode_name(self):
-        """Return the translated mode name"""
-        # We do things this way to avoid defining translated strings
-        # at import time
-        if self.mode == DRAW:
-            return _("draw")
-        elif self.mode == CYCLE:
-            return _("cycle")
-        elif self.mode == DELETE:
-            return _("delete")
-        elif self.mode == IMAGE:
-            return _("image")
-        else:
-            raise RuntimeError("Invalid mode")
-
-    def _print_thing(self, thing, interact_name):
-        """Helper to avoid repeated translations"""
-        print (_("Thing %(thing)s Interact %(interact)s") %
-                {'thing': thing.name, 'interact': interact_name})
-
-    def _print_rects(self, rect1, rect2):
-        """Helper to avoid repeated translations"""
-        print _("     Rects"), rect1, rect2
-
-    def find_existing_intersects(self):
-        """Parse the things in the scene for overlaps"""
-        scene = self._scene
-        # Pylint hates this function
-        for thing in scene.things.itervalues():
-            for interact_name in thing.interacts:
-                thing._set_interact(interact_name)
-                if hasattr(thing.rect, 'collidepoint'):
-                    thing_rects = [thing.rect]
-                else:
-                    thing_rects = thing.rect
-                for thing2 in scene.things.itervalues():
-                    if thing is thing2:
-                        continue
-                    for interact2_name in thing2.interacts:
-                        thing2._set_interact(interact2_name)
-                        if hasattr(thing2.rect, 'collidepoint'):
-                            thing2_rects = [thing2.rect]
-                        else:
-                            thing2_rects = thing2.rect
-                        for my_rect in thing_rects:
-                            for other_rect in thing2_rects:
-                                if my_rect.colliderect(other_rect):
-                                    print _('Existing Intersecting rects')
-                                    self._print_thing(thing, interact_name)
-                                    self._print_thing(thing2, interact2_name)
-                                    self._print_rects(my_rect, other_rect)
-        print
-
-    def find_intersecting_rects(self, d):
-        """Find if any rect collections intersect"""
-        # I loath N^X brute search algorithms, but whatever, hey
-        scene = self._scene
-        for (num, col) in enumerate(d):
-            rect_list = d[col]
-            for thing in scene.things.itervalues():
-                for interact_name in thing.interacts:
-                    thing._set_interact(interact_name)
-                    if hasattr(thing.rect, 'collidepoint'):
-                        thing_rects = [thing.rect]
-                    else:
-                        thing_rects = thing.rect
-                    for other_rect in thing_rects:
-                        for my_rect in rect_list:
-                            if my_rect.colliderect(other_rect):
-                                print _('Intersecting rects')
-                                print _("  Object %s") % num
-                                self._print_thing(thing, interact_name)
-                                self._print_rects(my_rect, other_rect)
-                if thing.INITIAL:
-                    thing._set_interact(thing.INITIAL)
-            print
-            for (num2, col2) in enumerate(d):
-                if num2 == num:
-                    continue
-                other_list = d[col2]
-                for my_rect in rect_list:
-                    for other_rect in other_list:
-                        if my_rect.colliderect(other_rect):
-                            print _('Intersecting rects'),
-                            print (_('  Object %(object1)s and %(object2)s') %
-                                    {'object1': num, 'object2': num2})
-                            self._print_rects(my_rect, other_rect)
-            print
-            print
-
-    def toggle_things(self, ev, widget):
-        self.draw_things = not self.draw_things
-
-    def toggle_thing_rects(self, ev, widget):
-        self.draw_thing_rects = not self.draw_thing_rects
-        scene = self._scene
-        for thing in scene.things.itervalues():
-            if not self.draw_thing_rects:
-                if not hasattr(thing, 'old_colour'):
-                    thing.old_colour = thing._interact_hilight_color
-                thing._interact_hilight_color = None
-            else:
-                thing._interact_hilight_color = thing.old_colour
-
-    def toggle_images(self, ev, widget):
-        self.draw_images = not self.draw_images
-        for image in self.images:
-            image.set_visible(self.draw_images)
-        if self.current_image:
-            self.current_image.set_visible(self.draw_images)
-        self.invalidate()
-
-    def toggle_trans_images(self, ev, widget):
-        self.trans_images = not self.trans_images
-        for image in self.images:
-            image.translucent = self.trans_images
-        if self.current_image:
-            self.current_image.translucent = self.trans_images
-        self.invalidate()
-
-    def toggle_rects(self, ev, widget):
-        self.draw_rects = not self.draw_rects
-
-    def toggle_toolbar(self, ev, widget):
-        self.draw_toolbar = not self.draw_toolbar
-
-    def toggle_zoom(self, ev, widget):
-        self.zoom_display = not self.zoom_display
-        self.invalidate()
-
-    def toggle_anim(self, ev, widget):
-        self.draw_anim = not self.draw_anim
-
-    def draw_mode(self, ev, widget):
-        self.mode = DRAW
-
-    def del_mode(self, ev, widget):
-        self.mode = DELETE
-        self.start_pos = None
-        self.end_pos = None
-
-    def invalidate(self):
-        self.clear_display = True
-
-    def draw(self, surface):
-        if not self.visible:
-            return
-        self.do_prepare()
-        if self.clear_display:
-            surface.fill(pygame.color.Color(0, 0, 0),
-                    pygame.Rect(0, 0, constants.screen[0],
-                        constants.screen[1]))
-            self.clear_display = False
-
-        if self.zoom_display:
-            base_surface = surface.copy()
-            self.do_unzoomed_draw(base_surface)
-            zoomed = pygame.transform.scale(base_surface,
-                            (constants.zoom * base_surface.get_width(),
-                             constants.zoom * base_surface.get_height()))
-            area = pygame.rect.Rect(self.zoom_offset[0], self.zoom_offset[1],
-                                    constants.screen[0], constants.screen[1])
-            surface.blit(zoomed, (0, 0), area)
-        else:
-            self.do_unzoomed_draw(surface)
-
-    def do_unzoomed_draw(self, surface):
-        if self.draw_things:
-            self._scene.draw(surface)
-        else:
-            self._scene.draw_background(surface)
-        if self._detail:
-            # We duplicate draw logic here, so we zoom the close
-            # button correctly
-            self.close_button.draw(surface)
-        if self.mode == DRAW and self.start_pos and self.draw_rects:
-            rect = pygame.rect.Rect(self.start_pos[0], self.start_pos[1],
-                    self.end_pos[0] - self.start_pos[0],
-                    self.end_pos[1] - self.start_pos[1])
-            rect.normalize()
-            draw_rect_image(surface, self.rect_color, rect, self.draw_thick)
-        if self.draw_rects:
-            for (col, rect) in self.rects:
-                draw_rect_image(surface, col, rect, self.rect_thick)
-        for image in self.images:
-            image.draw(surface)
-        if self.current_image and self.mode == IMAGE:
-            self.current_image.draw(surface)
-        if self.draw_toolbar:
-            tb_surf = surface.subsurface(0, constants.screen[1]
-                                            - constants.button_size,
-                                         constants.screen[0],
-                                         constants.button_size).convert_alpha()
-            tb_surf.fill(pygame.color.Color(127, 0, 0, 191))
-            surface.blit(tb_surf, (0, constants.screen[1]
-                                      - constants.button_size))
-
-    def _make_dict(self):
-        d = {}
-        for col, rect in self.rects:
-            col = (col.r, col.g, col.b)
-            d.setdefault(col, [])
-            d[col].append(rect)
-        return d
-
-    def print_objs(self, ev, widget):
-        d = self._make_dict()
-        self.find_intersecting_rects(d)
-        for (num, col) in enumerate(d):
-            print _('Rect %d : ') % num
-            for rect in d[col]:
-                r = rect.move(self.offset)
-                print '   (%d, %d, %d, %d),' % (r.x, r.y, r.w, r.h)
-            print
-        for i, image in enumerate(self.images):
-            print _('Image %d') % i
-            rect = image.rect
-            r = rect.move(self.offset)
-            print '   (%d, %d, %d, %d),' % (r.x, r.y, r.w, r.h)
-            print
-        print
-
-    def image_load(self, ev, widget):
-        if self.filechooser is None:
-            self.filechooser = FileChooser((0, 0), self.gd, None, os.curdir,
-                    self.do_load_image)
-        else:
-            self.filechooser.refresh()
-        self.invalidate()
-        self._parent.paused = True
-        self._parent.add(self.filechooser)
-
-    def do_load_image(self, filename):
-        try:
-            self.current_image = TranslucentImage((0, 0), self.gd,
-                    pygame.image.load(filename))
-            if not self.draw_images:
-                # Selecting an image makes image visible
-                self.toggle_images(None, None)
-            self.current_image.translucent = self.trans_images
-            self.place_image_menu.enabled = True
-            self.current_image.rect = self.current_image.rect.move(
-                    constants.screen[0] + constants.menu_width,
-                    constants.screen[1])
-            self.image_mode(None, None)
-        except pygame.error, e:
-            print 'Unable to load image %s (reason %s)' % (filename, e)
-
-    def image_mode(self, ev, widget):
-        self.mode = IMAGE
-        self.start_pos = None
-        self.end_pos = None
-        # So we do the right thing for off screen images
-        self.old_mouse_pos = None
-
-    def cycle_mode(self, ev, widget):
-        self.mode = CYCLE
-
-    def _conv_pos(self, mouse_pos):
-        if self.zoom_display:
-            pos = ((mouse_pos[0] + self.zoom_offset[0]) / constants.zoom,
-                   (mouse_pos[1] + self.zoom_offset[1]) / constants.zoom)
-        else:
-            pos = mouse_pos
-        return pos
-
-    def _check_limits(self, offset):
-        if offset[0] < 0:
-            offset[0] = 0
-        if offset[1] < 0:
-            offset[1] = 0
-        width, height = constants.screen
-        if offset[0] > constants.zoom * width - width:
-            offset[0] = constants.zoom * width - width
-        if offset[1] > constants.zoom * height - height:
-            offset[1] = constants.zoom * height - height
-
-    def _make_zoom_offset(self, pos):
-        zoom_pos = (pos[0] * constants.zoom, pos[1] * constants.zoom)
-        offset = [zoom_pos[0] - constants.screen[0] / 2,
-                zoom_pos[1] - constants.screen[1] / 2]
-        self._check_limits(offset)
-        self.zoom_offset = tuple(offset)
-
-    def _move_zoom(self, x, y):
-        offset = list(self.zoom_offset)
-        offset[0] += constants.zoom_step * x
-        offset[1] += constants.zoom_step * y
-        self._check_limits(offset)
-        self.zoom_offset = tuple(offset)
-
-    def key_down(self, ev, widget):
-        if self.mode == IMAGE and self.current_image:
-            # Move the image by 1 pixel
-            cur_pos = self.current_image.rect.center
-            if ev.key == K_LEFT:
-                self.current_image.rect.center = (cur_pos[0] - 1, cur_pos[1])
-            elif ev.key == K_RIGHT:
-                self.current_image.rect.center = (cur_pos[0] + 1, cur_pos[1])
-            elif ev.key == K_UP:
-                self.current_image.rect.center = (cur_pos[0], cur_pos[1] - 1)
-            elif ev.key == K_DOWN:
-                self.current_image.rect.center = (cur_pos[0], cur_pos[1] + 1)
-        elif self.zoom_display:
-            if ev.key == K_LEFT:
-                self._move_zoom(-1, 0)
-            elif ev.key == K_RIGHT:
-                self._move_zoom(1, 0)
-            elif ev.key == K_UP:
-                self._move_zoom(0, -1)
-            elif ev.key == K_DOWN:
-                self._move_zoom(0, 1)
-
-        if ev.key == K_o:
-            self.toggle_trans_images(None, None)
-        elif ev.key == K_t:
-            self.toggle_things(None, None)
-        elif ev.key == K_r:
-            self.toggle_thing_rects(None, None)
-        elif ev.key == K_i:
-            self.toggle_images(None, None)
-        elif ev.key == K_d:
-            self.toggle_rects(None, None)
-        elif ev.key == K_b:
-            self.toggle_toolbar(None, None)
-        elif ev.key == K_z:
-            self.toggle_zoom(None, None)
-        elif ev.key == K_a:
-            self.toggle_anim(None, None)
-
-    def mouse_down(self, ev, widget):
-        pos = self._conv_pos(ev.pos)
-        if self._parent.paused:
-            # Ignore this if the filechooser is active
-            return False
-        if self.mode == DELETE:
-            cand = None
-            # Images are drawn above rectangles, so search those first
-            for image in self.images:
-                if image.rect.collidepoint(pos):
-                    cand = image
-                    break
-            if cand:
-                self.images.remove(cand)
-                self.invalidate()
-                return
-            for (col, rect) in self.rects:
-                if rect.collidepoint(pos):
-                    cand = (col, rect)
-                    break
-            if cand:
-                self.rects.remove(cand)
-                self.invalidate()
-        elif self.mode == CYCLE:
-            scene = self._scene
-            cand = None
-            for thing in scene.things.itervalues():
-                if thing.contains(pos):
-                    cand = thing
-                    break
-            if cand:
-                # Find current interacts in this thing
-                cur_interact = cand.current_interact
-                j = cand.interacts.values().index(cur_interact)
-                if j + 1 < len(cand.interacts):
-                    next_name = cand.interacts.keys()[j + 1]
-                else:
-                    next_name = cand.interacts.keys()[0]
-                if cand.interacts[next_name] != cur_interact:
-                    cand._set_interact(next_name)
-        elif self.mode == DRAW:
-            self.start_pos = pos
-            self.end_pos = pos
-        elif self.mode == IMAGE:
-            if self.current_image:
-                self.images.append(self.current_image)
-                self.current_image = None
-                self.old_mouse_pos = None
-                self.invalidate()
-            else:
-                cand = None
-                for image in self.images:
-                    if image.rect.collidepoint(pos):
-                        cand = image
-                        break
-                if cand:
-                    self.images.remove(cand)
-                    self.current_image = cand
-                    # We want to move relative to the current mouse pos, so
-                    self.old_mouse_pos = pos
-                    self.invalidate()
-
-    def mouse_up(self, ev, widget):
-        if self._parent.paused:
-            return False
-        if self.mode == DRAW:
-            if self.start_pos is None:
-                # We've come here not via a drawing situation, so bail
-                return False
-            rect = pygame.rect.Rect(self.start_pos[0], self.start_pos[1],
-                    self.end_pos[0] - self.start_pos[0],
-                    self.end_pos[1] - self.start_pos[1])
-            rect.normalize()
-            self.rects.append((self.rect_color, rect))
-            self.start_pos = self.end_pos = None
-
-    def mouse_move(self, ev, widget):
-        # We're only interested in this if left mouse button is down or we've
-        # got and image
-        if self.mode == IMAGE and self.current_image:
-            pos = self._conv_pos(ev.pos)
-            if self.old_mouse_pos:
-                delta = (pos[0] - self.old_mouse_pos[0],
-                         pos[1] - self.old_mouse_pos[1])
-                self.current_image.rect.center = (
-                        self.current_image.rect.center[0] + delta[0],
-                        self.current_image.rect.center[1] + delta[1])
-            else:
-                self.current_image.rect.center = pos
-            self.invalidate()
-            self.old_mouse_pos = pos
-            return True
-        elif ev.buttons[0] == 1 and self.mode == DRAW:
-            self.end_pos = self._conv_pos(ev.pos)
-            return True
-        return False
-
-    def animate(self):
-        if self.draw_anim:
-            self._scene.animate()
-
-
-class ModeLabel(LabelWidget):
-
-    def __init__(self, pos, gd, app_image, size=None):
-        self.app_image = app_image
-        super(ModeLabel, self).__init__(pos,
-                gd, _('Mode : '), fontname=constants.bold_font,
-                fontsize=15, color=pygame.color.Color(128, 0, 255),
-                size=size)
-        self.start_rect = self.rect.copy()
-
-    def draw(self, surface):
-        self.do_prepare()
-        text = _('Mode : %s') % self.app_image.get_mode_name()
-        if self.text != text:
-            self.text = text
-            self.is_prepared = False
-            self.rect = self.start_rect.copy()
-            self.do_prepare()
-        super(ModeLabel, self).draw(surface)
-
-
-def make_button(text, gd, action, ypos):
-    rect = pygame.rect.Rect(0, 0, constants.menu_width,
-            constants.menu_button_height)
-    rect.move_ip(805, ypos)
-    button = TextButton(rect.topleft, gd, text, size=(constants.menu_width,
-        constants.menu_button_height),
-            fontname=constants.font, fontsize=12,
-            color=pygame.color.Color(255, 255, 0), border=1, padding=3)
-    button.add_callback('clicked', action)
-    return button
-
-
-class RectApp(Container):
-    """The actual rect drawer main app"""
-    def __init__(self, rect, gd, detail):
-        super(RectApp, self).__init__(rect, gd)
-
-        try:
-            state = gd.initial_state()
-            scene = state.scenes[gd._initial_scene]
-        except KeyError:
-            raise RectDrawerError(_('Invalid scene: %s') % gd._initial_scene)
-        gd.sound.disable_sound()  # No sound here
-
-        if detail:
-            try:
-                scene = state.detail_views[detail]
-            except KeyError:
-                raise RectDrawerError(_('Invalid detail: %s') % detail)
-
-        self.paused = False
-
-        self.image = AppImage(self, gd, state, scene, detail is not None)
-        self.add(self.image)
-        mode_label = ModeLabel((805, 0), self.gd, self.image, size=(200, 50))
-        self.add(mode_label)
-        y = mode_label.rect.height
-        draw = make_button(_('Draw Rect'), gd, self.image.draw_mode, y)
-        self.add(draw)
-        y += draw.rect.height
-        load_image = make_button(_("Load image"), gd, self.image.image_load, y)
-        self.add(load_image)
-        y += load_image.rect.height
-        add_image = make_button(_("Place/Move images"), gd,
-                self.image.image_mode, y)
-        add_image.enabled = False
-        self.add(add_image)
-        self.image.place_image_menu = add_image
-        y += add_image.rect.height
-        cycle = make_button(_("Cycle interacts"), gd, self.image.cycle_mode, y)
-        self.add(cycle)
-        y += cycle.rect.height
-        delete = make_button(_("Delete Objects"), gd, self.image.del_mode, y)
-        self.add(delete)
-        y += delete.rect.height
-        palette = AppPalette((810, y), gd, self.image, size=(200, 0))
-        self.add(palette)
-        y += palette.rect.height
-        print_rects = make_button(_("Print objects"), gd,
-                self.image.print_objs, y)
-        self.add(print_rects)
-        y += print_rects.rect.height
-        toggle_things = make_button(_("Show Things (t)"), gd,
-                self.image.toggle_things, y)
-        self.add(toggle_things)
-        y += toggle_things.rect.height
-        toggle_thing_rects = make_button(_("Show Thing Rects (r)"), gd,
-                self.image.toggle_thing_rects, y)
-        self.add(toggle_thing_rects)
-        y += toggle_thing_rects.rect.height
-        toggle_images = make_button(_("Show Images (i)"), gd,
-                self.image.toggle_images, y)
-        self.add(toggle_images)
-        y += toggle_images.rect.height
-        trans_images = make_button(_("Opaque Images (o)"), gd,
-                self.image.toggle_trans_images, y)
-        self.add(trans_images)
-        y += trans_images.rect.height
-        toggle_rects = make_button(_("Show Drawn Rects (d)"), gd,
-                self.image.toggle_rects, y)
-        self.add(toggle_rects)
-        y += toggle_rects.rect.height
-        toggle_toolbar = make_button(_("Show Toolbar (b)"), gd,
-                self.image.toggle_toolbar, y)
-        self.add(toggle_toolbar)
-        y += toggle_toolbar.rect.height
-        toggle_anim = make_button(_("Show Animations (a)"), gd,
-                self.image.toggle_anim, y)
-        self.add(toggle_anim)
-        y += toggle_anim.rect.height
-        toggle_zoom = make_button(_("Zoom (z)"), gd,
-                self.image.toggle_zoom, y)
-        self.add(toggle_zoom)
-        y += toggle_zoom.rect.height
-        quit_but = make_button(_("Quit"), gd, self.quit, 570)
-        self.add(quit_but)
-
-    def quit(self, ev, widget):
-        pygame.event.post(pygame.event.Event(QUIT))
-
-    def animate(self):
-        self.image.animate()
-
-
-class RectEngine(object):
-    """Engine for the rect drawer."""
-
-    def __init__(self, gd, detail):
-        self.state = None
-        self._gd = gd
-        rect = pygame.display.get_surface().get_rect()
-        self.app = RectApp(rect.topleft, self._gd, detail)
-
-    def run(self):
-        """App loop"""
-        clock = pygame.time.Clock()
-        while True:
-            events = pygame.event.get()
-            for ev in events:
-                if ev.type == QUIT:
-                    return
-                else:
-                    self.app.event(ev)
-            self.app.animate()
-            surface = pygame.display.get_surface()
-            self.app.draw(surface)
-            pygame.display.flip()
-            clock.tick(self._gd.constants.frame_rate)
-
-
-def make_rect_display():
-    pygame.display.init()
-    pygame.font.init()
-    pygame.display.set_mode((constants.screen[0]
-        + constants.menu_width, constants.screen[1]))
--- a/pyntnclick/utils.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-# Misc utils I don't know where else to put
-
-import pygame
-from pygame.locals import SRCALPHA
-from pygame.surface import Surface
-
-
-def list_scenes(scene_module, scene_list):
-    """List the scenes in the state"""
-    print "Available scenes and details:"
-    for scene in scene_list:
-        scenemod = __import__('%s.%s' % (scene_module, scene),
-                         fromlist=[scene])
-        if scenemod.SCENES:
-            print " * %s" % scene
-        else:
-            print " * %s (details only)" % scene
-        for detailcls in getattr(scenemod, 'DETAIL_VIEWS', []):
-            print "   - %s" % detailcls.NAME
-
-
-def draw_rect_image(surface, color, rect, thickness):
-    """Draw a rectangle with lines thickness wide"""
-    # top
-    surface.fill(color, (rect.left, rect.top, rect.width, thickness))
-    # bottom
-    surface.fill(color, (rect.left, rect.bottom - thickness, rect.width,
-        thickness))
-    # left
-    surface.fill(color, (rect.left, rect.top, thickness, rect.height))
-    # right
-    surface.fill(color, (rect.right - thickness, rect.top, thickness,
-        rect.height))
-
-
-def convert_color(color):
-    """Give me a pygame Color, dammit"""
-    if isinstance(color, pygame.Color):
-        return color
-    if isinstance(color, basestring):
-        return pygame.Color(color)
-    return pygame.Color(*color)
-
-
-def render_text(text, fontname, font_size, color, bg_color, resource, size,
-        centre=True):
-    """Render the text so it will fit in the given size, reducing font
-       size as needed.
-
-       Note that this does not do any text wrapping."""
-    done = False
-    width, height = size
-    color = convert_color(color)
-    bg_color = convert_color(bg_color)
-    surface = Surface(size, SRCALPHA).convert_alpha()
-    surface.fill(bg_color)
-    while not done and font_size > 0:
-        # We bail at font_size 1 and just clip in that case, since we're
-        # out of good options
-        font = resource.get_font(fontname, font_size)
-        text_surf = font.render(text, True, color)
-        if (text_surf.get_width() > width or text_surf.get_height() > height):
-            font_size -= 1
-        else:
-            done = True
-    if centre:
-        # Centre the text in the rect
-        x = max(0, (width - text_surf.get_width()) / 2)
-        y = max(0, (height - text_surf.get_height()) / 2)
-    else:
-        x = y = 0
-    surface.blit(text_surf, (x, y))
-    return surface
--- a/pyntnclick/version.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-"""Pyntnclick Version Information"""
-
-VERSION = (0, 0, 1, 'alpha', 0)
-BASE_VERSION_STR = '.'.join([str(x) for x in VERSION[:3]])
-VERSION_STR = {
-    'final': BASE_VERSION_STR,
-    'alpha': BASE_VERSION_STR + 'a' + str(VERSION[4]),
-    'rc': BASE_VERSION_STR + 'rc' + str(VERSION[4]),
-}[VERSION[3]]
-
-NAME = 'Pyntnclick'
-DESCRIPTION = 'Point-and-click adventure game engine using Pygame.'
-
-PEOPLE = {
-    'Simon': ('Simon Cross', 'hodgestar+rinkhals@gmail.com'),
-    'Neil': ('Neil Muller', 'drnmuller+rinkhals@gmail.com'),
-    'Adrianna': ('Adrianna Pinska', 'adrianna.pinska+rinkhals@gmail.com'),
-    'Jeremy': ('Jeremy Thurgood', 'firxen+rinkhals@gmail.com'),
-    'Stefano': ('Stefano Rivera', 'stefano@rivera.za.net'),
-}
-
-AUTHORS = [
-    PEOPLE['Simon'],
-    PEOPLE['Neil'],
-    PEOPLE['Adrianna'],
-    PEOPLE['Jeremy'],
-    PEOPLE['Stefano'],
-]
-
-AUTHOR_NAME = AUTHORS[0][0]
-AUTHOR_EMAIL = AUTHORS[0][1]
-
-MAINTAINERS = AUTHORS
-
-MAINTAINER_NAME = MAINTAINERS[0][0]
-MAINTAINER_EMAIL = MAINTAINERS[0][1]
-
-ARTISTS = [
-    PEOPLE['Adrianna'],
-]
-
-DOCUMENTERS = [
-    PEOPLE['Simon'],
-    PEOPLE['Stefano'],
-]
-
-# HOMEPAGE = 'http://sourceforge.net/projects/XXXX/'
-# PYPI_URL = 'http://pypi.python.org/pypi/XXXX/'
-
-LICENSE = 'MIT'
-# LICENSE_TEXT = resource_string(__name__, 'COPYING')
-
-CLASSIFIERS = [
-    'Development Status :: 4 - Beta',
-    'Environment :: MacOS X',
-    'Environment :: Win32 (MS Windows)',
-    'Environment :: X11 Applications',
-    'Intended Audience :: Developers',
-    'License :: OSI Approved :: MIT License',
-    'Natural Language :: English',
-    'Operating System :: Microsoft :: Windows',
-    'Operating System :: POSIX',
-    'Operating System :: MacOS :: MacOS X',
-    'Programming Language :: Python :: 2.5',
-    'Programming Language :: Python :: 2.6',
-    'Topic :: Games/Entertainment',
-]
-
-PLATFORMS = [
-    'Linux',
-    'Mac OS X',
-    'Windows',
-]
-
-INSTALL_REQUIRES = [
-]
-
-# Install these manually
-NON_EGG_REQUIREMENTS = [
-    'setuptools',
-    'pygame',
-]
--- a/pyntnclick/widgets/__init__.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-# __init__.py for the widgets
-# Copyright Boomslang team, 2010-2012 (see COPYING File)
-
-"""pyntnclick widgets"""
--- a/pyntnclick/widgets/base.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,275 +0,0 @@
-import collections
-
-import pygame
-from pygame.locals import (MOUSEBUTTONDOWN, MOUSEBUTTONUP,
-                           MOUSEMOTION, SRCALPHA, USEREVENT,
-                           BLEND_RGBA_MIN)
-
-from pyntnclick.engine import UserEvent
-from pyntnclick.utils import convert_color
-
-
-class Widget(object):
-
-    highlight_cursor = False
-
-    def __init__(self, pos, gd, size):
-        self.pos = pos
-        self.gd = gd
-        self.resource = gd.resource
-        self.size = size
-        self.rect = pygame.Rect(pos, size if size else (0, 0))
-        self.modal = False
-        self.parent = None
-        self.disabled = False
-        self.visible = True
-        self.callbacks = collections.defaultdict(list)
-        # To track which widget the mouse is over
-        self.mouseover_widget = self
-        self.is_prepared = False
-
-    def set_parent(self, parent):
-        self.parent = parent
-
-    def add_callback(self, eventtype, callback, *args):
-        self.callbacks[eventtype].append((callback, args))
-
-    def event(self, ev):
-        "Don't override this without damn good reason"
-        if self.disabled or not self.visible:
-            return False
-
-        type_ = ev.type
-        if type_ == USEREVENT:
-            for k in self.callbacks.iterkeys():
-                if (isinstance(k, type) and issubclass(k, UserEvent)
-                        and k.matches(ev)):
-                    type_ = k
-                    break
-
-        for callback, args in self.callbacks[type_]:
-            if callback(ev, self, *args):
-                return True
-        return False
-
-    def draw(self, surface):
-        "Override me"
-        pass
-
-    def prepare(self):
-        """Override me"""
-        pass
-
-    def do_prepare(self):
-        if not self.is_prepared:
-            self.prepare()
-            self.is_prepared = True
-
-    def disable(self):
-        if not self.disabled:
-            self.disabled = True
-            self.prepare()
-            self.is_prepared = True
-
-    def enable(self):
-        if self.disabled:
-            self.disabled = False
-            self.prepare()
-            self.is_prepared = True
-
-    def set_visible(self, visible):
-        if self.visible != visible:
-            self.visible = visible
-            self.prepare()
-            self.is_prepared = True
-
-    def global_to_local(self, pos):
-        x, y = pos
-        return (x - self.rect.left, y - self.rect.top)
-
-
-class Button(Widget):
-
-    highlight_cursor = True
-
-    def event(self, ev):
-        if super(Button, self).event(ev):
-            return True
-        if ev.type == MOUSEBUTTONDOWN:
-            for callback, args in self.callbacks['clicked']:
-                if callback(ev, self, *args):
-                    return True
-            return False
-
-    def forced_click(self):
-        """Force calling the clicked handler"""
-        for callback, args in self.callbacks['clicked']:
-            if callback(None, self, *args):
-                return True
-        return False
-
-
-class Container(Widget):
-
-    def __init__(self, pos, gd, size=None):
-        super(Container, self).__init__(pos, gd, size)
-        self.children = []
-
-    def event(self, ev):
-        """Push an event down through the tree, and fire our own event as a
-        last resort
-        """
-        self.mouseover_widget = self
-        if ev.type in (MOUSEMOTION, MOUSEBUTTONUP, MOUSEBUTTONDOWN):
-            for child in self.children[:]:
-                if child.rect.collidepoint(ev.pos):
-                    result = child.event(ev)
-                    self.mouseover_widget = child.mouseover_widget
-                    if result:
-                        return True
-
-        else:
-            # Other events go to all children first
-            for child in self.children[:]:
-                if child.event(ev):
-                    return True
-        if super(Container, self).event(ev):
-            return True
-
-    def add(self, widget):
-        widget.set_parent(self)
-        widget.prepare()
-        self.children.append(widget)
-        if not self.size:
-            self.rect = self.rect.union(widget.rect)
-        return widget
-
-    def remove(self, widget):
-        widget.set_parent(None)
-        self.children.remove(widget)
-
-    def remove_all(self):
-        for widget in reversed(self.children[:]):
-            self.remove(widget)
-
-    def draw(self, surface):
-        if self.visible:
-            self.do_prepare()
-            for child in self.children:
-                child.draw(surface)
-
-
-class ModalStackContainer(Container):
-
-    def __init__(self, pos, gd, size, obscure_color=None):
-        super(ModalStackContainer, self).__init__(pos, gd, size)
-        if obscure_color is None:
-            obscure_color = gd.constants.modal_obscure_color
-        self.obscure_color = convert_color(obscure_color)
-
-    @property
-    def top(self):
-        if self.children:
-            return self.children[-1]
-        return None
-
-    def event(self, ev):
-        """Only the topmost child gets events.
-        """
-        self.mouseover_widget = self
-        if self.top:
-            self.mouseover_widget = self.top.mouseover_widget
-            if self.top.event(ev):
-                return True
-
-        # We skip Container's event() method and hop straight to its parent's.
-        if super(Container, self).event(ev):
-            return True
-
-    def is_top(self, widget):
-        return self.top is widget
-
-    def draw(self, surface):
-        if self.visible:
-            self.do_prepare()
-            obscure = pygame.Surface(self.rect.size, SRCALPHA)
-            obscure.fill(self.obscure_color)
-            for child in self.children:
-                surface.blit(obscure, self.rect)
-                child.draw(surface)
-
-
-class Box(Container):
-    """A container that draws a filled background with a border"""
-    padding = 4
-
-    def draw(self, surface):
-        if self.visible:
-            self.do_prepare()
-            # TODO: Why isn't this done in prepare?
-            expandrect = self.rect.move((-self.padding, -self.padding))
-            expandrect.width = self.rect.width + 2 * self.padding
-            expandrect.height = self.rect.height + 2 * self.padding
-            border = pygame.Surface(expandrect.size, SRCALPHA)
-            border.fill(pygame.Color('black'))
-            surface.blit(border, expandrect)
-            background = pygame.Surface(self.rect.size, SRCALPHA)
-            background.fill(pygame.Color('gray'))
-            surface.blit(background, self.rect)
-            super(Box, self).draw(surface)
-
-
-class ModalWrapper(Container):
-    "A wrapper around a widget that removes itself when a mouse click occurs"
-
-    def __init__(self, widget, close_callback=None):
-        super(ModalWrapper, self).__init__(widget.rect.topleft, widget.gd,
-                                           widget.rect.size)
-        self.close_callback = close_callback
-        self.add(widget)
-        self.add_callback(MOUSEBUTTONDOWN, self.close)
-        widget.add_callback(MOUSEBUTTONDOWN, self.close)
-
-    def close(self, ev, widget):
-        if self.parent:
-            self.parent.remove(self)
-            if self.close_callback:
-                self.close_callback()
-            return True
-
-
-class Image(Widget):
-    """Basic widget that draws an image, with an associated rect"""
-
-    def __init__(self, pos, gd, image, size=None):
-        super(Image, self).__init__(pos, gd, size)
-        self.image = image
-        if not size:
-            self.rect.size = image.get_rect().size
-        self.visible = True
-
-    def draw(self, surface):
-        self.do_prepare()
-        if self.visible:
-            surface.blit(self.image, self.rect)
-
-
-class TranslucentImage(Image):
-    """Image that can also be translucent"""
-
-    def __init__(self, pos, gd, image, size=None):
-        super(TranslucentImage, self).__init__(pos, gd, image, size)
-        self.translucent = False
-        surf = pygame.surface.Surface((self.rect.width, self.rect.height),
-                SRCALPHA).convert_alpha()
-        surf.fill(pygame.color.Color(255, 255, 255, 96))
-        surf.blit(self.image, (0, 0), None, BLEND_RGBA_MIN)
-        self.trans_image = surf
-
-    def draw(self, surface):
-        self.do_prepare()
-        if self.visible:
-            if self.translucent:
-                surface.blit(self.trans_image, self.rect)
-            else:
-                surface.blit(self.image, self.rect)
--- a/pyntnclick/widgets/filechooser.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-# Display a paged lsit of files and directories
-# Allow moving up and down directory trees
-
-import os
-
-from pyntnclick.widgets.base import Box
-from pyntnclick.widgets.text import TextButton, LabelWidget
-
-
-class FileChooser(Box):
-
-    def __init__(self, pos, gd, size, curdir, ok_callback,
-            page_length=12, padding=2):
-        super(FileChooser, self).__init__(pos, gd, size)
-        self.page_length = page_length
-        self.page = 0
-        self.ok_callback = ok_callback
-        self.curdir = os.path.realpath(os.path.normpath(curdir))
-        self.selected = None
-        self.padding = padding
-        self.dirs = []
-        self.files = []
-        self.modal = True
-        self.prev_but = None
-        self.next_but = None
-
-    def get_lists(self):
-        self.dirs = []
-        self.files = []
-        for entry in sorted(os.listdir(self.curdir)):
-            path = os.path.join(self.curdir, entry)
-            if os.path.isdir(path):
-                self.dirs.append(entry)
-            else:
-                self.files.append(entry)
-
-    def prepare(self):
-        super(FileChooser, self).prepare()
-        self.refresh()
-
-    def refresh(self):
-        self.page = 0
-        self.selected = None
-        self.get_lists()
-        self.fill_page()
-
-    def _dir_button(self, entry):
-        widget = TextButton((0, 0), self.gd, entry + '/',
-                fontname=self.gd.constants.bold_font,
-                fontsize=10)
-        widget.do_prepare()
-        widget.add_callback('clicked', self.change_dir, entry)
-        return widget
-
-    def _file_button(self, entry):
-        if entry == self.selected:
-            # highlight
-            widget = TextButton((0, 0), self.gd, entry,
-                    fontsize=10, border=2, color='yellow')
-        else:
-            widget = TextButton((0, 0), self.gd, entry, border=0,
-                    fontsize=10)
-        widget.do_prepare()
-        widget.add_callback('clicked', self.change_selection, entry)
-        return widget
-
-    def fill_page(self):
-        for widget in self.children[:]:
-            self.remove(widget)
-        start_page = self.page * self.page_length
-        end_page = start_page + self.page_length
-        entries = self.dirs + self.files
-        top = self.rect.top + self.padding
-        left = self.rect.left + self.padding
-        # Add current directory at the top
-        widget = LabelWidget((left, top), self.gd, self.curdir[-30:],
-                             color='black')
-        widget.do_prepare()
-        self.add(widget)
-        upbut = TextButton((left + 2 * self.padding + widget.rect.width, top),
-                self.gd, u'\N{LEFTWARDS ARROW WITH HOOK}Back one level')
-        upbut.do_prepare()
-        upbut.add_callback('clicked', self.change_dir, os.pardir)
-        self.add(upbut)
-        top += max(widget.rect.height, upbut.rect.height) + 4 * self.padding
-        page_top = top
-        page_left = left
-        top += self.padding
-        for entry in entries[start_page:end_page]:
-            if entry in self.dirs:
-                widget = self._dir_button(entry)
-            else:
-                widget = self._file_button(entry)
-            widget.rect.topleft = (left, top)
-            self.add(widget)
-            top += widget.rect.height + self.padding
-            page_left = max(page_left, left + widget.rect.width + self.padding)
-        # Add page list buttons
-        if not self.prev_but:
-            self.prev_but = TextButton((0, 0), self.gd, u'\N{UPWARDS ARROW}')
-            self.prev_but.do_prepare()
-            self.prev_but.add_callback('clicked', self.change_page, -1)
-        self.prev_but.rect.topleft = (page_left, page_top)
-        if not self.next_but:
-            self.next_but = TextButton((0, 0), self.gd, u'\N{DOWNWARDS ARROW}')
-            self.next_but.do_prepare()
-            self.next_but.add_callback('clicked', self.change_page, +1)
-        page_top = max(top - self.next_but.rect.height,
-                self.prev_but.rect.bottom + self.padding)
-        self.next_but.rect.topleft = (page_left, page_top)
-        if self.page > 0:
-            self.prev_but.enable()
-        else:
-            self.prev_but.disable()
-        if end_page + 1 < len(entries):
-            self.next_but.enable()
-        else:
-            self.next_but.disable()
-        self.add(self.next_but)
-        self.add(self.prev_but)
-        # Add OK and Cancel buttons
-        top = max(self.prev_but.rect.bottom + self.padding,
-                top + 2 * self.padding)
-        ok_but = TextButton((left, top), self.gd, 'OK')
-        ok_but.add_callback('clicked', self.ok)
-        self.add(ok_but)
-        cancel_but = TextButton(
-                (left + ok_but.rect.width + 4 * self.padding, top),
-                self.gd, 'Cancel')
-        cancel_but.add_callback('clicked', self.cancel)
-        self.add(cancel_but)
-
-    def change_page(self, ev, widget, change):
-        self.page += change
-        self.fill_page()
-        return True
-
-    def change_dir(self, ev, widget, newdir):
-        """Change directory and refresh the widget."""
-        self.curdir = os.path.normpath(os.path.join(self.curdir, newdir))
-        self.page = 0
-        self.selected = None
-        self.get_lists()
-        self.fill_page()
-
-    def change_selection(self, ev, widget, entry):
-        """Update selection"""
-        self.selected = entry
-        self.fill_page()
-
-    def cancel(self, ev, widget):
-        if hasattr(self.parent, 'paused'):
-            self.parent.paused = False
-        self.parent.remove(self)
-        return True
-
-    def ok(self, ev, widget):
-        if hasattr(self.parent, 'paused'):
-            self.parent.paused = False
-        self.parent.remove(self)
-        if self.selected:
-            self.ok_callback(os.path.normpath(os.path.join(self.curdir,
-                self.selected)))
-        return True
--- a/pyntnclick/widgets/imagebutton.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-from pyntnclick.widgets.base import Button
-
-
-class ImageButtonWidget(Button):
-    """An image that is also a button. Whatever next?"""
-
-    def __init__(self, pos, gd, image, size=None):
-        super(ImageButtonWidget, self).__init__(pos, gd, size)
-        if not size:
-            self.rect.size = image.get_rect().size
-        self.image = image
-
-    def draw(self, surface):
-        if self.visible:
-            surface.blit(self.image, self.rect)
--- a/pyntnclick/widgets/text.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-from textwrap import wrap
-
-import pygame
-from pygame.constants import SRCALPHA
-
-from pyntnclick.widgets.base import Widget, Button
-from pyntnclick.utils import convert_color
-
-
-class TextWidget(Widget):
-    def __init__(self, pos, gd, text, size=None, fontname=None, fontsize=None,
-                 color=None):
-        super(TextWidget, self).__init__(pos, gd, size)
-        self.text = text
-        constants = self.gd.constants
-        self.fontname = fontname or constants.font
-        self.fontsize = fontsize or constants.font_size
-        self.color = color or constants.text_color
-
-    def prepare(self):
-        self.font = self.resource.get_font(self.fontname, self.fontsize)
-        self.color = convert_color(self.color)
-        self.surface = self.font.render(self.text, True, self.color)
-        self.text_rect = self.surface.get_rect()
-        if not self.size:
-            self.rect.size = self.text_rect.size
-
-    def draw(self, surface):
-        if self.visible:
-            self.do_prepare()
-            surface.blit(self.surface, self.rect)
-
-
-class LabelWidget(TextWidget):
-    def __init__(self, pos, gd, *args, **kwargs):
-        constants = gd.constants
-        self.padding = kwargs.pop('padding', constants.label_padding)
-        self.border = kwargs.pop('border', constants.label_border)
-        self.bg_color = convert_color(
-                kwargs.pop('bg_color', constants.label_bg_color))
-        self.border_color = convert_color(
-                kwargs.pop('border_color', constants.label_border_color))
-        super(LabelWidget, self).__init__(pos, gd, *args, **kwargs)
-
-    def prepare(self):
-        super(LabelWidget, self).prepare()
-        if not self.size:
-            self.rect.width += 2 * self.padding
-            self.rect.height += 2 * self.padding
-        new_surface = pygame.Surface(self.rect.size)
-        new_surface = new_surface.convert_alpha()
-        new_surface.fill(self.bg_color)
-        new_surface.blit(self.surface, self.surface.get_rect().move(
-                (self.padding, self.padding)))
-        if self.border:
-            pygame.draw.rect(new_surface, self.border_color,
-                             new_surface.get_rect(),
-                             self.border)
-        self.surface = new_surface
-
-    def draw(self, surface):
-        if self.visible:
-            self.do_prepare()
-            surface.blit(self.surface, self.rect)
-
-
-class TextButton(Button, TextWidget):
-    def __init__(self, pos, gd, *args, **kwargs):
-        constants = gd.constants
-        self.padding = kwargs.pop('padding', constants.label_padding)
-        self.border = kwargs.pop('border', constants.label_border)
-
-        kwargs['color'] = convert_color(
-                kwargs.pop('color', constants.button_color))
-        self.disabled_color = convert_color(
-                kwargs.pop('disabled_color', constants.button_disabled_color))
-        self.bg_color = convert_color(
-                kwargs.pop('bg_color', constants.button_bg_color))
-
-        super(TextButton, self).__init__(pos, gd, *args, **kwargs)
-
-    def prepare(self):
-        super(TextButton, self).prepare()
-        text = self.surface
-        text_rect = self.text_rect
-        color = self.disabled_color if self.disabled else self.color
-
-        width = text_rect.width + self.padding * 2
-        height = text_rect.height + self.padding * 2
-        if not self.size:
-            self.rect.width = max(self.rect.width, width)
-            self.rect.height = max(self.rect.height, height)
-        self.surface = pygame.Surface(self.rect.size, SRCALPHA)
-        self.surface.fill(self.bg_color)
-        offset = (
-            (self.rect.width - width) / 2 + self.padding,
-            (self.rect.height - height) / 2 + self.padding)
-        self.surface.blit(text, text.get_rect().move(offset))
-
-        if self.border:
-            pygame.draw.rect(self.surface, color, self.surface.get_rect(),
-                             self.border)
-
-    def draw(self, surface):
-        super(TextButton, self).draw(surface)
-
-
-class WrappedTextLabel(LabelWidget):
-    """A Label Widget that wraps the text to a given maximum width"""
-
-    def __init__(self, pos, gd, *args, **kwargs):
-        self.max_width = kwargs.pop('max_width', gd.constants.screen[0] - 50)
-        self._wrap_width = None
-        self._text_lines = None
-        super(WrappedTextLabel, self).__init__(pos, gd, *args, **kwargs)
-
-    def prepare(self):
-        if self._wrap_width is None:
-            # Start without wrapping
-            self._wrap_width = len(self.text) + 1
-            self._text_lines = [self.text]
-
-        self.font = self.resource.get_font(self.fontname, self.fontsize)
-        self.color = convert_color(self.color)
-        self._render()
-        self.text_rect = self.surface.get_rect()
-        width, height = self.surface.get_rect().size
-        while width > self.max_width:
-            # Very simplistic approach
-            self._wrap_width = self._wrap_width / 2
-            self._text_lines = wrap(self.text, self._wrap_width)
-            self._render()
-            width, height = self.surface.get_rect().size
-        if not self.size:
-            self.rect.width = max(self.rect.width, width)
-            self.rect.height = max(self.rect.height, height)
-
-        if self.border:
-            pygame.draw.rect(self.surface, self.border_color,
-                             self.surface.get_rect(),
-                             self.border)
-
-    def _render(self):
-        surfaces = []
-        width = 0
-        height = 0
-        for line in self._text_lines:
-            line_surf = self.font.render(line, True, self.color)
-            surfaces.append(line_surf)
-            width = max(line_surf.get_rect().width, width)
-            height += line_surf.get_rect().height
-
-        width += 2 * self.padding
-        height += 2 * self.padding
-
-        self.surface = pygame.Surface((width, height))
-        self.surface = self.surface.convert_alpha()
-        self.surface.fill(self.bg_color)
-        height = self.padding
-        for line_surf in surfaces:
-            rect = pygame.Rect((self.padding, height),
-                               (line_surf.get_rect().size))
-            self.surface.blit(line_surf, rect)
-            height += line_surf.get_rect().height
--- a/pyntnclick/widgets/toollist.py	Sat Jun 21 22:04:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-from pyntntclick.widgets.base import Container
-from pyntntclick.widgets.text import TextButton
-
-
-class ToolListWidget(Container):
-    """List of other widgets, with some paging trickery"""
-
-    def __init__(self, pos, gd, size, widget_list, page_length,
-                 padding=2):
-        widget_list.sort(key=lambda w: w.text)
-        self.widget_list = widget_list
-        self.page_length = page_length
-        self.padding = padding
-        self.page = 0
-        super(ToolListWidget, self).__init__(pos, gd, size)
-        self.prev_but = None
-        self.next_but = None
-
-    def prepare(self):
-        self.fill_page()
-
-    def fill_page(self):
-        for widget in self.children[:]:
-            self.remove(widget)
-        start_page = self.page * self.page_length
-        end_page = start_page + self.page_length
-        button_height = self.rect.top + self.padding
-        button_left = self.rect.left + self.padding
-        for widget in self.widget_list[start_page:end_page]:
-            widget.rect.topleft = (button_left, button_height)
-            self.add(widget)
-            button_height += widget.rect.height + self.padding
-        if not self.prev_but:
-            self.prev_but = TextButton((button_left, button_height),
-                                       u'\N{LEFTWARDS ARROW}')
-            self.prev_but.add_callback('clicked', self.change_page, -1)
-        else:
-            self.prev_but.rect.top = max(button_height, self.prev_but.rect.top)
-        if not self.next_but:
-            self.next_but = TextButton((button_left + 100, button_height),
-                    u'\N{RIGHTWARDS ARROW}')
-            self.next_but.add_callback('clicked', self.change_page, 1)
-        else:
-            self.next_but.rect.top = max(button_height, self.next_but.rect.top)
-        if start_page > 0:
-            self.prev_but.enable()
-        else:
-            self.prev_but.disable()
-        if end_page < len(self.widget_list):
-            self.next_but.enable()
-        else:
-            self.next_but.disable()
-        self.add(self.prev_but)
-        self.add(self.next_but)
-        for widget in self.children[:]:
-            if widget in self.widget_list:
-                # Standardise widdths
-                widget.rect.width = self.rect.width - 2
-                widget.prepare()
-
-    def change_page(self, ev, widget, change):
-        self.page += change
-        self.fill_page()
-        return True