Merge pull request #47 from emilk/web-app-example

Demonstrate fetch
This commit is contained in:
Emil Ernerfeldt 2020-11-18 01:11:59 +01:00 committed by GitHub
commit 7249fc45d0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 1319 additions and 67 deletions

12
Cargo.lock generated
View file

@ -580,6 +580,18 @@ dependencies = [
"serde",
]
[[package]]
name = "example_web"
version = "0.1.0"
dependencies = [
"egui",
"egui_web",
"js-sys",
"serde",
"serde_json",
"wasm-bindgen",
]
[[package]]
name = "fnv"
version = "1.0.7"

View file

@ -1,11 +1,12 @@
[workspace]
members = [
"demo_glium",
"demo_web",
"egui_glium",
"egui_web",
"egui",
"example_glium",
"demo_web",
"example_web",
]

View file

@ -15,7 +15,7 @@ BUILD=release
export RUSTFLAGS=--cfg=web_sys_unstable_apis # required for the clipboard API
# Clear output from old stuff:
rm -rf docs/*.wasm
rm -rf docs/demo_web.wasm
echo "Build rust:"
# cargo build -p demo_web --target wasm32-unknown-unknown
@ -27,4 +27,4 @@ TARGET_NAME="demo_web.wasm"
wasm-bindgen "target/wasm32-unknown-unknown/$BUILD/$TARGET_NAME" \
--out-dir docs --no-modules --no-typescript
open http://localhost:8888
open http://localhost:8888/index.html

30
build_example_web.sh Executable file
View file

@ -0,0 +1,30 @@
#!/bin/bash
set -eu
# Pre-requisites:
rustup target add wasm32-unknown-unknown
if ! wasm-bindgen --version; then
cargo clean
cargo install -f wasm-bindgen-cli
cargo update
fi
# BUILD=debug
BUILD=release
export RUSTFLAGS=--cfg=web_sys_unstable_apis # required for the clipboard API
# Clear output from old stuff:
rm -rf docs/example_web.wasm
echo "Build rust:"
# cargo build -p example_web --target wasm32-unknown-unknown
cargo build --release -p example_web --target wasm32-unknown-unknown
echo "Generate JS bindings for wasm:"
FOLDER_NAME=${PWD##*/}
TARGET_NAME="example_web.wasm"
wasm-bindgen "target/wasm32-unknown-unknown/$BUILD/$TARGET_NAME" \
--out-dir docs --no-modules --no-typescript
open http://localhost:8888/example.html

View file

@ -9,7 +9,10 @@ CARGO_INCREMENTAL=0 cargo clippy --workspace --all-targets --all-features -- -D
cargo test --workspace --all-targets --all-features
cargo test --workspace --doc
cargo check -p egui --target wasm32-unknown-unknown
cargo check -p egui_web --target wasm32-unknown-unknown
cargo check -p demo_web --target wasm32-unknown-unknown
cargo check -p example_web --target wasm32-unknown-unknown
# For finding bloat:
# cargo bloat --release --bin demo_glium -n 200 | rg egui

View file

@ -1,3 +1,4 @@
#![forbid(unsafe_code)]
#![deny(warnings)]
#![warn(clippy::all)]

View file

@ -5,11 +5,14 @@
use wasm_bindgen::prelude::*;
/// This is the entry-point for all the web-assembly.
/// This is called once from the HTML.
/// It loads the app, installs some callbacks, then returns.
/// You can add more callbacks like this if you want to call in to your code.
#[wasm_bindgen]
pub fn start(canvas_id: &str) -> Result<(), wasm_bindgen::JsValue> {
let app = egui::DemoApp::default();
let backend = egui_web::WebBackend::new(canvas_id)?;
let app = Box::new(egui::DemoApp::default());
let runner = egui_web::AppRunner::new(backend, app)?;
let runner = egui_web::AppRunner::new(backend, Box::new(app))?;
egui_web::start(runner)?;
Ok(())
}

67
docs/example.html Normal file
View file

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- Disable zooming: -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<head>
<title>Egui An experimental immediate mode GUI written in Rust</title>
<style>
html {
/* Remove touch delay: */
touch-action: manipulation;
}
body {
background: #101010;
}
/* Allow canvas to fill entire web page: */
html,
body {
overflow: hidden;
margin: 0 !important;
padding: 0 !important;
}
</style>
</head>
<body>
<!--
THis is where the app will show up.
The WASM code will resize this to cover the entire screen.
-->
<canvas id="the_canvas_id"></canvas>
<script>
// The `--no-modules`-generated JS from `wasm-bindgen` attempts to use
// `WebAssembly.instantiateStreaming` to instantiate the wasm module,
// but this doesn't work with `file://` urls. This example is frequently
// viewed by simply opening `index.html` in a browser (with a `file://`
// url), so it would fail if we were to call this function!
//
// Work around this for now by deleting the function to ensure that the
// `no_modules.js` script doesn't have access to it. You won't need this
// hack when deploying over HTTP.
delete WebAssembly.instantiateStreaming;
</script>
<!-- this is the JS generated by the `wasm-bindgen` CLI tool -->
<script src="example_web.js"></script>
<script>
// We'll defer our execution until the wasm is ready to go.
// Here we tell bindgen the path to the wasm file so it can start
// initialization and return to us a promise when it's done.
wasm_bindgen("./example_web_bg.wasm")
.then(on_wasm_loaded)["catch"](console.error);
function on_wasm_loaded() {
// This call installs a bunch of callbacks and then return
wasm_bindgen.start("the_canvas_id");
}
</script>
</body>
</html>

899
docs/example_web.js Normal file
View file

