/// Converts a percentage (0-100) to pixels based on the dimension #[inline] pub fn percent_to_pixel(percentage: f64, dimension: f64) -> f64 { (percentage * dimension) / 100.0 } /// Parses a hex color string to RGB components (0.0-1.0) pub fn parse_color(color: &str) -> (f64, f64, f64) { let color = color.trim_start_matches('#'); if color.len() != 6 { return (0.0, 0.0, 0.0); // Default to black on error } let r = u8::from_str_radix(&color[0..2], 16).unwrap_or(0) as f64 / 255.0; let g = u8::from_str_radix(&color[2..4], 16).unwrap_or(0) as f64 / 255.0; let b = u8::from_str_radix(&color[4..6], 16).unwrap_or(0) as f64 / 255.0; (r, g, b) } /// Sets the cairo context color from a hex string pub fn set_color(ctx: &cairo::Context, color: &str) { let (r, g, b) = parse_color(color); ctx.set_source_rgb(r, g, b); } #[cfg(test)] mod tests { use super::*; #[test] fn test_percent_to_pixel() { assert_eq!(percent_to_pixel(0.0, 100.0), 0.0); assert_eq!(percent_to_pixel(50.0, 100.0), 50.0); assert_eq!(percent_to_pixel(100.0, 100.0), 100.0); assert_eq!(percent_to_pixel(25.0, 1300.0), 325.0); } #[test] fn test_parse_color() { // Test white assert_eq!(parse_color("#FFFFFF"), (1.0, 1.0, 1.0)); // Test black assert_eq!(parse_color("#000000"), (0.0, 0.0, 0.0)); // Test custom color (#0F261F) let (r, g, b) = parse_color("#0F261F"); assert!((r - 0.058823).abs() < 0.001); // 15/255 assert!((g - 0.149019).abs() < 0.001); // 38/255 assert!((b - 0.121568).abs() < 0.001); // 31/255 } }