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 = 450 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 - (93 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, 62 if uiscale is bui.UIScale.SMALL else 35), 105 size=( 106 width - (80 + 2 * x_inset), 107 height - (160 if uiscale is bui.UIScale.SMALL else 100), 108 ), 109 capture_arrows=True, 110 ) 111 112 bui.widget( 113 edit=scroll, 114 right_widget=bui.get_special_widget('squad_button'), 115 ) 116 if uiscale is bui.UIScale.SMALL: 117 bui.widget( 118 edit=scroll, 119 left_widget=bui.get_special_widget('back_button'), 120 ) 121 122 def _format_names(names2: Sequence[str], inset: float) -> str: 123 sval = '' 124 # measure a series since there's overlaps and stuff.. 125 space_width = ( 126 bui.get_string_width(' ' * 10, suppress_warning=True) / 10.0 127 ) 128 spacing = 330.0 129 col1 = inset 130 col2 = col1 + spacing 131 col3 = col2 + spacing 132 line_width = 0.0 133 nline = '' 134 for name in names2: 135 # move to the next column (or row) and print 136 if line_width > col3: 137 sval += nline + '\n' 138 nline = '' 139 line_width = 0 140 141 if line_width > col2: 142 target = col3 143 elif line_width > col1: 144 target = col2 145 else: 146 target = col1 147 spacingstr = ' ' * int((target - line_width) / space_width) 148 nline += spacingstr 149 nline += name 150 line_width = bui.get_string_width(nline, suppress_warning=True) 151 if nline != '': 152 sval += nline + '\n' 153 return sval 154 155 sound_and_music = bui.Lstr( 156 resource=f'{self._r}.songCreditText' 157 ).evaluate() 158 sound_and_music = sound_and_music.replace( 159 '${TITLE}', "'William Tell (Trumpet Entry)'" 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 '${PERFORMER}', 'The Apollo Symphony Orchestra' 166 ) 167 sound_and_music = sound_and_music.replace( 168 '${COMPOSER}', 'Gioacchino Rossini' 169 ) 170 sound_and_music = sound_and_music.replace('${ARRANGER}', 'Chris Worth') 171 sound_and_music = sound_and_music.replace('${PUBLISHER}', 'BMI') 172 sound_and_music = sound_and_music.replace( 173 '${SOURCE}', 'www.AudioSparx.com' 174 ) 175 spc = ' ' 176 sound_and_music = spc + sound_and_music.replace('\n', '\n' + spc) 177 names = [ 178 'HubOfTheUniverseProd', 179 'Jovica', 180 'LG', 181 'Leady', 182 'Percy Duke', 183 'PhreaKsAccount', 184 'Pogotron', 185 'Rock Savage', 186 'anamorphosis', 187 'benboncan', 188 'cdrk', 189 'chipfork', 190 'guitarguy1985', 191 'jascha', 192 'joedeshon', 193 'loofa', 194 'm_O_m', 195 'mich3d', 196 'sandyrb', 197 'shakaharu', 198 'sirplus', 199 'stickman', 200 'thanvannispen', 201 'virotic', 202 'zimbot', 203 ] 204 names.sort(key=lambda x: x.lower()) 205 freesound_names = _format_names(names, 90) 206 207 try: 208 with open( 209 os.path.join( 210 bui.app.env.data_directory, 211 'ba_data', 212 'data', 213 'langdata.json', 214 ), 215 encoding='utf-8', 216 ) as infile: 217 translation_contributors = json.loads(infile.read())[ 218 'translation_contributors' 219 ] 220 except Exception: 221 logging.exception('Error reading translation contributors.') 222 translation_contributors = [] 223 224 translation_names = _format_names(translation_contributors, 60) 225 226 # Need to bake this out and chop it up since we're passing our 227 # 65535 vertex limit for meshes.. 228 # We can remove that limit once we drop support for GL ES2.. :-/ 229 # (or add mesh splitting under the hood) 230 credits_text = ( 231 ' ' 232 + bui.Lstr(resource=f'{self._r}.codingGraphicsAudioText') 233 .evaluate() 234 .replace('${NAME}', 'Eric Froemling') 235 + '\n' 236 '\n' 237 ' ' 238 + bui.Lstr(resource=f'{self._r}.additionalAudioArtIdeasText') 239 .evaluate() 240 .replace('${NAME}', 'Raphael Suter') 241 + '\n' 242 '\n' 243 ' ' 244 + bui.Lstr(resource=f'{self._r}.soundAndMusicText').evaluate() 245 + '\n' 246 '\n' + sound_and_music + '\n' 247 '\n' 248 ' ' 249 + bui.Lstr(resource=f'{self._r}.publicDomainMusicViaText') 250 .evaluate() 251 .replace('${NAME}', 'Musopen.com') 252 + '\n' 253 ' ' 254 + bui.Lstr(resource=f'{self._r}.thanksEspeciallyToText') 255 .evaluate() 256 .replace('${NAME}', 'the US Army, Navy, and Marine Bands') 257 + '\n' 258 '\n' 259 ' ' 260 + bui.Lstr(resource=f'{self._r}.additionalMusicFromText') 261 .evaluate() 262 .replace('${NAME}', 'The YouTube Audio Library') 263 + '\n' 264 '\n' 265 ' ' 266 + bui.Lstr(resource=f'{self._r}.soundsText') 267 .evaluate() 268 .replace('${SOURCE}', 'Freesound.org') 269 + '\n' 270 '\n' + freesound_names + '\n' 271 '\n' 272 ' ' 273 + bui.Lstr( 274 resource=f'{self._r}.languageTranslationsText' 275 ).evaluate() 276 + '\n' 277 '\n' 278 + '\n'.join(translation_names.splitlines()[:146]) 279 + '\n'.join(translation_names.splitlines()[146:]) 280 + '\n' 281 '\n' 282 ' Shout Out to Awesome Mods / Modders / Contributors:\n\n' 283 ' BombDash ModPack\n' 284 ' TheMikirog & SoK - BombSquad Joyride Modpack\n' 285 ' Mrmaxmeier - BombSquad-Community-Mod-Manager\n' 286 ' Ritiek Malhotra \n' 287 ' Dliwk\n' 288 ' vishal332008\n' 289 ' itsre3\n' 290 ' Drooopyyy\n' 291 '\n' 292 ' Holiday theme vector art designed by Freepik\n' 293 '\n' 294 ' ' 295 + bui.Lstr(resource=f'{self._r}.specialThanksText').evaluate() 296 + '\n' 297 '\n' 298 ' Todd, Laura, and Robert Froemling\n' 299 ' ' 300 + bui.Lstr(resource=f'{self._r}.allMyFamilyText') 301 .evaluate() 302 .replace('\n', '\n ') 303 + '\n' 304 ' ' 305 + bui.Lstr( 306 resource=f'{self._r}.whoeverInventedCoffeeText' 307 ).evaluate() 308 + '\n' 309 '\n' 310 ' ' + bui.Lstr(resource=f'{self._r}.legalText').evaluate() + '\n' 311 '\n' 312 ' ' 313 + bui.Lstr(resource=f'{self._r}.softwareBasedOnText') 314 .evaluate() 315 .replace('${NAME}', 'the Khronos Group') 316 + '\n' 317 '\n' 318 ' ' 319 ' www.ballistica.net\n' 320 ) 321 322 txt = credits_text 323 lines = txt.splitlines() 324 line_height = 20 325 326 scale = 0.55 327 self._sub_width = width - 80 328 self._sub_height = line_height * len(lines) + 40 329 330 container = self._subcontainer = bui.containerwidget( 331 parent=scroll, 332 size=(self._sub_width, self._sub_height), 333 background=False, 334 claims_left_right=False, 335 claims_tab=False, 336 ) 337 338 voffs = 0 339 for line in lines: 340 bui.textwidget( 341 parent=container, 342 padding=4, 343 color=(0.7, 0.9, 0.7, 1.0), 344 scale=scale, 345 flatness=1.0, 346 size=(0, 0), 347 position=(0, self._sub_height - 20 + voffs), 348 h_align='left', 349 v_align='top', 350 text=bui.Lstr(value=line), 351 ) 352 voffs -= line_height 353 354 @override 355 def get_main_window_state(self) -> bui.MainWindowState: 356 # Support recreating our window for back/refresh purposes. 357 cls = type(self) 358 return bui.BasicMainWindowState( 359 create_call=lambda transition, origin_widget: cls( 360 transition=transition, origin_widget=origin_widget 361 ) 362 )
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 = 450 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 - (93 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, 62 if uiscale is bui.UIScale.SMALL else 35), 106 size=( 107 width - (80 + 2 * x_inset), 108 height - (160 if uiscale is bui.UIScale.SMALL else 100), 109 ), 110 capture_arrows=True, 111 ) 112 113 bui.widget( 114 edit=scroll, 115 right_widget=bui.get_special_widget('squad_button'), 116 ) 117 if uiscale is bui.UIScale.SMALL: 118 bui.widget( 119 edit=scroll, 120 left_widget=bui.get_special_widget('back_button'), 121 ) 122 123 def _format_names(names2: Sequence[str], inset: float) -> str: 124 sval = '' 125 # measure a series since there's overlaps and stuff.. 126 space_width = ( 127 bui.get_string_width(' ' * 10, suppress_warning=True) / 10.0 128 ) 129 spacing = 330.0 130 col1 = inset 131 col2 = col1 + spacing 132 col3 = col2 + spacing 133 line_width = 0.0 134 nline = '' 135 for name in names2: 136 # move to the next column (or row) and print 137 if line_width > col3: 138 sval += nline + '\n' 139 nline = '' 140 line_width = 0 141 142 if line_width > col2: 143 target = col3 144 elif line_width > col1: 145 target = col2 146 else: 147 target = col1 148 spacingstr = ' ' * int((target - line_width) / space_width) 149 nline += spacingstr 150 nline += name 151 line_width = bui.get_string_width(nline, suppress_warning=True) 152 if nline != '': 153 sval += nline + '\n' 154 return sval 155 156 sound_and_music = bui.Lstr( 157 resource=f'{self._r}.songCreditText' 158 ).evaluate() 159 sound_and_music = sound_and_music.replace( 160 '${TITLE}', "'William Tell (Trumpet Entry)'" 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 '${PERFORMER}', 'The Apollo Symphony Orchestra' 167 ) 168 sound_and_music = sound_and_music.replace( 169 '${COMPOSER}', 'Gioacchino Rossini' 170 ) 171 sound_and_music = sound_and_music.replace('${ARRANGER}', 'Chris Worth') 172 sound_and_music = sound_and_music.replace('${PUBLISHER}', 'BMI') 173 sound_and_music = sound_and_music.replace( 174 '${SOURCE}', 'www.AudioSparx.com' 175 ) 176 spc = ' ' 177 sound_and_music = spc + sound_and_music.replace('\n', '\n' + spc) 178 names = [ 179 'HubOfTheUniverseProd', 180 'Jovica', 181 'LG', 182 'Leady', 183 'Percy Duke', 184 'PhreaKsAccount', 185 'Pogotron', 186 'Rock Savage', 187 'anamorphosis', 188 'benboncan', 189 'cdrk', 190 'chipfork', 191 'guitarguy1985', 192 'jascha', 193 'joedeshon', 194 'loofa', 195 'm_O_m', 196 'mich3d', 197 'sandyrb', 198 'shakaharu', 199 'sirplus', 200 'stickman', 201 'thanvannispen', 202 'virotic', 203 'zimbot', 204 ] 205 names.sort(key=lambda x: x.lower()) 206 freesound_names = _format_names(names, 90) 207 208 try: 209 with open( 210 os.path.join( 211 bui.app.env.data_directory, 212 'ba_data', 213 'data', 214 'langdata.json', 215 ), 216 encoding='utf-8', 217 ) as infile: 218 translation_contributors = json.loads(infile.read())[ 219 'translation_contributors' 220 ] 221 except Exception: 222 logging.exception('Error reading translation contributors.') 223 translation_contributors = [] 224 225 translation_names = _format_names(translation_contributors, 60) 226 227 # Need to bake this out and chop it up since we're passing our 228 # 65535 vertex limit for meshes.. 229 # We can remove that limit once we drop support for GL ES2.. :-/ 230 # (or add mesh splitting under the hood) 231 credits_text = ( 232 ' ' 233 + bui.Lstr(resource=f'{self._r}.codingGraphicsAudioText') 234 .evaluate() 235 .replace('${NAME}', 'Eric Froemling') 236 + '\n' 237 '\n' 238 ' ' 239 + bui.Lstr(resource=f'{self._r}.additionalAudioArtIdeasText') 240 .evaluate() 241 .replace('${NAME}', 'Raphael Suter') 242 + '\n' 243 '\n' 244 ' ' 245 + bui.Lstr(resource=f'{self._r}.soundAndMusicText').evaluate() 246 + '\n' 247 '\n' + sound_and_music + '\n' 248 '\n' 249 ' ' 250 + bui.Lstr(resource=f'{self._r}.publicDomainMusicViaText') 251 .evaluate() 252 .replace('${NAME}', 'Musopen.com') 253 + '\n' 254 ' ' 255 + bui.Lstr(resource=f'{self._r}.thanksEspeciallyToText') 256 .evaluate() 257 .replace('${NAME}', 'the US Army, Navy, and Marine Bands') 258 + '\n' 259 '\n' 260 ' ' 261 + bui.Lstr(resource=f'{self._r}.additionalMusicFromText') 262 .evaluate() 263 .replace('${NAME}', 'The YouTube Audio Library') 264 + '\n' 265 '\n' 266 ' ' 267 + bui.Lstr(resource=f'{self._r}.soundsText') 268 .evaluate() 269 .replace('${SOURCE}', 'Freesound.org') 270 + '\n' 271 '\n' + freesound_names + '\n' 272 '\n' 273 ' ' 274 + bui.Lstr( 275 resource=f'{self._r}.languageTranslationsText' 276 ).evaluate() 277 + '\n' 278 '\n' 279 + '\n'.join(translation_names.splitlines()[:146]) 280 + '\n'.join(translation_names.splitlines()[146:]) 281 + '\n' 282 '\n' 283 ' Shout Out to Awesome Mods / Modders / Contributors:\n\n' 284 ' BombDash ModPack\n' 285 ' TheMikirog & SoK - BombSquad Joyride Modpack\n' 286 ' Mrmaxmeier - BombSquad-Community-Mod-Manager\n' 287 ' Ritiek Malhotra \n' 288 ' Dliwk\n' 289 ' vishal332008\n' 290 ' itsre3\n' 291 ' Drooopyyy\n' 292 '\n' 293 ' Holiday theme vector art designed by Freepik\n' 294 '\n' 295 ' ' 296 + bui.Lstr(resource=f'{self._r}.specialThanksText').evaluate() 297 + '\n' 298 '\n' 299 ' Todd, Laura, and Robert Froemling\n' 300 ' ' 301 + bui.Lstr(resource=f'{self._r}.allMyFamilyText') 302 .evaluate() 303 .replace('\n', '\n ') 304 + '\n' 305 ' ' 306 + bui.Lstr( 307 resource=f'{self._r}.whoeverInventedCoffeeText' 308 ).evaluate() 309 + '\n' 310 '\n' 311 ' ' + bui.Lstr(resource=f'{self._r}.legalText').evaluate() + '\n' 312 '\n' 313 ' ' 314 + bui.Lstr(resource=f'{self._r}.softwareBasedOnText') 315 .evaluate() 316 .replace('${NAME}', 'the Khronos Group') 317 + '\n' 318 '\n' 319 ' ' 320 ' www.ballistica.net\n' 321 ) 322 323 txt = credits_text 324 lines = txt.splitlines() 325 line_height = 20 326 327 scale = 0.55 328 self._sub_width = width - 80 329 self._sub_height = line_height * len(lines) + 40 330 331 container = self._subcontainer = bui.containerwidget( 332 parent=scroll, 333 size=(self._sub_width, self._sub_height), 334 background=False, 335 claims_left_right=False, 336 claims_tab=False, 337 ) 338 339 voffs = 0 340 for line in lines: 341 bui.textwidget( 342 parent=container, 343 padding=4, 344 color=(0.7, 0.9, 0.7, 1.0), 345 scale=scale, 346 flatness=1.0, 347 size=(0, 0), 348 position=(0, self._sub_height - 20 + voffs), 349 h_align='left', 350 v_align='top', 351 text=bui.Lstr(value=line), 352 ) 353 voffs -= line_height 354 355 @override 356 def get_main_window_state(self) -> bui.MainWindowState: 357 # Support recreating our window for back/refresh purposes. 358 cls = type(self) 359 return bui.BasicMainWindowState( 360 create_call=lambda transition, origin_widget: cls( 361 transition=transition, origin_widget=origin_widget 362 ) 363 )
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 = 450 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 - (93 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, 62 if uiscale is bui.UIScale.SMALL else 35), 106 size=( 107 width - (80 + 2 * x_inset), 108 height - (160 if uiscale is bui.UIScale.SMALL else 100), 109 ), 110 capture_arrows=True, 111 ) 112 113 bui.widget( 114 edit=scroll, 115 right_widget=bui.get_special_widget('squad_button'), 116 ) 117 if uiscale is bui.UIScale.SMALL: 118 bui.widget( 119 edit=scroll, 120 left_widget=bui.get_special_widget('back_button'), 121 ) 122 123 def _format_names(names2: Sequence[str], inset: float) -> str: 124 sval = '' 125 # measure a series since there's overlaps and stuff.. 126 space_width = ( 127 bui.get_string_width(' ' * 10, suppress_warning=True) / 10.0 128 ) 129 spacing = 330.0 130 col1 = inset 131 col2 = col1 + spacing 132 col3 = col2 + spacing 133 line_width = 0.0 134 nline = '' 135 for name in names2: 136 # move to the next column (or row) and print 137 if line_width > col3: 138 sval += nline + '\n' 139 nline = '' 140 line_width = 0 141 142 if line_width > col2: 143 target = col3 144 elif line_width > col1: 145 target = col2 146 else: 147 target = col1 148 spacingstr = ' ' * int((target - line_width) / space_width) 149 nline += spacingstr 150 nline += name 151 line_width = bui.get_string_width(nline, suppress_warning=True) 152 if nline != '': 153 sval += nline + '\n' 154 return sval 155 156 sound_and_music = bui.Lstr( 157 resource=f'{self._r}.songCreditText' 158 ).evaluate() 159 sound_and_music = sound_and_music.replace( 160 '${TITLE}', "'William Tell (Trumpet Entry)'" 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 '${PERFORMER}', 'The Apollo Symphony Orchestra' 167 ) 168 sound_and_music = sound_and_music.replace( 169 '${COMPOSER}', 'Gioacchino Rossini' 170 ) 171 sound_and_music = sound_and_music.replace('${ARRANGER}', 'Chris Worth') 172 sound_and_music = sound_and_music.replace('${PUBLISHER}', 'BMI') 173 sound_and_music = sound_and_music.replace( 174 '${SOURCE}', 'www.AudioSparx.com' 175 ) 176 spc = ' ' 177 sound_and_music = spc + sound_and_music.replace('\n', '\n' + spc) 178 names = [ 179 'HubOfTheUniverseProd', 180 'Jovica', 181 'LG', 182 'Leady', 183 'Percy Duke', 184 'PhreaKsAccount', 185 'Pogotron', 186 'Rock Savage', 187 'anamorphosis', 188 'benboncan', 189 'cdrk', 190 'chipfork', 191 'guitarguy1985', 192 'jascha', 193 'joedeshon', 194 'loofa', 195 'm_O_m', 196 'mich3d', 197 'sandyrb', 198 'shakaharu', 199 'sirplus', 200 'stickman', 201 'thanvannispen', 202 'virotic', 203 'zimbot', 204 ] 205 names.sort(key=lambda x: x.lower()) 206 freesound_names = _format_names(names, 90) 207 208 try: 209 with open( 210 os.path.join( 211 bui.app.env.data_directory, 212 'ba_data', 213 'data', 214 'langdata.json', 215 ), 216 encoding='utf-8', 217 ) as infile: 218 translation_contributors = json.loads(infile.read())[ 219 'translation_contributors' 220 ] 221 except Exception: 222 logging.exception('Error reading translation contributors.') 223 translation_contributors = [] 224 225 translation_names = _format_names(translation_contributors, 60) 226 227 # Need to bake this out and chop it up since we're passing our 228 # 65535 vertex limit for meshes.. 229 # We can remove that limit once we drop support for GL ES2.. :-/ 230 # (or add mesh splitting under the hood) 231 credits_text = ( 232 ' ' 233 + bui.Lstr(resource=f'{self._r}.codingGraphicsAudioText') 234 .evaluate() 235 .replace('${NAME}', 'Eric Froemling') 236 + '\n' 237 '\n' 238 ' ' 239 + bui.Lstr(resource=f'{self._r}.additionalAudioArtIdeasText') 240 .evaluate() 241 .replace('${NAME}', 'Raphael Suter') 242 + '\n' 243 '\n' 244 ' ' 245 + bui.Lstr(resource=f'{self._r}.soundAndMusicText').evaluate() 246 + '\n' 247 '\n' + sound_and_music + '\n' 248 '\n' 249 ' ' 250 + bui.Lstr(resource=f'{self._r}.publicDomainMusicViaText') 251 .evaluate() 252 .replace('${NAME}', 'Musopen.com') 253 + '\n' 254 ' ' 255 + bui.Lstr(resource=f'{self._r}.thanksEspeciallyToText') 256 .evaluate() 257 .replace('${NAME}', 'the US Army, Navy, and Marine Bands') 258 + '\n' 259 '\n' 260 ' ' 261 + bui.Lstr(resource=f'{self._r}.additionalMusicFromText') 262 .evaluate() 263 .replace('${NAME}', 'The YouTube Audio Library') 264 + '\n' 265 '\n' 266 ' ' 267 + bui.Lstr(resource=f'{self._r}.soundsText') 268 .evaluate() 269 .replace('${SOURCE}', 'Freesound.org') 270 + '\n' 271 '\n' + freesound_names + '\n' 272 '\n' 273 ' ' 274 + bui.Lstr( 275 resource=f'{self._r}.languageTranslationsText' 276 ).evaluate() 277 + '\n' 278 '\n' 279 + '\n'.join(translation_names.splitlines()[:146]) 280 + '\n'.join(translation_names.splitlines()[146:]) 281 + '\n' 282 '\n' 283 ' Shout Out to Awesome Mods / Modders / Contributors:\n\n' 284 ' BombDash ModPack\n' 285 ' TheMikirog & SoK - BombSquad Joyride Modpack\n' 286 ' Mrmaxmeier - BombSquad-Community-Mod-Manager\n' 287 ' Ritiek Malhotra \n' 288 ' Dliwk\n' 289 ' vishal332008\n' 290 ' itsre3\n' 291 ' Drooopyyy\n' 292 '\n' 293 ' Holiday theme vector art designed by Freepik\n' 294 '\n' 295 ' ' 296 + bui.Lstr(resource=f'{self._r}.specialThanksText').evaluate() 297 + '\n' 298 '\n' 299 ' Todd, Laura, and Robert Froemling\n' 300 ' ' 301 + bui.Lstr(resource=f'{self._r}.allMyFamilyText') 302 .evaluate() 303 .replace('\n', '\n ') 304 + '\n' 305 ' ' 306 + bui.Lstr( 307 resource=f'{self._r}.whoeverInventedCoffeeText' 308 ).evaluate() 309 + '\n' 310 '\n' 311 ' ' + bui.Lstr(resource=f'{self._r}.legalText').evaluate() + '\n' 312 '\n' 313 ' ' 314 + bui.Lstr(resource=f'{self._r}.softwareBasedOnText') 315 .evaluate() 316 .replace('${NAME}', 'the Khronos Group') 317 + '\n' 318 '\n' 319 ' ' 320 ' www.ballistica.net\n' 321 ) 322 323 txt = credits_text 324 lines = txt.splitlines() 325 line_height = 20 326 327 scale = 0.55 328 self._sub_width = width - 80 329 self._sub_height = line_height * len(lines) + 40 330 331 container = self._subcontainer = bui.containerwidget( 332 parent=scroll, 333 size=(self._sub_width, self._sub_height), 334 background=False, 335 claims_left_right=False, 336 claims_tab=False, 337 ) 338 339 voffs = 0 340 for line in lines: 341 bui.textwidget( 342 parent=container, 343 padding=4, 344 color=(0.7, 0.9, 0.7, 1.0), 345 scale=scale, 346 flatness=1.0, 347 size=(0, 0), 348 position=(0, self._sub_height - 20 + voffs), 349 h_align='left', 350 v_align='top', 351 text=bui.Lstr(value=line), 352 ) 353 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.
355 @override 356 def get_main_window_state(self) -> bui.MainWindowState: 357 # Support recreating our window for back/refresh purposes. 358 cls = type(self) 359 return bui.BasicMainWindowState( 360 create_call=lambda transition, origin_widget: cls( 361 transition=transition, origin_widget=origin_widget 362 ) 363 )
Return a WindowState to recreate this window, if supported.