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