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
  8from typing import override
  9
 10import bascenev1 as bs
 11import bauiv1 as bui
 12
 13
 14class PlayWindow(bui.MainWindow):
 15    """Window for selecting overall play type."""
 16
 17    def __init__(
 18        self,
 19        transition: str | None = 'in_right',
 20        origin_widget: bui.Widget | None = None,
 21    ):
 22        # pylint: disable=too-many-statements
 23        # pylint: disable=too-many-locals
 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        bui.app.threadpool_submit_no_wait(self._preload_modules)
 28
 29        classic = bui.app.classic
 30        assert classic is not None
 31
 32        # We can currently be used either for main window duty or
 33        # modally for selecting playlists. Ideally we should clean
 34        # things up and make playlist selection go through the
 35        # main-window mechanism.
 36        self._is_main_menu = not classic.selecting_private_party_playlist
 37
 38        uiscale = bui.app.ui_v1.uiscale
 39        width = 1100 if uiscale is bui.UIScale.SMALL else 800
 40        x_offs = 150 if uiscale is bui.UIScale.SMALL else 0
 41        height = 550
 42        button_width = 400
 43
 44        if origin_widget is not None:
 45
 46            # Need to store this ourself since we can function as a
 47            # non-main window.
 48            self._transition_out = 'out_scale'
 49        else:
 50            self._transition_out = 'out_right'
 51
 52        self._r = 'playWindow'
 53
 54        super().__init__(
 55            root_widget=bui.containerwidget(
 56                size=(width, height),
 57                toolbar_visibility='menu_full',
 58                scale=(
 59                    1.35
 60                    if uiscale is bui.UIScale.SMALL
 61                    else 0.9 if uiscale is bui.UIScale.MEDIUM else 0.8
 62                ),
 63                stack_offset=(
 64                    (0, 20) if uiscale is bui.UIScale.SMALL else (0, 0)
 65                ),
 66            ),
 67            transition=transition,
 68            origin_widget=origin_widget,
 69        )
 70        self._back_button = back_button = btn = bui.buttonwidget(
 71            parent=self._root_widget,
 72            position=(55 + x_offs, height - 132),
 73            size=(120, 60),
 74            scale=1.1,
 75            text_res_scale=1.5,
 76            text_scale=1.2,
 77            autoselect=True,
 78            label=bui.Lstr(resource='backText'),
 79            button_type='back',
 80        )
 81
 82        txt = bui.textwidget(
 83            parent=self._root_widget,
 84            position=(width * 0.5, height - 101),
 85            # position=(width * 0.5, height -
 86            #           (101 if main_menu else 61)),
 87            size=(0, 0),
 88            text=bui.Lstr(
 89                resource=(
 90                    (f'{self._r}.titleText')
 91                    if self._is_main_menu
 92                    else 'playlistsText'
 93                )
 94            ),
 95            scale=1.7,
 96            res_scale=2.0,
 97            maxwidth=400,
 98            color=bui.app.ui_v1.heading_color,
 99            h_align='center',
100            v_align='center',
101        )
102
103        bui.buttonwidget(
104            edit=btn,
105            button_type='backSmall',
106            size=(60, 60),
107            label=bui.charstr(bui.SpecialChar.BACK),
108        )
109        if uiscale is bui.UIScale.SMALL:
110            bui.textwidget(edit=txt, text='')
111
112        v = height - (110 if self._is_main_menu else 90)
113        v -= 100
114        clr = (0.6, 0.7, 0.6, 1.0)
115        v -= 280 if self._is_main_menu else 180
116        v += 30 if uiscale is bui.UIScale.SMALL else 0
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 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=f'{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        bui.widget(
261            edit=btn,
262            up_widget=bui.get_special_widget('get_tokens_button'),
263            right_widget=bui.get_special_widget('squad_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=f'{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=f'{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 uiscale is bui.UIScale.SMALL:
493            back_button.delete()
494            bui.containerwidget(
495                edit=self._root_widget,
496                on_cancel_call=self._back,
497                # cancel_button=bui.get_special_widget('back_button'),
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    @override
519    def get_main_window_state(self) -> bui.MainWindowState:
520        # Support recreating our window for back/refresh purposes.
521        cls = type(self)
522        return bui.BasicMainWindowState(
523            create_call=lambda transition, origin_widget: cls(
524                transition=transition, origin_widget=origin_widget
525            )
526        )
527
528    @override
529    def on_main_window_close(self) -> None:
530        self._save_state()
531
532    @staticmethod
533    def _preload_modules() -> None:
534        """Preload modules we use; avoids hitches (called in bg thread)."""
535        import bauiv1lib.mainmenu as _unused1
536        import bauiv1lib.account as _unused2
537        import bauiv1lib.coop.browser as _unused3
538        import bauiv1lib.playlist.browser as _unused4
539
540    def _back(self) -> None:
541        # pylint: disable=cyclic-import
542
543        # no-op if we're not currently in control.
544        if not self.can_change_main_window():
545            return
546
547        if self._is_main_menu:
548            self.main_window_back()
549        else:
550            from bauiv1lib.gather import GatherWindow
551
552            assert bui.app.classic is not None
553
554            self._save_state()
555            bui.app.ui_v1.set_main_window(
556                GatherWindow(transition='in_left'),
557                from_window=self,
558                is_back=True,
559            )
560            bui.containerwidget(
561                edit=self._root_widget, transition=self._transition_out
562            )
563
564    def _coop(self) -> None:
565        # pylint: disable=cyclic-import
566        from bauiv1lib.account import show_sign_in_prompt
567        from bauiv1lib.coop.browser import CoopBrowserWindow
568
569        # no-op if we're not currently in control.
570        if not self.can_change_main_window():
571            return
572
573        plus = bui.app.plus
574        assert plus is not None
575
576        if plus.get_v1_account_state() != 'signed_in':
577            show_sign_in_prompt()
578            return
579        self._save_state()
580        bui.containerwidget(edit=self._root_widget, transition='out_left')
581        assert bui.app.classic is not None
582        bui.app.ui_v1.set_main_window(
583            CoopBrowserWindow(origin_widget=self._coop_button), from_window=self
584        )
585
586    def _team_tourney(self) -> None:
587        # pylint: disable=cyclic-import
588        from bauiv1lib.playlist.browser import PlaylistBrowserWindow
589
590        # no-op if we're not currently in control.
591        if not self.can_change_main_window():
592            return
593
594        self._save_state()
595
596        self.main_window_replace(
597            PlaylistBrowserWindow(
598                origin_widget=self._teams_button, sessiontype=bs.DualTeamSession
599            )
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 we're not currently in control.
607        if not self.can_change_main_window():
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_window(
614            PlaylistBrowserWindow(
615                origin_widget=self._free_for_all_button,
616                sessiontype=bs.FreeForAllSession,
617            ),
618            from_window=self,
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)
class PlayWindow(bauiv1._uitypes.MainWindow):
 15class PlayWindow(bui.MainWindow):
 16    """Window for selecting overall play type."""
 17
 18    def __init__(
 19        self,
 20        transition: str | None = 'in_right',
 21        origin_widget: bui.Widget | None = None,
 22    ):
 23        # pylint: disable=too-many-statements
 24        # pylint: disable=too-many-locals
 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        bui.app.threadpool_submit_no_wait(self._preload_modules)
 29
 30        classic = bui.app.classic
 31        assert classic is not None
 32
 33        # We can currently be used either for main window duty or
 34        # modally for selecting playlists. Ideally we should clean
 35        # things up and make playlist selection go through the
 36        # main-window mechanism.
 37        self._is_main_menu = not classic.selecting_private_party_playlist
 38
 39        uiscale = bui.app.ui_v1.uiscale
 40        width = 1100 if uiscale is bui.UIScale.SMALL else 800
 41        x_offs = 150 if uiscale is bui.UIScale.SMALL else 0
 42        height = 550
 43        button_width = 400
 44
 45        if origin_widget is not None:
 46
 47            # Need to store this ourself since we can function as a
 48            # non-main window.
 49            self._transition_out = 'out_scale'
 50        else:
 51            self._transition_out = 'out_right'
 52
 53        self._r = 'playWindow'
 54
 55        super().__init__(
 56            root_widget=bui.containerwidget(
 57                size=(width, height),
 58                toolbar_visibility='menu_full',
 59                scale=(
 60                    1.35
 61                    if uiscale is bui.UIScale.SMALL
 62                    else 0.9 if uiscale is bui.UIScale.MEDIUM else 0.8
 63                ),
 64                stack_offset=(
 65                    (0, 20) if uiscale is bui.UIScale.SMALL else (0, 0)
 66                ),
 67            ),
 68            transition=transition,
 69            origin_widget=origin_widget,
 70        )
 71        self._back_button = back_button = btn = bui.buttonwidget(
 72            parent=self._root_widget,
 73            position=(55 + x_offs, height - 132),
 74            size=(120, 60),
 75            scale=1.1,
 76            text_res_scale=1.5,
 77            text_scale=1.2,
 78            autoselect=True,
 79            label=bui.Lstr(resource='backText'),
 80            button_type='back',
 81        )
 82
 83        txt = bui.textwidget(
 84            parent=self._root_widget,
 85            position=(width * 0.5, height - 101),
 86            # position=(width * 0.5, height -
 87            #           (101 if main_menu else 61)),
 88            size=(0, 0),
 89            text=bui.Lstr(
 90                resource=(
 91                    (f'{self._r}.titleText')
 92                    if self._is_main_menu
 93                    else 'playlistsText'
 94                )
 95            ),
 96            scale=1.7,
 97            res_scale=2.0,
 98            maxwidth=400,
 99            color=bui.app.ui_v1.heading_color,
100            h_align='center',
101            v_align='center',
102        )
103
104        bui.buttonwidget(
105            edit=btn,
106            button_type='backSmall',
107            size=(60, 60),
108            label=bui.charstr(bui.SpecialChar.BACK),
109        )
110        if uiscale is bui.UIScale.SMALL:
111            bui.textwidget(edit=txt, text='')
112
113        v = height - (110 if self._is_main_menu else 90)
114        v -= 100
115        clr = (0.6, 0.7, 0.6, 1.0)
116        v -= 280 if self._is_main_menu else 180
117        v += 30 if uiscale is bui.UIScale.SMALL else 0
118        hoffs = x_offs + 80 if self._is_main_menu else x_offs - 100
119        scl = 1.13 if self._is_main_menu else 0.68
120
121        self._lineup_tex = bui.gettexture('playerLineup')
122        angry_computer_transparent_mesh = bui.getmesh(
123            'angryComputerTransparent'
124        )
125        self._lineup_1_transparent_mesh = bui.getmesh(
126            'playerLineup1Transparent'
127        )
128        self._lineup_2_transparent_mesh = bui.getmesh(
129            'playerLineup2Transparent'
130        )
131        self._lineup_3_transparent_mesh = bui.getmesh(
132            'playerLineup3Transparent'
133        )
134        self._lineup_4_transparent_mesh = bui.getmesh(
135            'playerLineup4Transparent'
136        )
137        self._eyes_mesh = bui.getmesh('plasticEyesTransparent')
138
139        self._coop_button: bui.Widget | None = None
140
141        # Only show coop button in main-menu variant.
142        if self._is_main_menu:
143            self._coop_button = btn = bui.buttonwidget(
144                parent=self._root_widget,
145                position=(hoffs, v + (scl * 15)),
146                size=(
147                    scl * button_width,
148                    scl * 300,
149                ),
150                extra_touch_border_scale=0.1,
151                autoselect=True,
152                label='',
153                button_type='square',
154                text_scale=1.13,
155                on_activate_call=self._coop,
156            )
157
158            if uiscale is bui.UIScale.SMALL:
159                bui.widget(
160                    edit=btn,
161                    left_widget=bui.get_special_widget('back_button'),
162                )
163                bui.widget(
164                    edit=btn,
165                    up_widget=bui.get_special_widget('account_button'),
166                )
167                bui.widget(
168                    edit=btn,
169                    down_widget=bui.get_special_widget('settings_button'),
170                )
171
172            self._draw_dude(
173                0,
174                btn,
175                hoffs,
176                v,
177                scl,
178                position=(140, 30),
179                color=(0.72, 0.4, 1.0),
180            )
181            self._draw_dude(
182                1,
183                btn,
184                hoffs,
185                v,
186                scl,
187                position=(185, 53),
188                color=(0.71, 0.5, 1.0),
189            )
190            self._draw_dude(
191                2,
192                btn,
193                hoffs,
194                v,
195                scl,
196                position=(220, 27),
197                color=(0.67, 0.44, 1.0),
198            )
199            self._draw_dude(
200                3, btn, hoffs, v, scl, position=(255, 57), color=(0.7, 0.3, 1.0)
201            )
202            bui.imagewidget(
203                parent=self._root_widget,
204                draw_controller=btn,
205                position=(hoffs + scl * 230, v + scl * 153),
206                size=(scl * 115, scl * 115),
207                texture=self._lineup_tex,
208                mesh_transparent=angry_computer_transparent_mesh,
209            )
210
211            bui.textwidget(
212                parent=self._root_widget,
213                draw_controller=btn,
214                position=(hoffs + scl * (-10), v + scl * 95),
215                size=(scl * button_width, scl * 50),
216                text=bui.Lstr(
217                    resource='playModes.singlePlayerCoopText',
218                    fallback_resource='playModes.coopText',
219                ),
220                maxwidth=scl * button_width * 0.7,
221                res_scale=1.5,
222                h_align='center',
223                v_align='center',
224                color=(0.7, 0.9, 0.7, 1.0),
225                scale=scl * 2.3,
226            )
227
228            bui.textwidget(
229                parent=self._root_widget,
230                draw_controller=btn,
231                position=(hoffs + scl * (-10), v + (scl * 54)),
232                size=(scl * button_width, scl * 30),
233                text=bui.Lstr(resource=f'{self._r}.oneToFourPlayersText'),
234                h_align='center',
235                v_align='center',
236                scale=0.83 * scl,
237                flatness=1.0,
238                maxwidth=scl * button_width * 0.7,
239                color=clr,
240            )
241
242        scl = 0.5 if self._is_main_menu else 0.68
243        hoffs += 440 if self._is_main_menu else 216
244        v += 180 if self._is_main_menu else -68
245
246        self._teams_button = btn = bui.buttonwidget(
247            parent=self._root_widget,
248            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
249            size=(
250                scl * button_width,
251                scl * (300 if self._is_main_menu else 360),
252            ),
253            extra_touch_border_scale=0.1,
254            autoselect=True,
255            label='',
256            button_type='square',
257            text_scale=1.13,
258            on_activate_call=self._team_tourney,
259        )
260
261        bui.widget(
262            edit=btn,
263            up_widget=bui.get_special_widget('get_tokens_button'),
264            right_widget=bui.get_special_widget('squad_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=f'{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=f'{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 uiscale is bui.UIScale.SMALL:
494            back_button.delete()
495            bui.containerwidget(
496                edit=self._root_widget,
497                on_cancel_call=self._back,
498                # cancel_button=bui.get_special_widget('back_button'),
499                selected_child=(
500                    self._coop_button
501                    if self._is_main_menu
502                    else self._teams_button
503                ),
504            )
505        else:
506            bui.buttonwidget(edit=back_button, on_activate_call=self._back)
507            bui.containerwidget(
508                edit=self._root_widget,
509                cancel_button=back_button,
510                selected_child=(
511                    self._coop_button
512                    if self._is_main_menu
513                    else self._teams_button
514                ),
515            )
516
517        self._restore_state()
518
519    @override
520    def get_main_window_state(self) -> bui.MainWindowState:
521        # Support recreating our window for back/refresh purposes.
522        cls = type(self)
523        return bui.BasicMainWindowState(
524            create_call=lambda transition, origin_widget: cls(
525                transition=transition, origin_widget=origin_widget
526            )
527        )
528
529    @override
530    def on_main_window_close(self) -> None:
531        self._save_state()
532
533    @staticmethod
534    def _preload_modules() -> None:
535        """Preload modules we use; avoids hitches (called in bg thread)."""
536        import bauiv1lib.mainmenu as _unused1
537        import bauiv1lib.account as _unused2
538        import bauiv1lib.coop.browser as _unused3
539        import bauiv1lib.playlist.browser as _unused4
540
541    def _back(self) -> None:
542        # pylint: disable=cyclic-import
543
544        # no-op if we're not currently in control.
545        if not self.can_change_main_window():
546            return
547
548        if self._is_main_menu:
549            self.main_window_back()
550        else:
551            from bauiv1lib.gather import GatherWindow
552
553            assert bui.app.classic is not None
554
555            self._save_state()
556            bui.app.ui_v1.set_main_window(
557                GatherWindow(transition='in_left'),
558                from_window=self,
559                is_back=True,
560            )
561            bui.containerwidget(
562                edit=self._root_widget, transition=self._transition_out
563            )
564
565    def _coop(self) -> None:
566        # pylint: disable=cyclic-import
567        from bauiv1lib.account import show_sign_in_prompt
568        from bauiv1lib.coop.browser import CoopBrowserWindow
569
570        # no-op if we're not currently in control.
571        if not self.can_change_main_window():
572            return
573
574        plus = bui.app.plus
575        assert plus is not None
576
577        if plus.get_v1_account_state() != 'signed_in':
578            show_sign_in_prompt()
579            return
580        self._save_state()
581        bui.containerwidget(edit=self._root_widget, transition='out_left')
582        assert bui.app.classic is not None
583        bui.app.ui_v1.set_main_window(
584            CoopBrowserWindow(origin_widget=self._coop_button), from_window=self
585        )
586
587    def _team_tourney(self) -> None:
588        # pylint: disable=cyclic-import
589        from bauiv1lib.playlist.browser import PlaylistBrowserWindow
590
591        # no-op if we're not currently in control.
592        if not self.can_change_main_window():
593            return
594
595        self._save_state()
596
597        self.main_window_replace(
598            PlaylistBrowserWindow(
599                origin_widget=self._teams_button, sessiontype=bs.DualTeamSession
600            )
601        )
602
603    def _free_for_all(self) -> None:
604        # pylint: disable=cyclic-import
605        from bauiv1lib.playlist.browser import PlaylistBrowserWindow
606
607        # no-op if we're not currently in control.
608        if not self.can_change_main_window():
609            return
610
611        self._save_state()
612        bui.containerwidget(edit=self._root_widget, transition='out_left')
613        assert bui.app.classic is not None
614        bui.app.ui_v1.set_main_window(
615            PlaylistBrowserWindow(
616                origin_widget=self._free_for_all_button,
617                sessiontype=bs.FreeForAllSession,
618            ),
619            from_window=self,
620        )
621
622    def _draw_dude(
623        self,
624        i: int,
625        btn: bui.Widget,
626        hoffs: float,
627        v: float,
628        scl: float,
629        position: tuple[float, float],
630        color: tuple[float, float, float],
631    ) -> None:
632        h_extra = -100
633        v_extra = 130
634        eye_color = (
635            0.7 * 1.0 + 0.3 * color[0],
636            0.7 * 1.0 + 0.3 * color[1],
637            0.7 * 1.0 + 0.3 * color[2],
638        )
639        if i == 0:
640            bui.imagewidget(
641                parent=self._root_widget,
642                draw_controller=btn,
643                position=(
644                    hoffs + scl * (h_extra + position[0]),
645                    v + scl * (v_extra + position[1]),
646                ),
647                size=(scl * 60, scl * 80),
648                color=color,
649                texture=self._lineup_tex,
650                mesh_transparent=self._lineup_1_transparent_mesh,
651            )
652            bui.imagewidget(
653                parent=self._root_widget,
654                draw_controller=btn,
655                position=(
656                    hoffs + scl * (h_extra + position[0] + 12),
657                    v + scl * (v_extra + position[1] + 53),
658                ),
659                size=(scl * 36, scl * 18),
660                texture=self._lineup_tex,
661                color=eye_color,
662                mesh_transparent=self._eyes_mesh,
663            )
664        elif i == 1:
665            bui.imagewidget(
666                parent=self._root_widget,
667                draw_controller=btn,
668                position=(
669                    hoffs + scl * (h_extra + position[0]),
670                    v + scl * (v_extra + position[1]),
671                ),
672                size=(scl * 45, scl * 90),
673                color=color,
674                texture=self._lineup_tex,
675                mesh_transparent=self._lineup_2_transparent_mesh,
676            )
677            bui.imagewidget(
678                parent=self._root_widget,
679                draw_controller=btn,
680                position=(
681                    hoffs + scl * (h_extra + position[0] + 5),
682                    v + scl * (v_extra + position[1] + 67),
683                ),
684                size=(scl * 32, scl * 16),
685                texture=self._lineup_tex,
686                color=eye_color,
687                mesh_transparent=self._eyes_mesh,
688            )
689        elif i == 2:
690            bui.imagewidget(
691                parent=self._root_widget,
692                draw_controller=btn,
693                position=(
694                    hoffs + scl * (h_extra + position[0]),
695                    v + scl * (v_extra + position[1]),
696                ),
697                size=(scl * 45, scl * 90),
698                color=color,
699                texture=self._lineup_tex,
700                mesh_transparent=self._lineup_3_transparent_mesh,
701            )
702            bui.imagewidget(
703                parent=self._root_widget,
704                draw_controller=btn,
705                position=(
706                    hoffs + scl * (h_extra + position[0] + 5),
707                    v + scl * (v_extra + position[1] + 59),
708                ),
709                size=(scl * 34, scl * 17),
710                texture=self._lineup_tex,
711                color=eye_color,
712                mesh_transparent=self._eyes_mesh,
713            )
714        elif i == 3:
715            bui.imagewidget(
716                parent=self._root_widget,
717                draw_controller=btn,
718                position=(
719                    hoffs + scl * (h_extra + position[0]),
720                    v + scl * (v_extra + position[1]),
721                ),
722                size=(scl * 48, scl * 96),
723                color=color,
724                texture=self._lineup_tex,
725                mesh_transparent=self._lineup_4_transparent_mesh,
726            )
727            bui.imagewidget(
728                parent=self._root_widget,
729                draw_controller=btn,
730                position=(
731                    hoffs + scl * (h_extra + position[0] + 2),
732                    v + scl * (v_extra + position[1] + 62),
733                ),
734                size=(scl * 38, scl * 19),
735                texture=self._lineup_tex,
736                color=eye_color,
737                mesh_transparent=self._eyes_mesh,
738            )
739
740    def _save_state(self) -> None:
741        try:
742            sel = self._root_widget.get_selected_child()
743            if sel == self._teams_button:
744                sel_name = 'Team Games'
745            elif self._coop_button is not None and sel == self._coop_button:
746                sel_name = 'Co-op Games'
747            elif sel == self._free_for_all_button:
748                sel_name = 'Free-for-All Games'
749            elif sel == self._back_button:
750                sel_name = 'Back'
751            else:
752                raise ValueError(f'unrecognized selection {sel}')
753            assert bui.app.classic is not None
754            bui.app.ui_v1.window_states[type(self)] = sel_name
755        except Exception:
756            logging.exception('Error saving state for %s.', self)
757
758    def _restore_state(self) -> None:
759        try:
760            assert bui.app.classic is not None
761            sel_name = bui.app.ui_v1.window_states.get(type(self))
762            if sel_name == 'Team Games':
763                sel = self._teams_button
764            elif sel_name == 'Co-op Games' and self._coop_button is not None:
765                sel = self._coop_button
766            elif sel_name == 'Free-for-All Games':
767                sel = self._free_for_all_button
768            elif sel_name == 'Back':
769                sel = self._back_button
770            else:
771                sel = (
772                    self._coop_button
773                    if self._coop_button is not None
774                    else self._teams_button
775                )
776            bui.containerwidget(edit=self._root_widget, selected_child=sel)
777        except Exception:
778            logging.exception('Error restoring state for %s.', self)

Window for selecting overall play type.

PlayWindow( transition: str | None = 'in_right', origin_widget: _bauiv1.Widget | None = None)
 18    def __init__(
 19        self,
 20        transition: str | None = 'in_right',
 21        origin_widget: bui.Widget | None = None,
 22    ):
 23        # pylint: disable=too-many-statements
 24        # pylint: disable=too-many-locals
 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        bui.app.threadpool_submit_no_wait(self._preload_modules)
 29
 30        classic = bui.app.classic
 31        assert classic is not None
 32
 33        # We can currently be used either for main window duty or
 34        # modally for selecting playlists. Ideally we should clean
 35        # things up and make playlist selection go through the
 36        # main-window mechanism.
 37        self._is_main_menu = not classic.selecting_private_party_playlist
 38
 39        uiscale = bui.app.ui_v1.uiscale
 40        width = 1100 if uiscale is bui.UIScale.SMALL else 800
 41        x_offs = 150 if uiscale is bui.UIScale.SMALL else 0
 42        height = 550
 43        button_width = 400
 44
 45        if origin_widget is not None:
 46
 47            # Need to store this ourself since we can function as a
 48            # non-main window.
 49            self._transition_out = 'out_scale'
 50        else:
 51            self._transition_out = 'out_right'
 52
 53        self._r = 'playWindow'
 54
 55        super().__init__(
 56            root_widget=bui.containerwidget(
 57                size=(width, height),
 58                toolbar_visibility='menu_full',
 59                scale=(
 60                    1.35
 61                    if uiscale is bui.UIScale.SMALL
 62                    else 0.9 if uiscale is bui.UIScale.MEDIUM else 0.8
 63                ),
 64                stack_offset=(
 65                    (0, 20) if uiscale is bui.UIScale.SMALL else (0, 0)
 66                ),
 67            ),
 68            transition=transition,
 69            origin_widget=origin_widget,
 70        )
 71        self._back_button = back_button = btn = bui.buttonwidget(
 72            parent=self._root_widget,
 73            position=(55 + x_offs, height - 132),
 74            size=(120, 60),
 75            scale=1.1,
 76            text_res_scale=1.5,
 77            text_scale=1.2,
 78            autoselect=True,
 79            label=bui.Lstr(resource='backText'),
 80            button_type='back',
 81        )
 82
 83        txt = bui.textwidget(
 84            parent=self._root_widget,
 85            position=(width * 0.5, height - 101),
 86            # position=(width * 0.5, height -
 87            #           (101 if main_menu else 61)),
 88            size=(0, 0),
 89            text=bui.Lstr(
 90                resource=(
 91                    (f'{self._r}.titleText')
 92                    if self._is_main_menu
 93                    else 'playlistsText'
 94                )
 95            ),
 96            scale=1.7,
 97            res_scale=2.0,
 98            maxwidth=400,
 99            color=bui.app.ui_v1.heading_color,
100            h_align='center',
101            v_align='center',
102        )
103
104        bui.buttonwidget(
105            edit=btn,
106            button_type='backSmall',
107            size=(60, 60),
108            label=bui.charstr(bui.SpecialChar.BACK),
109        )
110        if uiscale is bui.UIScale.SMALL:
111            bui.textwidget(edit=txt, text='')
112
113        v = height - (110 if self._is_main_menu else 90)
114        v -= 100
115        clr = (0.6, 0.7, 0.6, 1.0)
116        v -= 280 if self._is_main_menu else 180
117        v += 30 if uiscale is bui.UIScale.SMALL else 0
118        hoffs = x_offs + 80 if self._is_main_menu else x_offs - 100
119        scl = 1.13 if self._is_main_menu else 0.68
120
121        self._lineup_tex = bui.gettexture('playerLineup')
122        angry_computer_transparent_mesh = bui.getmesh(
123            'angryComputerTransparent'
124        )
125        self._lineup_1_transparent_mesh = bui.getmesh(
126            'playerLineup1Transparent'
127        )
128        self._lineup_2_transparent_mesh = bui.getmesh(
129            'playerLineup2Transparent'
130        )
131        self._lineup_3_transparent_mesh = bui.getmesh(
132            'playerLineup3Transparent'
133        )
134        self._lineup_4_transparent_mesh = bui.getmesh(
135            'playerLineup4Transparent'
136        )
137        self._eyes_mesh = bui.getmesh('plasticEyesTransparent')
138
139        self._coop_button: bui.Widget | None = None
140
141        # Only show coop button in main-menu variant.
142        if self._is_main_menu:
143            self._coop_button = btn = bui.buttonwidget(
144                parent=self._root_widget,
145                position=(hoffs, v + (scl * 15)),
146                size=(
147                    scl * button_width,
148                    scl * 300,
149                ),
150                extra_touch_border_scale=0.1,
151                autoselect=True,
152                label='',
153                button_type='square',
154                text_scale=1.13,
155                on_activate_call=self._coop,
156            )
157
158            if uiscale is bui.UIScale.SMALL:
159                bui.widget(
160                    edit=btn,
161                    left_widget=bui.get_special_widget('back_button'),
162                )
163                bui.widget(
164                    edit=btn,
165                    up_widget=bui.get_special_widget('account_button'),
166                )
167                bui.widget(
168                    edit=btn,
169                    down_widget=bui.get_special_widget('settings_button'),
170                )
171
172            self._draw_dude(
173                0,
174                btn,
175                hoffs,
176                v,
177                scl,
178                position=(140, 30),
179                color=(0.72, 0.4, 1.0),
180            )
181            self._draw_dude(
182                1,
183                btn,
184                hoffs,
185                v,
186                scl,
187                position=(185, 53),
188                color=(0.71, 0.5, 1.0),
189            )
190            self._draw_dude(
191                2,
192                btn,
193                hoffs,
194                v,
195                scl,
196                position=(220, 27),
197                color=(0.67, 0.44, 1.0),
198            )
199            self._draw_dude(
200                3, btn, hoffs, v, scl, position=(255, 57), color=(0.7, 0.3, 1.0)
201            )
202            bui.imagewidget(
203                parent=self._root_widget,
204                draw_controller=btn,
205                position=(hoffs + scl * 230, v + scl * 153),
206                size=(scl * 115, scl * 115),
207                texture=self._lineup_tex,
208                mesh_transparent=angry_computer_transparent_mesh,
209            )
210
211            bui.textwidget(
212                parent=self._root_widget,
213                draw_controller=btn,
214                position=(hoffs + scl * (-10), v + scl * 95),
215                size=(scl * button_width, scl * 50),
216                text=bui.Lstr(
217                    resource='playModes.singlePlayerCoopText',
218                    fallback_resource='playModes.coopText',
219                ),
220                maxwidth=scl * button_width * 0.7,
221                res_scale=1.5,
222                h_align='center',
223                v_align='center',
224                color=(0.7, 0.9, 0.7, 1.0),
225                scale=scl * 2.3,
226            )
227
228            bui.textwidget(
229                parent=self._root_widget,
230                draw_controller=btn,
231                position=(hoffs + scl * (-10), v + (scl * 54)),
232                size=(scl * button_width, scl * 30),
233                text=bui.Lstr(resource=f'{self._r}.oneToFourPlayersText'),
234                h_align='center',
235                v_align='center',
236                scale=0.83 * scl,
237                flatness=1.0,
238                maxwidth=scl * button_width * 0.7,
239                color=clr,
240            )
241
242        scl = 0.5 if self._is_main_menu else 0.68
243        hoffs += 440 if self._is_main_menu else 216
244        v += 180 if self._is_main_menu else -68
245
246        self._teams_button = btn = bui.buttonwidget(
247            parent=self._root_widget,
248            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
249            size=(
250                scl * button_width,
251                scl * (300 if self._is_main_menu else 360),
252            ),
253            extra_touch_border_scale=0.1,
254            autoselect=True,
255            label='',
256            button_type='square',
257            text_scale=1.13,
258            on_activate_call=self._team_tourney,
259        )
260
261        bui.widget(
262            edit=btn,
263            up_widget=bui.get_special_widget('get_tokens_button'),
264            right_widget=bui.get_special_widget('squad_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=f'{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=f'{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 uiscale is bui.UIScale.SMALL:
494            back_button.delete()
495            bui.containerwidget(
496                edit=self._root_widget,
497                on_cancel_call=self._back,
498                # cancel_button=bui.get_special_widget('back_button'),
499                selected_child=(
500                    self._coop_button
501                    if self._is_main_menu
502                    else self._teams_button
503                ),
504            )
505        else:
506            bui.buttonwidget(edit=back_button, on_activate_call=self._back)
507            bui.containerwidget(
508                edit=self._root_widget,
509                cancel_button=back_button,
510                selected_child=(
511                    self._coop_button
512                    if self._is_main_menu
513                    else self._teams_button
514                ),
515            )
516
517        self._restore_state()

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:
519    @override
520    def get_main_window_state(self) -> bui.MainWindowState:
521        # Support recreating our window for back/refresh purposes.
522        cls = type(self)
523        return bui.BasicMainWindowState(
524            create_call=lambda transition, origin_widget: cls(
525                transition=transition, origin_widget=origin_widget
526            )
527        )

Return a WindowState to recreate this window, if supported.

@override
def on_main_window_close(self) -> None:
529    @override
530    def on_main_window_close(self) -> None:
531        self._save_state()

Called before transitioning out a main window.

A good opportunity to save window state/etc.

Inherited Members
bauiv1._uitypes.MainWindow
main_window_back_state
main_window_close
can_change_main_window
main_window_back
main_window_replace
bauiv1._uitypes.Window
get_root_widget