comparison nuklear_ui/blastem_nuklear.c @ 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 c768bbd912f1
children ad9e074c8901
comparison
equal deleted inserted replaced
2615:cbd54de385d3 2616:cbf5a01e429e
103 static const char *browser_label; 103 static const char *browser_label;
104 static const char *browser_setting_path; 104 static const char *browser_setting_path;
105 static const char **browser_ext_list; 105 static const char **browser_ext_list;
106 static uint32_t browser_num_exts; 106 static uint32_t browser_num_exts;
107 static uint8_t use_native_filechooser; 107 static uint8_t use_native_filechooser;
108 108 #ifdef __EMSCRIPTEN__
109 static void handle_chooser_result(uint8_t normal_open, char *full_path) 109 #include <emscripten.h>
110 { 110 static uint8_t chooser_open;
111
112 EM_JS(void, show_html_chooser, (const char *title, const char *extensions, int normal_open, int is_settings), {
113 let container = document.getElementById('chooser');
114 let canvas = document.getElementById('canvas');
115 let fileIn = null;
116 let titleEl = null;
117 if (!container) {
118 container = document.createElement('div');
119 container.id = 'chooser';
120 container.style.position = 'absolute';
121 container.style.display = 'none';
122 container.style.borderWidth = '2px';
123 container.style.borderColor = 'black';
124 titleEl = document.createElement('h3');
125 titleEl.id = 'chooser_title';
126 container.appendChild(titleEl);
127 fileIn = document.createElement('input');
128 fileIn.type = 'file';
129 fileIn.id = 'file';
130 container.appendChild(fileIn);
131 canvas.parentNode.appendChild(container);
132 } else {
133 fileIn = document.getElementById('file');
134 titleEl = document.getElementById('chooser_title');
135 }
136 titleEl.innerText = UTF8ToString(title);
137 fileIn.onchange = (event) => {
138 let f = event.target;
139 if (f.files.length) {
140 let reader = new FileReader();
141 let name = f.files[0].name;
142 reader.onload = (event) => {
143 let prefix = '/roms';
144 let prevPath = null;
145 if (normal_open) {
146 prevPath = 'previousRomPath';
147 } else if (is_settings) {
148 prefix = '/firmware';
149 } else {
150 prevPath = 'previousSpecialPath';
151 }
152 if (prevPath && window[prevPath]) {
153 FS.unlink(window[prevPath]);
154 } else {
155 FS.mkdir(prefix);
156 }
157
158 let buffer = new Uint8Array(event.target.result);
159 FS.createDataFile(prefix, name, buffer, true, false, false);
160 let fullPath = prefix + "/" + name;
161 if (prevPath) {
162 window[prevPath] = fullPath;
163 }
164 console.log(fullPath, normal_open, is_settings);
165 document.getElementById('chooser').style.display = 'none';
166 Module.ccall('handle_chooser_result', 'void', ['number', 'string'], [normal_open, fullPath]);
167 };
168 reader.readAsArrayBuffer(f.files[0]);
169 }
170 };
171 fileIn.accept = UTF8ToString(extensions);
172 let cRect = canvas.getBoundingClientRect();
173 let pRect = canvas.parentNode.parentNode.getBoundingClientRect();
174 container.style.top = '' + (cRect.top - pRect.top) + 'px';
175 container.style.left = '' + (cRect.left - pRect.left) + 'px';
176 container.style.width = '' + cRect.width + 'px';
177 container.style.height = '' + cRect.height + 'px';
178 container.style.display = 'block';
179 container.style.backgroundColor = 'white';
180 });
181 #endif
182
183 void handle_chooser_result(uint8_t normal_open, char *full_path)
184 {
185 #ifdef __EMSCRIPTEN__
186 chooser_open = 0;
187 full_path = strdup(full_path);
188 #endif
111 if(normal_open) { 189 if(normal_open) {
112 lockon_media(NULL); 190 lockon_media(NULL);
113 if (current_system) { 191 if (current_system) {
114 current_system->next_rom = full_path; 192 current_system->next_rom = full_path;
115 current_system->request_exit(current_system); 193 current_system->request_exit(current_system);
132 } 210 }
133 } 211 }
134 212
135 void view_file_browser(struct nk_context *context, uint8_t normal_open) 213 void view_file_browser(struct nk_context *context, uint8_t normal_open)
136 { 214 {
215 static const char **ext_list;
216 static uint32_t num_exts;
217 static uint8_t got_ext_list;
218 if (!browser_ext_list) {
219 if (!got_ext_list) {
220 ext_list = (const char **)get_extension_list(config, &num_exts);
221 got_ext_list = 1;
222 }
223 browser_ext_list = ext_list;
224 browser_num_exts = num_exts;
225 }
226 #ifdef __EMSCRIPTEN__
227 uint8_t just_opened = !chooser_open;
228 chooser_open = 1;
229 if (just_opened) {
230 size_t total_length = 0;
231 for (uint32_t i = 0; i < browser_num_exts; i++)
232 {
233 total_length += 1 + strlen(browser_ext_list[i]);
234 if (i) {
235 total_length++;
236 }
237 }
238 char *list = calloc(total_length + 1, 1);
239 char *cur = list;
240 for (uint32_t i = 0; i < browser_num_exts; i++)
241 {
242 if (i) {
243 *(cur++) = ',';
244 }
245 *(cur++) = '.';
246 size_t len = strlen(browser_ext_list[i]);
247 memcpy(cur, browser_ext_list[i], len);
248 cur += len;
249 }
250 *(cur) = 0;
251 show_html_chooser(browser_label, list, normal_open, browser_setting_path != NULL);
252 free(list);
253 }
254 #else
137 static dir_entry *entries; 255 static dir_entry *entries;
138 static size_t num_entries; 256 static size_t num_entries;
139 static int32_t selected_entry = -1; 257 static int32_t selected_entry = -1;
140 static const char **ext_list;
141 static uint32_t num_exts;
142 static uint8_t got_ext_list;
143 if (!browser_cur_path) { 258 if (!browser_cur_path) {
144 get_initial_browse_path(&browser_cur_path); 259 get_initial_browse_path(&browser_cur_path);
145 } 260 }
146 if (use_native_filechooser && native_filechooser_available()) { 261 if (use_native_filechooser && native_filechooser_available()) {
147 char *path = native_filechooser_pick(browser_label, browser_cur_path); 262 char *path = native_filechooser_pick(browser_label, browser_cur_path);
167 entries = calloc(1, sizeof(dir_entry)); 282 entries = calloc(1, sizeof(dir_entry));
168 entries[0].name = strdup(".."); 283 entries[0].name = strdup("..");
169 entries[0].is_dir = 1; 284 entries[0].is_dir = 1;
170 num_entries = 1; 285 num_entries = 1;
171 } 286 }
172 }
173 if (!browser_ext_list) {
174 if (!got_ext_list) {
175 ext_list = (const char **)get_extension_list(config, &num_exts);
176 got_ext_list = 1;
177 }
178 browser_ext_list = ext_list;
179 browser_num_exts = num_exts;
180 } 287 }
181 uint32_t width = render_width(); 288 uint32_t width = render_width();
182 uint32_t height = render_height(); 289 uint32_t height = render_height();
183 if (nk_begin(context, "Load ROM", nk_rect(0, 0, width, height), 0)) { 290 if (nk_begin(context, "Load ROM", nk_rect(0, 0, width, height), 0)) {
184 nk_layout_row_static(context, height - context->style.font->height * 3, width - 60, 1); 291 nk_layout_row_static(context, height - context->style.font->height * 3, width - 60, 1);
226 } 333 }
227 selected_entry = -1; 334 selected_entry = -1;
228 } 335 }
229 nk_end(context); 336 nk_end(context);
230 } 337 }
338 #endif
339
231 } 340 }
232 341
233 void view_load(struct nk_context *context) 342 void view_load(struct nk_context *context)
234 { 343 {
235 browser_label = "Select ROM"; 344 browser_label = "Select ROM";