changeset 324:3476e8f3b100

Fixed mouse and cursor handling.
author Jeremy Thurgood <firxen@gmail.com>
date Sat, 28 Aug 2010 13:30:44 +0200
parents 0630a37cb371
children 05b5723aa11b
files gamelib/cursor.py gamelib/gamescreen.py gamelib/state.py gamelib/widgets.py
diffstat 4 files changed, 68 insertions(+), 60 deletions(-) [+]
line wrap: on
line diff
--- a/gamelib/cursor.py	Sat Aug 28 13:10:55 2010 +0200
+++ b/gamelib/cursor.py	Sat Aug 28 13:30:44 2010 +0200
@@ -57,11 +57,11 @@
     """Mix-in widget to ensure that mouse_move is propogated to parents"""
 
     cursor = HAND
+    _cursor_group = RenderUpdates()
+    _loaded_cursor = None
 
     def __init__(self, screen, *args, **kwargs):
         Widget.__init__(self, *args, **kwargs)
-        self._cursor_group = RenderUpdates()
-        self._loaded_cursor = None
         self.screen = screen
 
     def enter_screen(self):
@@ -70,24 +70,13 @@
     def leave_screen(self):
         pygame.mouse.set_visible(1)
 
-    def draw_all(self, _surface):
-        Widget.draw_all(self, _surface)
-        item = self.screen.state.tool
-        if item is None:
-            self.set_cursor(HAND)
-        else:
-            self.set_cursor(item.CURSOR)
-        surface = self.get_root().surface
-        if self.cursor != self._loaded_cursor:
-            self._loaded_cursor = self.cursor
-            if self.cursor is None:
-                pygame.mouse.set_visible(1)
-                self._cursor_group.empty()
-            else:
-                pygame.mouse.set_visible(0)
-                self.cursor.load()
-                self._cursor_group.empty()
-                self._cursor_group.add(self.cursor)
+    def draw_all(self, surface):
+        Widget.draw_all(self, surface)
+        self.draw_cursor(self.get_root().surface)
+
+    def draw_cursor(self, surface):
+        self.set_cursor(self.screen.state.tool)
+        self.cursor.set_highlight(self.cursor_highlight())
         if self.cursor is not None:
             self._cursor_group.update()
             self._cursor_group.draw(surface)
@@ -95,8 +84,27 @@
     def mouse_delta(self, event):
         self.invalidate()
 
-    def set_cursor(self, cursor):
-        CursorWidget.cursor = cursor
+    @classmethod
+    def set_cursor(cls, item):
+        if item is None:
+            cls.cursor = HAND
+        else:
+            cls.cursor = item.CURSOR
+        if cls.cursor != cls._loaded_cursor:
+            cls._loaded_cursor = cls.cursor
+            if cls.cursor is None:
+                pygame.mouse.set_visible(1)
+                cls._cursor_group.empty()
+            else:
+                pygame.mouse.set_visible(0)
+                cls.cursor.load()
+                cls._cursor_group.empty()
+                cls._cursor_group.add(cls.cursor)
 
-    def cursor_highlight(self, enable):
-        self.cursor.set_highlight(enable)
+    def cursor_highlight(self):
+        if self.screen.state.highlight_override:
+            return True
+        current_thing = self.screen.state.current_thing
+        if current_thing:
+            return current_thing.is_interactive()
+        return False
--- a/gamelib/gamescreen.py	Sat Aug 28 13:10:55 2010 +0200
+++ b/gamelib/gamescreen.py	Sat Aug 28 13:30:44 2010 +0200
@@ -85,14 +85,15 @@
         handle_result(result, self)
 
     def mouse_move(self, event):
+        self.state.highlight_override = False
         if not self.subwidgets:
             self._mouse_move(event.pos)
 
     def _mouse_move(self, pos):
-        self.state.mouse_move(pos, self.screen)
+        self.state.highlight_override = False
+        self.state.mouse_move(pos)
 
     def show_message(self, message, style=None):
-        self.parent.cursor_highlight(False)
         # Display the message as a modal dialog
         MessageDialog(self.screen, message, 60, style=style).present()
         # queue a redraw to show updated state
@@ -108,7 +109,6 @@
         self.detail.set_image_rect(Rect(0, 0, w, h))
         self.add_centered(self.detail)
         self.state.do_enter_detail()
-        self.parent.cursor_highlight(False)
 
     def clear_detail(self):
         """Hide the detail view"""
@@ -153,7 +153,8 @@
         self._mouse_move(event.pos)
 
     def _mouse_move(self, pos):
-        self.state.mouse_move_detail(self.global_to_local(pos), self.screen)
+        self.state.highlight_override = False
+        self.state.mouse_move_detail(self.global_to_local(pos))
 
     def show_message(self, message, style=None):
         self.parent.show_message(message, style)
@@ -227,8 +228,3 @@
     def begin_frame(self):
         if self.running:
             self.state_widget.animate()
