changeset 803:bcc9277a23e6 pyntnclick

Refactor widget positioning API. Remove unused widgets
author Stefano Rivera <stefano@rivera.za.net>
date Sun, 27 Jan 2013 14:52:16 +0200
parents 5ec7905b2365
children 16401f997e32
files gamelib/custom_widgets.py gamelib/endscreen.py pyntnclick/engine.py pyntnclick/gamescreen.py pyntnclick/menuscreen.py pyntnclick/state.py pyntnclick/widgets/base.py pyntnclick/widgets/filechooser.py pyntnclick/widgets/game.py pyntnclick/widgets/imagebutton.py pyntnclick/widgets/listbox.py pyntnclick/widgets/messagebox.py pyntnclick/widgets/overlay.py pyntnclick/widgets/text.py pyntnclick/widgets/toollist.py
diffstat 15 files changed, 103 insertions(+), 246 deletions(-) [+]
line wrap: on
line diff
--- a/gamelib/custom_widgets.py	Sun Jan 27 14:50:33 2013 +0200
+++ b/gamelib/custom_widgets.py	Sun Jan 27 14:52:16 2013 +0200
@@ -8,8 +8,9 @@
     """Custom widget for JIM's speech"""
 
     def __init__(self, gd, mesg):
-        rect = pygame.Rect((0, 0), (1, 1))
-        super(JimLabel, self).__init__(rect, gd,
+        pos = (0, 0)
+        size = None
+        super(JimLabel, self).__init__(pos, gd, size=size,
                 text=mesg, fontname='Monospace.ttf', fontsize=20,
                 bg_color=pygame.Color(255, 175, 127, 191),
                 color=pygame.Color(0, 0, 0),
--- a/gamelib/endscreen.py	Sun Jan 27 14:50:33 2013 +0200
+++ b/gamelib/endscreen.py	Sun Jan 27 14:52:16 2013 +0200
@@ -14,9 +14,9 @@
         self.add_image_button((26, 500), 'won/menu.png', self.main_menu)
         self.add_image_button((250, 500), 'won/quit.png', self.quit)
 
-    def add_image_button(self, rect, image_name, callback):
+    def add_image_button(self, pos, image_name, callback):
         image = self.resource.get_image(image_name)
-        widget = ImageButtonWidget(rect, self.gd, image)
+        widget = ImageButtonWidget(pos, self.gd, image)
         widget.add_callback('clicked', callback)
         self.container.add(widget)
 
--- a/pyntnclick/engine.py	Sun Jan 27 14:50:33 2013 +0200
+++ b/pyntnclick/engine.py	Sun Jan 27 14:52:16 2013 +0200
@@ -69,8 +69,7 @@
 
         self.surface_size = gd.constants.screen
         self.surface = None
-        self.container = Container(pygame.Rect((0, 0), self.surface_size),
-                self.gd)
+        self.container = Container((0, 0), self.gd, self.surface_size)
         self.setup()
 
     def on_enter(self):
--- a/pyntnclick/gamescreen.py	Sun Jan 27 14:50:33 2013 +0200
+++ b/pyntnclick/gamescreen.py	Sun Jan 27 14:52:16 2013 +0200
@@ -3,7 +3,7 @@
 # Main menu for the game
 
 import pygame.draw
-from pygame import Rect, Surface
+from pygame import Surface
 from pygame.color import Color
 from pygame.locals import MOUSEBUTTONDOWN, MOUSEMOTION, KEYDOWN, K_ESCAPE
 
@@ -20,9 +20,9 @@
     SELECTED_COLOR = Color("yellow")
     SELECTED_WIDTH = 2
 
-    def __init__(self, rect, gd):
+    def __init__(self, pos, gd, size):
         self.item = None
-        super(InventorySlot, self).__init__(rect, gd, None)
+        super(InventorySlot, self).__init__(pos, gd, None, size)
         self.add_callback(MOUSEBUTTONDOWN, self.mouse_down)
 
     def set_item(self, item):
@@ -53,8 +53,9 @@
 
 class UpDownButton(TextButton):
     # TextButton for now.
-    def __init__(self, rect, gd):
-        super(UpDownButton, self).__init__(rect, gd, self.TEXT, padding=3)
+    def __init__(self, pos, gd, size=None):
+        super(UpDownButton, self).__init__(pos, gd, self.TEXT, size=size,
+                                           padding=3)
 
 
 class UpButton(UpDownButton):
@@ -68,9 +69,9 @@
 class InventoryView(Container):
     MIN_UPDOWN_WIDTH = 16
 
-    def __init__(self, rect, gd, screen):
+    def __init__(self, pos, gd, size, screen):
         self.bsize = gd.constants.button_size
-        super(InventoryView, self).__init__(rect, gd)
+        super(InventoryView, self).__init__(pos, gd, size)
         self.screen = screen
         self.game = screen.game
 
@@ -80,22 +81,21 @@
 
         self.updown_width = self.rect.width - slots * self.bsize
         ud_left = self.rect.right - self.updown_width
-        self.up_button = self.add(UpButton(Rect(
-                    (ud_left, self.rect.top),
-                    (self.updown_width, self.rect.height / 2)), gd))
+        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(Rect(
-                    (ud_left, self.rect.top + self.rect.height / 2),
-                    (self.updown_width, self.rect.height / 2)), gd))
+        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):
-        rect = Rect((self.rect.left + slot * self.bsize, self.rect.top),
-                    (self.bsize, self.rect.height))
-        return InventorySlot(rect, self.gd)
+        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)
@@ -138,8 +138,8 @@
     DETAIL_BORDER = 4
     DETAIL_BORDER_COLOR = Color("black")
 
