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

205 lines
5.7 KiB
Plaintext

#include "audio_paths.nvgt"
#include "file_viewer.nvgt"
funcdef void docs_browser_speak_callback(const string &in message, bool interrupt);
funcdef void docs_browser_tick_callback();
docs_browser_speak_callback@ docsBrowserSpeakCallback = null;
docs_browser_tick_callback@ docsBrowserTickCallback = null;
string docsBrowserDirectory = "files";
string docsBrowserMenuSoundDir = "sounds/menu";
bool docsBrowserWrap = true;
string[] docsBrowserExtensions = {"md", "MD", "txt", "TXT"};
sound docsBrowserMoveSound;
sound docsBrowserSelectSound;
void docs_browser_set_speak_callback(docs_browser_speak_callback@ callback) {
@docsBrowserSpeakCallback = @callback;
}
void docs_browser_set_tick_callback(docs_browser_tick_callback@ callback) {
@docsBrowserTickCallback = @callback;
}
void docs_browser_set_docs_dir(const string docsDir) {
docsBrowserDirectory = docsDir;
}
void docs_browser_set_menu_sound_dir(const string menuSoundDir) {
docsBrowserMenuSoundDir = menuSoundDir;
}
void docs_browser_set_wrap(bool wrap) {
docsBrowserWrap = wrap;
}
void docs_browser_set_extensions(string[]@ extensions) {
docsBrowserExtensions.resize(0);
if (@extensions is null) return;
for (uint extIndex = 0; extIndex < extensions.length(); extIndex++) {
docsBrowserExtensions.insert_last(extensions[extIndex]);
}
}
void docs_browser_reset_default_extensions() {
string[] defaults = {"md", "MD", "txt", "TXT"};
docs_browser_set_extensions(defaults);
}
void docs_browser_speak(const string &in message, bool interrupt) {
if (@docsBrowserSpeakCallback !is null) {
docsBrowserSpeakCallback(message, interrupt);
return;
}
screen_reader_speak(message, interrupt);
}
void docs_browser_tick() {
if (@docsBrowserTickCallback !is null) {
docsBrowserTickCallback();
}
}
bool docs_browser_sort_case_insensitive(const string &in a, const string &in b) {
return a.lower() < b.lower();
}
void docs_browser_append_unique_case_insensitive(string[]@ items, const string&in value) {
string lowerValue = value.lower();
for (uint itemIndex = 0; itemIndex < items.length(); itemIndex++) {
if (items[itemIndex].lower() == lowerValue) return;
}
items.insert_last(value);
}
string docs_browser_collapse_spaces(const string&in text) {
string result = text;
while (result.find_first(" ") > -1) {
result = result.replace(" ", " ", true);
}
return result;
}
string docs_browser_format_label(const string&in filename) {
string name = filename;
int dotPos = name.find_last_of(".");
if (dotPos > 0) {
name = name.substr(0, dotPos);
}
name = name.replace("_", " ", true);
name = name.replace("-", " ", true);
name = docs_browser_collapse_spaces(name);
name = name.lower();
name.trim_whitespace_this();
if (name.length() == 0) return "Document";
string first = name.substr(0, 1).upper();
if (name.length() == 1) return first;
return first + name.substr(1);
}
void docs_browser_collect_entries(string[]@ labels, string[]@ paths) {
labels.resize(0);
paths.resize(0);
if (!directory_exists(docsBrowserDirectory)) return;
string[] docFiles;
for (uint extIndex = 0; extIndex < docsBrowserExtensions.length(); extIndex++) {
string ext = docsBrowserExtensions[extIndex];
if (ext == "") continue;
if (ext.substr(0, 1) == ".") {
ext = ext.substr(1);
}
string[]@ found = find_files(docsBrowserDirectory + "/*." + ext);
if (@found is null) continue;
for (uint fileIndex = 0; fileIndex < found.length(); fileIndex++) {
docs_browser_append_unique_case_insensitive(docFiles, found[fileIndex]);
}
}
if (docFiles.length() > 1) {
docFiles.sort(docs_browser_sort_case_insensitive);
}
for (uint fileIndex = 0; fileIndex < docFiles.length(); fileIndex++) {
labels.insert_last(docs_browser_format_label(docFiles[fileIndex]));
paths.insert_last(docsBrowserDirectory + "/" + docFiles[fileIndex]);
}
}
void docs_browser_add_entries(string[]@ labels, string[]@ paths, int[]@ types, const int typeValue = 1) {
string[] docLabels;
string[] docPaths;
docs_browser_collect_entries(docLabels, docPaths);
for (uint entryIndex = 0; entryIndex < docLabels.length(); entryIndex++) {
labels.insert_last(docLabels[entryIndex]);
paths.insert_last(docPaths[entryIndex]);
types.insert_last(typeValue);
}
}
void docs_browser_play_ui_sound(sound &inout soundObj, const string basePath) {
string soundPath = resolve_audio_path(basePath);
if (soundPath == "") return;
soundObj.close();
if (!soundObj.load(soundPath)) return;
soundObj.play();
}
void docs_browser_run_menu(const string menuTitle = "Documents") {
string[] labels;
string[] paths;
docs_browser_collect_entries(labels, paths);
docs_browser_speak(menuTitle + ".", true);
if (labels.length() == 0) {
docs_browser_speak("No documents found.", true);
return;
}
int selection = 0;
docs_browser_speak(labels[selection], true);
while (true) {
wait(5);
docs_browser_tick();
if (key_pressed(KEY_ESCAPE)) {
docs_browser_speak("Closed.", true);
return;
}
if (key_pressed(KEY_DOWN)) {
docs_browser_play_ui_sound(docsBrowserMoveSound, docsBrowserMenuSoundDir + "/menu_move");
selection++;
if (selection >= int(labels.length())) {
selection = docsBrowserWrap ? 0 : int(labels.length()) - 1;
}
docs_browser_speak(labels[selection], true);
}
if (key_pressed(KEY_UP)) {
docs_browser_play_ui_sound(docsBrowserMoveSound, docsBrowserMenuSoundDir + "/menu_move");
selection--;
if (selection < 0) {
selection = docsBrowserWrap ? int(labels.length()) - 1 : 0;
}
docs_browser_speak(labels[selection], true);
}
if (key_pressed(KEY_RETURN)) {
docs_browser_play_ui_sound(docsBrowserSelectSound, docsBrowserMenuSoundDir + "/menu_select");
file_viewer_file(paths[selection], labels[selection], true);
docs_browser_speak(labels[selection], true);
}
}
}