@@ -74,6 +74,75 @@ def get_displayed_option_at_idx(idx: int) -> BaseOption:
74
74
return option_stack [- 1 ].drawn_options [idx ]
75
75
76
76
77
+ def any_option_visible (options : Sequence [BaseOption ]) -> bool :
78
+ """
79
+ Recursively checks if any option in a sequence is visible.
80
+
81
+ Recurses into grouped options, but not nested ones. A grouped option which is not explicitly
82
+ hidden, but contains no visible children, does not count as visible.
83
+
84
+ Args:
85
+ options: The sequence of options to check.
86
+ """
87
+ return any (
88
+ (
89
+ isinstance (option , GroupedOption )
90
+ and not option .is_hidden
91
+ and any_option_visible (option .children )
92
+ )
93
+ or (not option .is_hidden )
94
+ for option in options
95
+ )
96
+
97
+
98
+ def draw_grouped_option (
99
+ self : UObject ,
100
+ options : Sequence [BaseOption ],
101
+ group_stack : list [GroupedOption ],
102
+ option : GroupedOption ,
103
+ options_idx : int ,
104
+ ) -> None :
105
+ """
106
+ Draws a grouped option and it's children.
107
+
108
+ Args:
109
+ self: The options menu being drawn.
110
+ options: The full options list this group is part of.
111
+ group_stack: The stack of currently open grouped options.
112
+ option: The specific grouped option to add.
113
+ options_idx: The index of the specific grouped option being added.
114
+ """
115
+ if not any_option_visible (option .children ):
116
+ return
117
+
118
+ group_stack .append (option )
119
+
120
+ # If the first entry of the group is another group, don't draw a title, let the nested call do
121
+ # it, so the first title is the most nested
122
+ # If we're empty, or a different type, draw our own header
123
+ if len (option .children ) == 0 or not isinstance (option .children [0 ], GroupedOption ):
124
+ add_title (self , " - " .join (g .display_name for g in group_stack ))
125
+ option_stack [- 1 ].drawn_options .append (option )
126
+
127
+ draw_options (self , option .children , group_stack )
128
+
129
+ group_stack .pop ()
130
+
131
+ # If we didn't just close the outermost group, the group above us still has extra visible
132
+ # options, and the next one of those options is not another group, re-draw the outer group's
133
+ # header
134
+ if (
135
+ group_stack
136
+ and options_idx != len (options ) - 1
137
+ and any_option_visible (options [options_idx + 1 :])
138
+ and not isinstance (options [options_idx + 1 ], GroupedOption )
139
+ ):
140
+ # This will print an empty string if we're on the last stack - which is about
141
+ # the best we can do, we still want a gap
142
+ add_title (self , " - " .join (g .display_name for g in group_stack ))
143
+ option_stack [- 1 ].drawn_options .append (option )
144
+
145
+
77
146
def draw_options ( # noqa: C901 - imo the match is rated too highly
78
147
self : UObject ,
79
148
options : Sequence [BaseOption ],
@@ -152,26 +221,7 @@ def draw_options( # noqa: C901 - imo the match is rated too highly
152
221
case GroupedOption () if option in group_stack :
153
222
logging .dev_warning (f"Found recursive options group, not drawing: { option } " )
154
223
case GroupedOption ():
155
- group_stack .append (option )
156
-
157
- # If the first entry of the group is another group, don't draw a title, let the
158
- # nested call do it, so the first title is the most nested
159
- # If we're empty, or a different type, draw our own header
160
- if len (option .children ) == 0 or not isinstance (option .children [0 ], GroupedOption ):
161
- add_title (self , " - " .join (g .display_name for g in group_stack ))
162
- option_stack [- 1 ].drawn_options .append (option )
163
-
164
- draw_options (self , option .children , group_stack )
165
-
166
- group_stack .pop ()
167
-
168
- # If we have more options left in this group, and we're not immediately followed by
169
- # another group, re-draw the base header
170
- if idx != len (options ) - 1 and not isinstance (options [idx + 1 ], GroupedOption ):
171
- # This will print an empty string if we're on the last stack - which is about
172
- # the best we can do, we still want a gap
173
- add_title (self , " - " .join (g .display_name for g in group_stack ))
174
- option_stack [- 1 ].drawn_options .append (option )
224
+ draw_grouped_option (self , options , group_stack , option , idx )
175
225
176
226
case _:
177
227
logging .dev_warning (f"Encountered unknown option type { type (option )} " )
@@ -357,7 +407,7 @@ def open_nested_options_menu(nested: NestedOption) -> None:
357
407
)
358
408
359
409
360
- @hook ("/Script/OakGame.GFxFrontendMenu:OnMenuStackChanged" , Type .POST , auto_enable = True )
410
+ @hook ("/Script/OakGame.GFxFrontendMenu:OnMenuStackChanged" , Type .POST , immediately_enable = True )
361
411
def frontend_menu_change_hook (
362
412
_1 : UObject ,
363
413
args : WrappedStruct ,
0 commit comments