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
238                in (
239                    'Challenges:Infinite Runaround',
240                    'Challenges:Infinite Onslaught',
241                )
242                and not bui.app.classic.accounts.have_pro()
243            )
244            or (
245                game in ('Challenges:Meteor Shower',)
246                and not plus.get_v1_account_product_purchased(
247                    'games.meteor_shower'
248                )
249            )
250            or (
251                game
252                in (
253                    'Challenges:Target Practice',
254                    'Challenges:Target Practice B',
255                )
256                and not plus.get_v1_account_product_purchased(
257                    'games.target_practice'
258                )
259            )
260            or (
261                game in ('Challenges:Ninja Fight',)
262                and not plus.get_v1_account_product_purchased(
263                    'games.ninja_fight'
264                )
265            )
266            or (
267                game in ('Challenges:Pro Ninja Fight',)
268                and not plus.get_v1_account_product_purchased(
269                    'games.ninja_fight'
270                )
271            )
272            or (
273                game
274                in (
275                    'Challenges:Easter Egg Hunt',
276                    'Challenges:Pro Easter Egg Hunt',
277                )
278                and not plus.get_v1_account_product_purchased(
279                    'games.easter_egg_hunt'
280                )
281            )
282        ):
283            unlocked = False
284
285        # Let's tint levels a slightly different color when easy mode
286        # is selected.
287        unlocked_color = (
288            (0.85, 0.95, 0.5) if game.startswith('Easy:') else (0.5, 0.7, 0.2)
289        )
290
291        bui.buttonwidget(
292            edit=self._button,
293            color=unlocked_color if unlocked else (0.5, 0.5, 0.5),
294        )
295
296        bui.imagewidget(
297            edit=self._lock_widget, opacity=0.0 if unlocked else 1.0
298        )
299        bui.imagewidget(
300            edit=self._preview_widget, opacity=1.0 if unlocked else 0.3
301        )
302        bui.textwidget(
303            edit=self._name_widget,
304            color=(0.8, 1.0, 0.8, 1.0) if unlocked else (0.7, 0.7, 0.7, 0.7),
305        )
306        for widget in self._star_widgets:
307            bui.imagewidget(
308                edit=widget,
309                opacity=1.0 if unlocked else 0.3,
310                color=(2.2, 1.2, 0.3) if unlocked else (1, 1, 1),
311            )
312        for i, ach in enumerate(self._achievements):
313            a_complete = ach.complete
314            bui.imagewidget(
315                edit=self._achievement_widgets[i][0],
316                opacity=1.0 if (a_complete and unlocked) else 0.3,
317            )
318            bui.imagewidget(
319                edit=self._achievement_widgets[i][1],
320                opacity=(
321                    1.0
322                    if (a_complete and unlocked)
323                    else 0.2 if a_complete else 0.0
324                ),
325            )
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
239                in (
240                    'Challenges:Infinite Runaround',
241                    'Challenges:Infinite Onslaught',
242                )
243                and not bui.app.classic.accounts.have_pro()
244            )
245            or (
246                game in ('Challenges:Meteor Shower',)
247                and not plus.get_v1_account_product_purchased(
248                    'games.meteor_shower'
249                )
250            )
251            or (
252                game
253                in (
254                    'Challenges:Target Practice',
255                    'Challenges:Target Practice B',
256                )
257                and not plus.get_v1_account_product_purchased(
258                    'games.target_practice'
259                )
260            )
261            or (
262                game in ('Challenges:Ninja Fight',)
263                and not plus.get_v1_account_product_purchased(
264                    'games.ninja_fight'
265                )
266            )
267            or (
268                game in ('Challenges:Pro Ninja Fight',)
269                and not plus.get_v1_account_product_purchased(
270                    'games.ninja_fight'
271                )
272            )
273            or (
274                game
275                in (
276                    'Challenges:Easter Egg Hunt',
277                    'Challenges:Pro Easter Egg Hunt',
278                )
279                and not plus.get_v1_account_product_purchased(
280                    'games.easter_egg_hunt'
281                )
282            )
283        ):
284            unlocked = False
285
286        # Let's tint levels a slightly different color when easy mode
287        # is selected.
288        unlocked_color = (
289            (0.85, 0.95, 0.5) if game.startswith('Easy:') else (0.5, 0.7, 0.2)
290        )
291
292        bui.buttonwidget(
293            edit=self._button,
294            color=unlocked_color if unlocked else (0.5, 0.5, 0.5),
295        )
296
297        bui.imagewidget(
298            edit=self._lock_widget, opacity=0.0 if unlocked else 1.0
299        )
300        bui.imagewidget(
301            edit=self._preview_widget, opacity=1.0 if unlocked else 0.3
302        )
303        bui.textwidget(
304            edit=self._name_widget,
305            color=(0.8, 1.0, 0.8, 1.0) if unlocked else (0.7, 0.7, 0.7, 0.7),
306        )
307        for widget in self._star_widgets:
308            bui.imagewidget(
309                edit=widget,
310                opacity=1.0 if unlocked else 0.3,
311                color=(2.2, 1.2, 0.3) if unlocked else (1, 1, 1),
312            )
313        for i, ach in enumerate(self._achievements):
314            a_complete = ach.complete
315            bui.imagewidget(
316                edit=self._achievement_widgets[i][0],
317                opacity=1.0 if (a_complete and unlocked) else 0.3,
318            )
319            bui.imagewidget(
320                edit=self._achievement_widgets[i][1],
321                opacity=(
322                    1.0
323                    if (a_complete and unlocked)
324                    else 0.2 if a_complete else 0.0
325                ),
326            )

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.