bauiv1lib.settings.gamepadselect

Settings UI related to gamepad functionality.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Settings UI related to gamepad functionality."""
  4
  5from __future__ import annotations
  6
  7import logging
  8from typing import TYPE_CHECKING, override
  9
 10import bascenev1 as bs
 11import bauiv1 as bui
 12
 13if TYPE_CHECKING:
 14    from typing import Any
 15
 16
 17def gamepad_configure_callback(event: dict[str, Any]) -> None:
 18    """Respond to a gamepad button press during config selection."""
 19    from bauiv1lib.settings.gamepad import GamepadSettingsWindow
 20
 21    # Ignore all but button-presses.
 22    if event['type'] not in ['BUTTONDOWN', 'HATMOTION']:
 23        return
 24    bs.release_gamepad_input()
 25
 26    if bool(True):
 27        bui.screenmessage('UNDER CONSTRUCTION')
 28        return
 29
 30    assert bui.app.classic is not None
 31    try:
 32        bui.app.ui_v1.clear_main_window()
 33    except Exception:
 34        logging.exception('Error transitioning out main_menu_window.')
 35    bui.getsound('activateBeep').play()
 36    bui.getsound('swish').play()
 37    device = event['input_device']
 38    assert isinstance(device, bs.InputDevice)
 39    if device.allows_configuring:
 40        bui.app.ui_v1.set_main_window(
 41            GamepadSettingsWindow(device), from_window=None
 42        )
 43    else:
 44        width = 700
 45        height = 200
 46        button_width = 80
 47        uiscale = bui.app.ui_v1.uiscale
 48
 49        class _Window(bui.MainWindow):
 50            def __init__(self) -> None:
 51                super().__init__(
 52                    root_widget=bui.containerwidget(
 53                        scale=(
 54                            1.7
 55                            if uiscale is bui.UIScale.SMALL
 56                            else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
 57                        ),
 58                        size=(width, height),
 59                    ),
 60                    transition='in_right',
 61                    origin_widget=None,
 62                )
 63
 64        win = _Window()
 65        dlg = win.get_root_widget()
 66
 67        bui.app.ui_v1.set_main_window(win, from_window=None)
 68
 69        if device.allows_configuring_in_system_settings:
 70            msg = bui.Lstr(
 71                resource='configureDeviceInSystemSettingsText',
 72                subs=[('${DEVICE}', device.name)],
 73            )
 74        elif device.is_controller_app:
 75            msg = bui.Lstr(
 76                resource='bsRemoteConfigureInAppText',
 77                subs=[('${REMOTE_APP_NAME}', bui.get_remote_app_name())],
 78            )
 79        else:
 80            msg = bui.Lstr(
 81                resource='cantConfigureDeviceText',
 82                subs=[('${DEVICE}', device.name)],
 83            )
 84        bui.textwidget(
 85            parent=dlg,
 86            position=(0, height - 80),
 87            size=(width, 25),
 88            text=msg,
 89            scale=0.8,
 90            h_align='center',
 91            v_align='top',
 92        )
 93
 94        def _ok() -> None:
 95            from bauiv1lib.settings import controls
 96
 97            # no-op if our underlying widget is dead or on its way out.
 98            if not dlg or dlg.transitioning_out:
 99                return
100
101            bui.containerwidget(edit=dlg, transition='out_right')
102            assert bui.app.classic is not None
103            bui.app.ui_v1.set_main_window(
104                controls.ControlsSettingsWindow(transition='in_left'),
105                from_window=win,
106                is_back=True,
107            )
108
109        bui.buttonwidget(
110            parent=dlg,
111            position=((width - button_width) / 2, 20),
112            size=(button_width, 60),
113            label=bui.Lstr(resource='okText'),
114            on_activate_call=_ok,
115        )
116
117
118class GamepadSelectWindow(bui.MainWindow):
119    """Window for selecting a gamepad to configure."""
120
121    def __init__(
122        self,
123        transition: str | None = 'in_right',
124        origin_widget: bui.Widget | None = None,
125    ) -> None:
126        from typing import cast
127
128        width = 480
129        height = 170
130        spacing = 40
131        self._r = 'configGamepadSelectWindow'
132
133        assert bui.app.classic is not None
134        uiscale = bui.app.ui_v1.uiscale
135        super().__init__(
136            root_widget=bui.containerwidget(
137                scale=(
138                    2.3
139                    if uiscale is bui.UIScale.SMALL
140                    else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
141                ),
142                size=(width, height),
143            ),
144            transition=transition,
145            origin_widget=origin_widget,
146        )
147
148        btn = bui.buttonwidget(
149            parent=self._root_widget,
150            position=(20, height - 60),
151            size=(130, 60),
152            label=bui.Lstr(resource='backText'),
153            button_type='back',
154            scale=0.8,
155            on_activate_call=self.main_window_back,
156        )
157
158        # Let's not have anything selected by default; its misleading looking
159        # for the controller getting configured.
160        bui.containerwidget(
161            edit=self._root_widget,
162            cancel_button=btn,
163            selected_child=cast(bui.Widget, 0),
164        )
165        bui.textwidget(
166            parent=self._root_widget,
167            position=(20, height - 50),
168            size=(width, 25),
169            text=bui.Lstr(resource=f'{self._r}.titleText'),
170            maxwidth=250,
171            color=bui.app.ui_v1.title_color,
172            h_align='center',
173            v_align='center',
174        )
175
176        bui.buttonwidget(
177            edit=btn,
178            button_type='backSmall',
179            size=(60, 60),
180            label=bui.charstr(bui.SpecialChar.BACK),
181        )
182
183        v: float = height - 60
184        v -= spacing
185        bui.textwidget(
186            parent=self._root_widget,
187            position=(15, v),
188            size=(width - 30, 30),
189            scale=0.8,
190            text=bui.Lstr(resource=f'{self._r}.pressAnyButtonText'),
191            maxwidth=width * 0.95,
192            color=bui.app.ui_v1.infotextcolor,
193            h_align='center',
194            v_align='top',
195        )
196        v -= spacing * 1.24
197        if bui.app.classic.platform == 'android':
198            bui.textwidget(
199                parent=self._root_widget,
200                position=(15, v),
201                size=(width - 30, 30),
202                scale=0.46,
203                text=bui.Lstr(resource=f'{self._r}.androidNoteText'),
204                maxwidth=width * 0.95,
205                color=(0.7, 0.9, 0.7, 0.5),
206                h_align='center',
207                v_align='top',
208            )
209
210        bs.capture_gamepad_input(gamepad_configure_callback)
211
212    @override
213    def get_main_window_state(self) -> bui.MainWindowState:
214        # Support recreating our window for back/refresh purposes.
215        cls = type(self)
216        return bui.BasicMainWindowState(
217            create_call=lambda transition, origin_widget: cls(
218                transition=transition, origin_widget=origin_widget
219            )
220        )
221
222    @override
223    def on_main_window_close(self) -> None:
224        bs.release_gamepad_input()
def gamepad_configure_callback(event: dict[str, typing.Any]) -> None:
 18def gamepad_configure_callback(event: dict[str, Any]) -> None:
 19    """Respond to a gamepad button press during config selection."""
 20    from bauiv1lib.settings.gamepad import GamepadSettingsWindow
 21
 22    # Ignore all but button-presses.
 23    if event['type'] not in ['BUTTONDOWN', 'HATMOTION']:
 24        return
 25    bs.release_gamepad_input()
 26
 27    if bool(True):
 28        bui.screenmessage('UNDER CONSTRUCTION')
 29        return
 30
 31    assert bui.app.classic is not None
 32    try:
 33        bui.app.ui_v1.clear_main_window()
 34    except Exception:
 35        logging.exception('Error transitioning out main_menu_window.')
 36    bui.getsound('activateBeep').play()
 37    bui.getsound('swish').play()
 38    device = event['input_device']
 39    assert isinstance(device, bs.InputDevice)
 40    if device.allows_configuring:
 41        bui.app.ui_v1.set_main_window(
 42            GamepadSettingsWindow(device), from_window=None
 43        )
 44    else:
 45        width = 700
 46        height = 200
 47        button_width = 80
 48        uiscale = bui.app.ui_v1.uiscale
 49
 50        class _Window(bui.MainWindow):
 51            def __init__(self) -> None:
 52                super().__init__(
 53                    root_widget=bui.containerwidget(
 54                        scale=(
 55                            1.7
 56                            if uiscale is bui.UIScale.SMALL
 57                            else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
 58                        ),
 59                        size=(width, height),
 60                    ),
 61                    transition='in_right',
 62                    origin_widget=None,
 63                )
 64
 65        win = _Window()
 66        dlg = win.get_root_widget()
 67
 68        bui.app.ui_v1.set_main_window(win, from_window=None)
 69
 70        if device.allows_configuring_in_system_settings:
 71            msg = bui.Lstr(
 72                resource='configureDeviceInSystemSettingsText',
 73                subs=[('${DEVICE}', device.name)],
 74            )
 75        elif device.is_controller_app:
 76            msg = bui.Lstr(
 77                resource='bsRemoteConfigureInAppText',
 78                subs=[('${REMOTE_APP_NAME}', bui.get_remote_app_name())],
 79            )
 80        else:
 81            msg = bui.Lstr(
 82                resource='cantConfigureDeviceText',
 83                subs=[('${DEVICE}', device.name)],
 84            )
 85        bui.textwidget(
 86            parent=dlg,
 87            position=(0, height - 80),
 88            size=(width, 25),
 89            text=msg,
 90            scale=0.8,
 91            h_align='center',
 92            v_align='top',
 93        )
 94
 95        def _ok() -> None:
 96            from bauiv1lib.settings import controls
 97
 98            # no-op if our underlying widget is dead or on its way out.
 99            if not dlg or dlg.transitioning_out:
100                return
101
102            bui.containerwidget(edit=dlg, transition='out_right')
103            assert bui.app.classic is not None
104            bui.app.ui_v1.set_main_window(
105                controls.ControlsSettingsWindow(transition='in_left'),
106                from_window=win,
107                is_back=True,
108            )
109
110        bui.buttonwidget(
111            parent=dlg,
112            position=((width - button_width) / 2, 20),
113            size=(button_width, 60),
114            label=bui.Lstr(resource='okText'),
115            on_activate_call=_ok,
116        )

Respond to a gamepad button press during config selection.

class GamepadSelectWindow(bauiv1._uitypes.MainWindow):
119class GamepadSelectWindow(bui.MainWindow):
120    """Window for selecting a gamepad to configure."""
121
122    def __init__(
123        self,
124        transition: str | None = 'in_right',
125        origin_widget: bui.Widget | None = None,
126    ) -> None:
127        from typing import cast
128
129        width = 480
130        height = 170
131        spacing = 40
132        self._r = 'configGamepadSelectWindow'
133
134        assert bui.app.classic is not None
135        uiscale = bui.app.ui_v1.uiscale
136        super().__init__(
137            root_widget=bui.containerwidget(
138                scale=(
139                    2.3
140                    if uiscale is bui.UIScale.SMALL
141                    else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
142                ),
143                size=(width, height),
144            ),
145            transition=transition,
146            origin_widget=origin_widget,
147        )
148
149        btn = bui.buttonwidget(
150            parent=self._root_widget,
151            position=(20, height - 60),
152            size=(130, 60),
153            label=bui.Lstr(resource='backText'),
154            button_type='back',
155            scale=0.8,
156            on_activate_call=self.main_window_back,
157        )
158
159        # Let's not have anything selected by default; its misleading looking
160        # for the controller getting configured.
161        bui.containerwidget(
162            edit=self._root_widget,
163            cancel_button=btn,
164            selected_child=cast(bui.Widget, 0),
165        )
166        bui.textwidget(
167            parent=self._root_widget,
168            position=(20, height - 50),
169            size=(width, 25),
170            text=bui.Lstr(resource=f'{self._r}.titleText'),
171            maxwidth=250,
172            color=bui.app.ui_v1.title_color,
173            h_align='center',
174            v_align='center',
175        )
176
177        bui.buttonwidget(
178            edit=btn,
179            button_type='backSmall',
180            size=(60, 60),
181            label=bui.charstr(bui.SpecialChar.BACK),
182        )
183
184        v: float = height - 60
185        v -= spacing
186        bui.textwidget(
187            parent=self._root_widget,
188            position=(15, v),
189            size=(width - 30, 30),
190            scale=0.8,
191            text=bui.Lstr(resource=f'{self._r}.pressAnyButtonText'),
192            maxwidth=width * 0.95,
193            color=bui.app.ui_v1.infotextcolor,
194            h_align='center',
195            v_align='top',
196        )
197        v -= spacing * 1.24
198        if bui.app.classic.platform == 'android':
199            bui.textwidget(
200                parent=self._root_widget,
201                position=(15, v),
202                size=(width - 30, 30),
203                scale=0.46,
204                text=bui.Lstr(resource=f'{self._r}.androidNoteText'),
205                maxwidth=width * 0.95,
206                color=(0.7, 0.9, 0.7, 0.5),
207                h_align='center',
208                v_align='top',
209            )
210
211        bs.capture_gamepad_input(gamepad_configure_callback)
212
213    @override
214    def get_main_window_state(self) -> bui.MainWindowState:
215        # Support recreating our window for back/refresh purposes.
216        cls = type(self)
217        return bui.BasicMainWindowState(
218            create_call=lambda transition, origin_widget: cls(
219                transition=transition, origin_widget=origin_widget
220            )
221        )
222
223    @override
224    def on_main_window_close(self) -> None:
225        bs.release_gamepad_input()

Window for selecting a gamepad to configure.

GamepadSelectWindow( transition: str | None = 'in_right', origin_widget: _bauiv1.Widget | None = None)
122    def __init__(
123        self,
124        transition: str | None = 'in_right',
125        origin_widget: bui.Widget | None = None,
126    ) -> None:
127        from typing import cast
128
129        width = 480
130        height = 170
131        spacing = 40
132        self._r = 'configGamepadSelectWindow'
133
134        assert bui.app.classic is not None
135        uiscale = bui.app.ui_v1.uiscale
136        super().__init__(
137            root_widget=bui.containerwidget(
138                scale=(
139                    2.3
140                    if uiscale is bui.UIScale.SMALL
141                    else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
142                ),
143                size=(width, height),
144            ),
145            transition=transition,
146            origin_widget=origin_widget,
147        )
148
149        btn = bui.buttonwidget(
150            parent=self._root_widget,
151            position=(20, height - 60),
152            size=(130, 60),
153            label=bui.Lstr(resource='backText'),
154            button_type='back',
155            scale=0.8,
156            on_activate_call=self.main_window_back,
157        )
158
159        # Let's not have anything selected by default; its misleading looking
160        # for the controller getting configured.
161        bui.containerwidget(
162            edit=self._root_widget,
163            cancel_button=btn,
164            selected_child=cast(bui.Widget, 0),
165        )
166        bui.textwidget(
167            parent=self._root_widget,
168            position=(20, height - 50),
169            size=(width, 25),
170            text=bui.Lstr(resource=f'{self._r}.titleText'),
171            maxwidth=250,
172            color=bui.app.ui_v1.title_color,
173            h_align='center',
174            v_align='center',
175        )
176
177        bui.buttonwidget(
178            edit=btn,
179            button_type='backSmall',
180            size=(60, 60),
181            label=bui.charstr(bui.SpecialChar.BACK),
182        )
183
184        v: float = height - 60
185        v -= spacing
186        bui.textwidget(
187            parent=self._root_widget,
188            position=(15, v),
189            size=(width - 30, 30),
190            scale=0.8,
191            text=bui.Lstr(resource=f'{self._r}.pressAnyButtonText'),
192            maxwidth=width * 0.95,
193            color=bui.app.ui_v1.infotextcolor,
194            h_align='center',
195            v_align='top',
196        )
197        v -= spacing * 1.24
198        if bui.app.classic.platform == 'android':
199            bui.textwidget(
200                parent=self._root_widget,
201                position=(15, v),
202                size=(width - 30, 30),
203                scale=0.46,
204                text=bui.Lstr(resource=f'{self._r}.androidNoteText'),
205                maxwidth=width * 0.95,
206                color=(0.7, 0.9, 0.7, 0.5),
207                h_align='center',
208                v_align='top',
209            )
210
211        bs.capture_gamepad_input(gamepad_configure_callback)

Create a MainWindow given a root widget and transition info.

Automatically handles in and out transitions on the provided widget, so there is no need to set transitions when creating it.

@override
def get_main_window_state(self) -> bauiv1.MainWindowState:
213    @override
214    def get_main_window_state(self) -> bui.MainWindowState:
215        # Support recreating our window for back/refresh purposes.
216        cls = type(self)
217        return bui.BasicMainWindowState(
218            create_call=lambda transition, origin_widget: cls(
219                transition=transition, origin_widget=origin_widget
220            )
221        )

Return a WindowState to recreate this window, if supported.

@override
def on_main_window_close(self) -> None:
223    @override
224    def on_main_window_close(self) -> None:
225        bs.release_gamepad_input()

Called before transitioning out a main window.

A good opportunity to save window state/etc.

Inherited Members
bauiv1._uitypes.MainWindow
main_window_back_state
main_window_close
can_change_main_window
main_window_back
main_window_replace
bauiv1._uitypes.Window
get_root_widget