-    def __init__(self, rect, gd, scene, screen, is_detail=False):
-        super(SceneWidget, self).__init__(rect, gd)
+    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
@@ -150,6 +150,7 @@
         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)
@@ -194,35 +195,32 @@
 
 
 class ToolBar(Container):
-    def __init__(self, rect, gd, screen):
+    def __init__(self, pos, gd, size, screen):
         self.screen = screen
-        button_size = gd.constants.button_size
 
-        if not isinstance(rect, Rect):
-            rect = Rect(rect, (gd.constants.scene_size[0], button_size))
-        super(ToolBar, self).__init__(rect, gd)
+        super(ToolBar, self).__init__(pos, gd, size)
 
         self.bg_color = (31, 31, 31)
         self.left = self.rect.left
 
         self.menu_button = self.add_tool(
-            0, TextButton, gd, _("Menu"), fontname=gd.constants.bold_font,
+            None, 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, gd, hand_image)
+            None, ImageButtonWidget, hand_image)
         self.hand_button.add_callback(MOUSEBUTTONDOWN, self.hand_callback)
 
         self.inventory = self.add_tool(
-            self.rect.width - self.left, InventoryView, gd, screen)
+            self.rect.width - self.left, InventoryView, screen=screen)
 
     def add_tool(self, width, cls, *args, **kw):
-        rect = (self.left, self.rect.top)
+        pos = (self.left, self.rect.top)
         if width is not None:
-            rect = Rect(rect, (width, self.rect.height))
-        tool = cls(rect, *args, **kw)
+            kw['size'] = (width, self.rect.height)
+        tool = cls(pos, self.gd, *args, **kw)
         self.add(tool)
         tool.do_prepare()
         self.left += tool.rect.width
@@ -278,18 +276,19 @@
         self.game = self.create_initial_state(game_state)
 
         self.screen_modal = self.container.add(
-            ModalStackContainer(self.container.rect.copy(), self.gd))
+            ModalStackContainer(self.container.pos, self.gd,
+                                self.container.size))
         self.inner_container = self.screen_modal.add(
-            Container(self.container.rect.copy(), self.gd))
+            Container(self.container.pos, self.gd, self.container.size))
 
         toolbar_height = self.gd.constants.button_size
