pub mod colors;
pub mod tables;
use crate::generator::{
Shape, ShapeType, ShapeFill, ShapeLine,
ImageBuilder,
TableBuilder, ChartBuilder, ChartType,
};
use crate::elements::{Color, RgbColor};
use crate::core::Dimension;
pub use colors::ColorValue;
pub use colors::{
red, green, blue, yellow, cyan, magenta, white, black, gray, grey,
light_gray, light_grey, dark_gray, dark_grey, silver,
orange, purple, pink, brown, navy, teal, olive, maroon, lime, aqua,
material_red, material_pink, material_purple, material_indigo,
material_blue, material_cyan, material_teal, material_green,
material_lime, material_amber, material_orange, material_brown,
material_gray, material_grey,
corporate_blue, corporate_green, corporate_red, corporate_orange,
};
pub use tables::{
simple_table, table_with_widths, table_from_data, table_with_header,
QuickTable, cell, header_cell, highlight_cell,
};
pub fn rect(x: f64, y: f64, width: f64, height: f64) -> Shape {
Shape::from_dimensions(
ShapeType::Rectangle,
Dimension::Inches(x),
Dimension::Inches(y),
Dimension::Inches(width),
Dimension::Inches(height),
)
}
pub fn circle(x: f64, y: f64, diameter: f64) -> Shape {
Shape::from_dimensions(
ShapeType::Ellipse,
Dimension::Inches(x),
Dimension::Inches(y),
Dimension::Inches(diameter),
Dimension::Inches(diameter),
)
}
pub fn ellipse(x: f64, y: f64, width: f64, height: f64) -> Shape {
Shape::from_dimensions(
ShapeType::Ellipse,
Dimension::Inches(x),
Dimension::Inches(y),
Dimension::Inches(width),
Dimension::Inches(height),
)
}
pub fn rounded_rect(x: f64, y: f64, width: f64, height: f64) -> Shape {
Shape::from_dimensions(
ShapeType::RoundedRectangle,
Dimension::Inches(x),
Dimension::Inches(y),
Dimension::Inches(width),
Dimension::Inches(height),
)
}
pub fn triangle(x: f64, y: f64, width: f64, height: f64) -> Shape {
Shape::from_dimensions(
ShapeType::Triangle,
Dimension::Inches(x),
Dimension::Inches(y),
Dimension::Inches(width),
Dimension::Inches(height),
)
}
pub fn diamond(x: f64, y: f64, width: f64, height: f64) -> Shape {
Shape::from_dimensions(
ShapeType::Diamond,
Dimension::Inches(x),
Dimension::Inches(y),
Dimension::Inches(width),
Dimension::Inches(height),
)
}
pub fn image<T: Into<Vec<u8>>>(data: T) -> ImageBuilder {
ImageBuilder::auto(data.into())
}
pub fn image_file(path: &str) -> crate::exc::Result<ImageBuilder> {
let bytes = std::fs::read(path)?;
Ok(ImageBuilder::auto(bytes))
}
pub fn rgb(r: u8, g: u8, b: u8) -> Color {
Color::Rgb(RgbColor::new(r, g, b))
}
pub fn hex(color: &str) -> Color {
let color = color.trim_start_matches('#');
if color.len() == 6 {
let r = u8::from_str_radix(&color[0..2], 16).unwrap_or(0);
let g = u8::from_str_radix(&color[2..4], 16).unwrap_or(0);
let b = u8::from_str_radix(&color[4..6], 16).unwrap_or(0);
Color::Rgb(RgbColor::new(r, g, b))
} else {
Color::Rgb(RgbColor::new(0, 0, 0)) }
}
pub fn table(column_widths: Vec<u32>) -> TableBuilder {
TableBuilder::new(column_widths)
}
pub fn bar_chart(title: &str) -> ChartBuilder {
ChartBuilder::new(title, ChartType::Bar)
}
pub fn line_chart(title: &str) -> ChartBuilder {
ChartBuilder::new(title, ChartType::Line)
}
pub fn pie_chart(title: &str) -> ChartBuilder {
ChartBuilder::new(title, ChartType::Pie)
}
pub fn area_chart(title: &str) -> ChartBuilder {
ChartBuilder::new(title, ChartType::Area)
}
pub trait ShapeExt {
fn fill(self, color: Color) -> Self;
fn stroke(self, color: Color, width_pt: f64) -> Self;
fn text(self, text: &str) -> Self;
}
impl ShapeExt for Shape {
fn fill(self, color: Color) -> Self {
let color_str = match color {
Color::Rgb(rgb) => format!("{:02X}{:02X}{:02X}", rgb.r, rgb.g, rgb.b),
_ => "000000".to_string(),
};
self.with_fill(ShapeFill::new(&color_str))
}
fn stroke(self, color: Color, width_pt: f64) -> Self {
let color_str = match color {
Color::Rgb(rgb) => format!("{:02X}{:02X}{:02X}", rgb.r, rgb.g, rgb.b),
_ => "000000".to_string(),
};
let width_emu = (width_pt * 12700.0) as u32; self.with_line(ShapeLine::new(&color_str, width_emu))
}
fn text(self, text: &str) -> Self {
self.with_text(text)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::{Positioned, ElementSized};
#[test]
fn test_rect_helper() {
let shape = rect(0.5, 1.0, 2.0, 1.5);
assert_eq!(shape.x(), (0.5 * 914400.0) as u32);
assert_eq!(shape.y(), (1.0 * 914400.0) as u32);
}
#[test]
fn test_circle_helper() {
let shape = circle(2.0, 3.0, 1.5);
assert_eq!(shape.width(), shape.height()); }
#[test]
fn test_rgb_helper() {
let color = rgb(79, 129, 189);
match color {
Color::Rgb(rgb) => {
assert_eq!(rgb.r, 79);
assert_eq!(rgb.g, 129);
assert_eq!(rgb.b, 189);
}
_ => panic!("Expected RGB color"),
}
}
#[test]
fn test_hex_helper() {
let color1 = hex("4F81BD");
let color2 = hex("#4F81BD");
match (color1, color2) {
(Color::Rgb(rgb1), Color::Rgb(rgb2)) => {
assert_eq!(rgb1.r, 79);
assert_eq!(rgb1.g, 129);
assert_eq!(rgb1.b, 189);
assert_eq!(rgb1.r, rgb2.r);
assert_eq!(rgb1.g, rgb2.g);
assert_eq!(rgb1.b, rgb2.b);
}
_ => panic!("Expected RGB colors"),
}
}
#[test]
fn test_shape_ext() {
let shape = rect(0.5, 1.0, 2.0, 1.5)
.fill(rgb(79, 129, 189))
.text("Hello");
assert!(shape.text.is_some());
assert_eq!(shape.text.unwrap(), "Hello");
}
}