added tooltips with information about light tools
authoradrianna <adrianna.pinska@gmail.com>
Thu, 15 Sep 2016 22:58:40 +0000 (00:58 +0200)
committeradrianna <adrianna.pinska@gmail.com>
Thu, 15 Sep 2016 22:58:40 +0000 (00:58 +0200)
TODO.txt
tabakrolletjie/lights.py
tabakrolletjie/scenes/day.py
tabakrolletjie/widgets.py

index a38aa5886435b4517403f9dbef006e5c9c7fb766..033052afbbc91c5c99840b74a2ba549860b506b2 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -10,8 +10,8 @@ Features
 * Maybe configure lights in separate json file, to allow reuse of consistent models in multiple levels?
 * Allow going down to zero seeds by buying lights if a turnip is planted
 * Maybe make the mould weaker at the start
-* Display power usage when lights are bought? Also other properties.
-* Maybe also display information next to existing lights (on click?)
+* Display average power usage in light tooltip
+* Maybe also display information next to existing lights -- tooltip?
 * Generally balance the levels better and add more levels
 * Graphical level selection with screenshots
 * Fast forward button for night-time (calculate more steps between redraws; play sounds sped up and with higher pitch)
@@ -49,3 +49,4 @@ Done
 * Different power usage for different lights (this was already done)
 * Different prices for different lights
 * Calculate both from # of colours, speed, beam width, etc.?
+* added tooltips for lights
index 44c93871c805b34b5fc70761e4be500f3b461957..00f4c85b6e6f767fa761f920afc31ba2db6e5fb3 100644 (file)
@@ -142,6 +142,11 @@ def seed_cost(light_config, num_colours):
     cls = BaseLight.find_cls(light_config["type"])
     return cls.BASE_COST + int(cls.find_cost(light_config) / 10) + num_colours
 
+def light_info(light_config):
+    """Generate info about a light to go in the tooltip. """
+    cls = BaseLight.find_cls(light_config["type"])
+    return cls.get_info(light_config)
+
 
 class BaseLight(object):
     """ Common light functionality. """
@@ -216,6 +221,10 @@ class BaseLight(object):
         cost = 5 * config["intensity"]
         return cost
 
+    @classmethod
+    def get_info(cls, config):
+        return ["intensity: %g" % config["intensity"]]
+
     def add(self, space):
         if self.body.space is not None:
             space.remove(self.body, *self.body.shapes)
@@ -382,6 +391,17 @@ class PulsatingLamp(BaseLight):
         cost += 5 * (ir[1] - ir[0])
         return cost
 
+    @classmethod
+    def get_info(cls, config):
+        pr = config.get("pulse_range", cls.DEFAULT_PULSE_RANGE)
+        pv = config.get("pulse_velocity", cls.DEFAULT_PULSE_VELOCITY)
+        ir = config.get("intensity_range", cls.DEFAULT_INTENSITY_RANGE)
+        iv = config.get("intensity_velocity", cls.DEFAULT_INTENSITY_VELOCITY)
+        return [
+            "intensity: %g - %g, velocity %g" % (ir[0], ir[1], iv),
+            "pulse: %d - %d, velocity %g" % (pr[0], pr[1], pv),
+        ]
+
 
 class SpotLight(BaseLight):
 
@@ -417,4 +437,18 @@ class SpotLight(BaseLight):
     def find_cost(cls, config):
         cost = super(SpotLight, cls).find_cost(config)
         cost += config.get("angular_velocity", 0)
+        cost += config["spread"] / 10
+        rl = config["radius_limits"]
+        cost += (rl[1] - rl[0]) / 10
         return cost
+
+    @classmethod
+    def get_info(cls, config):
+        info = super(SpotLight, cls).get_info(config)
+        rl = config["radius_limits"]
+        info.extend([
+            "spread: %d" % config["spread"],
+            "length: %d" % (rl[1] - rl[0]),
+            "angular velocity: %g" % config.get("angular_velocity", 0),
+        ])
+        return info
index 8dd9c7b84add10af9ffbb1187ef1baa8d22f98a1..a43517cd92efa0574515be687539f7cb58c006d2 100644 (file)
@@ -11,7 +11,7 @@ import pymunk.pygame_util
 
 from .base import BaseScene
 from ..battery import BatteryManager
-from ..lights import LightManager, light_fitting_by_type, check_space_for_light, seed_cost
+from ..lights import LightManager, light_fitting_by_type, check_space_for_light, seed_cost, light_info
 from ..infobar import InfoBar
 from ..obstacles import ObstacleManager
 from ..events import SceneChangeEvent
