Mercurial > repos > blastem
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"; |