-        rect = Rect(0, 0, self.surface_size[0],
-                    self.surface_size[1] - toolbar_height)
 
         self.scene_modal = self.inner_container.add(
-            ModalStackContainer(rect, self.gd))
+            ModalStackContainer((0, 0), self.gd,
+                (self.surface_size[0], self.surface_size[1] - toolbar_height)))
         self.toolbar = self.inner_container.add(
-            ToolBar((0, rect.height), self.gd, self))
+            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
@@ -315,12 +314,15 @@
         self._add_scene(self.game.detail_views[detail_name], True)
 
     def _add_scene(self, scene, detail=False):
-        rect = self.scene_modal.rect.copy()
+        pos = self.scene_modal.rect.topleft
+        size = self.scene_modal.rect.size
         if detail:
-            rect = Rect((0, 0), scene.get_detail_size())
-            rect.center = self.scene_modal.rect.center
+            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(rect, self.gd, scene, self, detail))
+        self.scene_modal.add(SceneWidget(pos, self.gd, size, scene, self,
+                                         detail))
         self.handle_result(scene.enter())
 
     def close_detail(self, detail=None):
@@ -354,10 +356,11 @@
         self.show_queued_widget()
 
     def show_message(self, message):
-        rect = Rect((0, 0), (1, 1))
         max_width = self.gd.constants.screen[0] - 100
-        widget = WrappedTextLabel(rect, self.gd, message, max_width=max_width)
+        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)
 
--- a/pyntnclick/menuscreen.py	Sun Jan 27 14:50:33 2013 +0200
+++ b/pyntnclick/menuscreen.py	Sun Jan 27 14:52:16 2013 +0200
@@ -77,14 +77,14 @@
         self._quit_button = self.make_quit_button()
         self._quit_button.add_callback('clicked', self.quit)
 
-    def make_text_button(self, rect, text):
-        widget = TextButton(rect, self.gd, text)
+    def make_text_button(self, pos, text):
+        widget = TextButton(pos, self.gd, text)
         self.container.add(widget)
         return widget
 
-    def make_image_button(self, rect, image_name):
+    def make_image_button(self, pos, image_name):
         image = self.resource.get_image(image_name)
-        widget = ImageButtonWidget(rect, self.gd, image)
+        widget = ImageButtonWidget(pos, self.gd, image)
         self.container.add(widget)
         return widget
 
--- a/pyntnclick/state.py	Sun Jan 27 14:50:33 2013 +0200
+++ b/pyntnclick/state.py	Sun Jan 27 14:52:16 2013 +0200
@@ -321,6 +321,7 @@
             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
 
--- a/pyntnclick/widgets/base.py	Sun Jan 27 14:50:33 2013 +0200
+++ b/pyntnclick/widgets/base.py	Sun Jan 27 14:52:16 2013 +0200
@@ -12,12 +12,12 @@
 
     highlight_cursor = False
 
-    def __init__(self, rect, gd):
-        if not isinstance(rect, pygame.Rect):
-            rect = pygame.Rect(rect, (0, 0))
-        self.rect = rect
+    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
@@ -103,10 +103,8 @@
 
 class Container(Widget):
 
-    def __init__(self, rect, gd):
-        if rect is None:
-            rect = pygame.Rect(0, 0, 0, 0)
-        super(Container, self).__init__(rect, gd)
+    def __init__(self, pos, gd, size=None):
+        super(Container, self).__init__(pos, gd, size)
         self.children = []
 
     def event(self, ev):
@@ -134,7 +132,8 @@
         widget.set_parent(self)
         widget.prepare()
         self.children.append(widget)
-        self.rect = self.rect.union(widget.rect)
+        if not self.size:
+            self.rect = self.rect.union(widget.rect)
         return widget
 
     def remove(self, widget):
@@ -153,8 +152,8 @@
 
 class ModalStackContainer(Container):
 
-    def __init__(self, rect, gd, obscure_color=None):
-        super(ModalStackContainer, self).__init__(rect, gd)
+    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)
@@ -190,27 +189,13 @@
             child.draw(surface)
 
 
