bastd.ui.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 10import ba 11import ba.internal 12from bastd.ui import popup 13 14if TYPE_CHECKING: 15 from typing import Any, Sequence 16 17 18class CharacterPicker(popup.PopupWindow): 19 """Popup window for selecting characters.""" 20 21 def __init__( 22 self, 23 parent: ba.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 bastd.actor import spazappearance 34 35 del parent # unused here 36 uiscale = ba.app.ui.uiscale 37 if scale is None: 38 scale = ( 39 1.85 40 if uiscale is ba.UIScale.SMALL 41 else 1.65 42 if uiscale is ba.UIScale.MEDIUM 43 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 ba.gettexture(ba.app.spaz_appearances[s].icon_texture) 54 for s in self._spazzes 55 ] 56 self._icon_tint_textures = [ 57 ba.gettexture(ba.app.spaz_appearances[s].icon_mask_texture) 58 for s in self._spazzes 59 ] 60 61 count = len(self._spazzes) 62 63 columns = 3 64 rows = int(math.ceil(float(count) / columns)) 65 66 button_width = 100 67 button_height = 100 68 button_buffer_h = 10 69 button_buffer_v = 15 70 71 self._width = 10 + columns * (button_width + 2 * button_buffer_h) * ( 72 1.0 / 0.95 73 ) * (1.0 / 0.8) 74 self._height = self._width * ( 75 0.8 if uiscale is ba.UIScale.SMALL else 1.06 76 ) 77 78 self._scroll_width = self._width * 0.8 79 self._scroll_height = self._height * 0.8 80 self._scroll_position = ( 81 (self._width - self._scroll_width) * 0.5, 82 (self._height - self._scroll_height) * 0.5, 83 ) 84 85 # creates our _root_widget 86 popup.PopupWindow.__init__( 87 self, 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 = ba.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 ba.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 = ba.containerwidget( 111 parent=self._scrollwidget, 112 size=(self._sub_width, self._sub_height), 113 background=False, 114 ) 115 index = 0 116 mask_texture = ba.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 = ba.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=ba.Call( 138 self._select_character, self._spazzes[index] 139 ), 140 position=pos, 141 ) 142 ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) 143 if self._spazzes[index] == selected_character: 144 ba.containerwidget( 145 edit=self._subcontainer, 146 selected_child=btn, 147 visible_child=btn, 148 ) 149 name = ba.Lstr( 150 translate=('characterNames', self._spazzes[index]) 151 ) 152 ba.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 = ba.buttonwidget( 171 parent=self._subcontainer, 172 size=(self._sub_width * 0.8, 60), 173 position=(self._sub_width * 0.1, 30), 174 label=ba.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 ba.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30) 181 182 def _on_store_press(self) -> None: 183 from bastd.ui.account import show_sign_in_prompt 184 from bastd.ui.store.browser import StoreBrowserWindow 185 186 if ba.internal.get_v1_account_state() != 'signed_in': 187 show_sign_in_prompt() 188 return 189 self._transition_out() 190 StoreBrowserWindow( 191 modal=True, 192 show_tab=StoreBrowserWindow.TabID.CHARACTERS, 193 origin_widget=self._get_more_characters_button, 194 ) 195 196 def _select_character(self, character: str) -> None: 197 if self._delegate is not None: 198 self._delegate.on_character_picker_pick(character) 199 self._transition_out() 200 201 def _transition_out(self) -> None: 202 if not self._transitioning_out: 203 self._transitioning_out = True 204 ba.containerwidget(edit=self.root_widget, transition='out_scale') 205 206 def on_popup_cancel(self) -> None: 207 ba.playsound(ba.getsound('swish')) 208 self._transition_out()
19class CharacterPicker(popup.PopupWindow): 20 """Popup window for selecting characters.""" 21 22 def __init__( 23 self, 24 parent: ba.Widget, 25 position: tuple[float, float] = (0.0, 0.0), 26 delegate: Any = None, 27 scale: float | None = None, 28 offset: tuple[float, float] = (0.0, 0.0), 29 tint_color: Sequence[float] = (1.0, 1.0, 1.0), 30 tint2_color: Sequence[float] = (1.0, 1.0, 1.0), 31 selected_character: str | None = None, 32 ): 33 # pylint: disable=too-many-locals 34 from bastd.actor import spazappearance 35 36 del parent # unused here 37 uiscale = ba.app.ui.uiscale 38 if scale is None: 39 scale = ( 40 1.85 41 if uiscale is ba.UIScale.SMALL 42 else 1.65 43 if uiscale is ba.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 ba.gettexture(ba.app.spaz_appearances[s].icon_texture) 55 for s in self._spazzes 56 ] 57 self._icon_tint_textures = [ 58 ba.gettexture(ba.app.spaz_appearances[s].icon_mask_texture) 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 ba.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 popup.PopupWindow.__init__( 88 self, 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 = ba.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 ba.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 = ba.containerwidget( 112 parent=self._scrollwidget, 113 size=(self._sub_width, self._sub_height), 114 background=False, 115 ) 116 index = 0 117 mask_texture = ba.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 = ba.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=ba.Call( 139 self._select_character, self._spazzes[index] 140 ), 141 position=pos, 142 ) 143 ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) 144 if self._spazzes[index] == selected_character: 145 ba.containerwidget( 146 edit=self._subcontainer, 147 selected_child=btn, 148 visible_child=btn, 149 ) 150 name = ba.Lstr( 151 translate=('characterNames', self._spazzes[index]) 152 ) 153 ba.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 = ba.buttonwidget( 172 parent=self._subcontainer, 173 size=(self._sub_width * 0.8, 60), 174 position=(self._sub_width * 0.1, 30), 175 label=ba.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 ba.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30) 182 183 def _on_store_press(self) -> None: 184 from bastd.ui.account import show_sign_in_prompt 185 from bastd.ui.store.browser import StoreBrowserWindow 186 187 if ba.internal.get_v1_account_state() != 'signed_in': 188 show_sign_in_prompt() 189 return 190 self._transition_out() 191 StoreBrowserWindow( 192 modal=True, 193 show_tab=StoreBrowserWindow.TabID.CHARACTERS, 194 origin_widget=self._get_more_characters_button, 195 ) 196 197 def _select_character(self, character: str) -> None: 198 if self._delegate is not None: 199 self._delegate.on_character_picker_pick(character) 200 self._transition_out() 201 202 def _transition_out(self) -> None: 203 if not self._transitioning_out: 204 self._transitioning_out = True 205 ba.containerwidget(edit=self.root_widget, transition='out_scale') 206 207 def on_popup_cancel(self) -> None: 208 ba.playsound(ba.getsound('swish')) 209 self._transition_out()
Popup window for selecting characters.
CharacterPicker( parent: _ba.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)
22 def __init__( 23 self, 24 parent: ba.Widget, 25 position: tuple[float, float] = (0.0, 0.0), 26 delegate: Any = None, 27 scale: float | None = None, 28 offset: tuple[float, float] = (0.0, 0.0), 29 tint_color: Sequence[float] = (1.0, 1.0, 1.0), 30 tint2_color: Sequence[float] = (1.0, 1.0, 1.0), 31 selected_character: str | None = None, 32 ): 33 # pylint: disable=too-many-locals 34 from bastd.actor import spazappearance 35 36 del parent # unused here 37 uiscale = ba.app.ui.uiscale 38 if scale is None: 39 scale = ( 40 1.85 41 if uiscale is ba.UIScale.SMALL 42 else 1.65 43 if uiscale is ba.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 ba.gettexture(ba.app.spaz_appearances[s].icon_texture) 55 for s in self._spazzes 56 ] 57 self._icon_tint_textures = [ 58 ba.gettexture(ba.app.spaz_appearances[s].icon_mask_texture) 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 ba.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 popup.PopupWindow.__init__( 88 self, 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 = ba.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 ba.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 = ba.containerwidget( 112 parent=self._scrollwidget, 113 size=(self._sub_width, self._sub_height), 114 background=False, 115 ) 116 index = 0 117 mask_texture = ba.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 = ba.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=ba.Call( 139 self._select_character, self._spazzes[index] 140 ), 141 position=pos, 142 ) 143 ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) 144 if self._spazzes[index] == selected_character: 145 ba.containerwidget( 146 edit=self._subcontainer, 147 selected_child=btn, 148 visible_child=btn, 149 ) 150 name = ba.Lstr( 151 translate=('characterNames', self._spazzes[index]) 152 ) 153 ba.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 = ba.buttonwidget( 172 parent=self._subcontainer, 173 size=(self._sub_width * 0.8, 60), 174 position=(self._sub_width * 0.1, 30), 175 label=ba.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 ba.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30)