Bombsquad-Ballistica-Modded.../dist/ba_data/python/bauiv1lib/mainmenu.py

568 lines
20 KiB
Python
Raw Permalink Normal View History

2021-03-29 03:24:13 +05:30
# Released under the MIT License. See LICENSE for details.
#
"""Implements the main menu window."""
from __future__ import annotations
2025-02-09 00:17:58 +05:30
from typing import TYPE_CHECKING, override
2023-08-13 17:21:49 +05:30
import logging
2021-03-29 03:24:13 +05:30
2023-08-13 17:21:49 +05:30
import bauiv1 as bui
import bascenev1 as bs
2021-03-29 03:24:13 +05:30
if TYPE_CHECKING:
2022-06-30 00:31:52 +05:30
from typing import Any, Callable
2021-03-29 03:24:13 +05:30
2025-02-09 00:17:58 +05:30
class MainMenuWindow(bui.MainWindow):
"""The main menu window."""
2021-03-29 03:24:13 +05:30
2025-02-09 00:17:58 +05:30
def __init__(
self,
transition: str | None = 'in_right',
origin_widget: bui.Widget | None = None,
):
2025-10-21 19:08:49 +05:30
ui = bui.app.ui_v1
2021-03-29 03:24:13 +05:30
# Preload some modules we use in a background thread so we won't
# have a visual hitch when the user taps them.
2025-02-09 00:17:58 +05:30
bui.app.threadpool.submit_no_wait(self._preload_modules)
bui.set_analytics_screen('Main Menu')
self._show_remote_app_info_on_first_launch()
2021-03-29 03:24:13 +05:30
2025-10-21 19:08:49 +05:30
uiscale = ui.uiscale
2021-03-29 03:24:13 +05:30
2024-11-28 00:23:35 +05:30
# Make a vanilla container; we'll modify it to our needs in
# refresh.
super().__init__(
2023-08-13 17:21:49 +05:30
root_widget=bui.containerwidget(
2025-10-21 19:08:49 +05:30
toolbar_visibility=('menu_full_no_back'),
2025-02-09 00:17:58 +05:30
),
transition=transition,
origin_widget=origin_widget,
# We're affected by screen size only at small ui-scale.
refresh_on_screen_size_changes=uiscale is bui.UIScale.SMALL,
)
2021-03-29 03:24:13 +05:30
self._tdelay = 0.0
self._t_delay_inc = 0.02
self._t_delay_play = 1.7
self._use_autoselect = True
self._button_width = 200.0
self._button_height = 45.0
self._width = 100.0
self._height = 100.0
2023-08-13 17:21:49 +05:30
self._demo_menu_button: bui.Widget | None = None
self._gather_button: bui.Widget | None = None
2025-02-09 00:17:58 +05:30
self._play_button: bui.Widget | None = None
2023-08-13 17:21:49 +05:30
self._watch_button: bui.Widget | None = None
self._how_to_play_button: bui.Widget | None = None
self._credits_button: bui.Widget | None = None
2021-03-29 03:24:13 +05:30
self._refresh()
2025-02-09 00:17:58 +05:30
@override
def get_main_window_state(self) -> bui.MainWindowState:
# Support recreating our window for back/refresh purposes.
cls = type(self)
2025-10-21 19:08:49 +05:30
# Pull values from self here; if we do it in the lambda we'll
# keep self alive which we don't want.
# id_prefix = self._id_prefix
2025-02-09 00:17:58 +05:30
return bui.BasicMainWindowState(
create_call=lambda transition, origin_widget: cls(
2025-10-21 19:08:49 +05:30
transition=transition,
origin_widget=origin_widget,
),
)
2021-03-29 03:24:13 +05:30
2025-10-21 19:08:49 +05:30
@override
def main_window_should_preserve_selection(self) -> bool:
return True
2021-03-29 03:24:13 +05:30
@staticmethod
def _preload_modules() -> None:
2023-09-30 17:21:33 +05:30
"""Preload modules we use; avoids hitches (called in bg thread)."""
2025-02-09 00:17:58 +05:30
# pylint: disable=cyclic-import
2023-08-13 17:21:49 +05:30
import bauiv1lib.getremote as _unused
import bauiv1lib.confirm as _unused2
import bauiv1lib.account.settings as _unused5
2026-02-15 14:00:00 +05:30
import bauiv1lib.credits as _unused6
import bauiv1lib.help as _unused7
import bauiv1lib.settings.allsettings as _unused8
import bauiv1lib.gather as _unused9
import bauiv1lib.watch as _unused10
import bauiv1lib.play as _unused11
2021-03-29 03:24:13 +05:30
def _show_remote_app_info_on_first_launch(self) -> None:
2023-08-13 17:21:49 +05:30
app = bui.app
assert app.classic is not None
2025-02-09 00:17:58 +05:30
# The first time the non-in-game menu pops up, we might wanna
# show a 'get-remote-app' dialog in front of it.
2023-08-13 17:21:49 +05:30
if app.classic.first_main_menu:
app.classic.first_main_menu = False
2021-03-29 03:24:13 +05:30
try:
force_test = False
2023-08-13 17:21:49 +05:30
bs.get_local_active_input_devices_count()
if (
2023-09-30 17:21:33 +05:30
(app.env.tv or app.classic.platform == 'mac')
2023-08-13 17:21:49 +05:30
and bui.app.config.get('launchCount', 0) <= 1
) or force_test:
2021-03-29 03:24:13 +05:30
def _check_show_bs_remote_window() -> None:
try:
2023-08-13 17:21:49 +05:30
from bauiv1lib.getremote import GetBSRemoteWindow
2023-08-13 17:21:49 +05:30
bui.getsound('swish').play()
2021-03-29 03:24:13 +05:30
GetBSRemoteWindow()
except Exception:
2023-08-13 17:21:49 +05:30
logging.exception(
'Error showing get-remote window.'
)
2023-08-13 17:21:49 +05:30
bui.apptimer(2.5, _check_show_bs_remote_window)
2021-03-29 03:24:13 +05:30
except Exception:
2023-08-13 17:21:49 +05:30
logging.exception('Error showing get-remote-app info.')
2021-03-29 03:24:13 +05:30
2023-08-13 17:21:49 +05:30
def get_play_button(self) -> bui.Widget | None:
2021-03-29 03:24:13 +05:30
"""Return the play button."""
2025-02-09 00:17:58 +05:30
return self._play_button
2021-03-29 03:24:13 +05:30
def _refresh(self) -> None:
# pylint: disable=too-many-statements
2025-02-09 00:17:58 +05:30
# pylint: disable=too-many-locals
2023-08-13 17:21:49 +05:30
2025-02-09 00:17:58 +05:30
classic = bui.app.classic
assert classic is not None
2021-03-29 03:24:13 +05:30
# Clear everything that was there.
children = self._root_widget.get_children()
for child in children:
child.delete()
self._tdelay = 0.0
self._t_delay_inc = 0.0
self._t_delay_play = 0.0
self._button_width = 200.0
self._button_height = 45.0
self._r = 'mainMenu'
2023-08-13 17:21:49 +05:30
app = bui.app
assert app.classic is not None
2025-02-09 00:17:58 +05:30
uiscale = app.ui_v1.uiscale
2021-03-29 03:24:13 +05:30
2025-02-09 00:17:58 +05:30
# Temp note about UI changes.
if bool(False):
2024-05-19 18:25:43 +05:30
bui.textwidget(
parent=self._root_widget,
position=(
2025-02-09 00:17:58 +05:30
(-400, 400)
if uiscale is bui.UIScale.LARGE
else (
(-270, 320)
if uiscale is bui.UIScale.MEDIUM
else (-280, 280)
)
2024-05-19 18:25:43 +05:30
),
size=(0, 0),
2025-02-09 00:17:58 +05:30
scale=0.4,
flatness=1.0,
text=(
'WARNING: This build contains a revamped UI\n'
'which is still a work-in-progress. A number\n'
'of features are not currently functional or\n'
'contain bugs. To go back to the stable legacy UI,\n'
'grab version 1.7.36 from ballistica.net'
2024-05-19 18:25:43 +05:30
),
2025-02-09 00:17:58 +05:30
h_align='left',
v_align='top',
2024-05-19 18:25:43 +05:30
)
2025-02-09 00:17:58 +05:30
self._have_quit_button = app.classic.platform in (
'windows',
'mac',
'linux',
)
2024-05-19 18:25:43 +05:30
2025-02-09 00:17:58 +05:30
if not classic.did_menu_intro:
self._tdelay = 1.6
self._t_delay_inc = 0.03
classic.did_menu_intro = True
td1 = 2
td2 = 1
td3 = 0
td4 = -1
td5 = -2
2021-03-29 03:24:13 +05:30
self._width = 400.0
self._height = 200.0
2025-02-09 00:17:58 +05:30
play_button_width = self._button_width * 0.65
play_button_height = self._button_height * 1.1
play_button_scale = 1.7
hspace = 20.0
side_button_width = self._button_width * 0.4
side_button_height = side_button_width
side_button_scale = 0.95
side_button_y_offs = 5.0
hspace2 = 15.0
side_button_2_width = self._button_width * 1.0
side_button_2_height = side_button_2_width * 0.3
side_button_2_y_offs = 10.0
side_button_2_scale = 0.5
2023-08-13 17:21:49 +05:30
if uiscale is bui.UIScale.SMALL:
2025-02-09 00:17:58 +05:30
# We're a generally widescreen shaped window, so bump our
# overall scale up a bit when screen width is wider than safe
# bounds to take advantage of the extra space.
screensize = bui.get_virtual_screen_size()
safesize = bui.get_virtual_safe_area_size()
root_widget_scale = min(1.55, 1.3 * screensize[0] / safesize[0])
2021-03-29 03:24:13 +05:30
button_y_offs = -20.0
self._button_height *= 1.3
2023-08-13 17:21:49 +05:30
elif uiscale is bui.UIScale.MEDIUM:
2021-03-29 03:24:13 +05:30
root_widget_scale = 1.3
button_y_offs = -55.0
self._button_height *= 1.25
else:
root_widget_scale = 1.0
2025-02-09 00:17:58 +05:30
button_y_offs = -90.0
2021-03-29 03:24:13 +05:30
self._button_height *= 1.2
2025-02-09 00:17:58 +05:30
2023-08-13 17:21:49 +05:30
bui.containerwidget(
edit=self._root_widget,
size=(self._width, self._height),
background=False,
scale=root_widget_scale,
)
2025-02-09 00:17:58 +05:30
# Version/copyright info.
thistdelay = self._tdelay + td3 * self._t_delay_inc
bui.textwidget(
parent=self._root_widget,
position=(self._width * 0.5, button_y_offs - 10),
size=(0, 0),
scale=0.4,
flatness=1.0,
color=(1, 1, 1, 0.3),
text=(
f'{app.env.engine_version}'
f' build {app.env.engine_build_number}.'
2026-02-15 14:00:00 +05:30
f' Copyright 2011-2026 Eric Froemling.'
2025-02-09 00:17:58 +05:30
),
h_align='center',
v_align='center',
transition_delay=thistdelay,
)
2025-09-07 18:34:55 +05:30
variant = bui.app.env.variant
vart = type(variant)
arcade_or_demo = variant is vart.ARCADE or variant is vart.DEMO
2021-03-29 03:24:13 +05:30
# In kiosk mode, provide a button to get back to the kiosk menu.
2025-09-07 18:34:55 +05:30
if arcade_or_demo:
2025-02-09 00:17:58 +05:30
h = self._width * 0.5
v = button_y_offs
scale = 1.0
2021-03-29 03:24:13 +05:30
this_b_width = self._button_width * 0.4 * scale
2025-02-09 00:17:58 +05:30
demo_menu_delay = 0.0
2023-08-13 17:21:49 +05:30
self._demo_menu_button = bui.buttonwidget(
2021-03-29 03:24:13 +05:30
parent=self._root_widget,
2025-10-21 19:08:49 +05:30
id=f'{self.main_window_id_prefix}|demo',
2021-03-29 03:24:13 +05:30
position=(self._width * 0.5 - this_b_width * 0.5, v + 90),
size=(this_b_width, 45),
autoselect=True,
color=(0.45, 0.55, 0.45),
textcolor=(0.7, 0.8, 0.7),
2023-08-13 17:21:49 +05:30
label=bui.Lstr(
2024-05-19 18:25:43 +05:30
resource=(
'modeArcadeText'
2025-09-07 18:34:55 +05:30
if variant is vart.ARCADE
2024-05-19 18:25:43 +05:30
else 'modeDemoText'
)
),
2021-03-29 03:24:13 +05:30
transition_delay=demo_menu_delay,
2025-02-09 00:17:58 +05:30
on_activate_call=self.main_window_back,
)
2021-03-29 03:24:13 +05:30
else:
self._demo_menu_button = None
2025-02-09 00:17:58 +05:30
# Gather button
h = self._width * 0.5
h = (
self._width * 0.5
- play_button_width * play_button_scale * 0.5
- hspace
- side_button_width * side_button_scale * 0.5
)
2025-02-09 00:17:58 +05:30
v = button_y_offs + side_button_y_offs
thistdelay = self._tdelay + td2 * self._t_delay_inc
2025-05-26 01:11:57 +05:30
self._gather_button = bui.buttonwidget(
2021-03-29 03:24:13 +05:30
parent=self._root_widget,
2025-10-21 19:08:49 +05:30
id=f'{self.main_window_id_prefix}|gather',
2025-02-09 00:17:58 +05:30
position=(h - side_button_width * side_button_scale * 0.5, v),
size=(side_button_width, side_button_height),
scale=side_button_scale,
2021-03-29 03:24:13 +05:30
autoselect=self._use_autoselect,
button_type='square',
label='',
2025-02-09 00:17:58 +05:30
transition_delay=thistdelay,
on_activate_call=self._gather_press,
)
2023-08-13 17:21:49 +05:30
bui.textwidget(
parent=self._root_widget,
2025-02-09 00:17:58 +05:30
position=(h, v + side_button_height * side_button_scale * 0.25),
size=(0, 0),
scale=0.75,
2025-02-09 00:17:58 +05:30
transition_delay=thistdelay,
2025-05-26 01:11:57 +05:30
draw_controller=self._gather_button,
color=(0.75, 1.0, 0.7),
2025-02-09 00:17:58 +05:30
maxwidth=side_button_width * side_button_scale * 0.8,
2023-08-13 17:21:49 +05:30
text=bui.Lstr(resource='gatherWindow.titleText'),
h_align='center',
v_align='center',
)
2025-02-09 00:17:58 +05:30
icon_size = side_button_width * side_button_scale * 0.63
2023-08-13 17:21:49 +05:30
bui.imagewidget(
parent=self._root_widget,
size=(icon_size, icon_size),
2025-05-26 01:11:57 +05:30
draw_controller=self._gather_button,
2025-02-09 00:17:58 +05:30
transition_delay=thistdelay,
position=(
h - 0.5 * icon_size,
v
+ 0.65 * side_button_height * side_button_scale
- 0.5 * icon_size,
),
2023-08-13 17:21:49 +05:30
texture=bui.gettexture('usersButton'),
)
2025-02-09 00:17:58 +05:30
thistdelay = self._tdelay + td1 * self._t_delay_inc
h -= (
side_button_width * side_button_scale * 0.5
+ hspace2
+ side_button_2_width * side_button_2_scale
)
v = button_y_offs + side_button_2_y_offs
2025-05-26 01:11:57 +05:30
self._how_to_play_button = bui.buttonwidget(
2025-02-09 00:17:58 +05:30
parent=self._root_widget,
2025-10-21 19:08:49 +05:30
id=f'{self.main_window_id_prefix}|howtoplay',
2025-02-09 00:17:58 +05:30
position=(h, v),
autoselect=self._use_autoselect,
size=(side_button_2_width, side_button_2_height * 2.0),
button_type='square',
scale=side_button_2_scale,
label=bui.Lstr(resource=f'{self._r}.howToPlayText'),
transition_delay=thistdelay,
on_activate_call=self._howtoplay,
)
2025-05-26 01:11:57 +05:30
bui.widget(
edit=self._how_to_play_button,
left_widget=bui.get_special_widget('settings_button'),
)
2021-03-29 03:24:13 +05:30
# Play button.
2025-02-09 00:17:58 +05:30
h = self._width * 0.5
v = button_y_offs
assert play_button_width is not None
assert play_button_height is not None
thistdelay = self._tdelay + td3 * self._t_delay_inc
2025-10-21 19:08:49 +05:30
self._play_button = play_button = bui.buttonwidget(
2021-03-29 03:24:13 +05:30
parent=self._root_widget,
2025-10-21 19:08:49 +05:30
id=f'{self.main_window_id_prefix}|play',
2025-02-09 00:17:58 +05:30
position=(h - play_button_width * 0.5 * play_button_scale, v),
2021-03-29 03:24:13 +05:30
size=(play_button_width, play_button_height),
autoselect=self._use_autoselect,
2025-02-09 00:17:58 +05:30
scale=play_button_scale,
2021-03-29 03:24:13 +05:30
text_res_scale=2.0,
2023-08-13 17:21:49 +05:30
label=bui.Lstr(resource='playText'),
2025-02-09 00:17:58 +05:30
transition_delay=thistdelay,
on_activate_call=self._play_press,
)
2023-08-13 17:21:49 +05:30
bui.containerwidget(
edit=self._root_widget,
2025-10-21 19:08:49 +05:30
start_button=play_button,
selected_child=play_button,
)
2025-02-09 00:17:58 +05:30
h = (
self._width * 0.5
+ play_button_width * play_button_scale * 0.5
+ hspace
+ side_button_width * side_button_scale * 0.5
)
2025-02-09 00:17:58 +05:30
v = button_y_offs + side_button_y_offs
thistdelay = self._tdelay + td4 * self._t_delay_inc
2025-05-26 01:11:57 +05:30
self._watch_button = bui.buttonwidget(
2021-03-29 03:24:13 +05:30
parent=self._root_widget,
2025-10-21 19:08:49 +05:30
id=f'{self.main_window_id_prefix}|watch',
2025-02-09 00:17:58 +05:30
position=(h - side_button_width * side_button_scale * 0.5, v),
size=(side_button_width, side_button_height),
scale=side_button_scale,
2021-03-29 03:24:13 +05:30
autoselect=self._use_autoselect,
button_type='square',
label='',
2025-02-09 00:17:58 +05:30
transition_delay=thistdelay,
on_activate_call=self._watch_press,
)
2023-08-13 17:21:49 +05:30
bui.textwidget(
parent=self._root_widget,
2025-02-09 00:17:58 +05:30
position=(h, v + side_button_height * side_button_scale * 0.25),
size=(0, 0),
scale=0.75,
2025-02-09 00:17:58 +05:30
transition_delay=thistdelay,
color=(0.75, 1.0, 0.7),
2025-05-26 01:11:57 +05:30
draw_controller=self._watch_button,
2025-02-09 00:17:58 +05:30
maxwidth=side_button_width * side_button_scale * 0.8,
2023-08-13 17:21:49 +05:30
text=bui.Lstr(resource='watchWindow.titleText'),
h_align='center',
v_align='center',
)
2025-02-09 00:17:58 +05:30
icon_size = side_button_width * side_button_scale * 0.63
2023-08-13 17:21:49 +05:30
bui.imagewidget(
parent=self._root_widget,
size=(icon_size, icon_size),
2025-05-26 01:11:57 +05:30
draw_controller=self._watch_button,
2025-02-09 00:17:58 +05:30
transition_delay=thistdelay,
position=(
h - 0.5 * icon_size,
v
+ 0.65 * side_button_height * side_button_scale
- 0.5 * icon_size,
),
2023-08-13 17:21:49 +05:30
texture=bui.gettexture('tv'),
)
2021-03-29 03:24:13 +05:30
2025-02-09 00:17:58 +05:30
# Credits button.
thistdelay = self._tdelay + td5 * self._t_delay_inc
2021-03-29 03:24:13 +05:30
2025-02-09 00:17:58 +05:30
h += side_button_width * side_button_scale * 0.5 + hspace2
v = button_y_offs + side_button_2_y_offs
if self._have_quit_button:
v += 1.17 * side_button_2_height * side_button_2_scale
2021-03-29 03:24:13 +05:30
2023-08-13 17:21:49 +05:30
self._credits_button = bui.buttonwidget(
2021-03-29 03:24:13 +05:30
parent=self._root_widget,
2025-10-21 19:08:49 +05:30
id=f'{self.main_window_id_prefix}|credits',
2025-02-09 00:17:58 +05:30
position=(h, v),
button_type=None if self._have_quit_button else 'square',
size=(
side_button_2_width,
side_button_2_height * (1.0 if self._have_quit_button else 2.0),
),
scale=side_button_2_scale,
2021-03-29 03:24:13 +05:30
autoselect=self._use_autoselect,
2024-11-28 00:23:35 +05:30
label=bui.Lstr(resource=f'{self._r}.creditsText'),
2025-02-09 00:17:58 +05:30
transition_delay=thistdelay,
on_activate_call=self._credits,
)
2021-03-29 03:24:13 +05:30
2025-02-09 00:17:58 +05:30
self._quit_button: bui.Widget | None
if self._have_quit_button:
v -= 1.1 * side_button_2_height * side_button_2_scale
# Nudge this a tiny bit right so we can press right from the
# credits button to get to it.
self._quit_button = quit_button = bui.buttonwidget(
parent=self._root_widget,
2025-10-21 19:08:49 +05:30
id=f'{self.main_window_id_prefix}|quit',
autoselect=self._use_autoselect,
2025-02-09 00:17:58 +05:30
position=(h + 4.0, v),
size=(side_button_2_width, side_button_2_height),
scale=side_button_2_scale,
label=bui.Lstr(
resource=self._r
+ (
'.quitText'
if 'Mac' in app.classic.legacy_user_agent_string
else '.exitGameText'
)
),
2025-02-09 00:17:58 +05:30
on_activate_call=self._quit,
transition_delay=thistdelay,
)
2021-03-29 03:24:13 +05:30
2025-02-09 00:17:58 +05:30
bui.containerwidget(
edit=self._root_widget, cancel_button=quit_button
2024-01-27 21:25:16 +05:30
)
2025-02-09 00:17:58 +05:30
# self._tdelay += self._t_delay_inc
2025-05-26 01:11:57 +05:30
rightmost_button = quit_button
2024-01-27 21:25:16 +05:30
else:
2025-05-26 01:11:57 +05:30
rightmost_button = self._credits_button
2025-02-09 00:17:58 +05:30
self._quit_button = None
# If we're not in-game, have no quit button, and this is
# android, we want back presses to quit our activity.
if app.classic.platform == 'android':
def _do_quit() -> None:
bui.quit(confirm=True, quit_type=bui.QuitType.BACK)
bui.containerwidget(
edit=self._root_widget, on_cancel_call=_do_quit
)
2025-05-26 01:11:57 +05:30
bui.widget(
edit=rightmost_button,
right_widget=bui.get_special_widget('store_button'),
)
2024-01-27 21:25:16 +05:30
2021-03-29 03:24:13 +05:30
def _quit(self) -> None:
# pylint: disable=cyclic-import
2023-08-13 17:21:49 +05:30
from bauiv1lib.confirm import QuitWindow
2025-02-09 00:17:58 +05:30
# no-op if we're not currently in control.
if not self.main_window_has_control():
2023-12-21 15:55:50 +05:30
return
# Note: Normally we should go through bui.quit(confirm=True) but
# invoking the window directly lets us scale it up from the
# button.
2021-03-29 03:24:13 +05:30
QuitWindow(origin_widget=self._quit_button)
def _credits(self) -> None:
# pylint: disable=cyclic-import
2025-02-09 00:17:58 +05:30
from bauiv1lib.credits import CreditsWindow
2025-02-09 00:17:58 +05:30
self.main_window_replace(
2025-10-21 19:08:49 +05:30
lambda: CreditsWindow(origin_widget=self._credits_button),
)
2021-03-29 03:24:13 +05:30
def _howtoplay(self) -> None:
# pylint: disable=cyclic-import
2025-02-09 00:17:58 +05:30
from bauiv1lib.help import HelpWindow
2025-02-09 00:17:58 +05:30
self.main_window_replace(
2025-10-21 19:08:49 +05:30
lambda: HelpWindow(origin_widget=self._how_to_play_button),
)
2021-03-29 03:24:13 +05:30
def _gather_press(self) -> None:
# pylint: disable=cyclic-import
2023-08-13 17:21:49 +05:30
from bauiv1lib.gather import GatherWindow
2025-02-09 00:17:58 +05:30
self.main_window_replace(
2025-10-21 19:08:49 +05:30
lambda: GatherWindow(origin_widget=self._gather_button)
)
2021-03-29 03:24:13 +05:30
def _watch_press(self) -> None:
# pylint: disable=cyclic-import
2023-08-13 17:21:49 +05:30
from bauiv1lib.watch import WatchWindow
2025-02-09 00:17:58 +05:30
self.main_window_replace(
2025-10-21 19:08:49 +05:30
lambda: WatchWindow(origin_widget=self._watch_button),
)
2021-03-29 03:24:13 +05:30
def _play_press(self) -> None:
# pylint: disable=cyclic-import
2023-08-13 17:21:49 +05:30
from bauiv1lib.play import PlayWindow
2025-10-21 19:08:49 +05:30
self.main_window_replace(
lambda: PlayWindow(origin_widget=self._play_button)
)