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.

@override
def get_main_window_state(self) -> bauiv1.MainWindowState:
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