bauiv1lib.creditslist
Provides a window to display game credits.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides a window to display game credits.""" 4 5from __future__ import annotations 6 7import os 8import logging 9from typing import TYPE_CHECKING 10 11import bauiv1 as bui 12 13if TYPE_CHECKING: 14 from typing import Sequence 15 16 17class CreditsListWindow(bui.Window): 18 """Window for displaying game credits.""" 19 20 def __init__(self, origin_widget: bui.Widget | None = None): 21 # pylint: disable=too-many-locals 22 # pylint: disable=too-many-statements 23 import json 24 25 bui.set_analytics_screen('Credits Window') 26 27 # if they provided an origin-widget, scale up from that 28 scale_origin: tuple[float, float] | None 29 if origin_widget is not None: 30 self._transition_out = 'out_scale' 31 scale_origin = origin_widget.get_screen_space_center() 32 transition = 'in_scale' 33 else: 34 self._transition_out = 'out_right' 35 scale_origin = None 36 transition = 'in_right' 37 38 assert bui.app.classic is not None 39 uiscale = bui.app.ui_v1.uiscale 40 width = 870 if uiscale is bui.UIScale.SMALL else 670 41 x_inset = 100 if uiscale is bui.UIScale.SMALL else 0 42 height = 398 if uiscale is bui.UIScale.SMALL else 500 43 44 self._r = 'creditsWindow' 45 super().__init__( 46 root_widget=bui.containerwidget( 47 size=(width, height), 48 transition=transition, 49 toolbar_visibility='menu_minimal', 50 scale_origin_stack_offset=scale_origin, 51 scale=( 52 2.0 53 if uiscale is bui.UIScale.SMALL 54 else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0 55 ), 56 stack_offset=( 57 (0, -8) if uiscale is bui.UIScale.SMALL else (0, 0) 58 ), 59 ) 60 ) 61 62 if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL: 63 bui.containerwidget( 64 edit=self._root_widget, on_cancel_call=self._back 65 ) 66 else: 67 btn = bui.buttonwidget( 68 parent=self._root_widget, 69 position=( 70 40 + x_inset, 71 height - (68 if uiscale is bui.UIScale.SMALL else 62), 72 ), 73 size=(140, 60), 74 scale=0.8, 75 label=bui.Lstr(resource='backText'), 76 button_type='back', 77 on_activate_call=self._back, 78 autoselect=True, 79 ) 80 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 81 82 bui.buttonwidget( 83 edit=btn, 84 button_type='backSmall', 85 position=( 86 40 + x_inset, 87 height - (68 if uiscale is bui.UIScale.SMALL else 62) + 5, 88 ), 89 size=(60, 48), 90 label=bui.charstr(bui.SpecialChar.BACK), 91 ) 92 93 bui.textwidget( 94 parent=self._root_widget, 95 position=(0, height - (59 if uiscale is bui.UIScale.SMALL else 54)), 96 size=(width, 30), 97 text=bui.Lstr( 98 resource=f'{self._r}.titleText', 99 subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))], 100 ), 101 h_align='center', 102 color=bui.app.ui_v1.title_color, 103 maxwidth=330, 104 v_align='center', 105 ) 106 107 scroll = bui.scrollwidget( 108 parent=self._root_widget, 109 position=(40 + x_inset, 35), 110 size=(width - (80 + 2 * x_inset), height - 100), 111 capture_arrows=True, 112 ) 113 114 if bui.app.ui_v1.use_toolbars: 115 bui.widget( 116 edit=scroll, 117 right_widget=bui.get_special_widget('party_button'), 118 ) 119 if uiscale is bui.UIScale.SMALL: 120 bui.widget( 121 edit=scroll, 122 left_widget=bui.get_special_widget('back_button'), 123 ) 124 125 def _format_names(names2: Sequence[str], inset: float) -> str: 126 sval = '' 127 # measure a series since there's overlaps and stuff.. 128 space_width = ( 129 bui.get_string_width(' ' * 10, suppress_warning=True) / 10.0 130 ) 131 spacing = 330.0 132 col1 = inset 133 col2 = col1 + spacing 134 col3 = col2 + spacing 135 line_width = 0.0 136 nline = '' 137 for name in names2: 138 # move to the next column (or row) and print 139 if line_width > col3: 140 sval += nline + '\n' 141 nline = '' 142 line_width = 0 143 144 if line_width > col2: 145 target = col3 146 elif line_width > col1: 147 target = col2 148 else: 149 target = col1 150 spacingstr = ' ' * int((target - line_width) / space_width) 151 nline += spacingstr 152 nline += name 153 line_width = bui.get_string_width(nline, suppress_warning=True) 154 if nline != '': 155 sval += nline + '\n' 156 return sval 157 158 sound_and_music = bui.Lstr( 159 resource=f'{self._r}.songCreditText' 160 ).evaluate() 161 sound_and_music = sound_and_music.replace( 162 '${TITLE}', "'William Tell (Trumpet Entry)'" 163 ) 164 sound_and_music = sound_and_music.replace( 165 '${PERFORMER}', 'The Apollo Symphony Orchestra' 166 ) 167 sound_and_music = sound_and_music.replace( 168 '${PERFORMER}', 'The Apollo Symphony Orchestra' 169 ) 170 sound_and_music = sound_and_music.replace( 171 '${COMPOSER}', 'Gioacchino Rossini' 172 ) 173 sound_and_music = sound_and_music.replace('${ARRANGER}', 'Chris Worth') 174 sound_and_music = sound_and_music.replace('${PUBLISHER}', 'BMI') 175 sound_and_music = sound_and_music.replace( 176 '${SOURCE}', 'www.AudioSparx.com' 177 ) 178 spc = ' ' 179 sound_and_music = spc + sound_and_music.replace('\n', '\n' + spc) 180 names = [ 181 'HubOfTheUniverseProd', 182 'Jovica', 183 'LG', 184 'Leady', 185 'Percy Duke', 186 'PhreaKsAccount', 187 'Pogotron', 188 'Rock Savage', 189 'anamorphosis', 190 'benboncan', 191 'cdrk', 192 'chipfork', 193 'guitarguy1985', 194 'jascha', 195 'joedeshon', 196 'loofa', 197 'm_O_m', 198 'mich3d', 199 'sandyrb', 200 'shakaharu', 201 'sirplus', 202 'stickman', 203 'thanvannispen', 204 'virotic', 205 'zimbot', 206 ] 207 names.sort(key=lambda x: x.lower()) 208 freesound_names = _format_names(names, 90) 209 210 try: 211 with open( 212 os.path.join( 213 bui.app.env.data_directory, 214 'ba_data', 215 'data', 216 'langdata.json', 217 ), 218 encoding='utf-8', 219 ) as infile: 220 translation_contributors = json.loads(infile.read())[ 221 'translation_contributors' 222 ] 223 except Exception: 224 logging.exception('Error reading translation contributors.') 225 translation_contributors = [] 226 227 translation_names = _format_names(translation_contributors, 60) 228 229 # Need to bake this out and chop it up since we're passing our 230 # 65535 vertex limit for meshes.. 231 # We can remove that limit once we drop support for GL ES2.. :-/ 232 # (or add mesh splitting under the hood) 233 credits_text = ( 234 ' ' 235 + bui.Lstr(resource=f'{self._r}.codingGraphicsAudioText') 236 .evaluate() 237 .replace('${NAME}', 'Eric Froemling') 238 + '\n' 239 '\n' 240 ' ' 241 + bui.Lstr(resource=f'{self._r}.additionalAudioArtIdeasText') 242 .evaluate() 243 .replace('${NAME}', 'Raphael Suter') 244 + '\n' 245 '\n' 246 ' ' 247 + bui.Lstr(resource=f'{self._r}.soundAndMusicText').evaluate() 248 + '\n' 249 '\n' + sound_and_music + '\n' 250 '\n' 251 ' ' 252 + bui.Lstr(resource=f'{self._r}.publicDomainMusicViaText') 253 .evaluate() 254 .replace('${NAME}', 'Musopen.com') 255 + '\n' 256 ' ' 257 + bui.Lstr(resource=f'{self._r}.thanksEspeciallyToText') 258 .evaluate() 259 .replace('${NAME}', 'the US Army, Navy, and Marine Bands') 260 + '\n' 261 '\n' 262 ' ' 263 + bui.Lstr(resource=f'{self._r}.additionalMusicFromText') 264 .evaluate() 265 .replace('${NAME}', 'The YouTube Audio Library') 266 + '\n' 267 '\n' 268 ' ' 269 + bui.Lstr(resource=f'{self._r}.soundsText') 270 .evaluate() 271 .replace('${SOURCE}', 'Freesound.org') 272 + '\n' 273 '\n' + freesound_names + '\n' 274 '\n' 275 ' ' 276 + bui.Lstr( 277 resource=f'{self._r}.languageTranslationsText' 278 ).evaluate() 279 + '\n' 280 '\n' 281 + '\n'.join(translation_names.splitlines()[:146]) 282 + '\n'.join(translation_names.splitlines()[146:]) 283 + '\n' 284 '\n' 285 ' Shout Out to Awesome Mods / Modders / Contributors:\n\n' 286 ' BombDash ModPack\n' 287 ' TheMikirog & SoK - BombSquad Joyride Modpack\n' 288 ' Mrmaxmeier - BombSquad-Community-Mod-Manager\n' 289 ' Ritiek Malhotra \n' 290 ' Dliwk\n' 291 ' vishal332008\n' 292 ' itsre3\n' 293 ' Drooopyyy\n' 294 '\n' 295 ' Holiday theme vector art designed by Freepik\n' 296 '\n' 297 ' ' 298 + bui.Lstr(resource=f'{self._r}.specialThanksText').evaluate() 299 + '\n' 300 '\n' 301 ' Todd, Laura, and Robert Froemling\n' 302 ' ' 303 + bui.Lstr(resource=f'{self._r}.allMyFamilyText') 304 .evaluate() 305 .replace('\n', '\n ') 306 + '\n' 307 ' ' 308 + bui.Lstr( 309 resource=f'{self._r}.whoeverInventedCoffeeText' 310 ).evaluate() 311 + '\n' 312 '\n' 313 ' ' + bui.Lstr(resource=f'{self._r}.legalText').evaluate() + '\n' 314 '\n' 315 ' ' 316 + bui.Lstr(resource=f'{self._r}.softwareBasedOnText') 317 .evaluate() 318 .replace('${NAME}', 'the Khronos Group') 319 + '\n' 320 '\n' 321 ' ' 322 ' www.ballistica.net\n' 323 ) 324 325 txt = credits_text 326 lines = txt.splitlines() 327 line_height = 20 328 329 scale = 0.55 330 self._sub_width = width - 80 331 self._sub_height = line_height * len(lines) + 40 332 333 container = self._subcontainer = bui.containerwidget( 334 parent=scroll, 335 size=(self._sub_width, self._sub_height), 336 background=False, 337 claims_left_right=False, 338 claims_tab=False, 339 ) 340 341 voffs = 0 342 for line in lines: 343 bui.textwidget( 344 parent=container, 345 padding=4, 346 color=(0.7, 0.9, 0.7, 1.0), 347 scale=scale, 348 flatness=1.0, 349 size=(0, 0), 350 position=(0, self._sub_height - 20 + voffs), 351 h_align='left', 352 v_align='top', 353 text=bui.Lstr(value=line), 354 ) 355 voffs -= line_height 356 357 def _back(self) -> None: 358 from bauiv1lib.mainmenu import MainMenuWindow 359 360 # no-op if our underlying widget is dead or on its way out. 361 if not self._root_widget or self._root_widget.transitioning_out: 362 return 363 364 bui.containerwidget( 365 edit=self._root_widget, transition=self._transition_out 366 ) 367 assert bui.app.classic is not None 368 bui.app.ui_v1.set_main_menu_window( 369 MainMenuWindow(transition='in_left').get_root_widget(), 370 from_window=self._root_widget, 371 )
class
CreditsListWindow(bauiv1._uitypes.Window):
18class CreditsListWindow(bui.Window): 19 """Window for displaying game credits.""" 20 21 def __init__(self, origin_widget: bui.Widget | None = None): 22 # pylint: disable=too-many-locals 23 # pylint: disable=too-many-statements 24 import json 25 26 bui.set_analytics_screen('Credits Window') 27 28 # if they provided an origin-widget, scale up from that 29 scale_origin: tuple[float, float] | None 30 if origin_widget is not None: 31 self._transition_out = 'out_scale' 32 scale_origin = origin_widget.get_screen_space_center() 33 transition = 'in_scale' 34 else: 35 self._transition_out = 'out_right' 36 scale_origin = None 37 transition = 'in_right' 38 39 assert bui.app.classic is not None 40 uiscale = bui.app.ui_v1.uiscale 41 width = 870 if uiscale is bui.UIScale.SMALL else 670 42 x_inset = 100 if uiscale is bui.UIScale.SMALL else 0 43 height = 398 if uiscale is bui.UIScale.SMALL else 500 44 45 self._r = 'creditsWindow' 46 super().__init__( 47 root_widget=bui.containerwidget( 48 size=(width, height), 49 transition=transition, 50 toolbar_visibility='menu_minimal', 51 scale_origin_stack_offset=scale_origin, 52 scale=( 53 2.0 54 if uiscale is bui.UIScale.SMALL 55 else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0 56 ), 57 stack_offset=( 58 (0, -8) if uiscale is bui.UIScale.SMALL else (0, 0) 59 ), 60 ) 61 ) 62 63 if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL: 64 bui.containerwidget( 65 edit=self._root_widget, on_cancel_call=self._back 66 ) 67 else: 68 btn = bui.buttonwidget( 69 parent=self._root_widget, 70 position=( 71 40 + x_inset, 72 height - (68 if uiscale is bui.UIScale.SMALL else 62), 73 ), 74 size=(140, 60), 75 scale=0.8, 76 label=bui.Lstr(resource='backText'), 77 button_type='back', 78 on_activate_call=self._back, 79 autoselect=True, 80 ) 81 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 82 83 bui.buttonwidget( 84 edit=btn, 85 button_type='backSmall', 86 position=( 87 40 + x_inset, 88 height - (68 if uiscale is bui.UIScale.SMALL else 62) + 5, 89 ), 90 size=(60, 48), 91 label=bui.charstr(bui.SpecialChar.BACK), 92 ) 93 94 bui.textwidget( 95 parent=self._root_widget, 96 position=(0, height - (59 if uiscale is bui.UIScale.SMALL else 54)), 97 size=(width, 30), 98 text=bui.Lstr( 99 resource=f'{self._r}.titleText', 100 subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))], 101 ), 102 h_align='center', 103 color=bui.app.ui_v1.title_color, 104 maxwidth=330, 105 v_align='center', 106 ) 107 108 scroll = bui.scrollwidget( 109 parent=self._root_widget, 110 position=(40 + x_inset, 35), 111 size=(width - (80 + 2 * x_inset), height - 100), 112 capture_arrows=True, 113 ) 114 115 if bui.app.ui_v1.use_toolbars: 116 bui.widget( 117 edit=scroll, 118 right_widget=bui.get_special_widget('party_button'), 119 ) 120 if uiscale is bui.UIScale.SMALL: 121 bui.widget( 122 edit=scroll, 123 left_widget=bui.get_special_widget('back_button'), 124 ) 125 126 def _format_names(names2: Sequence[str], inset: float) -> str: 127 sval = '' 128 # measure a series since there's overlaps and stuff.. 129 space_width = ( 130 bui.get_string_width(' ' * 10, suppress_warning=True) / 10.0 131 ) 132 spacing = 330.0 133 col1 = inset 134 col2 = col1 + spacing 135 col3 = col2 + spacing 136 line_width = 0.0 137 nline = '' 138 for name in names2: 139 # move to the next column (or row) and print 140 if line_width > col3: 141 sval += nline + '\n' 142 nline = '' 143 line_width = 0 144 145 if line_width > col2: 146 target = col3 147 elif line_width > col1: 148 target = col2 149 else: 150 target = col1 151 spacingstr = ' ' * int((target - line_width) / space_width) 152 nline += spacingstr 153 nline += name 154 line_width = bui.get_string_width(nline, suppress_warning=True) 155 if nline != '': 156 sval += nline + '\n' 157 return sval 158 159 sound_and_music = bui.Lstr( 160 resource=f'{self._r}.songCreditText' 161 ).evaluate() 162 sound_and_music = sound_and_music.replace( 163 '${TITLE}', "'William Tell (Trumpet Entry)'" 164 ) 165 sound_and_music = sound_and_music.replace( 166 '${PERFORMER}', 'The Apollo Symphony Orchestra' 167 ) 168 sound_and_music = sound_and_music.replace( 169 '${PERFORMER}', 'The Apollo Symphony Orchestra' 170 ) 171 sound_and_music = sound_and_music.replace( 172 '${COMPOSER}', 'Gioacchino Rossini' 173 ) 174 sound_and_music = sound_and_music.replace('${ARRANGER}', 'Chris Worth') 175 sound_and_music = sound_and_music.replace('${PUBLISHER}', 'BMI') 176 sound_and_music = sound_and_music.replace( 177 '${SOURCE}', 'www.AudioSparx.com' 178 ) 179 spc = ' ' 180 sound_and_music = spc + sound_and_music.replace('\n', '\n' + spc) 181 names = [ 182 'HubOfTheUniverseProd', 183 'Jovica', 184 'LG', 185 'Leady', 186 'Percy Duke', 187 'PhreaKsAccount', 188 'Pogotron', 189 'Rock Savage', 190 'anamorphosis', 191 'benboncan', 192 'cdrk', 193 'chipfork', 194 'guitarguy1985', 195 'jascha', 196 'joedeshon', 197 'loofa', 198 'm_O_m', 199 'mich3d', 200 'sandyrb', 201 'shakaharu', 202 'sirplus', 203 'stickman', 204 'thanvannispen', 205 'virotic', 206 'zimbot', 207 ] 208 names.sort(key=lambda x: x.lower()) 209 freesound_names = _format_names(names, 90) 210 211 try: 212 with open( 213 os.path.join( 214 bui.app.env.data_directory, 215 'ba_data', 216 'data', 217 'langdata.json', 218 ), 219 encoding='utf-8', 220 ) as infile: 221 translation_contributors = json.loads(infile.read())[ 222 'translation_contributors' 223 ] 224 except Exception: 225 logging.exception('Error reading translation contributors.') 226 translation_contributors = [] 227 228 translation_names = _format_names(translation_contributors, 60) 229 230 # Need to bake this out and chop it up since we're passing our 231 # 65535 vertex limit for meshes.. 232 # We can remove that limit once we drop support for GL ES2.. :-/ 233 # (or add mesh splitting under the hood) 234 credits_text = ( 235 ' ' 236 + bui.Lstr(resource=f'{self._r}.codingGraphicsAudioText') 237 .evaluate() 238 .replace('${NAME}', 'Eric Froemling') 239 + '\n' 240 '\n' 241 ' ' 242 + bui.Lstr(resource=f'{self._r}.additionalAudioArtIdeasText') 243 .evaluate() 244 .replace('${NAME}', 'Raphael Suter') 245 + '\n' 246 '\n' 247 ' ' 248 + bui.Lstr(resource=f'{self._r}.soundAndMusicText').evaluate() 249 + '\n' 250 '\n' + sound_and_music + '\n' 251 '\n' 252 ' ' 253 + bui.Lstr(resource=f'{self._r}.publicDomainMusicViaText') 254 .evaluate() 255 .replace('${NAME}', 'Musopen.com') 256 + '\n' 257 ' ' 258 + bui.Lstr(resource=f'{self._r}.thanksEspeciallyToText') 259 .evaluate() 260 .replace('${NAME}', 'the US Army, Navy, and Marine Bands') 261 + '\n' 262 '\n' 263 ' ' 264 + bui.Lstr(resource=f'{self._r}.additionalMusicFromText') 265 .evaluate() 266 .replace('${NAME}', 'The YouTube Audio Library') 267 + '\n' 268 '\n' 269 ' ' 270 + bui.Lstr(resource=f'{self._r}.soundsText') 271 .evaluate() 272 .replace('${SOURCE}', 'Freesound.org') 273 + '\n' 274 '\n' + freesound_names + '\n' 275 '\n' 276 ' ' 277 + bui.Lstr( 278 resource=f'{self._r}.languageTranslationsText' 279 ).evaluate() 280 + '\n' 281 '\n' 282 + '\n'.join(translation_names.splitlines()[:146]) 283 + '\n'.join(translation_names.splitlines()[146:]) 284 + '\n' 285 '\n' 286 ' Shout Out to Awesome Mods / Modders / Contributors:\n\n' 287 ' BombDash ModPack\n' 288 ' TheMikirog & SoK - BombSquad Joyride Modpack\n' 289 ' Mrmaxmeier - BombSquad-Community-Mod-Manager\n' 290 ' Ritiek Malhotra \n' 291 ' Dliwk\n' 292 ' vishal332008\n' 293 ' itsre3\n' 294 ' Drooopyyy\n' 295 '\n' 296 ' Holiday theme vector art designed by Freepik\n' 297 '\n' 298 ' ' 299 + bui.Lstr(resource=f'{self._r}.specialThanksText').evaluate() 300 + '\n' 301 '\n' 302 ' Todd, Laura, and Robert Froemling\n' 303 ' ' 304 + bui.Lstr(resource=f'{self._r}.allMyFamilyText') 305 .evaluate() 306 .replace('\n', '\n ') 307 + '\n' 308 ' ' 309 + bui.Lstr( 310 resource=f'{self._r}.whoeverInventedCoffeeText' 311 ).evaluate() 312 + '\n' 313 '\n' 314 ' ' + bui.Lstr(resource=f'{self._r}.legalText').evaluate() + '\n' 315 '\n' 316 ' ' 317 + bui.Lstr(resource=f'{self._r}.softwareBasedOnText') 318 .evaluate() 319 .replace('${NAME}', 'the Khronos Group') 320 + '\n' 321 '\n' 322 ' ' 323 ' www.ballistica.net\n' 324 ) 325 326 txt = credits_text 327 lines = txt.splitlines() 328 line_height = 20 329 330 scale = 0.55 331 self._sub_width = width - 80 332 self._sub_height = line_height * len(lines) + 40 333 334 container = self._subcontainer = bui.containerwidget( 335 parent=scroll, 336 size=(self._sub_width, self._sub_height), 337 background=False, 338 claims_left_right=False, 339 claims_tab=False, 340 ) 341 342 voffs = 0 343 for line in lines: 344 bui.textwidget( 345 parent=container, 346 padding=4, 347 color=(0.7, 0.9, 0.7, 1.0), 348 scale=scale, 349 flatness=1.0, 350 size=(0, 0), 351 position=(0, self._sub_height - 20 + voffs), 352 h_align='left', 353 v_align='top', 354 text=bui.Lstr(value=line), 355 ) 356 voffs -= line_height 357 358 def _back(self) -> None: 359 from bauiv1lib.mainmenu import MainMenuWindow 360 361 # no-op if our underlying widget is dead or on its way out. 362 if not self._root_widget or self._root_widget.transitioning_out: 363 return 364 365 bui.containerwidget( 366 edit=self._root_widget, transition=self._transition_out 367 ) 368 assert bui.app.classic is not None 369 bui.app.ui_v1.set_main_menu_window( 370 MainMenuWindow(transition='in_left').get_root_widget(), 371 from_window=self._root_widget, 372 )
Window for displaying game credits.
CreditsListWindow(origin_widget: _bauiv1.Widget | None = None)
21 def __init__(self, origin_widget: bui.Widget | None = None): 22 # pylint: disable=too-many-locals 23 # pylint: disable=too-many-statements 24 import json 25 26 bui.set_analytics_screen('Credits Window') 27 28 # if they provided an origin-widget, scale up from that 29 scale_origin: tuple[float, float] | None 30 if origin_widget is not None: 31 self._transition_out = 'out_scale' 32 scale_origin = origin_widget.get_screen_space_center() 33 transition = 'in_scale' 34 else: 35 self._transition_out = 'out_right' 36 scale_origin = None 37 transition = 'in_right' 38 39 assert bui.app.classic is not None 40 uiscale = bui.app.ui_v1.uiscale 41 width = 870 if uiscale is bui.UIScale.SMALL else 670 42 x_inset = 100 if uiscale is bui.UIScale.SMALL else 0 43 height = 398 if uiscale is bui.UIScale.SMALL else 500 44 45 self._r = 'creditsWindow' 46 super().__init__( 47 root_widget=bui.containerwidget( 48 size=(width, height), 49 transition=transition, 50 toolbar_visibility='menu_minimal', 51 scale_origin_stack_offset=scale_origin, 52 scale=( 53 2.0 54 if uiscale is bui.UIScale.SMALL 55 else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0 56 ), 57 stack_offset=( 58 (0, -8) if uiscale is bui.UIScale.SMALL else (0, 0) 59 ), 60 ) 61 ) 62 63 if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL: 64 bui.containerwidget( 65 edit=self._root_widget, on_cancel_call=self._back 66 ) 67 else: 68 btn = bui.buttonwidget( 69 parent=self._root_widget, 70 position=( 71 40 + x_inset, 72 height - (68 if uiscale is bui.UIScale.SMALL else 62), 73 ), 74 size=(140, 60), 75 scale=0.8, 76 label=bui.Lstr(resource='backText'), 77 button_type='back', 78 on_activate_call=self._back, 79 autoselect=True, 80 ) 81 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 82 83 bui.buttonwidget( 84 edit=btn, 85 button_type='backSmall', 86 position=( 87 40 + x_inset, 88 height - (68 if uiscale is bui.UIScale.SMALL else 62) + 5, 89 ), 90 size=(60, 48), 91 label=bui.charstr(bui.SpecialChar.BACK), 92 ) 93 94 bui.textwidget( 95 parent=self._root_widget, 96 position=(0, height - (59 if uiscale is bui.UIScale.SMALL else 54)), 97 size=(width, 30), 98 text=bui.Lstr( 99 resource=f'{self._r}.titleText', 100 subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))], 101 ), 102 h_align='center', 103 color=bui.app.ui_v1.title_color, 104 maxwidth=330, 105 v_align='center', 106 ) 107 108 scroll = bui.scrollwidget( 109 parent=self._root_widget, 110 position=(40 + x_inset, 35), 111 size=(width - (80 + 2 * x_inset), height - 100), 112 capture_arrows=True, 113 ) 114 115 if bui.app.ui_v1.use_toolbars: 116 bui.widget( 117 edit=scroll, 118 right_widget=bui.get_special_widget('party_button'), 119 ) 120 if uiscale is bui.UIScale.SMALL: 121 bui.widget( 122 edit=scroll, 123 left_widget=bui.get_special_widget('back_button'), 124 ) 125 126 def _format_names(names2: Sequence[str], inset: float) -> str: 127 sval = '' 128 # measure a series since there's overlaps and stuff.. 129 space_width = ( 130 bui.get_string_width(' ' * 10, suppress_warning=True) / 10.0 131 ) 132 spacing = 330.0 133 col1 = inset 134 col2 = col1 + spacing 135 col3 = col2 + spacing 136 line_width = 0.0 137 nline = '' 138 for name in names2: 139 # move to the next column (or row) and print 140 if line_width > col3: 141 sval += nline + '\n' 142 nline = '' 143 line_width = 0 144 145 if line_width > col2: 146 target = col3 147 elif line_width > col1: 148 target = col2 149 else: 150 target = col1 151 spacingstr = ' ' * int((target - line_width) / space_width) 152 nline += spacingstr 153 nline += name 154 line_width = bui.get_string_width(nline, suppress_warning=True) 155 if nline != '': 156 sval += nline + '\n' 157 return sval 158 159 sound_and_music = bui.Lstr( 160 resource=f'{self._r}.songCreditText' 161 ).evaluate() 162 sound_and_music = sound_and_music.replace( 163 '${TITLE}', "'William Tell (Trumpet Entry)'" 164 ) 165 sound_and_music = sound_and_music.replace( 166 '${PERFORMER}', 'The Apollo Symphony Orchestra' 167 ) 168 sound_and_music = sound_and_music.replace( 169 '${PERFORMER}', 'The Apollo Symphony Orchestra' 170 ) 171 sound_and_music = sound_and_music.replace( 172 '${COMPOSER}', 'Gioacchino Rossini' 173 ) 174 sound_and_music = sound_and_music.replace('${ARRANGER}', 'Chris Worth') 175 sound_and_music = sound_and_music.replace('${PUBLISHER}', 'BMI') 176 sound_and_music = sound_and_music.replace( 177 '${SOURCE}', 'www.AudioSparx.com' 178 ) 179 spc = ' ' 180 sound_and_music = spc + sound_and_music.replace('\n', '\n' + spc) 181 names = [ 182 'HubOfTheUniverseProd', 183 'Jovica', 184 'LG', 185 'Leady', 186 'Percy Duke', 187 'PhreaKsAccount', 188 'Pogotron', 189 'Rock Savage', 190 'anamorphosis', 191 'benboncan', 192 'cdrk', 193 'chipfork', 194 'guitarguy1985', 195 'jascha', 196 'joedeshon', 197 'loofa', 198 'm_O_m', 199 'mich3d', 200 'sandyrb', 201 'shakaharu', 202 'sirplus', 203 'stickman', 204 'thanvannispen', 205 'virotic', 206 'zimbot', 207 ] 208 names.sort(key=lambda x: x.lower()) 209 freesound_names = _format_names(names, 90) 210 211 try: 212 with open( 213 os.path.join( 214 bui.app.env.data_directory, 215 'ba_data', 216 'data', 217 'langdata.json', 218 ), 219 encoding='utf-8', 220 ) as infile: 221 translation_contributors = json.loads(infile.read())[ 222 'translation_contributors' 223 ] 224 except Exception: 225 logging.exception('Error reading translation contributors.') 226 translation_contributors = [] 227 228 translation_names = _format_names(translation_contributors, 60) 229 230 # Need to bake this out and chop it up since we're passing our 231 # 65535 vertex limit for meshes.. 232 # We can remove that limit once we drop support for GL ES2.. :-/ 233 # (or add mesh splitting under the hood) 234 credits_text = ( 235 ' ' 236 + bui.Lstr(resource=f'{self._r}.codingGraphicsAudioText') 237 .evaluate() 238 .replace('${NAME}', 'Eric Froemling') 239 + '\n' 240 '\n' 241 ' ' 242 + bui.Lstr(resource=f'{self._r}.additionalAudioArtIdeasText') 243 .evaluate() 244 .replace('${NAME}', 'Raphael Suter') 245 + '\n' 246 '\n' 247 ' ' 248 + bui.Lstr(resource=f'{self._r}.soundAndMusicText').evaluate() 249 + '\n' 250 '\n' + sound_and_music + '\n' 251 '\n' 252 ' ' 253 + bui.Lstr(resource=f'{self._r}.publicDomainMusicViaText') 254 .evaluate() 255 .replace('${NAME}', 'Musopen.com') 256 + '\n' 257 ' ' 258 + bui.Lstr(resource=f'{self._r}.thanksEspeciallyToText') 259 .evaluate() 260 .replace('${NAME}', 'the US Army, Navy, and Marine Bands') 261 + '\n' 262 '\n' 263 ' ' 264 + bui.Lstr(resource=f'{self._r}.additionalMusicFromText') 265 .evaluate() 266 .replace('${NAME}', 'The YouTube Audio Library') 267 + '\n' 268 '\n' 269 ' ' 270 + bui.Lstr(resource=f'{self._r}.soundsText') 271 .evaluate() 272 .replace('${SOURCE}', 'Freesound.org') 273 + '\n' 274 '\n' + freesound_names + '\n' 275 '\n' 276 ' ' 277 + bui.Lstr( 278 resource=f'{self._r}.languageTranslationsText' 279 ).evaluate() 280 + '\n' 281 '\n' 282 + '\n'.join(translation_names.splitlines()[:146]) 283 + '\n'.join(translation_names.splitlines()[146:]) 284 + '\n' 285 '\n' 286 ' Shout Out to Awesome Mods / Modders / Contributors:\n\n' 287 ' BombDash ModPack\n' 288 ' TheMikirog & SoK - BombSquad Joyride Modpack\n' 289 ' Mrmaxmeier - BombSquad-Community-Mod-Manager\n' 290 ' Ritiek Malhotra \n' 291 ' Dliwk\n' 292 ' vishal332008\n' 293 ' itsre3\n' 294 ' Drooopyyy\n' 295 '\n' 296 ' Holiday theme vector art designed by Freepik\n' 297 '\n' 298 ' ' 299 + bui.Lstr(resource=f'{self._r}.specialThanksText').evaluate() 300 + '\n' 301 '\n' 302 ' Todd, Laura, and Robert Froemling\n' 303 ' ' 304 + bui.Lstr(resource=f'{self._r}.allMyFamilyText') 305 .evaluate() 306 .replace('\n', '\n ') 307 + '\n' 308 ' ' 309 + bui.Lstr( 310 resource=f'{self._r}.whoeverInventedCoffeeText' 311 ).evaluate() 312 + '\n' 313 '\n' 314 ' ' + bui.Lstr(resource=f'{self._r}.legalText').evaluate() + '\n' 315 '\n' 316 ' ' 317 + bui.Lstr(resource=f'{self._r}.softwareBasedOnText') 318 .evaluate() 319 .replace('${NAME}', 'the Khronos Group') 320 + '\n' 321 '\n' 322 ' ' 323 ' www.ballistica.net\n' 324 ) 325 326 txt = credits_text 327 lines = txt.splitlines() 328 line_height = 20 329 330 scale = 0.55 331 self._sub_width = width - 80 332 self._sub_height = line_height * len(lines) + 40 333 334 container = self._subcontainer = bui.containerwidget( 335 parent=scroll, 336 size=(self._sub_width, self._sub_height), 337 background=False, 338 claims_left_right=False, 339 claims_tab=False, 340 ) 341 342 voffs = 0 343 for line in lines: 344 bui.textwidget( 345 parent=container, 346 padding=4, 347 color=(0.7, 0.9, 0.7, 1.0), 348 scale=scale, 349 flatness=1.0, 350 size=(0, 0), 351 position=(0, self._sub_height - 20 + voffs), 352 h_align='left', 353 v_align='top', 354 text=bui.Lstr(value=line), 355 ) 356 voffs -= line_height
Inherited Members
- bauiv1._uitypes.Window
- get_root_widget