Nicer rust code

This commit is contained in:
Emil Ernerfeldt 2018-12-24 00:15:18 +01:00
parent 2e2e7a7839
commit 6755a90734
7 changed files with 153 additions and 53 deletions

View file

@ -19,3 +19,8 @@ This is similar to Dear ImGui but separates the layout from the rendering, and a
Input is gathered in TypeScript.
PaintCommands rendered to a HTML canvas.
Everything else is written in Rust, compiled to WASM.
# Test goal:
Make an "any" editor. Store text files, make a VERY SIMPLE text editor, in the web.
Supports MARKDEEP. A place for you ideas. Stored on your computer (local storage).

View file

@ -15,19 +15,23 @@ rm -rf docs/*.d.ts
rm -rf docs/*.js
rm -rf docs/*.wasm
echo "Build rust:"
cargo build --target wasm32-unknown-unknown
function build_rust
{
echo "Build rust:"
cargo build --target wasm32-unknown-unknown
echo "Lint and clean up typescript:"
tslint --fix docs/*.ts
echo "Compile typescript:"
tsc
echo "Generate JS bindings for wasm:"
FOLDER_NAME=${PWD##*/}
TARGET_NAME="$FOLDER_NAME.wasm"
wasm-bindgen "target/wasm32-unknown-unknown/$BUILD/$TARGET_NAME" \
echo "Generate JS bindings for wasm:"
FOLDER_NAME=${PWD##*/}
TARGET_NAME="$FOLDER_NAME.wasm"
wasm-bindgen "target/wasm32-unknown-unknown/$BUILD/$TARGET_NAME" \
--out-dir docs --no-modules
# --no-modules-global hoboho
}
echo "Compile typescript:"
build_rust
tsc
# wait || exit $?
# 3.4 s

Binary file not shown.

View file

@ -2,7 +2,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<head>
<title>Gui Experiment</title>
<title>Emgui A experiment in an Immediate Mode GUI written in Rust</title>
<style>
html {
@ -11,9 +11,9 @@
}
body {
background: #111111;
background: #000000;
color: #bbbbbb;
max-width: 480px;
max-width: 1024px;
margin: auto;
}
</style>
@ -38,7 +38,7 @@
<script src="frontend.js" type="module"></script>
<!-- TODO: make this cover the entire screen, with resize and all -->
<canvas id="canvas" width="480" height="800"></canvas>
<canvas id="canvas" width="1024" height="768"></canvas>
</body>
</html>

5
lint.sh Executable file
View file

@ -0,0 +1,5 @@
#!/bin/bash
set -eu
echo "Lint and clean up typescript:"
tslint --fix docs/*.ts

View file

@ -15,6 +15,76 @@ mod types;
use types::*;
/*
// Fast compilation, slow code:
fn foo(x: &dyn Trait);
// Fast code, slow compilation:
fn foo<T: Trait>(x: &dyn T);
// Compiles quickly in debug, fast in release:
#[dynimp(Trait)]
fn foo(x: &Trait);
*/
#[derive(Default)]
pub struct InteractInfo {
pub is_hovering: bool,
}
// TODO: implement Gui on this so we can add children to a widget
// pub struct Widget {}
pub struct Gui {
commands: Vec<PaintCmd>,
input: Input,
}
impl Gui {
pub fn new(input: Input) -> Self {
Gui {
commands: vec![PaintCmd::Clear {
fill_style: "#44444400".to_string(),
}],
input,
}
}
pub fn input(&self) -> &Input {
&self.input
}
pub fn into_commands(self) -> Vec<PaintCmd> {
self.commands
}
pub fn rect(&mut self, rect: Rect) -> InteractInfo {
let ii = InteractInfo {
is_hovering: rect.contains(&self.input.mouse_pos),
};
self.commands.push(PaintCmd::RoundedRect {
fill_style: "#ffffff10".to_string(),
pos: rect.pos,
corner_radius: 40.0,
size: rect.size,
});
ii
}
pub fn text(&mut self, pos: Vec2, text: String) {
self.commands.push(PaintCmd::Text {
fill_style: "#11ff00".to_string(),
font: "14px Palatino".to_string(),
pos,
text,
text_align: TextAlign::Start,
});
}
}
struct App {
count: i32,
}
@ -24,42 +94,55 @@ impl App {
App { count: 0 }
}
fn show_gui(&mut self, input: &Input) -> Vec<PaintCmd> {
let rect = Rect {
fn show_gui(&mut self, gui: &mut Gui, input: &Input) {
gui.rect(Rect {
pos: Vec2 { x: 0.0, y: 0.0 },
size: input.screen_size,
});
gui.rect(Rect {
pos: Vec2 { x: 50.0, y: 50.0 },
size: Vec2 {
x: (input.screen_size.x - 100.0) / 3.0,
y: (input.screen_size.y - 100.0),
},
});
let is_hovering = gui
.rect(Rect {
pos: Vec2 { x: 100.0, y: 100.0 },
size: Vec2 { x: 200.0, y: 200.0 },
};
}).is_hovering;
let is_hovering = rect.contains(&input.mouse_pos);
if is_hovering {
self.count += 1;
}
vec![
PaintCmd::Clear {
fill_style: "#44444400".to_string(),
},
PaintCmd::Text {
fill_style: "#11ff00".to_string(),
font: "14px Palatino".to_string(),
pos: Vec2 { x: 200.0, y: 32.0 },
text: format!(
gui.text(
Vec2 { x: 100.0, y: 350.0 },
format!(
"Mouse pos: {} {}, is_hovering: {}",
input.mouse_pos.x, input.mouse_pos.y, is_hovering
),
text_align: TextAlign::Center,
);
let m = input.mouse_pos;
let hw = 32.0;
gui.rect(Rect {
pos: Vec2 {
x: m.x - hw,
y: m.y - hw,
},
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,
size: Vec2 {
x: 2.0 * hw,
y: 2.0 * hw,
},
PaintCmd::RoundedRect {
fill_style: "#1111ff".to_string(),
pos: rect.pos,
corner_radius: 40.0,
size: rect.size,
},
]
});
gui.text(
Vec2 { x: 100.0, y: 400.0 },
format!("Count: {}", self.count),
);
}
}
@ -71,6 +154,9 @@ pub fn show_gui(input_json: &str) -> String {
// TODO: faster interface than JSON
let input: Input = serde_json::from_str(input_json).unwrap();
let commands = APP.lock().unwrap().show_gui(&input);
let mut gui = Gui::new(input);
APP.lock().unwrap().show_gui(&mut gui, &input);
let commands = gui.into_commands();
serde_json::to_string(&commands).unwrap()
}

View file

@ -1,10 +1,10 @@
#[derive(Deserialize, Serialize)]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct Vec2 {
pub x: f32,
pub y: f32,
}
#[derive(Deserialize, Serialize)]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct Rect {
pub pos: Vec2,
pub size: Vec2,
@ -19,21 +19,21 @@ impl Rect {
}
}
#[derive(Deserialize)]
#[derive(Clone, Copy, Debug, Deserialize)]
pub struct Input {
pub screen_size: Vec2,
pub mouse_pos: Vec2,
}
#[derive(Serialize)]
#[derive(Clone, Copy, Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum TextAlign {
Start,
Start, // Test with arabic text
Center,
End,
}
#[derive(Serialize)]
#[derive(Clone, Debug, Serialize)] // TODOcopy
#[serde(rename_all = "snake_case", tag = "kind")]
pub enum PaintCmd {
Clear {