use crate::enums::ShapeType;
use crate::types::{AnimationEffect, Color, Coord, CustomGeomPoint, GradientFill, HyperlinkProps, LineCap, LineJoin, PatternFill, PositionProps, Scene3DProps, ShadowProps, Shape3DProps, ShapeFillProps, ShapeLineProps};
use crate::objects::text::TextObject;
#[derive(Debug, Clone)]
pub struct ShapeObject {
pub object_name: String,
pub shape_type: ShapeType,
pub options: ShapeOptions,
pub text: Option<TextObject>,
}
#[derive(Debug, Clone)]
pub struct ShapeOptions {
pub position: PositionProps,
pub fill: Option<ShapeFillProps>,
pub line: Option<ShapeLineProps>,
pub shadow: Option<ShadowProps>,
pub rotate: Option<f64>,
pub flip_h: bool,
pub flip_v: bool,
pub rect_radius: Option<f64>,
pub hyperlink: Option<HyperlinkProps>,
pub hover: Option<HyperlinkProps>,
pub alt_text: Option<String>,
pub angle_range: Option<[f64; 2]>,
pub arc_thickness: Option<f64>,
pub custom_geometry: Option<Vec<CustomGeomPoint>>,
pub animations: Vec<AnimationEffect>,
pub shape_3d: Option<Shape3DProps>,
pub scene_3d: Option<Scene3DProps>,
}
impl Default for ShapeOptions {
fn default() -> Self {
ShapeOptions {
position: PositionProps::default(),
fill: None,
line: None,
shadow: None,
rotate: None,
flip_h: false,
flip_v: false,
rect_radius: None,
hyperlink: None,
hover: None,
alt_text: None,
angle_range: None,
arc_thickness: None,
custom_geometry: None,
animations: Vec::new(),
shape_3d: None,
scene_3d: None,
}
}
}
pub struct ShapeOptionsBuilder {
opts: ShapeOptions,
}
impl ShapeOptionsBuilder {
pub fn new() -> Self {
ShapeOptionsBuilder { opts: ShapeOptions::default() }
}
pub fn x(mut self, v: f64) -> Self { self.opts.position.x = Some(Coord::Inches(v)); self }
pub fn y(mut self, v: f64) -> Self { self.opts.position.y = Some(Coord::Inches(v)); self }
pub fn w(mut self, v: f64) -> Self { self.opts.position.w = Some(Coord::Inches(v)); self }
pub fn h(mut self, v: f64) -> Self { self.opts.position.h = Some(Coord::Inches(v)); self }
pub fn pos(self, x: f64, y: f64) -> Self {
self.x(x).y(y)
}
pub fn size(self, w: f64, h: f64) -> Self {
self.w(w).h(h)
}
pub fn rect(self, r: crate::layout::CellRect) -> Self {
self.pos(r.x, r.y).size(r.w, r.h)
}
pub fn bounds(self, x: f64, y: f64, w: f64, h: f64) -> Self {
self.pos(x, y).size(w, h)
}
pub fn x_pct(mut self, v: f64) -> Self { self.opts.position.x = Some(Coord::Percent(v)); self }
pub fn y_pct(mut self, v: f64) -> Self { self.opts.position.y = Some(Coord::Percent(v)); self }
pub fn w_pct(mut self, v: f64) -> Self { self.opts.position.w = Some(Coord::Percent(v)); self }
pub fn h_pct(mut self, v: f64) -> Self { self.opts.position.h = Some(Coord::Percent(v)); self }
pub fn fill_color(mut self, color: impl Into<String>) -> Self {
let mut fill = ShapeFillProps::default();
fill.color = Some(Color::Hex(color.into().trim_start_matches('#').to_uppercase()));
self.opts.fill = Some(fill);
self
}
pub fn fill_color_value(mut self, color: Color) -> Self {
let mut fill = ShapeFillProps::default();
fill.color = Some(color);
self.opts.fill = Some(fill);
self
}
pub fn no_fill(mut self) -> Self {
let mut fill = ShapeFillProps::default();
fill.fill_type = crate::types::FillType::None;
self.opts.fill = Some(fill);
self
}
pub fn gradient_fill(mut self, g: GradientFill) -> Self {
self.opts.fill = Some(ShapeFillProps {
fill_type: crate::types::FillType::Gradient,
color: None,
transparency: None,
gradient: Some(g),
pattern: None,
});
self
}
pub fn line_color(mut self, color: impl Into<String>) -> Self {
let line = self.opts.line.get_or_insert_with(ShapeLineProps::default);
line.color = Some(color.into().trim_start_matches('#').to_uppercase());
self
}
pub fn line_width(mut self, pt: f64) -> Self {
let line = self.opts.line.get_or_insert_with(ShapeLineProps::default);
line.width = Some(pt);
self
}
pub fn line_cap(mut self, cap: LineCap) -> Self {
let line = self.opts.line.get_or_insert_with(ShapeLineProps::default);
line.cap = Some(cap);
self
}
pub fn line_join(mut self, join: LineJoin) -> Self {
let line = self.opts.line.get_or_insert_with(ShapeLineProps::default);
line.join = Some(join);
self
}
pub fn rotate(mut self, deg: f64) -> Self { self.opts.rotate = Some(deg); self }
pub fn flip_h(mut self) -> Self { self.opts.flip_h = true; self }
pub fn flip_v(mut self) -> Self { self.opts.flip_v = true; self }
pub fn shadow(mut self, s: ShadowProps) -> Self { self.opts.shadow = Some(s); self }
pub fn rect_radius(mut self, r: f64) -> Self { self.opts.rect_radius = Some(r); self }
pub fn hyperlink(mut self, h: HyperlinkProps) -> Self { self.opts.hyperlink = Some(h); self }
pub fn hover(mut self, h: HyperlinkProps) -> Self { self.opts.hover = Some(h); self }
pub fn alt_text(mut self, t: impl Into<String>) -> Self { self.opts.alt_text = Some(t.into()); self }
pub fn angle_range(mut self, start: f64, swing: f64) -> Self {
self.opts.angle_range = Some([start, swing]);
self
}
pub fn arc_thickness(mut self, ratio: f64) -> Self { self.opts.arc_thickness = Some(ratio); self }
pub fn custom_geometry(mut self, pts: Vec<CustomGeomPoint>) -> Self {
self.opts.custom_geometry = Some(pts);
self
}
pub fn pattern_fill(mut self, p: PatternFill) -> Self {
self.opts.fill = Some(ShapeFillProps {
fill_type: crate::types::FillType::Pattern,
color: None,
transparency: None,
gradient: None,
pattern: Some(p),
});
self
}
pub fn animation(mut self, anim: AnimationEffect) -> Self { self.opts.animations.push(anim); self }
pub fn shape_3d(mut self, props: Shape3DProps) -> Self { self.opts.shape_3d = Some(props); self }
pub fn scene_3d(mut self, props: Scene3DProps) -> Self { self.opts.scene_3d = Some(props); self }
pub fn build(self) -> ShapeOptions {
self.opts
}
}
impl Default for ShapeOptionsBuilder {
fn default() -> Self {
Self::new()
}
}