add js save dialog

This commit is contained in:
2019-10-10 01:33:59 +02:00
parent a669d1313b
commit fd3eba69b8
5 changed files with 105 additions and 19 deletions

View File

@@ -167,7 +167,7 @@ public:
bool clipboard_set_text(const std::string& s);
void pick_image(std::function<void(std::string path)> callback);
void pick_file(std::vector<std::string> types, std::function<void(std::string path)> callback);
#if __IOS__
#if __IOS__ || __WEB__
void pick_file_save(const std::string& type, std::function<void(std::string path)> writer,
std::function<void(bool saved)> callback);
#else

View File

@@ -8,11 +8,15 @@
#include "node_about.h"
#include "node_changelog.h"
#include "node_usermanual.h"
#include "node_dialog_export_ppbr.h"
#ifdef __QUEST__
#include "oculus_vr.h"
#elif __WEB__
void webgl_pick_file(std::function<void(std::string)> callback);
void webgl_pick_file_save(const std::string& path,
const std::string& name, std::function<void(bool)> callback);
#endif
#include "node_dialog_export_ppbr.h"
std::shared_ptr<NodeProgressBar> App::show_progress(const std::string& title, int total /*= 0*/)
{
@@ -435,7 +439,8 @@ void App::dialog_export(std::string ext)
{
// TODO: use picker
auto path = work_path + "/" + doc_name + ext;
canvas->m_canvas->export_equirectangular(path, [this, path]{
auto name = doc_name + ext;
canvas->m_canvas->export_equirectangular(path, [this, path, name]{
#if defined(__IOS__)
message_box("Export Equirectangular", "Image exported to Photos");
#elif defined(__OSX__)
@@ -444,6 +449,10 @@ void App::dialog_export(std::string ext)
message_box("Export Equirectangular", "Image exported to " + work_path);
#elif defined(__QUEST__)
//auto result = ovr_Media_ShareToFacebook("Sharing from PanoPainter on Oculus Quest", path.c_str(), ovrMediaContentType_Photo);
#elif __WEB__
ui_task([=]{
webgl_pick_file_save(path, name, [](bool success){ });
});
#endif
});
}
@@ -609,7 +618,7 @@ void App::dialog_ppbr_export()
info.dest_path = dialog->m_dest_path;
if (dialog->export_check)
info.export_data = dialog->export_check->checked;
#if __IOS__
#if __IOS__ || __WEB__
App::I->pick_file_save("ppbr",
[this, dialog, info] (std::string path) {
presets->export_ppbr(path, info);

View File

@@ -19,6 +19,8 @@ std::string win32_clipboard_get_text();
#include <tinyfiledialogs.h>
#elif __WEB__
void webgl_pick_file(std::function<void(std::string)> callback);
void webgl_pick_file_save(const std::string& path,
const std::string& name, std::function<void(bool)> callback);
#endif
@@ -235,8 +237,18 @@ void App::pick_file_save(const std::string& type, std::function<void(std::string
mb->destroy();
};
}
#elif __WEB__
void App::pick_file_save(const std::string& type, std::function<void(std::string)> writer,
std::function<void(bool saved)> callback)
{
redraw = true;
auto path = data_path + "/file-save." + type;
LOG("App::pick_file_save %s", path.c_str());
writer(path);
webgl_pick_file_save(path, "file." + type, callback);
}
#else
void App::pick_file_save(std::vector<std::string> types, std::function<void (std::string)> callback)
void App::pick_file_save(std::vector<std::string> types, std::function<void(std::string)> callback)
{
redraw = true;
#if __OSX__

View File

@@ -14,15 +14,20 @@ GLFWwindow* wnd;
float theta = 0;
glm::vec2 g_cursor_pos;
template<typename F>
class TaskCallback
{
std::function<void(std::string)> fn;
std::function<F> fn;
public:
template<typename T> TaskCallback(T callback) : fn(callback) {}
void call(const std::string& tmp_file_path)
{
fn(tmp_file_path);
}
void call(bool success)
{
fn(success);
}
TaskCallback()
{
printf("callback created\n");
@@ -33,36 +38,64 @@ public:
}
};
void TaskCallback_call(uintptr_t tc, std::string tmp_file_path)
void TaskCallback_open_call(uintptr_t tc, std::string tmp_file_path)
{
auto x = reinterpret_cast<TaskCallback*>(tc);
auto x = reinterpret_cast<TaskCallback<void(std::string)>*>(tc);
x->call(tmp_file_path);
}
void TaskCallback_delete(uintptr_t tc)
void TaskCallback_open_delete(uintptr_t tc)
{
auto x = reinterpret_cast<TaskCallback*>(tc);
auto x = reinterpret_cast<TaskCallback<void(std::string)>*>(tc);
delete x;
}
void TaskCallback_save_call(uintptr_t tc, bool success)
{
auto x = reinterpret_cast<TaskCallback<void(bool)>*>(tc);
x->call(success);
}
void TaskCallback_save_delete(uintptr_t tc)
{
auto x = reinterpret_cast<TaskCallback<void(bool)>*>(tc);
delete x;
}
std::string UtilityGetString(uintptr_t s)
{
return *reinterpret_cast<std::string*>(s);
}
EMSCRIPTEN_BINDINGS(TaskCallback_bind) {
class_<TaskCallback>("TaskCallback");
function("TaskCallback_call", &TaskCallback_call);
function("TaskCallback_delete", &TaskCallback_delete);
class_<TaskCallback<void(std::string)>>("TaskCallbackOpen");
class_<TaskCallback<void(bool)>>("TaskCallbackSave");
function("TaskCallback_save_call", &TaskCallback_save_call);
function("TaskCallback_save_delete", &TaskCallback_save_delete);
function("TaskCallback_open_call", &TaskCallback_open_call);
function("TaskCallback_open_delete", &TaskCallback_open_delete);
function("UtilityGetString", &UtilityGetString);
}
extern "C" {
extern void js_pick_file(TaskCallback* tc);
extern void js_pick_file(TaskCallback<void(std::string)>* tc);
extern void js_pick_file_save(std::string path, std::string name, TaskCallback<void(bool)>* tc);
}
void webgl_pick_file(std::function<void(std::string)> callback)
{
js_pick_file(new TaskCallback([callback](std::string tmp_file_path){
js_pick_file(new TaskCallback<void(std::string)>([callback](std::string tmp_file_path){
printf("callback called: %s\n", tmp_file_path.c_str());
callback(tmp_file_path);
}));
}
void webgl_pick_file_save(const std::string& path,
const std::string& name, std::function<void(bool)> callback)
{
js_pick_file_save(path, name, new TaskCallback<void(bool)>([callback](bool success){
printf("save callback called: %s\n", success ? "ok" : "failed");
callback(success);
}));
}
void main_loop()
{
app.render_thread_tick();

View File

@@ -15,14 +15,46 @@ function js_pick_file(fn) {
console.log("reader.onload " + file.name);
var content = new Uint8Array(readerEvent.target.result); // this is the content!
console.log( content );
FS.writeFile(file.name, content);
Module.TaskCallback_call(fn, file.name);
Module.TaskCallback_delete(fn);
FS.writeFile("/" + file.name, content);
Module.TaskCallback_open_call(fn, "/" + file.name);
Module.TaskCallback_open_delete(fn);
}
}
input.click();
}
function js_pick_file_save(path, name, fn) {
jspath = Module.UtilityGetString(path);
jsname = Module.UtilityGetString(name);
console.log("js_pick_file_save");
console.log(jspath);
file = FS.readFile(jspath);
blob = new Blob([file]);
console.log(file);
// IE hack;
// see: http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx
if (window.navigator.msSaveOrOpenBlob)
{
window.navigator.msSaveBlob(blob, jsname);
}
else
{
var a = window.document.createElement("a");
a.href = window.URL.createObjectURL(blob, {type: "application/octet-stream"});
a.download = jsname;
document.body.appendChild(a);
// IE: "Access is denied";
// see: https://connect.microsoft.com/IE/feedback/details/797361/ie-10-treats-blob-url-as-cross-origin-and-denies-access
a.click();
document.body.removeChild(a);
}
Module.TaskCallback_save_call(fn, true);
Module.TaskCallback_save_delete(fn);
}
mergeInto(LibraryManager.library, {
js_pick_file: js_pick_file,
js_pick_file_save: js_pick_file_save,
});