bauiv1lib.coop.gamebutton

Defines button for co-op games.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Defines button for co-op games."""
  4
  5from __future__ import annotations
  6
  7import random
  8from typing import TYPE_CHECKING
  9
 10import bauiv1 as bui
 11
 12if TYPE_CHECKING:
 13    from bauiv1lib.coop.browser import CoopBrowserWindow
 14
 15
 16class GameButton:
 17    """Button for entering co-op games."""
 18
 19    def __init__(
 20        self,
 21        window: CoopBrowserWindow,
 22        parent: bui.Widget,
 23        game: str,
 24        x: float,
 25        y: float,
 26        select: bool,
 27        row: str,
 28    ):
 29        # pylint: disable=too-many-positional-arguments
 30        # pylint: disable=too-many-statements
 31        # pylint: disable=too-many-locals
 32
 33        assert bui.app.classic is not None
 34        self._game = game
 35        sclx = 195.0
 36        scly = 195.0
 37
 38        campaignname, levelname = game.split(':')
 39
 40        # Hack: The Last Stand doesn't actually exist in the easy
 41        # tourney. We just want it for display purposes. Map it to
 42        # the hard-mode version.
 43        if game == 'Easy:The Last Stand':
 44            campaignname = 'Default'
 45
 46        rating: float | None
 47        campaign = bui.app.classic.getcampaign(campaignname)
 48        rating = campaign.getlevel(levelname).rating
 49
 50        if game == 'Easy:The Last Stand':
 51            rating = None
 52
 53        if rating is None or rating == 0.0:
 54            stars = 0
 55        elif rating >= 9.5:
 56            stars = 3
 57        elif rating >= 7.5:
 58            stars = 2
 59        else:
 60            stars = 1
 61
 62        self._button = btn = bui.buttonwidget(
 63            parent=parent,
 64            position=(x + 23, y + 4),
 65            size=(sclx, scly),
 66            label='',
 67            on_activate_call=bui.Call(window.run_game, game),
 68            button_type='square',
 69            autoselect=True,
 70            on_select_call=bui.Call(window.sel_change, row, game),
 71        )
 72        bui.widget(
 73            edit=btn,
 74            show_buffer_bottom=50,
 75            show_buffer_top=50,
 76            show_buffer_left=400,
 77            show_buffer_right=200,
 78        )
 79        if select:
 80            bui.containerwidget(
 81                edit=parent, selected_child=btn, visible_child=btn
 82            )
 83        image_width = sclx * 0.85 * 0.75
 84        self._preview_widget = bui.imagewidget(
 85            parent=parent,
 86            draw_controller=btn,
 87            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 104),
 88            size=(image_width, image_width * 0.5),
 89            mesh_transparent=window.lsbt,
 90            mesh_opaque=window.lsbo,
 91            texture=bui.gettexture(
 92                campaign.getlevel(levelname).preview_texture_name
 93            ),
 94            mask_texture=bui.gettexture('mapPreviewMask'),
 95        )
 96
 97        translated = campaign.getlevel(levelname).displayname
 98        self._achievements = bui.app.classic.ach.achievements_for_coop_level(
 99            game
100        )
101
102        self._name_widget = bui.textwidget(
103            parent=parent,
104            draw_controller=btn,
105            position=(x + 20 + sclx * 0.5, y + scly - 27),
106            size=(0, 0),
107            h_align='center',
108            text=translated,
109            v_align='center',
110            maxwidth=sclx * 0.76,
111            scale=0.85,
112        )
113        xscl = x + (67 if self._achievements else 50)
114        yscl = y + scly - (137 if self._achievements else 157)
115
116        starscale = 35.0 if self._achievements else 45.0
117
118        self._star_widgets: list[bui.Widget] = []
119        for _i in range(stars):
120            imw = bui.imagewidget(
121                parent=parent,
122                draw_controller=btn,
123                position=(xscl, yscl),
124                size=(starscale, starscale),
125                texture=window.star_tex,
126            )
127            self._star_widgets.append(imw)
128            xscl += starscale
129        for _i in range(3 - stars):
130            bui.imagewidget(
131                parent=parent,
132                draw_controller=btn,
133                position=(xscl, yscl),
134                size=(starscale, starscale),
135                color=(0, 0, 0),
136                texture=window.star_tex,
137                opacity=0.3,
138            )
139            xscl += starscale
140
141        xach = x + 69
142        yach = y + scly - 168
143        a_scale = 30.0
144        self._achievement_widgets: list[tuple[bui.Widget, bui.Widget]] = []
145        for ach in self._achievements:
146            a_complete = ach.complete
147            imw = bui.imagewidget(
148                parent=parent,
149                draw_controller=btn,
150                position=(xach, yach),
151                size=(a_scale, a_scale),
152                color=(
153                    tuple(ach.get_icon_color(a_complete)[:3])
154                    if a_complete
155                    else (1.2, 1.2, 1.2)
156                ),
157                texture=ach.get_icon_ui_texture(a_complete),
158            )
159            imw2 = bui.imagewidget(
160                parent=parent,
161                draw_controller=btn,
162                position=(xach, yach),
163                size=(a_scale, a_scale),
164                color=(2, 1.4, 0.4),
165                texture=window.a_outline_tex,
166                mesh_transparent=window.a_outline_mesh,
167            )
168            self._achievement_widgets.append((imw, imw2))
169            # if a_complete:
170            xach += a_scale * 1.2
171
172        # if not unlocked:
173        self._lock_widget = bui.imagewidget(
174            parent=parent,
175            draw_controller=btn,
176            position=(x - 8 + sclx * 0.5, y + scly * 0.5 - 20),
177            size=(60, 60),
178            opacity=0.0,
179            texture=bui.gettexture('lock'),
180        )
181
182        # give a quasi-random update increment to spread the load..
183        self._update_timer = bui.AppTimer(
184            0.001 * (900 + random.randrange(200)),
185            bui.WeakCall(self._update),
186            repeat=True,
187        )
188        self._update()
189
190    def get_button(self) -> bui.Widget:
191        """Return the underlying button bui.Widget."""
192        return self._button
193
194    def _update(self) -> None:
195        # pylint: disable=too-many-boolean-expressions
196
197        plus = bui.app.plus
198        assert plus is not None
199
200        classic = bui.app.classic
201        assert classic is not None
202
203        # In case we stick around after our UI...
204        if not self._button:
205            return
206
207        game = self._game
208        campaignname, levelname = game.split(':')
209
210        # Hack - The Last Stand doesn't actually exist in the
211        # easy tourney; we just want it for display purposes. Map it to
212        # the hard-mode version.
213        if game == 'Easy:The Last Stand':
214            campaignname = 'Default'
215
216        campaign = classic.getcampaign(campaignname)
217
218        # If this campaign is sequential, make sure we've unlocked
219        # everything up to here.
220        unlocked = True
221        if campaign.sequential:
222            for level in campaign.levels:
223                if level.name == levelname:
224                    break
225                if not level.complete:
226                    unlocked = False
227                    break
228
229        # We never actually allow playing last-stand on easy mode.
230        if game == 'Easy:The Last Stand':
231            unlocked = False
232
233        # Hard-code games we haven't unlocked.
234        assert bui.app.classic is not None
235        if (
236            (
237                game in ('Challenges:Infinite Runaround',)
238                and not (
239                    bui.app.classic.accounts.have_pro()
240                    or plus.get_v1_account_product_purchased(
241                        'upgrades.infinite_runaround'
242                    )
243                )
244            )
245            or (
246                game in ('Challenges:Infinite Onslaught',)
247                and not (
248                    bui.app.classic.accounts.have_pro()
249                    or plus.get_v1_account_product_purchased(
250                        'upgrades.infinite_onslaught'
251                    )
252                )
253            )
254            or (
255                game in ('Challenges:Meteor Shower',)
256                and not plus.get_v1_account_product_purchased(
257                    'games.meteor_shower'
258                )
259            )
260            or (
261                game
262                in (
263                    'Challenges:Target Practice',
264                    'Challenges:Target Practice B',
265                )
266                and not plus.get_v1_account_product_purchased(
267                    'games.target_practice'
268                )
269            )
270            or (
271                game in ('Challenges:Ninja Fight',)
272                and not plus.get_v1_account_product_purchased(
273                    'games.ninja_fight'
274                )
275            )
276            or (
277                game in ('Challenges:Pro Ninja Fight',)
278                and not plus.get_v1_account_product_purchased(
279                    'games.ninja_fight'
280                )
281            )
282            or (
283                game
284                in (
285                    'Challenges:Easter Egg Hunt',
286                    'Challenges:Pro Easter Egg Hunt',
287                )
288                and not plus.get_v1_account_product_purchased(
289                    'games.easter_egg_hunt'
290                )
291            )
292        ):
293            unlocked = False
294
295        # Let's tint levels a slightly different color when easy mode
296        # is selected.
297        unlocked_color = (
298            (0.85, 0.95, 0.5) if game.startswith('Easy:') else (0.5, 0.7, 0.2)
299        )
300
301        bui.buttonwidget(
302            edit=self._button,
303            color=unlocked_color if unlocked else (0.5, 0.5, 0.5),
304        )
305
306        bui.imagewidget(
307            edit=self._lock_widget, opacity=0.0 if unlocked else 1.0
308        )
309        bui.imagewidget(
310            edit=self._preview_widget, opacity=1.0 if unlocked else 0.3
311        )
312        bui.textwidget(
313            edit=self._name_widget,
314            color=(0.8, 1.0, 0.8, 1.0) if unlocked else (0.7, 0.7, 0.7, 0.7),
315        )
316        for widget in self._star_widgets:
317            bui.imagewidget(
318                edit=widget,
319                opacity=1.0 if unlocked else 0.3,
320                color=(2.2, 1.2, 0.3) if unlocked else (1, 1, 1),
321            )
322        for i, ach in enumerate(self._achievements):
323            a_complete = ach.complete
324            bui.imagewidget(
325                edit=self._achievement_widgets[i][0],
326                opacity=1.0 if (a_complete and unlocked) else 0.3,
327            )
328            bui.imagewidget(
329                edit=self._achievement_widgets[i][1],
330                opacity=(
331                    1.0
332                    if (a_complete and unlocked)
333                    else 0.2 if a_complete else 0.0
334                ),
335            )
class GameButton:
 17class GameButton:
 18    """Button for entering co-op games."""
 19
 20    def __init__(
 21        self,
 22        window: CoopBrowserWindow,
 23        parent: bui.Widget,
 24        game: str,
 25        x: float,
 26        y: float,
 27        select: bool,
 28        row: str,
 29    ):
 30        # pylint: disable=too-many-positional-arguments
 31        # pylint: disable=too-many-statements
 32        # pylint: disable=too-many-locals
 33
 34        assert bui.app.classic is not None
 35        self._game = game
 36        sclx = 195.0
 37        scly = 195.0
 38
 39        campaignname, levelname = game.split(':')
 40
 41        # Hack: The Last Stand doesn't actually exist in the easy
 42        # tourney. We just want it for display purposes. Map it to
 43        # the hard-mode version.
 44        if game == 'Easy:The Last Stand':
 45            campaignname = 'Default'
 46
 47        rating: float | None
 48        campaign = bui.app.classic.getcampaign(campaignname)
 49        rating = campaign.getlevel(levelname).rating
 50
 51        if game == 'Easy:The Last Stand':
 52            rating = None
 53
 54        if rating is None or rating == 0.0:
 55            stars = 0
 56        elif rating >= 9.5:
 57            stars = 3
 58        elif rating >= 7.5:
 59            stars = 2
 60        else:
 61            stars = 1
 62
 63        self._button = btn = bui.buttonwidget(
 64            parent=parent,
 65            position=(x + 23, y + 4),
 66            size=(sclx, scly),
 67            label='',
 68            on_activate_call=bui.Call(window.run_game, game),
 69            button_type='square',
 70            autoselect=True,
 71            on_select_call=bui.Call(window.sel_change, row, game),
 72        )
 73        bui.widget(
 74            edit=btn,
 75            show_buffer_bottom=50,
 76            show_buffer_top=50,
 77            show_buffer_left=400,
 78            show_buffer_right=200,
 79        )
 80        if select:
 81            bui.containerwidget(
 82                edit=parent, selected_child=btn, visible_child=btn
 83            )
 84        image_width = sclx * 0.85 * 0.75
 85        self._preview_widget = bui.imagewidget(
 86            parent=parent,
 87            draw_controller=btn,
 88            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 104),
 89            size=(image_width, image_width * 0.5),
 90            mesh_transparent=window.lsbt,
 91            mesh_opaque=window.lsbo,
 92            texture=bui.gettexture(
 93                campaign.getlevel(levelname).preview_texture_name
 94            ),
 95            mask_texture=bui.gettexture('mapPreviewMask'),
 96        )
 97
 98        translated = campaign.getlevel(levelname).displayname
 99        self._achievements = bui.app.classic.ach.achievements_for_coop_level(
100            game
101        )
102
103        self._name_widget = bui.textwidget(
104            parent=parent,
105            draw_controller=btn,
106            position=(x + 20 + sclx * 0.5, y + scly - 27),
107            size=(0, 0),
108            h_align='center',
109            text=translated,
110            v_align='center',
111            maxwidth=sclx * 0.76,
112            scale=0.85,
113        )
114        xscl = x + (67 if self._achievements else 50)
115        yscl = y + scly - (137 if self._achievements else 157)
116
117        starscale = 35.0 if self._achievements else 45.0
118
119        self._star_widgets: list[bui.Widget] = []
120        for _i in range(stars):
121            imw = bui.imagewidget(
122                parent=parent,
123                draw_controller=btn,
124                position=(xscl, yscl),
125                size=(starscale, starscale),
126                texture=window.star_tex,
127            )
128            self._star_widgets.append(imw)
129            xscl += starscale
130        for _i in range(3 - stars):
131            bui.imagewidget(
132                parent=parent,
133                draw_controller=btn,
134                position=(xscl, yscl),
135                size=(starscale, starscale),
136                color=(0, 0, 0),
137                texture=window.star_tex,
138                opacity=0.3,
139            )
140            xscl += starscale
141
142        xach = x + 69
143        yach = y + scly - 168
144        a_scale = 30.0
145        self._achievement_widgets: list[tuple[bui.Widget, bui.Widget]] = []
146        for ach in self._achievements:
147            a_complete = ach.complete
148            imw = bui.imagewidget(
149                parent=parent,
150                draw_controller=btn,
151                position=(xach, yach),
152                size=(a_scale, a_scale),
153                color=(
154                    tuple(ach.get_icon_color(a_complete)[:3])
155                    if a_complete
156                    else (1.2, 1.2, 1.2)
157                ),
158                texture=ach.get_icon_ui_texture(a_complete),
159            )
160            imw2 = bui.imagewidget(
161                parent=parent,
162                draw_controller=btn,
163                position=(xach, yach),
164                size=(a_scale, a_scale),
165                color=(2, 1.4, 0.4),
166                texture=window.a_outline_tex,
167                mesh_transparent=window.a_outline_mesh,
168            )
169            self._achievement_widgets.append((imw, imw2))
170            # if a_complete:
171            xach += a_scale * 1.2
172
173        # if not unlocked:
174        self._lock_widget = bui.imagewidget(
175            parent=parent,
176            draw_controller=btn,
177            position=(x - 8 + sclx * 0.5, y + scly * 0.5 - 20),
178            size=(60, 60),
179            opacity=0.0,
180            texture=bui.gettexture('lock'),
181        )
182
183        # give a quasi-random update increment to spread the load..
184        self._update_timer = bui.AppTimer(
185            0.001 * (900 + random.randrange(200)),
186            bui.WeakCall(self._update),
187            repeat=True,
188        )
189        self._update()
190
191    def get_button(self) -> bui.Widget:
192        """Return the underlying button bui.Widget."""
193        return self._button
194
195    def _update(self) -> None:
196        # pylint: disable=too-many-boolean-expressions
197
198        plus = bui.app.plus
199        assert plus is not None
200
201        classic = bui.app.classic
202        assert classic is not None
203
204        # In case we stick around after our UI...
205        if not self._button:
206            return
207
208        game = self._game
209        campaignname, levelname = game.split(':')
210
211        # Hack - The Last Stand doesn't actually exist in the
212        # easy tourney; we just want it for display purposes. Map it to
213        # the hard-mode version.
214        if game == 'Easy:The Last Stand':
215            campaignname = 'Default'
216
217        campaign = classic.getcampaign(campaignname)
218
219        # If this campaign is sequential, make sure we've unlocked
220        # everything up to here.
221        unlocked = True
222        if campaign.sequential:
223            for level in campaign.levels:
224                if level.name == levelname:
225                    break
226                if not level.complete:
227                    unlocked = False
228                    break
229
230        # We never actually allow playing last-stand on easy mode.
231        if game == 'Easy:The Last Stand':
232            unlocked = False
233
234        # Hard-code games we haven't unlocked.
235        assert bui.app.classic is not None
236        if (
237            (
238                game in ('Challenges:Infinite Runaround',)
239                and not (
240                    bui.app.classic.accounts.have_pro()
241                    or plus.get_v1_account_product_purchased(
242                        'upgrades.infinite_runaround'
243                    )
244                )
245            )
246            or (
247                game in ('Challenges:Infinite Onslaught',)
248                and not (
249                    bui.app.classic.accounts.have_pro()
250                    or plus.get_v1_account_product_purchased(
251                        'upgrades.infinite_onslaught'
252                    )
253                )
254            )
255            or (
256                game in ('Challenges:Meteor Shower',)
257                and not plus.get_v1_account_product_purchased(
258                    'games.meteor_shower'
259                )
260            )
261            or (
262                game
263                in (
264                    'Challenges:Target Practice',
265                    'Challenges:Target Practice B',
266                )
267                and not plus.get_v1_account_product_purchased(
268                    'games.target_practice'
269                )
270            )
271            or (
272                game in ('Challenges:Ninja Fight',)
273                and not plus.get_v1_account_product_purchased(
274                    'games.ninja_fight'
275                )
276            )
277            or (
278                game in ('Challenges:Pro Ninja Fight',)
279                and not plus.get_v1_account_product_purchased(
280                    'games.ninja_fight'
281                )
282            )
283            or (
284                game
285                in (
286                    'Challenges:Easter Egg Hunt',
287                    'Challenges:Pro Easter Egg Hunt',
288                )
289                and not plus.get_v1_account_product_purchased(
290                    'games.easter_egg_hunt'
291                )
292            )
293        ):
294            unlocked = False
295
296        # Let's tint levels a slightly different color when easy mode
297        # is selected.
298        unlocked_color = (
299            (0.85, 0.95, 0.5) if game.startswith('Easy:') else (0.5, 0.7, 0.2)
300        )
301
302        bui.buttonwidget(
303            edit=self._button,
304            color=unlocked_color if unlocked else (0.5, 0.5, 0.5),
305        )
306
307        bui.imagewidget(
308            edit=self._lock_widget, opacity=0.0 if unlocked else 1.0
309        )
310        bui.imagewidget(
311            edit=self._preview_widget, opacity=1.0 if unlocked else 0.3
312        )
313        bui.textwidget(
314            edit=self._name_widget,
315            color=(0.8, 1.0, 0.8, 1.0) if unlocked else (0.7, 0.7, 0.7, 0.7),
316        )
317        for widget in self._star_widgets:
318            bui.imagewidget(
319                edit=widget,
320                opacity=1.0 if unlocked else 0.3,
321                color=(2.2, 1.2, 0.3) if unlocked else (1, 1, 1),
322            )
323        for i, ach in enumerate(self._achievements):
324            a_complete = ach.complete
325            bui.imagewidget(
326                edit=self._achievement_widgets[i][0],
327                opacity=1.0 if (a_complete and unlocked) else 0.3,
328            )
329            bui.imagewidget(
330                edit=self._achievement_widgets[i][1],
331                opacity=(
332                    1.0
333                    if (a_complete and unlocked)
334                    else 0.2 if a_complete else 0.0
335                ),
336            )

Button for entering co-op games.

GameButton( window: bauiv1lib.coop.browser.CoopBrowserWindow, parent: _bauiv1.Widget, game: str, x: float, y: float, select: bool, row: str)
 20    def __init__(
 21        self,
 22        window: CoopBrowserWindow,
 23        parent: bui.Widget,
 24        game: str,
 25        x: float,
 26        y: float,
 27        select: bool,
 28        row: str,
 29    ):
 30        # pylint: disable=too-many-positional-arguments
 31        # pylint: disable=too-many-statements
 32        # pylint: disable=too-many-locals
 33
 34        assert bui.app.classic is not None
 35        self._game = game
 36        sclx = 195.0
 37        scly = 195.0
 38
 39        campaignname, levelname = game.split(':')
 40
 41        # Hack: The Last Stand doesn't actually exist in the easy
 42        # tourney. We just want it for display purposes. Map it to
 43        # the hard-mode version.
 44        if game == 'Easy:The Last Stand':
 45            campaignname = 'Default'
 46
 47        rating: float | None
 48        campaign = bui.app.classic.getcampaign(campaignname)
 49        rating = campaign.getlevel(levelname).rating
 50
 51        if game == 'Easy:The Last Stand':
 52            rating = None
 53
 54        if rating is None or rating == 0.0:
 55            stars = 0
 56        elif rating >= 9.5:
 57            stars = 3
 58        elif rating >= 7.5:
 59            stars = 2
 60        else:
 61            stars = 1
 62
 63        self._button = btn = bui.buttonwidget(
 64            parent=parent,
 65            position=(x + 23, y + 4),
 66            size=(sclx, scly),
 67            label='',
 68            on_activate_call=bui.Call(window.run_game, game),
 69            button_type='square',
 70            autoselect=True,
 71            on_select_call=bui.Call(window.sel_change, row, game),
 72        )
 73        bui.widget(
 74            edit=btn,
 75            show_buffer_bottom=50,
 76            show_buffer_top=50,
 77            show_buffer_left=400,
 78            show_buffer_right=200,
 79        )
 80        if select:
 81            bui.containerwidget(
 82                edit=parent, selected_child=btn, visible_child=btn
 83            )
 84        image_width = sclx * 0.85 * 0.75
 85        self._preview_widget = bui.imagewidget(
 86            parent=parent,
 87            draw_controller=btn,
 88            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 104),
 89            size=(image_width, image_width * 0.5),
 90            mesh_transparent=window.lsbt,
 91            mesh_opaque=window.lsbo,
 92            texture=bui.gettexture(
 93                campaign.getlevel(levelname).preview_texture_name
 94            ),
 95            mask_texture=bui.gettexture('mapPreviewMask'),
 96        )
 97
 98        translated = campaign.getlevel(levelname).displayname
 99        self._achievements = bui.app.classic.ach.achievements_for_coop_level(
100            game
101        )
102
103        self._name_widget = bui.textwidget(
104            parent=parent,
105            draw_controller=btn,
106            position=(x + 20 + sclx * 0.5, y + scly - 27),
107            size=(0, 0),
108            h_align='center',
109            text=translated,
110            v_align='center',
111            maxwidth=sclx * 0.76,
112            scale=0.85,
113        )
114        xscl = x + (67 if self._achievements else 50)
115        yscl = y + scly - (137 if self._achievements else 157)
116
117        starscale = 35.0 if self._achievements else 45.0
118
119        self._star_widgets: list[bui.Widget] = []
120        for _i in range(stars):
121            imw = bui.imagewidget(
122                parent=parent,
123                draw_controller=btn,
124                position=(xscl, yscl),
125                size=(starscale, starscale),
126                texture=window.star_tex,
127            )
128            self._star_widgets.append(imw)
129            xscl += starscale
130        for _i in range(3 - stars):
131            bui.imagewidget(
132                parent=parent,
133                draw_controller=btn,
134                position=(xscl, yscl),
135                size=(starscale, starscale),
136                color=(0, 0, 0),
137                texture=window.star_tex,
138                opacity=0.3,
139            )
140            xscl += starscale
141
142        xach = x + 69
143        yach = y + scly - 168
144        a_scale = 30.0
145        self._achievement_widgets: list[tuple[bui.Widget, bui.Widget]] = []
146        for ach in self._achievements:
147            a_complete = ach.complete
148            imw = bui.imagewidget(
149                parent=parent,
150                draw_controller=btn,
151                position=(xach, yach),
152                size=(a_scale, a_scale),
153                color=(
154                    tuple(ach.get_icon_color(a_complete)[:3])
155                    if a_complete
156                    else (1.2, 1.2, 1.2)
157                ),
158                texture=ach.get_icon_ui_texture(a_complete),
159            )
160            imw2 = bui.imagewidget(
161                parent=parent,
162                draw_controller=btn,
163                position=(xach, yach),
164                size=(a_scale, a_scale),
165                color=(2, 1.4, 0.4),
166                texture=window.a_outline_tex,
167                mesh_transparent=window.a_outline_mesh,
168            )
169            self._achievement_widgets.append((imw, imw2))
170            # if a_complete:
171            xach += a_scale * 1.2
172
173        # if not unlocked:
174        self._lock_widget = bui.imagewidget(
175            parent=parent,
176            draw_controller=btn,
177            position=(x - 8 + sclx * 0.5, y + scly * 0.5 - 20),
178            size=(60, 60),
179            opacity=0.0,
180            texture=bui.gettexture('lock'),
181        )
182
183        # give a quasi-random update increment to spread the load..
184        self._update_timer = bui.AppTimer(
185            0.001 * (900 + random.randrange(200)),
186            bui.WeakCall(self._update),
187            repeat=True,
188        )
189        self._update()
def get_button(self) -> _bauiv1.Widget:
191    def get_button(self) -> bui.Widget:
192        """Return the underlying button bui.Widget."""
193        return self._button

Return the underlying button bui.Widget.