# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse # SPDX-License-Identifier: GPL-3.0-or-later import curses from random import randint from typing import List from squirrelbattle.menus import Menu, MainMenu, SettingsMenu from .display import Box, Display from ..enums import KeyValues, GameMode from ..game import Game from ..resources import ResourceManager from ..translations import gettext as _ class MenuDisplay(Display): """ A class to display the menu objects """ menu: Menu position: int def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.menubox = Box(*args, **kwargs) def update_menu(self, menu: Menu) -> None: self.menu = menu # Menu values are printed in pad self.pad = self.newpad(self.trueheight, self.truewidth + 2) def update_pad(self) -> None: for i in range(self.trueheight): self.addstr(self.pad, i, 0, " " + self.values[i]) # set a marker on the selected line self.addstr(self.pad, self.menu.position, 0, " >") def display(self) -> None: cornery = 0 if self.height - 2 >= self.menu.position - 1 \ else self.trueheight - self.height + 2 \ if self.height - 2 >= self.trueheight - self.menu.position else 0 # Menu box self.menubox.refresh(self.y, self.x, self.height, self.width) self.pad.erase() self.update_pad() self.refresh_pad(self.pad, cornery, 0, self.y + 1, self.x + 1, self.height - 2 + self.y, self.width - 2 + self.x) def handle_click(self, y: int, x: int, game: Game) -> None: """ We can select a menu item with the mouse. """ self.menu.position = max(0, min(len(self.menu.values) - 1, y - 1)) game.handle_key_pressed(KeyValues.ENTER) @property def truewidth(self) -> int: return max([len(str(a)) for a in self.values]) @property def trueheight(self) -> int: return len(self.values) @property def preferred_width(self) -> int: return self.truewidth + 6 @property def preferred_height(self) -> int: return self.trueheight + 2 @property def values(self) -> List[str]: return [str(a) for a in self.menu.values] class SettingsMenuDisplay(MenuDisplay): """ A class to display specifically a settingsmenu object """ menu: SettingsMenu def update(self, game: Game) -> None: self.update_menu(game.settings_menu) @property def values(self) -> List[str]: return [_(a[1][1]) + (" : " + ("?" if self.menu.waiting_for_key and a == self.menu.validate() else a[1][0] .replace("\n", "\\n")) if a[1][0] else "") for a in self.menu.values] class MainMenuDisplay(Display): """ A class to display specifically a mainmenu object """ def __init__(self, menu: MainMenu, *args): super().__init__(*args) self.menu = menu with open(ResourceManager.get_asset_path("ascii_art.txt"), "r") as file: self.title = file.read().split("\n") self.pad = self.newpad(max(self.rows, len(self.title) + 30), max(len(self.title[0]) + 5, self.cols)) self.fg_color = curses.COLOR_WHITE self.menudisplay = MenuDisplay(self.screen, self.pack) self.menudisplay.update_menu(self.menu) def display(self) -> None: for i in range(len(self.title)): self.addstr(self.pad, 4 + i, max(self.width // 2 - len(self.title[0]) // 2 - 1, 0), self.title[i], self.fg_color) self.refresh_pad(self.pad, 0, 0, self.y, self.x, self.height + self.y - 1, self.width + self.x - 1) menuwidth = min(self.menudisplay.preferred_width, self.width) menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1 self.menudisplay.refresh( menuy, menux, min(self.menudisplay.preferred_height, self.height - menuy), menuwidth) def update(self, game: Game) -> None: self.menudisplay.update_menu(game.main_menu) def handle_click(self, y: int, x: int, game: Game) -> None: menuwidth = min(self.menudisplay.preferred_width, self.width) menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1 menuheight = min(self.menudisplay.preferred_height, self.height - menuy) if menuy <= y < menuy + menuheight and menux <= x < menux + menuwidth: self.menudisplay.handle_click(y - menuy, x - menux, game) if y <= len(self.title): self.fg_color = randint(0, 1000), randint(0, 1000), randint(0, 1000) class PlayerInventoryDisplay(MenuDisplay): def update(self, game: Game) -> None: self.update_menu(game.inventory_menu) def update_pad(self) -> None: self.menubox.update_title(_("INVENTORY")) for i, item in enumerate(self.menu.values): rep = self.pack[item.name.upper()] selection = f"[{rep}]" if i == self.menu.position \ and (Game.INSTANCE.state == GameMode.INVENTORY or Game.INSTANCE.state == GameMode.STORE and not Game.INSTANCE.is_in_store_menu) else f" {rep} " self.addstr(self.pad, i + 1, 0, selection + " " + item.translated_name.capitalize() + (": " + str(item.price) + " Hazels" if Game.INSTANCE.state == GameMode.STORE else "")) @property def truewidth(self) -> int: return max(1, self.height if hasattr(self, "height") else 10) @property def trueheight(self) -> int: return 2 + super().trueheight def handle_click(self, y: int, x: int, game: Game) -> None: """ We can select a menu item with the mouse. """ self.menu.position = max(0, min(len(self.menu.values) - 1, y - 2)) game.is_in_store_menu = False game.handle_key_pressed(KeyValues.ENTER) class StoreInventoryDisplay(MenuDisplay): def update(self, game: Game) -> None: self.update_menu(game.store_menu) def update_pad(self) -> None: self.menubox.update_title(_("STALL")) for i, item in enumerate(self.menu.values): rep = self.pack[item.name.upper()] selection = f"[{rep}]" if i == self.menu.position \ and Game.INSTANCE.is_in_store_menu else f" {rep} " self.addstr(self.pad, i + 1, 0, selection + " " + item.translated_name.capitalize() + ": " + str(item.price) + " Hazels") @property def truewidth(self) -> int: return max(1, self.height if hasattr(self, "height") else 10) @property def trueheight(self) -> int: return 2 + super().trueheight def handle_click(self, y: int, x: int, game: Game) -> None: """ We can select a menu item with the mouse. """ self.menu.position = max(0, min(len(self.menu.values) - 1, y - 2)) game.is_in_store_menu = True game.handle_key_pressed(KeyValues.ENTER)