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()
class CharacterPicker(bauiv1lib.popup.PopupWindow):
 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:
212    def on_popup_cancel(self) -> None:
213        bui.getsound('swish').play()
214        self._transition_out()

Called when the popup is canceled.

Cancels can occur due to clicking outside the window, hitting escape, etc.