bauiv1lib.settings.controls

Provides a top level control settings window.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Provides a top level control settings window."""
  4
  5from __future__ import annotations
  6
  7from bauiv1lib.popup import PopupMenu
  8import bascenev1 as bs
  9import bauiv1 as bui
 10
 11
 12class ControlsSettingsWindow(bui.Window):
 13    """Top level control settings window."""
 14
 15    def __init__(
 16        self,
 17        transition: str = 'in_right',
 18        origin_widget: bui.Widget | None = None,
 19    ):
 20        # FIXME: should tidy up here.
 21        # pylint: disable=too-many-statements
 22        # pylint: disable=too-many-branches
 23        # pylint: disable=too-many-locals
 24        # pylint: disable=cyclic-import
 25
 26        self._have_selected_child = False
 27
 28        scale_origin: tuple[float, float] | None
 29
 30        # If they provided an origin-widget, scale up from that.
 31        if origin_widget is not None:
 32            self._transition_out = 'out_scale'
 33            scale_origin = origin_widget.get_screen_space_center()
 34            transition = 'in_scale'
 35        else:
 36            self._transition_out = 'out_right'
 37            scale_origin = None
 38
 39        self._r = 'configControllersWindow'
 40        app = bui.app
 41        assert app.classic is not None
 42
 43        spacing = 50.0
 44        button_width = 350.0
 45        width = 460.0
 46        height = 130.0
 47
 48        space_height = spacing * 0.3
 49
 50        # FIXME: should create vis settings under platform or app-adapter
 51        # to determine whether to show this stuff; not hard code it.
 52
 53        show_gamepads = False
 54        platform = app.classic.platform
 55        subplatform = app.classic.subplatform
 56        non_vr_windows = platform == 'windows' and (
 57            subplatform != 'oculus' or not app.env.vr
 58        )
 59        if platform in ('linux', 'android', 'mac') or non_vr_windows:
 60            show_gamepads = True
 61            height += spacing
 62
 63        show_touch = False
 64        if bs.have_touchscreen_input():
 65            show_touch = True
 66            height += spacing
 67
 68        show_space_1 = False
 69        if show_gamepads or show_touch:
 70            show_space_1 = True
 71            height += space_height
 72
 73        show_keyboard = False
 74        if bs.getinputdevice('Keyboard', '#1', doraise=False) is not None:
 75            show_keyboard = True
 76            height += spacing
 77        show_keyboard_p2 = False if app.env.vr else show_keyboard
 78        if show_keyboard_p2:
 79            height += spacing
 80
 81        show_space_2 = False
 82        if show_keyboard:
 83            show_space_2 = True
 84            height += space_height
 85
 86        if bool(True):
 87            show_remote = True
 88            height += spacing
 89        else:
 90            show_remote = False
 91
 92        # On windows (outside of oculus/vr), show an option to disable xinput.
 93        show_xinput_toggle = False
 94        if platform == 'windows' and not app.env.vr:
 95            show_xinput_toggle = True
 96
 97        # On mac builds, show an option to switch between generic and
 98        # made-for-iOS/Mac systems
 99        # (we can run into problems where devices register as one of each
100        # type otherwise)..
101        show_mac_controller_subsystem = False
102        if platform == 'mac' and bui.is_xcode_build():
103            show_mac_controller_subsystem = True
104
105        if show_mac_controller_subsystem:
106            height += spacing * 1.5
107
108        if show_xinput_toggle:
109            height += spacing
110
111        assert bui.app.classic is not None
112        uiscale = bui.app.ui_v1.uiscale
113        smallscale = 1.7 if show_keyboard else 2.2
114        super().__init__(
115            root_widget=bui.containerwidget(
116                size=(width, height),
117                transition=transition,
118                scale_origin_stack_offset=scale_origin,
119                stack_offset=(
120                    (0, -10) if uiscale is bui.UIScale.SMALL else (0, 0)
121                ),
122                scale=(
123                    smallscale
124                    if uiscale is bui.UIScale.SMALL
125                    else 1.5
126                    if uiscale is bui.UIScale.MEDIUM
127                    else 1.0
128                ),
129            )
130        )
131        self._back_button = btn = bui.buttonwidget(
132            parent=self._root_widget,
133            position=(35, height - 60),
134            size=(140, 65),
135            scale=0.8,
136            text_scale=1.2,
137            autoselect=True,
138            label=bui.Lstr(resource='backText'),
139            button_type='back',
140            on_activate_call=self._back,
141        )
142        bui.containerwidget(edit=self._root_widget, cancel_button=btn)
143
144        # We need these vars to exist even if the buttons don't.
145        self._gamepads_button: bui.Widget | None = None
146        self._touch_button: bui.Widget | None = None
147        self._keyboard_button: bui.Widget | None = None
148        self._keyboard_2_button: bui.Widget | None = None
149        self._idevices_button: bui.Widget | None = None
150
151        bui.textwidget(
152            parent=self._root_widget,
153            position=(0, height - 49),
154            size=(width, 25),
155            text=bui.Lstr(resource=self._r + '.titleText'),
156            color=bui.app.ui_v1.title_color,
157            h_align='center',
158            v_align='top',
159        )
160        bui.buttonwidget(
161            edit=btn,
162            button_type='backSmall',
163            size=(60, 60),
164            label=bui.charstr(bui.SpecialChar.BACK),
165        )
166
167        v = height - 75
168        v -= spacing
169
170        if show_touch:
171            self._touch_button = btn = bui.buttonwidget(
172                parent=self._root_widget,
173                position=((width - button_width) / 2, v),
174                size=(button_width, 43),
175                autoselect=True,
176                label=bui.Lstr(resource=self._r + '.configureTouchText'),
177                on_activate_call=self._do_touchscreen,
178            )
179            if bui.app.ui_v1.use_toolbars:
180                bui.widget(
181                    edit=btn,
182                    right_widget=bui.get_special_widget('party_button'),
183                )
184            if not self._have_selected_child:
185                bui.containerwidget(
186                    edit=self._root_widget, selected_child=self._touch_button
187                )
188                bui.widget(
189                    edit=self._back_button, down_widget=self._touch_button
190                )
191                self._have_selected_child = True
192            v -= spacing
193
194        if show_gamepads:
195            self._gamepads_button = btn = bui.buttonwidget(
196                parent=self._root_widget,
197                position=((width - button_width) / 2 - 7, v),
198                size=(button_width, 43),
199                autoselect=True,
200                label=bui.Lstr(resource=self._r + '.configureControllersText'),
201                on_activate_call=self._do_gamepads,
202            )
203            if bui.app.ui_v1.use_toolbars:
204                bui.widget(
205                    edit=btn,
206                    right_widget=bui.get_special_widget('party_button'),
207                )
208            if not self._have_selected_child:
209                bui.containerwidget(
210                    edit=self._root_widget, selected_child=self._gamepads_button
211                )
212                bui.widget(
213                    edit=self._back_button, down_widget=self._gamepads_button
214                )
215                self._have_selected_child = True
216            v -= spacing
217        else:
218            self._gamepads_button = None
219
220        if show_space_1:
221            v -= space_height
222
223        if show_keyboard:
224            self._keyboard_button = btn = bui.buttonwidget(
225                parent=self._root_widget,
226                position=((width - button_width) / 2 + 5, v),
227                size=(button_width, 43),
228                autoselect=True,
229                label=bui.Lstr(resource=self._r + '.configureKeyboardText'),
230                on_activate_call=self._config_keyboard,
231            )
232            if bui.app.ui_v1.use_toolbars:
233                bui.widget(
234                    edit=btn,
235                    right_widget=bui.get_special_widget('party_button'),
236                )
237            if not self._have_selected_child:
238                bui.containerwidget(
239                    edit=self._root_widget, selected_child=self._keyboard_button
240                )
241                bui.widget(
242                    edit=self._back_button, down_widget=self._keyboard_button
243                )
244                self._have_selected_child = True
245            v -= spacing
246        if show_keyboard_p2:
247            self._keyboard_2_button = bui.buttonwidget(
248                parent=self._root_widget,
249                position=((width - button_width) / 2 - 3, v),
250                size=(button_width, 43),
251                autoselect=True,
252                label=bui.Lstr(resource=self._r + '.configureKeyboard2Text'),
253                on_activate_call=self._config_keyboard2,
254            )
255            v -= spacing
256        if show_space_2:
257            v -= space_height
258        if show_remote:
259            self._idevices_button = btn = bui.buttonwidget(
260                parent=self._root_widget,
261                position=((width - button_width) / 2 - 5, v),
262                size=(button_width, 43),
263                autoselect=True,
264                label=bui.Lstr(resource=self._r + '.configureMobileText'),
265                on_activate_call=self._do_mobile_devices,
266            )
267            if bui.app.ui_v1.use_toolbars:
268                bui.widget(
269                    edit=btn,
270                    right_widget=bui.get_special_widget('party_button'),
271                )
272            if not self._have_selected_child:
273                bui.containerwidget(
274                    edit=self._root_widget, selected_child=self._idevices_button
275                )
276                bui.widget(
277                    edit=self._back_button, down_widget=self._idevices_button
278                )
279                self._have_selected_child = True
280            v -= spacing
281
282        if show_xinput_toggle:
283
284            def do_toggle(value: bool) -> None:
285                bui.screenmessage(
286                    bui.Lstr(resource='settingsWindowAdvanced.mustRestartText'),
287                    color=(1, 1, 0),
288                )
289                bui.getsound('gunCocking').play()
290                bui.set_low_level_config_value('enablexinput', not value)
291
292            bui.checkboxwidget(
293                parent=self._root_widget,
294                position=(100, v + 3),
295                size=(120, 30),
296                value=(not bui.get_low_level_config_value('enablexinput', 1)),
297                maxwidth=200,
298                on_value_change_call=do_toggle,
299                text=bui.Lstr(resource='disableXInputText'),
300                autoselect=True,
301            )
302            bui.textwidget(
303                parent=self._root_widget,
304                position=(width * 0.5, v - 5),
305                size=(0, 0),
306                text=bui.Lstr(resource='disableXInputDescriptionText'),
307                scale=0.5,
308                h_align='center',
309                v_align='center',
310                color=bui.app.ui_v1.infotextcolor,
311                maxwidth=width * 0.8,
312            )
313            v -= spacing
314        if show_mac_controller_subsystem:
315            PopupMenu(
316                parent=self._root_widget,
317                position=(260, v - 10),
318                width=160,
319                button_size=(150, 50),
320                scale=1.5,
321                choices=['Classic', 'MFi', 'Both'],
322                choices_display=[
323                    bui.Lstr(resource='macControllerSubsystemClassicText'),
324                    bui.Lstr(resource='macControllerSubsystemMFiText'),
325                    bui.Lstr(resource='macControllerSubsystemBothText'),
326                ],
327                current_choice=bui.app.config.resolve(
328                    'Mac Controller Subsystem'
329                ),
330                on_value_change_call=self._set_mac_controller_subsystem,
331            )
332            bui.textwidget(
333                parent=self._root_widget,
334                position=(245, v + 13),
335                size=(0, 0),
336                text=bui.Lstr(resource='macControllerSubsystemTitleText'),
337                scale=1.0,
338                h_align='right',
339                v_align='center',
340                color=bui.app.ui_v1.infotextcolor,
341                maxwidth=180,
342            )
343            bui.textwidget(
344                parent=self._root_widget,
345                position=(width * 0.5, v - 20),
346                size=(0, 0),
347                text=bui.Lstr(resource='macControllerSubsystemDescriptionText'),
348                scale=0.5,
349                h_align='center',
350                v_align='center',
351                color=bui.app.ui_v1.infotextcolor,
352                maxwidth=width * 0.8,
353            )
354            v -= spacing * 1.5
355
356        self._restore_state()
357
358    def _set_mac_controller_subsystem(self, val: str) -> None:
359        cfg = bui.app.config
360        cfg['Mac Controller Subsystem'] = val
361        cfg.apply_and_commit()
362
363    def _config_keyboard(self) -> None:
364        # pylint: disable=cyclic-import
365        from bauiv1lib.settings.keyboard import ConfigKeyboardWindow
366
367        self._save_state()
368        bui.containerwidget(edit=self._root_widget, transition='out_left')
369        assert bui.app.classic is not None
370        bui.app.ui_v1.set_main_menu_window(
371            ConfigKeyboardWindow(
372                bs.getinputdevice('Keyboard', '#1')
373            ).get_root_widget()
374        )
375
376    def _config_keyboard2(self) -> None:
377        # pylint: disable=cyclic-import
378        from bauiv1lib.settings.keyboard import ConfigKeyboardWindow
379
380        self._save_state()
381        bui.containerwidget(edit=self._root_widget, transition='out_left')
382        assert bui.app.classic is not None
383        bui.app.ui_v1.set_main_menu_window(
384            ConfigKeyboardWindow(
385                bs.getinputdevice('Keyboard', '#2')
386            ).get_root_widget()
387        )
388
389    def _do_mobile_devices(self) -> None:
390        # pylint: disable=cyclic-import
391        from bauiv1lib.settings.remoteapp import RemoteAppSettingsWindow
392
393        self._save_state()
394        bui.containerwidget(edit=self._root_widget, transition='out_left')
395        assert bui.app.classic is not None
396        bui.app.ui_v1.set_main_menu_window(
397            RemoteAppSettingsWindow().get_root_widget()
398        )
399
400    def _do_gamepads(self) -> None:
401        # pylint: disable=cyclic-import
402        from bauiv1lib.settings.gamepadselect import GamepadSelectWindow
403
404        self._save_state()
405        bui.containerwidget(edit=self._root_widget, transition='out_left')
406        assert bui.app.classic is not None
407        bui.app.ui_v1.set_main_menu_window(
408            GamepadSelectWindow().get_root_widget()
409        )
410
411    def _do_touchscreen(self) -> None:
412        # pylint: disable=cyclic-import
413        from bauiv1lib.settings.touchscreen import TouchscreenSettingsWindow
414
415        self._save_state()
416        bui.containerwidget(edit=self._root_widget, transition='out_left')
417        assert bui.app.classic is not None
418        bui.app.ui_v1.set_main_menu_window(
419            TouchscreenSettingsWindow().get_root_widget()
420        )
421
422    def _save_state(self) -> None:
423        sel = self._root_widget.get_selected_child()
424        if sel == self._gamepads_button:
425            sel_name = 'GamePads'
426        elif sel == self._touch_button:
427            sel_name = 'Touch'
428        elif sel == self._keyboard_button:
429            sel_name = 'Keyboard'
430        elif sel == self._keyboard_2_button:
431            sel_name = 'Keyboard2'
432        elif sel == self._idevices_button:
433            sel_name = 'iDevices'
434        else:
435            sel_name = 'Back'
436        assert bui.app.classic is not None
437        bui.app.ui_v1.window_states[type(self)] = sel_name
438
439    def _restore_state(self) -> None:
440        assert bui.app.classic is not None
441        sel_name = bui.app.ui_v1.window_states.get(type(self))
442        if sel_name == 'GamePads':
443            sel = self._gamepads_button
444        elif sel_name == 'Touch':
445            sel = self._touch_button
446        elif sel_name == 'Keyboard':
447            sel = self._keyboard_button
448        elif sel_name == 'Keyboard2':
449            sel = self._keyboard_2_button
450        elif sel_name == 'iDevices':
451            sel = self._idevices_button
452        elif sel_name == 'Back':
453            sel = self._back_button
454        else:
455            sel = (
456                self._gamepads_button
457                if self._gamepads_button is not None
458                else self._back_button
459            )
460        bui.containerwidget(edit=self._root_widget, selected_child=sel)
461
462    def _back(self) -> None:
463        # pylint: disable=cyclic-import
464        from bauiv1lib.settings.allsettings import AllSettingsWindow
465
466        self._save_state()
467        bui.containerwidget(
468            edit=self._root_widget, transition=self._transition_out
469        )
470        assert bui.app.classic is not None
471        bui.app.ui_v1.set_main_menu_window(
472            AllSettingsWindow(transition='in_left').get_root_widget()
473        )
class ControlsSettingsWindow(bauiv1._uitypes.Window):
 13class ControlsSettingsWindow(bui.Window):
 14    """Top level control settings window."""
 15
 16    def __init__(
 17        self,
 18        transition: str = 'in_right',
 19        origin_widget: bui.Widget | None = None,
 20    ):
 21        # FIXME: should tidy up here.
 22        # pylint: disable=too-many-statements
 23        # pylint: disable=too-many-branches
 24        # pylint: disable=too-many-locals
 25        # pylint: disable=cyclic-import
 26
 27        self._have_selected_child = False
 28
 29        scale_origin: tuple[float, float] | None
 30
 31        # If they provided an origin-widget, scale up from that.
 32        if origin_widget is not None:
 33            self._transition_out = 'out_scale'
 34            scale_origin = origin_widget.get_screen_space_center()
 35            transition = 'in_scale'
 36        else:
 37            self._transition_out = 'out_right'
 38            scale_origin = None
 39
 40        self._r = 'configControllersWindow'
 41        app = bui.app
 42        assert app.classic is not None
 43
 44        spacing = 50.0
 45        button_width = 350.0
 46        width = 460.0
 47        height = 130.0
 48
 49        space_height = spacing * 0.3
 50
 51        # FIXME: should create vis settings under platform or app-adapter
 52        # to determine whether to show this stuff; not hard code it.
 53
 54        show_gamepads = False
 55        platform = app.classic.platform
 56        subplatform = app.classic.subplatform
 57        non_vr_windows = platform == 'windows' and (
 58            subplatform != 'oculus' or not app.env.vr
 59        )
 60        if platform in ('linux', 'android', 'mac') or non_vr_windows:
 61            show_gamepads = True
 62            height += spacing
 63
 64        show_touch = False
 65        if bs.have_touchscreen_input():
 66            show_touch = True
 67            height += spacing
 68
 69        show_space_1 = False
 70        if show_gamepads or show_touch:
 71            show_space_1 = True
 72            height += space_height
 73
 74        show_keyboard = False
 75        if bs.getinputdevice('Keyboard', '#1', doraise=False) is not None:
 76            show_keyboard = True
 77            height += spacing
 78        show_keyboard_p2 = False if app.env.vr else show_keyboard
 79        if show_keyboard_p2:
 80            height += spacing
 81
 82        show_space_2 = False
 83        if show_keyboard:
 84            show_space_2 = True
 85            height += space_height
 86
 87        if bool(True):
 88            show_remote = True
 89            height += spacing
 90        else:
 91            show_remote = False
 92
 93        # On windows (outside of oculus/vr), show an option to disable xinput.
 94        show_xinput_toggle = False
 95        if platform == 'windows' and not app.env.vr:
 96            show_xinput_toggle = True
 97
 98        # On mac builds, show an option to switch between generic and
 99        # made-for-iOS/Mac systems
100        # (we can run into problems where devices register as one of each
101        # type otherwise)..
102        show_mac_controller_subsystem = False
103        if platform == 'mac' and bui.is_xcode_build():
104            show_mac_controller_subsystem = True
105
106        if show_mac_controller_subsystem:
107            height += spacing * 1.5
108
109        if show_xinput_toggle:
110            height += spacing
111
112        assert bui.app.classic is not None
113        uiscale = bui.app.ui_v1.uiscale
114        smallscale = 1.7 if show_keyboard else 2.2
115        super().__init__(
116            root_widget=bui.containerwidget(
117                size=(width, height),
118                transition=transition,
119                scale_origin_stack_offset=scale_origin,
120                stack_offset=(
121                    (0, -10) if uiscale is bui.UIScale.SMALL else (0, 0)
122                ),
123                scale=(
124                    smallscale
125                    if uiscale is bui.UIScale.SMALL
126                    else 1.5
127                    if uiscale is bui.UIScale.MEDIUM
128                    else 1.0
129                ),
130            )
131        )
132        self._back_button = btn = bui.buttonwidget(
133            parent=self._root_widget,
134            position=(35, height - 60),
135            size=(140, 65),
136            scale=0.8,
137            text_scale=1.2,
138            autoselect=True,
139            label=bui.Lstr(resource='backText'),
140            button_type='back',
141            on_activate_call=self._back,
142        )
143        bui.containerwidget(edit=self._root_widget, cancel_button=btn)
144
145        # We need these vars to exist even if the buttons don't.
146        self._gamepads_button: bui.Widget | None = None
147        self._touch_button: bui.Widget | None = None
148        self._keyboard_button: bui.Widget | None = None
149        self._keyboard_2_button: bui.Widget | None = None
150        self._idevices_button: bui.Widget | None = None
151
152        bui.textwidget(
153            parent=self._root_widget,
154            position=(0, height - 49),
155            size=(width, 25),
156            text=bui.Lstr(resource=self._r + '.titleText'),
157            color=bui.app.ui_v1.title_color,
158            h_align='center',
159            v_align='top',
160        )
161        bui.buttonwidget(
162            edit=btn,
163            button_type='backSmall',
164            size=(60, 60),
165            label=bui.charstr(bui.SpecialChar.BACK),
166        )
167
168        v = height - 75
169        v -= spacing
170
171        if show_touch:
172            self._touch_button = btn = bui.buttonwidget(
173                parent=self._root_widget,
174                position=((width - button_width) / 2, v),
175                size=(button_width, 43),
176                autoselect=True,
177                label=bui.Lstr(resource=self._r + '.configureTouchText'),
178                on_activate_call=self._do_touchscreen,
179            )
180            if bui.app.ui_v1.use_toolbars:
181                bui.widget(
182                    edit=btn,
183                    right_widget=bui.get_special_widget('party_button'),
184                )
185            if not self._have_selected_child:
186                bui.containerwidget(
187                    edit=self._root_widget, selected_child=self._touch_button
188                )
189                bui.widget(
190                    edit=self._back_button, down_widget=self._touch_button
191                )
192                self._have_selected_child = True
193            v -= spacing
194
195        if show_gamepads:
196            self._gamepads_button = btn = bui.buttonwidget(
197                parent=self._root_widget,
198                position=((width - button_width) / 2 - 7, v),
199                size=(button_width, 43),
200                autoselect=True,
201                label=bui.Lstr(resource=self._r + '.configureControllersText'),
202                on_activate_call=self._do_gamepads,
203            )
204            if bui.app.ui_v1.use_toolbars:
205                bui.widget(
206                    edit=btn,
207                    right_widget=bui.get_special_widget('party_button'),
208                )
209            if not self._have_selected_child:
210                bui.containerwidget(
211                    edit=self._root_widget, selected_child=self._gamepads_button
212                )
213                bui.widget(
214                    edit=self._back_button, down_widget=self._gamepads_button
215                )
216                self._have_selected_child = True
217            v -= spacing
218        else:
219            self._gamepads_button = None
220
221        if show_space_1:
222            v -= space_height
223
224        if show_keyboard:
225            self._keyboard_button = btn = bui.buttonwidget(
226                parent=self._root_widget,
227                position=((width - button_width) / 2 + 5, v),
228                size=(button_width, 43),
229                autoselect=True,
230                label=bui.Lstr(resource=self._r + '.configureKeyboardText'),
231                on_activate_call=self._config_keyboard,
232            )
233            if bui.app.ui_v1.use_toolbars:
234                bui.widget(
235                    edit=btn,
236                    right_widget=bui.get_special_widget('party_button'),
237                )
238            if not self._have_selected_child:
239                bui.containerwidget(
240                    edit=self._root_widget, selected_child=self._keyboard_button
241                )
242                bui.widget(
243                    edit=self._back_button, down_widget=self._keyboard_button
244                )
245                self._have_selected_child = True
246            v -= spacing
247        if show_keyboard_p2:
248            self._keyboard_2_button = bui.buttonwidget(
249                parent=self._root_widget,
250                position=((width - button_width) / 2 - 3, v),
251                size=(button_width, 43),
252                autoselect=True,
253                label=bui.Lstr(resource=self._r + '.configureKeyboard2Text'),
254                on_activate_call=self._config_keyboard2,
255            )
256            v -= spacing
257        if show_space_2:
258            v -= space_height
259        if show_remote:
260            self._idevices_button = btn = bui.buttonwidget(
261                parent=self._root_widget,
262                position=((width - button_width) / 2 - 5, v),
263                size=(button_width, 43),
264                autoselect=True,
265                label=bui.Lstr(resource=self._r + '.configureMobileText'),
266                on_activate_call=self._do_mobile_devices,
267            )
268            if bui.app.ui_v1.use_toolbars:
269                bui.widget(
270                    edit=btn,
271                    right_widget=bui.get_special_widget('party_button'),
272                )
273            if not self._have_selected_child:
274                bui.containerwidget(
275                    edit=self._root_widget, selected_child=self._idevices_button
276                )
277                bui.widget(
278                    edit=self._back_button, down_widget=self._idevices_button
279                )
280                self._have_selected_child = True
281            v -= spacing
282
283        if show_xinput_toggle:
284
285            def do_toggle(value: bool) -> None:
286                bui.screenmessage(
287                    bui.Lstr(resource='settingsWindowAdvanced.mustRestartText'),
288                    color=(1, 1, 0),
289                )
290                bui.getsound('gunCocking').play()
291                bui.set_low_level_config_value('enablexinput', not value)
292
293            bui.checkboxwidget(
294                parent=self._root_widget,
295                position=(100, v + 3),
296                size=(120, 30),
297                value=(not bui.get_low_level_config_value('enablexinput', 1)),
298                maxwidth=200,
299                on_value_change_call=do_toggle,
300                text=bui.Lstr(resource='disableXInputText'),
301                autoselect=True,
302            )
303            bui.textwidget(
304                parent=self._root_widget,
305                position=(width * 0.5, v - 5),
306                size=(0, 0),
307                text=bui.Lstr(resource='disableXInputDescriptionText'),
308                scale=0.5,
309                h_align='center',
310                v_align='center',
311                color=bui.app.ui_v1.infotextcolor,
312                maxwidth=width * 0.8,
313            )
314            v -= spacing
315        if show_mac_controller_subsystem:
316            PopupMenu(
317                parent=self._root_widget,
318                position=(260, v - 10),
319                width=160,
320                button_size=(150, 50),
321                scale=1.5,
322                choices=['Classic', 'MFi', 'Both'],
323                choices_display=[
324                    bui.Lstr(resource='macControllerSubsystemClassicText'),
325                    bui.Lstr(resource='macControllerSubsystemMFiText'),
326                    bui.Lstr(resource='macControllerSubsystemBothText'),
327                ],
328                current_choice=bui.app.config.resolve(
329                    'Mac Controller Subsystem'
330                ),
331                on_value_change_call=self._set_mac_controller_subsystem,
332            )
333            bui.textwidget(
334                parent=self._root_widget,
335                position=(245, v + 13),
336                size=(0, 0),
337                text=bui.Lstr(resource='macControllerSubsystemTitleText'),
338                scale=1.0,
339                h_align='right',
340                v_align='center',
341                color=bui.app.ui_v1.infotextcolor,
342                maxwidth=180,
343            )
344            bui.textwidget(
345                parent=self._root_widget,
346                position=(width * 0.5, v - 20),
347                size=(0, 0),
348                text=bui.Lstr(resource='macControllerSubsystemDescriptionText'),
349                scale=0.5,
350                h_align='center',
351                v_align='center',
352                color=bui.app.ui_v1.infotextcolor,
353                maxwidth=width * 0.8,
354            )
355            v -= spacing * 1.5
356
357        self._restore_state()
358
359    def _set_mac_controller_subsystem(self, val: str) -> None:
360        cfg = bui.app.config
361        cfg['Mac Controller Subsystem'] = val
362        cfg.apply_and_commit()
363
364    def _config_keyboard(self) -> None:
365        # pylint: disable=cyclic-import
366        from bauiv1lib.settings.keyboard import ConfigKeyboardWindow
367
368        self._save_state()
369        bui.containerwidget(edit=self._root_widget, transition='out_left')
370        assert bui.app.classic is not None
371        bui.app.ui_v1.set_main_menu_window(
372            ConfigKeyboardWindow(
373                bs.getinputdevice('Keyboard', '#1')
374            ).get_root_widget()
375        )
376
377    def _config_keyboard2(self) -> None:
378        # pylint: disable=cyclic-import
379        from bauiv1lib.settings.keyboard import ConfigKeyboardWindow
380
381        self._save_state()
382        bui.containerwidget(edit=self._root_widget, transition='out_left')
383        assert bui.app.classic is not None
384        bui.app.ui_v1.set_main_menu_window(
385            ConfigKeyboardWindow(
386                bs.getinputdevice('Keyboard', '#2')
387            ).get_root_widget()
388        )
389
390    def _do_mobile_devices(self) -> None:
391        # pylint: disable=cyclic-import
392        from bauiv1lib.settings.remoteapp import RemoteAppSettingsWindow
393
394        self._save_state()
395        bui.containerwidget(edit=self._root_widget, transition='out_left')
396        assert bui.app.classic is not None
397        bui.app.ui_v1.set_main_menu_window(
398            RemoteAppSettingsWindow().get_root_widget()
399        )
400
401    def _do_gamepads(self) -> None:
402        # pylint: disable=cyclic-import
403        from bauiv1lib.settings.gamepadselect import GamepadSelectWindow
404
405        self._save_state()
406        bui.containerwidget(edit=self._root_widget, transition='out_left')
407        assert bui.app.classic is not None
408        bui.app.ui_v1.set_main_menu_window(
409            GamepadSelectWindow().get_root_widget()
410        )
411
412    def _do_touchscreen(self) -> None:
413        # pylint: disable=cyclic-import
414        from bauiv1lib.settings.touchscreen import TouchscreenSettingsWindow
415
416        self._save_state()
417        bui.containerwidget(edit=self._root_widget, transition='out_left')
418        assert bui.app.classic is not None
419        bui.app.ui_v1.set_main_menu_window(
420            TouchscreenSettingsWindow().get_root_widget()
421        )
422
423    def _save_state(self) -> None:
424        sel = self._root_widget.get_selected_child()
425        if sel == self._gamepads_button:
426            sel_name = 'GamePads'
427        elif sel == self._touch_button:
428            sel_name = 'Touch'
429        elif sel == self._keyboard_button:
430            sel_name = 'Keyboard'
431        elif sel == self._keyboard_2_button:
432            sel_name = 'Keyboard2'
433        elif sel == self._idevices_button:
434            sel_name = 'iDevices'
435        else:
436            sel_name = 'Back'
437        assert bui.app.classic is not None
438        bui.app.ui_v1.window_states[type(self)] = sel_name
439
440    def _restore_state(self) -> None:
441        assert bui.app.classic is not None
442        sel_name = bui.app.ui_v1.window_states.get(type(self))
443        if sel_name == 'GamePads':
444            sel = self._gamepads_button
445        elif sel_name == 'Touch':
446            sel = self._touch_button
447        elif sel_name == 'Keyboard':
448            sel = self._keyboard_button
449        elif sel_name == 'Keyboard2':
450            sel = self._keyboard_2_button
451        elif sel_name == 'iDevices':
452            sel = self._idevices_button
453        elif sel_name == 'Back':
454            sel = self._back_button
455        else:
456            sel = (
457                self._gamepads_button
458                if self._gamepads_button is not None
459                else self._back_button
460            )
461        bui.containerwidget(edit=self._root_widget, selected_child=sel)
462
463    def _back(self) -> None:
464        # pylint: disable=cyclic-import
465        from bauiv1lib.settings.allsettings import AllSettingsWindow
466
467        self._save_state()
468        bui.containerwidget(
469            edit=self._root_widget, transition=self._transition_out
470        )
471        assert bui.app.classic is not None
472        bui.app.ui_v1.set_main_menu_window(
473            AllSettingsWindow(transition='in_left').get_root_widget()
474        )

Top level control settings window.

ControlsSettingsWindow( transition: str = 'in_right', origin_widget: _bauiv1.Widget | None = None)
 16    def __init__(
 17        self,
 18        transition: str = 'in_right',
 19        origin_widget: bui.Widget | None = None,
 20    ):
 21        # FIXME: should tidy up here.
 22        # pylint: disable=too-many-statements
 23        # pylint: disable=too-many-branches
 24        # pylint: disable=too-many-locals
 25        # pylint: disable=cyclic-import
 26
 27        self._have_selected_child = False
 28
 29        scale_origin: tuple[float, float] | None
 30
 31        # If they provided an origin-widget, scale up from that.
 32        if origin_widget is not None:
 33            self._transition_out = 'out_scale'
 34            scale_origin = origin_widget.get_screen_space_center()
 35            transition = 'in_scale'
 36        else:
 37            self._transition_out = 'out_right'
 38            scale_origin = None
 39
 40        self._r = 'configControllersWindow'
 41        app = bui.app
 42        assert app.classic is not None
 43
 44        spacing = 50.0
 45        button_width = 350.0
 46        width = 460.0
 47        height = 130.0
 48
 49        space_height = spacing * 0.3
 50
 51        # FIXME: should create vis settings under platform or app-adapter
 52        # to determine whether to show this stuff; not hard code it.
 53
 54        show_gamepads = False
 55        platform = app.classic.platform
 56        subplatform = app.classic.subplatform
 57        non_vr_windows = platform == 'windows' and (
 58            subplatform != 'oculus' or not app.env.vr
 59        )
 60        if platform in ('linux', 'android', 'mac') or non_vr_windows:
 61            show_gamepads = True
 62            height += spacing
 63
 64        show_touch = False
 65        if bs.have_touchscreen_input():
 66            show_touch = True
 67            height += spacing
 68
 69        show_space_1 = False
 70        if show_gamepads or show_touch:
 71            show_space_1 = True
 72            height += space_height
 73
 74        show_keyboard = False
 75        if bs.getinputdevice('Keyboard', '#1', doraise=False) is not None:
 76            show_keyboard = True
 77            height += spacing
 78        show_keyboard_p2 = False if app.env.vr else show_keyboard
 79        if show_keyboard_p2:
 80            height += spacing
 81
 82        show_space_2 = False
 83        if show_keyboard:
 84            show_space_2 = True
 85            height += space_height
 86
 87        if bool(True):
 88            show_remote = True
 89            height += spacing
 90        else:
 91            show_remote = False
 92
 93        # On windows (outside of oculus/vr), show an option to disable xinput.
 94        show_xinput_toggle = False
 95        if platform == 'windows' and not app.env.vr:
 96            show_xinput_toggle = True
 97
 98        # On mac builds, show an option to switch between generic and
 99        # made-for-iOS/Mac systems
100        # (we can run into problems where devices register as one of each
101        # type otherwise)..
102        show_mac_controller_subsystem = False
103        if platform == 'mac' and bui.is_xcode_build():
104            show_mac_controller_subsystem = True
105
106        if show_mac_controller_subsystem:
107            height += spacing * 1.5
108
109        if show_xinput_toggle:
110            height += spacing
111
112        assert bui.app.classic is not None
113        uiscale = bui.app.ui_v1.uiscale
114        smallscale = 1.7 if show_keyboard else 2.2
115        super().__init__(
116            root_widget=bui.containerwidget(
117                size=(width, height),
118                transition=transition,
119                scale_origin_stack_offset=scale_origin,
120                stack_offset=(
121                    (0, -10) if uiscale is bui.UIScale.SMALL else (0, 0)
122                ),
123                scale=(
124                    smallscale
125                    if uiscale is bui.UIScale.SMALL
126                    else 1.5
127                    if uiscale is bui.UIScale.MEDIUM
128                    else 1.0
129                ),
130            )
131        )
132        self._back_button = btn = bui.buttonwidget(
133            parent=self._root_widget,
134            position=(35, height - 60),
135            size=(140, 65),
136            scale=0.8,
137            text_scale=1.2,
138            autoselect=True,
139            label=bui.Lstr(resource='backText'),
140            button_type='back',
141            on_activate_call=self._back,
142        )
143        bui.containerwidget(edit=self._root_widget, cancel_button=btn)
144
145        # We need these vars to exist even if the buttons don't.
146        self._gamepads_button: bui.Widget | None = None
147        self._touch_button: bui.Widget | None = None
148        self._keyboard_button: bui.Widget | None = None
149        self._keyboard_2_button: bui.Widget | None = None
150        self._idevices_button: bui.Widget | None = None
151
152        bui.textwidget(
153            parent=self._root_widget,
154            position=(0, height - 49),
155            size=(width, 25),
156            text=bui.Lstr(resource=self._r + '.titleText'),
157            color=bui.app.ui_v1.title_color,
158            h_align='center',
159            v_align='top',
160        )
161        bui.buttonwidget(
162            edit=btn,
163            button_type='backSmall',
164            size=(60, 60),
165            label=bui.charstr(bui.SpecialChar.BACK),
166        )
167
168        v = height - 75
169        v -= spacing
170
171        if show_touch:
172            self._touch_button = btn = bui.buttonwidget(
173                parent=self._root_widget,
174                position=((width - button_width) / 2, v),
175                size=(button_width, 43),
176                autoselect=True,
177                label=bui.Lstr(resource=self._r + '.configureTouchText'),
178                on_activate_call=self._do_touchscreen,
179            )
180            if bui.app.ui_v1.use_toolbars:
181                bui.widget(
182                    edit=btn,
183                    right_widget=bui.get_special_widget('party_button'),
184                )
185            if not self._have_selected_child:
186                bui.containerwidget(
187                    edit=self._root_widget, selected_child=self._touch_button
188                )
189                bui.widget(
190                    edit=self._back_button, down_widget=self._touch_button
191                )
192                self._have_selected_child = True
193            v -= spacing
194
195        if show_gamepads:
196            self._gamepads_button = btn = bui.buttonwidget(
197                parent=self._root_widget,
198                position=((width - button_width) / 2 - 7, v),
199                size=(button_width, 43),
200                autoselect=True,
201                label=bui.Lstr(resource=self._r + '.configureControllersText'),
202                on_activate_call=self._do_gamepads,
203            )
204            if bui.app.ui_v1.use_toolbars:
205                bui.widget(
206                    edit=btn,
207                    right_widget=bui.get_special_widget('party_button'),
208                )
209            if not self._have_selected_child:
210                bui.containerwidget(
211                    edit=self._root_widget, selected_child=self._gamepads_button
212                )
213                bui.widget(
214                    edit=self._back_button, down_widget=self._gamepads_button
215                )
216                self._have_selected_child = True
217            v -= spacing
218        else:
219            self._gamepads_button = None
220
221        if show_space_1:
222            v -= space_height
223
224        if show_keyboard:
225            self._keyboard_button = btn = bui.buttonwidget(
226                parent=self._root_widget,
227                position=((width - button_width) / 2 + 5, v),
228                size=(button_width, 43),
229                autoselect=True,
230                label=bui.Lstr(resource=self._r + '.configureKeyboardText'),
231                on_activate_call=self._config_keyboard,
232            )
233            if bui.app.ui_v1.use_toolbars:
234                bui.widget(
235                    edit=btn,
236                    right_widget=bui.get_special_widget('party_button'),
237                )
238            if not self._have_selected_child:
239                bui.containerwidget(
240                    edit=self._root_widget, selected_child=self._keyboard_button
241                )
242                bui.widget(
243                    edit=self._back_button, down_widget=self._keyboard_button
244                )
245                self._have_selected_child = True
246            v -= spacing
247        if show_keyboard_p2:
248            self._keyboard_2_button = bui.buttonwidget(
249                parent=self._root_widget,
250                position=((width - button_width) / 2 - 3, v),
251                size=(button_width, 43),
252                autoselect=True,
253                label=bui.Lstr(resource=self._r + '.configureKeyboard2Text'),
254                on_activate_call=self._config_keyboard2,
255            )
256            v -= spacing
257        if show_space_2:
258            v -= space_height
259        if show_remote:
260            self._idevices_button = btn = bui.buttonwidget(
261                parent=self._root_widget,
262                position=((width - button_width) / 2 - 5, v),
263                size=(button_width, 43),
264                autoselect=True,
265                label=bui.Lstr(resource=self._r + '.configureMobileText'),
266                on_activate_call=self._do_mobile_devices,
267            )
268            if bui.app.ui_v1.use_toolbars:
269                bui.widget(
270                    edit=btn,
271                    right_widget=bui.get_special_widget('party_button'),
272                )
273            if not self._have_selected_child:
274                bui.containerwidget(
275                    edit=self._root_widget, selected_child=self._idevices_button
276                )
277                bui.widget(
278                    edit=self._back_button, down_widget=self._idevices_button
279                )
280                self._have_selected_child = True
281            v -= spacing
282
283        if show_xinput_toggle:
284
285            def do_toggle(value: bool) -> None:
286                bui.screenmessage(
287                    bui.Lstr(resource='settingsWindowAdvanced.mustRestartText'),
288                    color=(1, 1, 0),
289                )
290                bui.getsound('gunCocking').play()
291                bui.set_low_level_config_value('enablexinput', not value)
292
293            bui.checkboxwidget(
294                parent=self._root_widget,
295                position=(100, v + 3),
296                size=(120, 30),
297                value=(not bui.get_low_level_config_value('enablexinput', 1)),
298                maxwidth=200,
299                on_value_change_call=do_toggle,
300                text=bui.Lstr(resource='disableXInputText'),
301                autoselect=True,
302            )
303            bui.textwidget(
304                parent=self._root_widget,
305                position=(width * 0.5, v - 5),
306                size=(0, 0),
307                text=bui.Lstr(resource='disableXInputDescriptionText'),
308                scale=0.5,
309                h_align='center',
310                v_align='center',
311                color=bui.app.ui_v1.infotextcolor,
312                maxwidth=width * 0.8,
313            )
314            v -= spacing
315        if show_mac_controller_subsystem:
316            PopupMenu(
317                parent=self._root_widget,
318                position=(260, v - 10),
319                width=160,
320                button_size=(150, 50),
321                scale=1.5,
322                choices=['Classic', 'MFi', 'Both'],
323                choices_display=[
324                    bui.Lstr(resource='macControllerSubsystemClassicText'),
325                    bui.Lstr(resource='macControllerSubsystemMFiText'),
326                    bui.Lstr(resource='macControllerSubsystemBothText'),
327                ],
328                current_choice=bui.app.config.resolve(
329                    'Mac Controller Subsystem'
330                ),
331                on_value_change_call=self._set_mac_controller_subsystem,
332            )
333            bui.textwidget(
334                parent=self._root_widget,
335                position=(245, v + 13),
336                size=(0, 0),
337                text=bui.Lstr(resource='macControllerSubsystemTitleText'),
338                scale=1.0,
339                h_align='right',
340                v_align='center',
341                color=bui.app.ui_v1.infotextcolor,
342                maxwidth=180,
343            )
344            bui.textwidget(
345                parent=self._root_widget,
346                position=(width * 0.5, v - 20),
347                size=(0, 0),
348                text=bui.Lstr(resource='macControllerSubsystemDescriptionText'),
349                scale=0.5,
350                h_align='center',
351                v_align='center',
352                color=bui.app.ui_v1.infotextcolor,
353                maxwidth=width * 0.8,
354            )
355            v -= spacing * 1.5
356
357        self._restore_state()
Inherited Members
bauiv1._uitypes.Window
get_root_widget