bauiv1lib.settings.keyboard
Keyboard settings related UI functionality.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Keyboard settings related UI functionality.""" 4 5from __future__ import annotations 6 7from typing import TYPE_CHECKING 8 9from bauiv1lib.popup import PopupMenuWindow 10import bauiv1 as bui 11import bascenev1 as bs 12 13if TYPE_CHECKING: 14 from typing import Any 15 from bauiv1lib.popup import PopupWindow 16 17 18class ConfigKeyboardWindow(bui.Window): 19 """Window for configuring keyboards.""" 20 21 def __init__(self, c: bs.InputDevice, transition: str = 'in_right'): 22 self._r = 'configKeyboardWindow' 23 self._input = c 24 self._name = self._input.name 25 self._unique_id = self._input.unique_identifier 26 dname_raw = self._name 27 if self._unique_id != '#1': 28 dname_raw += ' ' + self._unique_id.replace('#', 'P') 29 self._displayname = bui.Lstr(translate=('inputDeviceNames', dname_raw)) 30 self._width = 700 31 if self._unique_id != '#1': 32 self._height = 480 33 else: 34 self._height = 375 35 self._spacing = 40 36 assert bui.app.classic is not None 37 uiscale = bui.app.ui_v1.uiscale 38 super().__init__( 39 root_widget=bui.containerwidget( 40 size=(self._width, self._height), 41 scale=( 42 1.6 43 if uiscale is bui.UIScale.SMALL 44 else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0 45 ), 46 stack_offset=(0, 5) if uiscale is bui.UIScale.SMALL else (0, 0), 47 transition=transition, 48 ) 49 ) 50 51 self._settings: dict[str, int] = {} 52 self._get_config_mapping() 53 54 self._rebuild_ui() 55 56 def _get_config_mapping(self, default: bool = False) -> None: 57 for button in [ 58 'buttonJump', 59 'buttonPunch', 60 'buttonBomb', 61 'buttonPickUp', 62 'buttonStart', 63 'buttonStart2', 64 'buttonUp', 65 'buttonDown', 66 'buttonLeft', 67 'buttonRight', 68 ]: 69 assert bui.app.classic is not None 70 self._settings[button] = ( 71 bui.app.classic.get_input_device_mapped_value( 72 self._input, button, default 73 ) 74 ) 75 76 def _rebuild_ui(self, is_reset: bool = False) -> None: 77 assert bui.app.classic is not None 78 79 for widget in self._root_widget.get_children(): 80 widget.delete() 81 82 # b_off = 0 if self._unique_id != '#1' else 9 83 cancel_button = bui.buttonwidget( 84 parent=self._root_widget, 85 autoselect=True, 86 position=(38, self._height - 85), 87 size=(170, 60), 88 label=bui.Lstr(resource='cancelText'), 89 scale=0.9, 90 on_activate_call=self._cancel, 91 ) 92 save_button = bui.buttonwidget( 93 parent=self._root_widget, 94 autoselect=True, 95 position=(self._width - 190, self._height - 85), 96 size=(180, 60), 97 label=bui.Lstr(resource='saveText'), 98 scale=0.9, 99 text_scale=0.9, 100 on_activate_call=self._save, 101 ) 102 bui.containerwidget( 103 edit=self._root_widget, 104 cancel_button=cancel_button, 105 start_button=save_button, 106 ) 107 108 v = self._height - 74.0 109 bui.textwidget( 110 parent=self._root_widget, 111 position=(self._width * 0.5, v + 15), 112 size=(0, 0), 113 text=bui.Lstr( 114 resource=self._r + '.configuringText', 115 subs=[('${DEVICE}', self._displayname)], 116 ), 117 color=bui.app.ui_v1.title_color, 118 h_align='center', 119 v_align='center', 120 maxwidth=270, 121 scale=0.83, 122 ) 123 v -= 20 124 125 if self._unique_id != '#1': 126 v -= 20 127 v -= self._spacing 128 bui.textwidget( 129 parent=self._root_widget, 130 position=(0, v + 19), 131 size=(self._width, 50), 132 text=bui.Lstr(resource=self._r + '.keyboard2NoteText'), 133 scale=0.7, 134 maxwidth=self._width * 0.75, 135 max_height=110, 136 color=bui.app.ui_v1.infotextcolor, 137 h_align='center', 138 v_align='top', 139 ) 140 v -= 40 141 v -= 10 142 v -= self._spacing * 2.2 143 v += 25 144 v -= 42 145 h_offs = 160 146 dist = 70 147 d_color = (0.4, 0.4, 0.8) 148 self._capture_button( 149 pos=(h_offs, v + 0.95 * dist), 150 color=d_color, 151 button='buttonUp', 152 texture=bui.gettexture('upButton'), 153 scale=1.0, 154 ) 155 self._capture_button( 156 pos=(h_offs - 1.2 * dist, v), 157 color=d_color, 158 button='buttonLeft', 159 texture=bui.gettexture('leftButton'), 160 scale=1.0, 161 ) 162 self._capture_button( 163 pos=(h_offs + 1.2 * dist, v), 164 color=d_color, 165 button='buttonRight', 166 texture=bui.gettexture('rightButton'), 167 scale=1.0, 168 ) 169 self._capture_button( 170 pos=(h_offs, v - 0.95 * dist), 171 color=d_color, 172 button='buttonDown', 173 texture=bui.gettexture('downButton'), 174 scale=1.0, 175 ) 176 177 if self._unique_id == '#2': 178 self._capture_button( 179 pos=(self._width * 0.5, v + 0.1 * dist), 180 color=(0.4, 0.4, 0.6), 181 button='buttonStart', 182 texture=bui.gettexture('startButton'), 183 scale=0.8, 184 ) 185 186 h_offs = self._width - 160 187 188 self._capture_button( 189 pos=(h_offs, v + 0.95 * dist), 190 color=(0.6, 0.4, 0.8), 191 button='buttonPickUp', 192 texture=bui.gettexture('buttonPickUp'), 193 scale=1.0, 194 ) 195 self._capture_button( 196 pos=(h_offs - 1.2 * dist, v), 197 color=(0.7, 0.5, 0.1), 198 button='buttonPunch', 199 texture=bui.gettexture('buttonPunch'), 200 scale=1.0, 201 ) 202 self._capture_button( 203 pos=(h_offs + 1.2 * dist, v), 204 color=(0.5, 0.2, 0.1), 205 button='buttonBomb', 206 texture=bui.gettexture('buttonBomb'), 207 scale=1.0, 208 ) 209 self._capture_button( 210 pos=(h_offs, v - 0.95 * dist), 211 color=(0.2, 0.5, 0.2), 212 button='buttonJump', 213 texture=bui.gettexture('buttonJump'), 214 scale=1.0, 215 ) 216 217 self._more_button = bui.buttonwidget( 218 parent=self._root_widget, 219 autoselect=True, 220 label='...', 221 text_scale=0.9, 222 color=(0.45, 0.4, 0.5), 223 textcolor=(0.65, 0.6, 0.7), 224 position=(self._width * 0.5 - 65, 30), 225 size=(130, 40), 226 on_activate_call=self._do_more, 227 ) 228 229 if is_reset: 230 bui.containerwidget( 231 edit=self._root_widget, 232 selected_child=self._more_button, 233 ) 234 235 def _pretty_button_name(self, button_name: str) -> bui.Lstr: 236 button_id = self._settings[button_name] 237 if button_id == -1: 238 return bs.Lstr(resource='configGamepadWindow.unsetText') 239 return self._input.get_button_name(button_id) 240 241 def _capture_button( 242 self, 243 pos: tuple[float, float], 244 color: tuple[float, float, float], 245 texture: bui.Texture, 246 button: str, 247 scale: float = 1.0, 248 ) -> None: 249 base_size = 79 250 btn = bui.buttonwidget( 251 parent=self._root_widget, 252 autoselect=True, 253 position=( 254 pos[0] - base_size * 0.5 * scale, 255 pos[1] - base_size * 0.5 * scale, 256 ), 257 size=(base_size * scale, base_size * scale), 258 texture=texture, 259 label='', 260 color=color, 261 ) 262 263 # Do this deferred so it shows up on top of other buttons. (ew.) 264 def doit() -> None: 265 if not self._root_widget: 266 return 267 uiscale = 0.66 * scale * 2.0 268 maxwidth = 76.0 * scale 269 txt = bui.textwidget( 270 parent=self._root_widget, 271 position=(pos[0] + 0.0 * scale, pos[1] - (57.0 - 18.0) * scale), 272 color=(1, 1, 1, 0.3), 273 size=(0, 0), 274 h_align='center', 275 v_align='top', 276 scale=uiscale, 277 maxwidth=maxwidth, 278 text=self._pretty_button_name(button), 279 ) 280 bui.buttonwidget( 281 edit=btn, 282 autoselect=True, 283 on_activate_call=bui.Call( 284 AwaitKeyboardInputWindow, button, txt, self._settings 285 ), 286 ) 287 288 bui.pushcall(doit) 289 290 def _cancel(self) -> None: 291 from bauiv1lib.settings.controls import ControlsSettingsWindow 292 293 # no-op if our underlying widget is dead or on its way out. 294 if not self._root_widget or self._root_widget.transitioning_out: 295 return 296 297 bui.containerwidget(edit=self._root_widget, transition='out_right') 298 assert bui.app.classic is not None 299 bui.app.ui_v1.set_main_menu_window( 300 ControlsSettingsWindow(transition='in_left').get_root_widget(), 301 from_window=self._root_widget, 302 ) 303 304 def _reset(self) -> None: 305 from bauiv1lib.confirm import ConfirmWindow 306 307 assert bui.app.classic is not None 308 309 # efro note: I think it's ok to reset without a confirm here 310 # because the user can see pretty clearly what changes and can 311 # cancel out of the keyboard settings edit if they want. 312 if bool(False): 313 ConfirmWindow( 314 # TODO: Implement a translation string for this! 315 'Are you sure you want to reset your button mapping?', 316 self._do_reset, 317 width=480, 318 height=95, 319 ) 320 else: 321 self._do_reset() 322 323 def _do_reset(self) -> None: 324 """Resets the input's mapping settings.""" 325 self._settings = {} 326 self._get_config_mapping(default=True) 327 self._rebuild_ui(is_reset=True) 328 bui.getsound('gunCocking').play() 329 330 def _do_more(self) -> None: 331 """Show a burger menu with extra settings.""" 332 # pylint: disable=cyclic-import 333 choices: list[str] = [ 334 'reset', 335 ] 336 choices_display: list[bui.Lstr] = [ 337 bui.Lstr(resource='settingsWindowAdvanced.resetText'), 338 ] 339 340 uiscale = bui.app.ui_v1.uiscale 341 PopupMenuWindow( 342 position=self._more_button.get_screen_space_center(), 343 scale=( 344 2.3 345 if uiscale is bui.UIScale.SMALL 346 else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23 347 ), 348 width=150, 349 choices=choices, 350 choices_display=choices_display, 351 current_choice='reset', 352 delegate=self, 353 ) 354 355 def popup_menu_selected_choice( 356 self, popup_window: PopupMenuWindow, choice: str 357 ) -> None: 358 """Called when a choice is selected in the popup.""" 359 del popup_window # unused 360 if choice == 'reset': 361 self._reset() 362 else: 363 print(f'invalid choice: {choice}') 364 365 def popup_menu_closing(self, popup_window: PopupWindow) -> None: 366 """Called when the popup is closing.""" 367 368 def _save(self) -> None: 369 from bauiv1lib.settings.controls import ControlsSettingsWindow 370 371 # no-op if our underlying widget is dead or on its way out. 372 if not self._root_widget or self._root_widget.transitioning_out: 373 return 374 375 assert bui.app.classic is not None 376 bui.containerwidget(edit=self._root_widget, transition='out_right') 377 bui.getsound('gunCocking').play() 378 379 # There's a chance the device disappeared; handle that gracefully. 380 if not self._input: 381 return 382 383 dst = bui.app.classic.get_input_device_config( 384 self._input, default=False 385 ) 386 dst2: dict[str, Any] = dst[0][dst[1]] 387 dst2.clear() 388 389 # Store any values that aren't -1. 390 for key, val in list(self._settings.items()): 391 if val != -1: 392 dst2[key] = val 393 394 # Send this config to the master-server so we can generate 395 # more defaults in the future. 396 if bui.app.classic is not None: 397 bui.app.classic.master_server_v1_post( 398 'controllerConfig', 399 { 400 'ua': bui.app.classic.legacy_user_agent_string, 401 'name': self._name, 402 'b': bui.app.env.build_number, 403 'config': dst2, 404 'v': 2, 405 }, 406 ) 407 bui.app.config.apply_and_commit() 408 bui.app.ui_v1.set_main_menu_window( 409 ControlsSettingsWindow(transition='in_left').get_root_widget(), 410 from_window=self._root_widget, 411 ) 412 413 414class AwaitKeyboardInputWindow(bui.Window): 415 """Window for capturing a keypress.""" 416 417 def __init__(self, button: str, ui: bui.Widget, settings: dict): 418 self._capture_button = button 419 self._capture_key_ui = ui 420 self._settings = settings 421 422 width = 400 423 height = 150 424 assert bui.app.classic is not None 425 uiscale = bui.app.ui_v1.uiscale 426 super().__init__( 427 root_widget=bui.containerwidget( 428 size=(width, height), 429 transition='in_right', 430 scale=( 431 2.0 432 if uiscale is bui.UIScale.SMALL 433 else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0 434 ), 435 ) 436 ) 437 bui.textwidget( 438 parent=self._root_widget, 439 position=(0, height - 60), 440 size=(width, 25), 441 text=bui.Lstr(resource='pressAnyKeyText'), 442 h_align='center', 443 v_align='top', 444 ) 445 446 self._counter = 5 447 self._count_down_text = bui.textwidget( 448 parent=self._root_widget, 449 h_align='center', 450 position=(0, height - 110), 451 size=(width, 25), 452 color=(1, 1, 1, 0.3), 453 text=str(self._counter), 454 ) 455 self._decrement_timer: bui.AppTimer | None = bui.AppTimer( 456 1.0, self._decrement, repeat=True 457 ) 458 bs.capture_keyboard_input(bui.WeakCall(self._button_callback)) 459 460 def __del__(self) -> None: 461 bs.release_keyboard_input() 462 463 def _die(self) -> None: 464 # This strong-refs us; killing it allows us to die now. 465 self._decrement_timer = None 466 if self._root_widget: 467 bui.containerwidget(edit=self._root_widget, transition='out_left') 468 469 def _button_callback(self, event: dict[str, Any]) -> None: 470 self._settings[self._capture_button] = event['button'] 471 if event['type'] == 'BUTTONDOWN': 472 bname = event['input_device'].get_button_name(event['button']) 473 bui.textwidget(edit=self._capture_key_ui, text=bname) 474 bui.getsound('gunCocking').play() 475 self._die() 476 477 def _decrement(self) -> None: 478 self._counter -= 1 479 if self._counter >= 1: 480 bui.textwidget(edit=self._count_down_text, text=str(self._counter)) 481 else: 482 self._die()
class
ConfigKeyboardWindow(bauiv1._uitypes.Window):
19class ConfigKeyboardWindow(bui.Window): 20 """Window for configuring keyboards.""" 21 22 def __init__(self, c: bs.InputDevice, transition: str = 'in_right'): 23 self._r = 'configKeyboardWindow' 24 self._input = c 25 self._name = self._input.name 26 self._unique_id = self._input.unique_identifier 27 dname_raw = self._name 28 if self._unique_id != '#1': 29 dname_raw += ' ' + self._unique_id.replace('#', 'P') 30 self._displayname = bui.Lstr(translate=('inputDeviceNames', dname_raw)) 31 self._width = 700 32 if self._unique_id != '#1': 33 self._height = 480 34 else: 35 self._height = 375 36 self._spacing = 40 37 assert bui.app.classic is not None 38 uiscale = bui.app.ui_v1.uiscale 39 super().__init__( 40 root_widget=bui.containerwidget( 41 size=(self._width, self._height), 42 scale=( 43 1.6 44 if uiscale is bui.UIScale.SMALL 45 else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0 46 ), 47 stack_offset=(0, 5) if uiscale is bui.UIScale.SMALL else (0, 0), 48 transition=transition, 49 ) 50 ) 51 52 self._settings: dict[str, int] = {} 53 self._get_config_mapping() 54 55 self._rebuild_ui() 56 57 def _get_config_mapping(self, default: bool = False) -> None: 58 for button in [ 59 'buttonJump', 60 'buttonPunch', 61 'buttonBomb', 62 'buttonPickUp', 63 'buttonStart', 64 'buttonStart2', 65 'buttonUp', 66 'buttonDown', 67 'buttonLeft', 68 'buttonRight', 69 ]: 70 assert bui.app.classic is not None 71 self._settings[button] = ( 72 bui.app.classic.get_input_device_mapped_value( 73 self._input, button, default 74 ) 75 ) 76 77 def _rebuild_ui(self, is_reset: bool = False) -> None: 78 assert bui.app.classic is not None 79 80 for widget in self._root_widget.get_children(): 81 widget.delete() 82 83 # b_off = 0 if self._unique_id != '#1' else 9 84 cancel_button = bui.buttonwidget( 85 parent=self._root_widget, 86 autoselect=True, 87 position=(38, self._height - 85), 88 size=(170, 60), 89 label=bui.Lstr(resource='cancelText'), 90 scale=0.9, 91 on_activate_call=self._cancel, 92 ) 93 save_button = bui.buttonwidget( 94 parent=self._root_widget, 95 autoselect=True, 96 position=(self._width - 190, self._height - 85), 97 size=(180, 60), 98 label=bui.Lstr(resource='saveText'), 99 scale=0.9, 100 text_scale=0.9, 101 on_activate_call=self._save, 102 ) 103 bui.containerwidget( 104 edit=self._root_widget, 105 cancel_button=cancel_button, 106 start_button=save_button, 107 ) 108 109 v = self._height - 74.0 110 bui.textwidget( 111 parent=self._root_widget, 112 position=(self._width * 0.5, v + 15), 113 size=(0, 0), 114 text=bui.Lstr( 115 resource=self._r + '.configuringText', 116 subs=[('${DEVICE}', self._displayname)], 117 ), 118 color=bui.app.ui_v1.title_color, 119 h_align='center', 120 v_align='center', 121 maxwidth=270, 122 scale=0.83, 123 ) 124 v -= 20 125 126 if self._unique_id != '#1': 127 v -= 20 128 v -= self._spacing 129 bui.textwidget( 130 parent=self._root_widget, 131 position=(0, v + 19), 132 size=(self._width, 50), 133 text=bui.Lstr(resource=self._r + '.keyboard2NoteText'), 134 scale=0.7, 135 maxwidth=self._width * 0.75, 136 max_height=110, 137 color=bui.app.ui_v1.infotextcolor, 138 h_align='center', 139 v_align='top', 140 ) 141 v -= 40 142 v -= 10 143 v -= self._spacing * 2.2 144 v += 25 145 v -= 42 146 h_offs = 160 147 dist = 70 148 d_color = (0.4, 0.4, 0.8) 149 self._capture_button( 150 pos=(h_offs, v + 0.95 * dist), 151 color=d_color, 152 button='buttonUp', 153 texture=bui.gettexture('upButton'), 154 scale=1.0, 155 ) 156 self._capture_button( 157 pos=(h_offs - 1.2 * dist, v), 158 color=d_color, 159 button='buttonLeft', 160 texture=bui.gettexture('leftButton'), 161 scale=1.0, 162 ) 163 self._capture_button( 164 pos=(h_offs + 1.2 * dist, v), 165 color=d_color, 166 button='buttonRight', 167 texture=bui.gettexture('rightButton'), 168 scale=1.0, 169 ) 170 self._capture_button( 171 pos=(h_offs, v - 0.95 * dist), 172 color=d_color, 173 button='buttonDown', 174 texture=bui.gettexture('downButton'), 175 scale=1.0, 176 ) 177 178 if self._unique_id == '#2': 179 self._capture_button( 180 pos=(self._width * 0.5, v + 0.1 * dist), 181 color=(0.4, 0.4, 0.6), 182 button='buttonStart', 183 texture=bui.gettexture('startButton'), 184 scale=0.8, 185 ) 186 187 h_offs = self._width - 160 188 189 self._capture_button( 190 pos=(h_offs, v + 0.95 * dist), 191 color=(0.6, 0.4, 0.8), 192 button='buttonPickUp', 193 texture=bui.gettexture('buttonPickUp'), 194 scale=1.0, 195 ) 196 self._capture_button( 197 pos=(h_offs - 1.2 * dist, v), 198 color=(0.7, 0.5, 0.1), 199 button='buttonPunch', 200 texture=bui.gettexture('buttonPunch'), 201 scale=1.0, 202 ) 203 self._capture_button( 204 pos=(h_offs + 1.2 * dist, v), 205 color=(0.5, 0.2, 0.1), 206 button='buttonBomb', 207 texture=bui.gettexture('buttonBomb'), 208 scale=1.0, 209 ) 210 self._capture_button( 211 pos=(h_offs, v - 0.95 * dist), 212 color=(0.2, 0.5, 0.2), 213 button='buttonJump', 214 texture=bui.gettexture('buttonJump'), 215 scale=1.0, 216 ) 217 218 self._more_button = bui.buttonwidget( 219 parent=self._root_widget, 220 autoselect=True, 221 label='...', 222 text_scale=0.9, 223 color=(0.45, 0.4, 0.5), 224 textcolor=(0.65, 0.6, 0.7), 225 position=(self._width * 0.5 - 65, 30), 226 size=(130, 40), 227 on_activate_call=self._do_more, 228 ) 229 230 if is_reset: 231 bui.containerwidget( 232 edit=self._root_widget, 233 selected_child=self._more_button, 234 ) 235 236 def _pretty_button_name(self, button_name: str) -> bui.Lstr: 237 button_id = self._settings[button_name] 238 if button_id == -1: 239 return bs.Lstr(resource='configGamepadWindow.unsetText') 240 return self._input.get_button_name(button_id) 241 242 def _capture_button( 243 self, 244 pos: tuple[float, float], 245 color: tuple[float, float, float], 246 texture: bui.Texture, 247 button: str, 248 scale: float = 1.0, 249 ) -> None: 250 base_size = 79 251 btn = bui.buttonwidget( 252 parent=self._root_widget, 253 autoselect=True, 254 position=( 255 pos[0] - base_size * 0.5 * scale, 256 pos[1] - base_size * 0.5 * scale, 257 ), 258 size=(base_size * scale, base_size * scale), 259 texture=texture, 260 label='', 261 color=color, 262 ) 263 264 # Do this deferred so it shows up on top of other buttons. (ew.) 265 def doit() -> None: 266 if not self._root_widget: 267 return 268 uiscale = 0.66 * scale * 2.0 269 maxwidth = 76.0 * scale 270 txt = bui.textwidget( 271 parent=self._root_widget, 272 position=(pos[0] + 0.0 * scale, pos[1] - (57.0 - 18.0) * scale), 273 color=(1, 1, 1, 0.3), 274 size=(0, 0), 275 h_align='center', 276 v_align='top', 277 scale=uiscale, 278 maxwidth=maxwidth, 279 text=self._pretty_button_name(button), 280 ) 281 bui.buttonwidget( 282 edit=btn, 283 autoselect=True, 284 on_activate_call=bui.Call( 285 AwaitKeyboardInputWindow, button, txt, self._settings 286 ), 287 ) 288 289 bui.pushcall(doit) 290 291 def _cancel(self) -> None: 292 from bauiv1lib.settings.controls import ControlsSettingsWindow 293 294 # no-op if our underlying widget is dead or on its way out. 295 if not self._root_widget or self._root_widget.transitioning_out: 296 return 297 298 bui.containerwidget(edit=self._root_widget, transition='out_right') 299 assert bui.app.classic is not None 300 bui.app.ui_v1.set_main_menu_window( 301 ControlsSettingsWindow(transition='in_left').get_root_widget(), 302 from_window=self._root_widget, 303 ) 304 305 def _reset(self) -> None: 306 from bauiv1lib.confirm import ConfirmWindow 307 308 assert bui.app.classic is not None 309 310 # efro note: I think it's ok to reset without a confirm here 311 # because the user can see pretty clearly what changes and can 312 # cancel out of the keyboard settings edit if they want. 313 if bool(False): 314 ConfirmWindow( 315 # TODO: Implement a translation string for this! 316 'Are you sure you want to reset your button mapping?', 317 self._do_reset, 318 width=480, 319 height=95, 320 ) 321 else: 322 self._do_reset() 323 324 def _do_reset(self) -> None: 325 """Resets the input's mapping settings.""" 326 self._settings = {} 327 self._get_config_mapping(default=True) 328 self._rebuild_ui(is_reset=True) 329 bui.getsound('gunCocking').play() 330 331 def _do_more(self) -> None: 332 """Show a burger menu with extra settings.""" 333 # pylint: disable=cyclic-import 334 choices: list[str] = [ 335 'reset', 336 ] 337 choices_display: list[bui.Lstr] = [ 338 bui.Lstr(resource='settingsWindowAdvanced.resetText'), 339 ] 340 341 uiscale = bui.app.ui_v1.uiscale 342 PopupMenuWindow( 343 position=self._more_button.get_screen_space_center(), 344 scale=( 345 2.3 346 if uiscale is bui.UIScale.SMALL 347 else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23 348 ), 349 width=150, 350 choices=choices, 351 choices_display=choices_display, 352 current_choice='reset', 353 delegate=self, 354 ) 355 356 def popup_menu_selected_choice( 357 self, popup_window: PopupMenuWindow, choice: str 358 ) -> None: 359 """Called when a choice is selected in the popup.""" 360 del popup_window # unused 361 if choice == 'reset': 362 self._reset() 363 else: 364 print(f'invalid choice: {choice}') 365 366 def popup_menu_closing(self, popup_window: PopupWindow) -> None: 367 """Called when the popup is closing.""" 368 369 def _save(self) -> None: 370 from bauiv1lib.settings.controls import ControlsSettingsWindow 371 372 # no-op if our underlying widget is dead or on its way out. 373 if not self._root_widget or self._root_widget.transitioning_out: 374 return 375 376 assert bui.app.classic is not None 377 bui.containerwidget(edit=self._root_widget, transition='out_right') 378 bui.getsound('gunCocking').play() 379 380 # There's a chance the device disappeared; handle that gracefully. 381 if not self._input: 382 return 383 384 dst = bui.app.classic.get_input_device_config( 385 self._input, default=False 386 ) 387 dst2: dict[str, Any] = dst[0][dst[1]] 388 dst2.clear() 389 390 # Store any values that aren't -1. 391 for key, val in list(self._settings.items()): 392 if val != -1: 393 dst2[key] = val 394 395 # Send this config to the master-server so we can generate 396 # more defaults in the future. 397 if bui.app.classic is not None: 398 bui.app.classic.master_server_v1_post( 399 'controllerConfig', 400 { 401 'ua': bui.app.classic.legacy_user_agent_string, 402 'name': self._name, 403 'b': bui.app.env.build_number, 404 'config': dst2, 405 'v': 2, 406 }, 407 ) 408 bui.app.config.apply_and_commit() 409 bui.app.ui_v1.set_main_menu_window( 410 ControlsSettingsWindow(transition='in_left').get_root_widget(), 411 from_window=self._root_widget, 412 )
Window for configuring keyboards.
ConfigKeyboardWindow(c: _bascenev1.InputDevice, transition: str = 'in_right')
22 def __init__(self, c: bs.InputDevice, transition: str = 'in_right'): 23 self._r = 'configKeyboardWindow' 24 self._input = c 25 self._name = self._input.name 26 self._unique_id = self._input.unique_identifier 27 dname_raw = self._name 28 if self._unique_id != '#1': 29 dname_raw += ' ' + self._unique_id.replace('#', 'P') 30 self._displayname = bui.Lstr(translate=('inputDeviceNames', dname_raw)) 31 self._width = 700 32 if self._unique_id != '#1': 33 self._height = 480 34 else: 35 self._height = 375 36 self._spacing = 40 37 assert bui.app.classic is not None 38 uiscale = bui.app.ui_v1.uiscale 39 super().__init__( 40 root_widget=bui.containerwidget( 41 size=(self._width, self._height), 42 scale=( 43 1.6 44 if uiscale is bui.UIScale.SMALL 45 else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0 46 ), 47 stack_offset=(0, 5) if uiscale is bui.UIScale.SMALL else (0, 0), 48 transition=transition, 49 ) 50 ) 51 52 self._settings: dict[str, int] = {} 53 self._get_config_mapping() 54 55 self._rebuild_ui()
Inherited Members
- bauiv1._uitypes.Window
- get_root_widget
class
AwaitKeyboardInputWindow(bauiv1._uitypes.Window):
415class AwaitKeyboardInputWindow(bui.Window): 416 """Window for capturing a keypress.""" 417 418 def __init__(self, button: str, ui: bui.Widget, settings: dict): 419 self._capture_button = button 420 self._capture_key_ui = ui 421 self._settings = settings 422 423 width = 400 424 height = 150 425 assert bui.app.classic is not None 426 uiscale = bui.app.ui_v1.uiscale 427 super().__init__( 428 root_widget=bui.containerwidget( 429 size=(width, height), 430 transition='in_right', 431 scale=( 432 2.0 433 if uiscale is bui.UIScale.SMALL 434 else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0 435 ), 436 ) 437 ) 438 bui.textwidget( 439 parent=self._root_widget, 440 position=(0, height - 60), 441 size=(width, 25), 442 text=bui.Lstr(resource='pressAnyKeyText'), 443 h_align='center', 444 v_align='top', 445 ) 446 447 self._counter = 5 448 self._count_down_text = bui.textwidget( 449 parent=self._root_widget, 450 h_align='center', 451 position=(0, height - 110), 452 size=(width, 25), 453 color=(1, 1, 1, 0.3), 454 text=str(self._counter), 455 ) 456 self._decrement_timer: bui.AppTimer | None = bui.AppTimer( 457 1.0, self._decrement, repeat=True 458 ) 459 bs.capture_keyboard_input(bui.WeakCall(self._button_callback)) 460 461 def __del__(self) -> None: 462 bs.release_keyboard_input() 463 464 def _die(self) -> None: 465 # This strong-refs us; killing it allows us to die now. 466 self._decrement_timer = None 467 if self._root_widget: 468 bui.containerwidget(edit=self._root_widget, transition='out_left') 469 470 def _button_callback(self, event: dict[str, Any]) -> None: 471 self._settings[self._capture_button] = event['button'] 472 if event['type'] == 'BUTTONDOWN': 473 bname = event['input_device'].get_button_name(event['button']) 474 bui.textwidget(edit=self._capture_key_ui, text=bname) 475 bui.getsound('gunCocking').play() 476 self._die() 477 478 def _decrement(self) -> None: 479 self._counter -= 1 480 if self._counter >= 1: 481 bui.textwidget(edit=self._count_down_text, text=str(self._counter)) 482 else: 483 self._die()
Window for capturing a keypress.
AwaitKeyboardInputWindow(button: str, ui: _bauiv1.Widget, settings: dict)
418 def __init__(self, button: str, ui: bui.Widget, settings: dict): 419 self._capture_button = button 420 self._capture_key_ui = ui 421 self._settings = settings 422 423 width = 400 424 height = 150 425 assert bui.app.classic is not None 426 uiscale = bui.app.ui_v1.uiscale 427 super().__init__( 428 root_widget=bui.containerwidget( 429 size=(width, height), 430 transition='in_right', 431 scale=( 432 2.0 433 if uiscale is bui.UIScale.SMALL 434 else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0 435 ), 436 ) 437 ) 438 bui.textwidget( 439 parent=self._root_widget, 440 position=(0, height - 60), 441 size=(width, 25), 442 text=bui.Lstr(resource='pressAnyKeyText'), 443 h_align='center', 444 v_align='top', 445 ) 446 447 self._counter = 5 448 self._count_down_text = bui.textwidget( 449 parent=self._root_widget, 450 h_align='center', 451 position=(0, height - 110), 452 size=(width, 25), 453 color=(1, 1, 1, 0.3), 454 text=str(self._counter), 455 ) 456 self._decrement_timer: bui.AppTimer | None = bui.AppTimer( 457 1.0, self._decrement, repeat=True 458 ) 459 bs.capture_keyboard_input(bui.WeakCall(self._button_callback))
Inherited Members
- bauiv1._uitypes.Window
- get_root_widget