bastd.ui.iconpicker

Provides a picker for icons.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Provides a picker for icons."""
  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 IconPicker(popup.PopupWindow):
 19    """Picker for icons."""
 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_icon: str | None = None,
 31    ):
 32        # pylint: disable=too-many-locals
 33        del parent  # unused here
 34        del tint_color  # unused_here
 35        del tint2_color  # 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        self._icons = [
 50            ba.charstr(ba.SpecialChar.LOGO)
 51        ] + ba.app.accounts_v1.get_purchased_icons()
 52        count = len(self._icons)
 53        columns = 4
 54        rows = int(math.ceil(float(count) / columns))
 55
 56        button_width = 50
 57        button_height = 50
 58        button_buffer_h = 10
 59        button_buffer_v = 5
 60
 61        self._width = 10 + columns * (button_width + 2 * button_buffer_h) * (
 62            1.0 / 0.95
 63        ) * (1.0 / 0.8)
 64        self._height = self._width * (
 65            0.8 if uiscale is ba.UIScale.SMALL else 1.06
 66        )
 67
 68        self._scroll_width = self._width * 0.8
 69        self._scroll_height = self._height * 0.8
 70        self._scroll_position = (
 71            (self._width - self._scroll_width) * 0.5,
 72            (self._height - self._scroll_height) * 0.5,
 73        )
 74
 75        # creates our _root_widget
 76        popup.PopupWindow.__init__(
 77            self,
 78            position=position,
 79            size=(self._width, self._height),
 80            scale=scale,
 81            bg_color=(0.5, 0.5, 0.5),
 82            offset=offset,
 83            focus_position=self._scroll_position,
 84            focus_size=(self._scroll_width, self._scroll_height),
 85        )
 86
 87        self._scrollwidget = ba.scrollwidget(
 88            parent=self.root_widget,
 89            size=(self._scroll_width, self._scroll_height),
 90            color=(0.55, 0.55, 0.55),
 91            highlight=False,
 92            position=self._scroll_position,
 93        )
 94        ba.containerwidget(edit=self._scrollwidget, claims_left_right=True)
 95
 96        self._sub_width = self._scroll_width * 0.95
 97        self._sub_height = (
 98            5 + rows * (button_height + 2 * button_buffer_v) + 100
 99        )
100        self._subcontainer = ba.containerwidget(
101            parent=self._scrollwidget,
102            size=(self._sub_width, self._sub_height),
103            background=False,
104        )
105        index = 0
106        for y in range(rows):
107            for x in range(columns):
108                pos = (
109                    x * (button_width + 2 * button_buffer_h) + button_buffer_h,
110                    self._sub_height
111                    - (y + 1) * (button_height + 2 * button_buffer_v)
112                    + 0,
113                )
114                btn = ba.buttonwidget(
115                    parent=self._subcontainer,
116                    button_type='square',
117                    size=(button_width, button_height),
118                    autoselect=True,
119                    text_scale=1.2,
120                    label='',
121                    color=(0.65, 0.65, 0.65),
122                    on_activate_call=ba.Call(
123                        self._select_icon, self._icons[index]
124                    ),
125                    position=pos,
126                )
127                ba.textwidget(
128                    parent=self._subcontainer,
129                    h_align='center',
130                    v_align='center',
131                    size=(0, 0),
132                    position=(pos[0] + 0.5 * button_width - 1, pos[1] + 15),
133                    draw_controller=btn,
134                    text=self._icons[index],
135                    scale=1.8,
136                )
137                ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60)
138                if self._icons[index] == selected_icon:
139                    ba.containerwidget(
140                        edit=self._subcontainer,
141                        selected_child=btn,
142                        visible_child=btn,
143                    )
144                index += 1
145
146                if index >= count:
147                    break
148            if index >= count:
149                break
150        self._get_more_icons_button = btn = ba.buttonwidget(
151            parent=self._subcontainer,
152            size=(self._sub_width * 0.8, 60),
153            position=(self._sub_width * 0.1, 30),
154            label=ba.Lstr(resource='editProfileWindow.getMoreIconsText'),
155            on_activate_call=self._on_store_press,
156            color=(0.6, 0.6, 0.6),
157            textcolor=(0.8, 0.8, 0.8),
158            autoselect=True,
159        )
160        ba.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30)
161
162    def _on_store_press(self) -> None:
163        from bastd.ui.account import show_sign_in_prompt
164        from bastd.ui.store.browser import StoreBrowserWindow
165
166        if ba.internal.get_v1_account_state() != 'signed_in':
167            show_sign_in_prompt()
168            return
169        self._transition_out()
170        StoreBrowserWindow(
171            modal=True,
172            show_tab=StoreBrowserWindow.TabID.ICONS,
173            origin_widget=self._get_more_icons_button,
174        )
175
176    def _select_icon(self, icon: str) -> None:
177        if self._delegate is not None:
178            self._delegate.on_icon_picker_pick(icon)
179        self._transition_out()
180
181    def _transition_out(self) -> None:
182        if not self._transitioning_out:
183            self._transitioning_out = True
184            ba.containerwidget(edit=self.root_widget, transition='out_scale')
185
186    def on_popup_cancel(self) -> None:
187        ba.playsound(ba.getsound('swish'))
188        self._transition_out()
class IconPicker(bastd.ui.popup.PopupWindow):
 19class IconPicker(popup.PopupWindow):
 20    """Picker for icons."""
 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_icon: str | None = None,
 32    ):
 33        # pylint: disable=too-many-locals
 34        del parent  # unused here
 35        del tint_color  # unused_here
 36        del tint2_color  # 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        self._icons = [
 51            ba.charstr(ba.SpecialChar.LOGO)
 52        ] + ba.app.accounts_v1.get_purchased_icons()
 53        count = len(self._icons)
 54        columns = 4
 55        rows = int(math.ceil(float(count) / columns))
 56
 57        button_width = 50
 58        button_height = 50
 59        button_buffer_h = 10
 60        button_buffer_v = 5
 61
 62        self._width = 10 + columns * (button_width + 2 * button_buffer_h) * (
 63            1.0 / 0.95
 64        ) * (1.0 / 0.8)
 65        self._height = self._width * (
 66            0.8 if uiscale is ba.UIScale.SMALL else 1.06
 67        )
 68
 69        self._scroll_width = self._width * 0.8
 70        self._scroll_height = self._height * 0.8
 71        self._scroll_position = (
 72            (self._width - self._scroll_width) * 0.5,
 73            (self._height - self._scroll_height) * 0.5,
 74        )
 75
 76        # creates our _root_widget
 77        popup.PopupWindow.__init__(
 78            self,
 79            position=position,
 80            size=(self._width, self._height),
 81            scale=scale,
 82            bg_color=(0.5, 0.5, 0.5),
 83            offset=offset,
 84            focus_position=self._scroll_position,
 85            focus_size=(self._scroll_width, self._scroll_height),
 86        )
 87
 88        self._scrollwidget = ba.scrollwidget(
 89            parent=self.root_widget,
 90            size=(self._scroll_width, self._scroll_height),
 91            color=(0.55, 0.55, 0.55),
 92            highlight=False,
 93            position=self._scroll_position,
 94        )
 95        ba.containerwidget(edit=self._scrollwidget, claims_left_right=True)
 96
 97        self._sub_width = self._scroll_width * 0.95
 98        self._sub_height = (
 99            5 + rows * (button_height + 2 * button_buffer_v) + 100
100        )
101        self._subcontainer = ba.containerwidget(
102            parent=self._scrollwidget,
103            size=(self._sub_width, self._sub_height),
104            background=False,
105        )
106        index = 0
107        for y in range(rows):
108            for x in range(columns):
109                pos = (
110                    x * (button_width + 2 * button_buffer_h) + button_buffer_h,
111                    self._sub_height
112                    - (y + 1) * (button_height + 2 * button_buffer_v)
113                    + 0,
114                )
115                btn = ba.buttonwidget(
116                    parent=self._subcontainer,
117                    button_type='square',
118                    size=(button_width, button_height),
119                    autoselect=True,
120                    text_scale=1.2,
121                    label='',
122                    color=(0.65, 0.65, 0.65),
123                    on_activate_call=ba.Call(
124                        self._select_icon, self._icons[index]
125                    ),
126                    position=pos,
127                )
128                ba.textwidget(
129                    parent=self._subcontainer,
130                    h_align='center',
131                    v_align='center',
132                    size=(0, 0),
133                    position=(pos[0] + 0.5 * button_width - 1, pos[1] + 15),
134                    draw_controller=btn,
135                    text=self._icons[index],
136                    scale=1.8,
137                )
138                ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60)
139                if self._icons[index] == selected_icon:
140                    ba.containerwidget(
141                        edit=self._subcontainer,
142                        selected_child=btn,
143                        visible_child=btn,
144                    )
145                index += 1
146
147                if index >= count:
148                    break
149            if index >= count:
150                break
151        self._get_more_icons_button = btn = ba.buttonwidget(
152            parent=self._subcontainer,
153            size=(self._sub_width * 0.8, 60),
154            position=(self._sub_width * 0.1, 30),
155            label=ba.Lstr(resource='editProfileWindow.getMoreIconsText'),
156            on_activate_call=self._on_store_press,
157            color=(0.6, 0.6, 0.6),
158            textcolor=(0.8, 0.8, 0.8),
159            autoselect=True,
160        )
161        ba.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30)
162
163    def _on_store_press(self) -> None:
164        from bastd.ui.account import show_sign_in_prompt
165        from bastd.ui.store.browser import StoreBrowserWindow
166
167        if ba.internal.get_v1_account_state() != 'signed_in':
168            show_sign_in_prompt()
169            return
170        self._transition_out()
171        StoreBrowserWindow(
172            modal=True,
173            show_tab=StoreBrowserWindow.TabID.ICONS,
174            origin_widget=self._get_more_icons_button,
175        )
176
177    def _select_icon(self, icon: str) -> None:
178        if self._delegate is not None:
179            self._delegate.on_icon_picker_pick(icon)
180        self._transition_out()
181
182    def _transition_out(self) -> None:
183        if not self._transitioning_out:
184            self._transitioning_out = True
185            ba.containerwidget(edit=self.root_widget, transition='out_scale')
186
187    def on_popup_cancel(self) -> None:
188        ba.playsound(ba.getsound('swish'))
189        self._transition_out()

Picker for icons.

IconPicker( 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_icon: 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_icon: str | None = None,
 32    ):
 33        # pylint: disable=too-many-locals
 34        del parent  # unused here
 35        del tint_color  # unused_here
 36        del tint2_color  # 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        self._icons = [
 51            ba.charstr(ba.SpecialChar.LOGO)
 52        ] + ba.app.accounts_v1.get_purchased_icons()
 53        count = len(self._icons)
 54        columns = 4
 55        rows = int(math.ceil(float(count) / columns))
 56
 57        button_width = 50
 58        button_height = 50
 59        button_buffer_h = 10
 60        button_buffer_v = 5
 61
 62        self._width = 10 + columns * (button_width + 2 * button_buffer_h) * (
 63            1.0 / 0.95
 64        ) * (1.0 / 0.8)
 65        self._height = self._width * (
 66            0.8 if uiscale is ba.UIScale.SMALL else 1.06
 67        )
 68
 69        self._scroll_width = self._width * 0.8
 70        self._scroll_height = self._height * 0.8
 71        self._scroll_position = (
 72            (self._width - self._scroll_width) * 0.5,
 73            (self._height - self._scroll_height) * 0.5,
 74        )
 75
 76        # creates our _root_widget
 77        popup.PopupWindow.__init__(
 78            self,
 79            position=position,
 80            size=(self._width, self._height),
 81            scale=scale,
 82            bg_color=(0.5, 0.5, 0.5),
 83            offset=offset,
 84            focus_position=self._scroll_position,
 85            focus_size=(self._scroll_width, self._scroll_height),
 86        )
 87
 88        self._scrollwidget = ba.scrollwidget(
 89            parent=self.root_widget,
 90            size=(self._scroll_width, self._scroll_height),
 91            color=(0.55, 0.55, 0.55),
 92            highlight=False,
 93            position=self._scroll_position,
 94        )
 95        ba.containerwidget(edit=self._scrollwidget, claims_left_right=True)
 96
 97        self._sub_width = self._scroll_width * 0.95
 98        self._sub_height = (
 99            5 + rows * (button_height + 2 * button_buffer_v) + 100
100        )
101        self._subcontainer = ba.containerwidget(
102            parent=self._scrollwidget,
103            size=(self._sub_width, self._sub_height),
104            background=False,
105        )
106        index = 0
107        for y in range(rows):
108            for x in range(columns):
109                pos = (
110                    x * (button_width + 2 * button_buffer_h) + button_buffer_h,
111                    self._sub_height
112                    - (y + 1) * (button_height + 2 * button_buffer_v)
113                    + 0,
114                )
115                btn = ba.buttonwidget(
116                    parent=self._subcontainer,
117                    button_type='square',
118                    size=(button_width, button_height),
119                    autoselect=True,
120                    text_scale=1.2,
121                    label='',
122                    color=(0.65, 0.65, 0.65),
123                    on_activate_call=ba.Call(
124                        self._select_icon, self._icons[index]
125                    ),
126                    position=pos,
127                )
128                ba.textwidget(
129                    parent=self._subcontainer,
130                    h_align='center',
131                    v_align='center',
132                    size=(0, 0),
133                    position=(pos[0] + 0.5 * button_width - 1, pos[1] + 15),
134                    draw_controller=btn,
135                    text=self._icons[index],
136                    scale=1.8,
137                )
138                ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60)
139                if self._icons[index] == selected_icon:
140                    ba.containerwidget(
141                        edit=self._subcontainer,
142                        selected_child=btn,
143                        visible_child=btn,
144                    )
145                index += 1
146
147                if index >= count:
148                    break
149            if index >= count:
150                break
151        self._get_more_icons_button = btn = ba.buttonwidget(
152            parent=self._subcontainer,
153            size=(self._sub_width * 0.8, 60),
154            position=(self._sub_width * 0.1, 30),
155            label=ba.Lstr(resource='editProfileWindow.getMoreIconsText'),
156            on_activate_call=self._on_store_press,
157            color=(0.6, 0.6, 0.6),
158            textcolor=(0.8, 0.8, 0.8),
159            autoselect=True,
160        )
161        ba.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30)
def on_popup_cancel(self) -> None:
187    def on_popup_cancel(self) -> None:
188        ba.playsound(ba.getsound('swish'))
189        self._transition_out()

Called when the popup is canceled.

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