-class GridContainer(Container):
-    """Hacky container that only supports grids, won't work with Container
-    children, or modal children.
-    """
-
-    def __init__(self, width, rect=None):
-        super(GridContainer, self).__init__(rect)
-        self.width = width
-
-    def add(self, widget):
-        assert not isinstance(widget, Container)
-        assert not widget.modal
-        super(GridContainer, self).add(widget)
-
-
 class Box(Container):
     """A container that draws a filled background with a border"""
     padding = 4
 
     def draw(self, surface):
         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
@@ -236,17 +221,13 @@
     "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, widget.gd)
+        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 set_parent(self, parent):
-        super(ModalWrapper, self).set_parent(parent)
-        if parent:
-            self.rect = self.parent.rect
-
     def close(self, ev, widget):
         if self.parent:
             self.parent.remove(self)
@@ -258,11 +239,11 @@
 class Image(Widget):
     """Basic widget that draws an image, with an associated rect"""
 
-    def __init__(self, rect, gd, image):
-        super(Image, self).__init__(rect, gd)
+    def __init__(self, pos, gd, image, size=None):
+        super(Image, self).__init__(pos, gd, size)
         self.image = image
-        self.rect.width = image.get_rect().width
-        self.rect.height = image.get_rect().height
+        if not size:
+            self.rect.size = image.get_rect().size
         self.visible = True
 
     def draw(self, surface):
@@ -274,8 +255,8 @@
 class TranslucentImage(Image):
     """Image that can also be translucent"""
 
-    def __init__(self, rect, gd, image):
-        super(TranslucentImage, self).__init__(rect, gd, image)
+    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()
--- a/pyntnclick/widgets/filechooser.py	Sun Jan 27 14:50:33 2013 +0200
+++ b/pyntnclick/widgets/filechooser.py	Sun Jan 27 14:52:16 2013 +0200
@@ -9,9 +9,9 @@
 
 class FileChooser(Box):
 
