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