Files
libstorm-nvgt/menu_helpers.nvgt
2026-02-22 19:18:47 -05:00

153 lines
4.6 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;
}