diff --git a/docs/frontend.js b/docs/frontend.js index 483a46af..4889dc6a 100644 --- a/docs/frontend.js +++ b/docs/frontend.js @@ -1,22 +1,25 @@ -function paintCommand(canvas, cmd) { +function styleFromColor(color) { + return "rgba(" + color.r + ", " + color.g + ", " + color.b + ", " + color.a / 255.0 + ")"; +} +function paint_command(canvas, cmd) { var ctx = canvas.getContext("2d"); // console.log(`cmd: ${JSON.stringify(cmd)}`); switch (cmd.kind) { case "circle": ctx.beginPath(); ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false); - if (cmd.fill_style) { - ctx.fillStyle = cmd.fill_style; + if (cmd.fill_color) { + ctx.fillStyle = styleFromColor(cmd.fill_color); ctx.fill(); } if (cmd.outline) { ctx.lineWidth = cmd.outline.width; - ctx.strokeStyle = cmd.outline.style; + ctx.strokeStyle = styleFromColor(cmd.outline.color); ctx.stroke(); } return; case "clear": - ctx.fillStyle = cmd.fill_style; + ctx.fillStyle = styleFromColor(cmd.fill_color); ctx.clearRect(0, 0, canvas.width, canvas.height); return; case "line": @@ -27,7 +30,7 @@ function paintCommand(canvas, cmd) { ctx.lineTo(point.x, point.y); } ctx.lineWidth = cmd.width; - ctx.strokeStyle = cmd.style; + ctx.strokeStyle = styleFromColor(cmd.color); ctx.stroke(); return; case "rect": @@ -47,19 +50,19 @@ function paintCommand(canvas, cmd) { ctx.lineTo(x, y + r); ctx.quadraticCurveTo(x, y, x + r, y); ctx.closePath(); - if (cmd.fill_style) { - ctx.fillStyle = cmd.fill_style; + if (cmd.fill_color) { + ctx.fillStyle = styleFromColor(cmd.fill_color); ctx.fill(); } if (cmd.outline) { ctx.lineWidth = cmd.outline.width; - ctx.strokeStyle = cmd.outline.style; + ctx.strokeStyle = styleFromColor(cmd.outline.color); ctx.stroke(); } return; case "text": ctx.font = cmd.font; - ctx.fillStyle = cmd.fill_style; + ctx.fillStyle = styleFromColor(cmd.fill_color); ctx.textAlign = cmd.text_align; ctx.fillText(cmd.text, cmd.pos.x, cmd.pos.y); return; @@ -96,12 +99,12 @@ function js_gui(input) { function paint_gui(canvas, input) { var commands = rust_gui(input); commands.unshift({ - fill_style: "#00000000", + fill_color: { r: 0, g: 0, b: 0, a: 0 }, kind: "clear" }); for (var _i = 0, commands_1 = commands; _i < commands_1.length; _i++) { var cmd = commands_1[_i]; - paintCommand(canvas, cmd); + paint_command(canvas, cmd); } } // ---------------------------------------------------------------------------- diff --git a/docs/frontend.ts b/docs/frontend.ts index 3b5424c4..9bccf18a 100644 --- a/docs/frontend.ts +++ b/docs/frontend.ts @@ -6,26 +6,34 @@ interface Vec2 { // ---------------------------------------------------------------------------- // Paint module: +/// 0-255 sRGBA +interface Color { + r: number; + g: number; + b: number; + a: number; +} + interface Clear { kind: "clear"; - fill_style: string; + fill_color: Color; } interface Line { kind: "line"; points: Vec2[]; - style: string; + color: Color; width: number; } interface Outline { width: number; - style: string; + color: Color; } interface Circle { center: Vec2; - fill_style: string | null; + fill_color: Color | null; kind: "circle"; outline: Outline | null; radius: number; @@ -33,7 +41,7 @@ interface Circle { interface Rect { corner_radius: number; - fill_style: string | null; + fill_color: Color | null; kind: "rect"; outline: Outline | null; pos: Vec2; @@ -42,17 +50,21 @@ interface Rect { interface Text { kind: "text"; - fill_style: string | null; + fill_color: Color | null; font: string; pos: Vec2; - stroke_style: string | null; + stroke_color: Color | null; text: string; text_align: "start" | "center" | "end"; } type PaintCmd = Circle | Clear | Line | Rect | Text; -function paintCommand(canvas, cmd: PaintCmd) { +function styleFromColor(color: Color): string { + return `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a / 255.0})`; +} + +function paint_command(canvas, cmd: PaintCmd) { const ctx = canvas.getContext("2d"); // console.log(`cmd: ${JSON.stringify(cmd)}`); @@ -61,19 +73,19 @@ function paintCommand(canvas, cmd: PaintCmd) { case "circle": ctx.beginPath(); ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false); - if (cmd.fill_style) { - ctx.fillStyle = cmd.fill_style; + if (cmd.fill_color) { + ctx.fillStyle = styleFromColor(cmd.fill_color); ctx.fill(); } if (cmd.outline) { ctx.lineWidth = cmd.outline.width; - ctx.strokeStyle = cmd.outline.style; + ctx.strokeStyle = styleFromColor(cmd.outline.color); ctx.stroke(); } return; case "clear": - ctx.fillStyle = cmd.fill_style; + ctx.fillStyle = styleFromColor(cmd.fill_color); ctx.clearRect(0, 0, canvas.width, canvas.height); return; @@ -84,7 +96,7 @@ function paintCommand(canvas, cmd: PaintCmd) { ctx.lineTo(point.x, point.y); } ctx.lineWidth = cmd.width; - ctx.strokeStyle = cmd.style; + ctx.strokeStyle = styleFromColor(cmd.color); ctx.stroke(); return; @@ -105,20 +117,20 @@ function paintCommand(canvas, cmd: PaintCmd) { ctx.lineTo(x, y + r); ctx.quadraticCurveTo(x, y, x + r, y); ctx.closePath(); - if (cmd.fill_style) { - ctx.fillStyle = cmd.fill_style; + if (cmd.fill_color) { + ctx.fillStyle = styleFromColor(cmd.fill_color); ctx.fill(); } if (cmd.outline) { ctx.lineWidth = cmd.outline.width; - ctx.strokeStyle = cmd.outline.style; + ctx.strokeStyle = styleFromColor(cmd.outline.color); ctx.stroke(); } return; case "text": ctx.font = cmd.font; - ctx.fillStyle = cmd.fill_style; + ctx.fillStyle = styleFromColor(cmd.fill_color); ctx.textAlign = cmd.text_align; ctx.fillText(cmd.text, cmd.pos.x, cmd.pos.y); return; @@ -184,12 +196,12 @@ function js_gui(input: RawInput): PaintCmd[] { function paint_gui(canvas, input: RawInput) { const commands = rust_gui(input); commands.unshift({ - fill_style: "#00000000", + fill_color: {r: 0, g: 0, b: 0, a: 0}, kind: "clear", }); for (const cmd of commands) { - paintCommand(canvas, cmd); + paint_command(canvas, cmd); } } diff --git a/src/app.rs b/src/app.rs index c6389c5e..2128eb94 100644 --- a/src/app.rs +++ b/src/app.rs @@ -66,12 +66,12 @@ impl GuiSettings for App { gui.commands .push(GuiCmd::PaintCommands(vec![PaintCmd::Rect { corner_radius: self.corner_radius, - fill_style: Some("#888888ff".into()), + fill_color: Some(srgba(136, 136, 136, 255)), pos: vec2(300.0, 100.0), size: vec2(self.width, self.height), outline: Some(Outline { width: self.stroke_width, - style: "#ffffffff".into(), + color: srgba(255, 255, 255, 255), }), }])); diff --git a/src/style.rs b/src/style.rs index 9141ed44..0450612e 100644 --- a/src/style.rs +++ b/src/style.rs @@ -21,23 +21,23 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { rect, text, } => { - let rect_fill_style = if interact.active { - "#888888ff".to_string() + let rect_fill_color = if interact.active { + srgba(136, 136, 136, 255) } else if interact.hovered { - "#666666ff".to_string() + srgba(100, 100, 100, 255) } else { - "#444444ff".to_string() + srgba(68, 68, 68, 255) }; out_commands.push(PaintCmd::Rect { corner_radius: 5.0, - fill_style: Some(rect_fill_style), + fill_color: Some(rect_fill_color), outline: None, pos: rect.pos, size: rect.size, }); // TODO: clip-rect of text out_commands.push(PaintCmd::Text { - fill_style: "#ffffffbb".to_string(), + fill_color: srgba(255, 255, 255, 187), font: "14px Palatino".to_string(), pos: Vec2 { x: rect.center().x, @@ -53,20 +53,20 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { rect, text, } => { - let fill_style = if interact.active { - "#888888ff".to_string() + let fill_color = if interact.active { + srgba(136, 136, 136, 255) } else if interact.hovered { - "#666666ff".to_string() + srgba(100, 100, 100, 255) } else { - "#444444ff".to_string() + srgba(68, 68, 68, 255) }; - let stroke_style = if interact.active { - "#ffffffff".to_string() + let stroke_color = if interact.active { + srgba(255, 255, 255, 255) } else if interact.hovered { - "#ffffffcc".to_string() + srgba(255, 255, 255, 200) } else { - "#ffffffaa".to_string() + srgba(255, 255, 255, 170) }; let box_side = 16.0; @@ -76,7 +76,7 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { ); out_commands.push(PaintCmd::Rect { corner_radius: 3.0, - fill_style: Some(fill_style), + fill_color: Some(fill_color), outline: None, pos: box_rect.pos, size: box_rect.size, @@ -90,13 +90,13 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { vec2(smaller_rect.center().x, smaller_rect.max().y), vec2(smaller_rect.max().x, smaller_rect.min().y), ], - style: stroke_style.clone(), + color: stroke_color, width: style.line_width, }); } out_commands.push(PaintCmd::Text { - fill_style: stroke_style.clone(), + fill_color: stroke_color, font: "14px Palatino".to_string(), pos: Vec2 { x: box_rect.max().x + 4.0, @@ -112,27 +112,27 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { rect, text, } => { - let fill_style = if interact.active { - "#888888ff".to_string() + let fill_color = if interact.active { + srgba(136, 136, 136, 255) } else if interact.hovered { - "#666666ff".to_string() + srgba(100, 100, 100, 255) } else { - "#444444ff".to_string() + srgba(68, 68, 68, 255) }; - let stroke_style = if interact.active { - "#ffffffff".to_string() + let stroke_color = if interact.active { + srgba(255, 255, 255, 255) } else if interact.hovered { - "#ffffffcc".to_string() + srgba(255, 255, 255, 200) } else { - "#ffffffaa".to_string() + srgba(255, 255, 255, 170) }; let circle_radius = 8.0; let circle_center = vec2(rect.min().x + circle_radius, rect.center().y); out_commands.push(PaintCmd::Circle { center: circle_center, - fill_style: Some(fill_style), + fill_color: Some(fill_color), outline: None, radius: circle_radius, }); @@ -140,14 +140,14 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { if checked { out_commands.push(PaintCmd::Circle { center: circle_center, - fill_style: Some("#000000ff".to_string()), + fill_color: Some(srgba(0, 0, 0, 255)), outline: None, radius: circle_radius * 0.5, }); } out_commands.push(PaintCmd::Text { - fill_style: stroke_style.clone(), + fill_color: stroke_color, font: "14px Palatino".to_string(), pos: Vec2 { x: rect.min().x + 2.0 * circle_radius + 4.0, @@ -177,17 +177,17 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { vec2(16.0, 16.0), ); - let marker_fill_style = if interact.active { - "#888888ff".to_string() + let marker_fill_color = if interact.active { + srgba(136, 136, 136, 255) } else if interact.hovered { - "#666666ff".to_string() + srgba(100, 100, 100, 255) } else { - "#444444ff".to_string() + srgba(68, 68, 68, 255) }; out_commands.push(PaintCmd::Rect { corner_radius: 2.0, - fill_style: Some("#222222ff".to_string()), + fill_color: Some(srgba(34, 34, 34, 255)), outline: None, pos: thin_rect.pos, size: thin_rect.size, @@ -195,14 +195,14 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { out_commands.push(PaintCmd::Rect { corner_radius: 3.0, - fill_style: Some(marker_fill_style), + fill_color: Some(marker_fill_color), outline: None, pos: marker_rect.pos, size: marker_rect.size, }); out_commands.push(PaintCmd::Text { - fill_style: "#ffffffbb".to_string(), + fill_color: srgba(255, 255, 255, 187), font: "14px Palatino".to_string(), pos: vec2( rect.min().x, @@ -218,11 +218,11 @@ fn translate_cmd(out_commands: &mut Vec, style: &Style, cmd: GuiCmd) { text_align, style, } => { - let fill_style = match style { - TextStyle::Label => "#ffffffbb".to_string(), + let fill_color = match style { + TextStyle::Label => srgba(255, 255, 255, 187), }; out_commands.push(PaintCmd::Text { - fill_style, + fill_color, font: "14px Palatino".to_string(), pos: pos + vec2(0.0, 7.0), // TODO: FIXME text, diff --git a/src/types.rs b/src/types.rs index f2f96b22..d4618365 100644 --- a/src/types.rs +++ b/src/types.rs @@ -48,6 +48,21 @@ impl GuiInput { // ---------------------------------------------------------------------------- +/// 0-255 sRGBA +#[derive(Clone, Copy, Debug, Default, Serialize)] +pub struct Color { + pub r: u8, + pub g: u8, + pub b: u8, + pub a: u8, +} + +pub fn srgba(r: u8, g: u8, b: u8, a: u8) -> Color { + Color { r, g, b, a } +} + +// ---------------------------------------------------------------------------- + #[derive(Clone, Copy, Debug, Default, Serialize)] pub struct InteractInfo { pub hovered: bool, @@ -111,12 +126,10 @@ pub enum GuiCmd { // ---------------------------------------------------------------------------- -pub type Style = String; - #[derive(Clone, Debug, Serialize)] pub struct Outline { pub width: f32, - pub style: Style, + pub color: Color, } #[derive(Clone, Debug, Serialize)] // TODO: copy @@ -124,27 +137,27 @@ pub struct Outline { pub enum PaintCmd { Circle { center: Vec2, - fill_style: Option