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

Picker for icons.

IconPicker( 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_icon: 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_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        assert bui.app.classic is not None
 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        assert bui.app.classic is not None
 49        self._icons = [
 50            bui.charstr(bui.SpecialChar.LOGO)
 51        ] + bui.app.classic.accounts.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 bui.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        super().__init__(
 77            position=position,
 78            size=(self._width, self._height),
 79            scale=scale,
 80            bg_color=(0.5, 0.5, 0.5),
 81            offset=offset,
 82            focus_position=self._scroll_position,
 83            focus_size=(self._scroll_width, self._scroll_height),
 84        )
 85
 86        self._scrollwidget = bui.scrollwidget(
 87            parent=self.root_widget,
 88            size=(self._scroll_width, self._scroll_height),
 89            color=(0.55, 0.55, 0.55),
 90            highlight=False,
 91            position=self._scroll_position,
 92        )
 93        bui.containerwidget(edit=self._scrollwidget, claims_left_right=True)
 94
 95        self._sub_width = self._scroll_width * 0.95
 96        self._sub_height = (
 97            5 + rows * (button_height + 2 * button_buffer_v) + 100
 98        )
 99        self._subcontainer = bui.containerwidget(
100            parent=self._scrollwidget,
101            size=(self._sub_width, self._sub_height),
102            background=False,
103        )
104        index = 0
105        for y in range(rows):
106            for x in range(columns):
107                pos = (
108                    x * (button_width + 2 * button_buffer_h) + button_buffer_h,
109                    self._sub_height
110                    - (y + 1) * (button_height + 2 * button_buffer_v)
111                    + 0,
112                )
113                btn = bui.buttonwidget(
114                    parent=self._subcontainer,
115                    button_type='square',
116                    size=(button_width, button_height),
117                    autoselect=True,
118                    text_scale=1.2,
119                    label='',
120                    color=(0.65, 0.65, 0.65),
121                    on_activate_call=bui.Call(
122                        self._select_icon, self._icons[index]
123                    ),
124                    position=pos,
125                )
126                bui.textwidget(
127                    parent=self._subcontainer,
128                    h_align='center',
129                    v_align='center',
130                    size=(0, 0),
131                    position=(pos[0] + 0.5 * button_width - 1, pos[1] + 15),
132                    draw_controller=btn,
133                    text=self._icons[index],
134                    scale=1.8,
135                )
136                bui.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60)
137                if self._icons[index] == selected_icon:
138                    bui.containerwidget(
139                        edit=self._subcontainer,
140                        selected_child=btn,
141                        visible_child=btn,
142                    )
143                index += 1
144
145                if index >= count:
146                    break
147            if index >= count:
148                break
149        self._get_more_icons_button = btn = bui.buttonwidget(
150            parent=self._subcontainer,
151            size=(self._sub_width * 0.8, 60),
152            position=(self._sub_width * 0.1, 30),
153            label=bui.Lstr(resource='editProfileWindow.getMoreIconsText'),
154            on_activate_call=self._on_store_press,
155            color=(0.6, 0.6, 0.6),
156            textcolor=(0.8, 0.8, 0.8),
157            autoselect=True,
158        )
159        bui.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30)
@override
def on_popup_cancel(self) -> None:
188    @override
189    def on_popup_cancel(self) -> None:
190        bui.getsound('swish').play()
191        self._transition_out()

Called when the popup is canceled.

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