bauiv1lib.play

Provides the top level play window.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Provides the top level play window."""
  4
  5from __future__ import annotations
  6
  7import logging
  8
  9import bascenev1 as bs
 10import bauiv1 as bui
 11
 12
 13class PlayWindow(bui.Window):
 14    """Window for selecting overall play type."""
 15
 16    def __init__(
 17        self,
 18        transition: str = 'in_right',
 19        origin_widget: bui.Widget | None = None,
 20    ):
 21        # pylint: disable=too-many-statements
 22        # pylint: disable=too-many-locals
 23        import threading
 24
 25        # Preload some modules we use in a background thread so we won't
 26        # have a visual hitch when the user taps them.
 27        threading.Thread(target=self._preload_modules).start()
 28
 29        # We can currently be used either for main menu duty or for selecting
 30        # playlists (should make this more elegant/general).
 31        assert bui.app.classic is not None
 32        self._is_main_menu = not bui.app.ui_v1.selecting_private_party_playlist
 33
 34        uiscale = bui.app.ui_v1.uiscale
 35        width = 1100 if uiscale is bui.UIScale.SMALL else 800
 36        x_offs = 150 if uiscale is bui.UIScale.SMALL else 0
 37        height = 550
 38        button_width = 400
 39
 40        scale_origin: tuple[float, float] | None
 41        if origin_widget is not None:
 42            self._transition_out = 'out_scale'
 43            scale_origin = origin_widget.get_screen_space_center()
 44            transition = 'in_scale'
 45        else:
 46            self._transition_out = 'out_right'
 47            scale_origin = None
 48
 49        self._r = 'playWindow'
 50
 51        super().__init__(
 52            root_widget=bui.containerwidget(
 53                size=(width, height),
 54                transition=transition,
 55                toolbar_visibility='menu_full',
 56                scale_origin_stack_offset=scale_origin,
 57                scale=(
 58                    1.6
 59                    if uiscale is bui.UIScale.SMALL
 60                    else 0.9 if uiscale is bui.UIScale.MEDIUM else 0.8
 61                ),
 62                stack_offset=(0, 0) if uiscale is bui.UIScale.SMALL else (0, 0),
 63            )
 64        )
 65        self._back_button = back_button = btn = bui.buttonwidget(
 66            parent=self._root_widget,
 67            position=(55 + x_offs, height - 132),
 68            size=(120, 60),
 69            scale=1.1,
 70            text_res_scale=1.5,
 71            text_scale=1.2,
 72            autoselect=True,
 73            label=bui.Lstr(resource='backText'),
 74            button_type='back',
 75        )
 76
 77        txt = bui.textwidget(
 78            parent=self._root_widget,
 79            position=(width * 0.5, height - 101),
 80            # position=(width * 0.5, height -
 81            #           (101 if main_menu else 61)),
 82            size=(0, 0),
 83            text=bui.Lstr(
 84                resource=(
 85                    (self._r + '.titleText')
 86                    if self._is_main_menu
 87                    else 'playlistsText'
 88                )
 89            ),
 90            scale=1.7,
 91            res_scale=2.0,
 92            maxwidth=400,
 93            color=bui.app.ui_v1.heading_color,
 94            h_align='center',
 95            v_align='center',
 96        )
 97
 98        bui.buttonwidget(
 99            edit=btn,
100            button_type='backSmall',
101            size=(60, 60),
102            label=bui.charstr(bui.SpecialChar.BACK),
103        )
104        if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
105            bui.textwidget(edit=txt, text='')
106
107        v = height - (110 if self._is_main_menu else 90)
108        v -= 100
109        clr = (0.6, 0.7, 0.6, 1.0)
110        v -= 280 if self._is_main_menu else 180
111        v += (
112            30
113            if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL
114            else 0
115        )
116        hoffs = x_offs + 80 if self._is_main_menu else x_offs - 100
117        scl = 1.13 if self._is_main_menu else 0.68
118
119        self._lineup_tex = bui.gettexture('playerLineup')
120        angry_computer_transparent_mesh = bui.getmesh(
121            'angryComputerTransparent'
122        )
123        self._lineup_1_transparent_mesh = bui.getmesh(
124            'playerLineup1Transparent'
125        )
126        self._lineup_2_transparent_mesh = bui.getmesh(
127            'playerLineup2Transparent'
128        )
129        self._lineup_3_transparent_mesh = bui.getmesh(
130            'playerLineup3Transparent'
131        )
132        self._lineup_4_transparent_mesh = bui.getmesh(
133            'playerLineup4Transparent'
134        )
135        self._eyes_mesh = bui.getmesh('plasticEyesTransparent')
136
137        self._coop_button: bui.Widget | None = None
138
139        # Only show coop button in main-menu variant.
140        if self._is_main_menu:
141            self._coop_button = btn = bui.buttonwidget(
142                parent=self._root_widget,
143                position=(hoffs, v + (scl * 15)),
144                size=(
145                    scl * button_width,
146                    scl * 300,
147                ),
148                extra_touch_border_scale=0.1,
149                autoselect=True,
150                label='',
151                button_type='square',
152                text_scale=1.13,
153                on_activate_call=self._coop,
154            )
155
156            if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
157                bui.widget(
158                    edit=btn,
159                    left_widget=bui.get_special_widget('back_button'),
160                )
161                bui.widget(
162                    edit=btn,
163                    up_widget=bui.get_special_widget('account_button'),
164                )
165                bui.widget(
166                    edit=btn,
167                    down_widget=bui.get_special_widget('settings_button'),
168                )
169
170            self._draw_dude(
171                0,
172                btn,
173                hoffs,
174                v,
175                scl,
176                position=(140, 30),
177                color=(0.72, 0.4, 1.0),
178            )
179            self._draw_dude(
180                1,
181                btn,
182                hoffs,
183                v,
184                scl,
185                position=(185, 53),
186                color=(0.71, 0.5, 1.0),
187            )
188            self._draw_dude(
189                2,
190                btn,
191                hoffs,
192                v,
193                scl,
194                position=(220, 27),
195                color=(0.67, 0.44, 1.0),
196            )
197            self._draw_dude(
198                3, btn, hoffs, v, scl, position=(255, 57), color=(0.7, 0.3, 1.0)
199            )
200            bui.imagewidget(
201                parent=self._root_widget,
202                draw_controller=btn,
203                position=(hoffs + scl * 230, v + scl * 153),
204                size=(scl * 115, scl * 115),
205                texture=self._lineup_tex,
206                mesh_transparent=angry_computer_transparent_mesh,
207            )
208
209            bui.textwidget(
210                parent=self._root_widget,
211                draw_controller=btn,
212                position=(hoffs + scl * (-10), v + scl * 95),
213                size=(scl * button_width, scl * 50),
214                text=bui.Lstr(
215                    resource='playModes.singlePlayerCoopText',
216                    fallback_resource='playModes.coopText',
217                ),
218                maxwidth=scl * button_width * 0.7,
219                res_scale=1.5,
220                h_align='center',
221                v_align='center',
222                color=(0.7, 0.9, 0.7, 1.0),
223                scale=scl * 2.3,
224            )
225
226            bui.textwidget(
227                parent=self._root_widget,
228                draw_controller=btn,
229                position=(hoffs + scl * (-10), v + (scl * 54)),
230                size=(scl * button_width, scl * 30),
231                text=bui.Lstr(resource=self._r + '.oneToFourPlayersText'),
232                h_align='center',
233                v_align='center',
234                scale=0.83 * scl,
235                flatness=1.0,
236                maxwidth=scl * button_width * 0.7,
237                color=clr,
238            )
239
240        scl = 0.5 if self._is_main_menu else 0.68
241        hoffs += 440 if self._is_main_menu else 216
242        v += 180 if self._is_main_menu else -68
243
244        self._teams_button = btn = bui.buttonwidget(
245            parent=self._root_widget,
246            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
247            size=(
248                scl * button_width,
249                scl * (300 if self._is_main_menu else 360),
250            ),
251            extra_touch_border_scale=0.1,
252            autoselect=True,
253            label='',
254            button_type='square',
255            text_scale=1.13,
256            on_activate_call=self._team_tourney,
257        )
258
259        if bui.app.ui_v1.use_toolbars:
260            bui.widget(
261                edit=btn,
262                up_widget=bui.get_special_widget('tickets_plus_button'),
263                right_widget=bui.get_special_widget('party_button'),
264            )
265
266        xxx = -14
267        self._draw_dude(
268            2,
269            btn,
270            hoffs,
271            v,
272            scl,
273            position=(xxx + 148, 30),
274            color=(0.2, 0.4, 1.0),
275        )
276        self._draw_dude(
277            3,
278            btn,
279            hoffs,
280            v,
281            scl,
282            position=(xxx + 181, 53),
283            color=(0.3, 0.4, 1.0),
284        )
285        self._draw_dude(
286            1,
287            btn,
288            hoffs,
289            v,
290            scl,
291            position=(xxx + 216, 33),
292            color=(0.3, 0.5, 1.0),
293        )
294        self._draw_dude(
295            0,
296            btn,
297            hoffs,
298            v,
299            scl,
300            position=(xxx + 245, 57),
301            color=(0.3, 0.5, 1.0),
302        )
303
304        xxx = 155
305        self._draw_dude(
306            0,
307            btn,
308            hoffs,
309            v,
310            scl,
311            position=(xxx + 151, 30),
312            color=(1.0, 0.5, 0.4),
313        )
314        self._draw_dude(
315            1,
316            btn,
317            hoffs,
318            v,
319            scl,
320            position=(xxx + 189, 53),
321            color=(1.0, 0.58, 0.58),
322        )
323        self._draw_dude(
324            3,
325            btn,
326            hoffs,
327            v,
328            scl,
329            position=(xxx + 223, 27),
330            color=(1.0, 0.5, 0.5),
331        )
332        self._draw_dude(
333            2,
334            btn,
335            hoffs,
336            v,
337            scl,
338            position=(xxx + 257, 57),
339            color=(1.0, 0.5, 0.5),
340        )
341
342        bui.textwidget(
343            parent=self._root_widget,
344            draw_controller=btn,
345            position=(hoffs + scl * (-10), v + scl * 95),
346            size=(scl * button_width, scl * 50),
347            text=bui.Lstr(
348                resource='playModes.teamsText', fallback_resource='teamsText'
349            ),
350            res_scale=1.5,
351            maxwidth=scl * button_width * 0.7,
352            h_align='center',
353            v_align='center',
354            color=(0.7, 0.9, 0.7, 1.0),
355            scale=scl * 2.3,
356        )
357        bui.textwidget(
358            parent=self._root_widget,
359            draw_controller=btn,
360            position=(hoffs + scl * (-10), v + (scl * 54)),
361            size=(scl * button_width, scl * 30),
362            text=bui.Lstr(resource=self._r + '.twoToEightPlayersText'),
363            h_align='center',
364            v_align='center',
365            res_scale=1.5,
366            scale=0.9 * scl,
367            flatness=1.0,
368            maxwidth=scl * button_width * 0.7,
369            color=clr,
370        )
371
372        hoffs += 0 if self._is_main_menu else 300
373        v -= 155 if self._is_main_menu else 0
374        self._free_for_all_button = btn = bui.buttonwidget(
375            parent=self._root_widget,
376            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
377            size=(
378                scl * button_width,
379                scl * (300 if self._is_main_menu else 360),
380            ),
381            extra_touch_border_scale=0.1,
382            autoselect=True,
383            label='',
384            button_type='square',
385            text_scale=1.13,
386            on_activate_call=self._free_for_all,
387        )
388
389        xxx = -5
390        self._draw_dude(
391            0,
392            btn,
393            hoffs,
394            v,
395            scl,
396            position=(xxx + 140, 30),
397            color=(0.4, 1.0, 0.4),
398        )
399        self._draw_dude(
400            3,
401            btn,
402            hoffs,
403            v,
404            scl,
405            position=(xxx + 185, 53),
406            color=(1.0, 0.4, 0.5),
407        )
408        self._draw_dude(
409            1,
410            btn,
411            hoffs,
412            v,
413            scl,
414            position=(xxx + 220, 27),
415            color=(0.4, 0.5, 1.0),
416        )
417        self._draw_dude(
418            2,
419            btn,
420            hoffs,
421            v,
422            scl,
423            position=(xxx + 255, 57),
424            color=(0.5, 1.0, 0.4),
425        )
426        xxx = 140
427        self._draw_dude(
428            2,
429            btn,
430            hoffs,
431            v,
432            scl,
433            position=(xxx + 148, 30),
434            color=(1.0, 0.9, 0.4),
435        )
436        self._draw_dude(
437            0,
438            btn,
439            hoffs,
440            v,
441            scl,
442            position=(xxx + 182, 53),
443            color=(0.7, 1.0, 0.5),
444        )
445        self._draw_dude(
446            3,
447            btn,
448            hoffs,
449            v,
450            scl,
451            position=(xxx + 233, 27),
452            color=(0.7, 0.5, 0.9),
453        )
454        self._draw_dude(
455            1,
456            btn,
457            hoffs,
458            v,
459            scl,
460            position=(xxx + 266, 53),
461            color=(0.4, 0.5, 0.8),
462        )
463        bui.textwidget(
464            parent=self._root_widget,
465            draw_controller=btn,
466            position=(hoffs + scl * (-10), v + scl * 95),
467            size=(scl * button_width, scl * 50),
468            text=bui.Lstr(
469                resource='playModes.freeForAllText',
470                fallback_resource='freeForAllText',
471            ),
472            maxwidth=scl * button_width * 0.7,
473            h_align='center',
474            v_align='center',
475            color=(0.7, 0.9, 0.7, 1.0),
476            scale=scl * 1.9,
477        )
478        bui.textwidget(
479            parent=self._root_widget,
480            draw_controller=btn,
481            position=(hoffs + scl * (-10), v + (scl * 54)),
482            size=(scl * button_width, scl * 30),
483            text=bui.Lstr(resource=self._r + '.twoToEightPlayersText'),
484            h_align='center',
485            v_align='center',
486            scale=0.9 * scl,
487            flatness=1.0,
488            maxwidth=scl * button_width * 0.7,
489            color=clr,
490        )
491
492        if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
493            back_button.delete()
494            bui.containerwidget(
495                edit=self._root_widget,
496                on_cancel_call=self._back,
497                selected_child=(
498                    self._coop_button
499                    if self._is_main_menu
500                    else self._teams_button
501                ),
502            )
503        else:
504            bui.buttonwidget(edit=back_button, on_activate_call=self._back)
505            bui.containerwidget(
506                edit=self._root_widget,
507                cancel_button=back_button,
508                selected_child=(
509                    self._coop_button
510                    if self._is_main_menu
511                    else self._teams_button
512                ),
513            )
514
515        self._restore_state()
516
517    # noinspection PyUnresolvedReferences
518    @staticmethod
519    def _preload_modules() -> None:
520        """Preload modules we use; avoids hitches (called in bg thread)."""
521        import bauiv1lib.mainmenu as _unused1
522        import bauiv1lib.account as _unused2
523        import bauiv1lib.coop.browser as _unused3
524        import bauiv1lib.playlist.browser as _unused4
525
526    def _back(self) -> None:
527        # pylint: disable=cyclic-import
528
529        # no-op if our underlying widget is dead or on its way out.
530        if not self._root_widget or self._root_widget.transitioning_out:
531            return
532
533        if self._is_main_menu:
534            from bauiv1lib.mainmenu import MainMenuWindow
535
536            self._save_state()
537            assert bui.app.classic is not None
538            bui.app.ui_v1.set_main_menu_window(
539                MainMenuWindow(transition='in_left').get_root_widget(),
540                from_window=self._root_widget,
541            )
542            bui.containerwidget(
543                edit=self._root_widget, transition=self._transition_out
544            )
545        else:
546            from bauiv1lib.gather import GatherWindow
547
548            self._save_state()
549            assert bui.app.classic is not None
550            bui.app.ui_v1.set_main_menu_window(
551                GatherWindow(transition='in_left').get_root_widget(),
552                from_window=self._root_widget,
553            )
554            bui.containerwidget(
555                edit=self._root_widget, transition=self._transition_out
556            )
557
558    def _coop(self) -> None:
559        # pylint: disable=cyclic-import
560        from bauiv1lib.account import show_sign_in_prompt
561        from bauiv1lib.coop.browser import CoopBrowserWindow
562
563        # no-op if our underlying widget is dead or on its way out.
564        if not self._root_widget or self._root_widget.transitioning_out:
565            return
566
567        plus = bui.app.plus
568        assert plus is not None
569
570        if plus.get_v1_account_state() != 'signed_in':
571            show_sign_in_prompt()
572            return
573        self._save_state()
574        bui.containerwidget(edit=self._root_widget, transition='out_left')
575        assert bui.app.classic is not None
576        bui.app.ui_v1.set_main_menu_window(
577            CoopBrowserWindow(
578                origin_widget=self._coop_button
579            ).get_root_widget(),
580            from_window=self._root_widget,
581        )
582
583    def _team_tourney(self) -> None:
584        # pylint: disable=cyclic-import
585        from bauiv1lib.playlist.browser import PlaylistBrowserWindow
586
587        # no-op if our underlying widget is dead or on its way out.
588        if not self._root_widget or self._root_widget.transitioning_out:
589            return
590
591        self._save_state()
592        bui.containerwidget(edit=self._root_widget, transition='out_left')
593        assert bui.app.classic is not None
594        bui.app.ui_v1.set_main_menu_window(
595            PlaylistBrowserWindow(
596                origin_widget=self._teams_button, sessiontype=bs.DualTeamSession
597            ).get_root_widget(),
598            from_window=self._root_widget,
599        )
600
601    def _free_for_all(self) -> None:
602        # pylint: disable=cyclic-import
603        from bauiv1lib.playlist.browser import PlaylistBrowserWindow
604
605        # no-op if our underlying widget is dead or on its way out.
606        if not self._root_widget or self._root_widget.transitioning_out:
607            return
608
609        self._save_state()
610        bui.containerwidget(edit=self._root_widget, transition='out_left')
611        assert bui.app.classic is not None
612        bui.app.ui_v1.set_main_menu_window(
613            PlaylistBrowserWindow(
614                origin_widget=self._free_for_all_button,
615                sessiontype=bs.FreeForAllSession,
616            ).get_root_widget(),
617            from_window=self._root_widget,
618        )
619
620    def _draw_dude(
621        self,
622        i: int,
623        btn: bui.Widget,
624        hoffs: float,
625        v: float,
626        scl: float,
627        position: tuple[float, float],
628        color: tuple[float, float, float],
629    ) -> None:
630        h_extra = -100
631        v_extra = 130
632        eye_color = (
633            0.7 * 1.0 + 0.3 * color[0],
634            0.7 * 1.0 + 0.3 * color[1],
635            0.7 * 1.0 + 0.3 * color[2],
636        )
637        if i == 0:
638            bui.imagewidget(
639                parent=self._root_widget,
640                draw_controller=btn,
641                position=(
642                    hoffs + scl * (h_extra + position[0]),
643                    v + scl * (v_extra + position[1]),
644                ),
645                size=(scl * 60, scl * 80),
646                color=color,
647                texture=self._lineup_tex,
648                mesh_transparent=self._lineup_1_transparent_mesh,
649            )
650            bui.imagewidget(
651                parent=self._root_widget,
652                draw_controller=btn,
653                position=(
654                    hoffs + scl * (h_extra + position[0] + 12),
655                    v + scl * (v_extra + position[1] + 53),
656                ),
657                size=(scl * 36, scl * 18),
658                texture=self._lineup_tex,
659                color=eye_color,
660                mesh_transparent=self._eyes_mesh,
661            )
662        elif i == 1:
663            bui.imagewidget(
664                parent=self._root_widget,
665                draw_controller=btn,
666                position=(
667                    hoffs + scl * (h_extra + position[0]),
668                    v + scl * (v_extra + position[1]),
669                ),
670                size=(scl * 45, scl * 90),
671                color=color,
672                texture=self._lineup_tex,
673                mesh_transparent=self._lineup_2_transparent_mesh,
674            )
675            bui.imagewidget(
676                parent=self._root_widget,
677                draw_controller=btn,
678                position=(
679                    hoffs + scl * (h_extra + position[0] + 5),
680                    v + scl * (v_extra + position[1] + 67),
681                ),
682                size=(scl * 32, scl * 16),
683                texture=self._lineup_tex,
684                color=eye_color,
685                mesh_transparent=self._eyes_mesh,
686            )
687        elif i == 2:
688            bui.imagewidget(
689                parent=self._root_widget,
690                draw_controller=btn,
691                position=(
692                    hoffs + scl * (h_extra + position[0]),
693                    v + scl * (v_extra + position[1]),
694                ),
695                size=(scl * 45, scl * 90),
696                color=color,
697                texture=self._lineup_tex,
698                mesh_transparent=self._lineup_3_transparent_mesh,
699            )
700            bui.imagewidget(
701                parent=self._root_widget,
702                draw_controller=btn,
703                position=(
704                    hoffs + scl * (h_extra + position[0] + 5),
705                    v + scl * (v_extra + position[1] + 59),
706                ),
707                size=(scl * 34, scl * 17),
708                texture=self._lineup_tex,
709                color=eye_color,
710                mesh_transparent=self._eyes_mesh,
711            )
712        elif i == 3:
713            bui.imagewidget(
714                parent=self._root_widget,
715                draw_controller=btn,
716                position=(
717                    hoffs + scl * (h_extra + position[0]),
718                    v + scl * (v_extra + position[1]),
719                ),
720                size=(scl * 48, scl * 96),
721                color=color,
722                texture=self._lineup_tex,
723                mesh_transparent=self._lineup_4_transparent_mesh,
724            )
725            bui.imagewidget(
726                parent=self._root_widget,
727                draw_controller=btn,
728                position=(
729                    hoffs + scl * (h_extra + position[0] + 2),
730                    v + scl * (v_extra + position[1] + 62),
731                ),
732                size=(scl * 38, scl * 19),
733                texture=self._lineup_tex,
734                color=eye_color,
735                mesh_transparent=self._eyes_mesh,
736            )
737
738    def _save_state(self) -> None:
739        try:
740            sel = self._root_widget.get_selected_child()
741            if sel == self._teams_button:
742                sel_name = 'Team Games'
743            elif self._coop_button is not None and sel == self._coop_button:
744                sel_name = 'Co-op Games'
745            elif sel == self._free_for_all_button:
746                sel_name = 'Free-for-All Games'
747            elif sel == self._back_button:
748                sel_name = 'Back'
749            else:
750                raise ValueError(f'unrecognized selection {sel}')
751            assert bui.app.classic is not None
752            bui.app.ui_v1.window_states[type(self)] = sel_name
753        except Exception:
754            logging.exception('Error saving state for %s.', self)
755
756    def _restore_state(self) -> None:
757        try:
758            assert bui.app.classic is not None
759            sel_name = bui.app.ui_v1.window_states.get(type(self))
760            if sel_name == 'Team Games':
761                sel = self._teams_button
762            elif sel_name == 'Co-op Games' and self._coop_button is not None:
763                sel = self._coop_button
764            elif sel_name == 'Free-for-All Games':
765                sel = self._free_for_all_button
766            elif sel_name == 'Back':
767                sel = self._back_button
768            else:
769                sel = (
770                    self._coop_button
771                    if self._coop_button is not None
772                    else self._teams_button
773                )
774            bui.containerwidget(edit=self._root_widget, selected_child=sel)
775        except Exception:
776            logging.exception('Error restoring state for %s.', self)
class PlayWindow(bauiv1._uitypes.Window):
 14class PlayWindow(bui.Window):
 15    """Window for selecting overall play type."""
 16
 17    def __init__(
 18        self,
 19        transition: str = 'in_right',
 20        origin_widget: bui.Widget | None = None,
 21    ):
 22        # pylint: disable=too-many-statements
 23        # pylint: disable=too-many-locals
 24        import threading
 25
 26        # Preload some modules we use in a background thread so we won't
 27        # have a visual hitch when the user taps them.
 28        threading.Thread(target=self._preload_modules).start()
 29
 30        # We can currently be used either for main menu duty or for selecting
 31        # playlists (should make this more elegant/general).
 32        assert bui.app.classic is not None
 33        self._is_main_menu = not bui.app.ui_v1.selecting_private_party_playlist
 34
 35        uiscale = bui.app.ui_v1.uiscale
 36        width = 1100 if uiscale is bui.UIScale.SMALL else 800
 37        x_offs = 150 if uiscale is bui.UIScale.SMALL else 0
 38        height = 550
 39        button_width = 400
 40
 41        scale_origin: tuple[float, float] | None
 42        if origin_widget is not None:
 43            self._transition_out = 'out_scale'
 44            scale_origin = origin_widget.get_screen_space_center()
 45            transition = 'in_scale'
 46        else:
 47            self._transition_out = 'out_right'
 48            scale_origin = None
 49
 50        self._r = 'playWindow'
 51
 52        super().__init__(
 53            root_widget=bui.containerwidget(
 54                size=(width, height),
 55                transition=transition,
 56                toolbar_visibility='menu_full',
 57                scale_origin_stack_offset=scale_origin,
 58                scale=(
 59                    1.6
 60                    if uiscale is bui.UIScale.SMALL
 61                    else 0.9 if uiscale is bui.UIScale.MEDIUM else 0.8
 62                ),
 63                stack_offset=(0, 0) if uiscale is bui.UIScale.SMALL else (0, 0),
 64            )
 65        )
 66        self._back_button = back_button = btn = bui.buttonwidget(
 67            parent=self._root_widget,
 68            position=(55 + x_offs, height - 132),
 69            size=(120, 60),
 70            scale=1.1,
 71            text_res_scale=1.5,
 72            text_scale=1.2,
 73            autoselect=True,
 74            label=bui.Lstr(resource='backText'),
 75            button_type='back',
 76        )
 77
 78        txt = bui.textwidget(
 79            parent=self._root_widget,
 80            position=(width * 0.5, height - 101),
 81            # position=(width * 0.5, height -
 82            #           (101 if main_menu else 61)),
 83            size=(0, 0),
 84            text=bui.Lstr(
 85                resource=(
 86                    (self._r + '.titleText')
 87                    if self._is_main_menu
 88                    else 'playlistsText'
 89                )
 90            ),
 91            scale=1.7,
 92            res_scale=2.0,
 93            maxwidth=400,
 94            color=bui.app.ui_v1.heading_color,
 95            h_align='center',
 96            v_align='center',
 97        )
 98
 99        bui.buttonwidget(
100            edit=btn,
101            button_type='backSmall',
102            size=(60, 60),
103            label=bui.charstr(bui.SpecialChar.BACK),
104        )
105        if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
106            bui.textwidget(edit=txt, text='')
107
108        v = height - (110 if self._is_main_menu else 90)
109        v -= 100
110        clr = (0.6, 0.7, 0.6, 1.0)
111        v -= 280 if self._is_main_menu else 180
112        v += (
113            30
114            if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL
115            else 0
116        )
117        hoffs = x_offs + 80 if self._is_main_menu else x_offs - 100
118        scl = 1.13 if self._is_main_menu else 0.68
119
120        self._lineup_tex = bui.gettexture('playerLineup')
121        angry_computer_transparent_mesh = bui.getmesh(
122            'angryComputerTransparent'
123        )
124        self._lineup_1_transparent_mesh = bui.getmesh(
125            'playerLineup1Transparent'
126        )
127        self._lineup_2_transparent_mesh = bui.getmesh(
128            'playerLineup2Transparent'
129        )
130        self._lineup_3_transparent_mesh = bui.getmesh(
131            'playerLineup3Transparent'
132        )
133        self._lineup_4_transparent_mesh = bui.getmesh(
134            'playerLineup4Transparent'
135        )
136        self._eyes_mesh = bui.getmesh('plasticEyesTransparent')
137
138        self._coop_button: bui.Widget | None = None
139
140        # Only show coop button in main-menu variant.
141        if self._is_main_menu:
142            self._coop_button = btn = bui.buttonwidget(
143                parent=self._root_widget,
144                position=(hoffs, v + (scl * 15)),
145                size=(
146                    scl * button_width,
147                    scl * 300,
148                ),
149                extra_touch_border_scale=0.1,
150                autoselect=True,
151                label='',
152                button_type='square',
153                text_scale=1.13,
154                on_activate_call=self._coop,
155            )
156
157            if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
158                bui.widget(
159                    edit=btn,
160                    left_widget=bui.get_special_widget('back_button'),
161                )
162                bui.widget(
163                    edit=btn,
164                    up_widget=bui.get_special_widget('account_button'),
165                )
166                bui.widget(
167                    edit=btn,
168                    down_widget=bui.get_special_widget('settings_button'),
169                )
170
171            self._draw_dude(
172                0,
173                btn,
174                hoffs,
175                v,
176                scl,
177                position=(140, 30),
178                color=(0.72, 0.4, 1.0),
179            )
180            self._draw_dude(
181                1,
182                btn,
183                hoffs,
184                v,
185                scl,
186                position=(185, 53),
187                color=(0.71, 0.5, 1.0),
188            )
189            self._draw_dude(
190                2,
191                btn,
192                hoffs,
193                v,
194                scl,
195                position=(220, 27),
196                color=(0.67, 0.44, 1.0),
197            )
198            self._draw_dude(
199                3, btn, hoffs, v, scl, position=(255, 57), color=(0.7, 0.3, 1.0)
200            )
201            bui.imagewidget(
202                parent=self._root_widget,
203                draw_controller=btn,
204                position=(hoffs + scl * 230, v + scl * 153),
205                size=(scl * 115, scl * 115),
206                texture=self._lineup_tex,
207                mesh_transparent=angry_computer_transparent_mesh,
208            )
209
210            bui.textwidget(
211                parent=self._root_widget,
212                draw_controller=btn,
213                position=(hoffs + scl * (-10), v + scl * 95),
214                size=(scl * button_width, scl * 50),
215                text=bui.Lstr(
216                    resource='playModes.singlePlayerCoopText',
217                    fallback_resource='playModes.coopText',
218                ),
219                maxwidth=scl * button_width * 0.7,
220                res_scale=1.5,
221                h_align='center',
222                v_align='center',
223                color=(0.7, 0.9, 0.7, 1.0),
224                scale=scl * 2.3,
225            )
226
227            bui.textwidget(
228                parent=self._root_widget,
229                draw_controller=btn,
230                position=(hoffs + scl * (-10), v + (scl * 54)),
231                size=(scl * button_width, scl * 30),
232                text=bui.Lstr(resource=self._r + '.oneToFourPlayersText'),
233                h_align='center',
234                v_align='center',
235                scale=0.83 * scl,
236                flatness=1.0,
237                maxwidth=scl * button_width * 0.7,
238                color=clr,
239            )
240
241        scl = 0.5 if self._is_main_menu else 0.68
242        hoffs += 440 if self._is_main_menu else 216
243        v += 180 if self._is_main_menu else -68
244
245        self._teams_button = btn = bui.buttonwidget(
246            parent=self._root_widget,
247            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
248            size=(
249                scl * button_width,
250                scl * (300 if self._is_main_menu else 360),
251            ),
252            extra_touch_border_scale=0.1,
253            autoselect=True,
254            label='',
255            button_type='square',
256            text_scale=1.13,
257            on_activate_call=self._team_tourney,
258        )
259
260        if bui.app.ui_v1.use_toolbars:
261            bui.widget(
262                edit=btn,
263                up_widget=bui.get_special_widget('tickets_plus_button'),
264                right_widget=bui.get_special_widget('party_button'),
265            )
266
267        xxx = -14
268        self._draw_dude(
269            2,
270            btn,
271            hoffs,
272            v,
273            scl,
274            position=(xxx + 148, 30),
275            color=(0.2, 0.4, 1.0),
276        )
277        self._draw_dude(
278            3,
279            btn,
280            hoffs,
281            v,
282            scl,
283            position=(xxx + 181, 53),
284            color=(0.3, 0.4, 1.0),
285        )
286        self._draw_dude(
287            1,
288            btn,
289            hoffs,
290            v,
291            scl,
292            position=(xxx + 216, 33),
293            color=(0.3, 0.5, 1.0),
294        )
295        self._draw_dude(
296            0,
297            btn,
298            hoffs,
299            v,
300            scl,
301            position=(xxx + 245, 57),
302            color=(0.3, 0.5, 1.0),
303        )
304
305        xxx = 155
306        self._draw_dude(
307            0,
308            btn,
309            hoffs,
310            v,
311            scl,
312            position=(xxx + 151, 30),
313            color=(1.0, 0.5, 0.4),
314        )
315        self._draw_dude(
316            1,
317            btn,
318            hoffs,
319            v,
320            scl,
321            position=(xxx + 189, 53),
322            color=(1.0, 0.58, 0.58),
323        )
324        self._draw_dude(
325            3,
326            btn,
327            hoffs,
328            v,
329            scl,
330            position=(xxx + 223, 27),
331            color=(1.0, 0.5, 0.5),
332        )
333        self._draw_dude(
334            2,
335            btn,
336            hoffs,
337            v,
338            scl,
339            position=(xxx + 257, 57),
340            color=(1.0, 0.5, 0.5),
341        )
342
343        bui.textwidget(
344            parent=self._root_widget,
345            draw_controller=btn,
346            position=(hoffs + scl * (-10), v + scl * 95),
347            size=(scl * button_width, scl * 50),
348            text=bui.Lstr(
349                resource='playModes.teamsText', fallback_resource='teamsText'
350            ),
351            res_scale=1.5,
352            maxwidth=scl * button_width * 0.7,
353            h_align='center',
354            v_align='center',
355            color=(0.7, 0.9, 0.7, 1.0),
356            scale=scl * 2.3,
357        )
358        bui.textwidget(
359            parent=self._root_widget,
360            draw_controller=btn,
361            position=(hoffs + scl * (-10), v + (scl * 54)),
362            size=(scl * button_width, scl * 30),
363            text=bui.Lstr(resource=self._r + '.twoToEightPlayersText'),
364            h_align='center',
365            v_align='center',
366            res_scale=1.5,
367            scale=0.9 * scl,
368            flatness=1.0,
369            maxwidth=scl * button_width * 0.7,
370            color=clr,
371        )
372
373        hoffs += 0 if self._is_main_menu else 300
374        v -= 155 if self._is_main_menu else 0
375        self._free_for_all_button = btn = bui.buttonwidget(
376            parent=self._root_widget,
377            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
378            size=(
379                scl * button_width,
380                scl * (300 if self._is_main_menu else 360),
381            ),
382            extra_touch_border_scale=0.1,
383            autoselect=True,
384            label='',
385            button_type='square',
386            text_scale=1.13,
387            on_activate_call=self._free_for_all,
388        )
389
390        xxx = -5
391        self._draw_dude(
392            0,
393            btn,
394            hoffs,
395            v,
396            scl,
397            position=(xxx + 140, 30),
398            color=(0.4, 1.0, 0.4),
399        )
400        self._draw_dude(
401            3,
402            btn,
403            hoffs,
404            v,
405            scl,
406            position=(xxx + 185, 53),
407            color=(1.0, 0.4, 0.5),
408        )
409        self._draw_dude(
410            1,
411            btn,
412            hoffs,
413            v,
414            scl,
415            position=(xxx + 220, 27),
416            color=(0.4, 0.5, 1.0),
417        )
418        self._draw_dude(
419            2,
420            btn,
421            hoffs,
422            v,
423            scl,
424            position=(xxx + 255, 57),
425            color=(0.5, 1.0, 0.4),
426        )
427        xxx = 140
428        self._draw_dude(
429            2,
430            btn,
431            hoffs,
432            v,
433            scl,
434            position=(xxx + 148, 30),
435            color=(1.0, 0.9, 0.4),
436        )
437        self._draw_dude(
438            0,
439            btn,
440            hoffs,
441            v,
442            scl,
443            position=(xxx + 182, 53),
444            color=(0.7, 1.0, 0.5),
445        )
446        self._draw_dude(
447            3,
448            btn,
449            hoffs,
450            v,
451            scl,
452            position=(xxx + 233, 27),
453            color=(0.7, 0.5, 0.9),
454        )
455        self._draw_dude(
456            1,
457            btn,
458            hoffs,
459            v,
460            scl,
461            position=(xxx + 266, 53),
462            color=(0.4, 0.5, 0.8),
463        )
464        bui.textwidget(
465            parent=self._root_widget,
466            draw_controller=btn,
467            position=(hoffs + scl * (-10), v + scl * 95),
468            size=(scl * button_width, scl * 50),
469            text=bui.Lstr(
470                resource='playModes.freeForAllText',
471                fallback_resource='freeForAllText',
472            ),
473            maxwidth=scl * button_width * 0.7,
474            h_align='center',
475            v_align='center',
476            color=(0.7, 0.9, 0.7, 1.0),
477            scale=scl * 1.9,
478        )
479        bui.textwidget(
480            parent=self._root_widget,
481            draw_controller=btn,
482            position=(hoffs + scl * (-10), v + (scl * 54)),
483            size=(scl * button_width, scl * 30),
484            text=bui.Lstr(resource=self._r + '.twoToEightPlayersText'),
485            h_align='center',
486            v_align='center',
487            scale=0.9 * scl,
488            flatness=1.0,
489            maxwidth=scl * button_width * 0.7,
490            color=clr,
491        )
492
493        if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
494            back_button.delete()
495            bui.containerwidget(
496                edit=self._root_widget,
497                on_cancel_call=self._back,
498                selected_child=(
499                    self._coop_button
500                    if self._is_main_menu
501                    else self._teams_button
502                ),
503            )
504        else:
505            bui.buttonwidget(edit=back_button, on_activate_call=self._back)
506            bui.containerwidget(
507                edit=self._root_widget,
508                cancel_button=back_button,
509                selected_child=(
510                    self._coop_button
511                    if self._is_main_menu
512                    else self._teams_button
513                ),
514            )
515
516        self._restore_state()
517
518    # noinspection PyUnresolvedReferences
519    @staticmethod
520    def _preload_modules() -> None:
521        """Preload modules we use; avoids hitches (called in bg thread)."""
522        import bauiv1lib.mainmenu as _unused1
523        import bauiv1lib.account as _unused2
524        import bauiv1lib.coop.browser as _unused3
525        import bauiv1lib.playlist.browser as _unused4
526
527    def _back(self) -> None:
528        # pylint: disable=cyclic-import
529
530        # no-op if our underlying widget is dead or on its way out.
531        if not self._root_widget or self._root_widget.transitioning_out:
532            return
533
534        if self._is_main_menu:
535            from bauiv1lib.mainmenu import MainMenuWindow
536
537            self._save_state()
538            assert bui.app.classic is not None
539            bui.app.ui_v1.set_main_menu_window(
540                MainMenuWindow(transition='in_left').get_root_widget(),
541                from_window=self._root_widget,
542            )
543            bui.containerwidget(
544                edit=self._root_widget, transition=self._transition_out
545            )
546        else:
547            from bauiv1lib.gather import GatherWindow
548
549            self._save_state()
550            assert bui.app.classic is not None
551            bui.app.ui_v1.set_main_menu_window(
552                GatherWindow(transition='in_left').get_root_widget(),
553                from_window=self._root_widget,
554            )
555            bui.containerwidget(
556                edit=self._root_widget, transition=self._transition_out
557            )
558
559    def _coop(self) -> None:
560        # pylint: disable=cyclic-import
561        from bauiv1lib.account import show_sign_in_prompt
562        from bauiv1lib.coop.browser import CoopBrowserWindow
563
564        # no-op if our underlying widget is dead or on its way out.
565        if not self._root_widget or self._root_widget.transitioning_out:
566            return
567
568        plus = bui.app.plus
569        assert plus is not None
570
571        if plus.get_v1_account_state() != 'signed_in':
572            show_sign_in_prompt()
573            return
574        self._save_state()
575        bui.containerwidget(edit=self._root_widget, transition='out_left')
576        assert bui.app.classic is not None
577        bui.app.ui_v1.set_main_menu_window(
578            CoopBrowserWindow(
579                origin_widget=self._coop_button
580            ).get_root_widget(),
581            from_window=self._root_widget,
582        )
583
584    def _team_tourney(self) -> None:
585        # pylint: disable=cyclic-import
586        from bauiv1lib.playlist.browser import PlaylistBrowserWindow
587
588        # no-op if our underlying widget is dead or on its way out.
589        if not self._root_widget or self._root_widget.transitioning_out:
590            return
591
592        self._save_state()
593        bui.containerwidget(edit=self._root_widget, transition='out_left')
594        assert bui.app.classic is not None
595        bui.app.ui_v1.set_main_menu_window(
596            PlaylistBrowserWindow(
597                origin_widget=self._teams_button, sessiontype=bs.DualTeamSession
598            ).get_root_widget(),
599            from_window=self._root_widget,
600        )
601
602    def _free_for_all(self) -> None:
603        # pylint: disable=cyclic-import
604        from bauiv1lib.playlist.browser import PlaylistBrowserWindow
605
606        # no-op if our underlying widget is dead or on its way out.
607        if not self._root_widget or self._root_widget.transitioning_out:
608            return
609
610        self._save_state()
611        bui.containerwidget(edit=self._root_widget, transition='out_left')
612        assert bui.app.classic is not None
613        bui.app.ui_v1.set_main_menu_window(
614            PlaylistBrowserWindow(
615                origin_widget=self._free_for_all_button,
616                sessiontype=bs.FreeForAllSession,
617            ).get_root_widget(),
618            from_window=self._root_widget,
619        )
620
621    def _draw_dude(
622        self,
623        i: int,
624        btn: bui.Widget,
625        hoffs: float,
626        v: float,
627        scl: float,
628        position: tuple[float, float],
629        color: tuple[float, float, float],
630    ) -> None:
631        h_extra = -100
632        v_extra = 130
633        eye_color = (
634            0.7 * 1.0 + 0.3 * color[0],
635            0.7 * 1.0 + 0.3 * color[1],
636            0.7 * 1.0 + 0.3 * color[2],
637        )
638        if i == 0:
639            bui.imagewidget(
640                parent=self._root_widget,
641                draw_controller=btn,
642                position=(
643                    hoffs + scl * (h_extra + position[0]),
644                    v + scl * (v_extra + position[1]),
645                ),
646                size=(scl * 60, scl * 80),
647                color=color,
648                texture=self._lineup_tex,
649                mesh_transparent=self._lineup_1_transparent_mesh,
650            )
651            bui.imagewidget(
652                parent=self._root_widget,
653                draw_controller=btn,
654                position=(
655                    hoffs + scl * (h_extra + position[0] + 12),
656                    v + scl * (v_extra + position[1] + 53),
657                ),
658                size=(scl * 36, scl * 18),
659                texture=self._lineup_tex,
660                color=eye_color,
661                mesh_transparent=self._eyes_mesh,
662            )
663        elif i == 1:
664            bui.imagewidget(
665                parent=self._root_widget,
666                draw_controller=btn,
667                position=(
668                    hoffs + scl * (h_extra + position[0]),
669                    v + scl * (v_extra + position[1]),
670                ),
671                size=(scl * 45, scl * 90),
672                color=color,
673                texture=self._lineup_tex,
674                mesh_transparent=self._lineup_2_transparent_mesh,
675            )
676            bui.imagewidget(
677                parent=self._root_widget,
678                draw_controller=btn,
679                position=(
680                    hoffs + scl * (h_extra + position[0] + 5),
681                    v + scl * (v_extra + position[1] + 67),
682                ),
683                size=(scl * 32, scl * 16),
684                texture=self._lineup_tex,
685                color=eye_color,
686                mesh_transparent=self._eyes_mesh,
687            )
688        elif i == 2:
689            bui.imagewidget(
690                parent=self._root_widget,
691                draw_controller=btn,
692                position=(
693                    hoffs + scl * (h_extra + position[0]),
694                    v + scl * (v_extra + position[1]),
695                ),
696                size=(scl * 45, scl * 90),
697                color=color,
698                texture=self._lineup_tex,
699                mesh_transparent=self._lineup_3_transparent_mesh,
700            )
701            bui.imagewidget(
702                parent=self._root_widget,
703                draw_controller=btn,
704                position=(
705                    hoffs + scl * (h_extra + position[0] + 5),
706                    v + scl * (v_extra + position[1] + 59),
707                ),
708                size=(scl * 34, scl * 17),
709                texture=self._lineup_tex,
710                color=eye_color,
711                mesh_transparent=self._eyes_mesh,
712            )
713        elif i == 3:
714            bui.imagewidget(
715                parent=self._root_widget,
716                draw_controller=btn,
717                position=(
718                    hoffs + scl * (h_extra + position[0]),
719                    v + scl * (v_extra + position[1]),
720                ),
721                size=(scl * 48, scl * 96),
722                color=color,
723                texture=self._lineup_tex,
724                mesh_transparent=self._lineup_4_transparent_mesh,
725            )
726            bui.imagewidget(
727                parent=self._root_widget,
728                draw_controller=btn,
729                position=(
730                    hoffs + scl * (h_extra + position[0] + 2),
731                    v + scl * (v_extra + position[1] + 62),
732                ),
733                size=(scl * 38, scl * 19),
734                texture=self._lineup_tex,
735                color=eye_color,
736                mesh_transparent=self._eyes_mesh,
737            )
738
739    def _save_state(self) -> None:
740        try:
741            sel = self._root_widget.get_selected_child()
742            if sel == self._teams_button:
743                sel_name = 'Team Games'
744            elif self._coop_button is not None and sel == self._coop_button:
745                sel_name = 'Co-op Games'
746            elif sel == self._free_for_all_button:
747                sel_name = 'Free-for-All Games'
748            elif sel == self._back_button:
749                sel_name = 'Back'
750            else:
751                raise ValueError(f'unrecognized selection {sel}')
752            assert bui.app.classic is not None
753            bui.app.ui_v1.window_states[type(self)] = sel_name
754        except Exception:
755            logging.exception('Error saving state for %s.', self)
756
757    def _restore_state(self) -> None:
758        try:
759            assert bui.app.classic is not None
760            sel_name = bui.app.ui_v1.window_states.get(type(self))
761            if sel_name == 'Team Games':
762                sel = self._teams_button
763            elif sel_name == 'Co-op Games' and self._coop_button is not None:
764                sel = self._coop_button
765            elif sel_name == 'Free-for-All Games':
766                sel = self._free_for_all_button
767            elif sel_name == 'Back':
768                sel = self._back_button
769            else:
770                sel = (
771                    self._coop_button
772                    if self._coop_button is not None
773                    else self._teams_button
774                )
775            bui.containerwidget(edit=self._root_widget, selected_child=sel)
776        except Exception:
777            logging.exception('Error restoring state for %s.', self)

Window for selecting overall play type.

PlayWindow( transition: str = 'in_right', origin_widget: _bauiv1.Widget | None = None)
 17    def __init__(
 18        self,
 19        transition: str = 'in_right',
 20        origin_widget: bui.Widget | None = None,
 21    ):
 22        # pylint: disable=too-many-statements
 23        # pylint: disable=too-many-locals
 24        import threading
 25
 26        # Preload some modules we use in a background thread so we won't
 27        # have a visual hitch when the user taps them.
 28        threading.Thread(target=self._preload_modules).start()
 29
 30        # We can currently be used either for main menu duty or for selecting
 31        # playlists (should make this more elegant/general).
 32        assert bui.app.classic is not None
 33        self._is_main_menu = not bui.app.ui_v1.selecting_private_party_playlist
 34
 35        uiscale = bui.app.ui_v1.uiscale
 36        width = 1100 if uiscale is bui.UIScale.SMALL else 800
 37        x_offs = 150 if uiscale is bui.UIScale.SMALL else 0
 38        height = 550
 39        button_width = 400
 40
 41        scale_origin: tuple[float, float] | None
 42        if origin_widget is not None:
 43            self._transition_out = 'out_scale'
 44            scale_origin = origin_widget.get_screen_space_center()
 45            transition = 'in_scale'
 46        else:
 47            self._transition_out = 'out_right'
 48            scale_origin = None
 49
 50        self._r = 'playWindow'
 51
 52        super().__init__(
 53            root_widget=bui.containerwidget(
 54                size=(width, height),
 55                transition=transition,
 56                toolbar_visibility='menu_full',
 57                scale_origin_stack_offset=scale_origin,
 58                scale=(
 59                    1.6
 60                    if uiscale is bui.UIScale.SMALL
 61                    else 0.9 if uiscale is bui.UIScale.MEDIUM else 0.8
 62                ),
 63                stack_offset=(0, 0) if uiscale is bui.UIScale.SMALL else (0, 0),
 64            )
 65        )
 66        self._back_button = back_button = btn = bui.buttonwidget(
 67            parent=self._root_widget,
 68            position=(55 + x_offs, height - 132),
 69            size=(120, 60),
 70            scale=1.1,
 71            text_res_scale=1.5,
 72            text_scale=1.2,
 73            autoselect=True,
 74            label=bui.Lstr(resource='backText'),
 75            button_type='back',
 76        )
 77
 78        txt = bui.textwidget(
 79            parent=self._root_widget,
 80            position=(width * 0.5, height - 101),
 81            # position=(width * 0.5, height -
 82            #           (101 if main_menu else 61)),
 83            size=(0, 0),
 84            text=bui.Lstr(
 85                resource=(
 86                    (self._r + '.titleText')
 87                    if self._is_main_menu
 88                    else 'playlistsText'
 89                )
 90            ),
 91            scale=1.7,
 92            res_scale=2.0,
 93            maxwidth=400,
 94            color=bui.app.ui_v1.heading_color,
 95            h_align='center',
 96            v_align='center',
 97        )
 98
 99        bui.buttonwidget(
100            edit=btn,
101            button_type='backSmall',
102            size=(60, 60),
103            label=bui.charstr(bui.SpecialChar.BACK),
104        )
105        if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
106            bui.textwidget(edit=txt, text='')
107
108        v = height - (110 if self._is_main_menu else 90)
109        v -= 100
110        clr = (0.6, 0.7, 0.6, 1.0)
111        v -= 280 if self._is_main_menu else 180
112        v += (
113            30
114            if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL
115            else 0
116        )
117        hoffs = x_offs + 80 if self._is_main_menu else x_offs - 100
118        scl = 1.13 if self._is_main_menu else 0.68
119
120        self._lineup_tex = bui.gettexture('playerLineup')
121        angry_computer_transparent_mesh = bui.getmesh(
122            'angryComputerTransparent'
123        )
124        self._lineup_1_transparent_mesh = bui.getmesh(
125            'playerLineup1Transparent'
126        )
127        self._lineup_2_transparent_mesh = bui.getmesh(
128            'playerLineup2Transparent'
129        )
130        self._lineup_3_transparent_mesh = bui.getmesh(
131            'playerLineup3Transparent'
132        )
133        self._lineup_4_transparent_mesh = bui.getmesh(
134            'playerLineup4Transparent'
135        )
136        self._eyes_mesh = bui.getmesh('plasticEyesTransparent')
137
138        self._coop_button: bui.Widget | None = None
139
140        # Only show coop button in main-menu variant.
141        if self._is_main_menu:
142            self._coop_button = btn = bui.buttonwidget(
143                parent=self._root_widget,
144                position=(hoffs, v + (scl * 15)),
145                size=(
146                    scl * button_width,
147                    scl * 300,
148                ),
149                extra_touch_border_scale=0.1,
150                autoselect=True,
151                label='',
152                button_type='square',
153                text_scale=1.13,
154                on_activate_call=self._coop,
155            )
156
157            if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
158                bui.widget(
159                    edit=btn,
160                    left_widget=bui.get_special_widget('back_button'),
161                )
162                bui.widget(
163                    edit=btn,
164                    up_widget=bui.get_special_widget('account_button'),
165                )
166                bui.widget(
167                    edit=btn,
168                    down_widget=bui.get_special_widget('settings_button'),
169                )
170
171            self._draw_dude(
172                0,
173                btn,
174                hoffs,
175                v,
176                scl,
177                position=(140, 30),
178                color=(0.72, 0.4, 1.0),
179            )
180            self._draw_dude(
181                1,
182                btn,
183                hoffs,
184                v,
185                scl,
186                position=(185, 53),
187                color=(0.71, 0.5, 1.0),
188            )
189            self._draw_dude(
190                2,
191                btn,
192                hoffs,
193                v,
194                scl,
195                position=(220, 27),
196                color=(0.67, 0.44, 1.0),
197            )
198            self._draw_dude(
199                3, btn, hoffs, v, scl, position=(255, 57), color=(0.7, 0.3, 1.0)
200            )
201            bui.imagewidget(
202                parent=self._root_widget,
203                draw_controller=btn,
204                position=(hoffs + scl * 230, v + scl * 153),
205                size=(scl * 115, scl * 115),
206                texture=self._lineup_tex,
207                mesh_transparent=angry_computer_transparent_mesh,
208            )
209
210            bui.textwidget(
211                parent=self._root_widget,
212                draw_controller=btn,
213                position=(hoffs + scl * (-10), v + scl * 95),
214                size=(scl * button_width, scl * 50),
215                text=bui.Lstr(
216                    resource='playModes.singlePlayerCoopText',
217                    fallback_resource='playModes.coopText',
218                ),
219                maxwidth=scl * button_width * 0.7,
220                res_scale=1.5,
221                h_align='center',
222                v_align='center',
223                color=(0.7, 0.9, 0.7, 1.0),
224                scale=scl * 2.3,
225            )
226
227            bui.textwidget(
228                parent=self._root_widget,
229                draw_controller=btn,
230                position=(hoffs + scl * (-10), v + (scl * 54)),
231                size=(scl * button_width, scl * 30),
232                text=bui.Lstr(resource=self._r + '.oneToFourPlayersText'),
233                h_align='center',
234                v_align='center',
235                scale=0.83 * scl,
236                flatness=1.0,
237                maxwidth=scl * button_width * 0.7,
238                color=clr,
239            )
240
241        scl = 0.5 if self._is_main_menu else 0.68
242        hoffs += 440 if self._is_main_menu else 216
243        v += 180 if self._is_main_menu else -68
244
245        self._teams_button = btn = bui.buttonwidget(
246            parent=self._root_widget,
247            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
248            size=(
249                scl * button_width,
250                scl * (300 if self._is_main_menu else 360),
251            ),
252            extra_touch_border_scale=0.1,
253            autoselect=True,
254            label='',
255            button_type='square',
256            text_scale=1.13,
257            on_activate_call=self._team_tourney,
258        )
259
260        if bui.app.ui_v1.use_toolbars:
261            bui.widget(
262                edit=btn,
263                up_widget=bui.get_special_widget('tickets_plus_button'),
264                right_widget=bui.get_special_widget('party_button'),
265            )
266
267        xxx = -14
268        self._draw_dude(
269            2,
270            btn,
271            hoffs,
272            v,
273            scl,
274            position=(xxx + 148, 30),
275            color=(0.2, 0.4, 1.0),
276        )
277        self._draw_dude(
278            3,
279            btn,
280            hoffs,
281            v,
282            scl,
283            position=(xxx + 181, 53),
284            color=(0.3, 0.4, 1.0),
285        )
286        self._draw_dude(
287            1,
288            btn,
289            hoffs,
290            v,
291            scl,
292            position=(xxx + 216, 33),
293            color=(0.3, 0.5, 1.0),
294        )
295        self._draw_dude(
296            0,
297            btn,
298            hoffs,
299            v,
300            scl,
301            position=(xxx + 245, 57),
302            color=(0.3, 0.5, 1.0),
303        )
304
305        xxx = 155
306        self._draw_dude(
307            0,
308            btn,
309            hoffs,
310            v,
311            scl,
312            position=(xxx + 151, 30),
313            color=(1.0, 0.5, 0.4),
314        )
315        self._draw_dude(
316            1,
317            btn,
318            hoffs,
319            v,
320            scl,
321            position=(xxx + 189, 53),
322            color=(1.0, 0.58, 0.58),
323        )
324        self._draw_dude(
325            3,
326            btn,
327            hoffs,
328            v,
329            scl,
330            position=(xxx + 223, 27),
331            color=(1.0, 0.5, 0.5),
332        )
333        self._draw_dude(
334            2,
335            btn,
336            hoffs,
337            v,
338            scl,
339            position=(xxx + 257, 57),
340            color=(1.0, 0.5, 0.5),
341        )
342
343        bui.textwidget(
344            parent=self._root_widget,
345            draw_controller=btn,
346            position=(hoffs + scl * (-10), v + scl * 95),
347            size=(scl * button_width, scl * 50),
348            text=bui.Lstr(
349                resource='playModes.teamsText', fallback_resource='teamsText'
350            ),
351            res_scale=1.5,
352            maxwidth=scl * button_width * 0.7,
353            h_align='center',
354            v_align='center',
355            color=(0.7, 0.9, 0.7, 1.0),
356            scale=scl * 2.3,
357        )
358        bui.textwidget(
359            parent=self._root_widget,
360            draw_controller=btn,
361            position=(hoffs + scl * (-10), v + (scl * 54)),
362            size=(scl * button_width, scl * 30),
363            text=bui.Lstr(resource=self._r + '.twoToEightPlayersText'),
364            h_align='center',
365            v_align='center',
366            res_scale=1.5,
367            scale=0.9 * scl,
368            flatness=1.0,
369            maxwidth=scl * button_width * 0.7,
370            color=clr,
371        )
372
373        hoffs += 0 if self._is_main_menu else 300
374        v -= 155 if self._is_main_menu else 0
375        self._free_for_all_button = btn = bui.buttonwidget(
376            parent=self._root_widget,
377            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
378            size=(
379                scl * button_width,
380                scl * (300 if self._is_main_menu else 360),
381            ),
382            extra_touch_border_scale=0.1,
383            autoselect=True,
384            label='',
385            button_type='square',
386            text_scale=1.13,
387            on_activate_call=self._free_for_all,
388        )
389
390        xxx = -5
391        self._draw_dude(
392            0,
393            btn,
394            hoffs,
395            v,
396            scl,
397            position=(xxx + 140, 30),
398            color=(0.4, 1.0, 0.4),
399        )
400        self._draw_dude(
401            3,
402            btn,
403            hoffs,
404            v,
405            scl,
406            position=(xxx + 185, 53),
407            color=(1.0, 0.4, 0.5),
408        )
409        self._draw_dude(
410            1,
411            btn,
412            hoffs,
413            v,
414            scl,
415            position=(xxx + 220, 27),
416            color=(0.4, 0.5, 1.0),
417        )
418        self._draw_dude(
419            2,
420            btn,
421            hoffs,
422            v,
423            scl,
424            position=(xxx + 255, 57),
425            color=(0.5, 1.0, 0.4),
426        )
427        xxx = 140
428        self._draw_dude(
429            2,
430            btn,
431            hoffs,
432            v,
433            scl,
434            position=(xxx + 148, 30),
435            color=(1.0, 0.9, 0.4),
436        )
437        self._draw_dude(
438            0,
439            btn,
440            hoffs,
441            v,
442            scl,
443            position=(xxx + 182, 53),
444            color=(0.7, 1.0, 0.5),
445        )
446        self._draw_dude(
447            3,
448            btn,
449            hoffs,
450            v,
451            scl,
452            position=(xxx + 233, 27),
453            color=(0.7, 0.5, 0.9),
454        )
455        self._draw_dude(
456            1,
457            btn,
458            hoffs,
459            v,
460            scl,
461            position=(xxx + 266, 53),
462            color=(0.4, 0.5, 0.8),
463        )
464        bui.textwidget(
465            parent=self._root_widget,
466            draw_controller=btn,
467            position=(hoffs + scl * (-10), v + scl * 95),
468            size=(scl * button_width, scl * 50),
469            text=bui.Lstr(
470                resource='playModes.freeForAllText',
471                fallback_resource='freeForAllText',
472            ),
473            maxwidth=scl * button_width * 0.7,
474            h_align='center',
475            v_align='center',
476            color=(0.7, 0.9, 0.7, 1.0),
477            scale=scl * 1.9,
478        )
479        bui.textwidget(
480            parent=self._root_widget,
481            draw_controller=btn,
482            position=(hoffs + scl * (-10), v + (scl * 54)),
483            size=(scl * button_width, scl * 30),
484            text=bui.Lstr(resource=self._r + '.twoToEightPlayersText'),
485            h_align='center',
486            v_align='center',
487            scale=0.9 * scl,
488            flatness=1.0,
489            maxwidth=scl * button_width * 0.7,
490            color=clr,
491        )
492
493        if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
494            back_button.delete()
495            bui.containerwidget(
496                edit=self._root_widget,
497                on_cancel_call=self._back,
498                selected_child=(
499                    self._coop_button
500                    if self._is_main_menu
501                    else self._teams_button
502                ),
503            )
504        else:
505            bui.buttonwidget(edit=back_button, on_activate_call=self._back)
506            bui.containerwidget(
507                edit=self._root_widget,
508                cancel_button=back_button,
509                selected_child=(
510                    self._coop_button
511                    if self._is_main_menu
512                    else self._teams_button
513                ),
514            )
515
516        self._restore_state()
Inherited Members
bauiv1._uitypes.Window
get_root_widget