@ -0,0 +1,899 @@
let wasm_bindgen;
(function() {
const __exports = {};
let wasm;
const heap = new Array(32).fill(undefined);
heap.push(undefined, null, true, false);
function getObject(idx) { return heap[idx]; }
let heap_next = heap.length;
function dropObject(idx) {
if (idx < 36) return;
heap[idx] = heap_next;
heap_next = idx;
}
function takeObject(idx) {
const ret = getObject(idx);
dropObject(idx);
return ret;
}
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
let cachegetUint8Memory0 = null;
function getUint8Memory0() {
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachegetUint8Memory0;
}
function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
function isLikeNone(x) {
return x === undefined || x === null;
}
let cachegetFloat64Memory0 = null;
function getFloat64Memory0() {
if (cachegetFloat64Memory0 === null || cachegetFloat64Memory0.buffer !== wasm.memory.buffer) {
cachegetFloat64Memory0 = new Float64Array(wasm.memory.buffer);
}
return cachegetFloat64Memory0;
}
let cachegetInt32Memory0 = null;
function getInt32Memory0() {
if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) {
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
}
return cachegetInt32Memory0;
}
let WASM_VECTOR_LEN = 0;
let cachedTextEncoder = new TextEncoder('utf-8');
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
? function (arg, view) {
return cachedTextEncoder.encodeInto(arg, view);
}
: function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
});
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length);
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len);
const mem = getUint8Memory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3);
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
const ret = encodeString(arg, view);
offset += ret.written;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
function debugString(val) {
// primitive types
const type = typeof val;
if (type == 'number' || type == 'boolean' || val == null) {
return `${val}`;
}
if (type == 'string') {
return `"${val}"`;
}
if (type == 'symbol') {
const description = val.description;
if (description == null) {
return 'Symbol';
} else {
return `Symbol(${description})`;
}
}
if (type == 'function') {
const name = val.name;
if (typeof name == 'string' && name.length > 0) {
return `Function(${name})`;
} else {
return 'Function';
}
}
// objects
if (Array.isArray(val)) {
const length = val.length;
let debug = '[';
if (length > 0) {
debug += debugString(val[0]);
}
for(let i = 1; i < length; i++) {
debug += ', ' + debugString(val[i]);
}
debug += ']';
return debug;
}
// Test for built-in
const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
let className;
if (builtInMatches.length > 1) {
className = builtInMatches[1];
} else {
// Failed to match the standard '[object ClassName]'
return toString.call(val);
}
if (className == 'Object') {
// we're a user defined class or Object
// JSON.stringify avoids problems with cycles, and is generally much
// easier than looping through ownProperties of `val`.
try {
return 'Object(' + JSON.stringify(val) + ')';
} catch (_) {
return 'Object';
}
}
// errors
if (val instanceof Error) {
return `${val.name}: ${val.message}\n${val.stack}`;
}
// TODO we could test for more things here, like `Set`s and `Map`s.
return className;
}
function makeMutClosure(arg0, arg1, dtor, f) {
const state = { a: arg0, b: arg1, cnt: 1, dtor };
const real = (...args) => {
// First up with a closure we increment the internal reference
// count. This ensures that the Rust closure environment won't
// be deallocated while we're invoking it.
state.cnt++;
const a = state.a;
state.a = 0;
try {
return f(a, state.b, ...args);
} finally {
if (--state.cnt === 0) {
wasm.__wbindgen_export_2.get(state.dtor)(a, state.b);
} else {
state.a = a;
}
}
};
real.original = state;
return real;
}
function __wbg_adapter_26(arg0, arg1) {
wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hcf118a068d67b888(arg0, arg1);
}
function __wbg_adapter_29(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h232550930f57d037(arg0, arg1, addHeapObject(arg2));
}
function __wbg_adapter_32(arg0, arg1) {
wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__ha5199f647b73bd92(arg0, arg1);
}
function __wbg_adapter_35(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h232550930f57d037(arg0, arg1, addHeapObject(arg2));
}
function __wbg_adapter_38(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h232550930f57d037(arg0, arg1, addHeapObject(arg2));
}
function __wbg_adapter_41(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h232550930f57d037(arg0, arg1, addHeapObject(arg2));
}
function __wbg_adapter_44(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h232550930f57d037(arg0, arg1, addHeapObject(arg2));
}
function __wbg_adapter_47(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd5c13e870f8bfcb3(arg0, arg1, addHeapObject(arg2));
}
/**
* This is the entry-point for all the web-assembly.
* This is called once from the HTML.
* It loads the app, installs some callbacks, then returns.
* You can add more callbacks like this if you want to call in to your code.
* @param {string} canvas_id
*/
__exports.start = function(canvas_id) {
var ptr0 = passStringToWasm0(canvas_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
wasm.start(ptr0, len0);
};
function handleError(f) {
return function () {
try {
return f.apply(this, arguments);
} catch (e) {
wasm.__wbindgen_exn_store(addHeapObject(e));
}
};
}
function getArrayU8FromWasm0(ptr, len) {
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
}
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
} catch (e) {
if (module.headers.get('Content-Type') != 'application/wasm') {
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
} else {
throw e;
}
}
}
const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
return { instance, module };
} else {
return instance;
}
}
}
async function init(input) {
if (typeof input === 'undefined') {
let src;
if (typeof document === 'undefined') {
src = location.href;
} else {
src = document.currentScript.src;
}
input = src.replace(/\.js$/, '_bg.wasm');
}
const imports = {};
imports.wbg = {};
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
takeObject(arg0);
};
imports.wbg.__wbindgen_cb_drop = function(arg0) {
const obj = takeObject(arg0).original;
if (obj.cnt-- == 1) {
obj.a = 0;
return true;
}
var ret = false;
return ret;
};
imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
var ret = getStringFromWasm0(arg0, arg1);
return addHeapObject(ret);
};
imports.wbg.__wbg_instanceof_Window_adf3196bdc02b386 = function(arg0) {
var ret = getObject(arg0) instanceof Window;
return ret;
};
imports.wbg.__wbg_document_6cc8d0b87c0a99b9 = function(arg0) {
var ret = getObject(arg0).document;
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_location_9b924f46d7090431 = function(arg0) {
var ret = getObject(arg0).location;
return addHeapObject(ret);
};
imports.wbg.__wbg_navigator_71c234326c0a2ebb = function(arg0) {
var ret = getObject(arg0).navigator;
return addHeapObject(ret);
};
imports.wbg.__wbg_innerWidth_60241abd729ed26f = handleError(function(arg0) {
var ret = getObject(arg0).innerWidth;
return addHeapObject(ret);
});
imports.wbg.__wbg_innerHeight_2f860a67225f1fbd = handleError(function(arg0) {
var ret = getObject(arg0).innerHeight;
return addHeapObject(ret);
});
imports.wbg.__wbg_devicePixelRatio_599d41a9267fa1ca = function(arg0) {
var ret = getObject(arg0).devicePixelRatio;
return ret;
};
imports.wbg.__wbg_performance_8594a974edffb1dc = function(arg0) {
var ret = getObject(arg0).performance;
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_localStorage_47e8ad68b9e5dcb9 = handleError(function(arg0) {
var ret = getObject(arg0).localStorage;
return isLikeNone(ret) ? 0 : addHeapObject(ret);
});
imports.wbg.__wbg_open_7e3a4789bd559091 = handleError(function(arg0, arg1, arg2, arg3, arg4) {
var ret = getObject(arg0).open(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
return isLikeNone(ret) ? 0 : addHeapObject(ret);
});
imports.wbg.__wbg_requestAnimationFrame_89935c9d6ac25d2f = handleError(function(arg0, arg1) {
var ret = getObject(arg0).requestAnimationFrame(getObject(arg1));
return ret;
});
imports.wbg.__wbg_fetch_91f098921cc7cca8 = function(arg0, arg1) {
var ret = getObject(arg0).fetch(getObject(arg1));
return addHeapObject(ret);
};
imports.wbg.__wbg_setInterval_06df6f1ebeafd66f = handleError(function(arg0, arg1, arg2) {
var ret = getObject(arg0).setInterval(getObject(arg1), arg2);
return ret;
});
imports.wbg.__wbg_body_8c888fe47d81765f = function(arg0) {
var ret = getObject(arg0).body;
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_getElementById_0cb6ad9511b1efc0 = function(arg0, arg1, arg2) {
var ret = getObject(arg0).getElementById(getStringFromWasm0(arg1, arg2));
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
var ret = getObject(arg0);
return addHeapObject(ret);
};
imports.wbg.__wbg_setProperty_42eabadfcd7d6199 = handleError(function(arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).setProperty(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
});
imports.wbg.__wbg_addEventListener_9e7b0c3f65ebc0d7 = handleError(function(arg0, arg1, arg2, arg3) {
getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3));
});
imports.wbg.__wbg_getItem_cb17cd47353971da = handleError(function(arg0, arg1, arg2, arg3) {
var ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3));
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
});
imports.wbg.__wbg_setItem_71df4161bb87d575 = handleError(function(arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
});
imports.wbg.__wbg_writeText_f87e9b63346a7e47 = function(arg0, arg1, arg2) {
var ret = getObject(arg0).writeText(getStringFromWasm0(arg1, arg2));
return addHeapObject(ret);
};
imports.wbg.__wbg_set_e0c72ee4d5eea3d5 = handleError(function(arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
});
imports.wbg.__wbg_deltaX_ee242e8414135d41 = function(arg0) {
var ret = getObject(arg0).deltaX;
return ret;
};
imports.wbg.__wbg_deltaY_35bf8632b9f25820 = function(arg0) {
var ret = getObject(arg0).deltaY;
return ret;
};
imports.wbg.__wbg_instanceof_Response_328c03967a8e8902 = function(arg0) {
var ret = getObject(arg0) instanceof Response;
return ret;
};
imports.wbg.__wbg_url_67bbdafba8ff6e85 = function(arg0, arg1) {
var ret = getObject(arg1).url;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_status_eb6dbb31556c329f = function(arg0) {
var ret = getObject(arg0).status;
return ret;
};
imports.wbg.__wbg_ok_7f500542a5af3b60 = function(arg0) {
var ret = getObject(arg0).ok;
return ret;
};
imports.wbg.__wbg_statusText_99a522577dbca4cb = function(arg0, arg1) {
var ret = getObject(arg1).statusText;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_text_966d07536ca6ccdc = handleError(function(arg0) {
var ret = getObject(arg0).text();
return addHeapObject(ret);
});
imports.wbg.__wbg_now_49847177a6d1d57e = function(arg0) {
var ret = getObject(arg0).now();
return ret;
};
imports.wbg.__wbg_headers_d4301f4888b4640a = function(arg0) {
var ret = getObject(arg0).headers;
return addHeapObject(ret);
};
imports.wbg.__wbg_newwithstrandinit_d1de1bfcd175e38a = handleError(function(arg0, arg1, arg2) {
var ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2));
return addHeapObject(ret);
});
imports.wbg.__wbg_instanceof_HtmlCanvasElement_4f5b5ec6cd53ccf3 = function(arg0) {
var ret = getObject(arg0) instanceof HTMLCanvasElement;
return ret;
};
imports.wbg.__wbg_width_a22f9855caa54b53 = function(arg0) {
var ret = getObject(arg0).width;
return ret;
};
imports.wbg.__wbg_setwidth_5f26a8ba9dbfa0d0 = function(arg0, arg1) {
getObject(arg0).width = arg1 >>> 0;
};
imports.wbg.__wbg_height_9a404a6b3c61c7ef = function(arg0) {
var ret = getObject(arg0).height;
return ret;
};
imports.wbg.__wbg_setheight_70f62727aa9383c2 = function(arg0, arg1) {
getObject(arg0).height = arg1 >>> 0;
};
imports.wbg.__wbg_getContext_37ca0870acb096d9 = handleError(function(arg0, arg1, arg2) {
var ret = getObject(arg0).getContext(getStringFromWasm0(arg1, arg2));
return isLikeNone(ret) ? 0 : addHeapObject(ret);
});
imports.wbg.__wbg_pageX_234547d8f89fd3d0 = function(arg0) {
var ret = getObject(arg0).pageX;
return ret;
};
imports.wbg.__wbg_pageY_4f94b607e8f1a8a2 = function(arg0) {
var ret = getObject(arg0).pageY;
return ret;
};
imports.wbg.__wbg_clipboardData_d3dc621a701f9c49 = function(arg0) {
var ret = getObject(arg0).clipboardData;
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_getData_0a2347233cf89d01 = handleError(function(arg0, arg1, arg2, arg3) {
var ret = getObject(arg1).getData(getStringFromWasm0(arg2, arg3));
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
});
imports.wbg.__wbg_keyCode_689d196ab65a93d7 = function(arg0) {
var ret = getObject(arg0).keyCode;
return ret;
};
imports.wbg.__wbg_altKey_1b58e09f218a0f4b = function(arg0) {
var ret = getObject(arg0).altKey;
return ret;
};
imports.wbg.__wbg_ctrlKey_f080ec163dcc2703 = function(arg0) {
var ret = getObject(arg0).ctrlKey;
return ret;
};
imports.wbg.__wbg_shiftKey_d11f615955404512 = function(arg0) {
var ret = getObject(arg0).shiftKey;
return ret;
};
imports.wbg.__wbg_metaKey_9bc40bb1d5972ef2 = function(arg0) {
var ret = getObject(arg0).metaKey;
return ret;
};
imports.wbg.__wbg_isComposing_c0f97b8c3f5992b5 = function(arg0) {
var ret = getObject(arg0).isComposing;
return ret;
};
imports.wbg.__wbg_key_590d4d2a765d1b58 = function(arg0, arg1) {
var ret = getObject(arg1).key;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_get_814461b8584a55e7 = function(arg0, arg1) {
var ret = getObject(arg0)[arg1 >>> 0];
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_getBoundingClientRect_c6d612c06726983e = function(arg0) {
var ret = getObject(arg0).getBoundingClientRect();
return addHeapObject(ret);
};
imports.wbg.__wbg_instanceof_WebGlRenderingContext_a37cc8c6016098e4 = function(arg0) {
var ret = getObject(arg0) instanceof WebGLRenderingContext;
return ret;
};
imports.wbg.__wbg_bufferData_0690087420a9f115 = function(arg0, arg1, arg2, arg3) {
getObject(arg0).bufferData(arg1 >>> 0, getObject(arg2), arg3 >>> 0);
};
imports.wbg.__wbg_texImage2D_8d677a54ab75452c = handleError(function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) {
getObject(arg0).texImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9 === 0 ? undefined : getArrayU8FromWasm0(arg9, arg10));
});
imports.wbg.__wbg_activeTexture_7246ae8c464868b4 = function(arg0, arg1) {
getObject(arg0).activeTexture(arg1 >>> 0);
};
imports.wbg.__wbg_attachShader_d213e7ecd3432f4a = function(arg0, arg1, arg2) {
getObject(arg0).attachShader(getObject(arg1), getObject(arg2));
};
imports.wbg.__wbg_bindBuffer_f0ba4bbfd5b08434 = function(arg0, arg1, arg2) {
getObject(arg0).bindBuffer(arg1 >>> 0, getObject(arg2));
};
imports.wbg.__wbg_bindTexture_c00656e6f0530ee7 = function(arg0, arg1, arg2) {
getObject(arg0).bindTexture(arg1 >>> 0, getObject(arg2));
};
imports.wbg.__wbg_blendFunc_c7c9cda2a0e4b97f = function(arg0, arg1, arg2) {
getObject(arg0).blendFunc(arg1 >>> 0, arg2 >>> 0);
};
imports.wbg.__wbg_clear_c9cc14c37d12a838 = function(arg0, arg1) {
getObject(arg0).clear(arg1 >>> 0);
};
imports.wbg.__wbg_clearColor_73695d8d401f87e6 = function(arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).clearColor(arg1, arg2, arg3, arg4);
};
imports.wbg.__wbg_compileShader_961db910485f4a76 = function(arg0, arg1) {
getObject(arg0).compileShader(getObject(arg1));
};
imports.wbg.__wbg_createBuffer_4deb008968921e7f = function(arg0) {
var ret = getObject(arg0).createBuffer();
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_createProgram_b502951c403f671a = function(arg0) {
var ret = getObject(arg0).createProgram();
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_createShader_7bd4296ba9c32133 = function(arg0, arg1) {
var ret = getObject(arg0).createShader(arg1 >>> 0);
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_createTexture_e0437703d5b41f24 = function(arg0) {
var ret = getObject(arg0).createTexture();
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_disable_6d4d32f05b00518e = function(arg0, arg1) {
getObject(arg0).disable(arg1 >>> 0);
};
imports.wbg.__wbg_drawElements_b22db7173101346e = function(arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).drawElements(arg1 >>> 0, arg2, arg3 >>> 0, arg4);
};
imports.wbg.__wbg_enable_700dbd1724c67920 = function(arg0, arg1) {
getObject(arg0).enable(arg1 >>> 0);
};
imports.wbg.__wbg_enableVertexAttribArray_4b6614b028d442ff = function(arg0, arg1) {
getObject(arg0).enableVertexAttribArray(arg1 >>> 0);
};
imports.wbg.__wbg_getAttribLocation_98ff7fc515cda07d = function(arg0, arg1, arg2, arg3) {
var ret = getObject(arg0).getAttribLocation(getObject(arg1), getStringFromWasm0(arg2, arg3));
return ret;
};
imports.wbg.__wbg_getProgramInfoLog_a84afc629d343c75 = function(arg0, arg1, arg2) {
var ret = getObject(arg1).getProgramInfoLog(getObject(arg2));
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_getProgramParameter_327111ebb2bca7fb = function(arg0, arg1, arg2) {
var ret = getObject(arg0).getProgramParameter(getObject(arg1), arg2 >>> 0);
return addHeapObject(ret);
};
imports.wbg.__wbg_getShaderInfoLog_a9529ee3f2ebd3e0 = function(arg0, arg1, arg2) {
var ret = getObject(arg1).getShaderInfoLog(getObject(arg2));
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_getShaderParameter_d7853b2d4822ad9f = function(arg0, arg1, arg2) {
var ret = getObject(arg0).getShaderParameter(getObject(arg1), arg2 >>> 0);
return addHeapObject(ret);
};
imports.wbg.__wbg_getUniformLocation_55700686ebe625a9 = function(arg0, arg1, arg2, arg3) {
var ret = getObject(arg0).getUniformLocation(getObject(arg1), getStringFromWasm0(arg2, arg3));
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_linkProgram_7c29f15a5150d174 = function(arg0, arg1) {
getObject(arg0).linkProgram(getObject(arg1));
};
imports.wbg.__wbg_scissor_5d19639b621ab86f = function(arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).scissor(arg1, arg2, arg3, arg4);
};
imports.wbg.__wbg_shaderSource_bf6be2cc97a14fc1 = function(arg0, arg1, arg2, arg3) {
getObject(arg0).shaderSource(getObject(arg1), getStringFromWasm0(arg2, arg3));
};
imports.wbg.__wbg_texParameteri_c9ce5bb9e350c6cd = function(arg0, arg1, arg2, arg3) {
getObject(arg0).texParameteri(arg1 >>> 0, arg2 >>> 0, arg3);
};
imports.wbg.__wbg_uniform1i_bbbce4278738d73e = function(arg0, arg1, arg2) {
getObject(arg0).uniform1i(getObject(arg1), arg2);
};
imports.wbg.__wbg_uniform2f_aaa7fe970579cfd3 = function(arg0, arg1, arg2, arg3) {
getObject(arg0).uniform2f(getObject(arg1), arg2, arg3);
};
imports.wbg.__wbg_useProgram_51f7808f5955c03a = function(arg0, arg1) {
getObject(arg0).useProgram(getObject(arg1));
};
imports.wbg.__wbg_vertexAttribPointer_76ddec1ed8425967 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
getObject(arg0).vertexAttribPointer(arg1 >>> 0, arg2, arg3 >>> 0, arg4 !== 0, arg5, arg6);
};
imports.wbg.__wbg_viewport_dd0dedc488a8dba4 = function(arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).viewport(arg1, arg2, arg3, arg4);
};
imports.wbg.__wbg_log_3bafd82835c6de6d = function(arg0) {
console.log(getObject(arg0));
};
imports.wbg.__wbg_style_9a41d46c005f7596 = function(arg0) {
var ret = getObject(arg0).style;
return addHeapObject(ret);
};
imports.wbg.__wbg_preventDefault_93d06688748bfc14 = function(arg0) {
getObject(arg0).preventDefault();
};
imports.wbg.__wbg_stopPropagation_a47dd3b6ffe6b400 = function(arg0) {
getObject(arg0).stopPropagation();
};
imports.wbg.__wbg_touches_1cfb9ad18bd08588 = function(arg0) {
var ret = getObject(arg0).touches;
return addHeapObject(ret);
};
imports.wbg.__wbg_top_a6f8db7db6d2bf17 = function(arg0) {
var ret = getObject(arg0).top;
return ret;
};
imports.wbg.__wbg_left_b19dce37a1320f04 = function(arg0) {
var ret = getObject(arg0).left;
return ret;
};
imports.wbg.__wbg_clipboard_7862c97f3561ff94 = function(arg0) {
var ret = getObject(arg0).clipboard;
return addHeapObject(ret);
};
imports.wbg.__wbg_hash_1e68d402e53cef74 = handleError(function(arg0, arg1) {
var ret = getObject(arg1).hash;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
});
imports.wbg.__wbg_clientX_c1a2c3a6a07188a2 = function(arg0) {
var ret = getObject(arg0).clientX;
return ret;
};
imports.wbg.__wbg_clientY_090f8ba07f76875d = function(arg0) {
var ret = getObject(arg0).clientY;
return ret;
};
imports.wbg.__wbg_call_8e95613cc6524977 = handleError(function(arg0, arg1) {
var ret = getObject(arg0).call(getObject(arg1));
return addHeapObject(ret);
});
imports.wbg.__wbg_newnoargs_f3b8a801d5d4b079 = function(arg0, arg1) {
var ret = new Function(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbg_getHours_551ae9f419d47a3b = function(arg0) {
var ret = getObject(arg0).getHours();
return ret;
};
imports.wbg.__wbg_getMilliseconds_c188d73c551e97d1 = function(arg0) {
var ret = getObject(arg0).getMilliseconds();
return ret;
};
imports.wbg.__wbg_getMinutes_054a5442be4b9aa6 = function(arg0) {
var ret = getObject(arg0).getMinutes();
return ret;
};
imports.wbg.__wbg_getSeconds_9cda850b6648721a = function(arg0) {
var ret = getObject(arg0).getSeconds();
return ret;
};
imports.wbg.__wbg_new0_a3af66503e735141 = function() {
var ret = new Date();
return addHeapObject(ret);
};
imports.wbg.__wbg_new_3e06d4f36713e4cb = function() {
var ret = new Object();
return addHeapObject(ret);
};
imports.wbg.__wbg_resolve_2529512c3bb73938 = function(arg0) {
var ret = Promise.resolve(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_then_4a7a614abbbe6d81 = function(arg0, arg1) {
var ret = getObject(arg0).then(getObject(arg1));
return addHeapObject(ret);
};
imports.wbg.__wbg_then_3b7ac098cfda2fa5 = function(arg0, arg1, arg2) {
var ret = getObject(arg0).then(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
};
imports.wbg.__wbg_self_07b2f89e82ceb76d = handleError(function() {
var ret = self.self;
return addHeapObject(ret);
});
imports.wbg.__wbg_window_ba85d88572adc0dc = handleError(function() {
var ret = window.window;
return addHeapObject(ret);
});
imports.wbg.__wbg_globalThis_b9277fc37e201fe5 = handleError(function() {
var ret = globalThis.globalThis;
return addHeapObject(ret);
});
imports.wbg.__wbg_global_e16303fe83e1d57f = handleError(function() {
var ret = global.global;
return addHeapObject(ret);
});
imports.wbg.__wbindgen_is_undefined = function(arg0) {
var ret = getObject(arg0) === undefined;
return ret;
};
imports.wbg.__wbg_buffer_49131c283a06686f = function(arg0) {
var ret = getObject(arg0).buffer;
return addHeapObject(ret);
};
imports.wbg.__wbg_new_20cc9c1e8e319ac2 = function(arg0) {
var ret = new Int16Array(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_new_9b295d24cf1d706f = function(arg0) {
var ret = new Uint8Array(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_new_79f4487112eba5a7 = function(arg0) {
var ret = new Float32Array(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_subarray_4cf58941ccdff8e8 = function(arg0, arg1, arg2) {
var ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
imports.wbg.__wbg_subarray_4eaeb3de00cf1955 = function(arg0, arg1, arg2) {
var ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
imports.wbg.__wbg_subarray_f5aa665f0873e6e8 = function(arg0, arg1, arg2) {
var ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
imports.wbg.__wbg_instanceof_Memory_8d2ddec6afb83aaa = function(arg0) {
var ret = getObject(arg0) instanceof WebAssembly.Memory;
return ret;
};
imports.wbg.__wbg_set_304f2ec1a3ab3b79 = handleError(function(arg0, arg1, arg2) {
var ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2));
return ret;
});
imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
const obj = getObject(arg1);
var ret = typeof(obj) === 'number' ? obj : undefined;
getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret;
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret);
};
imports.wbg.__wbindgen_string_get = function(arg0, arg1) {
const obj = getObject(arg1);
var ret = typeof(obj) === 'string' ? obj : undefined;
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbindgen_boolean_get = function(arg0) {
const v = getObject(arg0);
var ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
return ret;
};
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
var ret = debugString(getObject(arg1));
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};
imports.wbg.__wbindgen_rethrow = function(arg0) {
throw takeObject(arg0);
};
imports.wbg.__wbindgen_memory = function() {
var ret = wasm.memory;
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper472 = function(arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 101, __wbg_adapter_26);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper473 = function(arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 101, __wbg_adapter_29);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper475 = function(arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 101, __wbg_adapter_32);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper477 = function(arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 101, __wbg_adapter_35);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper479 = function(arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 101, __wbg_adapter_38);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper482 = function(arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 101, __wbg_adapter_41);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper484 = function(arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 101, __wbg_adapter_44);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper1212 = function(arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 132, __wbg_adapter_47);
return addHeapObject(ret);
};
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
input = fetch(input);
}
const { instance, module } = await load(await input, imports);
wasm = instance.exports;
init.__wbindgen_wasm_module = module;
return wasm;
}
wasm_bindgen = Object.assign(init, __exports);
})();

BIN
docs/example_web_bg.wasm Normal file

Binary file not shown.

View file

@ -29,7 +29,7 @@
<body>
<!-- The WASM code will resize this to cover the entire screen -->
<canvas id="canvas"></canvas>
<canvas id="the_canvas_id"></canvas>
<script>
// The `--no-modules`-generated JS from `wasm-bindgen` attempts to use
@ -55,7 +55,8 @@
.then(on_wasm_loaded)["catch"](console.error);
function on_wasm_loaded() {
wasm_bindgen.start("canvas");
// This call installs a bunch of callbacks and then return
wasm_bindgen.start("the_canvas_id");
}
</script>
</body>

View file

@ -61,7 +61,7 @@ pub fn warn_if_debug_build(ui: &mut crate::Ui) {
macro_rules! github_link_file_line {
($github_url:expr, $label:expr) => {{
let url = format!("{}{}#L{}", $github_url, file!(), line!());
Hyperlink::new(url).text($label)
$crate::Hyperlink::new(url).text($label)
}};
}
@ -71,7 +71,7 @@ macro_rules! github_link_file_line {
macro_rules! github_link_file {
($github_url:expr, $label:expr) => {{
let url = format!("{}{}", $github_url, file!());
Hyperlink::new(url).text($label)
$crate::Hyperlink::new(url).text($label)
}};
}

View file

@ -35,6 +35,7 @@ features = [
'Document',
'DomRect',
'Element',
'Headers',
'HtmlCanvasElement',
'HtmlElement',
'KeyboardEvent',
@ -42,6 +43,10 @@ features = [
'MouseEvent',
'Navigator',
'Performance',
'Request',
'RequestInit',
'RequestMode',
'Response',
'Storage',
'Touch',
'TouchEvent',

View file

@ -200,6 +200,7 @@ pub fn start(app_runner: AppRunner) -> Result<AppRunnerRef, JsValue> {
let runner_ref = AppRunnerRef(Arc::new(Mutex::new(app_runner)));
install_canvas_events(&runner_ref)?;
install_document_events(&runner_ref)?;
repaint_every_ms(&runner_ref, 1000)?; // just in case. TODO: make it a parameter
paint_and_schedule(runner_ref.clone())?;
Ok(runner_ref)
}

53
egui_web/src/fetch.rs Normal file
View file

@ -0,0 +1,53 @@
use wasm_bindgen::prelude::*;
pub struct Response {
pub url: String,
pub ok: bool,
pub status: u16,
pub status_text: String,
pub body: String,
}
/// NOTE: Ok(..) is returned on network error.
/// Err is only for failure to use the fetch api.
pub async fn get_text(url: &str) -> Result<Response, String> {
get_text_jsvalue(url)
.await
.map_err(|err| err.as_string().unwrap_or_default())
}
/// NOTE: Ok(..) is returned on network error.
/// Err is only for failure to use the fetch api.
async fn get_text_jsvalue(url: &str) -> Result<Response, JsValue> {
// https://rustwasm.github.io/wasm-bindgen/examples/fetch.html
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
let mut opts = web_sys::RequestInit::new();
opts.method("GET");
opts.mode(web_sys::RequestMode::Cors);
let request = web_sys::Request::new_with_str_and_init(&url, &opts)?;
request.headers().set("Accept", "*/*")?;
let window = web_sys::window().unwrap();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
assert!(resp_value.is_instance_of::<web_sys::Response>());
let resp: web_sys::Response = resp_value.dyn_into().unwrap();
// TODO: headers
// TODO: support binary get
let body = JsFuture::from(resp.text()?).await?;
let body = body.as_string().unwrap_or_default();
Ok(Response {
status_text: resp.status_text(),
url: resp.url(),
ok: resp.ok(),
status: resp.status(),
body,
})
}

View file

@ -3,6 +3,7 @@
#![warn(clippy::all)]
pub mod backend;
pub mod fetch;
pub mod webgl;
pub use backend::*;
@ -14,10 +15,14 @@ use wasm_bindgen::prelude::*;
// ----------------------------------------------------------------------------
// Helpers to hide some of the verbosity of web_sys
pub fn console_log(s: String) {
pub fn console_log(s: impl Into<JsValue>) {
web_sys::console::log_1(&s.into());
}
pub fn console_error(s: impl Into<JsValue>) {
web_sys::console::error_1(&s.into());
}
pub fn now_sec() -> f64 {
web_sys::window()
.expect("should have a Window")
@ -182,6 +187,13 @@ pub fn set_clipboard_text(s: &str) {
}
}
pub fn spawn_future<F>(future: F)
where
F: std::future::Future<Output = ()> + 'static,
{
wasm_bindgen_futures::spawn_local(future);
}
fn cursor_web_name(cursor: egui::CursorIcon) -> &'static str {
use egui::CursorIcon::*;
match cursor {
@ -412,6 +424,23 @@ fn install_document_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
Ok(())
}
/// Repaint at least every `ms` milliseconds.
fn repaint_every_ms(runner_ref: &AppRunnerRef, milliseconds: i32) -> Result<(), JsValue> {
assert!(milliseconds >= 0);
use wasm_bindgen::JsCast;
let window = web_sys::window().unwrap();
let runner_ref = runner_ref.clone();
let closure = Closure::wrap(Box::new(move || {
runner_ref.0.lock().needs_repaint = true;
}) as Box<dyn FnMut()>);
window.set_interval_with_callback_and_timeout_and_arguments_0(
closure.as_ref().unchecked_ref(),
milliseconds,
)?;
closure.forget();
Ok(())
}
fn modifiers_from_event(event: &web_sys::KeyboardEvent) -> egui::Modifiers {
egui::Modifiers {
alt: event.alt_key(),

View file

@ -0,0 +1,55 @@
/// We derive Deserialize/Serialize so we can persist app state on shutdown.
#[derive(serde::Deserialize, serde::Serialize)]
pub struct ExampleApp {
name: String,
age: u32,
}
impl Default for ExampleApp {
fn default() -> Self {
Self {
name: "Arthur".to_owned(),
age: 42,
}
}
}
impl egui::app::App for ExampleApp {
/// Called each time the UI needs repainting, which may be many times per second.
/// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`.
fn ui(
&mut self,
ctx: &std::sync::Arc<egui::Context>,
integration_context: &mut egui::app::IntegrationContext,
) {
let ExampleApp { name, age } = self;
// Example used in `README.md`.
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("My Egui Application");
ui.horizontal(|ui| {
ui.label("Your name: ");
ui.text_edit_singleline(name);
});
ui.add(egui::Slider::u32(age, 0..=120).text("age"));
if ui.button("Click each year").clicked {
*age += 1;
}
ui.label(format!("Hello '{}', age {}", name, age));
ui.advance_cursor(16.0);
if ui.button("Quit").clicked {
integration_context.output.quit = true;
}
});
integration_context.output.window_size = Some(ctx.used_size()); // resize the window to be just the size we need it to be
}
fn on_exit(&mut self, storage: &mut dyn egui::app::Storage) {
egui::app::set_value(storage, egui::app::APP_KEY, self);
}
}

View file

@ -1,63 +1,10 @@
//! Example of how to use Egui
#![forbid(unsafe_code)]
#![deny(warnings)]
#![warn(clippy::all)]
/// We derive Deserialize/Serialize so we can persist app state on shutdown.
#[derive(serde::Deserialize, serde::Serialize)]
struct MyApp {
name: String,
age: u32,
}
impl Default for MyApp {
fn default() -> Self {
Self {
name: "Arthur".to_owned(),
age: 42,
}
}
}
impl egui::app::App for MyApp {
/// Called each time the UI needs repainting, which may be many times per second.
/// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`.
fn ui(
&mut self,
ctx: &std::sync::Arc<egui::Context>,
integration_context: &mut egui::app::IntegrationContext,
) {
let MyApp { name, age } = self;
// Example used in `README.md`.
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("My Egui Application");
ui.horizontal(|ui| {
ui.label("Your name: ");
ui.text_edit_singleline(name);
});
ui.add(egui::Slider::u32(age, 0..=120).text("age"));
if ui.button("Click each year").clicked {
*age += 1;
}
ui.label(format!("Hello '{}', age {}", name, age));
ui.advance_cursor(16.0);
if ui.button("Quit").clicked {
integration_context.output.quit = true;
}
});
integration_context.output.window_size = Some(ctx.used_size()); // resize the window to be just the size we need it to be
}
fn on_exit(&mut self, storage: &mut dyn egui::app::Storage) {
egui::app::set_value(storage, egui::app::APP_KEY, self);
}
}
mod example_app;
use example_app::ExampleApp;
fn main() {
let title = "My Egui Window";
@ -68,6 +15,8 @@ fn main() {
// Alternative: store nowhere
// let storage = egui::app::DummyStorage::default();
let app: MyApp = egui::app::get_value(&storage, egui::app::APP_KEY).unwrap_or_default(); // Restore `MyApp` from file, or create new `MyApp`.
// Restore `example_app` from file, or create new `ExampleApp`:
let app: ExampleApp = egui::app::get_value(&storage, egui::app::APP_KEY).unwrap_or_default();
egui_glium::run(title, Box::new(storage), app);
}

17
example_web/Cargo.toml Normal file
View file

@ -0,0 +1,17 @@
[package]
name = "example_web"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2018"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
egui = { path = "../egui", features = ["serde"] }
egui_web = { path = "../egui_web" }
js-sys = "0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
wasm-bindgen = "0.2"

View file

@ -0,0 +1,106 @@
use egui_web::fetch::Response;
use std::sync::mpsc::Receiver;
pub struct ExampleApp {
url: String,
receivers: Vec<Receiver<Result<Response, String>>>,
fetch_result: Option<Result<Response, String>>,
}
impl Default for ExampleApp {
fn default() -> Self {
Self {
url: "https://raw.githubusercontent.com/emilk/egui/master/README.md".to_owned(),
receivers: Default::default(),
fetch_result: Default::default(),
}
}
}
impl egui::app::App for ExampleApp {
/// Called each time the UI needs repainting, which may be many times per second.
/// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`.
fn ui(
&mut self,
ctx: &std::sync::Arc<egui::Context>,
_integration_context: &mut egui::app::IntegrationContext,
) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("HTTP Get inside of Egui");
ui.add(egui::github_link_file!(
"https://github.com/emilk/egui/blob/master/",
"(source code)"
));
{
let mut trigger_fetch = false;
ui.horizontal(|ui| {
ui.label("URL:");
trigger_fetch |= ui.text_edit_singleline(&mut self.url).lost_kb_focus;
if ui.button("Egui README.md").clicked {
self.url = "https://raw.githubusercontent.com/emilk/egui/master/README.md"
.to_owned();
trigger_fetch = true;
}
if ui.button("Source code for this file").clicked {
self.url =
format!("https://raw.githubusercontent.com/emilk/egui/{}", file!());
trigger_fetch = true;
}
});
trigger_fetch |= ui.button("GET").clicked;
if trigger_fetch {
let (sender, receiver) = std::sync::mpsc::channel();
self.receivers.push(receiver);
let url = self.url.clone();
let future = async move {
let result = egui_web::fetch::get_text(&url).await;
sender.send(result).ok();
// TODO: trigger egui repaint somehow
};
egui_web::spawn_future(future);
}
}
// Show finished download (if any):
if let Some(result) = &self.fetch_result {
ui.separator();
match result {
Ok(response) => {
ui_response(ui, response);
}
Err(error) => {
// This should only happen if the fetch API isn't available or something similar.
ui.add(egui::Label::new(error).text_color(egui::color::RED));
}
}
}
});
for i in (0..self.receivers.len()).rev() {
if let Ok(result) = self.receivers[i].try_recv() {
self.fetch_result = Some(result);
let _ = self.receivers.swap_remove(i);
}
}
}
}
fn ui_response(ui: &mut egui::Ui, response: &Response) {
ui.monospace(format!("url: {}", response.url));
ui.monospace(format!(
"status: {} ({})",
response.status, response.status_text
));
ui.monospace("Body:");
ui.separator();
egui::ScrollArea::auto_sized().show(ui, |ui| {
ui.monospace(&response.body);
});
}

20
example_web/src/lib.rs Normal file
View file

@ -0,0 +1,20 @@
#![forbid(unsafe_code)]
#![deny(warnings)]
#![warn(clippy::all)]
mod example_app;
use wasm_bindgen::prelude::*;
/// This is the entry-point for all the web-assembly.
/// This is called once from the HTML.
/// It loads the app, installs some callbacks, then returns.
/// You can add more callbacks like this if you want to call in to your code.
#[wasm_bindgen]
pub fn start(canvas_id: &str) -> Result<(), wasm_bindgen::JsValue> {
let app = example_app::ExampleApp::default();
let backend = egui_web::WebBackend::new(canvas_id)?;
let runner = egui_web::AppRunner::new(backend, Box::new(app))?;
egui_web::start(runner)?;
Ok(())
}