mirror of https://github.com/emilk/egui.git
Emil Ernerfeldt
4 years ago
14 changed files with 272 additions and 64 deletions
@ -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 |
@ -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> |
@ -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); |
|||
} |
|||
} |
@ -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" |
@ -0,0 +1,49 @@ |
|||
/// 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; |
|||
} |
|||
}); |
|||
} |
|||
} |
@ -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(()) |
|||
} |
Loading…
Reference in new issue