Source code for bauiv1lib.creditslist

# Released under the MIT License. See LICENSE for details.
#
"""Provides a window to display game credits."""

from __future__ import annotations

import os
import logging
from typing import TYPE_CHECKING

import bauiv1 as bui

if TYPE_CHECKING:
    from typing import Sequence


[docs] class CreditsListWindow(bui.Window): """Window for displaying game credits.""" def __init__(self, origin_widget: bui.Widget | None = None): # pylint: disable=too-many-locals # pylint: disable=too-many-statements import json bui.set_analytics_screen('Credits Window') # if they provided an origin-widget, scale up from that scale_origin: tuple[float, float] | None if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None transition = 'in_right' assert bui.app.classic is not None uiscale = bui.app.ui_v1.uiscale width = 870 if uiscale is bui.UIScale.SMALL else 670 x_inset = 100 if uiscale is bui.UIScale.SMALL else 0 height = 398 if uiscale is bui.UIScale.SMALL else 500 self._r = 'creditsWindow' super().__init__( root_widget=bui.containerwidget( size=(width, height), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, scale=( 2.0 if uiscale is bui.UIScale.SMALL else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0 ), stack_offset=( (0, -8) if uiscale is bui.UIScale.SMALL else (0, 0) ), ) ) if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL: bui.containerwidget( edit=self._root_widget, on_cancel_call=self._back ) else: btn = bui.buttonwidget( parent=self._root_widget, position=( 40 + x_inset, height - (68 if uiscale is bui.UIScale.SMALL else 62), ), size=(140, 60), scale=0.8, label=bui.Lstr(resource='backText'), button_type='back', on_activate_call=self._back, autoselect=True, ) bui.containerwidget(edit=self._root_widget, cancel_button=btn) bui.buttonwidget( edit=btn, button_type='backSmall', position=( 40 + x_inset, height - (68 if uiscale is bui.UIScale.SMALL else 62) + 5, ), size=(60, 48), label=bui.charstr(bui.SpecialChar.BACK), ) bui.textwidget( parent=self._root_widget, position=(0, height - (59 if uiscale is bui.UIScale.SMALL else 54)), size=(width, 30), text=bui.Lstr( resource=self._r + '.titleText', subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))], ), h_align='center', color=bui.app.ui_v1.title_color, maxwidth=330, v_align='center', ) scroll = bui.scrollwidget( parent=self._root_widget, position=(40 + x_inset, 35), size=(width - (80 + 2 * x_inset), height - 100), capture_arrows=True, ) if bui.app.ui_v1.use_toolbars: bui.widget( edit=scroll, right_widget=bui.get_special_widget('party_button'), ) if uiscale is bui.UIScale.SMALL: bui.widget( edit=scroll, left_widget=bui.get_special_widget('back_button'), ) def _format_names(names2: Sequence[str], inset: float) -> str: sval = '' # measure a series since there's overlaps and stuff.. space_width = ( bui.get_string_width(' ' * 10, suppress_warning=True) / 10.0 ) spacing = 330.0 col1 = inset col2 = col1 + spacing col3 = col2 + spacing line_width = 0.0 nline = '' for name in names2: # move to the next column (or row) and print if line_width > col3: sval += nline + '\n' nline = '' line_width = 0 if line_width > col2: target = col3 elif line_width > col1: target = col2 else: target = col1 spacingstr = ' ' * int((target - line_width) / space_width) nline += spacingstr nline += name line_width = bui.get_string_width(nline, suppress_warning=True) if nline != '': sval += nline + '\n' return sval sound_and_music = bui.Lstr( resource=self._r + '.songCreditText' ).evaluate() sound_and_music = sound_and_music.replace( '${TITLE}', "'William Tell (Trumpet Entry)'" ) sound_and_music = sound_and_music.replace( '${PERFORMER}', 'The Apollo Symphony Orchestra' ) sound_and_music = sound_and_music.replace( '${PERFORMER}', 'The Apollo Symphony Orchestra' ) sound_and_music = sound_and_music.replace( '${COMPOSER}', 'Gioacchino Rossini' ) sound_and_music = sound_and_music.replace('${ARRANGER}', 'Chris Worth') sound_and_music = sound_and_music.replace('${PUBLISHER}', 'BMI') sound_and_music = sound_and_music.replace( '${SOURCE}', 'www.AudioSparx.com' ) spc = ' ' sound_and_music = spc + sound_and_music.replace('\n', '\n' + spc) names = [ 'HubOfTheUniverseProd', 'Jovica', 'LG', 'Leady', 'Percy Duke', 'PhreaKsAccount', 'Pogotron', 'Rock Savage', 'anamorphosis', 'benboncan', 'cdrk', 'chipfork', 'guitarguy1985', 'jascha', 'joedeshon', 'loofa', 'm_O_m', 'mich3d', 'sandyrb', 'shakaharu', 'sirplus', 'stickman', 'thanvannispen', 'virotic', 'zimbot', ] names.sort(key=lambda x: x.lower()) freesound_names = _format_names(names, 90) try: with open( os.path.join( bui.app.env.data_directory, 'ba_data', 'data', 'langdata.json', ), encoding='utf-8', ) as infile: translation_contributors = json.loads(infile.read())[ 'translation_contributors' ] except Exception: logging.exception('Error reading translation contributors.') translation_contributors = [] translation_names = _format_names(translation_contributors, 60) # Need to bake this out and chop it up since we're passing our # 65535 vertex limit for meshes.. # We can remove that limit once we drop support for GL ES2.. :-/ # (or add mesh splitting under the hood) credits_text = ( ' ' + bui.Lstr(resource=self._r + '.codingGraphicsAudioText') .evaluate() .replace('${NAME}', 'Eric Froemling') + '\n' '\n' ' ' + bui.Lstr(resource=self._r + '.additionalAudioArtIdeasText') .evaluate() .replace('${NAME}', 'Raphael Suter') + '\n' '\n' ' ' + bui.Lstr(resource=self._r + '.soundAndMusicText').evaluate() + '\n' '\n' + sound_and_music + '\n' '\n' ' ' + bui.Lstr(resource=self._r + '.publicDomainMusicViaText') .evaluate() .replace('${NAME}', 'Musopen.com') + '\n' ' ' + bui.Lstr(resource=self._r + '.thanksEspeciallyToText') .evaluate() .replace('${NAME}', 'the US Army, Navy, and Marine Bands') + '\n' '\n' ' ' + bui.Lstr(resource=self._r + '.additionalMusicFromText') .evaluate() .replace('${NAME}', 'The YouTube Audio Library') + '\n' '\n' ' ' + bui.Lstr(resource=self._r + '.soundsText') .evaluate() .replace('${SOURCE}', 'Freesound.org') + '\n' '\n' + freesound_names + '\n' '\n' ' ' + bui.Lstr( resource=self._r + '.languageTranslationsText' ).evaluate() + '\n' '\n' + '\n'.join(translation_names.splitlines()[:146]) + '\n'.join(translation_names.splitlines()[146:]) + '\n' '\n' ' Shout Out to Awesome Mods / Modders / Contributors:\n\n' ' BombDash ModPack\n' ' TheMikirog & SoK - BombSquad Joyride Modpack\n' ' Mrmaxmeier - BombSquad-Community-Mod-Manager\n' ' Ritiek Malhotra \n' ' Dliwk\n' ' vishal332008\n' ' itsre3\n' ' Drooopyyy\n' '\n' ' Holiday theme vector art designed by Freepik\n' '\n' ' ' + bui.Lstr(resource=self._r + '.specialThanksText').evaluate() + '\n' '\n' ' Todd, Laura, and Robert Froemling\n' ' ' + bui.Lstr(resource=self._r + '.allMyFamilyText') .evaluate() .replace('\n', '\n ') + '\n' ' ' + bui.Lstr( resource=self._r + '.whoeverInventedCoffeeText' ).evaluate() + '\n' '\n' ' ' + bui.Lstr(resource=self._r + '.legalText').evaluate() + '\n' '\n' ' ' + bui.Lstr(resource=self._r + '.softwareBasedOnText') .evaluate() .replace('${NAME}', 'the Khronos Group') + '\n' '\n' ' ' ' www.ballistica.net\n' ) txt = credits_text lines = txt.splitlines() line_height = 20 scale = 0.55 self._sub_width = width - 80 self._sub_height = line_height * len(lines) + 40 container = self._subcontainer = bui.containerwidget( parent=scroll, size=(self._sub_width, self._sub_height), background=False, claims_left_right=False, claims_tab=False, ) voffs = 0 for line in lines: bui.textwidget( parent=container, padding=4, color=(0.7, 0.9, 0.7, 1.0), scale=scale, flatness=1.0, size=(0, 0), position=(0, self._sub_height - 20 + voffs), h_align='left', v_align='top', text=bui.Lstr(value=line), ) voffs -= line_height def _back(self) -> None: from bauiv1lib.mainmenu import MainMenuWindow # no-op if our underlying widget is dead or on its way out. if not self._root_widget or self._root_widget.transitioning_out: return bui.containerwidget( edit=self._root_widget, transition=self._transition_out ) assert bui.app.classic is not None bui.app.ui_v1.set_main_menu_window( MainMenuWindow(transition='in_left').get_root_widget(), from_window=self._root_widget, )