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