NotQuiteParadise2

Source code for nqp.ui_elements.generic.ui_tooltip

from __future__ import annotations

from typing import TYPE_CHECKING

import pygame

from nqp.core.constants import FontType, GAP_SIZE, WindowType
from nqp.ui_elements.generic.ui_frame import UIFrame
from nqp.ui_elements.generic.ui_window import UIWindow

if TYPE_CHECKING:
    from typing import Dict, List, Tuple

    from nqp.core.definitions import UIContainerLike
    from nqp.core.game import Game


__all__ = ["UITooltip"]


[docs]class UITooltip(UIWindow): """ A UIWindow subclass for showing specific information about a hovered item. """
[docs] def __init__( self, game: Game, pos: pygame.Vector2, tooltip_key: str | None = None, tooltip_content: Tuple[str, str, str] | None = None, ): """ Needs either tooltip_key or tooltip_content. tooltip_key takes precedent over tooltip_content, if both are provided only the key is used. """ super().__init__(game, WindowType.BASIC, pos, pygame.Vector2(0, 0), [], True) self.secondary_tooltips: None | UIWindow = None self.max_width: int = 100 # get the content from either param if tooltip_key is not None: content = self._get_content(tooltip_key) if content is not None: title, text, image_name = content self._build_self(title, text, image_name) elif tooltip_content is not None: title, text, image_name = tooltip_content self._build_self(title, text, image_name)
[docs] def update(self, delta_time: float): super().update(delta_time)
[docs] def draw(self, surface: pygame.Surface): super().draw(surface) if self.secondary_tooltips: self.secondary_tooltips.draw(surface)
def _get_content(self, tooltip_key: str) -> Tuple[str, str, str] | None: """ Get the content from the tooltip data, using the key. Returns None if key not found. """ try: title = self._game.data.tooltips[tooltip_key]["title"] text = self._game.data.tooltips[tooltip_key]["text"] image_name = self._game.data.tooltips[tooltip_key]["image"] return title, text, image_name except KeyError: return def _build_self(self, title: str, text: str, image_name: str): """ Build primary and secondary tooltips. Also recalcs size of self and rebuilds the window surface to align to the new size. """ text, keys = self._parse_text(text) pos = pygame.Vector2(self.pos.x + GAP_SIZE, self.pos.y + GAP_SIZE) frames = self._build_frames(title, text, image_name, pos) self._elements = self._elements + frames # need to recalc size and rebuild window to match self._recalculate_size() self._window_surface = self._build_window_surface() # build secondary tooltips pos = pygame.Vector2(self.pos.x + self.width + GAP_SIZE, self.pos.y + GAP_SIZE) secondary_frames = [] for key in keys: title, text, image_name = self._get_content(key) text, keys = self._parse_text(text) frames = self._build_frames(title, text, image_name, pos) secondary_frames = secondary_frames + frames # increment pos last_frame = frames[-1] pos = pygame.Vector2(pos.x, last_frame.pos.y + last_frame.height + 1) # +1 avoid overlap # add secondary frames to a window if secondary_frames: # recalc size height = 0 width = 0 for frame in secondary_frames: height += frame.height + 1 if frame.width > width: width = frame.width # add gap for whitespace width += GAP_SIZE height += GAP_SIZE * 2 pos = pygame.Vector2(self.pos.x + self.width + 1, self.pos.y) # +1 avoid overlap # create window, not tooltip, as we've already done all the work and we dont want recursive tooltips self.secondary_tooltips = UIWindow( self._game, self._window_type, pos, pygame.Vector2(width, height), secondary_frames, True ) @staticmethod def _parse_text(text: str) -> Tuple[str, List[str]]: """ Return text without tags and a list of any keys for secondary tooltips. """ # check for secondary tags start_indices = [i for i, char in enumerate(text) if char == "<"] end_indices = [i for i, char in enumerate(text) if char == ">"] secondary_tooltip_keys = [] # confirm results are as expected if len(start_indices) != 0 and len(start_indices) == len(end_indices): # loop indices, remove tags and keep strings in tags for getting secondary tooltips for i, index in enumerate(start_indices): end = end_indices[i] secondary_tooltip_keys.append(text[index + 1 : end]) # remove tags from text text = text.replace("<", "") text = text.replace(">", "") return text, secondary_tooltip_keys def _recalculate_size(self): """ Recalculate the size of the tooltip based on the the elements. """ height = 0 width = 0 for frame in self._elements: height += frame.height + 1 # account for overlap offset # get biggest width if frame.width > width: width = frame.width # add gap for whitespace width += GAP_SIZE height += GAP_SIZE * 2 self.size = pygame.Vector2(width, height) def _build_frames(self, title: str, text: str, image_name: str, pos: pygame.Vector2) -> List[UIFrame]: """ Build the various frames that make up the tooltip """ frames = [] # title frame font = self._game.visual.create_font(FontType.POSITIVE, title) if image_name: image = self._game.visual.get_image(image_name) frame = UIFrame(self._game, pos, font, image=image) else: frame = UIFrame(self._game, pos, font) frames.append(frame) height = frame.height # content frame font = self._game.visual.create_font(FontType.DEFAULT, text) pos = pygame.Vector2(pos.x, pos.y + frame.height + 1) # +1 avoid overlap frame = UIFrame(self._game, pos, font, max_width=self.max_width) frames.append(frame) height += frame.height return frames