diff --git a/docs/frontend.js b/docs/frontend.js index bf59625b0..3d8642cb5 100644 --- a/docs/frontend.js +++ b/docs/frontend.js @@ -15,18 +15,24 @@ function paintCommand(canvas, cmd) { ctx.stroke(); return; case "circle": - ctx.fillStyle = cmd.fill_style; ctx.beginPath(); ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false); - ctx.fill(); + if (cmd.fill_style) { + ctx.fillStyle = cmd.fill_style; + ctx.fill(); + } + if (cmd.outline) { + ctx.lineWidth = cmd.outline.width; + ctx.strokeStyle = cmd.outline.style; + ctx.stroke(); + } return; - case "rounded_rect": - ctx.fillStyle = cmd.fill_style; + case "rect": var x = cmd.pos.x; var y = cmd.pos.y; var width = cmd.size.x; var height = cmd.size.y; - var r = cmd.corner_radius; + var r = Math.min(cmd.corner_radius, width / 2, height / 2); ctx.beginPath(); ctx.moveTo(x + r, y); ctx.lineTo(x + width - r, y); @@ -38,7 +44,15 @@ function paintCommand(canvas, cmd) { ctx.lineTo(x, y + r); ctx.quadraticCurveTo(x, y, x + r, y); ctx.closePath(); - ctx.fill(); + if (cmd.fill_style) { + ctx.fillStyle = cmd.fill_style; + ctx.fill(); + } + if (cmd.outline) { + ctx.lineWidth = cmd.outline.width; + ctx.strokeStyle = cmd.outline.style; + ctx.stroke(); + } return; case "text": ctx.font = cmd.font; @@ -69,7 +83,7 @@ function js_gui(input) { }); commands.push({ fillStyle: "#ff1111", - kind: "rounded_rect", + kind: "rect", pos: { x: 100, y: 100 }, radius: 20, size: { x: 200, y: 100 } diff --git a/docs/frontend.ts b/docs/frontend.ts index a987728f9..21988068d 100644 --- a/docs/frontend.ts +++ b/docs/frontend.ts @@ -19,31 +19,39 @@ interface Line { to: Vec2; } +interface Outline { + width: number; + style: string; +} + interface Circle { - kind: "circle"; center: Vec2; - fill_style: string; + fill_style: string | null; + kind: "circle"; + outline: Outline | null; radius: number; } -interface RoundedRect { - kind: "rounded_rect"; - fill_style: string; - pos: Vec2; +interface Rect { corner_radius: number; + fill_style: string | null; + kind: "rect"; + outline: Outline | null; + pos: Vec2; size: Vec2; } interface Text { kind: "text"; - fill_style: string; + fill_style: string | null; font: string; pos: Vec2; + stroke_style: string | null; text: string; text_align: "start" | "center" | "end"; } -type PaintCmd = Clear | Line | Circle | RoundedRect | Text; +type PaintCmd = Circle | Clear | Line | Rect | Text; function paintCommand(canvas, cmd: PaintCmd) { const ctx = canvas.getContext("2d"); @@ -66,19 +74,25 @@ function paintCommand(canvas, cmd: PaintCmd) { return; case "circle": - ctx.fillStyle = cmd.fill_style; ctx.beginPath(); ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false); - ctx.fill(); + if (cmd.fill_style) { + ctx.fillStyle = cmd.fill_style; + ctx.fill(); + } + if (cmd.outline) { + ctx.lineWidth = cmd.outline.width; + ctx.strokeStyle = cmd.outline.style; + ctx.stroke(); + } return; - case "rounded_rect": - ctx.fillStyle = cmd.fill_style; + case "rect": const x = cmd.pos.x; const y = cmd.pos.y; const width = cmd.size.x; const height = cmd.size.y; - const r = cmd.corner_radius; + const r = Math.min(cmd.corner_radius, width / 2, height / 2); ctx.beginPath(); ctx.moveTo(x + r, y); ctx.lineTo(x + width - r, y); @@ -90,7 +104,15 @@ function paintCommand(canvas, cmd: PaintCmd) { ctx.lineTo(x, y + r); ctx.quadraticCurveTo(x, y, x + r, y); ctx.closePath(); - ctx.fill(); + if (cmd.fill_style) { + ctx.fillStyle = cmd.fill_style; + ctx.fill(); + } + if (cmd.outline) { + ctx.lineWidth = cmd.outline.width; + ctx.strokeStyle = cmd.outline.style; + ctx.stroke(); + } return; case "text": @@ -149,7 +171,7 @@ function js_gui(input: RawInput): PaintCmd[] { commands.push({ fillStyle: "#ff1111", - kind: "rounded_rect", + kind: "rect", pos: { x: 100, y: 100 }, radius: 20, size: { x: 200, y: 100 }, diff --git a/src/app.rs b/src/app.rs index a108386a7..2f984f242 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,12 +1,25 @@ -use crate::gui::Gui; +use crate::{gui::Gui, math::*, types::*}; -#[derive(Default)] pub struct App { count: i32, - slider_value: f32, + + width: f32, + height: f32, + corner_radius: f32, + stroke_width: f32, } impl App { + pub fn new() -> App { + App { + count: 0, + width: 100.0, + height: 50.0, + corner_radius: 5.0, + stroke_width: 2.0, + } + } + pub fn show_gui(&mut self, gui: &mut Gui) { if gui.button("Click me").clicked { self.count += 1; @@ -14,7 +27,21 @@ impl App { gui.label(format!("The button have been clicked {} times", self.count)); - gui.slider_f32("Slider", &mut self.slider_value, 0.0, 10.0); + 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.commands + .push(GuiCmd::PaintCommands(vec![PaintCmd::Rect { + corner_radius: self.corner_radius, + fill_style: Some("#888888ff".into()), + pos: vec2(300.0, 100.0), + size: vec2(self.width, self.height), + outline: Some(Outline { + width: self.stroke_width, + style: "#ffffffff".into(), + }), + }])); let commands_json = format!("{:#?}", gui.gui_commands()); gui.label(format!("All gui commands: {}", commands_json)); diff --git a/src/lib.rs b/src/lib.rs index 25317656e..4efbbbf37 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 = Default::default(); + static ref APP: Mutex = Mutex::new(app::App::new()); 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 7d330ea31..4fda6021a 100644 --- a/src/style.rs +++ b/src/style.rs @@ -3,6 +3,7 @@ use crate::{math::*, types::*}; /// TODO: a Style struct which defines colors etc fn translate_cmd(out_commands: &mut Vec, cmd: GuiCmd) { match cmd { + GuiCmd::PaintCommands(mut commands) => out_commands.append(&mut commands), GuiCmd::Rect { rect, style, @@ -12,36 +13,19 @@ fn translate_cmd(out_commands: &mut Vec, cmd: GuiCmd) { let fill_style = if interact.active { "#888888ff".to_string() } else if interact.hovered { - "#444444ff".to_string() + "#666666ff".to_string() } else { - "#222222ff".to_string() + "#444444ff".to_string() }; - out_commands.push(PaintCmd::RoundedRect { + out_commands.push(PaintCmd::Rect { corner_radius: 5.0, - fill_style, + fill_style: Some(fill_style), + outline: None, pos: rect.pos, size: rect.size, }); } }, - GuiCmd::Text { - pos, - text, - text_align, - style, - } => { - let fill_style = match style { - TextStyle::Button => "#ffffffbb".to_string(), - TextStyle::Label => "#ffffffbb".to_string(), - }; - out_commands.push(PaintCmd::Text { - fill_style, - font: "14px Palatino".to_string(), - pos, - text, - text_align, - }); - } GuiCmd::Slider { interact, label, @@ -60,21 +44,23 @@ fn translate_cmd(out_commands: &mut Vec, cmd: GuiCmd) { let marker_fill_style = if interact.active { "#888888ff".to_string() } else if interact.hovered { - "#444444ff".to_string() + "#666666ff".to_string() } else { - "#222222ff".to_string() + "#444444ff".to_string() }; - out_commands.push(PaintCmd::RoundedRect { + out_commands.push(PaintCmd::Rect { corner_radius: 2.0, - fill_style: "#111111ff".to_string(), + fill_style: Some("#222222ff".to_string()), + outline: None, pos: thin_rect.pos, size: thin_rect.size, }); - out_commands.push(PaintCmd::RoundedRect { + out_commands.push(PaintCmd::Rect { corner_radius: 3.0, - fill_style: marker_fill_style, + fill_style: Some(marker_fill_style), + outline: None, pos: marker_rect.pos, size: marker_rect.size, }); @@ -82,9 +68,27 @@ fn translate_cmd(out_commands: &mut Vec, cmd: GuiCmd) { out_commands.push(PaintCmd::Text { fill_style: "#ffffffbb".to_string(), font: "14px Palatino".to_string(), - pos: rect.center(), + pos: rect.min(), text: format!("{}: {:.3}", label, value), - text_align: TextAlign::Center, + text_align: TextAlign::Start, + }); + } + GuiCmd::Text { + pos, + text, + text_align, + style, + } => { + let fill_style = match style { + TextStyle::Button => "#ffffffbb".to_string(), + TextStyle::Label => "#ffffffbb".to_string(), + }; + out_commands.push(PaintCmd::Text { + fill_style, + font: "14px Palatino".to_string(), + pos, + text, + text_align, }); } } diff --git a/src/types.rs b/src/types.rs index 86c8109f0..8c8a10cb2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -104,17 +104,12 @@ pub enum TextStyle { #[derive(Clone, Debug, Serialize)] pub enum GuiCmd { + PaintCommands(Vec), Rect { rect: Rect, style: RectStyle, interact: InteractInfo, }, - Text { - pos: Vec2, - text: String, - text_align: TextAlign, - style: TextStyle, - }, Slider { interact: InteractInfo, label: String, @@ -123,24 +118,39 @@ pub enum GuiCmd { rect: Rect, value: f32, }, + Text { + pos: Vec2, + style: TextStyle, + text: String, + text_align: TextAlign, + }, } // ---------------------------------------------------------------------------- +pub type Style = String; + +#[derive(Clone, Debug, Serialize)] +pub struct Outline { + pub width: f32, + pub style: Style, +} + #[derive(Clone, Debug, Serialize)] // TODO: copy #[serde(rename_all = "snake_case", tag = "kind")] pub enum PaintCmd { Clear { - fill_style: String, + fill_style: Style, }, - RoundedRect { - fill_style: String, + Rect { + corner_radius: f32, + fill_style: Option