Source code for scripts.engine.core.ui

from __future__ import annotations

import logging
import os
from typing import TYPE_CHECKING

import pygame
from pygame_gui import UIManager

from scripts.engine.core import utility
from scripts.engine.internal import debug, library
from scripts.engine.internal.constant import ASSET_PATH, DATA_PATH, UIElement
from scripts.engine.widgets.screen_message import ScreenMessage

if TYPE_CHECKING:
    from typing import Dict, Optional, Tuple, TYPE_CHECKING, Union

    from scripts.engine.widgets.panel import Panel
    from scripts.engine.widgets.window import Window

__all__ = ["ui"]


[docs]class UI: """ Manage the UI, such as windows, resource bars etc """
[docs] def __init__(self): self.debug_font = None # first action needs to be to init pygame. pygame.init() pygame.font.init() # get config info base_window_data = library.VIDEO_CONFIG.base_window desired_window_data = library.VIDEO_CONFIG.desired_window # pull out to reduce use of accessor base_width = base_window_data.width base_height = base_window_data.height desired_width = desired_window_data.width desired_height = desired_window_data.height ## set the display # base values self.base_width = base_width self.base_height = base_height self._main_surface: pygame.Surface = pygame.Surface((base_width, base_height), pygame.SRCALPHA) # values to scale to self.desired_width = desired_width self.desired_height = desired_height self._window: pygame.display = pygame.display.set_mode((desired_width, desired_height)) # now that the display is configured init the pygame_gui self._gui = UIManager((desired_width, desired_height), DATA_PATH / "ui/themes.json") # elements info self._elements: Dict[UIElement, Union[Panel, Window]] = {} # dict of all init'd ui_manager elements # process config self._load_display_config() self._load_fonts() logging.info(f"UIManager initialised.")
################ CORE METHODS ########################
[docs] def update(self, time_delta: float): """ Update all ui_manager elements """ self._gui.update(time_delta)
[docs] def process_ui_events(self, event): """ Pass event to the gui manager. """ self._gui.process_events(event)
[docs] def draw(self): """ Draw the UI. """ # draw everything self._draw_debug() self._gui.draw_ui(self._window) pygame.display.flip() # make sure to do this as the last drawing element in a frame
def _draw_debug(self): """ Draw debug information, based on visible values in debug. """ values = debug.get_visible_values() y = 10 debug_font = self.debug_font for value in values: surface = debug_font.render(value, False, (255, 255, 255)) self._main_surface.blit(surface, (0, y)) y += 10 ##################### GET ############################
[docs] def get_element(self, element_type: UIElement) -> Union[Panel, Window]: """ Get UI element. """ if element_type in self._elements: return self._elements[element_type] element_name = utility.value_to_member(element_type, UIElement) raise KeyError(f"Tried to get {element_name} ui element but key not found.")
[docs] def get_gui_manager(self) -> UIManager: """ Return the pygame_gui UI Manager """ return self._gui
##################### INIT, LOAD AND CREATE ############################ @staticmethod def _load_display_config(): """ Initialise display settings. """ pygame.display.set_caption("Not Quite Paradise") pygame.display.set_icon(utility.get_image("ui/nqp_icon.png")) def _load_fonts(self): self._gui.add_font_paths("barlow", str(ASSET_PATH / "fonts/Barlow-Light.otf")) self._gui.add_font_paths("cozette", str(ASSET_PATH / "fonts/cozette_bitmap.ttf")) self.debug_font = pygame.font.Font(str(ASSET_PATH / "fonts/Barlow-Light.otf"), 6) fonts = [ {"name": "barlow", "point_size": 12, "style": "regular"}, {"name": "cozette", "point_size": 12, "style": "regular"}, ] self._gui.preload_fonts(fonts)
[docs] def register_element(self, element_type: UIElement, element: Union[Panel, Window]): """ Register the specified UI element. Can be returned with get_element at a later date. If it already exists current instance will be overwritten. """ # if it already exists, log that is being overwritten # N.B. do not use get_element to check as it will create a circular reference if element_type in self._elements: element_name = utility.value_to_member(element_type, UIElement) logging.warning(f"Created new {element_name} ui element, overwriting previous instance.") self._elements[element_type] = element
[docs] def create_screen_message(self, message: str, colour: str = "#531B75", size: int = 4): """ Create a message on the screen. """ text = f"<font face=cozette color={colour} size={size}>{message}</font>" rect = pygame.Rect((self.base_width / 4, self.base_height / 4), (self.base_width / 2, -1)) ScreenMessage(rect, text, self.get_gui_manager())
######################## KILL ###############################################
[docs] def kill_all_elements(self): """ Close and kill the game's UI elements. Helper function to run kill_element on all elements. """ elements = self._elements.copy() for element_type in elements.keys(): self.kill_element(element_type)
[docs] def kill_element(self, element_type: UIElement): """ Remove any reference to the element. """ element = self.get_element(element_type) del self._elements[element_type] element.kill()
################################ QUERIES #################################################################
[docs] def element_is_visible(self, element_type: UIElement) -> bool: """ Check if an element is visible. """ if self.has_element(element_type): element = self.get_element(element_type) return element.visible else: return False
[docs] def element_is_active(self, element_type: UIElement) -> bool: """ Check if an element has been created and is visible """ if element_type in self._elements: return self.element_is_visible(element_type) else: return False
[docs] def has_element(self, element_type: UIElement) -> bool: """ Check if an element exists """ if element_type in self._elements: return True else: return False
################################ UNIVERSAL ACTIONS #############################################
[docs] def set_element_visibility(self, element_type: UIElement, visible: bool) -> bool: """ Set whether the element is visible or not. Returns true if successful, false if element not found. """ if not self.has_element(element_type): return False element = self.get_element(element_type) element.visible = visible element_name = utility.value_to_member(element_type, UIElement) if visible: element.show() logging.debug(f"Showed {element_name} ui element.") else: element.hide() logging.debug(f"Hid {element_name} ui element.") return True
if "GENERATING_SPHINX_DOCS" not in os.environ: # when building in CI these fail ui = UI() else: ui = "" # type: ignore