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