mirror of
https://github.com/hypervortex/VH-Bombsquad-Modded-Server-Files
synced 2026-08-15 13:04:50 +00:00
381 lines
12 KiB
Python
381 lines
12 KiB
Python
# Released under the MIT License. See LICENSE for details.
|
|
#
|
|
"""Keyboard settings related UI functionality."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
import ba
|
|
import ba.internal
|
|
|
|
if TYPE_CHECKING:
|
|
from typing import Any
|
|
|
|
|
|
class ConfigKeyboardWindow(ba.Window):
|
|
"""Window for configuring keyboards."""
|
|
|
|
def __init__(self, c: ba.InputDevice, transition: str = 'in_right'):
|
|
self._r = 'configKeyboardWindow'
|
|
self._input = c
|
|
self._name = self._input.name
|
|
self._unique_id = self._input.unique_identifier
|
|
dname_raw = self._name
|
|
if self._unique_id != '#1':
|
|
dname_raw += ' ' + self._unique_id.replace('#', 'P')
|
|
self._displayname = ba.Lstr(translate=('inputDeviceNames', dname_raw))
|
|
self._width = 700
|
|
if self._unique_id != '#1':
|
|
self._height = 480
|
|
else:
|
|
self._height = 375
|
|
self._spacing = 40
|
|
uiscale = ba.app.ui.uiscale
|
|
super().__init__(
|
|
root_widget=ba.containerwidget(
|
|
size=(self._width, self._height),
|
|
scale=(
|
|
1.6
|
|
if uiscale is ba.UIScale.SMALL
|
|
else 1.3
|
|
if uiscale is ba.UIScale.MEDIUM
|
|
else 1.0
|
|
),
|
|
stack_offset=(0, 5) if uiscale is ba.UIScale.SMALL else (0, 0),
|
|
transition=transition,
|
|
)
|
|
)
|
|
|
|
self._rebuild_ui()
|
|
|
|
def _rebuild_ui(self) -> None:
|
|
from ba.internal import get_device_value
|
|
|
|
for widget in self._root_widget.get_children():
|
|
widget.delete()
|
|
|
|
# Fill our temp config with present values.
|
|
self._settings: dict[str, int] = {}
|
|
for button in [
|
|
'buttonJump',
|
|
'buttonPunch',
|
|
'buttonBomb',
|
|
'buttonPickUp',
|
|
'buttonStart',
|
|
'buttonStart2',
|
|
'buttonUp',
|
|
'buttonDown',
|
|
'buttonLeft',
|
|
'buttonRight',
|
|
]:
|
|
self._settings[button] = get_device_value(self._input, button)
|
|
|
|
cancel_button = ba.buttonwidget(
|
|
parent=self._root_widget,
|
|
autoselect=True,
|
|
position=(38, self._height - 85),
|
|
size=(170, 60),
|
|
label=ba.Lstr(resource='cancelText'),
|
|
scale=0.9,
|
|
on_activate_call=self._cancel,
|
|
)
|
|
save_button = ba.buttonwidget(
|
|
parent=self._root_widget,
|
|
autoselect=True,
|
|
position=(self._width - 190, self._height - 85),
|
|
size=(180, 60),
|
|
label=ba.Lstr(resource='saveText'),
|
|
scale=0.9,
|
|
text_scale=0.9,
|
|
on_activate_call=self._save,
|
|
)
|
|
ba.containerwidget(
|
|
edit=self._root_widget,
|
|
cancel_button=cancel_button,
|
|
start_button=save_button,
|
|
)
|
|
|
|
ba.widget(edit=cancel_button, right_widget=save_button)
|
|
ba.widget(edit=save_button, left_widget=cancel_button)
|
|
|
|
v = self._height - 74.0
|
|
ba.textwidget(
|
|
parent=self._root_widget,
|
|
position=(self._width * 0.5, v + 15),
|
|
size=(0, 0),
|
|
text=ba.Lstr(
|
|
resource=self._r + '.configuringText',
|
|
subs=[('${DEVICE}', self._displayname)],
|
|
),
|
|
color=ba.app.ui.title_color,
|
|
h_align='center',
|
|
v_align='center',
|
|
maxwidth=270,
|
|
scale=0.83,
|
|
)
|
|
v -= 20
|
|
|
|
if self._unique_id != '#1':
|
|
v -= 20
|
|
v -= self._spacing
|
|
ba.textwidget(
|
|
parent=self._root_widget,
|
|
position=(0, v + 19),
|
|
size=(self._width, 50),
|
|
text=ba.Lstr(resource=self._r + '.keyboard2NoteText'),
|
|
scale=0.7,
|
|
maxwidth=self._width * 0.75,
|
|
max_height=110,
|
|
color=ba.app.ui.infotextcolor,
|
|
h_align='center',
|
|
v_align='top',
|
|
)
|
|
v -= 40
|
|
v -= 10
|
|
v -= self._spacing * 2.2
|
|
v += 25
|
|
v -= 42
|
|
h_offs = 160
|
|
dist = 70
|
|
d_color = (0.4, 0.4, 0.8)
|
|
self._capture_button(
|
|
pos=(h_offs, v + 0.95 * dist),
|
|
color=d_color,
|
|
button='buttonUp',
|
|
texture=ba.gettexture('upButton'),
|
|
scale=1.0,
|
|
)
|
|
self._capture_button(
|
|
pos=(h_offs - 1.2 * dist, v),
|
|
color=d_color,
|
|
button='buttonLeft',
|
|
texture=ba.gettexture('leftButton'),
|
|
scale=1.0,
|
|
)
|
|
self._capture_button(
|
|
pos=(h_offs + 1.2 * dist, v),
|
|
color=d_color,
|
|
button='buttonRight',
|
|
texture=ba.gettexture('rightButton'),
|
|
scale=1.0,
|
|
)
|
|
self._capture_button(
|
|
pos=(h_offs, v - 0.95 * dist),
|
|
color=d_color,
|
|
button='buttonDown',
|
|
texture=ba.gettexture('downButton'),
|
|
scale=1.0,
|
|
)
|
|
|
|
if self._unique_id == '#2':
|
|
self._capture_button(
|
|
pos=(self._width * 0.5, v + 0.1 * dist),
|
|
color=(0.4, 0.4, 0.6),
|
|
button='buttonStart',
|
|
texture=ba.gettexture('startButton'),
|
|
scale=0.8,
|
|
)
|
|
|
|
h_offs = self._width - 160
|
|
|
|
self._capture_button(
|
|
pos=(h_offs, v + 0.95 * dist),
|
|
color=(0.6, 0.4, 0.8),
|
|
button='buttonPickUp',
|
|
texture=ba.gettexture('buttonPickUp'),
|
|
scale=1.0,
|
|
)
|
|
self._capture_button(
|
|
pos=(h_offs - 1.2 * dist, v),
|
|
color=(0.7, 0.5, 0.1),
|
|
button='buttonPunch',
|
|
texture=ba.gettexture('buttonPunch'),
|
|
scale=1.0,
|
|
)
|
|
self._capture_button(
|
|
pos=(h_offs + 1.2 * dist, v),
|
|
color=(0.5, 0.2, 0.1),
|
|
button='buttonBomb',
|
|
texture=ba.gettexture('buttonBomb'),
|
|
scale=1.0,
|
|
)
|
|
self._capture_button(
|
|
pos=(h_offs, v - 0.95 * dist),
|
|
color=(0.2, 0.5, 0.2),
|
|
button='buttonJump',
|
|
texture=ba.gettexture('buttonJump'),
|
|
scale=1.0,
|
|
)
|
|
|
|
def _capture_button(
|
|
self,
|
|
pos: tuple[float, float],
|
|
color: tuple[float, float, float],
|
|
texture: ba.Texture,
|
|
button: str,
|
|
scale: float = 1.0,
|
|
) -> None:
|
|
base_size = 79
|
|
btn = ba.buttonwidget(
|
|
parent=self._root_widget,
|
|
autoselect=True,
|
|
position=(
|
|
pos[0] - base_size * 0.5 * scale,
|
|
pos[1] - base_size * 0.5 * scale,
|
|
),
|
|
size=(base_size * scale, base_size * scale),
|
|
texture=texture,
|
|
label='',
|
|
color=color,
|
|
)
|
|
|
|
# Do this deferred so it shows up on top of other buttons. (ew.)
|
|
def doit() -> None:
|
|
if not self._root_widget:
|
|
return
|
|
uiscale = 0.66 * scale * 2.0
|
|
maxwidth = 76.0 * scale
|
|
txt = ba.textwidget(
|
|
parent=self._root_widget,
|
|
position=(pos[0] + 0.0 * scale, pos[1] - (57.0 - 18.0) * scale),
|
|
color=(1, 1, 1, 0.3),
|
|
size=(0, 0),
|
|
h_align='center',
|
|
v_align='top',
|
|
scale=uiscale,
|
|
maxwidth=maxwidth,
|
|
text=self._input.get_button_name(self._settings[button]),
|
|
)
|
|
ba.buttonwidget(
|
|
edit=btn,
|
|
autoselect=True,
|
|
on_activate_call=ba.Call(
|
|
AwaitKeyboardInputWindow, button, txt, self._settings
|
|
),
|
|
)
|
|
|
|
ba.pushcall(doit)
|
|
|
|
def _cancel(self) -> None:
|
|
from bastd.ui.settings.controls import ControlsSettingsWindow
|
|
|
|
ba.containerwidget(edit=self._root_widget, transition='out_right')
|
|
ba.app.ui.set_main_menu_window(
|
|
ControlsSettingsWindow(transition='in_left').get_root_widget()
|
|
)
|
|
|
|
def _save(self) -> None:
|
|
from bastd.ui.settings.controls import ControlsSettingsWindow
|
|
from ba.internal import (
|
|
get_input_device_config,
|
|
should_submit_debug_info,
|
|
master_server_post,
|
|
)
|
|
|
|
ba.containerwidget(edit=self._root_widget, transition='out_right')
|
|
ba.playsound(ba.getsound('gunCocking'))
|
|
|
|
# There's a chance the device disappeared; handle that gracefully.
|
|
if not self._input:
|
|
return
|
|
|
|
dst = get_input_device_config(self._input, default=False)
|
|
dst2: dict[str, Any] = dst[0][dst[1]]
|
|
dst2.clear()
|
|
|
|
# Store any values that aren't -1.
|
|
for key, val in list(self._settings.items()):
|
|
if val != -1:
|
|
dst2[key] = val
|
|
|
|
# If we're allowed to phone home, send this config so we can generate
|
|
# more defaults in the future.
|
|
if should_submit_debug_info():
|
|
master_server_post(
|
|
'controllerConfig',
|
|
{
|
|
'ua': ba.app.user_agent_string,
|
|
'name': self._name,
|
|
'b': ba.app.build_number,
|
|
'config': dst2,
|
|
'v': 2,
|
|
},
|
|
)
|
|
ba.app.config.apply_and_commit()
|
|
ba.app.ui.set_main_menu_window(
|
|
ControlsSettingsWindow(transition='in_left').get_root_widget()
|
|
)
|
|
|
|
|
|
class AwaitKeyboardInputWindow(ba.Window):
|
|
"""Window for capturing a keypress."""
|
|
|
|
def __init__(self, button: str, ui: ba.Widget, settings: dict):
|
|
|
|
self._capture_button = button
|
|
self._capture_key_ui = ui
|
|
self._settings = settings
|
|
|
|
width = 400
|
|
height = 150
|
|
uiscale = ba.app.ui.uiscale
|
|
super().__init__(
|
|
root_widget=ba.containerwidget(
|
|
size=(width, height),
|
|
transition='in_right',
|
|
scale=(
|
|
2.0
|
|
if uiscale is ba.UIScale.SMALL
|
|
else 1.5
|
|
if uiscale is ba.UIScale.MEDIUM
|
|
else 1.0
|
|
),
|
|
)
|
|
)
|
|
ba.textwidget(
|
|
parent=self._root_widget,
|
|
position=(0, height - 60),
|
|
size=(width, 25),
|
|
text=ba.Lstr(resource='pressAnyKeyText'),
|
|
h_align='center',
|
|
v_align='top',
|
|
)
|
|
|
|
self._counter = 5
|
|
self._count_down_text = ba.textwidget(
|
|
parent=self._root_widget,
|
|
h_align='center',
|
|
position=(0, height - 110),
|
|
size=(width, 25),
|
|
color=(1, 1, 1, 0.3),
|
|
text=str(self._counter),
|
|
)
|
|
self._decrement_timer: ba.Timer | None = ba.Timer(
|
|
1.0, self._decrement, repeat=True, timetype=ba.TimeType.REAL
|
|
)
|
|
ba.internal.capture_keyboard_input(ba.WeakCall(self._button_callback))
|
|
|
|
def __del__(self) -> None:
|
|
ba.internal.release_keyboard_input()
|
|
|
|
def _die(self) -> None:
|
|
# This strong-refs us; killing it allows us to die now.
|
|
self._decrement_timer = None
|
|
if self._root_widget:
|
|
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
|
|
|
def _button_callback(self, event: dict[str, Any]) -> None:
|
|
self._settings[self._capture_button] = event['button']
|
|
if event['type'] == 'BUTTONDOWN':
|
|
bname = event['input_device'].get_button_name(event['button'])
|
|
ba.textwidget(edit=self._capture_key_ui, text=bname)
|
|
ba.playsound(ba.getsound('gunCocking'))
|
|
self._die()
|
|
|
|
def _decrement(self) -> None:
|
|
self._counter -= 1
|
|
if self._counter >= 1:
|
|
ba.textwidget(edit=self._count_down_text, text=str(self._counter))
|
|
else:
|
|
self._die()
|