@@ -21,7 +21,7 @@ from ..sound import sound
 from ..transforms import Overlay, Alpha, ColourWedges
 
 from ..constants import SCREEN_SIZE, FONTS, FPS, NIGHT_HOURS_PER_TICK, DEBUG
-from ..widgets import ImageButton
+from ..widgets import ImageButton, Tooltip
 from ..turnip import Turnip, TurnipInvalidPosition
 
 
@@ -159,6 +159,7 @@ class DayScene(BaseScene):
             tool.render(surface)
         for light_tool in self._light_toolbar:
             light_tool.render(surface)
+                
         self._draw_cursor(surface)
         if self._game_over_text:
             for surf, pos in self._game_over_text:
@@ -176,12 +177,15 @@ class DayScene(BaseScene):
             light_tool = ImageButton(
                 "32", light_fitting, transform=ColourWedges(colours=colours),
                 pos=(x, height), name=combo)
-            font = loader.load_font(FONTS["sans"], size=12)
-            tool_cost = font.render("%d" % cost, True, (0, 0, 0))
-            light_tool._img.blit(tool_cost, (16, 12), None)
             
             light_tool.colours = colours
             light_tool.cost = cost
+
+            tooltip_text = ["cost: %d" % cost] + light_info(light_config)
+
+            tooltip = Tooltip(tooltip_text)
+            light_tool.tooltip = tooltip
+            
             self._light_toolbar.append(light_tool)
             x += 40
 
index 4341c703d717be28ae59a4d1a6a16b056ac01061..166cfc0dc84ae88dcd330fc6cdb8cf83f462b112 100644 (file)
@@ -3,12 +3,40 @@
 # There is no implied container / window system (yet)
 
 import pygame.locals as pgl
+import pygame.mouse
+import pygame.surface
 
 from .loader import loader
-from .constants import FONTS
+from .constants import FONTS, COLOURS
 from .transforms import NullTransform, Multiply
 
 
+class Tooltip(object):
+    def __init__(self, textparts, font='sans', size=12, padding=5, distance=10):
+        self._font = loader.load_font(FONTS[font], size=size)
+        self._text = [self._font.render(text, True, COLOURS["white"]) for text in textparts]
+        self._padding = padding
+        self._distance =  distance
+
+    def render(self, surface, tool_pos, tool_width):
+        width = max(t.get_size()[0] for t in self._text) + 2 * self._padding
+        height = sum(t.get_size()[1] for t in self._text) + 2 * self._padding
+
+        tooltip = pygame.surface.Surface(
+            (width, height), pgl.SWSURFACE).convert_alpha()
+        tooltip.fill((0, 0, 0, 172))
+
+        ty = 0
+        for t in self._text:
+            tooltip.blit(t, (self._padding, self._padding + ty), None)
+            ty += self._font.get_height()
+
+        x = tool_pos[0] - width/2 + tool_width/2
+        y = tool_pos[1] - height - self._distance
+
+        surface.blit(tooltip, (x, y), None)
+        
+
 class Button(object):
 
     def __init__(self, size, name=None, pos=None, padding=10):
@@ -17,6 +45,7 @@ class Button(object):
         self.position = pos
         self.name = name
         self.enabled = True
+        self.tooltip = None
 
     def enable(self):
         self.enabled = True
@@ -58,6 +87,20 @@ class Button(object):
                     return True
         return False
 
+    def mouseover(self):
+        if not self.enabled:
+            return False
+        if self._pos is None:
+            # Unplaced buttons can't be moused over
+            return False
+
+        mpos = pygame.mouse.get_pos()
+        
+        if self._min_x < mpos[0] < self._max_x:
+            if self._min_y < mpos[1] < self._max_y:
+                return True
+        return False
+
 
 class SpacerButton(Button):
     """ Add a nothing object which can be used to space other things,
@@ -85,6 +128,8 @@ class TextButton(Button):
     def render(self, surface):
         if self.enabled:
             surface.blit(self._text, self._pos, None)
+            if self.mouseover() and self.tooltip:
+                self.tooltip.render(surface, self._pos, self.get_width())
         else:
             surface.blit(self._disabled_text, self._pos, None)
 
@@ -112,5 +157,7 @@ class ImageButton(Button):
     def render(self, surface):
         if self.enabled:
             surface.blit(self._img, self._pos, None)
+            if self.mouseover() and self.tooltip:
+                self.tooltip.render(surface, self._pos, self.get_width())
         else:
             surface.blit(self._disabled_img, self._pos, None)