Files
libstorm-nvgt/menu_helpers.nvgt
2026-02-16 19:49:29 -05:00

123 lines
3.9 KiB
Plaintext

#include "menu.nvgt"
#include "audio_paths.nvgt"
// Applies common menu sounds from a directory.
// Looks for both .ogg and .wav files automatically.
void menu_apply_default_sounds(menu@ menuRef, const string soundDir = "sounds/menu") {
if (@menuRef is null) {
return;
}
menuRef.click_sound = resolve_audio_path(soundDir + "/menu_move");
menuRef.select_sound = resolve_audio_path(soundDir + "/menu_select");
menuRef.edge_sound = resolve_audio_path(soundDir + "/menu_edge");
menuRef.wrap_sound = resolve_audio_path(soundDir + "/menu_wrap");
menuRef.open_sound = resolve_audio_path(soundDir + "/menu_open");
menuRef.close_sound = resolve_audio_path(soundDir + "/menu_close");
}
// Minimal blocking list menu.
// Returns selected index or -1 on empty input/escape.
int menu_run_simple(const string introText, string[]@ options, bool wrap = true, int startIndex = 0, const string soundDir = "sounds/menu") {
if (@options is null || options.length() == 0) {
return -1;
}
menu menuRef;
menu_apply_default_sounds(menuRef, soundDir);
menuRef.intro_text = introText;
menuRef.wrap = wrap;
menuRef.focus_first_item = true;
menuRef.add_items(options);
if (startIndex >= 0 && startIndex < int(options.length())) {
menuRef.focused_item = startIndex;
}
return menuRef.run();
}
// Returns a-z for menu prefix filtering, or empty string when no letter key was pressed.
string menu_get_filter_letter() {
if (key_pressed(KEY_A)) return "a";
if (key_pressed(KEY_B)) return "b";
if (key_pressed(KEY_C)) return "c";
if (key_pressed(KEY_D)) return "d";
if (key_pressed(KEY_E)) return "e";
if (key_pressed(KEY_F)) return "f";
if (key_pressed(KEY_G)) return "g";
if (key_pressed(KEY_H)) return "h";
if (key_pressed(KEY_I)) return "i";
if (key_pressed(KEY_J)) return "j";
if (key_pressed(KEY_K)) return "k";
if (key_pressed(KEY_L)) return "l";
if (key_pressed(KEY_M)) return "m";
if (key_pressed(KEY_N)) return "n";
if (key_pressed(KEY_O)) return "o";
if (key_pressed(KEY_P)) return "p";
if (key_pressed(KEY_Q)) return "q";
if (key_pressed(KEY_R)) return "r";
if (key_pressed(KEY_S)) return "s";
if (key_pressed(KEY_T)) return "t";
if (key_pressed(KEY_U)) return "u";
if (key_pressed(KEY_V)) return "v";
if (key_pressed(KEY_W)) return "w";
if (key_pressed(KEY_X)) return "x";
if (key_pressed(KEY_Y)) return "y";
if (key_pressed(KEY_Z)) return "z";
return "";
}
// Applies a prefix filter to menu options.
void menu_apply_prefix_filter(const string &in filterText, const string[]@ options, int[]@ filteredIndices, string[]@ filteredOptions) {
filteredIndices.resize(0);
filteredOptions.resize(0);
if (@options is null) {
return;
}
string filterLower = filterText.lower();
for (uint optionIndex = 0; optionIndex < options.length(); optionIndex++) {
if (filterLower.length() == 0) {
filteredIndices.insert_last(optionIndex);
filteredOptions.insert_last(options[optionIndex]);
continue;
}
string optionLower = options[optionIndex].lower();
if (optionLower.length() >= filterLower.length() && optionLower.substr(0, filterLower.length()) == filterLower) {
filteredIndices.insert_last(optionIndex);
filteredOptions.insert_last(options[optionIndex]);
}
}
}
// Updates filter text from keyboard input and reapplies filtering.
bool menu_update_prefix_filter(string &inout filterText, const string[]@ options, int[]@ filteredIndices, string[]@ filteredOptions, int &inout selection) {
bool filterChanged = false;
if (key_pressed(KEY_BACK) && filterText.length() > 0) {
filterText = filterText.substr(0, filterText.length() - 1);
filterChanged = true;
}
string filterLetter = menu_get_filter_letter();
if (filterLetter != "") {
filterText += filterLetter;
filterChanged = true;
}
if (filterChanged) {
menu_apply_prefix_filter(filterText, options, filteredIndices, filteredOptions);
if (selection < 0) {
selection = 0;
}
if (selection >= int(filteredOptions.length())) {
selection = 0;
}
}
return filterChanged;
}