Refactor with some better types

This commit is contained in:
Emil Ernerfeldt 2018-12-23 20:06:40 +01:00
parent 856bbf4dae
commit 2e2e7a7839
8 changed files with 176 additions and 185 deletions

View file

@ -2,12 +2,13 @@
name = "emgui" name = "emgui"
version = "0.1.0" version = "0.1.0"
authors = ["Emil Ernerfeldt <emilernerfeldt@gmail.com>"] authors = ["Emil Ernerfeldt <emilernerfeldt@gmail.com>"]
# edition = "2018" // TODO: update
[lib] [lib]
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]
[dependencies] [dependencies]
# rand = { version="0.6", features = ['wasm-bindgen'] } lazy_static = "1"
serde = "1" serde = "1"
serde_derive = "1" serde_derive = "1"
serde_json = "1" serde_json = "1"

8
docs/emgui.d.ts vendored
View file

@ -1,11 +1,3 @@
/* tslint:disable */ /* tslint:disable */
export function show_gui(arg0: string): string; export function show_gui(arg0: string): string;
export class Input {
free(): void;
screen_width: number
screen_height: number
mouse_x: number
mouse_y: number
}

View file

@ -67,59 +67,6 @@
}; };
function freeInput(ptr) {
wasm.__wbg_input_free(ptr);
}
/**
*/
class Input {
free() {
const ptr = this.ptr;
this.ptr = 0;
freeInput(ptr);
}
/**
* @returns {number}
*/
get screen_width() {
return wasm.__wbg_get_input_screen_width(this.ptr);
}
set screen_width(arg0) {
return wasm.__wbg_set_input_screen_width(this.ptr, arg0);
}
/**
* @returns {number}
*/
get screen_height() {
return wasm.__wbg_get_input_screen_height(this.ptr);
}
set screen_height(arg0) {
return wasm.__wbg_set_input_screen_height(this.ptr, arg0);
}
/**
* @returns {number}
*/
get mouse_x() {
return wasm.__wbg_get_input_mouse_x(this.ptr);
}
set mouse_x(arg0) {
return wasm.__wbg_set_input_mouse_x(this.ptr, arg0);
}
/**
* @returns {number}
*/
get mouse_y() {
return wasm.__wbg_get_input_mouse_y(this.ptr);
}
set mouse_y(arg0) {
return wasm.__wbg_set_input_mouse_y(this.ptr, arg0);
}
}
__exports.Input = Input;
__exports.__wbindgen_throw = function(ptr, len) { __exports.__wbindgen_throw = function(ptr, len) {
throw new Error(getStringFromWasm(ptr, len)); throw new Error(getStringFromWasm(ptr, len));
}; };

Binary file not shown.

View file

