# Released under the MIT License. See LICENSE for details.
#
"""Settings UI related to gamepad functionality."""
from __future__ import annotations
from typing import TYPE_CHECKING, override
import bascenev1 as bs
import bauiv1 as bui
if TYPE_CHECKING:
from typing import Any
[docs]
class GamepadSelectWindow(bui.MainWindow):
"""Window for selecting a gamepad to configure."""
def __init__(
self,
transition: str | None = 'in_right',
origin_widget: bui.Widget | None = None,
) -> None:
from typing import cast
width = 480
height = 170
spacing = 40
self._r = 'configGamepadSelectWindow'
assert bui.app.classic is not None
uiscale = bui.app.ui_v1.uiscale
super().__init__(
root_widget=bui.containerwidget(
scale=(
2.3
if uiscale is bui.UIScale.SMALL
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
),
size=(width, height),
),
transition=transition,
origin_widget=origin_widget,
)
btn = bui.buttonwidget(
parent=self._root_widget,
position=(20, height - 60),
size=(130, 60),
label=bui.Lstr(resource='backText'),
button_type='back',
scale=0.8,
on_activate_call=self.main_window_back,
)
# Let's not have anything selected by default; its misleading
# looking for the controller getting configured.
bui.containerwidget(
edit=self._root_widget,
cancel_button=btn,
selected_child=cast(bui.Widget, 0),
)
bui.textwidget(
parent=self._root_widget,
position=(20, height - 50),
size=(width, 25),
text=bui.Lstr(resource=f'{self._r}.titleText'),
maxwidth=250,
color=bui.app.ui_v1.title_color,
h_align='center',
v_align='center',
)
bui.buttonwidget(
edit=btn,
button_type='backSmall',
size=(60, 60),
label=bui.charstr(bui.SpecialChar.BACK),
)
v: float = height - 60
v -= spacing
bui.textwidget(
parent=self._root_widget,
position=(15, v),
size=(width - 30, 30),
scale=0.8,
text=bui.Lstr(resource=f'{self._r}.pressAnyButtonText'),
maxwidth=width * 0.95,
color=bui.app.ui_v1.infotextcolor,
h_align='center',
v_align='top',
)
v -= spacing * 1.24
if bui.app.classic.platform == 'android':
bui.textwidget(
parent=self._root_widget,
position=(15, v),
size=(width - 30, 30),
scale=0.46,
text=bui.Lstr(resource=f'{self._r}.androidNoteText'),
maxwidth=width * 0.95,
color=(0.7, 0.9, 0.7, 0.5),
h_align='center',
v_align='top',
)
bs.capture_gamepad_input(bui.WeakCall(self.gamepad_configure_callback))
def __del__(self) -> None:
bs.release_gamepad_input()
[docs]
@override
def get_main_window_state(self) -> bui.MainWindowState:
# Support recreating our window for back/refresh purposes.
cls = type(self)
return bui.BasicMainWindowState(
create_call=lambda transition, origin_widget: cls(
transition=transition, origin_widget=origin_widget
)
)
class _NotConfigurableWindow(bui.MainWindow):
def __init__(
self,
device: bs.InputDevice,
transition: str | None = 'in_right',
origin_widget: bui.Widget | None = None,
) -> None:
width = 700
height = 200
button_width = 80
uiscale = bui.app.ui_v1.uiscale
super().__init__(
root_widget=bui.containerwidget(
scale=(
1.7
if uiscale is bui.UIScale.SMALL
else (1.4 if uiscale is bui.UIScale.MEDIUM else 1.0)
),
size=(width, height),
),
transition=transition,
origin_widget=origin_widget,
)
self.device = device
if device.allows_configuring_in_system_settings:
msg = bui.Lstr(
resource='configureDeviceInSystemSettingsText',
subs=[('${DEVICE}', device.name)],
)
elif device.is_controller_app:
msg = bui.Lstr(
resource='bsRemoteConfigureInAppText',
subs=[
(
'${REMOTE_APP_NAME}',
bui.get_remote_app_name(),
)
],
)
else:
msg = bui.Lstr(
resource='cantConfigureDeviceText',
subs=[('${DEVICE}', device.name)],
)
bui.textwidget(
parent=self._root_widget,
position=(0, height - 80),
size=(width, 25),
text=msg,
scale=0.8,
h_align='center',
v_align='top',
)
btn = bui.buttonwidget(
parent=self._root_widget,
position=((width - button_width) / 2, 20),
size=(button_width, 60),
label=bui.Lstr(resource='okText'),
on_activate_call=self.main_window_back,
)
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
@override
def get_main_window_state(self) -> bui.MainWindowState:
# Support recreating our window for back/refresh purposes.
cls = type(self)
# Pull stuff out of self here; if we do it in the lambda we'll
# keep self alive which we don't want.
device = self.device
return bui.BasicMainWindowState(
create_call=lambda transition, origin_widget: cls(
device=device,
transition=transition,
origin_widget=origin_widget,
)
)
# Docs-generation hack; import some stuff that we likely only forward-declared
# in our actual source code so that docs tools can find it.
from typing import (Coroutine, Any, Literal, Callable,
Generator, Awaitable, Sequence, Self)
import asyncio
from concurrent.futures import Future
from pathlib import Path
from enum import Enum