Nicer rust code
This commit is contained in:
parent
2e2e7a7839
commit
6755a90734
7 changed files with 153 additions and 53 deletions
|
@ -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).
|
||||
|
|
18
build.sh
18
build.sh
|
@ -15,19 +15,23 @@ rm -rf docs/*.d.ts
|
|||
rm -rf docs/*.js
|
||||
rm -rf docs/*.wasm
|
||||
|
||||
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" \
|
||||
--out-dir docs --no-modules
|
||||
# --no-modules-global hoboho
|
||||
}
|
||||
|
||||
echo "Compile typescript:"
|
||||
build_rust
|
||||
tsc
|
||||
|
||||
# wait || exit $?
|
||||
|
||||
# 3.4 s
|
||||
|
|
Binary file not shown.
|
@ -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
5
lint.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
set -eu
|
||||
|
||||
echo "Lint and clean up typescript:"
|
||||
tslint --fix docs/*.ts
|
142
src/lib.rs
142
src/lib.rs
|
@ -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()
|
||||
}
|
||||
|
|
12
src/types.rs
12
src/types.rs
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue