bauiv1lib.characterpicker
Provides a picker for characters.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides a picker for characters.""" 4 5from __future__ import annotations 6 7import math 8from typing import TYPE_CHECKING, override 9 10from bauiv1lib.popup import PopupWindow 11import bauiv1 as bui 12 13if TYPE_CHECKING: 14 from typing import Any, Sequence 15 16 17class CharacterPicker(PopupWindow): 18 """Popup window for selecting characters.""" 19 20 def __init__( 21 self, 22 parent: bui.Widget, 23 position: tuple[float, float] = (0.0, 0.0), 24 delegate: Any = None, 25 scale: float | None = None, 26 offset: tuple[float, float] = (0.0, 0.0), 27 tint_color: Sequence[float] = (1.0, 1.0, 1.0), 28 tint2_color: Sequence[float] = (1.0, 1.0, 1.0), 29 selected_character: str | None = None, 30 ): 31 # pylint: disable=too-many-locals 32 from bascenev1lib.actor import spazappearance 33 34 assert bui.app.classic is not None 35 36 del parent # unused here 37 uiscale = bui.app.ui_v1.uiscale 38 if scale is None: 39 scale = ( 40 1.85 41 if uiscale is bui.UIScale.SMALL 42 else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23 43 ) 44 45 self._delegate = delegate 46 self._transitioning_out = False 47 48 # make a list of spaz icons 49 self._spazzes = spazappearance.get_appearances() 50 self._spazzes.sort() 51 self._icon_textures = [ 52 bui.gettexture(bui.app.classic.spaz_appearances[s].icon_texture) 53 for s in self._spazzes 54 ] 55 self._icon_tint_textures = [ 56 bui.gettexture( 57 bui.app.classic.spaz_appearances[s].icon_mask_texture 58 ) 59 for s in self._spazzes 60 ] 61 62 count = len(self._spazzes) 63 64 columns = 3 65 rows = int(math.ceil(float(count) / columns)) 66 67 button_width = 100 68 button_height = 100 69 button_buffer_h = 10 70 button_buffer_v = 15 71 72 self._width = 10 + columns * (button_width + 2 * button_buffer_h) * ( 73 1.0 / 0.95 74 ) * (1.0 / 0.8) 75 self._height = self._width * ( 76 0.8 if uiscale is bui.UIScale.SMALL else 1.06 77 ) 78 79 self._scroll_width = self._width * 0.8 80 self._scroll_height = self._height * 0.8 81 self._scroll_position = ( 82 (self._width - self._scroll_width) * 0.5, 83 (self._height - self._scroll_height) * 0.5, 84 ) 85 86 # Creates our _root_widget. 87 super().__init__( 88 position=position, 89 size=(self._width, self._height), 90 scale=scale, 91 bg_color=(0.5, 0.5, 0.5), 92 offset=offset, 93 focus_position=self._scroll_position, 94 focus_size=(self._scroll_width, self._scroll_height), 95 ) 96 97 self._scrollwidget = bui.scrollwidget( 98 parent=self.root_widget, 99 size=(self._scroll_width, self._scroll_height), 100 color=(0.55, 0.55, 0.55), 101 highlight=False, 102 position=self._scroll_position, 103 ) 104 bui.containerwidget(edit=self._scrollwidget, claims_left_right=True) 105 106 self._sub_width = self._scroll_width * 0.95 107 self._sub_height = ( 108 5 + rows * (button_height + 2 * button_buffer_v) + 100 109 ) 110 self._subcontainer = bui.containerwidget( 111 parent=self._scrollwidget, 112 size=(self._sub_width, self._sub_height), 113 background=False, 114 ) 115 index = 0 116 mask_texture = bui.gettexture('characterIconMask') 117 for y in range(rows): 118 for x in range(columns): 119 pos = ( 120 x * (button_width + 2 * button_buffer_h) + button_buffer_h, 121 self._sub_height 122 - (y + 1) * (button_height + 2 * button_buffer_v) 123 + 12, 124 ) 125 btn = bui.buttonwidget( 126 parent=self._subcontainer, 127 button_type='square', 128 size=(button_width, button_height), 129 autoselect=True, 130 texture=self._icon_textures[index], 131 tint_texture=self._icon_tint_textures[index], 132 mask_texture=mask_texture, 133 label='', 134 color=(1, 1, 1), 135 tint_color=tint_color, 136 tint2_color=tint2_color, 137 on_activate_call=bui.Call( 138 self._select_character, self._spazzes[index] 139 ), 140 position=pos, 141 ) 142 bui.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) 143 if self._spazzes[index] == selected_character: 144 bui.containerwidget( 145 edit=self._subcontainer, 146 selected_child=btn, 147 visible_child=btn, 148 ) 149 name = bui.Lstr( 150 translate=('characterNames', self._spazzes[index]) 151 ) 152 bui.textwidget( 153 parent=self._subcontainer, 154 text=name, 155 position=(pos[0] + button_width * 0.5, pos[1] - 12), 156 size=(0, 0), 157 scale=0.5, 158 maxwidth=button_width, 159 draw_controller=btn, 160 h_align='center', 161 v_align='center', 162 color=(0.8, 0.8, 0.8, 0.8), 163 ) 164 index += 1 165 166 if index >= count: 167 break 168 if index >= count: 169 break 170 self._get_more_characters_button = btn = bui.buttonwidget( 171 parent=self._subcontainer, 172 size=(self._sub_width * 0.8, 60), 173 position=(self._sub_width * 0.1, 30), 174 label=bui.Lstr(resource='editProfileWindow.getMoreCharactersText'), 175 on_activate_call=self._on_store_press, 176 color=(0.6, 0.6, 0.6), 177 textcolor=(0.8, 0.8, 0.8), 178 autoselect=True, 179 ) 180 bui.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30) 181 182 def _on_store_press(self) -> None: 183 from bauiv1lib.account import show_sign_in_prompt 184 from bauiv1lib.store.browser import StoreBrowserWindow 185 186 plus = bui.app.plus 187 assert plus is not None 188 189 if plus.get_v1_account_state() != 'signed_in': 190 show_sign_in_prompt() 191 return 192 self._transition_out() 193 StoreBrowserWindow( 194 modal=True, 195 show_tab=StoreBrowserWindow.TabID.CHARACTERS, 196 origin_widget=self._get_more_characters_button, 197 ) 198 199 def _select_character(self, character: str) -> None: 200 if self._delegate is not None: 201 self._delegate.on_character_picker_pick(character) 202 self._transition_out() 203 204 def _transition_out(self) -> None: 205 if not self._transitioning_out: 206 self._transitioning_out = True 207 bui.containerwidget(edit=self.root_widget, transition='out_scale') 208 209 @override 210 def on_popup_cancel(self) -> None: 211 bui.getsound('swish').play() 212 self._transition_out()
18class CharacterPicker(PopupWindow): 19 """Popup window for selecting characters.""" 20 21 def __init__( 22 self, 23 parent: bui.Widget, 24 position: tuple[float, float] = (0.0, 0.0), 25 delegate: Any = None, 26 scale: float | None = None, 27 offset: tuple[float, float] = (0.0, 0.0), 28 tint_color: Sequence[float] = (1.0, 1.0, 1.0), 29 tint2_color: Sequence[float] = (1.0, 1.0, 1.0), 30 selected_character: str | None = None, 31 ): 32 # pylint: disable=too-many-locals 33 from bascenev1lib.actor import spazappearance 34 35 assert bui.app.classic is not None 36 37 del parent # unused here 38 uiscale = bui.app.ui_v1.uiscale 39 if scale is None: 40 scale = ( 41 1.85 42 if uiscale is bui.UIScale.SMALL 43 else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23 44 ) 45 46 self._delegate = delegate 47 self._transitioning_out = False 48 49 # make a list of spaz icons 50 self._spazzes = spazappearance.get_appearances() 51 self._spazzes.sort() 52 self._icon_textures = [ 53 bui.gettexture(bui.app.classic.spaz_appearances[s].icon_texture) 54 for s in self._spazzes 55 ] 56 self._icon_tint_textures = [ 57 bui.gettexture( 58 bui.app.classic.spaz_appearances[s].icon_mask_texture 59 ) 60 for s in self._spazzes 61 ] 62 63 count = len(self._spazzes) 64 65 columns = 3 66 rows = int(math.ceil(float(count) / columns)) 67 68 button_width = 100 69 button_height = 100 70 button_buffer_h = 10 71 button_buffer_v = 15 72 73 self._width = 10 + columns * (button_width + 2 * button_buffer_h) * ( 74 1.0 / 0.95 75 ) * (1.0 / 0.8) 76 self._height = self._width * ( 77 0.8 if uiscale is bui.UIScale.SMALL else 1.06 78 ) 79 80 self._scroll_width = self._width * 0.8 81 self._scroll_height = self._height * 0.8 82 self._scroll_position = ( 83 (self._width - self._scroll_width) * 0.5, 84 (self._height - self._scroll_height) * 0.5, 85 ) 86 87 # Creates our _root_widget. 88 super().__init__( 89 position=position, 90 size=(self._width, self._height), 91 scale=scale, 92 bg_color=(0.5, 0.5, 0.5), 93 offset=offset, 94 focus_position=self._scroll_position, 95 focus_size=(self._scroll_width, self._scroll_height), 96 ) 97 98 self._scrollwidget = bui.scrollwidget( 99 parent=self.root_widget, 100 size=(self._scroll_width, self._scroll_height), 101 color=(0.55, 0.55, 0.55), 102 highlight=False, 103 position=self._scroll_position, 104 ) 105 bui.containerwidget(edit=self._scrollwidget, claims_left_right=True) 106 107 self._sub_width = self._scroll_width * 0.95 108 self._sub_height = ( 109 5 + rows * (button_height + 2 * button_buffer_v) + 100 110 ) 111 self._subcontainer = bui.containerwidget( 112 parent=self._scrollwidget, 113 size=(self._sub_width, self._sub_height), 114 background=False, 115 ) 116 index = 0 117 mask_texture = bui.gettexture('characterIconMask') 118 for y in range(rows): 119 for x in range(columns): 120 pos = ( 121 x * (button_width + 2 * button_buffer_h) + button_buffer_h, 122 self._sub_height 123 - (y + 1) * (button_height + 2 * button_buffer_v) 124 + 12, 125 ) 126 btn = bui.buttonwidget( 127 parent=self._subcontainer, 128 button_type='square', 129 size=(button_width, button_height), 130 autoselect=True, 131 texture=self._icon_textures[index], 132 tint_texture=self._icon_tint_textures[index], 133 mask_texture=mask_texture, 134 label='', 135 color=(1, 1, 1), 136 tint_color=tint_color, 137 tint2_color=tint2_color, 138 on_activate_call=bui.Call( 139 self._select_character, self._spazzes[index] 140 ), 141 position=pos, 142 ) 143 bui.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) 144 if self._spazzes[index] == selected_character: 145 bui.containerwidget( 146 edit=self._subcontainer, 147 selected_child=btn, 148 visible_child=btn, 149 ) 150 name = bui.Lstr( 151 translate=('characterNames', self._spazzes[index]) 152 ) 153 bui.textwidget( 154 parent=self._subcontainer, 155 text=name, 156 position=(pos[0] + button_width * 0.5, pos[1] - 12), 157 size=(0, 0), 158 scale=0.5, 159 maxwidth=button_width, 160 draw_controller=btn, 161 h_align='center', 162 v_align='center', 163 color=(0.8, 0.8, 0.8, 0.8), 164 ) 165 index += 1 166 167 if index >= count: 168 break 169 if index >= count: 170 break 171 self._get_more_characters_button = btn = bui.buttonwidget( 172 parent=self._subcontainer, 173 size=(self._sub_width * 0.8, 60), 174 position=(self._sub_width * 0.1, 30), 175 label=bui.Lstr(resource='editProfileWindow.getMoreCharactersText'), 176 on_activate_call=self._on_store_press, 177 color=(0.6, 0.6, 0.6), 178 textcolor=(0.8, 0.8, 0.8), 179 autoselect=True, 180 ) 181 bui.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30) 182 183 def _on_store_press(self) -> None: 184 from bauiv1lib.account import show_sign_in_prompt 185 from bauiv1lib.store.browser import StoreBrowserWindow 186 187 plus = bui.app.plus 188 assert plus is not None 189 190 if plus.get_v1_account_state() != 'signed_in': 191 show_sign_in_prompt() 192 return 193 self._transition_out() 194 StoreBrowserWindow( 195 modal=True, 196 show_tab=StoreBrowserWindow.TabID.CHARACTERS, 197 origin_widget=self._get_more_characters_button, 198 ) 199 200 def _select_character(self, character: str) -> None: 201 if self._delegate is not None: 202 self._delegate.on_character_picker_pick(character) 203 self._transition_out() 204 205 def _transition_out(self) -> None: 206 if not self._transitioning_out: 207 self._transitioning_out = True 208 bui.containerwidget(edit=self.root_widget, transition='out_scale') 209 210 @override 211 def on_popup_cancel(self) -> None: 212 bui.getsound('swish').play() 213 self._transition_out()
Popup window for selecting characters.
CharacterPicker( parent: _bauiv1.Widget, position: tuple[float, float] = (0.0, 0.0), delegate: Any = None, scale: float | None = None, offset: tuple[float, float] = (0.0, 0.0), tint_color: Sequence[float] = (1.0, 1.0, 1.0), tint2_color: Sequence[float] = (1.0, 1.0, 1.0), selected_character: str | None = None)
21 def __init__( 22 self, 23 parent: bui.Widget, 24 position: tuple[float, float] = (0.0, 0.0), 25 delegate: Any = None, 26 scale: float | None = None, 27 offset: tuple[float, float] = (0.0, 0.0), 28 tint_color: Sequence[float] = (1.0, 1.0, 1.0), 29 tint2_color: Sequence[float] = (1.0, 1.0, 1.0), 30 selected_character: str | None = None, 31 ): 32 # pylint: disable=too-many-locals 33 from bascenev1lib.actor import spazappearance 34 35 assert bui.app.classic is not None 36 37 del parent # unused here 38 uiscale = bui.app.ui_v1.uiscale 39 if scale is None: 40 scale = ( 41 1.85 42 if uiscale is bui.UIScale.SMALL 43 else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23 44 ) 45 46 self._delegate = delegate 47 self._transitioning_out = False 48 49 # make a list of spaz icons 50 self._spazzes = spazappearance.get_appearances() 51 self._spazzes.sort() 52 self._icon_textures = [ 53 bui.gettexture(bui.app.classic.spaz_appearances[s].icon_texture) 54 for s in self._spazzes 55 ] 56 self._icon_tint_textures = [ 57 bui.gettexture( 58 bui.app.classic.spaz_appearances[s].icon_mask_texture 59 ) 60 for s in self._spazzes 61 ] 62 63 count = len(self._spazzes) 64 65 columns = 3 66 rows = int(math.ceil(float(count) / columns)) 67 68 button_width = 100 69 button_height = 100 70 button_buffer_h = 10 71 button_buffer_v = 15 72 73 self._width = 10 + columns * (button_width + 2 * button_buffer_h) * ( 74 1.0 / 0.95 75 ) * (1.0 / 0.8) 76 self._height = self._width * ( 77 0.8 if uiscale is bui.UIScale.SMALL else 1.06 78 ) 79 80 self._scroll_width = self._width * 0.8 81 self._scroll_height = self._height * 0.8 82 self._scroll_position = ( 83 (self._width - self._scroll_width) * 0.5, 84 (self._height - self._scroll_height) * 0.5, 85 ) 86 87 # Creates our _root_widget. 88 super().__init__( 89 position=position, 90 size=(self._width, self._height), 91 scale=scale, 92 bg_color=(0.5, 0.5, 0.5), 93 offset=offset, 94 focus_position=self._scroll_position, 95 focus_size=(self._scroll_width, self._scroll_height), 96 ) 97 98 self._scrollwidget = bui.scrollwidget( 99 parent=self.root_widget, 100 size=(self._scroll_width, self._scroll_height), 101 color=(0.55, 0.55, 0.55), 102 highlight=False, 103 position=self._scroll_position, 104 ) 105 bui.containerwidget(edit=self._scrollwidget, claims_left_right=True) 106 107 self._sub_width = self._scroll_width * 0.95 108 self._sub_height = ( 109 5 + rows * (button_height + 2 * button_buffer_v) + 100 110 ) 111 self._subcontainer = bui.containerwidget( 112 parent=self._scrollwidget, 113 size=(self._sub_width, self._sub_height), 114 background=False, 115 ) 116 index = 0 117 mask_texture = bui.gettexture('characterIconMask') 118 for y in range(rows): 119 for x in range(columns): 120 pos = ( 121 x * (button_width + 2 * button_buffer_h) + button_buffer_h, 122 self._sub_height 123 - (y + 1) * (button_height + 2 * button_buffer_v) 124 + 12, 125 ) 126 btn = bui.buttonwidget( 127 parent=self._subcontainer, 128 button_type='square', 129 size=(button_width, button_height), 130 autoselect=True, 131 texture=self._icon_textures[index], 132 tint_texture=self._icon_tint_textures[index], 133 mask_texture=mask_texture, 134 label='', 135 color=(1, 1, 1), 136 tint_color=tint_color, 137 tint2_color=tint2_color, 138 on_activate_call=bui.Call( 139 self._select_character, self._spazzes[index] 140 ), 141 position=pos, 142 ) 143 bui.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) 144 if self._spazzes[index] == selected_character: 145 bui.containerwidget( 146 edit=self._subcontainer, 147 selected_child=btn, 148 visible_child=btn, 149 ) 150 name = bui.Lstr( 151 translate=('characterNames', self._spazzes[index]) 152 ) 153 bui.textwidget( 154 parent=self._subcontainer, 155 text=name, 156 position=(pos[0] + button_width * 0.5, pos[1] - 12), 157 size=(0, 0), 158 scale=0.5, 159 maxwidth=button_width, 160 draw_controller=btn, 161 h_align='center', 162 v_align='center', 163 color=(0.8, 0.8, 0.8, 0.8), 164 ) 165 index += 1 166 167 if index >= count: 168 break 169 if index >= count: 170 break 171 self._get_more_characters_button = btn = bui.buttonwidget( 172 parent=self._subcontainer, 173 size=(self._sub_width * 0.8, 60), 174 position=(self._sub_width * 0.1, 30), 175 label=bui.Lstr(resource='editProfileWindow.getMoreCharactersText'), 176 on_activate_call=self._on_store_press, 177 color=(0.6, 0.6, 0.6), 178 textcolor=(0.8, 0.8, 0.8), 179 autoselect=True, 180 ) 181 bui.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30)
@override
def
on_popup_cancel(self) -> None:
210 @override 211 def on_popup_cancel(self) -> None: 212 bui.getsound('swish').play() 213 self._transition_out()
Called when the popup is canceled.
Cancels can occur due to clicking outside the window, hitting escape, etc.