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