paperforge-layout 0.1.0

High-level document layout engine
Documentation
use paperforge_core::{Color, Point, Size};

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Align {
    Left,
    Center,
    Right,
    Justified,
}

#[derive(Debug, Clone)]
pub enum Element {
    Paragraph(Paragraph),
    Heading(Heading),
    Image(Image),
    List(List),
    Table(Table),
    Spacer(Spacer),
}

#[derive(Debug, Clone)]
pub struct Paragraph {
    pub text: String,
    pub align: Align,
    pub font_size: f64,
    pub color: Color,
    pub line_spacing: f64,
}

impl Paragraph {
    pub fn new(text: &str) -> Self {
        Self {
            text: text.to_string(),
            align: Align::Left,
            font_size: 12.0,
            color: Color::black(),
            line_spacing: 1.15,
        }
    }

    pub fn align(mut self, align: Align) -> Self {
        self.align = align;
        self
    }

    pub fn font_size(mut self, size: f64) -> Self {
        self.font_size = size;
        self
    }

    pub fn color(mut self, color: Color) -> Self {
        self.color = color;
        self
    }

    pub fn line_spacing(mut self, spacing: f64) -> Self {
        self.line_spacing = spacing;
        self
    }
}

#[derive(Debug, Clone)]
pub struct Heading {
    pub text: String,
    pub level: u8,
    pub font_size: f64,
    pub color: Color,
}

impl Heading {
    pub fn new(text: &str) -> Self {
        Self {
            text: text.to_string(),
            level: 1,
            font_size: 24.0,
            color: Color::black(),
        }
    }

    pub fn level(mut self, level: u8) -> Self {
        self.level = level;
        self
    }

    pub fn font_size(mut self, size: f64) -> Self {
        self.font_size = size;
        self
    }

    pub fn color(mut self, color: Color) -> Self {
        self.color = color;
        self
    }
}

#[derive(Debug, Clone)]
pub struct Image {
    pub data: Vec<u8>,
    pub position: Point,
    pub size: Size,
    pub rotation: f64,
    pub opacity: f64,
}

impl Image {
    pub fn new(data: Vec<u8>) -> Self {
        Self {
            data,
            position: Point::new(0.0, 0.0),
            size: Size::new(100.0, 100.0),
            rotation: 0.0,
            opacity: 1.0,
        }
    }

    pub fn at(mut self, x: f64, y: f64) -> Self {
        self.position = Point::new(x, y);
        self
    }

    pub fn width(mut self, width: f64) -> Self {
        self.size.width = width;
        self
    }

    pub fn height(mut self, height: f64) -> Self {
        self.size.height = height;
        self
    }

    pub fn rotate(mut self, angle: f64) -> Self {
        self.rotation = angle;
        self
    }

    pub fn opacity(mut self, opacity: f64) -> Self {
        self.opacity = opacity.clamp(0.0, 1.0);
        self
    }
}

#[derive(Debug, Clone)]
pub enum List {
    Unordered { items: Vec<String> },
    Ordered { items: Vec<String> },
}

impl List {
    pub fn unordered() -> Self {
        Self::Unordered { items: Vec::new() }
    }

    pub fn ordered() -> Self {
        Self::Ordered { items: Vec::new() }
    }

    pub fn item(mut self, text: &str) -> Self {
        match &mut self {
            Self::Unordered { items } => items.push(text.to_string()),
            Self::Ordered { items } => items.push(text.to_string()),
        }
        self
    }
}

#[derive(Debug, Clone)]
pub struct Table {
    pub headers: Vec<String>,
    pub rows: Vec<Vec<String>>,
    pub column_widths: Vec<f64>,
}

impl Table {
    pub fn new() -> Self {
        Self {
            headers: Vec::new(),
            rows: Vec::new(),
            column_widths: Vec::new(),
        }
    }

    pub fn header(mut self, columns: &[&str]) -> Self {
        self.headers = columns.iter().map(|s| s.to_string()).collect();
        self
    }

    pub fn row(mut self, cells: &[&str]) -> Self {
        self.rows
            .push(cells.iter().map(|s| s.to_string()).collect());
        self
    }

    pub fn column_widths(mut self, widths: Vec<f64>) -> Self {
        self.column_widths = widths;
        self
    }
}

impl Default for Table {
    fn default() -> Self {
        Self::new()
    }
}

#[derive(Debug, Clone)]
pub struct Spacer {
    pub height: f64,
}

impl Spacer {
    pub fn new(height: f64) -> Self {
        Self { height }
    }
}