-    def __init__(self, rect, gd, curdir, ok_callback,
+    def __init__(self, pos, gd, size, curdir, ok_callback,
             page_length=12, padding=2):
-        super(FileChooser, self).__init__(rect, gd)
+        super(FileChooser, self).__init__(pos, gd, size)
         self.page_length = page_length
         self.page = 0
         self.ok_callback = ok_callback
@@ -73,9 +73,9 @@
         top = self.rect.top + self.padding
         left = self.rect.left + self.padding
         # Add current directory at the top
-        widget = LabelWidget((0, 0), self.gd, self.curdir[-30:], color='black')
+        widget = LabelWidget((left, top), self.gd, self.curdir[-30:],
+                             color='black')
         widget.do_prepare()
-        widget.rect.topleft = (left, top)
         self.add(widget)
         upbut = TextButton((left + 2 * self.padding + widget.rect.width, top),
                 self.gd, u'\N{LEFTWARDS ARROW WITH HOOK}Back one level')
--- a/pyntnclick/widgets/game.py	Sun Jan 27 14:50:33 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-"""Display the game area."""
-
-from pygame.rect import Rect
-
-from pyntnclick.widgets.base import Widget
-from pyntnclick.engine import FlipArrowsEvent
-
-
-class GameWidget(Widget):
-    def __init__(self, world, offset=(0, 0)):
-        self.world = world
-        rect = Rect(offset, world.get_size())
-        super(GameWidget, self).__init__(rect)
-        self.add_callback(FlipArrowsEvent, self.flip_arrows)
-
-    def flip_arrows(self, ev, widget):
-        self.world.level.flip_arrows()
-
-    def draw(self, surface):
-        self.world.update()
-        self.world.draw(surface)
-
-    def restart(self):
-        self.world.restart()
--- a/pyntnclick/widgets/imagebutton.py	Sun Jan 27 14:50:33 2013 +0200
+++ b/pyntnclick/widgets/imagebutton.py	Sun Jan 27 14:52:16 2013 +0200
@@ -1,15 +1,13 @@
-import pygame
-
 from pyntnclick.widgets.base import Button
 
 
 class ImageButtonWidget(Button):
     """An image that is also a button. Whatever next?"""
 
-    def __init__(self, rect, gd, image):
-        if not isinstance(rect, pygame.Rect):
-            rect = pygame.Rect(rect, image.get_size())
-        super(ImageButtonWidget, self).__init__(rect, gd)
+    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
         self.visible = True
 
--- a/pyntnclick/widgets/listbox.py	Sun Jan 27 14:50:33 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-from pyntnclick.widgets.base import Box
-from pyntnclick.widgets.toollist import ToolListWidget
-from pyntnclick.widgets.text import TextWidget, TextButton
-
-
-class ListBox(Box):
-
-    def __init__(self, rect, gd, text, widget_list, page_length=8):
-        super(ListBox, self).__init__(rect, gd)
-        self.message = TextWidget(rect, text)
-        self.toolbar = ToolListWidget(rect, widget_list, page_length)
-        self.modal = True
-
-    def prepare(self):
-        width = max(self.toolbar.rect.width, self.message.rect.width)
-        if width > self.message.rect.width:
-            message_pos = (self.rect.left + width / 2
-                    - self.message.rect.width / 2, self.rect.top)
-        else:
-            message_pos = (self.rect.left, self.rect.top + 5)
-        tool_pos = (self.rect.left,
-                self.rect.top + self.message.rect.height + 2)
-        self.message.rect.topleft = message_pos
-        self.toolbar.rect.topleft = tool_pos
-        self.toolbar.fill_page()  # Fix alignment
-        self.add(self.message)
-        self.add(self.toolbar)
-        self.ok_button = ok_button = TextButton((0, 0), 'OK')
-        ok_pos = (self.rect.left + width / 2 - ok_button.rect.width / 2,
-                tool_pos[1] + 2 + self.toolbar.rect.height)
-        ok_button.rect.topleft = ok_pos
-        ok_button.add_callback('clicked', self.close)
-        self.add(ok_button)
-        self.rect.height += 5
-
-    def close(self, ev, widget):
-        if hasattr(self.parent, 'paused'):
-            self.parent.paused = False
-        self.parent.remove(self)
-        return True
--- a/pyntnclick/widgets/messagebox.py	Sun Jan 27 14:50:33 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-from pyntnclick.constants import FONT_SIZE
-from pyntnclick.widgets.base import Box
-from pyntnclick.widgets.text import TextWidget, TextButton
-
-
-class MessageBox(Box):
-
-    def __init__(self, rect, gd, text, post_callback=None, color='red',
-            fontsize=FONT_SIZE):
-        super(MessageBox, self).__init__(rect, gd)
-        self.text = text
-        self.font_size = fontsize
-        self.post_callback = post_callback
-        self.color = color
-        self.modal = True
-
-    def prepare(self):
-        cont = TextWidget((0, 0), "Press [OK] or Enter to continue",
-                fontsize=self.font_size)
-        widgets = []
-        width = cont.rect.width
-        for line in self.text.split('\n'):
-            message = TextWidget((0, 0), line, color=self.color,
-                    fontsize=self.font_size)
-            widgets.append(message)
-            width = max(width, message.rect.width)
-        widgets.append(cont)
-        top = self.rect.top + 10
-        left = self.rect.left + 5
-        for widget in widgets:
-            pos = (left + width / 2 - widget.rect.width / 2, top)
-            widget.rect.topleft = pos
-            top += widget.rect.height + 5
-            self.add(widget)
-        self.ok_button = ok_button = TextButton((0, 0), 'OK')
-        ok_pos = (self.rect.left + 5 + width / 2 - ok_button.rect.width / 2,
-                top + 5)
-        ok_button.rect.topleft = ok_pos
-        ok_button.add_callback('clicked', self.close)
-        self.add(ok_button)
-        self.rect.height += 5
-
-    def close(self, ev, widget):
-        if hasattr(self.parent, 'paused'):
-            self.parent.paused = False
-        self.parent.remove(self)
-        if self.post_callback:
-            self.post_callback()
-        if getattr(self, 'parent_modal', False):
-            self.parent.modal = True
--- a/pyntnclick/widgets/overlay.py	Sun Jan 27 14:50:33 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-from pyntnclick.widgets.base import Button
-
-
-class OverlayButton(Button):
-    """A non-visiable clickable area, that causes an overlay to be
-    displayed. Doesn't really understand this focus thing."""
-
-    def __init__(self, rect, gd, image):
-        self.image = image
-        super(OverlayButton, self).__init__(rect, gd)
-
-    def draw(self, surface):
-        if not self.disabled:
-            surface.blit(self.image, surface.get_rect())
--- a/pyntnclick/widgets/text.py	Sun Jan 27 14:50:33 2013 +0200
+++ b/pyntnclick/widgets/text.py	Sun Jan 27 14:52:16 2013 +0200
@@ -7,9 +7,9 @@
 
 
 class TextWidget(Widget):
-    def __init__(self, rect, gd, text, fontname=None, fontsize=None,
+    def __init__(self, pos, gd, text, size=None, fontname=None, fontsize=None,
                  color=None):
-        super(TextWidget, self).__init__(rect, gd)
+        super(TextWidget, self).__init__(pos, gd, size)
         self.text = text
         constants = self.gd.constants
         self.fontname = fontname or constants.font
@@ -22,9 +22,8 @@
         self.color = convert_color(self.color)
         self.surface = self.font.render(self.text, True, self.color)
         self.text_rect = self.surface.get_rect()
-        width, height = self.surface.get_rect().size
-        self.rect.width = max(self.rect.width, width)
-        self.rect.height = max(self.rect.height, height)
+        if not self.size:
+            self.rect.size = self.text_rect.size
 
     def draw(self, surface):
         if self.visible:
@@ -33,7 +32,7 @@
 
 
 class LabelWidget(TextWidget):
-    def __init__(self, rect, gd, *args, **kwargs):
+    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)
@@ -41,12 +40,13 @@
                 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__(rect, gd, *args, **kwargs)
+        super(LabelWidget, self).__init__(pos, gd, *args, **kwargs)
 
     def prepare(self):
         super(LabelWidget, self).prepare()
-        self.rect.width += 2 * self.padding
-        self.rect.height += 2 * self.padding
+        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)
@@ -64,7 +64,7 @@
 
 
 class TextButton(Button, TextWidget):
