changeset 679:fa168b5e2624 pyntnclick

The return of the message dialog (and there was much rejoicing)
author Neil Muller <neil@dip.sun.ac.za>
date Sun, 12 Feb 2012 23:06:44 +0200
parents 36d7f7e9650e
children c9562e24bfed
files pyntnclick/gamescreen.py pyntnclick/state.py pyntnclick/widgets/base.py pyntnclick/widgets/text.py
diffstat 4 files changed, 104 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/pyntnclick/gamescreen.py	Sun Feb 12 21:47:06 2012 +0200
+++ b/pyntnclick/gamescreen.py	Sun Feb 12 23:06:44 2012 +0200
@@ -11,7 +11,7 @@
 from pyntnclick.engine import Screen
 from pyntnclick.state import handle_result
 from pyntnclick.widgets.base import Container, ModalStackContainer
-from pyntnclick.widgets.text import TextButton, LabelWidget
+from pyntnclick.widgets.text import TextButton, ModalWrappedTextLabel
 from pyntnclick.widgets.imagebutton import ImageButtonWidget
 
 # XXX: Need a way to get at the constants.
@@ -151,6 +151,7 @@
         self.detail = DetailWindow(rect, gd, screen)
         self.add_callback(MOUSEBUTTONDOWN, self.mouse_down)
         self.add_callback(MOUSEMOTION, self.mouse_move)
+        self._message_queue = []
 
     def draw(self, surface):
         self.game.current_scene.draw(surface, self)
@@ -170,6 +171,9 @@
         else:
             self.game.current_scene.draw_description(surface)
 
+    def queue_widget(self, widget):
+        self._message_queue.append(widget)
+
     def mouse_down(self, event, widget):
         if self.game.current_detail:
             return self.detail.mouse_down(event, widget)
@@ -188,6 +192,11 @@
         # of what happens
         result = self.game.check_enter_leave(self.screen)
         handle_result(result, self)
+        if self._message_queue:
+            # Only add a message if we're at the top
+            if self.screen.modal_magic.is_top(self.screen.inner_container):
+                widget = self._message_queue.pop(0)
+                self.screen.modal_magic.add(widget)
         if self.game.current_detail:
             self.game.current_detail.animate()
         else:
@@ -200,10 +209,8 @@
         self.game.current_scene.mouse_move(event.pos)
         self.game.old_pos = event.pos
 
-    def show_message(self, message, style=None):
+    def show_message(self, message):
         # Display the message as a modal dialog
-        # self.screen.modal_magic.add(LabelWidget((50, 50), self.gd, message))
-        print message
         # XXX: MessageDialog(self.screen, message, 60, style=style).present()
         # queue a redraw to show updated state
         # XXX: self.invalidate()
@@ -212,6 +219,13 @@
         #    self.subwidgets[0]._mouse_move(mouse.get_pos())
         # else:
         #    self._mouse_move(mouse.get_pos())
+        rect = Rect((0, 0), (1, 1))
+        widget = ModalWrappedTextLabel(rect, self.gd, message,
+                max_width=self.gd.constants.screen[0] - 100)
+        widget.rect.center = self.rect.center
+        # We abuse animate so we can queue multiple results
+        # according
+        self.queue_widget(widget)
 
     def show_detail(self, detail):
         self.clear_detail()
@@ -286,10 +300,9 @@
         self.game.highlight_override = False
         self.game.current_detail.mouse_move(self.global_to_local(pos))
 
-    def show_message(self, message, style=None):
-        # self.parent.show_message(message, style)
+    def show_message(self, message):
+        self.parent.show_message(message)
         # self.invalidate()
-        print message
 
 
 class ToolBar(Container):
--- a/pyntnclick/state.py	Sun Feb 12 21:47:06 2012 +0200
+++ b/pyntnclick/state.py	Sun Feb 12 23:06:44 2012 +0200
@@ -37,7 +37,7 @@
         """Helper function to do the right thing with a result object"""
         self.play_sound(scene_widget)
         if self.message:
-            scene_widget.show_message(self.message, self.style)
+            scene_widget.show_message(self.message)
         if self.detail_view:
             scene_widget.show_detail(self.detail_view)
         if (self.close_detail
--- a/pyntnclick/widgets/base.py	Sun Feb 12 21:47:06 2012 +0200
+++ b/pyntnclick/widgets/base.py	Sun Feb 12 23:06:44 2012 +0200
@@ -139,6 +139,11 @@
         if super(Container, self).event(ev):
             return True
 
+    def is_top(self, widget):
+        if self.children:
+            return self.children[-1] is widget
+        return False
+
     def draw(self, surface):
         obscure = pygame.Surface(self.rect.size, SRCALPHA)
         obscure.fill(self.obscure_color)
--- a/pyntnclick/widgets/text.py	Sun Feb 12 21:47:06 2012 +0200
+++ b/pyntnclick/widgets/text.py	Sun Feb 12 23:06:44 2012 +0200
@@ -1,5 +1,8 @@
+from textwrap import wrap
+
 import pygame
 from pygame.constants import SRCALPHA
+from pygame.locals import MOUSEBUTTONDOWN
 
 from pyntnclick.widgets.base import Widget, Button, convert_color
 
@@ -96,3 +99,78 @@
 
     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, rect, 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)
+        self.prepare()
+
+    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
+        self.rect.width = max(self.rect.width, width)
+        self.rect.height = max(self.rect.height, height)
+
+        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 _render(self):
+        surfaces = []
+        width = 0
+        height = 0
+        for line in self._text_lines:
+            line_surf = self.font.render(line, True, self.color,
+                    self.bg_color)
+            surfaces.append(line_surf)
+            width = max(line_surf.get_rect().width, width)
+            height += line_surf.get_rect().height
+        self.surface = pygame.Surface((width, height))
+        self.surface.fill(self.bg_color)
+        height = 0
+        for line_surf in surfaces:
+            rect = pygame.Rect((0, height), (line_surf.get_rect().size))
+            self.surface.blit(line_surf, rect)
+            height += line_surf.get_rect().height
+
+
+class ModalWrappedTextLabel(WrappedTextLabel):
+    """A WrappedTextLabel that removes itself when a mouse
+       click occurs"""
+    def __init__(self, rect, gd, *args, **kwargs):
+        super(ModalWrappedTextLabel, self).__init__(rect, gd, *args, **kwargs)
+        self.add_callback(MOUSEBUTTONDOWN, self.close)
+
+    def close(self, ev, widget):
+        if self.parent:
+            self.parent.remove(self)
+            return True