@ -1,7 +1,6 @@
// ----------------------------------------------------------------------------
// Paint module:
function paintCommand(canvas, cmd) { function paintCommand(canvas, cmd) {
var ctx = canvas.getContext("2d"); var ctx = canvas.getContext("2d");
// console.log(`cmd: ${JSON.stringify(cmd)}`);
switch (cmd.kind) { switch (cmd.kind) {
case "clear": case "clear":
ctx.fillStyle = cmd.fill_style; ctx.fillStyle = cmd.fill_style;
@ -11,33 +10,33 @@ function paintCommand(canvas, cmd) {
ctx.beginPath(); ctx.beginPath();
ctx.lineWidth = cmd.line_width; ctx.lineWidth = cmd.line_width;
ctx.strokeStyle = cmd.stroke_style; ctx.strokeStyle = cmd.stroke_style;
ctx.moveTo(cmd.from[0], cmd.from[1]); ctx.moveTo(cmd.from.x, cmd.from.y);
ctx.lineTo(cmd.to[0], cmd.to[1]); ctx.lineTo(cmd.to.x, cmd.to.y);
ctx.stroke(); ctx.stroke();
return; return;
case "circle": case "circle":
ctx.fillStyle = cmd.fill_style; ctx.fillStyle = cmd.fill_style;
ctx.beginPath(); ctx.beginPath();
ctx.arc(cmd.center[0], cmd.center[1], cmd.radius, 0, 2 * Math.PI, false); ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false);
ctx.fill(); ctx.fill();
return; return;
case "rounded_rect": case "rounded_rect":
ctx.fillStyle = cmd.fill_style; ctx.fillStyle = cmd.fill_style;
var x = cmd.pos[0]; var x = cmd.pos.x;
var y = cmd.pos[1]; var y = cmd.pos.y;
var width = cmd.size[0]; var width = cmd.size.x;
var height = cmd.size[1]; var height = cmd.size.y;
var radius = cmd.radius; var r = cmd.corner_radius;
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(x + radius, y); ctx.moveTo(x + r, y);
ctx.lineTo(x + width - radius, y); ctx.lineTo(x + width - r, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius); ctx.quadraticCurveTo(x + width, y, x + width, y + r);
ctx.lineTo(x + width, y + height - radius); ctx.lineTo(x + width, y + height - r);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); ctx.quadraticCurveTo(x + width, y + height, x + width - r, y + height);
ctx.lineTo(x + radius, y + height); ctx.lineTo(x + r, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius); ctx.quadraticCurveTo(x, y + height, x, y + height - r);
ctx.lineTo(x, y + radius); ctx.lineTo(x, y + r);
ctx.quadraticCurveTo(x, y, x + radius, y); ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath(); ctx.closePath();
ctx.fill(); ctx.fill();
return; return;
@ -45,7 +44,7 @@ function paintCommand(canvas, cmd) {
ctx.font = cmd.font; ctx.font = cmd.font;
ctx.fillStyle = cmd.fill_style; ctx.fillStyle = cmd.fill_style;
ctx.textAlign = cmd.text_align; ctx.textAlign = cmd.text_align;
ctx.fillText(cmd.text, cmd.pos[0], cmd.pos[1]); ctx.fillText(cmd.text, cmd.pos.x, cmd.pos.y);
return; return;
} }
} }
@ -71,18 +70,16 @@ function js_gui(input) {
commands.push({ commands.push({
fillStyle: "#ff1111", fillStyle: "#ff1111",
kind: "rounded_rect", kind: "rounded_rect",
pos: [100, 100], pos: { x: 100, y: 100 },
radius: 20, radius: 20,
size: [200, 100] size: { x: 200, y: 100 }
}); });
return commands; return commands;
} }
function paint_gui(canvas, mouse_pos) { function paint_gui(canvas, mouse_pos) {
var input = { var input = {
mouse_x: mouse_pos.x, mouse_pos: mouse_pos,
mouse_y: mouse_pos.y, screen_size: { x: canvas.width, y: canvas.height }
screen_height: canvas.height,
screen_width: canvas.width
}; };
var commands = rust_gui(input); var commands = rust_gui(input);
for (var _i = 0, commands_1 = commands; _i < commands_1.length; _i++) { for (var _i = 0, commands_1 = commands; _i < commands_1.length; _i++) {

View file

@ -1,3 +1,8 @@
interface Vec2 {
x: number;
y: number;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Paint module: // Paint module:
@ -8,15 +13,15 @@ interface Clear {
interface Line { interface Line {
kind: "line"; kind: "line";
from: [number, number]; from: Vec2;
line_width: number; line_width: number;
stroke_style: string; stroke_style: string;
to: [number, number]; to: Vec2;
} }
interface Circle { interface Circle {
kind: "circle"; kind: "circle";
center: [number, number]; center: Vec2;
fill_style: string; fill_style: string;
radius: number; radius: number;
} }
@ -24,16 +29,16 @@ interface Circle {
interface RoundedRect { interface RoundedRect {
kind: "rounded_rect"; kind: "rounded_rect";
fill_style: string; fill_style: string;
pos: [number, number]; pos: Vec2;
radius: number; corner_radius: number;
size: [number, number]; size: Vec2;
} }
interface Text { interface Text {
kind: "text"; kind: "text";
fill_style: string; fill_style: string;
font: string; font: string;
pos: [number, number]; pos: Vec2;
text: string; text: string;
text_align: "start" | "center" | "end"; text_align: "start" | "center" | "end";
} }
@ -43,6 +48,8 @@ type PaintCmd = Clear | Line | Circle | RoundedRect | Text;
function paintCommand(canvas, cmd: PaintCmd) { function paintCommand(canvas, cmd: PaintCmd) {
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
// console.log(`cmd: ${JSON.stringify(cmd)}`);
switch (cmd.kind) { switch (cmd.kind) {
case "clear": case "clear":
ctx.fillStyle = cmd.fill_style; ctx.fillStyle = cmd.fill_style;
@ -53,40 +60,35 @@ function paintCommand(canvas, cmd: PaintCmd) {
ctx.beginPath(); ctx.beginPath();
ctx.lineWidth = cmd.line_width; ctx.lineWidth = cmd.line_width;
ctx.strokeStyle = cmd.stroke_style; ctx.strokeStyle = cmd.stroke_style;
ctx.moveTo(cmd.from[0], cmd.from[1]); ctx.moveTo(cmd.from.x, cmd.from.y);
ctx.lineTo(cmd.to[0], cmd.to[1]); ctx.lineTo(cmd.to.x, cmd.to.y);
ctx.stroke(); ctx.stroke();
return; return;
case "circle": case "circle":
ctx.fillStyle = cmd.fill_style; ctx.fillStyle = cmd.fill_style;
ctx.beginPath(); ctx.beginPath();
ctx.arc(cmd.center[0], cmd.center[1], cmd.radius, 0, 2 * Math.PI, false); ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false);
ctx.fill(); ctx.fill();
return; return;
case "rounded_rect": case "rounded_rect":
ctx.fillStyle = cmd.fill_style; ctx.fillStyle = cmd.fill_style;
const x = cmd.pos[0]; const x = cmd.pos.x;
const y = cmd.pos[1]; const y = cmd.pos.y;
const width = cmd.size[0]; const width = cmd.size.x;
const height = cmd.size[1]; const height = cmd.size.y;
const radius = cmd.radius; const r = cmd.corner_radius;
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(x + radius, y); ctx.moveTo(x + r, y);
ctx.lineTo(x + width - radius, y); ctx.lineTo(x + width - r, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius); ctx.quadraticCurveTo(x + width, y, x + width, y + r);
ctx.lineTo(x + width, y + height - radius); ctx.lineTo(x + width, y + height - r);
ctx.quadraticCurveTo( ctx.quadraticCurveTo(x + width, y + height, x + width - r, y + height);
x + width, ctx.lineTo(x + r, y + height);
y + height, ctx.quadraticCurveTo(x, y + height, x, y + height - r);
x + width - radius, ctx.lineTo(x, y + r);
y + height, ctx.quadraticCurveTo(x, y, x + r, y);
);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath(); ctx.closePath();
ctx.fill(); ctx.fill();
return; return;
@ -95,23 +97,16 @@ function paintCommand(canvas, cmd: PaintCmd) {
ctx.font = cmd.font; ctx.font = cmd.font;
ctx.fillStyle = cmd.fill_style; ctx.fillStyle = cmd.fill_style;
ctx.textAlign = cmd.text_align; ctx.textAlign = cmd.text_align;
ctx.fillText(cmd.text, cmd.pos[0], cmd.pos[1]); ctx.fillText(cmd.text, cmd.pos.x, cmd.pos.y);
return; return;
} }
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
interface Coord {
x: number;
y: number;
}
interface Input { interface Input {
mouse_x: number; mouse_pos: Vec2;
mouse_y: number; screen_size: Vec2;
screen_height: number;
screen_width: number;
// TODO: mouse down etc // TODO: mouse down etc
} }
@ -149,9 +144,9 @@ function js_gui(input: Input): PaintCmd[] {
commands.push({ commands.push({
fillStyle: "#ff1111", fillStyle: "#ff1111",
kind: "rounded_rect", kind: "rounded_rect",
pos: [100, 100], pos: { x: 100, y: 100 },
radius: 20, radius: 20,
size: [200, 100], size: { x: 200, y: 100 },
}); });
return commands; return commands;
@ -159,10 +154,8 @@ function js_gui(input: Input): PaintCmd[] {
function paint_gui(canvas, mouse_pos) { function paint_gui(canvas, mouse_pos) {
const input = { const input = {
mouse_x: mouse_pos.x, mouse_pos,
mouse_y: mouse_pos.y, screen_size: { x: canvas.width, y: canvas.height },
screen_height: canvas.height,
screen_width: canvas.width,
}; };
const commands = rust_gui(input); const commands = rust_gui(input);
@ -173,7 +166,7 @@ function paint_gui(canvas, mouse_pos) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
function mouse_pos_from_event(canvas, evt): Coord { function mouse_pos_from_event(canvas, evt): Vec2 {
const rect = canvas.getBoundingClientRect(); const rect = canvas.getBoundingClientRect();
return { return {
x: evt.clientX - rect.left, x: evt.clientX - rect.left,

View file

@ -1,70 +1,76 @@
extern crate lazy_static;
extern crate serde; extern crate serde;
extern crate serde_json; extern crate serde_json;
extern crate wasm_bindgen; extern crate wasm_bindgen;
extern crate web_sys; extern crate web_sys;
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
use std::sync::Mutex;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
#[wasm_bindgen] mod types;
#[derive(Deserialize)]
pub struct Input { use types::*;
pub screen_width: f32,
pub screen_height: f32, struct App {
pub mouse_x: f32, count: i32,
pub mouse_y: f32,
} }
#[derive(Serialize)] impl App {
#[serde(rename_all = "snake_case")] fn new() -> Self {
enum TextAlign { App { count: 0 }
Start, }
Center,
End,
}
#[derive(Serialize)] fn show_gui(&mut self, input: &Input) -> Vec<PaintCmd> {
#[serde(rename_all = "snake_case", tag = "kind")] let rect = Rect {
enum PaintCmd { pos: Vec2 { x: 100.0, y: 100.0 },
Clear { size: Vec2 { x: 200.0, y: 200.0 },
fill_style: String, };
},
RoundedRect { let is_hovering = rect.contains(&input.mouse_pos);
fill_style: String,
pos: [f32; 2], vec![
size: [f32; 2], PaintCmd::Clear {
radius: f32, fill_style: "#44444400".to_string(),
}, },
Text { PaintCmd::Text {
fill_style: String, fill_style: "#11ff00".to_string(),
font: String, font: "14px Palatino".to_string(),
pos: [f32; 2], pos: Vec2 { x: 200.0, y: 32.0 },
text: String, text: format!(
text_align: TextAlign, "Mouse pos: {} {}, is_hovering: {}",
}, input.mouse_pos.x, input.mouse_pos.y, is_hovering
),
text_align: TextAlign::Center,
},
PaintCmd::Text {
fill_style: "#11ff00".to_string(),
font: "14px Palatino".to_string(),
pos: Vec2 { x: 200.0, y: 64.0 },
text: format!("Count: {}", self.count),
text_align: TextAlign::Center,
},
PaintCmd::RoundedRect {
fill_style: "#1111ff".to_string(),
pos: rect.pos,
corner_radius: 40.0,
size: rect.size,
},
]
}
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn show_gui(input_json: &str) -> String { pub fn show_gui(input_json: &str) -> String {
lazy_static::lazy_static! {
static ref APP: Mutex<App> = Mutex::new(App::new());
}
// TODO: faster interface than JSON
let input: Input = serde_json::from_str(input_json).unwrap(); let input: Input = serde_json::from_str(input_json).unwrap();
let commands = [ let commands = APP.lock().unwrap().show_gui(&input);
PaintCmd::Clear {
fill_style: "#44444400".to_string(),
},
PaintCmd::RoundedRect {
fill_style: "#1111ff".to_string(),
pos: [100.0, 100.0],
radius: 40.0,
size: [200.0, 200.0],
},
PaintCmd::Text {
fill_style: "#11ff00".to_string(),
font: "14px Palatino".to_string(),
pos: [200.0, 32.0],
text: format!("Mouse pos: {} {}", input.mouse_x, input.mouse_y),
text_align: TextAlign::Center,
},
];
serde_json::to_string(&commands).unwrap() serde_json::to_string(&commands).unwrap()
} }

55
src/types.rs Normal file
View file

@ -0,0 +1,55 @@
#[derive(Deserialize, Serialize)]
pub struct Vec2 {
pub x: f32,
pub y: f32,
}
#[derive(Deserialize, Serialize)]
pub struct Rect {
pub pos: Vec2,
pub size: Vec2,
}
impl Rect {
pub fn contains(&self, p: &Vec2) -> bool {
self.pos.x <= p.x
&& p.x <= self.pos.x + self.size.x
&& self.pos.y <= p.y
&& p.y <= self.pos.y + self.size.y
}
}
#[derive(Deserialize)]
pub struct Input {
pub screen_size: Vec2,
pub mouse_pos: Vec2,
}
#[derive(Serialize)]
#[serde(rename_all = "snake_case")]
pub enum TextAlign {
Start,
Center,
End,
}
#[derive(Serialize)]
#[serde(rename_all = "snake_case", tag = "kind")]
pub enum PaintCmd {
Clear {
fill_style: String,
},
RoundedRect {
fill_style: String,
pos: Vec2,
size: Vec2,
corner_radius: f32,
},
Text {
fill_style: String,
font: String,
pos: Vec2,
text: String,
text_align: TextAlign,
},
}