Skip to content

Commit 4f25b1b

Browse files
authored
Merge pull request #6 from apple1417/master
mod menu improvements
2 parents 7ab4ad3 + 0e16c55 commit 4f25b1b

File tree

6 files changed

+116
-13
lines changed

6 files changed

+116
-13
lines changed

.cruft.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"template": "[email protected]:bl-sdk/common_dotfiles.git",
3-
"commit": "597ec422d3b5692927f325b9b5c2ae42288e8cc5",
3+
"commit": "91563903c1b88e5cc2363d448e62180fdb318382",
44
"checkout": null,
55
"context": {
66
"cookiecutter": {
@@ -15,7 +15,8 @@
1515
"__project_slug": "willow1_mod_manager",
1616
"include_cpp": true,
1717
"include_py": true,
18-
"_template": "[email protected]:bl-sdk/common_dotfiles.git"
18+
"_template": "[email protected]:bl-sdk/common_dotfiles.git",
19+
"_commit": "91563903c1b88e5cc2363d448e62180fdb318382"
1920
}
2021
},
2122
"directory": null

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
.vs
22
.vscode
33
.idea
4+
.nvim.lua
45

56
# C/C++ excludes
67
.cache/clangd

changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## v2.2 (Upcoming)
4+
### Willow1 Mod Menu v1.2
5+
- Now properly keeps track of what item you selected when opening a nested menu, and returns to that
6+
item when you close it.
7+
- Tried to improve how fraction slider option values are displayed.
8+
39
## v2.1: Orion
410
### Willow1 Mod Menu v1.1
511
- Fixed that Boolean and Slider options didn't properly detect changes.

src/willow1_mod_menu/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"__version_info__",
99
]
1010

11-
__version_info__: tuple[int, int] = (1, 1)
11+
__version_info__: tuple[int, int] = (1, 2)
1212
__version__: str = f"{__version_info__[0]}.{__version_info__[1]}"
1313
__author__: str = "bl-sdk"
1414

src/willow1_mod_menu/options.py

Lines changed: 103 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from mods_base import Mod, NestedOption, hook, html_to_plain_text
1414

1515
from .lobby import open_lobby_mods_menu
16-
from .util import find_focused_item
16+
from .util import ASType, find_focused_item
1717

1818
if TYPE_CHECKING:
1919
from .populators import Populator
@@ -22,9 +22,12 @@
2222
CUSTOM_OPTIONS_MENU_TAG = "willow1-mod-menu:custom-option"
2323
CUSTOM_KEYBINDS_MENU_TAG = "willow1-mod-menu:custom-keybinds"
2424

25-
RE_SELECTED_IDX = re.compile(r"^_level\d+\.(menu\.selections|content)\.mMenu\.mList\.item(\d+)$")
25+
RE_SELECTED_IDX = re.compile(
26+
r"^(?P<list>_level\d+\.(?:menu\.selections|content)\.mMenu\.mList)\.item(?P<idx>\d+)$",
27+
)
2628

2729
populator_stack: list[Populator] = []
30+
nested_selection_stack: list[tuple[str, float]] = []
2831

2932

3033
def create_mod_list_options_menu(menu: WillowGFxMenu) -> None:
@@ -47,6 +50,8 @@ def create_mod_options_menu(menu: WillowGFxMenu, mod: Mod) -> None:
4750
mod: The mod to create the options menu for.
4851
"""
4952
populator_stack.append(ModOptionPopulator(mod.name, mod=mod))
53+
if menu.Class.Name == "WillowGFxMenuPause":
54+
push_nested_selection(menu)
5055
open_new_generic_menu(menu)
5156

5257

@@ -59,6 +64,7 @@ def create_nested_options_menu(menu: WillowGFxMenu, option: NestedOption) -> Non
5964
option: The options whose children to create a menu for.
6065
"""
6166
populator_stack.append(OptionPopulator(option.display_name, option.children))
67+
push_nested_selection(menu)
6268
open_new_generic_menu(menu)
6369

6470

