mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-24 07:53:30 +08:00
Merge pull request #651 from 3alTemp/keybind_reset
Reset Mapping button in controllers config menu
This commit is contained in:
commit
be7eb36ba5
@ -20,6 +20,7 @@
|
||||
languages; I feel it helps keep logic more understandable and should help us
|
||||
catch problems where a base class changes or removes a method and child
|
||||
classes forget to adapt to the change.
|
||||
- Added a reset button in the input mapping menu. (Thanks Temp!)
|
||||
- Respawn icons now have dotted steps showing decimal progress to assist
|
||||
players on calculating when they are gonna respawn. (Thanks 3alTemp!)
|
||||
- Replays now have rewind/fast-forward buttons!! (Thanks Dliwk, vishal332008!)
|
||||
|
||||
@ -13,7 +13,10 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
def get_input_device_mapped_value(
|
||||
devicename: str, unique_id: str, name: str
|
||||
devicename: str,
|
||||
unique_id: str,
|
||||
name: str,
|
||||
default: bool = False,
|
||||
) -> Any:
|
||||
"""Returns a mapped value for an input device.
|
||||
|
||||
@ -30,8 +33,9 @@ def get_input_device_mapped_value(
|
||||
subplatform = app.classic.subplatform
|
||||
appconfig = babase.app.config
|
||||
|
||||
# If there's an entry in our config for this controller, use it.
|
||||
if 'Controllers' in appconfig:
|
||||
# If there's an entry in our config for this controller and
|
||||
# we're not looking for our default mappings, use it.
|
||||
if 'Controllers' in appconfig and not default:
|
||||
ccfgs = appconfig['Controllers']
|
||||
if devicename in ccfgs:
|
||||
mapping = None
|
||||
|
||||
@ -575,15 +575,18 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
)
|
||||
|
||||
def get_input_device_mapped_value(
|
||||
self, device: bascenev1.InputDevice, name: str
|
||||
self,
|
||||
device: bascenev1.InputDevice,
|
||||
name: str,
|
||||
default: bool = False,
|
||||
) -> Any:
|
||||
"""Returns a mapped value for an input device.
|
||||
"""Return a mapped value for an input device.
|
||||
|
||||
This checks the user config and falls back to default values
|
||||
where available.
|
||||
"""
|
||||
return _input.get_input_device_mapped_value(
|
||||
device.name, device.unique_identifier, name
|
||||
device.name, device.unique_identifier, name, default
|
||||
)
|
||||
|
||||
def get_input_device_map_hash(
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
# pylint: disable=too-many-lines
|
||||
"""Settings UI functionality related to gamepads."""
|
||||
|
||||
from __future__ import annotations
|
||||
@ -7,15 +8,18 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bauiv1lib.popup import PopupMenuWindow
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
from bauiv1lib.popup import PopupWindow
|
||||
|
||||
|
||||
class GamepadSettingsWindow(bui.Window):
|
||||
"""Window for configuring a gamepad."""
|
||||
# pylint: disable=too-many-public-methods
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -34,7 +38,6 @@ class GamepadSettingsWindow(bui.Window):
|
||||
self._name = self._input.name
|
||||
|
||||
self._r = 'configGamepadWindow'
|
||||
self._settings = settings
|
||||
self._transition_out = transition_out
|
||||
|
||||
# We're a secondary gamepad if supplied with settings.
|
||||
@ -62,12 +65,81 @@ class GamepadSettingsWindow(bui.Window):
|
||||
)
|
||||
)
|
||||
|
||||
self._settings: dict[str, int] = {}
|
||||
if not self._is_secondary:
|
||||
self._get_config_mapping()
|
||||
# Don't ask to config joysticks while we're in here.
|
||||
self._rebuild_ui()
|
||||
|
||||
def _rebuild_ui(self) -> None:
|
||||
def _get_config_mapping(self, default: bool = False) -> None:
|
||||
for button in [
|
||||
'buttonJump',
|
||||
'buttonJump_B',
|
||||
'buttonPunch',
|
||||
'buttonPunch_B',
|
||||
'buttonBomb',
|
||||
'buttonBomb_B',
|
||||
'buttonPickUp',
|
||||
'buttonPickUp_B',
|
||||
'buttonStart',
|
||||
'buttonStart_B',
|
||||
'buttonStart2',
|
||||
'buttonStart2_B',
|
||||
'buttonUp',
|
||||
'buttonUp_B',
|
||||
'buttonDown',
|
||||
'buttonDown_B',
|
||||
'buttonLeft',
|
||||
'buttonLeft_B',
|
||||
'buttonRight',
|
||||
'buttonRight_B',
|
||||
'buttonRun1',
|
||||
'buttonRun1_B',
|
||||
'buttonRun2',
|
||||
'buttonRun2_B',
|
||||
'triggerRun1',
|
||||
'triggerRun1_B',
|
||||
'triggerRun2',
|
||||
'triggerRun2_B',
|
||||
'buttonIgnored',
|
||||
'buttonIgnored_B',
|
||||
'buttonIgnored2',
|
||||
'buttonIgnored2_B',
|
||||
'buttonIgnored3',
|
||||
'buttonIgnored3_B',
|
||||
'buttonIgnored4',
|
||||
'buttonIgnored4_B',
|
||||
'buttonVRReorient',
|
||||
'buttonVRReorient_B',
|
||||
'analogStickDeadZone',
|
||||
'analogStickDeadZone_B',
|
||||
'dpad',
|
||||
'dpad_B',
|
||||
'unassignedButtonsRun',
|
||||
'unassignedButtonsRun_B',
|
||||
'startButtonActivatesDefaultWidget',
|
||||
'startButtonActivatesDefaultWidget_B',
|
||||
'uiOnly',
|
||||
'uiOnly_B',
|
||||
'ignoreCompletely',
|
||||
'ignoreCompletely_B',
|
||||
'autoRecalibrateAnalogStick',
|
||||
'autoRecalibrateAnalogStick_B',
|
||||
'analogStickLR',
|
||||
'analogStickLR_B',
|
||||
'analogStickUD',
|
||||
'analogStickUD_B',
|
||||
'enableSecondary',
|
||||
]:
|
||||
assert bui.app.classic is not None
|
||||
val = bui.app.classic.get_input_device_mapped_value(
|
||||
self._input, button, default
|
||||
)
|
||||
if val != -1:
|
||||
self._settings[button] = val
|
||||
|
||||
def _rebuild_ui(self, is_reset: bool = False) -> None:
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-locals
|
||||
|
||||
assert bui.app.classic is not None
|
||||
|
||||
@ -77,77 +149,6 @@ class GamepadSettingsWindow(bui.Window):
|
||||
|
||||
self._textwidgets: dict[str, bui.Widget] = {}
|
||||
|
||||
# If we were supplied with settings, we're a secondary joystick and
|
||||
# just operate on that. in the other (normal) case we make our own.
|
||||
if not self._is_secondary:
|
||||
# Fill our temp config with present values (for our primary and
|
||||
# secondary controls).
|
||||
self._settings = {}
|
||||
for skey in [
|
||||
'buttonJump',
|
||||
'buttonJump_B',
|
||||
'buttonPunch',
|
||||
'buttonPunch_B',
|
||||
'buttonBomb',
|
||||
'buttonBomb_B',
|
||||
'buttonPickUp',
|
||||
'buttonPickUp_B',
|
||||
'buttonStart',
|
||||
'buttonStart_B',
|
||||
'buttonStart2',
|
||||
'buttonStart2_B',
|
||||
'buttonUp',
|
||||
'buttonUp_B',
|
||||
'buttonDown',
|
||||
'buttonDown_B',
|
||||
'buttonLeft',
|
||||
'buttonLeft_B',
|
||||
'buttonRight',
|
||||
'buttonRight_B',
|
||||
'buttonRun1',
|
||||
'buttonRun1_B',
|
||||
'buttonRun2',
|
||||
'buttonRun2_B',
|
||||
'triggerRun1',
|
||||
'triggerRun1_B',
|
||||
'triggerRun2',
|
||||
'triggerRun2_B',
|
||||
'buttonIgnored',
|
||||
'buttonIgnored_B',
|
||||
'buttonIgnored2',
|
||||
'buttonIgnored2_B',
|
||||
'buttonIgnored3',
|
||||
'buttonIgnored3_B',
|
||||
'buttonIgnored4',
|
||||
'buttonIgnored4_B',
|
||||
'buttonVRReorient',
|
||||
'buttonVRReorient_B',
|
||||
'analogStickDeadZone',
|
||||
'analogStickDeadZone_B',
|
||||
'dpad',
|
||||
'dpad_B',
|
||||
'unassignedButtonsRun',
|
||||
'unassignedButtonsRun_B',
|
||||
'startButtonActivatesDefaultWidget',
|
||||
'startButtonActivatesDefaultWidget_B',
|
||||
'uiOnly',
|
||||
'uiOnly_B',
|
||||
'ignoreCompletely',
|
||||
'ignoreCompletely_B',
|
||||
'autoRecalibrateAnalogStick',
|
||||
'autoRecalibrateAnalogStick_B',
|
||||
'analogStickLR',
|
||||
'analogStickLR_B',
|
||||
'analogStickUD',
|
||||
'analogStickUD_B',
|
||||
'enableSecondary',
|
||||
]:
|
||||
val = bui.app.classic.get_input_device_mapped_value(
|
||||
self._input, skey
|
||||
)
|
||||
if val != -1:
|
||||
self._settings[skey] = val
|
||||
|
||||
back_button: bui.Widget | None
|
||||
|
||||
if self._is_secondary:
|
||||
@ -367,22 +368,27 @@ class GamepadSettingsWindow(bui.Window):
|
||||
scale=1.0,
|
||||
)
|
||||
|
||||
self._advanced_button = bui.buttonwidget(
|
||||
self._more_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource=self._r + '.advancedText'),
|
||||
label='...',
|
||||
text_scale=0.9,
|
||||
color=(0.45, 0.4, 0.5),
|
||||
textcolor=(0.65, 0.6, 0.7),
|
||||
position=(self._width - 300, 30),
|
||||
size=(130, 40),
|
||||
on_activate_call=self._do_advanced,
|
||||
on_activate_call=self._do_more,
|
||||
)
|
||||
|
||||
try:
|
||||
if cancel_button is not None and save_button is not None:
|
||||
bui.widget(edit=cancel_button, right_widget=save_button)
|
||||
bui.widget(edit=save_button, left_widget=cancel_button)
|
||||
if is_reset:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget,
|
||||
selected_child=self._more_button,
|
||||
)
|
||||
except Exception:
|
||||
logging.exception('Error wiring up gamepad config window.')
|
||||
|
||||
@ -392,7 +398,7 @@ class GamepadSettingsWindow(bui.Window):
|
||||
|
||||
def get_advanced_button(self) -> bui.Widget:
|
||||
"""(internal)"""
|
||||
return self._advanced_button
|
||||
return self._more_button
|
||||
|
||||
def get_is_secondary(self) -> bool:
|
||||
"""(internal)"""
|
||||
@ -801,6 +807,78 @@ class GamepadSettingsWindow(bui.Window):
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _reset(self) -> None:
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
assert bui.app.classic is not None
|
||||
ConfirmWindow(
|
||||
# TODO: Implement a translation string for this!
|
||||
'Are you sure you want to reset your button mapping?\n'
|
||||
'This will also reset your advanced mappings\n'
|
||||
'and secondary controller button mappings.',
|
||||
self._do_reset,
|
||||
width=490,
|
||||
height=150,
|
||||
)
|
||||
|
||||
def _do_reset(self) -> None:
|
||||
"""Resets the input's mapping settings."""
|
||||
from babase import InputDeviceNotFoundError
|
||||
self._settings = {}
|
||||
# Unplugging the controller while performing a
|
||||
# mapping reset makes things go bonkers a little.
|
||||
try:
|
||||
self._get_config_mapping(default=True)
|
||||
except InputDeviceNotFoundError:
|
||||
pass
|
||||
|
||||
self._rebuild_ui(is_reset=True)
|
||||
bui.getsound('gunCocking').play()
|
||||
|
||||
def _do_more(self) -> None:
|
||||
"""Show a burger menu with extra settings."""
|
||||
# pylint: disable=cyclic-import
|
||||
choices: list[str] = [
|
||||
'advanced',
|
||||
'reset',
|
||||
]
|
||||
choices_display: list[bui.Lstr] = [
|
||||
bui.Lstr(resource=self._r + '.advancedText'),
|
||||
bui.Lstr(resource='settingsWindowAdvanced.resetText'),
|
||||
]
|
||||
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
PopupMenuWindow(
|
||||
position=self._more_button.get_screen_space_center(),
|
||||
scale=(
|
||||
2.3
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.65
|
||||
if uiscale is bui.UIScale.MEDIUM
|
||||
else 1.23
|
||||
),
|
||||
width=150,
|
||||
choices=choices,
|
||||
choices_display=choices_display,
|
||||
current_choice='advanced',
|
||||
delegate=self,
|
||||
)
|
||||
|
||||
def popup_menu_selected_choice(
|
||||
self, popup_window: PopupMenuWindow, choice: str
|
||||
) -> None:
|
||||
"""Called when a choice is selected in the popup."""
|
||||
del popup_window # unused
|
||||
if choice == 'reset':
|
||||
self._reset()
|
||||
elif choice == 'advanced':
|
||||
self._do_advanced()
|
||||
else:
|
||||
print(f'invalid choice: {choice}')
|
||||
|
||||
def popup_menu_closing(self, popup_window: PopupWindow) -> None:
|
||||
"""Called when the popup is closing."""
|
||||
|
||||
def _save(self) -> None:
|
||||
classic = bui.app.classic
|
||||
assert classic is not None
|
||||
|
||||
@ -6,11 +6,13 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bauiv1lib.popup import PopupMenuWindow
|
||||
import bauiv1 as bui
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
from bauiv1lib.popup import PopupWindow
|
||||
|
||||
|
||||
class ConfigKeyboardWindow(bui.Window):
|
||||
@ -46,16 +48,12 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
)
|
||||
)
|
||||
|
||||
self._settings: dict[str, int] = {}
|
||||
self._get_config_mapping()
|
||||
|
||||
self._rebuild_ui()
|
||||
|
||||
def _rebuild_ui(self) -> None:
|
||||
assert bui.app.classic is not None
|
||||
|
||||
for widget in self._root_widget.get_children():
|
||||
widget.delete()
|
||||
|
||||
# Fill our temp config with present values.
|
||||
self._settings: dict[str, int] = {}
|
||||
def _get_config_mapping(self, default: bool = False) -> None:
|
||||
for button in [
|
||||
'buttonJump',
|
||||
'buttonPunch',
|
||||
@ -68,12 +66,20 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
'buttonLeft',
|
||||
'buttonRight',
|
||||
]:
|
||||
self._settings[button] = (
|
||||
bui.app.classic.get_input_device_mapped_value(
|
||||
self._input, button
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
self._settings[
|
||||
button
|
||||
] = bui.app.classic.get_input_device_mapped_value(
|
||||
self._input, button, default
|
||||
)
|
||||
|
||||
def _rebuild_ui(self, is_reset: bool = False) -> None:
|
||||
assert bui.app.classic is not None
|
||||
|
||||
for widget in self._root_widget.get_children():
|
||||
widget.delete()
|
||||
|
||||
#b_off = 0 if self._unique_id != '#1' else 9
|
||||
cancel_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
@ -99,9 +105,6 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
start_button=save_button,
|
||||
)
|
||||
|
||||
bui.widget(edit=cancel_button, right_widget=save_button)
|
||||
bui.widget(edit=save_button, left_widget=cancel_button)
|
||||
|
||||
v = self._height - 74.0
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -211,6 +214,24 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
scale=1.0,
|
||||
)
|
||||
|
||||
self._more_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
label='...',
|
||||
text_scale=0.9,
|
||||
color=(0.45, 0.4, 0.5),
|
||||
textcolor=(0.65, 0.6, 0.7),
|
||||
position=(self._width * 0.5 - 65, 30),
|
||||
size=(130, 40),
|
||||
on_activate_call=self._do_more,
|
||||
)
|
||||
|
||||
if is_reset:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget,
|
||||
selected_child=self._more_button,
|
||||
)
|
||||
|
||||
def _pretty_button_name(self, button_name: str) -> bui.Lstr:
|
||||
button_id = self._settings[button_name]
|
||||
if button_id == -1:
|
||||
@ -280,6 +301,65 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _reset(self) -> None:
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
assert bui.app.classic is not None
|
||||
ConfirmWindow(
|
||||
# TODO: Implement a translation string for this!
|
||||
'Are you sure you want to reset your button mapping?',
|
||||
self._do_reset,
|
||||
width=480,
|
||||
height=95,
|
||||
)
|
||||
|
||||
def _do_reset(self) -> None:
|
||||
"""Resets the input's mapping settings."""
|
||||
self._settings = {}
|
||||
self._get_config_mapping(default=True)
|
||||
self._rebuild_ui(is_reset=True)
|
||||
bui.getsound('gunCocking').play()
|
||||
|
||||
def _do_more(self) -> None:
|
||||
"""Show a burger menu with extra settings."""
|
||||
# pylint: disable=cyclic-import
|
||||
choices: list[str] = [
|
||||
'reset',
|
||||
]
|
||||
choices_display: list[bui.Lstr] = [
|
||||
bui.Lstr(resource='settingsWindowAdvanced.resetText'),
|
||||
]
|
||||
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
PopupMenuWindow(
|
||||
position=self._more_button.get_screen_space_center(),
|
||||
scale=(
|
||||
2.3
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.65
|
||||
if uiscale is bui.UIScale.MEDIUM
|
||||
else 1.23
|
||||
),
|
||||
width=150,
|
||||
choices=choices,
|
||||
choices_display=choices_display,
|
||||
current_choice='reset',
|
||||
delegate=self,
|
||||
)
|
||||
|
||||
def popup_menu_selected_choice(
|
||||
self, popup_window: PopupMenuWindow, choice: str
|
||||
) -> None:
|
||||
"""Called when a choice is selected in the popup."""
|
||||
del popup_window # unused
|
||||
if choice == 'reset':
|
||||
self._reset()
|
||||
else:
|
||||
print(f'invalid choice: {choice}')
|
||||
|
||||
def popup_menu_closing(self, popup_window: PopupWindow) -> None:
|
||||
"""Called when the popup is closing."""
|
||||
|
||||
def _save(self) -> None:
|
||||
from bauiv1lib.settings.controls import ControlsSettingsWindow
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user