bauiv1lib.profile.edit
Provides UI to edit a player profile.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides UI to edit a player profile.""" 4 5from __future__ import annotations 6 7import random 8from typing import cast, override 9 10from bauiv1lib.colorpicker import ColorPicker 11from bauiv1lib.characterpicker import CharacterPickerDelegate 12from bauiv1lib.iconpicker import IconPickerDelegate 13import bauiv1 as bui 14import bascenev1 as bs 15 16 17class EditProfileWindow( 18 bui.MainWindow, CharacterPickerDelegate, IconPickerDelegate 19): 20 """Window for editing a player profile.""" 21 22 def reload_window(self) -> None: 23 """Transitions out and recreates ourself.""" 24 25 # no-op if we're not in control. 26 if not self.main_window_has_control(): 27 return 28 29 # Replace ourself with ourself, but keep the same back location. 30 assert self.main_window_back_state is not None 31 self.main_window_replace( 32 EditProfileWindow(self.getname()), 33 back_state=self.main_window_back_state, 34 ) 35 36 # def __del__(self) -> None: 37 # print(f'~EditProfileWindow({id(self)})') 38 39 def __init__( 40 self, 41 existing_profile: str | None, 42 transition: str | None = 'in_right', 43 origin_widget: bui.Widget | None = None, 44 ): 45 # FIXME: Tidy this up a bit. 46 # pylint: disable=too-many-branches 47 # pylint: disable=too-many-statements 48 # pylint: disable=too-many-locals 49 50 assert bui.app.classic is not None 51 # print(f'EditProfileWindow({id(self)})') 52 53 plus = bui.app.plus 54 assert plus is not None 55 56 self._existing_profile = existing_profile 57 self._r = 'editProfileWindow' 58 self._spazzes: list[str] = [] 59 self._icon_textures: list[bui.Texture] = [] 60 self._icon_tint_textures: list[bui.Texture] = [] 61 62 # Grab profile colors or pick random ones. 63 ( 64 self._color, 65 self._highlight, 66 ) = bui.app.classic.get_player_profile_colors(existing_profile) 67 uiscale = bui.app.ui_v1.uiscale 68 self._width = width = 880.0 if uiscale is bui.UIScale.SMALL else 680.0 69 self._x_inset = x_inset = 100.0 if uiscale is bui.UIScale.SMALL else 0.0 70 self._height = height = ( 71 500.0 72 if uiscale is bui.UIScale.SMALL 73 else 400.0 if uiscale is bui.UIScale.MEDIUM else 450.0 74 ) 75 yoffs = -42 if uiscale is bui.UIScale.SMALL else 0 76 spacing = 40 77 self._base_scale = ( 78 1.6 79 if uiscale is bui.UIScale.SMALL 80 else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0 81 ) 82 top_extra = 70 if uiscale is bui.UIScale.SMALL else 15 83 super().__init__( 84 root_widget=bui.containerwidget( 85 size=(width, height + top_extra), 86 scale=self._base_scale, 87 stack_offset=( 88 (0, 0) if uiscale is bui.UIScale.SMALL else (0, 0) 89 ), 90 toolbar_visibility=( 91 None if uiscale is bui.UIScale.SMALL else 'menu_full' 92 ), 93 ), 94 transition=transition, 95 origin_widget=origin_widget, 96 ) 97 cancel_button = btn = bui.buttonwidget( 98 parent=self._root_widget, 99 position=(52 + x_inset, height - 60 + yoffs), 100 size=(155, 60), 101 scale=0.8, 102 autoselect=True, 103 label=bui.Lstr(resource='cancelText'), 104 on_activate_call=self._cancel, 105 ) 106 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 107 save_button = btn = bui.buttonwidget( 108 parent=self._root_widget, 109 position=(width - (177 + x_inset), height - 60 + yoffs), 110 size=(155, 60), 111 autoselect=True, 112 scale=0.8, 113 label=bui.Lstr(resource='saveText'), 114 ) 115 bui.widget(edit=save_button, left_widget=cancel_button) 116 bui.widget(edit=cancel_button, right_widget=save_button) 117 bui.containerwidget(edit=self._root_widget, start_button=btn) 118 bui.textwidget( 119 parent=self._root_widget, 120 position=(self._width * 0.5, height - 38 + yoffs), 121 size=(0, 0), 122 text=( 123 bui.Lstr(resource=f'{self._r}.titleNewText') 124 if existing_profile is None 125 else bui.Lstr(resource=f'{self._r}.titleEditText') 126 ), 127 color=bui.app.ui_v1.title_color, 128 maxwidth=290, 129 scale=1.0, 130 h_align='center', 131 v_align='center', 132 ) 133 134 # Make a list of spaz icons. 135 self.refresh_characters() 136 profile = bui.app.config.get('Player Profiles', {}).get( 137 self._existing_profile, {} 138 ) 139 140 if 'global' in profile: 141 self._global = profile['global'] 142 else: 143 self._global = False 144 145 if 'icon' in profile: 146 self._icon = profile['icon'] 147 else: 148 self._icon = bui.charstr(bui.SpecialChar.LOGO) 149 150 assigned_random_char = False 151 152 # Look for existing character choice or pick random one otherwise. 153 try: 154 icon_index = self._spazzes.index(profile['character']) 155 except Exception: 156 # Let's set the default icon to spaz for our first profile; after 157 # that we go random. 158 # (SCRATCH THAT.. we now hard-code account-profiles to start with 159 # spaz which has a similar effect) 160 # try: p_len = len(bui.app.config['Player Profiles']) 161 # except Exception: p_len = 0 162 # if p_len == 0: icon_index = self._spazzes.index('Spaz') 163 # else: 164 random.seed() 165 icon_index = random.randrange(len(self._spazzes)) 166 assigned_random_char = True 167 self._icon_index = icon_index 168 bui.buttonwidget(edit=save_button, on_activate_call=self.save) 169 170 v = height - 115.0 + yoffs 171 self._name = ( 172 '' if self._existing_profile is None else self._existing_profile 173 ) 174 self._is_account_profile = self._name == '__account__' 175 176 # If we just picked a random character, see if it has specific 177 # colors/highlights associated with it and assign them if so. 178 if assigned_random_char: 179 assert bui.app.classic is not None 180 clr = bui.app.classic.spaz_appearances[ 181 self._spazzes[icon_index] 182 ].default_color 183 if clr is not None: 184 self._color = clr 185 highlight = bui.app.classic.spaz_appearances[ 186 self._spazzes[icon_index] 187 ].default_highlight 188 if highlight is not None: 189 self._highlight = highlight 190 191 # Assign a random name if they had none. 192 if self._name == '': 193 names = bs.get_random_names() 194 self._name = names[random.randrange(len(names))] 195 196 self._clipped_name_text = bui.textwidget( 197 parent=self._root_widget, 198 text='', 199 position=(580 + x_inset, v - 8), 200 flatness=1.0, 201 shadow=0.0, 202 scale=0.55, 203 size=(0, 0), 204 maxwidth=100, 205 h_align='center', 206 v_align='center', 207 color=(1, 1, 0, 0.5), 208 ) 209 210 if not self._is_account_profile and not self._global: 211 bui.textwidget( 212 parent=self._root_widget, 213 text=bui.Lstr(resource=f'{self._r}.nameText'), 214 position=(200 + x_inset, v - 6), 215 size=(0, 0), 216 h_align='right', 217 v_align='center', 218 color=(1, 1, 1, 0.5), 219 scale=0.9, 220 ) 221 222 self._upgrade_button = None 223 if self._is_account_profile: 224 if plus.get_v1_account_state() == 'signed_in': 225 sval = plus.get_v1_account_display_string() 226 else: 227 sval = '??' 228 bui.textwidget( 229 parent=self._root_widget, 230 position=(self._width * 0.5, v - 7), 231 size=(0, 0), 232 scale=1.2, 233 text=sval, 234 maxwidth=270, 235 h_align='center', 236 v_align='center', 237 ) 238 txtl = bui.Lstr( 239 resource='editProfileWindow.accountProfileText' 240 ).evaluate() 241 b_width = min( 242 270.0, 243 bui.get_string_width(txtl, suppress_warning=True) * 0.6, 244 ) 245 bui.textwidget( 246 parent=self._root_widget, 247 position=(self._width * 0.5, v - 39), 248 size=(0, 0), 249 scale=0.6, 250 color=bui.app.ui_v1.infotextcolor, 251 text=txtl, 252 maxwidth=270, 253 h_align='center', 254 v_align='center', 255 ) 256 self._account_type_info_button = bui.buttonwidget( 257 parent=self._root_widget, 258 label='?', 259 size=(15, 15), 260 text_scale=0.6, 261 position=(self._width * 0.5 + b_width * 0.5 + 13, v - 47), 262 button_type='square', 263 color=(0.6, 0.5, 0.65), 264 autoselect=True, 265 on_activate_call=self.show_account_profile_info, 266 ) 267 elif self._global: 268 b_size = 60 269 self._icon_button = btn = bui.buttonwidget( 270 parent=self._root_widget, 271 autoselect=True, 272 position=(self._width * 0.5 - 160 - b_size * 0.5, v - 38 - 15), 273 size=(b_size, b_size), 274 color=(0.6, 0.5, 0.6), 275 label='', 276 button_type='square', 277 text_scale=1.2, 278 on_activate_call=self._on_icon_press, 279 ) 280 self._icon_button_label = bui.textwidget( 281 parent=self._root_widget, 282 position=(self._width * 0.5 - 160, v - 35), 283 draw_controller=btn, 284 h_align='center', 285 v_align='center', 286 size=(0, 0), 287 color=(1, 1, 1), 288 text='', 289 scale=2.0, 290 ) 291 292 bui.textwidget( 293 parent=self._root_widget, 294 h_align='center', 295 v_align='center', 296 position=(self._width * 0.5 - 160, v - 55 - 15), 297 size=(0, 0), 298 draw_controller=btn, 299 text=bui.Lstr(resource=f'{self._r}.iconText'), 300 scale=0.7, 301 color=bui.app.ui_v1.title_color, 302 maxwidth=120, 303 ) 304 305 self._update_icon() 306 307 bui.textwidget( 308 parent=self._root_widget, 309 position=(self._width * 0.5, v - 7), 310 size=(0, 0), 311 scale=1.2, 312 text=self._name, 313 maxwidth=240, 314 h_align='center', 315 v_align='center', 316 ) 317 # FIXME hard coded strings are bad 318 txtl = bui.Lstr( 319 resource='editProfileWindow.globalProfileText' 320 ).evaluate() 321 b_width = min( 322 240.0, 323 bui.get_string_width(txtl, suppress_warning=True) * 0.6, 324 ) 325 bui.textwidget( 326 parent=self._root_widget, 327 position=(self._width * 0.5, v - 39), 328 size=(0, 0), 329 scale=0.6, 330 color=bui.app.ui_v1.infotextcolor, 331 text=txtl, 332 maxwidth=240, 333 h_align='center', 334 v_align='center', 335 ) 336 self._account_type_info_button = bui.buttonwidget( 337 parent=self._root_widget, 338 label='?', 339 size=(15, 15), 340 text_scale=0.6, 341 position=(self._width * 0.5 + b_width * 0.5 + 13, v - 47), 342 button_type='square', 343 color=(0.6, 0.5, 0.65), 344 autoselect=True, 345 on_activate_call=self.show_global_profile_info, 346 ) 347 else: 348 self._text_field = bui.textwidget( 349 parent=self._root_widget, 350 position=(220 + x_inset, v - 30), 351 size=(265, 40), 352 text=self._name, 353 h_align='left', 354 v_align='center', 355 max_chars=16, 356 description=bui.Lstr(resource=f'{self._r}.nameDescriptionText'), 357 autoselect=True, 358 editable=True, 359 padding=4, 360 color=(0.9, 0.9, 0.9, 1.0), 361 on_return_press_call=bui.Call(save_button.activate), 362 ) 363 364 # FIXME hard coded strings are bad 365 txtl = bui.Lstr( 366 resource='editProfileWindow.localProfileText' 367 ).evaluate() 368 b_width = min( 369 270.0, 370 bui.get_string_width(txtl, suppress_warning=True) * 0.6, 371 ) 372 bui.textwidget( 373 parent=self._root_widget, 374 position=(self._width * 0.5, v - 43), 375 size=(0, 0), 376 scale=0.6, 377 color=bui.app.ui_v1.infotextcolor, 378 text=txtl, 379 maxwidth=270, 380 h_align='center', 381 v_align='center', 382 ) 383 self._account_type_info_button = bui.buttonwidget( 384 parent=self._root_widget, 385 label='?', 386 size=(15, 15), 387 text_scale=0.6, 388 position=(self._width * 0.5 + b_width * 0.5 + 13, v - 50), 389 button_type='square', 390 color=(0.6, 0.5, 0.65), 391 autoselect=True, 392 on_activate_call=self.show_local_profile_info, 393 ) 394 self._upgrade_button = bui.buttonwidget( 395 parent=self._root_widget, 396 label=bui.Lstr(resource='upgradeText'), 397 size=(40, 17), 398 text_scale=1.0, 399 button_type='square', 400 position=(self._width * 0.5 + b_width * 0.5 + 13 + 43, v - 51), 401 color=(0.6, 0.5, 0.65), 402 autoselect=True, 403 on_activate_call=self.upgrade_profile, 404 ) 405 self._random_name_button = bui.buttonwidget( 406 parent=self._root_widget, 407 label=bui.Lstr(resource='randomText'), 408 size=(30, 20), 409 position=(495 + x_inset, v - 20), 410 button_type='square', 411 color=(0.6, 0.5, 0.65), 412 autoselect=True, 413 on_activate_call=self.assign_random_name, 414 ) 415 416 self._update_clipped_name() 417 self._clipped_name_timer = bui.AppTimer( 418 0.333, bui.WeakCall(self._update_clipped_name), repeat=True 419 ) 420 421 v -= spacing * 3.0 422 b_size = 80 423 b_size_2 = 100 424 b_offs = 150 425 self._color_button = btn = bui.buttonwidget( 426 parent=self._root_widget, 427 autoselect=True, 428 position=(self._width * 0.5 - b_offs - b_size * 0.5, v - 50), 429 size=(b_size, b_size), 430 color=self._color, 431 label='', 432 button_type='square', 433 ) 434 origin = self._color_button.get_screen_space_center() 435 bui.buttonwidget( 436 edit=self._color_button, 437 on_activate_call=bui.WeakCall(self._make_picker, 'color', origin), 438 ) 439 bui.textwidget( 440 parent=self._root_widget, 441 h_align='center', 442 v_align='center', 443 position=(self._width * 0.5 - b_offs, v - 65), 444 size=(0, 0), 445 draw_controller=btn, 446 text=bui.Lstr(resource=f'{self._r}.colorText'), 447 scale=0.7, 448 color=bui.app.ui_v1.title_color, 449 maxwidth=120, 450 ) 451 452 self._character_button = btn = bui.buttonwidget( 453 parent=self._root_widget, 454 autoselect=True, 455 position=(self._width * 0.5 - b_size_2 * 0.5, v - 60), 456 up_widget=self._account_type_info_button, 457 on_activate_call=self._on_character_press, 458 size=(b_size_2, b_size_2), 459 label='', 460 color=(1, 1, 1), 461 mask_texture=bui.gettexture('characterIconMask'), 462 ) 463 if not self._is_account_profile and not self._global: 464 bui.containerwidget( 465 edit=self._root_widget, selected_child=self._text_field 466 ) 467 bui.textwidget( 468 parent=self._root_widget, 469 h_align='center', 470 v_align='center', 471 position=(self._width * 0.5, v - 80), 472 size=(0, 0), 473 draw_controller=btn, 474 text=bui.Lstr(resource=f'{self._r}.characterText'), 475 scale=0.7, 476 color=bui.app.ui_v1.title_color, 477 maxwidth=130, 478 ) 479 480 self._highlight_button = btn = bui.buttonwidget( 481 parent=self._root_widget, 482 autoselect=True, 483 position=(self._width * 0.5 + b_offs - b_size * 0.5, v - 50), 484 up_widget=( 485 self._upgrade_button 486 if self._upgrade_button is not None 487 else self._account_type_info_button 488 ), 489 size=(b_size, b_size), 490 color=self._highlight, 491 label='', 492 button_type='square', 493 ) 494 495 if not self._is_account_profile and not self._global: 496 bui.widget(edit=cancel_button, down_widget=self._text_field) 497 bui.widget(edit=save_button, down_widget=self._text_field) 498 bui.widget(edit=self._color_button, up_widget=self._text_field) 499 bui.widget( 500 edit=self._account_type_info_button, 501 down_widget=self._character_button, 502 ) 503 504 origin = self._highlight_button.get_screen_space_center() 505 bui.buttonwidget( 506 edit=self._highlight_button, 507 on_activate_call=bui.WeakCall( 508 self._make_picker, 'highlight', origin 509 ), 510 ) 511 bui.textwidget( 512 parent=self._root_widget, 513 h_align='center', 514 v_align='center', 515 position=(self._width * 0.5 + b_offs, v - 65), 516 size=(0, 0), 517 draw_controller=btn, 518 text=bui.Lstr(resource=f'{self._r}.highlightText'), 519 scale=0.7, 520 color=bui.app.ui_v1.title_color, 521 maxwidth=120, 522 ) 523 self._update_character() 524 525 @override 526 def get_main_window_state(self) -> bui.MainWindowState: 527 # Support recreating our window for back/refresh purposes. 528 cls = type(self) 529 530 # Pull things out of self here; if we do it within the lambda 531 # we'll keep ourself alive which is bad. 532 533 existing_profile = self._existing_profile 534 return bui.BasicMainWindowState( 535 create_call=lambda transition, origin_widget: cls( 536 transition=transition, 537 origin_widget=origin_widget, 538 existing_profile=existing_profile, 539 ) 540 ) 541 542 def assign_random_name(self) -> None: 543 """Assigning a random name to the player.""" 544 names = bs.get_random_names() 545 name = names[random.randrange(len(names))] 546 bui.textwidget( 547 edit=self._text_field, 548 text=name, 549 ) 550 551 def upgrade_profile(self) -> None: 552 """Attempt to upgrade the profile to global.""" 553 from bauiv1lib import account 554 from bauiv1lib.profile import upgrade as pupgrade 555 556 new_name = self.getname().strip() 557 558 if self._existing_profile and self._existing_profile != new_name: 559 bui.screenmessage( 560 'Unsaved changes found; you must save first.', color=(1, 0, 0) 561 ) 562 bui.getsound('error').play() 563 return 564 565 plus = bui.app.plus 566 assert plus is not None 567 568 if plus.get_v1_account_state() != 'signed_in': 569 account.show_sign_in_prompt() 570 return 571 572 pupgrade.ProfileUpgradeWindow(self) 573 574 def show_account_profile_info(self) -> None: 575 """Show an explanation of account profiles.""" 576 from bauiv1lib.confirm import ConfirmWindow 577 578 icons_str = ' '.join( 579 [ 580 bui.charstr(n) 581 for n in [ 582 bui.SpecialChar.GOOGLE_PLAY_GAMES_LOGO, 583 bui.SpecialChar.GAME_CENTER_LOGO, 584 bui.SpecialChar.LOCAL_ACCOUNT, 585 bui.SpecialChar.OCULUS_LOGO, 586 bui.SpecialChar.NVIDIA_LOGO, 587 bui.SpecialChar.V2_LOGO, 588 ] 589 ] 590 ) 591 txtl = bui.Lstr( 592 resource='editProfileWindow.accountProfileInfoText', 593 subs=[('${ICONS}', icons_str)], 594 ) 595 ConfirmWindow( 596 txtl, 597 cancel_button=False, 598 width=500, 599 height=300, 600 origin_widget=self._account_type_info_button, 601 ) 602 603 def show_local_profile_info(self) -> None: 604 """Show an explanation of local profiles.""" 605 from bauiv1lib.confirm import ConfirmWindow 606 607 txtl = bui.Lstr(resource='editProfileWindow.localProfileInfoText') 608 ConfirmWindow( 609 txtl, 610 cancel_button=False, 611 width=600, 612 height=250, 613 origin_widget=self._account_type_info_button, 614 ) 615 616 def show_global_profile_info(self) -> None: 617 """Show an explanation of global profiles.""" 618 from bauiv1lib.confirm import ConfirmWindow 619 620 txtl = bui.Lstr(resource='editProfileWindow.globalProfileInfoText') 621 ConfirmWindow( 622 txtl, 623 cancel_button=False, 624 width=600, 625 height=250, 626 origin_widget=self._account_type_info_button, 627 ) 628 629 def refresh_characters(self) -> None: 630 """Refresh available characters/icons.""" 631 from bascenev1lib.actor import spazappearance 632 633 assert bui.app.classic is not None 634 635 self._spazzes = spazappearance.get_appearances() 636 self._spazzes.sort() 637 self._icon_textures = [ 638 bui.gettexture(bui.app.classic.spaz_appearances[s].icon_texture) 639 for s in self._spazzes 640 ] 641 self._icon_tint_textures = [ 642 bui.gettexture( 643 bui.app.classic.spaz_appearances[s].icon_mask_texture 644 ) 645 for s in self._spazzes 646 ] 647 648 @override 649 def on_icon_picker_pick(self, icon: str) -> None: 650 """An icon has been selected by the picker.""" 651 self._icon = icon 652 self._update_icon() 653 654 @override 655 def on_icon_picker_get_more_press(self) -> None: 656 """User wants to get more icons.""" 657 from bauiv1lib.store.browser import StoreBrowserWindow 658 659 if not self.main_window_has_control(): 660 return 661 662 self.main_window_replace( 663 StoreBrowserWindow( 664 minimal_toolbars=True, 665 show_tab=StoreBrowserWindow.TabID.ICONS, 666 ) 667 ) 668 669 @override 670 def on_character_picker_pick(self, character: str) -> None: 671 """A character has been selected by the picker.""" 672 if not self._root_widget: 673 return 674 675 # The player could have bought a new one while the picker was 676 # up. 677 self.refresh_characters() 678 self._icon_index = ( 679 self._spazzes.index(character) if character in self._spazzes else 0 680 ) 681 self._update_character() 682 683 @override 684 def on_character_picker_get_more_press(self) -> None: 685 from bauiv1lib.store.browser import StoreBrowserWindow 686 687 if not self.main_window_has_control(): 688 return 689 690 self.main_window_replace( 691 StoreBrowserWindow( 692 minimal_toolbars=True, 693 show_tab=StoreBrowserWindow.TabID.CHARACTERS, 694 ) 695 ) 696 697 def _on_character_press(self) -> None: 698 from bauiv1lib import characterpicker 699 700 characterpicker.CharacterPicker( 701 parent=self._root_widget, 702 position=self._character_button.get_screen_space_center(), 703 selected_character=self._spazzes[self._icon_index], 704 delegate=self, 705 tint_color=self._color, 706 tint2_color=self._highlight, 707 ) 708 709 def _on_icon_press(self) -> None: 710 from bauiv1lib import iconpicker 711 712 iconpicker.IconPicker( 713 parent=self._root_widget, 714 position=self._icon_button.get_screen_space_center(), 715 selected_icon=self._icon, 716 delegate=self, 717 tint_color=self._color, 718 tint2_color=self._highlight, 719 ) 720 721 def _make_picker( 722 self, picker_type: str, origin: tuple[float, float] 723 ) -> None: 724 if picker_type == 'color': 725 initial_color = self._color 726 elif picker_type == 'highlight': 727 initial_color = self._highlight 728 else: 729 raise ValueError('invalid picker_type: ' + picker_type) 730 ColorPicker( 731 parent=self._root_widget, 732 position=origin, 733 offset=( 734 self._base_scale * (-100 if picker_type == 'color' else 100), 735 0, 736 ), 737 initial_color=initial_color, 738 delegate=self, 739 tag=picker_type, 740 ) 741 742 def _cancel(self) -> None: 743 self.main_window_back() 744 745 def _set_color(self, color: tuple[float, float, float]) -> None: 746 self._color = color 747 if self._color_button: 748 bui.buttonwidget(edit=self._color_button, color=color) 749 750 def _set_highlight(self, color: tuple[float, float, float]) -> None: 751 self._highlight = color 752 if self._highlight_button: 753 bui.buttonwidget(edit=self._highlight_button, color=color) 754 755 def color_picker_closing(self, picker: ColorPicker) -> None: 756 """Called when a color picker is closing.""" 757 if not self._root_widget: 758 return 759 tag = picker.get_tag() 760 if tag == 'color': 761 bui.containerwidget( 762 edit=self._root_widget, selected_child=self._color_button 763 ) 764 elif tag == 'highlight': 765 bui.containerwidget( 766 edit=self._root_widget, selected_child=self._highlight_button 767 ) 768 else: 769 print('color_picker_closing got unknown tag ' + str(tag)) 770 771 def color_picker_selected_color( 772 self, picker: ColorPicker, color: tuple[float, float, float] 773 ) -> None: 774 """Called when a color is selected in a color picker.""" 775 if not self._root_widget: 776 return 777 tag = picker.get_tag() 778 if tag == 'color': 779 self._set_color(color) 780 elif tag == 'highlight': 781 self._set_highlight(color) 782 else: 783 print('color_picker_selected_color got unknown tag ' + str(tag)) 784 self._update_character() 785 786 def _update_clipped_name(self) -> None: 787 plus = bui.app.plus 788 assert plus is not None 789 790 if not self._clipped_name_text: 791 return 792 name = self.getname() 793 if name == '__account__': 794 name = ( 795 plus.get_v1_account_name() 796 if plus.get_v1_account_state() == 'signed_in' 797 else '???' 798 ) 799 if len(name) > 10 and not (self._global or self._is_account_profile): 800 name = name.strip() 801 display_name = (name[:10] + '...') if len(name) > 10 else name 802 bui.textwidget( 803 edit=self._clipped_name_text, 804 text=bui.Lstr( 805 resource='inGameClippedNameText', 806 subs=[('${NAME}', display_name)], 807 ), 808 ) 809 else: 810 bui.textwidget(edit=self._clipped_name_text, text='') 811 812 def _update_character(self, change: int = 0) -> None: 813 self._icon_index = (self._icon_index + change) % len(self._spazzes) 814 if self._character_button: 815 bui.buttonwidget( 816 edit=self._character_button, 817 texture=self._icon_textures[self._icon_index], 818 tint_texture=self._icon_tint_textures[self._icon_index], 819 tint_color=self._color, 820 tint2_color=self._highlight, 821 ) 822 823 def _update_icon(self) -> None: 824 if self._icon_button_label: 825 bui.textwidget(edit=self._icon_button_label, text=self._icon) 826 827 def getname(self) -> str: 828 """Return the current profile name value.""" 829 if self._is_account_profile: 830 new_name = '__account__' 831 elif self._global: 832 new_name = self._name 833 else: 834 new_name = cast(str, bui.textwidget(query=self._text_field)) 835 return new_name 836 837 def save(self, transition_out: bool = True) -> bool: 838 """Save has been selected.""" 839 840 # no-op if our underlying widget is dead or on its way out. 841 if not self._root_widget or self._root_widget.transitioning_out: 842 return False 843 844 plus = bui.app.plus 845 assert plus is not None 846 847 new_name = self.getname().strip() 848 849 if not new_name: 850 bui.screenmessage(bui.Lstr(resource='nameNotEmptyText')) 851 bui.getsound('error').play() 852 return False 853 854 # Make sure we're not renaming to another existing profile. 855 profiles: dict = bui.app.config.get('Player Profiles', {}) 856 if self._existing_profile != new_name and new_name in profiles.keys(): 857 bui.screenmessage( 858 bui.Lstr(resource='editProfileWindow.profileAlreadyExistsText') 859 ) 860 bui.getsound('error').play() 861 return False 862 863 if transition_out: 864 bui.getsound('gunCocking').play() 865 866 # Delete old in case we're renaming. 867 if self._existing_profile and self._existing_profile != new_name: 868 plus.add_v1_account_transaction( 869 { 870 'type': 'REMOVE_PLAYER_PROFILE', 871 'name': self._existing_profile, 872 } 873 ) 874 875 # Also lets be aware we're no longer global if we're taking 876 # a new name (will need to re-request it). 877 self._global = False 878 879 plus.add_v1_account_transaction( 880 { 881 'type': 'ADD_PLAYER_PROFILE', 882 'name': new_name, 883 'profile': { 884 'character': self._spazzes[self._icon_index], 885 'color': list(self._color), 886 'global': self._global, 887 'icon': self._icon, 888 'highlight': list(self._highlight), 889 }, 890 } 891 ) 892 893 if transition_out: 894 plus.run_v1_account_transactions() 895 self.main_window_back() 896 897 return True
18class EditProfileWindow( 19 bui.MainWindow, CharacterPickerDelegate, IconPickerDelegate 20): 21 """Window for editing a player profile.""" 22 23 def reload_window(self) -> None: 24 """Transitions out and recreates ourself.""" 25 26 # no-op if we're not in control. 27 if not self.main_window_has_control(): 28 return 29 30 # Replace ourself with ourself, but keep the same back location. 31 assert self.main_window_back_state is not None 32 self.main_window_replace( 33 EditProfileWindow(self.getname()), 34 back_state=self.main_window_back_state, 35 ) 36 37 # def __del__(self) -> None: 38 # print(f'~EditProfileWindow({id(self)})') 39 40 def __init__( 41 self, 42 existing_profile: str | None, 43 transition: str | None = 'in_right', 44 origin_widget: bui.Widget | None = None, 45 ): 46 # FIXME: Tidy this up a bit. 47 # pylint: disable=too-many-branches 48 # pylint: disable=too-many-statements 49 # pylint: disable=too-many-locals 50 51 assert bui.app.classic is not None 52 # print(f'EditProfileWindow({id(self)})') 53 54 plus = bui.app.plus 55 assert plus is not None 56 57 self._existing_profile = existing_profile 58 self._r = 'editProfileWindow' 59 self._spazzes: list[str] = [] 60 self._icon_textures: list[bui.Texture] = [] 61 self._icon_tint_textures: list[bui.Texture] = [] 62 63 # Grab profile colors or pick random ones. 64 ( 65 self._color, 66 self._highlight, 67 ) = bui.app.classic.get_player_profile_colors(existing_profile) 68 uiscale = bui.app.ui_v1.uiscale 69 self._width = width = 880.0 if uiscale is bui.UIScale.SMALL else 680.0 70 self._x_inset = x_inset = 100.0 if uiscale is bui.UIScale.SMALL else 0.0 71 self._height = height = ( 72 500.0 73 if uiscale is bui.UIScale.SMALL 74 else 400.0 if uiscale is bui.UIScale.MEDIUM else 450.0 75 ) 76 yoffs = -42 if uiscale is bui.UIScale.SMALL else 0 77 spacing = 40 78 self._base_scale = ( 79 1.6 80 if uiscale is bui.UIScale.SMALL 81 else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0 82 ) 83 top_extra = 70 if uiscale is bui.UIScale.SMALL else 15 84 super().__init__( 85 root_widget=bui.containerwidget( 86 size=(width, height + top_extra), 87 scale=self._base_scale, 88 stack_offset=( 89 (0, 0) if uiscale is bui.UIScale.SMALL else (0, 0) 90 ), 91 toolbar_visibility=( 92 None if uiscale is bui.UIScale.SMALL else 'menu_full' 93 ), 94 ), 95 transition=transition, 96 origin_widget=origin_widget, 97 ) 98 cancel_button = btn = bui.buttonwidget( 99 parent=self._root_widget, 100 position=(52 + x_inset, height - 60 + yoffs), 101 size=(155, 60), 102 scale=0.8, 103 autoselect=True, 104 label=bui.Lstr(resource='cancelText'), 105 on_activate_call=self._cancel, 106 ) 107 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 108 save_button = btn = bui.buttonwidget( 109 parent=self._root_widget, 110 position=(width - (177 + x_inset), height - 60 + yoffs), 111 size=(155, 60), 112 autoselect=True, 113 scale=0.8, 114 label=bui.Lstr(resource='saveText'), 115 ) 116 bui.widget(edit=save_button, left_widget=cancel_button) 117 bui.widget(edit=cancel_button, right_widget=save_button) 118 bui.containerwidget(edit=self._root_widget, start_button=btn) 119 bui.textwidget( 120 parent=self._root_widget, 121 position=(self._width * 0.5, height - 38 + yoffs), 122 size=(0, 0), 123 text=( 124 bui.Lstr(resource=f'{self._r}.titleNewText') 125 if existing_profile is None 126 else bui.Lstr(resource=f'{self._r}.titleEditText') 127 ), 128 color=bui.app.ui_v1.title_color, 129 maxwidth=290, 130 scale=1.0, 131 h_align='center', 132 v_align='center', 133 ) 134 135 # Make a list of spaz icons. 136 self.refresh_characters() 137 profile = bui.app.config.get('Player Profiles', {}).get( 138 self._existing_profile, {} 139 ) 140 141 if 'global' in profile: 142 self._global = profile['global'] 143 else: 144 self._global = False 145 146 if 'icon' in profile: 147 self._icon = profile['icon'] 148 else: 149 self._icon = bui.charstr(bui.SpecialChar.LOGO) 150 151 assigned_random_char = False 152 153 # Look for existing character choice or pick random one otherwise. 154 try: 155 icon_index = self._spazzes.index(profile['character']) 156 except Exception: 157 # Let's set the default icon to spaz for our first profile; after 158 # that we go random. 159 # (SCRATCH THAT.. we now hard-code account-profiles to start with 160 # spaz which has a similar effect) 161 # try: p_len = len(bui.app.config['Player Profiles']) 162 # except Exception: p_len = 0 163 # if p_len == 0: icon_index = self._spazzes.index('Spaz') 164 # else: 165 random.seed() 166 icon_index = random.randrange(len(self._spazzes)) 167 assigned_random_char = True 168 self._icon_index = icon_index 169 bui.buttonwidget(edit=save_button, on_activate_call=self.save) 170 171 v = height - 115.0 + yoffs 172 self._name = ( 173 '' if self._existing_profile is None else self._existing_profile 174 ) 175 self._is_account_profile = self._name == '__account__' 176 177 # If we just picked a random character, see if it has specific 178 # colors/highlights associated with it and assign them if so. 179 if assigned_random_char: 180 assert bui.app.classic is not None 181 clr = bui.app.classic.spaz_appearances[ 182 self._spazzes[icon_index] 183 ].default_color 184 if clr is not None: 185 self._color = clr 186 highlight = bui.app.classic.spaz_appearances[ 187 self._spazzes[icon_index] 188 ].default_highlight 189 if highlight is not None: 190 self._highlight = highlight 191 192 # Assign a random name if they had none. 193 if self._name == '': 194 names = bs.get_random_names() 195 self._name = names[random.randrange(len(names))] 196 197 self._clipped_name_text = bui.textwidget( 198 parent=self._root_widget, 199 text='', 200 position=(580 + x_inset, v - 8), 201 flatness=1.0, 202 shadow=0.0, 203 scale=0.55, 204 size=(0, 0), 205 maxwidth=100, 206 h_align='center', 207 v_align='center', 208 color=(1, 1, 0, 0.5), 209 ) 210 211 if not self._is_account_profile and not self._global: 212 bui.textwidget( 213 parent=self._root_widget, 214 text=bui.Lstr(resource=f'{self._r}.nameText'), 215 position=(200 + x_inset, v - 6), 216 size=(0, 0), 217 h_align='right', 218 v_align='center', 219 color=(1, 1, 1, 0.5), 220 scale=0.9, 221 ) 222 223 self._upgrade_button = None 224 if self._is_account_profile: 225 if plus.get_v1_account_state() == 'signed_in': 226 sval = plus.get_v1_account_display_string() 227 else: 228 sval = '??' 229 bui.textwidget( 230 parent=self._root_widget, 231 position=(self._width * 0.5, v - 7), 232 size=(0, 0), 233 scale=1.2, 234 text=sval, 235 maxwidth=270, 236 h_align='center', 237 v_align='center', 238 ) 239 txtl = bui.Lstr( 240 resource='editProfileWindow.accountProfileText' 241 ).evaluate() 242 b_width = min( 243 270.0, 244 bui.get_string_width(txtl, suppress_warning=True) * 0.6, 245 ) 246 bui.textwidget( 247 parent=self._root_widget, 248 position=(self._width * 0.5, v - 39), 249 size=(0, 0), 250 scale=0.6, 251 color=bui.app.ui_v1.infotextcolor, 252 text=txtl, 253 maxwidth=270, 254 h_align='center', 255 v_align='center', 256 ) 257 self._account_type_info_button = bui.buttonwidget( 258 parent=self._root_widget, 259 label='?', 260 size=(15, 15), 261 text_scale=0.6, 262 position=(self._width * 0.5 + b_width * 0.5 + 13, v - 47), 263 button_type='square', 264 color=(0.6, 0.5, 0.65), 265 autoselect=True, 266 on_activate_call=self.show_account_profile_info, 267 ) 268 elif self._global: 269 b_size = 60 270 self._icon_button = btn = bui.buttonwidget( 271 parent=self._root_widget, 272 autoselect=True, 273 position=(self._width * 0.5 - 160 - b_size * 0.5, v - 38 - 15), 274 size=(b_size, b_size), 275 color=(0.6, 0.5, 0.6), 276 label='', 277 button_type='square', 278 text_scale=1.2, 279 on_activate_call=self._on_icon_press, 280 ) 281 self._icon_button_label = bui.textwidget( 282 parent=self._root_widget, 283 position=(self._width * 0.5 - 160, v - 35), 284 draw_controller=btn, 285 h_align='center', 286 v_align='center', 287 size=(0, 0), 288 color=(1, 1, 1), 289 text='', 290 scale=2.0, 291 ) 292 293 bui.textwidget( 294 parent=self._root_widget, 295 h_align='center', 296 v_align='center', 297 position=(self._width * 0.5 - 160, v - 55 - 15), 298 size=(0, 0), 299 draw_controller=btn, 300 text=bui.Lstr(resource=f'{self._r}.iconText'), 301 scale=0.7, 302 color=bui.app.ui_v1.title_color, 303 maxwidth=120, 304 ) 305 306 self._update_icon() 307 308 bui.textwidget( 309 parent=self._root_widget, 310 position=(self._width * 0.5, v - 7), 311 size=(0, 0), 312 scale=1.2, 313 text=self._name, 314 maxwidth=240, 315 h_align='center', 316 v_align='center', 317 ) 318 # FIXME hard coded strings are bad 319 txtl = bui.Lstr( 320 resource='editProfileWindow.globalProfileText' 321 ).evaluate() 322 b_width = min( 323 240.0, 324 bui.get_string_width(txtl, suppress_warning=True) * 0.6, 325 ) 326 bui.textwidget( 327 parent=self._root_widget, 328 position=(self._width * 0.5, v - 39), 329 size=(0, 0), 330 scale=0.6, 331 color=bui.app.ui_v1.infotextcolor, 332 text=txtl, 333 maxwidth=240, 334 h_align='center', 335 v_align='center', 336 ) 337 self._account_type_info_button = bui.buttonwidget( 338 parent=self._root_widget, 339 label='?', 340 size=(15, 15), 341 text_scale=0.6, 342 position=(self._width * 0.5 + b_width * 0.5 + 13, v - 47), 343 button_type='square', 344 color=(0.6, 0.5, 0.65), 345 autoselect=True, 346 on_activate_call=self.show_global_profile_info, 347 ) 348 else: 349 self._text_field = bui.textwidget( 350 parent=self._root_widget, 351 position=(220 + x_inset, v - 30), 352 size=(265, 40), 353 text=self._name, 354 h_align='left', 355 v_align='center', 356 max_chars=16, 357 description=bui.Lstr(resource=f'{self._r}.nameDescriptionText'), 358 autoselect=True, 359 editable=True, 360 padding=4, 361 color=(0.9, 0.9, 0.9, 1.0), 362 on_return_press_call=bui.Call(save_button.activate), 363 ) 364 365 # FIXME hard coded strings are bad 366 txtl = bui.Lstr( 367 resource='editProfileWindow.localProfileText' 368 ).evaluate() 369 b_width = min( 370 270.0, 371 bui.get_string_width(txtl, suppress_warning=True) * 0.6, 372 ) 373 bui.textwidget( 374 parent=self._root_widget, 375 position=(self._width * 0.5, v - 43), 376 size=(0, 0), 377 scale=0.6, 378 color=bui.app.ui_v1.infotextcolor, 379 text=txtl, 380 maxwidth=270, 381 h_align='center', 382 v_align='center', 383 ) 384 self._account_type_info_button = bui.buttonwidget( 385 parent=self._root_widget, 386 label='?', 387 size=(15, 15), 388 text_scale=0.6, 389 position=(self._width * 0.5 + b_width * 0.5 + 13, v - 50), 390 button_type='square', 391 color=(0.6, 0.5, 0.65), 392 autoselect=True, 393 on_activate_call=self.show_local_profile_info, 394 ) 395 self._upgrade_button = bui.buttonwidget( 396 parent=self._root_widget, 397 label=bui.Lstr(resource='upgradeText'), 398 size=(40, 17), 399 text_scale=1.0, 400 button_type='square', 401 position=(self._width * 0.5 + b_width * 0.5 + 13 + 43, v - 51), 402 color=(0.6, 0.5, 0.65), 403 autoselect=True, 404 on_activate_call=self.upgrade_profile, 405 ) 406 self._random_name_button = bui.buttonwidget( 407 parent=self._root_widget, 408 label=bui.Lstr(resource='randomText'), 409 size=(30, 20), 410 position=(495 + x_inset, v - 20), 411 button_type='square', 412 color=(0.6, 0.5, 0.65), 413 autoselect=True, 414 on_activate_call=self.assign_random_name, 415 ) 416 417 self._update_clipped_name() 418 self._clipped_name_timer = bui.AppTimer( 419 0.333, bui.WeakCall(self._update_clipped_name), repeat=True 420 ) 421 422 v -= spacing * 3.0 423 b_size = 80 424 b_size_2 = 100 425 b_offs = 150 426 self._color_button = btn = bui.buttonwidget( 427 parent=self._root_widget, 428 autoselect=True, 429 position=(self._width * 0.5 - b_offs - b_size * 0.5, v - 50), 430 size=(b_size, b_size), 431 color=self._color, 432 label='', 433 button_type='square', 434 ) 435 origin = self._color_button.get_screen_space_center() 436 bui.buttonwidget( 437 edit=self._color_button, 438 on_activate_call=bui.WeakCall(self._make_picker, 'color', origin), 439 ) 440 bui.textwidget( 441 parent=self._root_widget, 442 h_align='center', 443 v_align='center', 444 position=(self._width * 0.5 - b_offs, v - 65), 445 size=(0, 0), 446 draw_controller=btn, 447 text=bui.Lstr(resource=f'{self._r}.colorText'), 448 scale=0.7, 449 color=bui.app.ui_v1.title_color, 450 maxwidth=120, 451 ) 452 453 self._character_button = btn = bui.buttonwidget( 454 parent=self._root_widget, 455 autoselect=True, 456 position=(self._width * 0.5 - b_size_2 * 0.5, v - 60), 457 up_widget=self._account_type_info_button, 458 on_activate_call=self._on_character_press, 459 size=(b_size_2, b_size_2), 460 label='', 461 color=(1, 1, 1), 462 mask_texture=bui.gettexture('characterIconMask'), 463 ) 464 if not self._is_account_profile and not self._global: 465 bui.containerwidget( 466 edit=self._root_widget, selected_child=self._text_field 467 ) 468 bui.textwidget( 469 parent=self._root_widget, 470 h_align='center', 471 v_align='center', 472 position=(self._width * 0.5, v - 80), 473 size=(0, 0), 474 draw_controller=btn, 475 text=bui.Lstr(resource=f'{self._r}.characterText'), 476 scale=0.7, 477 color=bui.app.ui_v1.title_color, 478 maxwidth=130, 479 ) 480 481 self._highlight_button = btn = bui.buttonwidget( 482 parent=self._root_widget, 483 autoselect=True, 484 position=(self._width * 0.5 + b_offs - b_size * 0.5, v - 50), 485 up_widget=( 486 self._upgrade_button 487 if self._upgrade_button is not None 488 else self._account_type_info_button 489 ), 490 size=(b_size, b_size), 491 color=self._highlight, 492 label='', 493 button_type='square', 494 ) 495 496 if not self._is_account_profile and not self._global: 497 bui.widget(edit=cancel_button, down_widget=self._text_field) 498 bui.widget(edit=save_button, down_widget=self._text_field) 499 bui.widget(edit=self._color_button, up_widget=self._text_field) 500 bui.widget( 501 edit=self._account_type_info_button, 502 down_widget=self._character_button, 503 ) 504 505 origin = self._highlight_button.get_screen_space_center() 506 bui.buttonwidget( 507 edit=self._highlight_button, 508 on_activate_call=bui.WeakCall( 509 self._make_picker, 'highlight', origin 510 ), 511 ) 512 bui.textwidget( 513 parent=self._root_widget, 514 h_align='center', 515 v_align='center', 516 position=(self._width * 0.5 + b_offs, v - 65), 517 size=(0, 0), 518 draw_controller=btn, 519 text=bui.Lstr(resource=f'{self._r}.highlightText'), 520 scale=0.7, 521 color=bui.app.ui_v1.title_color, 522 maxwidth=120, 523 ) 524 self._update_character() 525 526 @override 527 def get_main_window_state(self) -> bui.MainWindowState: 528 # Support recreating our window for back/refresh purposes. 529 cls = type(self) 530 531 # Pull things out of self here; if we do it within the lambda 532 # we'll keep ourself alive which is bad. 533 534 existing_profile = self._existing_profile 535 return bui.BasicMainWindowState( 536 create_call=lambda transition, origin_widget: cls( 537 transition=transition, 538 origin_widget=origin_widget, 539 existing_profile=existing_profile, 540 ) 541 ) 542 543 def assign_random_name(self) -> None: 544 """Assigning a random name to the player.""" 545 names = bs.get_random_names() 546 name = names[random.randrange(len(names))] 547 bui.textwidget( 548 edit=self._text_field, 549 text=name, 550 ) 551 552 def upgrade_profile(self) -> None: 553 """Attempt to upgrade the profile to global.""" 554 from bauiv1lib import account 555 from bauiv1lib.profile import upgrade as pupgrade 556 557 new_name = self.getname().strip() 558 559 if self._existing_profile and self._existing_profile != new_name: 560 bui.screenmessage( 561 'Unsaved changes found; you must save first.', color=(1, 0, 0) 562 ) 563 bui.getsound('error').play() 564 return 565 566 plus = bui.app.plus 567 assert plus is not None 568 569 if plus.get_v1_account_state() != 'signed_in': 570 account.show_sign_in_prompt() 571 return 572 573 pupgrade.ProfileUpgradeWindow(self) 574 575 def show_account_profile_info(self) -> None: 576 """Show an explanation of account profiles.""" 577 from bauiv1lib.confirm import ConfirmWindow 578 579 icons_str = ' '.join( 580 [ 581 bui.charstr(n) 582 for n in [ 583 bui.SpecialChar.GOOGLE_PLAY_GAMES_LOGO, 584 bui.SpecialChar.GAME_CENTER_LOGO, 585 bui.SpecialChar.LOCAL_ACCOUNT, 586 bui.SpecialChar.OCULUS_LOGO, 587 bui.SpecialChar.NVIDIA_LOGO, 588 bui.SpecialChar.V2_LOGO, 589 ] 590 ] 591 ) 592 txtl = bui.Lstr( 593 resource='editProfileWindow.accountProfileInfoText', 594 subs=[('${ICONS}', icons_str)], 595 ) 596 ConfirmWindow( 597 txtl, 598 cancel_button=False, 599 width=500, 600 height=300, 601 origin_widget=self._account_type_info_button, 602 ) 603 604 def show_local_profile_info(self) -> None: 605 """Show an explanation of local profiles.""" 606 from bauiv1lib.confirm import ConfirmWindow 607 608 txtl = bui.Lstr(resource='editProfileWindow.localProfileInfoText') 609 ConfirmWindow( 610 txtl, 611 cancel_button=False, 612 width=600, 613 height=250, 614 origin_widget=self._account_type_info_button, 615 ) 616 617 def show_global_profile_info(self) -> None: 618 """Show an explanation of global profiles.""" 619 from bauiv1lib.confirm import ConfirmWindow 620 621 txtl = bui.Lstr(resource='editProfileWindow.globalProfileInfoText') 622 ConfirmWindow( 623 txtl, 624 cancel_button=False, 625 width=600, 626 height=250, 627 origin_widget=self._account_type_info_button, 628 ) 629 630 def refresh_characters(self) -> None: 631 """Refresh available characters/icons.""" 632 from bascenev1lib.actor import spazappearance 633 634 assert bui.app.classic is not None 635 636 self._spazzes = spazappearance.get_appearances() 637 self._spazzes.sort() 638 self._icon_textures = [ 639 bui.gettexture(bui.app.classic.spaz_appearances[s].icon_texture) 640 for s in self._spazzes 641 ] 642 self._icon_tint_textures = [ 643 bui.gettexture( 644 bui.app.classic.spaz_appearances[s].icon_mask_texture 645 ) 646 for s in self._spazzes 647 ] 648 649 @override 650 def on_icon_picker_pick(self, icon: str) -> None: 651 """An icon has been selected by the picker.""" 652 self._icon = icon 653 self._update_icon() 654 655 @override 656 def on_icon_picker_get_more_press(self) -> None: 657 """User wants to get more icons.""" 658 from bauiv1lib.store.browser import StoreBrowserWindow 659 660 if not self.main_window_has_control(): 661 return 662 663 self.main_window_replace( 664 StoreBrowserWindow( 665 minimal_toolbars=True, 666 show_tab=StoreBrowserWindow.TabID.ICONS, 667 ) 668 ) 669 670 @override 671 def on_character_picker_pick(self, character: str) -> None: 672 """A character has been selected by the picker.""" 673 if not self._root_widget: 674 return 675 676 # The player could have bought a new one while the picker was 677 # up. 678 self.refresh_characters() 679 self._icon_index = ( 680 self._spazzes.index(character) if character in self._spazzes else 0 681 ) 682 self._update_character() 683 684 @override 685 def on_character_picker_get_more_press(self) -> None: 686 from bauiv1lib.store.browser import StoreBrowserWindow 687 688 if not self.main_window_has_control(): 689 return 690 691 self.main_window_replace( 692 StoreBrowserWindow( 693 minimal_toolbars=True, 694 show_tab=StoreBrowserWindow.TabID.CHARACTERS, 695 ) 696 ) 697 698 def _on_character_press(self) -> None: 699 from bauiv1lib import characterpicker 700 701 characterpicker.CharacterPicker( 702 parent=self._root_widget, 703 position=self._character_button.get_screen_space_center(), 704 selected_character=self._spazzes[self._icon_index], 705 delegate=self, 706 tint_color=self._color, 707 tint2_color=self._highlight, 708 ) 709 710 def _on_icon_press(self) -> None: 711 from bauiv1lib import iconpicker 712 713 iconpicker.IconPicker( 714 parent=self._root_widget, 715 position=self._icon_button.get_screen_space_center(), 716 selected_icon=self._icon, 717 delegate=self, 718 tint_color=self._color, 719 tint2_color=self._highlight, 720 ) 721 722 def _make_picker( 723 self, picker_type: str, origin: tuple[float, float] 724 ) -> None: 725 if picker_type == 'color': 726 initial_color = self._color 727 elif picker_type == 'highlight': 728 initial_color = self._highlight 729 else: 730 raise ValueError('invalid picker_type: ' + picker_type) 731 ColorPicker( 732 parent=self._root_widget, 733 position=origin, 734 offset=( 735 self._base_scale * (-100 if picker_type == 'color' else 100), 736 0, 737 ), 738 initial_color=initial_color, 739 delegate=self, 740 tag=picker_type, 741 ) 742 743 def _cancel(self) -> None: 744 self.main_window_back() 745 746 def _set_color(self, color: tuple[float, float, float]) -> None: 747 self._color = color 748 if self._color_button: 749 bui.buttonwidget(edit=self._color_button, color=color) 750 751 def _set_highlight(self, color: tuple[float, float, float]) -> None: 752 self._highlight = color 753 if self._highlight_button: 754 bui.buttonwidget(edit=self._highlight_button, color=color) 755 756 def color_picker_closing(self, picker: ColorPicker) -> None: 757 """Called when a color picker is closing.""" 758 if not self._root_widget: 759 return 760 tag = picker.get_tag() 761 if tag == 'color': 762 bui.containerwidget( 763 edit=self._root_widget, selected_child=self._color_button 764 ) 765 elif tag == 'highlight': 766 bui.containerwidget( 767 edit=self._root_widget, selected_child=self._highlight_button 768 ) 769 else: 770 print('color_picker_closing got unknown tag ' + str(tag)) 771 772 def color_picker_selected_color( 773 self, picker: ColorPicker, color: tuple[float, float, float] 774 ) -> None: 775 """Called when a color is selected in a color picker.""" 776 if not self._root_widget: 777 return 778 tag = picker.get_tag() 779 if tag == 'color': 780 self._set_color(color) 781 elif tag == 'highlight': 782 self._set_highlight(color) 783 else: 784 print('color_picker_selected_color got unknown tag ' + str(tag)) 785 self._update_character() 786 787 def _update_clipped_name(self) -> None: 788 plus = bui.app.plus 789 assert plus is not None 790 791 if not self._clipped_name_text: 792 return 793 name = self.getname() 794 if name == '__account__': 795 name = ( 796 plus.get_v1_account_name() 797 if plus.get_v1_account_state() == 'signed_in' 798 else '???' 799 ) 800 if len(name) > 10 and not (self._global or self._is_account_profile): 801 name = name.strip() 802 display_name = (name[:10] + '...') if len(name) > 10 else name 803 bui.textwidget( 804 edit=self._clipped_name_text, 805 text=bui.Lstr( 806 resource='inGameClippedNameText', 807 subs=[('${NAME}', display_name)], 808 ), 809 ) 810 else: 811 bui.textwidget(edit=self._clipped_name_text, text='') 812 813 def _update_character(self, change: int = 0) -> None: 814 self._icon_index = (self._icon_index + change) % len(self._spazzes) 815 if self._character_button: 816 bui.buttonwidget( 817 edit=self._character_button, 818 texture=self._icon_textures[self._icon_index], 819 tint_texture=self._icon_tint_textures[self._icon_index], 820 tint_color=self._color, 821 tint2_color=self._highlight, 822 ) 823 824 def _update_icon(self) -> None: 825 if self._icon_button_label: 826 bui.textwidget(edit=self._icon_button_label, text=self._icon) 827 828 def getname(self) -> str: 829 """Return the current profile name value.""" 830 if self._is_account_profile: 831 new_name = '__account__' 832 elif self._global: 833 new_name = self._name 834 else: 835 new_name = cast(str, bui.textwidget(query=self._text_field)) 836 return new_name 837 838 def save(self, transition_out: bool = True) -> bool: 839 """Save has been selected.""" 840 841 # no-op if our underlying widget is dead or on its way out. 842 if not self._root_widget or self._root_widget.transitioning_out: 843 return False 844 845 plus = bui.app.plus 846 assert plus is not None 847 848 new_name = self.getname().strip() 849 850 if not new_name: 851 bui.screenmessage(bui.Lstr(resource='nameNotEmptyText')) 852 bui.getsound('error').play() 853 return False 854 855 # Make sure we're not renaming to another existing profile. 856 profiles: dict = bui.app.config.get('Player Profiles', {}) 857 if self._existing_profile != new_name and new_name in profiles.keys(): 858 bui.screenmessage( 859 bui.Lstr(resource='editProfileWindow.profileAlreadyExistsText') 860 ) 861 bui.getsound('error').play() 862 return False 863 864 if transition_out: 865 bui.getsound('gunCocking').play() 866 867 # Delete old in case we're renaming. 868 if self._existing_profile and self._existing_profile != new_name: 869 plus.add_v1_account_transaction( 870 { 871 'type': 'REMOVE_PLAYER_PROFILE', 872 'name': self._existing_profile, 873 } 874 ) 875 876 # Also lets be aware we're no longer global if we're taking 877 # a new name (will need to re-request it). 878 self._global = False 879 880 plus.add_v1_account_transaction( 881 { 882 'type': 'ADD_PLAYER_PROFILE', 883 'name': new_name, 884 'profile': { 885 'character': self._spazzes[self._icon_index], 886 'color': list(self._color), 887 'global': self._global, 888 'icon': self._icon, 889 'highlight': list(self._highlight), 890 }, 891 } 892 ) 893 894 if transition_out: 895 plus.run_v1_account_transactions() 896 self.main_window_back() 897 898 return True
Window for editing a player profile.
40 def __init__( 41 self, 42 existing_profile: str | None, 43 transition: str | None = 'in_right', 44 origin_widget: bui.Widget | None = None, 45 ): 46 # FIXME: Tidy this up a bit. 47 # pylint: disable=too-many-branches 48 # pylint: disable=too-many-statements 49 # pylint: disable=too-many-locals 50 51 assert bui.app.classic is not None 52 # print(f'EditProfileWindow({id(self)})') 53 54 plus = bui.app.plus 55 assert plus is not None 56 57 self._existing_profile = existing_profile 58 self._r = 'editProfileWindow' 59 self._spazzes: list[str] = [] 60 self._icon_textures: list[bui.Texture] = [] 61 self._icon_tint_textures: list[bui.Texture] = [] 62 63 # Grab profile colors or pick random ones. 64 ( 65 self._color, 66 self._highlight, 67 ) = bui.app.classic.get_player_profile_colors(existing_profile) 68 uiscale = bui.app.ui_v1.uiscale 69 self._width = width = 880.0 if uiscale is bui.UIScale.SMALL else 680.0 70 self._x_inset = x_inset = 100.0 if uiscale is bui.UIScale.SMALL else 0.0 71 self._height = height = ( 72 500.0 73 if uiscale is bui.UIScale.SMALL 74 else 400.0 if uiscale is bui.UIScale.MEDIUM else 450.0 75 ) 76 yoffs = -42 if uiscale is bui.UIScale.SMALL else 0 77 spacing = 40 78 self._base_scale = ( 79 1.6 80 if uiscale is bui.UIScale.SMALL 81 else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0 82 ) 83 top_extra = 70 if uiscale is bui.UIScale.SMALL else 15 84 super().__init__( 85 root_widget=bui.containerwidget( 86 size=(width, height + top_extra), 87 scale=self._base_scale, 88 stack_offset=( 89 (0, 0) if uiscale is bui.UIScale.SMALL else (0, 0) 90 ), 91 toolbar_visibility=( 92 None if uiscale is bui.UIScale.SMALL else 'menu_full' 93 ), 94 ), 95 transition=transition, 96 origin_widget=origin_widget, 97 ) 98 cancel_button = btn = bui.buttonwidget( 99 parent=self._root_widget, 100 position=(52 + x_inset, height - 60 + yoffs), 101 size=(155, 60), 102 scale=0.8, 103 autoselect=True, 104 label=bui.Lstr(resource='cancelText'), 105 on_activate_call=self._cancel, 106 ) 107 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 108 save_button = btn = bui.buttonwidget( 109 parent=self._root_widget, 110 position=(width - (177 + x_inset), height - 60 + yoffs), 111 size=(155, 60), 112 autoselect=True, 113 scale=0.8, 114 label=bui.Lstr(resource='saveText'), 115 ) 116 bui.widget(edit=save_button, left_widget=cancel_button) 117 bui.widget(edit=cancel_button, right_widget=save_button) 118 bui.containerwidget(edit=self._root_widget, start_button=btn) 119 bui.textwidget( 120 parent=self._root_widget, 121 position=(self._width * 0.5, height - 38 + yoffs), 122 size=(0, 0), 123 text=( 124 bui.Lstr(resource=f'{self._r}.titleNewText') 125 if existing_profile is None 126 else bui.Lstr(resource=f'{self._r}.titleEditText') 127 ), 128 color=bui.app.ui_v1.title_color, 129 maxwidth=290, 130 scale=1.0, 131 h_align='center', 132 v_align='center', 133 ) 134 135 # Make a list of spaz icons. 136 self.refresh_characters() 137 profile = bui.app.config.get('Player Profiles', {}).get( 138 self._existing_profile, {} 139 ) 140 141 if 'global' in profile: 142 self._global = profile['global'] 143 else: 144 self._global = False 145 146 if 'icon' in profile: 147 self._icon = profile['icon'] 148 else: 149 self._icon = bui.charstr(bui.SpecialChar.LOGO) 150 151 assigned_random_char = False 152 153 # Look for existing character choice or pick random one otherwise. 154 try: 155 icon_index = self._spazzes.index(profile['character']) 156 except Exception: 157 # Let's set the default icon to spaz for our first profile; after 158 # that we go random. 159 # (SCRATCH THAT.. we now hard-code account-profiles to start with 160 # spaz which has a similar effect) 161 # try: p_len = len(bui.app.config['Player Profiles']) 162 # except Exception: p_len = 0 163 # if p_len == 0: icon_index = self._spazzes.index('Spaz') 164 # else: 165 random.seed() 166 icon_index = random.randrange(len(self._spazzes)) 167 assigned_random_char = True 168 self._icon_index = icon_index 169 bui.buttonwidget(edit=save_button, on_activate_call=self.save) 170 171 v = height - 115.0 + yoffs 172 self._name = ( 173 '' if self._existing_profile is None else self._existing_profile 174 ) 175 self._is_account_profile = self._name == '__account__' 176 177 # If we just picked a random character, see if it has specific 178 # colors/highlights associated with it and assign them if so. 179 if assigned_random_char: 180 assert bui.app.classic is not None 181 clr = bui.app.classic.spaz_appearances[ 182 self._spazzes[icon_index] 183 ].default_color 184 if clr is not None: 185 self._color = clr 186 highlight = bui.app.classic.spaz_appearances[ 187 self._spazzes[icon_index] 188 ].default_highlight 189 if highlight is not None: 190 self._highlight = highlight 191 192 # Assign a random name if they had none. 193 if self._name == '': 194 names = bs.get_random_names() 195 self._name = names[random.randrange(len(names))] 196 197 self._clipped_name_text = bui.textwidget( 198 parent=self._root_widget, 199 text='', 200 position=(580 + x_inset, v - 8), 201 flatness=1.0, 202 shadow=0.0, 203 scale=0.55, 204 size=(0, 0), 205 maxwidth=100, 206 h_align='center', 207 v_align='center', 208 color=(1, 1, 0, 0.5), 209 ) 210 211 if not self._is_account_profile and not self._global: 212 bui.textwidget( 213 parent=self._root_widget, 214 text=bui.Lstr(resource=f'{self._r}.nameText'), 215 position=(200 + x_inset, v - 6), 216 size=(0, 0), 217 h_align='right', 218 v_align='center', 219 color=(1, 1, 1, 0.5), 220 scale=0.9, 221 ) 222 223 self._upgrade_button = None 224 if self._is_account_profile: 225 if plus.get_v1_account_state() == 'signed_in': 226 sval = plus.get_v1_account_display_string() 227 else: 228 sval = '??' 229 bui.textwidget( 230 parent=self._root_widget, 231 position=(self._width * 0.5, v - 7), 232 size=(0, 0), 233 scale=1.2, 234 text=sval, 235 maxwidth=270, 236 h_align='center', 237 v_align='center', 238 ) 239 txtl = bui.Lstr( 240 resource='editProfileWindow.accountProfileText' 241 ).evaluate() 242 b_width = min( 243 270.0, 244 bui.get_string_width(txtl, suppress_warning=True) * 0.6, 245 ) 246 bui.textwidget( 247 parent=self._root_widget, 248 position=(self._width * 0.5, v - 39), 249 size=(0, 0), 250 scale=0.6, 251 color=bui.app.ui_v1.infotextcolor, 252 text=txtl, 253 maxwidth=270, 254 h_align='center', 255 v_align='center', 256 ) 257 self._account_type_info_button = bui.buttonwidget( 258 parent=self._root_widget, 259 label='?', 260 size=(15, 15), 261 text_scale=0.6, 262 position=(self._width * 0.5 + b_width * 0.5 + 13, v - 47), 263 button_type='square', 264 color=(0.6, 0.5, 0.65), 265 autoselect=True, 266 on_activate_call=self.show_account_profile_info, 267 ) 268 elif self._global: 269 b_size = 60 270 self._icon_button = btn = bui.buttonwidget( 271 parent=self._root_widget, 272 autoselect=True, 273 position=(self._width * 0.5 - 160 - b_size * 0.5, v - 38 - 15), 274 size=(b_size, b_size), 275 color=(0.6, 0.5, 0.6), 276 label='', 277 button_type='square', 278 text_scale=1.2, 279 on_activate_call=self._on_icon_press, 280 ) 281 self._icon_button_label = bui.textwidget( 282 parent=self._root_widget, 283 position=(self._width * 0.5 - 160, v - 35), 284 draw_controller=btn, 285 h_align='center', 286 v_align='center', 287 size=(0, 0), 288 color=(1, 1, 1), 289 text='', 290 scale=2.0, 291 ) 292 293 bui.textwidget( 294 parent=self._root_widget, 295 h_align='center', 296 v_align='center', 297 position=(self._width * 0.5 - 160, v - 55 - 15), 298 size=(0, 0), 299 draw_controller=btn, 300 text=bui.Lstr(resource=f'{self._r}.iconText'), 301 scale=0.7, 302 color=bui.app.ui_v1.title_color, 303 maxwidth=120, 304 ) 305 306 self._update_icon() 307 308 bui.textwidget( 309 parent=self._root_widget, 310 position=(self._width * 0.5, v - 7), 311 size=(0, 0), 312 scale=1.2, 313 text=self._name, 314 maxwidth=240, 315 h_align='center', 316 v_align='center', 317 ) 318 # FIXME hard coded strings are bad 319 txtl = bui.Lstr( 320 resource='editProfileWindow.globalProfileText' 321 ).evaluate() 322 b_width = min( 323 240.0, 324 bui.get_string_width(txtl, suppress_warning=True) * 0.6, 325 ) 326 bui.textwidget( 327 parent=self._root_widget, 328 position=(self._width * 0.5, v - 39), 329 size=(0, 0), 330 scale=0.6, 331 color=bui.app.ui_v1.infotextcolor, 332 text=txtl, 333 maxwidth=240, 334 h_align='center', 335 v_align='center', 336 ) 337 self._account_type_info_button = bui.buttonwidget( 338 parent=self._root_widget, 339 label='?', 340 size=(15, 15), 341 text_scale=0.6, 342 position=(self._width * 0.5 + b_width * 0.5 + 13, v - 47), 343 button_type='square', 344 color=(0.6, 0.5, 0.65), 345 autoselect=True, 346 on_activate_call=self.show_global_profile_info, 347 ) 348 else: 349 self._text_field = bui.textwidget( 350 parent=self._root_widget, 351 position=(220 + x_inset, v - 30), 352 size=(265, 40), 353 text=self._name, 354 h_align='left', 355 v_align='center', 356 max_chars=16, 357 description=bui.Lstr(resource=f'{self._r}.nameDescriptionText'), 358 autoselect=True, 359 editable=True, 360 padding=4, 361 color=(0.9, 0.9, 0.9, 1.0), 362 on_return_press_call=bui.Call(save_button.activate), 363 ) 364 365 # FIXME hard coded strings are bad 366 txtl = bui.Lstr( 367 resource='editProfileWindow.localProfileText' 368 ).evaluate() 369 b_width = min( 370 270.0, 371 bui.get_string_width(txtl, suppress_warning=True) * 0.6, 372 ) 373 bui.textwidget( 374 parent=self._root_widget, 375 position=(self._width * 0.5, v - 43), 376 size=(0, 0), 377 scale=0.6, 378 color=bui.app.ui_v1.infotextcolor, 379 text=txtl, 380 maxwidth=270, 381 h_align='center', 382 v_align='center', 383 ) 384 self._account_type_info_button = bui.buttonwidget( 385 parent=self._root_widget, 386 label='?', 387 size=(15, 15), 388 text_scale=0.6, 389 position=(self._width * 0.5 + b_width * 0.5 + 13, v - 50), 390 button_type='square', 391 color=(0.6, 0.5, 0.65), 392 autoselect=True, 393 on_activate_call=self.show_local_profile_info, 394 ) 395 self._upgrade_button = bui.buttonwidget( 396 parent=self._root_widget, 397 label=bui.Lstr(resource='upgradeText'), 398 size=(40, 17), 399 text_scale=1.0, 400 button_type='square', 401 position=(self._width * 0.5 + b_width * 0.5 + 13 + 43, v - 51), 402 color=(0.6, 0.5, 0.65), 403 autoselect=True, 404 on_activate_call=self.upgrade_profile, 405 ) 406 self._random_name_button = bui.buttonwidget( 407 parent=self._root_widget, 408 label=bui.Lstr(resource='randomText'), 409 size=(30, 20), 410 position=(495 + x_inset, v - 20), 411 button_type='square', 412 color=(0.6, 0.5, 0.65), 413 autoselect=True, 414 on_activate_call=self.assign_random_name, 415 ) 416 417 self._update_clipped_name() 418 self._clipped_name_timer = bui.AppTimer( 419 0.333, bui.WeakCall(self._update_clipped_name), repeat=True 420 ) 421 422 v -= spacing * 3.0 423 b_size = 80 424 b_size_2 = 100 425 b_offs = 150 426 self._color_button = btn = bui.buttonwidget( 427 parent=self._root_widget, 428 autoselect=True, 429 position=(self._width * 0.5 - b_offs - b_size * 0.5, v - 50), 430 size=(b_size, b_size), 431 color=self._color, 432 label='', 433 button_type='square', 434 ) 435 origin = self._color_button.get_screen_space_center() 436 bui.buttonwidget( 437 edit=self._color_button, 438 on_activate_call=bui.WeakCall(self._make_picker, 'color', origin), 439 ) 440 bui.textwidget( 441 parent=self._root_widget, 442 h_align='center', 443 v_align='center', 444 position=(self._width * 0.5 - b_offs, v - 65), 445 size=(0, 0), 446 draw_controller=btn, 447 text=bui.Lstr(resource=f'{self._r}.colorText'), 448 scale=0.7, 449 color=bui.app.ui_v1.title_color, 450 maxwidth=120, 451 ) 452 453 self._character_button = btn = bui.buttonwidget( 454 parent=self._root_widget, 455 autoselect=True, 456 position=(self._width * 0.5 - b_size_2 * 0.5, v - 60), 457 up_widget=self._account_type_info_button, 458 on_activate_call=self._on_character_press, 459 size=(b_size_2, b_size_2), 460 label='', 461 color=(1, 1, 1), 462 mask_texture=bui.gettexture('characterIconMask'), 463 ) 464 if not self._is_account_profile and not self._global: 465 bui.containerwidget( 466 edit=self._root_widget, selected_child=self._text_field 467 ) 468 bui.textwidget( 469 parent=self._root_widget, 470 h_align='center', 471 v_align='center', 472 position=(self._width * 0.5, v - 80), 473 size=(0, 0), 474 draw_controller=btn, 475 text=bui.Lstr(resource=f'{self._r}.characterText'), 476 scale=0.7, 477 color=bui.app.ui_v1.title_color, 478 maxwidth=130, 479 ) 480 481 self._highlight_button = btn = bui.buttonwidget( 482 parent=self._root_widget, 483 autoselect=True, 484 position=(self._width * 0.5 + b_offs - b_size * 0.5, v - 50), 485 up_widget=( 486 self._upgrade_button 487 if self._upgrade_button is not None 488 else self._account_type_info_button 489 ), 490 size=(b_size, b_size), 491 color=self._highlight, 492 label='', 493 button_type='square', 494 ) 495 496 if not self._is_account_profile and not self._global: 497 bui.widget(edit=cancel_button, down_widget=self._text_field) 498 bui.widget(edit=save_button, down_widget=self._text_field) 499 bui.widget(edit=self._color_button, up_widget=self._text_field) 500 bui.widget( 501 edit=self._account_type_info_button, 502 down_widget=self._character_button, 503 ) 504 505 origin = self._highlight_button.get_screen_space_center() 506 bui.buttonwidget( 507 edit=self._highlight_button, 508 on_activate_call=bui.WeakCall( 509 self._make_picker, 'highlight', origin 510 ), 511 ) 512 bui.textwidget( 513 parent=self._root_widget, 514 h_align='center', 515 v_align='center', 516 position=(self._width * 0.5 + b_offs, v - 65), 517 size=(0, 0), 518 draw_controller=btn, 519 text=bui.Lstr(resource=f'{self._r}.highlightText'), 520 scale=0.7, 521 color=bui.app.ui_v1.title_color, 522 maxwidth=120, 523 ) 524 self._update_character()
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.
23 def reload_window(self) -> None: 24 """Transitions out and recreates ourself.""" 25 26 # no-op if we're not in control. 27 if not self.main_window_has_control(): 28 return 29 30 # Replace ourself with ourself, but keep the same back location. 31 assert self.main_window_back_state is not None 32 self.main_window_replace( 33 EditProfileWindow(self.getname()), 34 back_state=self.main_window_back_state, 35 )
Transitions out and recreates ourself.
526 @override 527 def get_main_window_state(self) -> bui.MainWindowState: 528 # Support recreating our window for back/refresh purposes. 529 cls = type(self) 530 531 # Pull things out of self here; if we do it within the lambda 532 # we'll keep ourself alive which is bad. 533 534 existing_profile = self._existing_profile 535 return bui.BasicMainWindowState( 536 create_call=lambda transition, origin_widget: cls( 537 transition=transition, 538 origin_widget=origin_widget, 539 existing_profile=existing_profile, 540 ) 541 )
Return a WindowState to recreate this window, if supported.
543 def assign_random_name(self) -> None: 544 """Assigning a random name to the player.""" 545 names = bs.get_random_names() 546 name = names[random.randrange(len(names))] 547 bui.textwidget( 548 edit=self._text_field, 549 text=name, 550 )
Assigning a random name to the player.
552 def upgrade_profile(self) -> None: 553 """Attempt to upgrade the profile to global.""" 554 from bauiv1lib import account 555 from bauiv1lib.profile import upgrade as pupgrade 556 557 new_name = self.getname().strip() 558 559 if self._existing_profile and self._existing_profile != new_name: 560 bui.screenmessage( 561 'Unsaved changes found; you must save first.', color=(1, 0, 0) 562 ) 563 bui.getsound('error').play() 564 return 565 566 plus = bui.app.plus 567 assert plus is not None 568 569 if plus.get_v1_account_state() != 'signed_in': 570 account.show_sign_in_prompt() 571 return 572 573 pupgrade.ProfileUpgradeWindow(self)
Attempt to upgrade the profile to global.
575 def show_account_profile_info(self) -> None: 576 """Show an explanation of account profiles.""" 577 from bauiv1lib.confirm import ConfirmWindow 578 579 icons_str = ' '.join( 580 [ 581 bui.charstr(n) 582 for n in [ 583 bui.SpecialChar.GOOGLE_PLAY_GAMES_LOGO, 584 bui.SpecialChar.GAME_CENTER_LOGO, 585 bui.SpecialChar.LOCAL_ACCOUNT, 586 bui.SpecialChar.OCULUS_LOGO, 587 bui.SpecialChar.NVIDIA_LOGO, 588 bui.SpecialChar.V2_LOGO, 589 ] 590 ] 591 ) 592 txtl = bui.Lstr( 593 resource='editProfileWindow.accountProfileInfoText', 594 subs=[('${ICONS}', icons_str)], 595 ) 596 ConfirmWindow( 597 txtl, 598 cancel_button=False, 599 width=500, 600 height=300, 601 origin_widget=self._account_type_info_button, 602 )
Show an explanation of account profiles.
604 def show_local_profile_info(self) -> None: 605 """Show an explanation of local profiles.""" 606 from bauiv1lib.confirm import ConfirmWindow 607 608 txtl = bui.Lstr(resource='editProfileWindow.localProfileInfoText') 609 ConfirmWindow( 610 txtl, 611 cancel_button=False, 612 width=600, 613 height=250, 614 origin_widget=self._account_type_info_button, 615 )
Show an explanation of local profiles.
617 def show_global_profile_info(self) -> None: 618 """Show an explanation of global profiles.""" 619 from bauiv1lib.confirm import ConfirmWindow 620 621 txtl = bui.Lstr(resource='editProfileWindow.globalProfileInfoText') 622 ConfirmWindow( 623 txtl, 624 cancel_button=False, 625 width=600, 626 height=250, 627 origin_widget=self._account_type_info_button, 628 )
Show an explanation of global profiles.
630 def refresh_characters(self) -> None: 631 """Refresh available characters/icons.""" 632 from bascenev1lib.actor import spazappearance 633 634 assert bui.app.classic is not None 635 636 self._spazzes = spazappearance.get_appearances() 637 self._spazzes.sort() 638 self._icon_textures = [ 639 bui.gettexture(bui.app.classic.spaz_appearances[s].icon_texture) 640 for s in self._spazzes 641 ] 642 self._icon_tint_textures = [ 643 bui.gettexture( 644 bui.app.classic.spaz_appearances[s].icon_mask_texture 645 ) 646 for s in self._spazzes 647 ]
Refresh available characters/icons.
649 @override 650 def on_icon_picker_pick(self, icon: str) -> None: 651 """An icon has been selected by the picker.""" 652 self._icon = icon 653 self._update_icon()
An icon has been selected by the picker.
655 @override 656 def on_icon_picker_get_more_press(self) -> None: 657 """User wants to get more icons.""" 658 from bauiv1lib.store.browser import StoreBrowserWindow 659 660 if not self.main_window_has_control(): 661 return 662 663 self.main_window_replace( 664 StoreBrowserWindow( 665 minimal_toolbars=True, 666 show_tab=StoreBrowserWindow.TabID.ICONS, 667 ) 668 )
User wants to get more icons.
670 @override 671 def on_character_picker_pick(self, character: str) -> None: 672 """A character has been selected by the picker.""" 673 if not self._root_widget: 674 return 675 676 # The player could have bought a new one while the picker was 677 # up. 678 self.refresh_characters() 679 self._icon_index = ( 680 self._spazzes.index(character) if character in self._spazzes else 0 681 ) 682 self._update_character()
A character has been selected by the picker.
684 @override 685 def on_character_picker_get_more_press(self) -> None: 686 from bauiv1lib.store.browser import StoreBrowserWindow 687 688 if not self.main_window_has_control(): 689 return 690 691 self.main_window_replace( 692 StoreBrowserWindow( 693 minimal_toolbars=True, 694 show_tab=StoreBrowserWindow.TabID.CHARACTERS, 695 ) 696 )
Called when the 'get more characters' button is pressed.
756 def color_picker_closing(self, picker: ColorPicker) -> None: 757 """Called when a color picker is closing.""" 758 if not self._root_widget: 759 return 760 tag = picker.get_tag() 761 if tag == 'color': 762 bui.containerwidget( 763 edit=self._root_widget, selected_child=self._color_button 764 ) 765 elif tag == 'highlight': 766 bui.containerwidget( 767 edit=self._root_widget, selected_child=self._highlight_button 768 ) 769 else: 770 print('color_picker_closing got unknown tag ' + str(tag))
Called when a color picker is closing.
772 def color_picker_selected_color( 773 self, picker: ColorPicker, color: tuple[float, float, float] 774 ) -> None: 775 """Called when a color is selected in a color picker.""" 776 if not self._root_widget: 777 return 778 tag = picker.get_tag() 779 if tag == 'color': 780 self._set_color(color) 781 elif tag == 'highlight': 782 self._set_highlight(color) 783 else: 784 print('color_picker_selected_color got unknown tag ' + str(tag)) 785 self._update_character()
Called when a color is selected in a color picker.
828 def getname(self) -> str: 829 """Return the current profile name value.""" 830 if self._is_account_profile: 831 new_name = '__account__' 832 elif self._global: 833 new_name = self._name 834 else: 835 new_name = cast(str, bui.textwidget(query=self._text_field)) 836 return new_name
Return the current profile name value.
838 def save(self, transition_out: bool = True) -> bool: 839 """Save has been selected.""" 840 841 # no-op if our underlying widget is dead or on its way out. 842 if not self._root_widget or self._root_widget.transitioning_out: 843 return False 844 845 plus = bui.app.plus 846 assert plus is not None 847 848 new_name = self.getname().strip() 849 850 if not new_name: 851 bui.screenmessage(bui.Lstr(resource='nameNotEmptyText')) 852 bui.getsound('error').play() 853 return False 854 855 # Make sure we're not renaming to another existing profile. 856 profiles: dict = bui.app.config.get('Player Profiles', {}) 857 if self._existing_profile != new_name and new_name in profiles.keys(): 858 bui.screenmessage( 859 bui.Lstr(resource='editProfileWindow.profileAlreadyExistsText') 860 ) 861 bui.getsound('error').play() 862 return False 863 864 if transition_out: 865 bui.getsound('gunCocking').play() 866 867 # Delete old in case we're renaming. 868 if self._existing_profile and self._existing_profile != new_name: 869 plus.add_v1_account_transaction( 870 { 871 'type': 'REMOVE_PLAYER_PROFILE', 872 'name': self._existing_profile, 873 } 874 ) 875 876 # Also lets be aware we're no longer global if we're taking 877 # a new name (will need to re-request it). 878 self._global = False 879 880 plus.add_v1_account_transaction( 881 { 882 'type': 'ADD_PLAYER_PROFILE', 883 'name': new_name, 884 'profile': { 885 'character': self._spazzes[self._icon_index], 886 'color': list(self._color), 887 'global': self._global, 888 'icon': self._icon, 889 'highlight': list(self._highlight), 890 }, 891 } 892 ) 893 894 if transition_out: 895 plus.run_v1_account_transactions() 896 self.main_window_back() 897 898 return True
Save has been selected.