Skip to content

Commit 3749f8d

Browse files
committed
backport layout save/restore from svalboard
1 parent b8b8f97 commit 3749f8d

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

src/index.html

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,73 @@
131131
document.getElementById("startup").style.display = "none";
132132
} else if (e.data.cmd == "notify_alive") {
133133
document.getElementById("startup_btn").disabled = false;
134+
} else if (e.data.cmd == "load_layout") {
135+
loadLayout();
136+
} else if (e.data.cmd == "save_layout") {
137+
saveLayout(e.data.layout);
134138
} else if (e.data.cmd == "fatal_error") {
135139
alert(e.data.msg);
136140
}
137141
}
138142

143+
const FILE_OPTIONS = {
144+
types: [
145+
{
146+
description: "Vial layout",
147+
accept: { "application/json": [".vil"] },
148+
},
149+
],
150+
excludeAcceptAllOption: false,
151+
multiple: false,
152+
};
153+
154+
async function loadLayout() {
155+
if (!window.showOpenFilePicker) {
156+
alert("File loading API unavailable. Please use a newer browser.");
157+
return;
158+
}
159+
160+
const [handle] = await window.showOpenFilePicker(FILE_OPTIONS);
161+
162+
if (!handle) {
163+
return;
164+
}
165+
166+
const file = await handle.getFile();
167+
const layout = await file.text();
168+
169+
PThread.runningWorkers[0].postMessage({
170+
cmd: "py",
171+
payload: `import webmain;webmain.window.on_layout_loaded(b${JSON.stringify(layout)})`,
172+
});
173+
}
174+
175+
async function saveLayout(layout) {
176+
if (window.showSaveFilePicker) {
177+
// This shows a file chooser dialog. It's a nicer experience
178+
// if available, allowing the user to select a target
179+
// filename and directory.
180+
const handle = await window.showSaveFilePicker(FILE_OPTIONS);
181+
const stream = await handle.createWritable();
182+
await stream.write(layout);
183+
await stream.close();
184+
} else {
185+
// If the File System API isn't available, we can at least
186+
// trigger a simple download with a hardcoded filename.
187+
const download = document.createElement('a');
188+
download.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(layout));
189+
download.setAttribute('download', 'layout.vil');
190+
191+
if (document.createEvent) {
192+
var event = document.createEvent('MouseEvents');
193+
event.initEvent('click', true, true);
194+
download.dispatchEvent(event);
195+
} else {
196+
download.click();
197+
}
198+
}
199+
}
200+
139201
async function connect() {
140202
var btn = document.getElementById("startup_btn");
141203

src/main.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,27 @@ static PyObject* vialglue_get_device_desc(PyObject *self, PyObject *args) {
133133
return PyUnicode_FromString(g_device_desc);
134134
}
135135

136+
static PyObject * vialglue_load_layout(PyObject *self, PyObject *args) {
137+
EM_ASM({
138+
postMessage({cmd: "load_layout"});
139+
});
140+
141+
return PyLong_FromLong(0);
142+
}
143+
144+
static PyObject * vialglue_save_layout(PyObject *self, PyObject *args) {
145+
const uint8_t *data;
146+
147+
if (!PyArg_ParseTuple(args, "y", &data))
148+
return NULL;
149+
150+
EM_ASM({
151+
postMessage({cmd: "save_layout", layout: UTF8ToString($0)});
152+
}, data);
153+
154+
return PyLong_FromLong(0);
155+
}
156+
136157
static PyObject* vialglue_fatal_error(PyObject *self, PyObject *args) {
137158
const char *msg;
138159

@@ -154,6 +175,8 @@ static PyMethodDef VialglueMethods[] = {
154175
{"unlock_done", vialglue_unlock_done, METH_VARARGS, ""},
155176
{"notify_ready", vialglue_notify_ready, METH_VARARGS, ""},
156177
{"get_device_desc", vialglue_get_device_desc, METH_VARARGS, ""},
178+
{"load_layout", vialglue_load_layout, METH_VARARGS, ""},
179+
{"save_layout", vialglue_save_layout, METH_VARARGS, ""},
157180
{"fatal_error", vialglue_fatal_error, METH_VARARGS, ""},
158181
{NULL, NULL, 0, NULL}
159182
};

0 commit comments

Comments
 (0)