@@ -69,11 +75,30 @@ def create_keybinds_menu(menu: WillowGFxMenu) -> None:
6975
Args:
7076
menu: The current menu to create the new one under.
7177
"""
78+
push_nested_selection(menu)
7279
create_keybinds_menu_impl(menu)
7380

7481

7582
# ==================================================================================================
7683

84+
85+
def push_nested_selection(menu: WillowGFxMenu) -> None:
86+
"""
87+
Pushes the currently selected item to the stack, so it can be restored when this menu is closed.
88+
89+
Args:
90+
menu: The current menu to retrieve the selected item from
91+
"""
92+
item = find_focused_item(menu)
93+
if (match := RE_SELECTED_IDX.match(item)) is None:
94+
# Just default to 0
95+
y = 0
96+
else:
97+
y = menu.GetVariableNumber(match.group("list") + "._y")
98+
99+
nested_selection_stack.append((item, y))
100+
101+
77102
# Avoid circular imports
78103
from .populators import LOCKED_KEY_PREFIX # noqa: E402
79104
from .populators.mod_list import ModListPopulator # noqa: E402
@@ -185,7 +210,7 @@ def get_selected_idx(menu: WillowGFxMenu) -> int | None:
185210
return None
186211

187212
try:
188-
return int(match.group(2))
213+
return int(match.group("idx"))
189214
except ValueError:
190215
return None
191216

@@ -278,17 +303,60 @@ def generic_screen_deactivate(
278303
if populator_stack:
279304
# If we have screens left, we can't immediately redraw them here, need to wait a little
280305
reactivate_upper_screen.enable()
306+
else:
307+
# Sanity check: the selection stack should also be clear now
308+
nested_selection_stack.clear()
281309

282-
elif (owner := obj.MenuOwner).Class.Name == "WillowGFxMenuFrontend":
283-
# We had screens, but don't anymore, and came from the frontend menu
284-
# Re-draw the lobby mods screen so we back out into it
285-
open_lobby_mods_menu(owner)
310+
if (owner := obj.MenuOwner).Class.Name == "WillowGFxMenuFrontend":
311+
# We had screens, but don't anymore, and came from the frontend menu
312+
# Re-draw the lobby mods screen so we back out into it
313+
open_lobby_mods_menu(owner)
286314

287315
# If we closed the last screen, can remove our hook
288316
if not populator_stack:
289317
play_sound.disable()
290318

291319

320+
# When you back out of a nested menu, we need to wait a few ticks before we can set your selection
321+
# back to what it was before
322+
reselect_nested_info: tuple[WeakPointer, str, int, float, float] | None = None
323+
324+
325+
@hook("GearboxFramework.GearboxGFxMovie:OnTick")
326+
def reselect_nested_next_tick(
327+
obj: UObject,
328+
_args: WrappedStruct,
329+
_ret: Any,
330+
_func: BoundFunction,
331+
) -> None:
332+
global reselect_nested_info
333+
if reselect_nested_info is None:
334+
reselect_nested_next_tick.disable()
335+
return
336+
337+
weak_menu, list_name, idx, y, original_tick_rate = reselect_nested_info
338+
if (menu := weak_menu()) is None:
339+
reselect_nested_next_tick.disable()
340+
return
341+
342+
# Ignore ticks from other movies, and wait for this menu to start up enough to focus something
343+
if obj != menu or not find_focused_item(menu):
344+
return
345+
346+
reselect_nested_next_tick.disable()
347+
reselect_nested_info = None
348+
349+
menu.SetVariableNumber(list_name + "._y", y)
350+
351+
invoke = menu.Invoke
352+
invoke_args = WrappedStruct(invoke.func)
353+
invoke_args.Method = list_name + ".setSelectedItem"
354+
invoke_args.args.emplace_struct(Type=ASType.AS_Number, N=idx)
355+
invoke(invoke_args)
356+
357+
menu.TickRateSeconds = original_tick_rate
358+
359+
292360
@hook("WillowGame.WillowGFxMenu:ActivateTopPage", hook_type=Type.POST)
293361
def reactivate_upper_screen(
294362
obj: UObject,
@@ -299,6 +367,34 @@ def reactivate_upper_screen(
299367
reactivate_upper_screen.disable()
300368
draw_custom_menu(obj)
301369

370+
if nested_selection_stack:
371+
item, y = nested_selection_stack.pop()
372+
if not item:
373+
# May happen if getting focus failed
374+
return
375+
376+
match = RE_SELECTED_IDX.match(item)
377+
if match is None:
378+
return
379+
try:
380+
idx = int(match.group("idx"))
381+
except ValueError:
382+
return
383+
384+
global reselect_nested_info
385+
reselect_nested_info = (
386+
WeakPointer(obj),
387+
match.group("list"),
388+
idx,
389+
y,
390+
obj.TickRateSeconds,
391+
)
392+
393+
# Default tickrate is very slow
394+
obj.TickRateSeconds = 1 / 60
395+
396+
reselect_nested_next_tick.enable()
397+
302398

303399
# ==================================================================================================
304400

@@ -321,7 +417,6 @@ def create_keybinds_menu_impl(obj: WillowGFxMenu) -> None:
321417

322418
obj.ScreenStack.append(keybinds_frame)
323419
obj.ActivateTopPage(0)
324-
obj.PlayUISound("Confirm")
325420

326421

327422
@hook("WillowGame.WillowGFxMenuScreenFrameKeyBinds:InitFrame")

src/willow1_mod_menu/populators/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,10 @@ def format_slider_label(option: SliderOption) -> str:
142142
The formatted label.
143143
"""
144144
value = option.value
145-
if option.is_integer or abs(option.step) > 1:
145+
if option.is_integer:
146146
value = round(value)
147147

148-
return f"{option.display_name}: {value}"
148+
return f"{option.display_name}: {value:g}"
149149

150150
def draw_slider(
151151
self,

0 commit comments

Comments
 (0)