-    def __init__(self, rect, gd, *args, **kwargs):
+    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)
@@ -76,7 +76,7 @@
         self.bg_color = convert_color(
                 kwargs.pop('bg_color', constants.button_bg_color))
 
-        super(TextButton, self).__init__(rect, gd, *args, **kwargs)
+        super(TextButton, self).__init__(pos, gd, *args, **kwargs)
 
     def prepare(self):
         super(TextButton, self).prepare()
@@ -86,8 +86,9 @@
 
         width = text_rect.width + self.padding * 2
         height = text_rect.height + self.padding * 2
-        self.rect.width = max(self.rect.width, width)
-        self.rect.height = max(self.rect.height, height)
+        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 = (
@@ -106,11 +107,11 @@
 class WrappedTextLabel(LabelWidget):
     """A Label Widget that wraps the text to a given maximum width"""
 
-    def __init__(self, rect, gd, *args, **kwargs):
+    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__(rect, gd, *args, **kwargs)
+        super(WrappedTextLabel, self).__init__(pos, gd, *args, **kwargs)
 
     def prepare(self):
         if self._wrap_width is None:
@@ -129,8 +130,9 @@
             self._text_lines = wrap(self.text, self._wrap_width)
             self._render()
             width, height = self.surface.get_rect().size
-        self.rect.width = max(self.rect.width, width)
-        self.rect.height = max(self.rect.height, height)
+        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,
--- a/pyntnclick/widgets/toollist.py	Sun Jan 27 14:50:33 2013 +0200
+++ b/pyntnclick/widgets/toollist.py	Sun Jan 27 14:52:16 2013 +0200
@@ -5,14 +5,14 @@
 class ToolListWidget(Container):
     """List of other widgets, with some paging trickery"""
 
-    def __init__(self, rect, gd, widget_list, page_length,
+    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__(rect, gd)
+        super(ToolListWidget, self).__init__(pos, gd, size)
         self.prev_but = None
         self.next_but = None