Rename to Emigui
This commit is contained in:
parent
1e8a4d3906
commit
8963a99a09
26 changed files with 281 additions and 249 deletions
|
@ -1,7 +1,7 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"emgui",
|
"emigui",
|
||||||
"emgui_wasm",
|
"emigui_wasm",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Optimize for small code size:
|
# Optimize for small code size:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Emgui – An Experimental, Modularized immediate mode Graphical User Interface
|
# Emigui – Experimental, Modularized Immediate mode Graphical User Interface
|
||||||
|
|
||||||
Here are the steps, in chronological order of execution:
|
Here are the steps, in chronological order of execution:
|
||||||
|
|
||||||
|
|
2
build.sh
2
build.sh
|
@ -20,7 +20,7 @@ function build_rust
|
||||||
|
|
||||||
echo "Generate JS bindings for wasm:"
|
echo "Generate JS bindings for wasm:"
|
||||||
FOLDER_NAME=${PWD##*/}
|
FOLDER_NAME=${PWD##*/}
|
||||||
TARGET_NAME="emgui_wasm.wasm"
|
TARGET_NAME="emigui_wasm.wasm"
|
||||||
wasm-bindgen "target/wasm32-unknown-unknown/$BUILD/$TARGET_NAME" \
|
wasm-bindgen "target/wasm32-unknown-unknown/$BUILD/$TARGET_NAME" \
|
||||||
--out-dir docs --no-modules --no-typescript
|
--out-dir docs --no-modules --no-typescript
|
||||||
# --no-modules-global hoboho
|
# --no-modules-global hoboho
|
||||||
|
|
|
@ -25,13 +25,13 @@
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param {string} arg0
|
* @param {string} arg0
|
||||||
* @returns {Painter}
|
* @returns {State}
|
||||||
*/
|
*/
|
||||||
__exports.new_webgl_painter = function(arg0) {
|
__exports.new_webgl_gui = function(arg0) {
|
||||||
const ptr0 = passStringToWasm(arg0);
|
const ptr0 = passStringToWasm(arg0);
|
||||||
const len0 = WASM_VECTOR_LEN;
|
const len0 = WASM_VECTOR_LEN;
|
||||||
try {
|
try {
|
||||||
return Painter.__wrap(wasm.new_webgl_painter(ptr0, len0));
|
return State.__wrap(wasm.new_webgl_gui(ptr0, len0));
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
wasm.__wbindgen_free(ptr0, len0 * 1);
|
wasm.__wbindgen_free(ptr0, len0 * 1);
|
||||||
|
@ -41,15 +41,15 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Painter} arg0
|
* @param {State} arg0
|
||||||
* @param {string} arg1
|
* @param {string} arg1
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
__exports.paint_webgl = function(arg0, arg1) {
|
__exports.run_gui = function(arg0, arg1) {
|
||||||
const ptr1 = passStringToWasm(arg1);
|
const ptr1 = passStringToWasm(arg1);
|
||||||
const len1 = WASM_VECTOR_LEN;
|
const len1 = WASM_VECTOR_LEN;
|
||||||
try {
|
try {
|
||||||
return wasm.paint_webgl(arg0.ptr, ptr1, len1);
|
return wasm.run_gui(arg0.ptr, ptr1, len1);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
wasm.__wbindgen_free(ptr1, len1 * 1);
|
wasm.__wbindgen_free(ptr1, len1 * 1);
|
||||||
|
@ -155,6 +155,14 @@ __exports.__widl_f_height_HTMLCanvasElement = function(arg0) {
|
||||||
return __widl_f_height_HTMLCanvasElement_target.call(getObject(arg0));
|
return __widl_f_height_HTMLCanvasElement_target.call(getObject(arg0));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const __widl_f_now_Performance_target = typeof Performance === 'undefined' ? null : Performance.prototype.now || function() {
|
||||||
|
throw new Error(`wasm-bindgen: Performance.now does not exist`);
|
||||||
|
};
|
||||||
|
|
||||||
|
__exports.__widl_f_now_Performance = function(arg0) {
|
||||||
|
return __widl_f_now_Performance_target.call(getObject(arg0));
|
||||||
|
};
|
||||||
|
|
||||||
__exports.__widl_instanceof_WebGLRenderingContext = function(idx) {
|
__exports.__widl_instanceof_WebGLRenderingContext = function(idx) {
|
||||||
return getObject(idx) instanceof WebGLRenderingContext ? 1 : 0;
|
return getObject(idx) instanceof WebGLRenderingContext ? 1 : 0;
|
||||||
};
|
};
|
||||||
|
@ -441,6 +449,30 @@ __exports.__widl_f_vertex_attrib_pointer_with_i32_WebGLRenderingContext = functi
|
||||||
__widl_f_vertex_attrib_pointer_with_i32_WebGLRenderingContext_target.call(getObject(arg0), arg1, arg2, arg3, arg4 !== 0, arg5, arg6);
|
__widl_f_vertex_attrib_pointer_with_i32_WebGLRenderingContext_target.call(getObject(arg0), arg1, arg2, arg3, arg4 !== 0, arg5, arg6);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const __widl_f_viewport_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.viewport || function() {
|
||||||
|
throw new Error(`wasm-bindgen: WebGLRenderingContext.viewport does not exist`);
|
||||||
|
};
|
||||||
|
|
||||||
|
__exports.__widl_f_viewport_WebGLRenderingContext = function(arg0, arg1, arg2, arg3, arg4) {
|
||||||
|
__widl_f_viewport_WebGLRenderingContext_target.call(getObject(arg0), arg1, arg2, arg3, arg4);
|
||||||
|
};
|
||||||
|
|
||||||
|
const __widl_f_drawing_buffer_width_WebGLRenderingContext_target = GetOwnOrInheritedPropertyDescriptor(typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype, 'drawingBufferWidth').get || function() {
|
||||||
|
throw new Error(`wasm-bindgen: WebGLRenderingContext.drawingBufferWidth does not exist`);
|
||||||
|
};
|
||||||
|
|
||||||
|
__exports.__widl_f_drawing_buffer_width_WebGLRenderingContext = function(arg0) {
|
||||||
|
return __widl_f_drawing_buffer_width_WebGLRenderingContext_target.call(getObject(arg0));
|
||||||
|
};
|
||||||
|
|
||||||
|
const __widl_f_drawing_buffer_height_WebGLRenderingContext_target = GetOwnOrInheritedPropertyDescriptor(typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype, 'drawingBufferHeight').get || function() {
|
||||||
|
throw new Error(`wasm-bindgen: WebGLRenderingContext.drawingBufferHeight does not exist`);
|
||||||
|
};
|
||||||
|
|
||||||
|
__exports.__widl_f_drawing_buffer_height_WebGLRenderingContext = function(arg0) {
|
||||||
|
return __widl_f_drawing_buffer_height_WebGLRenderingContext_target.call(getObject(arg0));
|
||||||
|
};
|
||||||
|
|
||||||
__exports.__widl_instanceof_Window = function(idx) {
|
__exports.__widl_instanceof_Window = function(idx) {
|
||||||
return getObject(idx) instanceof Window ? 1 : 0;
|
return getObject(idx) instanceof Window ? 1 : 0;
|
||||||
};
|
};
|
||||||
|
@ -452,6 +484,13 @@ __exports.__widl_f_document_Window = function(arg0) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
__exports.__widl_f_performance_Window = function(arg0) {
|
||||||
|
|
||||||
|
const val = getObject(arg0).performance;
|
||||||
|
return isLikeNone(val) ? 0 : addHeapObject(val);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
__exports.__wbg_new_c1b585153cd441ad = function(arg0) {
|
__exports.__wbg_new_c1b585153cd441ad = function(arg0) {
|
||||||
return addHeapObject(new Float32Array(getObject(arg0)));
|
return addHeapObject(new Float32Array(getObject(arg0)));
|
||||||
};
|
};
|
||||||
|
@ -508,16 +547,16 @@ __exports.__wbg_buffer_0413d5edaa0ff323 = function(arg0) {
|
||||||
return addHeapObject(getObject(arg0).buffer);
|
return addHeapObject(getObject(arg0).buffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
function freePainter(ptr) {
|
function freeState(ptr) {
|
||||||
|
|
||||||
wasm.__wbg_painter_free(ptr);
|
wasm.__wbg_state_free(ptr);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
class Painter {
|
class State {
|
||||||
|
|
||||||
static __wrap(ptr) {
|
static __wrap(ptr) {
|
||||||
const obj = Object.create(Painter.prototype);
|
const obj = Object.create(State.prototype);
|
||||||
obj.ptr = ptr;
|
obj.ptr = ptr;
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -526,11 +565,11 @@ class Painter {
|
||||||
free() {
|
free() {
|
||||||
const ptr = this.ptr;
|
const ptr = this.ptr;
|
||||||
this.ptr = 0;
|
this.ptr = 0;
|
||||||
freePainter(ptr);
|
freeState(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
__exports.Painter = Painter;
|
__exports.State = State;
|
||||||
|
|
||||||
__exports.__wbindgen_object_clone_ref = function(idx) {
|
__exports.__wbindgen_object_clone_ref = function(idx) {
|
||||||
return addHeapObject(getObject(idx));
|
return addHeapObject(getObject(idx));
|
||||||
|
@ -600,7 +639,7 @@ __exports.__wbindgen_throw = function(ptr, len) {
|
||||||
|
|
||||||
function init(path_or_module) {
|
function init(path_or_module) {
|
||||||
let instantiation;
|
let instantiation;
|
||||||
const imports = { './emgui_wasm': __exports };
|
const imports = { './emigui_wasm': __exports };
|
||||||
if (path_or_module instanceof WebAssembly.Module) {
|
if (path_or_module instanceof WebAssembly.Module) {
|
||||||
instantiation = WebAssembly.instantiate(path_or_module, imports)
|
instantiation = WebAssembly.instantiate(path_or_module, imports)
|
||||||
.then(instance => {
|
.then(instance => {
|
Binary file not shown.
|
@ -3,7 +3,7 @@
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Emgui – A experiment in an Immediate Mode GUI written in Rust</title>
|
<title>Emigui – A experiment in an Immediate Mode GUI written in Rust</title>
|
||||||
<style>
|
<style>
|
||||||
html {
|
html {
|
||||||
/* Remove touch delay: */
|
/* Remove touch delay: */
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
delete WebAssembly.instantiateStreaming;
|
delete WebAssembly.instantiateStreaming;
|
||||||
</script>
|
</script>
|
||||||
<!-- this is the JS generated by the `wasm-bindgen` CLI tool -->
|
<!-- this is the JS generated by the `wasm-bindgen` CLI tool -->
|
||||||
<script src="emgui_wasm.js"></script>
|
<script src="emigui_wasm.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// we'll defer our execution until the wasm is ready to go
|
// we'll defer our execution until the wasm is ready to go
|
||||||
function wasm_loaded() {
|
function wasm_loaded() {
|
||||||
|
@ -44,16 +44,16 @@
|
||||||
}
|
}
|
||||||
// here we tell bindgen the path to the wasm file so it can start
|
// 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
|
// initialization and return to us a promise when it's done
|
||||||
wasm_bindgen("./emgui_wasm_bg.wasm")
|
wasm_bindgen("./emigui_wasm_bg.wasm")
|
||||||
.then(wasm_loaded)["catch"](console.error);
|
.then(wasm_loaded)["catch"](console.error);
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
var g_webgl_painter = null;
|
var g_webgl_painter = null;
|
||||||
|
|
||||||
function paint_gui(canvas, input) {
|
function paint_gui(canvas, input) {
|
||||||
if (g_webgl_painter === null) {
|
if (g_webgl_painter === null) {
|
||||||
g_webgl_painter = wasm_bindgen.new_webgl_painter("canvas");
|
g_webgl_painter = wasm_bindgen.new_webgl_gui("canvas");
|
||||||
}
|
}
|
||||||
wasm_bindgen.paint_webgl(g_webgl_painter, JSON.stringify(input));
|
wasm_bindgen.run_gui(g_webgl_painter, JSON.stringify(input));
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
var g_mouse_pos = { x: -1000.0, y: -1000.0 };
|
var g_mouse_pos = { x: -1000.0, y: -1000.0 };
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::{font::Font, layout, style, types::GuiInput, Frame, Painter, RawInput};
|
|
||||||
|
|
||||||
/// Encapsulates input, layout and painting for ease of use.
|
|
||||||
pub struct Emgui {
|
|
||||||
pub last_input: RawInput,
|
|
||||||
pub data: Arc<layout::Data>,
|
|
||||||
pub style: style::Style,
|
|
||||||
pub painter: Painter,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Emgui {
|
|
||||||
pub fn new(font: Arc<Font>) -> Emgui {
|
|
||||||
Emgui {
|
|
||||||
last_input: Default::default(),
|
|
||||||
data: Arc::new(layout::Data::new(font.clone())),
|
|
||||||
style: Default::default(),
|
|
||||||
painter: Painter::new(font),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn texture(&self) -> (u16, u16, &[u8]) {
|
|
||||||
self.painter.texture()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_frame(&mut self, new_input: RawInput) {
|
|
||||||
let gui_input = GuiInput::from_last_and_new(&self.last_input, &new_input);
|
|
||||||
self.last_input = new_input;
|
|
||||||
|
|
||||||
let mut new_data = (*self.data).clone();
|
|
||||||
new_data.new_frame(gui_input);
|
|
||||||
self.data = Arc::new(new_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn whole_screen_region(&mut self) -> layout::Region {
|
|
||||||
let size = self.data.input.screen_size;
|
|
||||||
layout::Region {
|
|
||||||
data: self.data.clone(),
|
|
||||||
id: Default::default(),
|
|
||||||
dir: layout::Direction::Vertical,
|
|
||||||
cursor: Default::default(),
|
|
||||||
bounding_size: Default::default(),
|
|
||||||
available_space: size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn options(&self) -> &layout::LayoutOptions {
|
|
||||||
&self.data.options
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_options(&mut self, options: layout::LayoutOptions) {
|
|
||||||
let mut new_data = (*self.data).clone();
|
|
||||||
new_data.options = options;
|
|
||||||
self.data = Arc::new(new_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn paint(&mut self) -> Frame {
|
|
||||||
let gui_commands = self.data.graphics.lock().unwrap().drain();
|
|
||||||
let paint_commands = style::into_paint_commands(gui_commands, &self.style);
|
|
||||||
self.painter.paint(&paint_commands)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,125 +0,0 @@
|
||||||
#![deny(warnings)]
|
|
||||||
|
|
||||||
extern crate serde_json;
|
|
||||||
extern crate wasm_bindgen;
|
|
||||||
|
|
||||||
extern crate emgui;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use emgui::{widgets::label, Emgui, Font, RawInput};
|
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
|
|
||||||
mod app;
|
|
||||||
mod webgl;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
|
||||||
struct Stats {
|
|
||||||
num_vertices: usize,
|
|
||||||
num_triangles: usize,
|
|
||||||
everything_ms: f64,
|
|
||||||
webgl_ms: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn now_ms() -> f64 {
|
|
||||||
web_sys::window()
|
|
||||||
.expect("should have a Window")
|
|
||||||
.performance()
|
|
||||||
.expect("should have a Performance")
|
|
||||||
.now()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct State {
|
|
||||||
app: app::App,
|
|
||||||
emgui: Emgui,
|
|
||||||
webgl_painter: webgl::Painter,
|
|
||||||
stats: Stats,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
fn new(canvas_id: &str) -> Result<State, JsValue> {
|
|
||||||
let font = Arc::new(Font::new(20));
|
|
||||||
let emgui = Emgui::new(font);
|
|
||||||
let webgl_painter = webgl::Painter::new(canvas_id, emgui.texture())?;
|
|
||||||
Ok(State {
|
|
||||||
app: Default::default(),
|
|
||||||
emgui,
|
|
||||||
webgl_painter,
|
|
||||||
stats: Default::default(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&mut self, raw_input: RawInput) -> Result<(), JsValue> {
|
|
||||||
let everything_start = now_ms();
|
|
||||||
|
|
||||||
self.emgui.new_frame(raw_input);
|
|
||||||
|
|
||||||
use crate::app::GuiSettings;
|
|
||||||
|
|
||||||
let mut style = self.emgui.style.clone();
|
|
||||||
let mut region = self.emgui.whole_screen_region();
|
|
||||||
let mut region = region.centered_column(480.0);
|
|
||||||
self.app.show_gui(&mut region);
|
|
||||||
|
|
||||||
let mut options = self.emgui.options().clone();
|
|
||||||
region.foldable("LayoutOptions", |gui| {
|
|
||||||
options.show_gui(gui);
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: move this to some emgui::example module
|
|
||||||
region.foldable("Style", |gui| {
|
|
||||||
style.show_gui(gui);
|
|
||||||
});
|
|
||||||
|
|
||||||
region.foldable("Stats", |gui| {
|
|
||||||
gui.add(label(format!("num_vertices: {}", self.stats.num_vertices)));
|
|
||||||
gui.add(label(format!(
|
|
||||||
"num_triangles: {}",
|
|
||||||
self.stats.num_triangles
|
|
||||||
)));
|
|
||||||
|
|
||||||
gui.add(label("WebGl painter info:"));
|
|
||||||
gui.indent(|gui| {
|
|
||||||
gui.add(label(self.webgl_painter.debug_info()));
|
|
||||||
});
|
|
||||||
|
|
||||||
gui.add(label("Timings:"));
|
|
||||||
gui.indent(|gui| {
|
|
||||||
gui.add(label(format!(
|
|
||||||
"Everything: {:.1} ms",
|
|
||||||
self.stats.everything_ms
|
|
||||||
)));
|
|
||||||
gui.add(label(format!("WebGL: {:.1} ms", self.stats.webgl_ms)));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
self.emgui.set_options(options);
|
|
||||||
self.emgui.style = style;
|
|
||||||
let frame = self.emgui.paint();
|
|
||||||
|
|
||||||
self.stats.num_vertices = frame.vertices.len();
|
|
||||||
self.stats.num_triangles = frame.indices.len() / 3;
|
|
||||||
|
|
||||||
let webgl_start = now_ms();
|
|
||||||
let result = self.webgl_painter.paint(&frame);
|
|
||||||
self.stats.webgl_ms = now_ms() - webgl_start;
|
|
||||||
|
|
||||||
self.stats.everything_ms = now_ms() - everything_start;
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn new_webgl_gui(canvas_id: &str) -> Result<State, JsValue> {
|
|
||||||
State::new(canvas_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn run_gui(state: &mut State, raw_input_json: &str) -> Result<(), JsValue> {
|
|
||||||
// TODO: nicer interface than JSON
|
|
||||||
let raw_input: RawInput = serde_json::from_str(raw_input_json).unwrap();
|
|
||||||
state.run(raw_input)
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "emgui"
|
name = "emigui"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Emil Ernerfeldt <emilernerfeldt@gmail.com>"]
|
authors = ["Emil Ernerfeldt <emilernerfeldt@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
127
emigui/src/emigui.rs
Normal file
127
emigui/src/emigui.rs
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
font::Font,
|
||||||
|
layout,
|
||||||
|
layout::{LayoutOptions, Region},
|
||||||
|
style,
|
||||||
|
types::GuiInput,
|
||||||
|
widgets::*,
|
||||||
|
Frame, Painter, RawInput,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
struct Stats {
|
||||||
|
num_vertices: usize,
|
||||||
|
num_triangles: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_options(options: &mut LayoutOptions, gui: &mut Region) {
|
||||||
|
if gui.add(Button::new("Reset LayoutOptions")).clicked {
|
||||||
|
*options = Default::default();
|
||||||
|
}
|
||||||
|
gui.add(Slider::new(&mut options.item_spacing.x, 0.0, 10.0).text("item_spacing.x"));
|
||||||
|
gui.add(Slider::new(&mut options.item_spacing.y, 0.0, 10.0).text("item_spacing.y"));
|
||||||
|
gui.add(Slider::new(&mut options.window_padding.x, 0.0, 10.0).text("window_padding.x"));
|
||||||
|
gui.add(Slider::new(&mut options.window_padding.y, 0.0, 10.0).text("window_padding.y"));
|
||||||
|
gui.add(Slider::new(&mut options.indent, 0.0, 100.0).text("indent"));
|
||||||
|
gui.add(Slider::new(&mut options.button_padding.x, 0.0, 20.0).text("button_padding.x"));
|
||||||
|
gui.add(Slider::new(&mut options.button_padding.y, 0.0, 20.0).text("button_padding.y"));
|
||||||
|
gui.add(Slider::new(&mut options.start_icon_width, 0.0, 60.0).text("start_icon_width"));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_style(style: &mut style::Style, gui: &mut Region) {
|
||||||
|
if gui.add(Button::new("Reset Style")).clicked {
|
||||||
|
*style = Default::default();
|
||||||
|
}
|
||||||
|
gui.add(Checkbox::new(&mut style.debug_rects, "debug_rects"));
|
||||||
|
gui.add(Slider::new(&mut style.line_width, 0.0, 10.0).text("line_width"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encapsulates input, layout and painting for ease of use.
|
||||||
|
pub struct Emigui {
|
||||||
|
pub last_input: RawInput,
|
||||||
|
pub data: Arc<layout::Data>,
|
||||||
|
pub style: style::Style,
|
||||||
|
pub painter: Painter,
|
||||||
|
stats: Stats,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Emigui {
|
||||||
|
pub fn new(font: Arc<Font>) -> Emigui {
|
||||||
|
Emigui {
|
||||||
|
last_input: Default::default(),
|
||||||
|
data: Arc::new(layout::Data::new(font.clone())),
|
||||||
|
style: Default::default(),
|
||||||
|
painter: Painter::new(font),
|
||||||
|
stats: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture(&self) -> (u16, u16, &[u8]) {
|
||||||
|
self.painter.texture()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_frame(&mut self, new_input: RawInput) {
|
||||||
|
let gui_input = GuiInput::from_last_and_new(&self.last_input, &new_input);
|
||||||
|
self.last_input = new_input;
|
||||||
|
|
||||||
|
let mut new_data = (*self.data).clone();
|
||||||
|
new_data.new_frame(gui_input);
|
||||||
|
self.data = Arc::new(new_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn whole_screen_region(&mut self) -> layout::Region {
|
||||||
|
let size = self.data.input.screen_size;
|
||||||
|
layout::Region {
|
||||||
|
data: self.data.clone(),
|
||||||
|
id: Default::default(),
|
||||||
|
dir: layout::Direction::Vertical,
|
||||||
|
cursor: Default::default(),
|
||||||
|
bounding_size: Default::default(),
|
||||||
|
available_space: size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn options(&self) -> &layout::LayoutOptions {
|
||||||
|
&self.data.options
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_options(&mut self, options: layout::LayoutOptions) {
|
||||||
|
let mut new_data = (*self.data).clone();
|
||||||
|
new_data.options = options;
|
||||||
|
self.data = Arc::new(new_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paint(&mut self) -> Frame {
|
||||||
|
let gui_commands = self.data.graphics.lock().unwrap().drain();
|
||||||
|
let paint_commands = style::into_paint_commands(gui_commands, &self.style);
|
||||||
|
let frame = self.painter.paint(&paint_commands);
|
||||||
|
self.stats.num_vertices = frame.vertices.len();
|
||||||
|
self.stats.num_triangles = frame.indices.len() / 3;
|
||||||
|
frame
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn example(&mut self, region: &mut Region) {
|
||||||
|
let mut options = self.options().clone();
|
||||||
|
region.foldable("LayoutOptions", |gui| {
|
||||||
|
show_options(&mut options, gui);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut style = self.style.clone();
|
||||||
|
region.foldable("Style", |gui| {
|
||||||
|
show_style(&mut style, gui);
|
||||||
|
});
|
||||||
|
|
||||||
|
region.foldable("Stats", |gui| {
|
||||||
|
gui.add(label(format!("num_vertices: {}", self.stats.num_vertices)));
|
||||||
|
gui.add(label(format!(
|
||||||
|
"num_triangles: {}",
|
||||||
|
self.stats.num_triangles
|
||||||
|
)));
|
||||||
|
});
|
||||||
|
|
||||||
|
// self.set_options(options); // TODO
|
||||||
|
self.style = style;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ extern crate serde;
|
||||||
#[macro_use] // TODO: get rid of this
|
#[macro_use] // TODO: get rid of this
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
mod emgui;
|
mod emigui;
|
||||||
mod font;
|
mod font;
|
||||||
mod layout;
|
mod layout;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
|
@ -16,7 +16,7 @@ pub mod types;
|
||||||
pub mod widgets;
|
pub mod widgets;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
emgui::Emgui,
|
emigui::Emigui,
|
||||||
font::Font,
|
font::Font,
|
||||||
layout::LayoutOptions,
|
layout::LayoutOptions,
|
||||||
layout::Region,
|
layout::Region,
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "emgui_wasm"
|
name = "emigui_wasm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Emil Ernerfeldt <emilernerfeldt@gmail.com>"]
|
authors = ["Emil Ernerfeldt <emilernerfeldt@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
@ -13,7 +13,7 @@ serde = "1"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
|
|
||||||
emgui = { path = "../emgui" }
|
emigui = { path = "../emigui" }
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
version = "0.3"
|
version = "0.3"
|
|
@ -1,8 +1,4 @@
|
||||||
use emgui::{math::*, types::*, widgets::*, Region};
|
use emigui::{math::*, types::*, widgets::*, Region};
|
||||||
|
|
||||||
pub trait GuiSettings {
|
|
||||||
fn show_gui(&mut self, gui: &mut Region);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
checked: bool,
|
checked: bool,
|
||||||
|
@ -27,8 +23,10 @@ impl Default for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GuiSettings for App {
|
impl App {
|
||||||
fn show_gui(&mut self, gui: &mut Region) {
|
pub fn show_gui(&mut self, gui: &mut Region) {
|
||||||
|
gui.add(label("Emigui is an Immediate mode GUI written in Rust, compiled to WebAssembly, rendered with WebGL."));
|
||||||
|
|
||||||
gui.add(label(format!(
|
gui.add(label(format!(
|
||||||
"Screen size: {} x {}",
|
"Screen size: {} x {}",
|
||||||
gui.input().screen_size.x,
|
gui.input().screen_size.x,
|
||||||
|
@ -93,29 +91,3 @@ impl GuiSettings for App {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GuiSettings for emgui::LayoutOptions {
|
|
||||||
fn show_gui(&mut self, gui: &mut Region) {
|
|
||||||
if gui.add(Button::new("Reset LayoutOptions")).clicked {
|
|
||||||
*self = Default::default();
|
|
||||||
}
|
|
||||||
gui.add(Slider::new(&mut self.item_spacing.x, 0.0, 10.0).text("item_spacing.x"));
|
|
||||||
gui.add(Slider::new(&mut self.item_spacing.y, 0.0, 10.0).text("item_spacing.y"));
|
|
||||||
gui.add(Slider::new(&mut self.window_padding.x, 0.0, 10.0).text("window_padding.x"));
|
|
||||||
gui.add(Slider::new(&mut self.window_padding.y, 0.0, 10.0).text("window_padding.y"));
|
|
||||||
gui.add(Slider::new(&mut self.indent, 0.0, 100.0).text("indent"));
|
|
||||||
gui.add(Slider::new(&mut self.button_padding.x, 0.0, 20.0).text("button_padding.x"));
|
|
||||||
gui.add(Slider::new(&mut self.button_padding.y, 0.0, 20.0).text("button_padding.y"));
|
|
||||||
gui.add(Slider::new(&mut self.start_icon_width, 0.0, 60.0).text("start_icon_width"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GuiSettings for emgui::Style {
|
|
||||||
fn show_gui(&mut self, gui: &mut Region) {
|
|
||||||
if gui.add(Button::new("Reset Style")).clicked {
|
|
||||||
*self = Default::default();
|
|
||||||
}
|
|
||||||
gui.add(Checkbox::new(&mut self.debug_rects, "debug_rects"));
|
|
||||||
gui.add(Slider::new(&mut self.line_width, 0.0, 10.0).text("line_width"));
|
|
||||||
}
|
|
||||||
}
|
|
82
emigui_wasm/src/lib.rs
Normal file
82
emigui_wasm/src/lib.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#![deny(warnings)]
|
||||||
|
|
||||||
|
extern crate serde_json;
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
extern crate emigui;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use emigui::{widgets::label, Emigui, Font, RawInput};
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
mod app;
|
||||||
|
mod webgl;
|
||||||
|
|
||||||
|
fn now_ms() -> f64 {
|
||||||
|
web_sys::window()
|
||||||
|
.expect("should have a Window")
|
||||||
|
.performance()
|
||||||
|
.expect("should have a Performance")
|
||||||
|
.now()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct State {
|
||||||
|
app: app::App,
|
||||||
|
emigui: Emigui,
|
||||||
|
webgl_painter: webgl::Painter,
|
||||||
|
everything_ms: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn new(canvas_id: &str) -> Result<State, JsValue> {
|
||||||
|
let font = Arc::new(Font::new(20));
|
||||||
|
let emigui = Emigui::new(font);
|
||||||
|
let webgl_painter = webgl::Painter::new(canvas_id, emigui.texture())?;
|
||||||
|
Ok(State {
|
||||||
|
app: Default::default(),
|
||||||
|
emigui,
|
||||||
|
webgl_painter,
|
||||||
|
everything_ms: 0.0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&mut self, raw_input: RawInput) -> Result<(), JsValue> {
|
||||||
|
let everything_start = now_ms();
|
||||||
|
|
||||||
|
self.emigui.new_frame(raw_input);
|
||||||
|
|
||||||
|
let mut region = self.emigui.whole_screen_region();
|
||||||
|
let mut region = region.centered_column(480.0);
|
||||||
|
self.app.show_gui(&mut region);
|
||||||
|
self.emigui.example(&mut region);
|
||||||
|
|
||||||
|
region.add(label("WebGl painter info:"));
|
||||||
|
region.indent(|region| {
|
||||||
|
region.add(label(self.webgl_painter.debug_info()));
|
||||||
|
});
|
||||||
|
|
||||||
|
region.add(label(format!("Everything: {:.1} ms", self.everything_ms)));
|
||||||
|
|
||||||
|
let frame = self.emigui.paint();
|
||||||
|
let result = self.webgl_painter.paint(&frame);
|
||||||
|
|
||||||
|
self.everything_ms = now_ms() - everything_start;
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn new_webgl_gui(canvas_id: &str) -> Result<State, JsValue> {
|
||||||
|
State::new(canvas_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn run_gui(state: &mut State, raw_input_json: &str) -> Result<(), JsValue> {
|
||||||
|
// TODO: nicer interface than JSON
|
||||||
|
let raw_input: RawInput = serde_json::from_str(raw_input_json).unwrap();
|
||||||
|
state.run(raw_input)
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ use {
|
||||||
web_sys::{WebGlBuffer, WebGlProgram, WebGlRenderingContext, WebGlShader, WebGlTexture},
|
web_sys::{WebGlBuffer, WebGlProgram, WebGlRenderingContext, WebGlShader, WebGlTexture},
|
||||||
};
|
};
|
||||||
|
|
||||||
use emgui::Frame;
|
use emigui::Frame;
|
||||||
|
|
||||||
type Gl = WebGlRenderingContext;
|
type Gl = WebGlRenderingContext;
|
||||||
|
|
Loading…
Reference in a new issue