Checkbox
This commit is contained in:
parent
2e4d961676
commit
4bca549de1
7 changed files with 175 additions and 78 deletions
|
@ -2,18 +2,6 @@ function paintCommand(canvas, cmd) {
|
||||||
var ctx = canvas.getContext("2d");
|
var ctx = canvas.getContext("2d");
|
||||||
// console.log(`cmd: ${JSON.stringify(cmd)}`);
|
// console.log(`cmd: ${JSON.stringify(cmd)}`);
|
||||||
switch (cmd.kind) {
|
switch (cmd.kind) {
|
||||||
case "clear":
|
|
||||||
ctx.fillStyle = cmd.fill_style;
|
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
||||||
return;
|
|
||||||
case "line":
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.lineWidth = cmd.line_width;
|
|
||||||
ctx.strokeStyle = cmd.stroke_style;
|
|
||||||
ctx.moveTo(cmd.from.x, cmd.from.y);
|
|
||||||
ctx.lineTo(cmd.to.x, cmd.to.y);
|
|
||||||
ctx.stroke();
|
|
||||||
return;
|
|
||||||
case "circle":
|
case "circle":
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false);
|
ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false);
|
||||||
|
@ -27,6 +15,21 @@ function paintCommand(canvas, cmd) {
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
case "clear":
|
||||||
|
ctx.fillStyle = cmd.fill_style;
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
return;
|
||||||
|
case "line":
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(cmd.points[0].x, cmd.points[0].y);
|
||||||
|
for (var _i = 0, _a = cmd.points; _i < _a.length; _i++) {
|
||||||
|
var point = _a[_i];
|
||||||
|
ctx.lineTo(point.x, point.y);
|
||||||
|
}
|
||||||
|
ctx.lineWidth = cmd.width;
|
||||||
|
ctx.strokeStyle = cmd.style;
|
||||||
|
ctx.stroke();
|
||||||
|
return;
|
||||||
case "rect":
|
case "rect":
|
||||||
var x = cmd.pos.x;
|
var x = cmd.pos.x;
|
||||||
var y = cmd.pos.y;
|
var y = cmd.pos.y;
|
||||||
|
|
|
@ -13,10 +13,9 @@ interface Clear {
|
||||||
|
|
||||||
interface Line {
|
interface Line {
|
||||||
kind: "line";
|
kind: "line";
|
||||||
from: Vec2;
|
points: Vec2[];
|
||||||
line_width: number;
|
style: string;
|
||||||
stroke_style: string;
|
width: number;
|
||||||
to: Vec2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Outline {
|
interface Outline {
|
||||||
|
@ -59,20 +58,6 @@ function paintCommand(canvas, cmd: PaintCmd) {
|
||||||
// console.log(`cmd: ${JSON.stringify(cmd)}`);
|
// console.log(`cmd: ${JSON.stringify(cmd)}`);
|
||||||
|
|
||||||
switch (cmd.kind) {
|
switch (cmd.kind) {
|
||||||
case "clear":
|
|
||||||
ctx.fillStyle = cmd.fill_style;
|
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case "line":
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.lineWidth = cmd.line_width;
|
|
||||||
ctx.strokeStyle = cmd.stroke_style;
|
|
||||||
ctx.moveTo(cmd.from.x, cmd.from.y);
|
|
||||||
ctx.lineTo(cmd.to.x, cmd.to.y);
|
|
||||||
ctx.stroke();
|
|
||||||
return;
|
|
||||||
|
|
||||||
case "circle":
|
case "circle":
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false);
|
ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false);
|
||||||
|
@ -87,6 +72,22 @@ function paintCommand(canvas, cmd: PaintCmd) {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case "clear":
|
||||||
|
ctx.fillStyle = cmd.fill_style;
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case "line":
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(cmd.points[0].x, cmd.points[0].y);
|
||||||
|
for (const point of cmd.points) {
|
||||||
|
ctx.lineTo(point.x, point.y);
|
||||||
|
}
|
||||||
|
ctx.lineWidth = cmd.width;
|
||||||
|
ctx.strokeStyle = cmd.style;
|
||||||
|
ctx.stroke();
|
||||||
|
return;
|
||||||
|
|
||||||
case "rect":
|
case "rect":
|
||||||
const x = cmd.pos.x;
|
const x = cmd.pos.x;
|
||||||
const y = cmd.pos.y;
|
const y = cmd.pos.y;
|
||||||
|
|
17
src/app.rs
17
src/app.rs
|
@ -1,6 +1,7 @@
|
||||||
use crate::{gui::Gui, math::*, types::*};
|
use crate::{gui::Gui, math::*, types::*};
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
|
checked: bool,
|
||||||
count: i32,
|
count: i32,
|
||||||
|
|
||||||
width: f32,
|
width: f32,
|
||||||
|
@ -9,9 +10,10 @@ pub struct App {
|
||||||
stroke_width: f32,
|
stroke_width: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl Default for App {
|
||||||
pub fn new() -> App {
|
fn default() -> App {
|
||||||
App {
|
App {
|
||||||
|
checked: false,
|
||||||
count: 0,
|
count: 0,
|
||||||
width: 100.0,
|
width: 100.0,
|
||||||
height: 50.0,
|
height: 50.0,
|
||||||
|
@ -19,17 +21,22 @@ impl App {
|
||||||
stroke_width: 2.0,
|
stroke_width: 2.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
pub fn show_gui(&mut self, gui: &mut Gui) {
|
pub fn show_gui(&mut self, gui: &mut Gui) {
|
||||||
|
gui.checkbox("checkbox", &mut self.checked);
|
||||||
|
|
||||||
if gui.button("Click me").clicked {
|
if gui.button("Click me").clicked {
|
||||||
self.count += 1;
|
self.count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.label(format!("The button have been clicked {} times", self.count));
|
gui.label(format!("The button have been clicked {} times", self.count));
|
||||||
|
|
||||||
gui.slider_f32("width", &mut self.width, 0.0, 100.0);
|
gui.slider_f32("width", &mut self.width, 0.0, 500.0);
|
||||||
gui.slider_f32("height", &mut self.height, 0.0, 100.0);
|
gui.slider_f32("height", &mut self.height, 0.0, 500.0);
|
||||||
gui.slider_f32("corner_radius", &mut self.corner_radius, 0.0, 100.0);
|
gui.slider_f32("corner_radius", &mut self.corner_radius, 0.0, 50.0);
|
||||||
|
gui.slider_f32("stroke_width", &mut self.stroke_width, 0.0, 10.0);
|
||||||
|
|
||||||
gui.commands
|
gui.commands
|
||||||
.push(GuiCmd::PaintCommands(vec![PaintCmd::Rect {
|
.push(GuiCmd::PaintCommands(vec![PaintCmd::Rect {
|
||||||
|
|
39
src/gui.rs
39
src/gui.rs
|
@ -34,26 +34,41 @@ impl Gui {
|
||||||
let id = self.get_id(&text);
|
let id = self.get_id(&text);
|
||||||
let rect = Rect {
|
let rect = Rect {
|
||||||
pos: self.cursor,
|
pos: self.cursor,
|
||||||
size: Vec2 { x: 200.0, y: 32.0 }, // TODO: get from some settings
|
size: Vec2 { x: 176.0, y: 24.0 }, // TODO: get from some settings
|
||||||
};
|
};
|
||||||
|
|
||||||
let interact = self.interactive_rect(id, &rect);
|
let interact = self.interactive_rect(id, &rect);
|
||||||
|
|
||||||
self.commands.push(GuiCmd::Rect {
|
self.commands.push(GuiCmd::Button {
|
||||||
interact,
|
interact,
|
||||||
rect,
|
rect,
|
||||||
style: RectStyle::Button,
|
text,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.cursor.y += rect.size.y + 16.0;
|
||||||
|
interact
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn checkbox<S: Into<String>>(&mut self, label: S, checked: &mut bool) -> InteractInfo {
|
||||||
|
let label: String = label.into();
|
||||||
|
let id = self.get_id(&label);
|
||||||
|
let rect = Rect {
|
||||||
|
pos: self.cursor,
|
||||||
|
size: Vec2 { x: 200.0, y: 24.0 }, // TODO: get from some settings
|
||||||
|
};
|
||||||
|
|
||||||
|
let interact = self.interactive_rect(id, &rect);
|
||||||
|
if interact.clicked {
|
||||||
|
*checked = !*checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.commands.push(GuiCmd::Checkbox {
|
||||||
|
checked: *checked,
|
||||||
|
interact,
|
||||||
|
rect,
|
||||||
|
text: label,
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: clip-rect of text
|
|
||||||
self.text(
|
|
||||||
Vec2 {
|
|
||||||
x: rect.pos.x + 8.0,
|
|
||||||
y: rect.center().y + 14.0 / 2.0,
|
|
||||||
},
|
|
||||||
TextStyle::Button,
|
|
||||||
text,
|
|
||||||
);
|
|
||||||
self.cursor.y += rect.size.y + 16.0;
|
self.cursor.y += rect.size.y + 16.0;
|
||||||
interact
|
interact
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub fn show_gui(raw_input_json: &str) -> String {
|
||||||
let raw_input: RawInput = serde_json::from_str(raw_input_json).unwrap();
|
let raw_input: RawInput = serde_json::from_str(raw_input_json).unwrap();
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref APP: Mutex<app::App> = Mutex::new(app::App::new());
|
static ref APP: Mutex<app::App> = Default::default();
|
||||||
static ref LAST_INPUT: Mutex<RawInput> = Default::default();
|
static ref LAST_INPUT: Mutex<RawInput> = Default::default();
|
||||||
static ref GUI_STATE: Mutex<gui::GuiState> = Default::default();
|
static ref GUI_STATE: Mutex<gui::GuiState> = Default::default();
|
||||||
}
|
}
|
||||||
|
|
107
src/style.rs
107
src/style.rs
|
@ -4,28 +4,96 @@ use crate::{math::*, types::*};
|
||||||
fn translate_cmd(out_commands: &mut Vec<PaintCmd>, cmd: GuiCmd) {
|
fn translate_cmd(out_commands: &mut Vec<PaintCmd>, cmd: GuiCmd) {
|
||||||
match cmd {
|
match cmd {
|
||||||
GuiCmd::PaintCommands(mut commands) => out_commands.append(&mut commands),
|
GuiCmd::PaintCommands(mut commands) => out_commands.append(&mut commands),
|
||||||
GuiCmd::Rect {
|
GuiCmd::Button {
|
||||||
rect,
|
|
||||||
style,
|
|
||||||
interact,
|
interact,
|
||||||
} => match style {
|
rect,
|
||||||
RectStyle::Button => {
|
text,
|
||||||
let fill_style = if interact.active {
|
} => {
|
||||||
"#888888ff".to_string()
|
let rect_fill_style = if interact.active {
|
||||||
} else if interact.hovered {
|
"#888888ff".to_string()
|
||||||
"#666666ff".to_string()
|
} else if interact.hovered {
|
||||||
} else {
|
"#666666ff".to_string()
|
||||||
"#444444ff".to_string()
|
} else {
|
||||||
};
|
"#444444ff".to_string()
|
||||||
out_commands.push(PaintCmd::Rect {
|
};
|
||||||
corner_radius: 5.0,
|
out_commands.push(PaintCmd::Rect {
|
||||||
fill_style: Some(fill_style),
|
corner_radius: 5.0,
|
||||||
outline: None,
|
fill_style: Some(rect_fill_style),
|
||||||
pos: rect.pos,
|
outline: None,
|
||||||
size: rect.size,
|
pos: rect.pos,
|
||||||
|
size: rect.size,
|
||||||
|
});
|
||||||
|
// TODO: clip-rect of text
|
||||||
|
out_commands.push(PaintCmd::Text {
|
||||||
|
fill_style: "#ffffffbb".to_string(),
|
||||||
|
font: "14px Palatino".to_string(),
|
||||||
|
pos: Vec2 {
|
||||||
|
x: rect.center().x,
|
||||||
|
y: rect.center().y + 14.0 / 2.0,
|
||||||
|
},
|
||||||
|
text,
|
||||||
|
text_align: TextAlign::Center,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
GuiCmd::Checkbox {
|
||||||
|
checked,
|
||||||
|
interact,
|
||||||
|
rect,
|
||||||
|
text,
|
||||||
|
} => {
|
||||||
|
let fill_style = if interact.active {
|
||||||
|
"#888888ff".to_string()
|
||||||
|
} else if interact.hovered {
|
||||||
|
"#666666ff".to_string()
|
||||||
|
} else {
|
||||||
|
"#444444ff".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let stroke_style = if interact.active {
|
||||||
|
"#ffffffff".to_string()
|
||||||
|
} else if interact.hovered {
|
||||||
|
"#ffffffcc".to_string()
|
||||||
|
} else {
|
||||||
|
"#ffffffaa".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let box_side = 16.0;
|
||||||
|
let box_rect = Rect::from_center_size(
|
||||||
|
vec2(rect.min().x + box_side * 0.5, rect.center().y),
|
||||||
|
vec2(box_side, box_side),
|
||||||
|
);
|
||||||
|
out_commands.push(PaintCmd::Rect {
|
||||||
|
corner_radius: 3.0,
|
||||||
|
fill_style: Some(fill_style),
|
||||||
|
outline: None,
|
||||||
|
pos: box_rect.pos,
|
||||||
|
size: box_rect.size,
|
||||||
|
});
|
||||||
|
|
||||||
|
if checked {
|
||||||
|
let smaller_rect = Rect::from_center_size(box_rect.center(), vec2(10.0, 10.0));
|
||||||
|
out_commands.push(PaintCmd::Line {
|
||||||
|
points: vec![
|
||||||
|
vec2(smaller_rect.min().x, smaller_rect.center().y),
|
||||||
|
vec2(smaller_rect.center().x, smaller_rect.max().y),
|
||||||
|
vec2(smaller_rect.max().x, smaller_rect.min().y),
|
||||||
|
],
|
||||||
|
style: stroke_style.clone(),
|
||||||
|
width: 4.0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
out_commands.push(PaintCmd::Text {
|
||||||
|
fill_style: stroke_style.clone(),
|
||||||
|
font: "14px Palatino".to_string(),
|
||||||
|
pos: Vec2 {
|
||||||
|
x: box_rect.max().x + 4.0,
|
||||||
|
y: rect.center().y + 14.0 / 2.0,
|
||||||
|
},
|
||||||
|
text,
|
||||||
|
text_align: TextAlign::Start,
|
||||||
|
});
|
||||||
|
}
|
||||||
GuiCmd::Slider {
|
GuiCmd::Slider {
|
||||||
interact,
|
interact,
|
||||||
label,
|
label,
|
||||||
|
@ -80,7 +148,6 @@ fn translate_cmd(out_commands: &mut Vec<PaintCmd>, cmd: GuiCmd) {
|
||||||
style,
|
style,
|
||||||
} => {
|
} => {
|
||||||
let fill_style = match style {
|
let fill_style = match style {
|
||||||
TextStyle::Button => "#ffffffbb".to_string(),
|
|
||||||
TextStyle::Label => "#ffffffbb".to_string(),
|
TextStyle::Label => "#ffffffbb".to_string(),
|
||||||
};
|
};
|
||||||
out_commands.push(PaintCmd::Text {
|
out_commands.push(PaintCmd::Text {
|
||||||
|
|
24
src/types.rs
24
src/types.rs
|
@ -89,26 +89,25 @@ pub enum TextAlign {
|
||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum RectStyle {
|
|
||||||
Button,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize)]
|
#[derive(Clone, Copy, Debug, Serialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum TextStyle {
|
pub enum TextStyle {
|
||||||
Button,
|
|
||||||
Label,
|
Label,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
pub enum GuiCmd {
|
pub enum GuiCmd {
|
||||||
PaintCommands(Vec<PaintCmd>),
|
PaintCommands(Vec<PaintCmd>),
|
||||||
Rect {
|
Button {
|
||||||
rect: Rect,
|
|
||||||
style: RectStyle,
|
|
||||||
interact: InteractInfo,
|
interact: InteractInfo,
|
||||||
|
rect: Rect,
|
||||||
|
text: String,
|
||||||
|
},
|
||||||
|
Checkbox {
|
||||||
|
checked: bool,
|
||||||
|
interact: InteractInfo,
|
||||||
|
rect: Rect,
|
||||||
|
text: String,
|
||||||
},
|
},
|
||||||
Slider {
|
Slider {
|
||||||
interact: InteractInfo,
|
interact: InteractInfo,
|
||||||
|
@ -142,6 +141,11 @@ pub enum PaintCmd {
|
||||||
Clear {
|
Clear {
|
||||||
fill_style: Style,
|
fill_style: Style,
|
||||||
},
|
},
|
||||||
|
Line {
|
||||||
|
points: Vec<Vec2>,
|
||||||
|
style: Style,
|
||||||
|
width: f32,
|
||||||
|
},
|
||||||
Rect {
|
Rect {
|
||||||
corner_radius: f32,
|
corner_radius: f32,
|
||||||
fill_style: Option<Style>,
|
fill_style: Option<Style>,
|
||||||
|
|
Loading…
Reference in a new issue