Mercurial > repos > blastem
changeset 2616:cbf5a01e429e
Add an HTML/JS file picker to web build
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 21 Feb 2025 00:45:14 -0800 |
parents | cbd54de385d3 |
children | ad9e074c8901 |
files | Makefile nuklear_ui/blastem_nuklear.c |
diffstat | 2 files changed, 122 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Mon Feb 17 23:40:36 2025 -0800 +++ b/Makefile Fri Feb 21 00:45:14 2025 -0800 @@ -119,7 +119,7 @@ ifeq ($(CPU),wasm) CFLAGS+= --use-port=sdl2 -LDFLAGS+= --use-port=sdl2 --embed-file rom.db --embed-file default.cfg --embed-file systems.cfg --embed-file shaders/ --embed-file images/ --embed-file DroidSans.ttf --embed-file roms/ +LDFLAGS+= --use-port=sdl2 --embed-file rom.db --embed-file default.cfg --embed-file systems.cfg --embed-file shaders/ --embed-file images/ --embed-file DroidSans.ttf -sEXPORTED_FUNCTIONS=_main,_handle_chooser_result -sEXPORTED_RUNTIME_METHODS=ccall,cwrap EXE:=.html else #CPU=wasm
--- a/nuklear_ui/blastem_nuklear.c Mon Feb 17 23:40:36 2025 -0800 +++ b/nuklear_ui/blastem_nuklear.c Fri Feb 21 00:45:14 2025 -0800 @@ -105,9 +105,87 @@ static const char **browser_ext_list; static uint32_t browser_num_exts; static uint8_t use_native_filechooser; +#ifdef __EMSCRIPTEN__ +#include <emscripten.h> +static uint8_t chooser_open; -static void handle_chooser_result(uint8_t normal_open, char *full_path) +EM_JS(void, show_html_chooser, (const char *title, const char *extensions, int normal_open, int is_settings), { + let container = document.getElementById('chooser'); + let canvas = document.getElementById('canvas'); + let fileIn = null; + let titleEl = null; + if (!container) { + container = document.createElement('div'); + container.id = 'chooser'; + container.style.position = 'absolute'; + container.style.display = 'none'; + container.style.borderWidth = '2px'; + container.style.borderColor = 'black'; + titleEl = document.createElement('h3'); + titleEl.id = 'chooser_title'; + container.appendChild(titleEl); + fileIn = document.createElement('input'); + fileIn.type = 'file'; + fileIn.id = 'file'; + container.appendChild(fileIn); + canvas.parentNode.appendChild(container); + } else { + fileIn = document.getElementById('file'); + titleEl = document.getElementById('chooser_title'); + } + titleEl.innerText = UTF8ToString(title); + fileIn.onchange = (event) => { + let f = event.target; + if (f.files.length) { + let reader = new FileReader(); + let name = f.files[0].name; + reader.onload = (event) => { + let prefix = '/roms'; + let prevPath = null; + if (normal_open) { + prevPath = 'previousRomPath'; + } else if (is_settings) { + prefix = '/firmware'; + } else { + prevPath = 'previousSpecialPath'; + } + if (prevPath && window[prevPath]) { + FS.unlink(window[prevPath]); + } else { + FS.mkdir(prefix); + } + + let buffer = new Uint8Array(event.target.result); + FS.createDataFile(prefix, name, buffer, true, false, false); + let fullPath = prefix + "/" + name; + if (prevPath) { + window[prevPath] = fullPath; + } + console.log(fullPath, normal_open, is_settings); + document.getElementById('chooser').style.display = 'none'; + Module.ccall('handle_chooser_result', 'void', ['number', 'string'], [normal_open, fullPath]); + }; + reader.readAsArrayBuffer(f.files[0]); + } + }; + fileIn.accept = UTF8ToString(extensions); + let cRect = canvas.getBoundingClientRect(); + let pRect = canvas.parentNode.parentNode.getBoundingClientRect(); + container.style.top = '' + (cRect.top - pRect.top) + 'px'; + container.style.left = '' + (cRect.left - pRect.left) + 'px'; + container.style.width = '' + cRect.width + 'px'; + container.style.height = '' + cRect.height + 'px'; + container.style.display = 'block'; + container.style.backgroundColor = 'white'; +}); +#endif + +void handle_chooser_result(uint8_t normal_open, char *full_path) { +#ifdef __EMSCRIPTEN__ + chooser_open = 0; + full_path = strdup(full_path); +#endif if(normal_open) { lockon_media(NULL); if (current_system) { @@ -134,12 +212,49 @@ void view_file_browser(struct nk_context *context, uint8_t normal_open) { + static const char **ext_list; + static uint32_t num_exts; + static uint8_t got_ext_list; + if (!browser_ext_list) { + if (!got_ext_list) { + ext_list = (const char **)get_extension_list(config, &num_exts); + got_ext_list = 1; + } + browser_ext_list = ext_list; + browser_num_exts = num_exts; + } +#ifdef __EMSCRIPTEN__ + uint8_t just_opened = !chooser_open; + chooser_open = 1; + if (just_opened) { + size_t total_length = 0; + for (uint32_t i = 0; i < browser_num_exts; i++) + { + total_length += 1 + strlen(browser_ext_list[i]); + if (i) { + total_length++; + } + } + char *list = calloc(total_length + 1, 1); + char *cur = list; + for (uint32_t i = 0; i < browser_num_exts; i++) + { + if (i) { + *(cur++) = ','; + } + *(cur++) = '.'; + size_t len = strlen(browser_ext_list[i]); + memcpy(cur, browser_ext_list[i], len); + cur += len; + } + *(cur) = 0; + show_html_chooser(browser_label, list, normal_open, browser_setting_path != NULL); + free(list); + } +#else static dir_entry *entries; static size_t num_entries; static int32_t selected_entry = -1; - static const char **ext_list; - static uint32_t num_exts; - static uint8_t got_ext_list; if (!browser_cur_path) { get_initial_browse_path(&browser_cur_path); } @@ -170,14 +285,6 @@ num_entries = 1; } } - if (!browser_ext_list) { - if (!got_ext_list) { - ext_list = (const char **)get_extension_list(config, &num_exts); - got_ext_list = 1; - } - browser_ext_list = ext_list; - browser_num_exts = num_exts; - } uint32_t width = render_width(); uint32_t height = render_height(); if (nk_begin(context, "Load ROM", nk_rect(0, 0, width, height), 0)) { @@ -228,6 +335,8 @@ } nk_end(context); } +#endif + } void view_load(struct nk_context *context)