From 4bca549de13a31b2537feb39332ce19fb5522d5b Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 26 Dec 2018 22:17:33 +0100 Subject: [PATCH] Checkbox --- docs/frontend.js | 27 ++++++------ docs/frontend.ts | 37 ++++++++-------- src/app.rs | 17 +++++--- src/gui.rs | 39 +++++++++++------ src/lib.rs | 2 +- src/style.rs | 107 ++++++++++++++++++++++++++++++++++++++--------- src/types.rs | 24 ++++++----- 7 files changed, 175 insertions(+), 78 deletions(-) diff --git a/docs/frontend.js b/docs/frontend.js index 3d8642cb..483a46af 100644 --- a/docs/frontend.js +++ b/docs/frontend.js @@ -2,18 +2,6 @@ function paintCommand(canvas, cmd) { var ctx = canvas.getContext("2d"); // console.log(`cmd: ${JSON.stringify(cmd)}`); 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": ctx.beginPath(); 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(); } 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": var x = cmd.pos.x; var y = cmd.pos.y; diff --git a/docs/frontend.ts b/docs/frontend.ts index 21988068..3b5424c4 100644 --- a/docs/frontend.ts +++ b/docs/frontend.ts @@ -13,10 +13,9 @@ interface Clear { interface Line { kind: "line"; - from: Vec2; - line_width: number; - stroke_style: string; - to: Vec2; + points: Vec2[]; + style: string; + width: number; } interface Outline { @@ -59,20 +58,6 @@ function paintCommand(canvas, cmd: PaintCmd) { // console.log(`cmd: ${JSON.stringify(cmd)}`); 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": ctx.beginPath(); 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; + 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": const x = cmd.pos.x; const y = cmd.pos.y; diff --git a/src/app.rs b/src/app.rs index 2f984f24..bbe7679d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,6 +1,7 @@ use crate::{gui::Gui, math::*, types::*}; pub struct App { + checked: bool, count: i32, width: f32, @@ -9,9 +10,10 @@ pub struct App { stroke_width: f32, } -impl App { - pub fn new() -> App { +impl Default for App { + fn default() -> App { App { + checked: false, count: 0, width: 100.0, height: 50.0, @@ -19,17 +21,22 @@ impl App { stroke_width: 2.0, } } +} +impl App { pub fn show_gui(&mut self, gui: &mut Gui) { + gui.checkbox("checkbox", &mut self.checked); + if gui.button("Click me").clicked { self.count += 1; } 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("height", &mut self.height, 0.0, 100.0); - gui.slider_f32("corner_radius", &mut self.corner_radius, 0.0, 100.0); + gui.slider_f32("width", &mut self.width, 0.0, 500.0); + gui.slider_f32("height", &mut self.height, 0.0, 500.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 .push(GuiCmd::PaintCommands(vec![PaintCmd::Rect { diff --git a/src/gui.rs b/src/gui.rs index e01d0e92..a18a0e71 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -34,26 +34,41 @@ impl Gui { let id = self.get_id(&text); let rect = Rect { 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); - self.commands.push(GuiCmd::Rect { + self.commands.push(GuiCmd::Button { interact, rect, - style: RectStyle::Button, + text, + }); + + self.cursor.y += rect.size.y + 16.0; + interact + } + + pub fn checkbox>(&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; interact } diff --git a/src/lib.rs b/src/lib.rs index 4efbbbf3..25317656 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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(); lazy_static::lazy_static! { - static ref APP: Mutex = Mutex::new(app::App::new()); + static ref APP: Mutex = Default::default(); static ref LAST_INPUT: Mutex = Default::default(); static ref GUI_STATE: Mutex = Default::default(); } diff --git a/src/style.rs b/src/style.rs index 4fda6021..b8d7bfd7 100644 --- a/src/style.rs +++ b/src/style.rs @@ -4,28 +4,96 @@ use crate::{math::*, types::*}; fn translate_cmd(out_commands: &mut Vec, cmd: GuiCmd) { match cmd { GuiCmd::PaintCommands(mut commands) => out_commands.append(&mut commands), - GuiCmd::Rect { - rect, - style, + GuiCmd::Button { interact, - } => match style { - RectStyle::Button => { - let fill_style = if interact.active { - "#888888ff".to_string() - } else if interact.hovered { - "#666666ff".to_string() - } else { - "#444444ff".to_string() - }; - out_commands.push(PaintCmd::Rect { - corner_radius: 5.0, - fill_style: Some(fill_style), - outline: None, - pos: rect.pos, - size: rect.size, + rect, + text, + } => { + let rect_fill_style = if interact.active { + "#888888ff".to_string() + } else if interact.hovered { + "#666666ff".to_string() + } else { + "#444444ff".to_string() + }; + out_commands.push(PaintCmd::Rect { + corner_radius: 5.0, + fill_style: Some(rect_fill_style), + outline: None, + 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 { interact, label, @@ -80,7 +148,6 @@ fn translate_cmd(out_commands: &mut Vec, cmd: GuiCmd) { style, } => { let fill_style = match style { - TextStyle::Button => "#ffffffbb".to_string(), TextStyle::Label => "#ffffffbb".to_string(), }; out_commands.push(PaintCmd::Text { diff --git a/src/types.rs b/src/types.rs index 8c8a10cb..5e48f507 100644 --- a/src/types.rs +++ b/src/types.rs @@ -89,26 +89,25 @@ pub enum TextAlign { End, } -#[derive(Clone, Copy, Debug, Serialize)] -#[serde(rename_all = "snake_case")] -pub enum RectStyle { - Button, -} - #[derive(Clone, Copy, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum TextStyle { - Button, Label, } #[derive(Clone, Debug, Serialize)] pub enum GuiCmd { PaintCommands(Vec), - Rect { - rect: Rect, - style: RectStyle, + Button { interact: InteractInfo, + rect: Rect, + text: String, + }, + Checkbox { + checked: bool, + interact: InteractInfo, + rect: Rect, + text: String, }, Slider { interact: InteractInfo, @@ -142,6 +141,11 @@ pub enum PaintCmd { Clear { fill_style: Style, }, + Line { + points: Vec, + style: Style, + width: f32, + }, Rect { corner_radius: f32, fill_style: Option