-
-    def mouse_delta(self, event):
-        CursorWidget.mouse_delta(self, event)
-        if not self.state_widget.rect.collidepoint(event.pos):
-            self.cursor_highlight(False)
--- a/gamelib/state.py	Sat Aug 28 13:10:55 2010 +0200
+++ b/gamelib/state.py	Sat Aug 28 13:30:44 2010 +0200
@@ -91,6 +91,9 @@
         # scene transion helpers
         self.do_check = None
         self.old_pos = None
+        # current thing
+        self.current_thing = None
+        self.highlight_override = False
 
     def add_scene(self, scene):
         self.scenes[scene.name] = scene
@@ -112,16 +115,17 @@
     def set_current_scene(self, name):
         old_scene = self.current_scene
         self.current_scene = self.scenes[name]
+        self.current_thing = None
         if old_scene and old_scene != self.current_scene:
             self.previous_scene = old_scene
             self.set_do_enter_leave()
 
     def set_current_detail(self, name):
+        self.current_thing = None
         if name is None:
             self.current_detail = None
         else:
             self.current_detail = self.detail_views[name]
-            self.current_scene._current_thing = None
             return self.current_detail.get_detail_size()
 
     def add_inventory_item(self, name):
@@ -187,12 +191,12 @@
             self.do_check = None
             # Fix descriptions, etc.
             if self.old_pos:
-                self.current_scene.mouse_move(self.tool, self.old_pos, screen)
+                self.current_scene.update_current_thing(self.old_pos)
             return self.current_scene.enter()
         raise RuntimeError('invalid do_check value %s' % self.do_check)
 
-    def mouse_move(self, pos, screen):
-        self.current_scene.mouse_move(self.tool, pos, screen)
+    def mouse_move(self, pos):
+        self.current_scene.mouse_move(pos)
         # So we can do sensible things on enter and leave
         self.old_pos = pos
 
@@ -200,8 +204,8 @@
         """Flag that we need to run the enter loop"""
         self.do_check = constants.LEAVE
 
-    def mouse_move_detail(self, pos, screen):
-        self.current_detail.mouse_move(self.tool, pos, screen)
+    def mouse_move_detail(self, pos):
+        self.current_detail.mouse_move(pos)
 
 
 class StatefulGizmo(object):
@@ -251,7 +255,6 @@
             self._background = get_image(self.FOLDER, self.BACKGROUND)
         else:
             self._background = None
-        self._current_thing = None
 
     def add_item(self, item):
         self.state.add_item(item)
@@ -265,7 +268,8 @@
         self.leave()
 
     def _get_description(self):
-        text = self._current_thing and self._current_thing.get_description()
+        text = (self.state.current_thing and
+                self.state.current_thing.get_description())
         if text is None:
             return None
         label = BoomLabel(text)
@@ -305,8 +309,8 @@
 
         Returns a Result object to provide feedback to the player.
         """
-        if self._current_thing is not None:
-            return self._current_thing.interact(item)
+        if self.state.current_thing is not None:
+            return self.state.current_thing.interact(item)
 
     def animate(self):
         """Animate all the things in the scene.
@@ -324,24 +328,23 @@
     def leave(self):
         return None
 
-    def mouse_move(self, item, pos, screen):
+    def update_current_thing(self, pos):
+        if self.state.current_thing is not None:
+            if not self.state.current_thing.contains(pos):
+                self.state.current_thing.leave()
+                self.state.current_thing = None
+        for thing in self.things.itervalues():
+            if thing.contains(pos):
+                thing.enter(self.state.tool)
+                self.state.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.
         """
-        if self._current_thing is not None:
-            if self._current_thing.contains(pos):
-                screen.cursor_highlight(self._current_thing.is_interactive())
-                return
-            else:
-                self._current_thing.leave()
-                self._current_thing = None
-        for thing in self.things.itervalues():
-            if thing.contains(pos):
-                thing.enter(item)
-                self._current_thing = thing
-                break
-        screen.cursor_highlight(self._current_thing is not None)
+        self.update_current_thing(pos)
 
     def get_detail_size(self):
         return self._background.get_size()
--- a/gamelib/widgets.py	Sat Aug 28 13:10:55 2010 +0200
+++ b/gamelib/widgets.py	Sat Aug 28 13:30:44 2010 +0200
@@ -49,9 +49,7 @@
         self.screen.state_widget.mouse_move(event)
 
     def mouse_move(self, event):
-        pos = self.parent.global_to_local(event.pos)
-        if self.rect.collidepoint(pos):
-            self.screen.cursor_highlight(True)
+        self.screen.state.highlight_override = True
 
 
 class MessageDialog(BoomLabel, CursorWidget):
@@ -83,3 +81,6 @@
 
     def mouse_down(self, event):
         self.dismiss()
+
+    def cursor_highlight(self):
+        return False