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