#[derive(Debug, Clone, PartialEq, Default)]
pub struct ShapeProperties {
pub transform: Option<Transform2D>,
pub geometry: Option<Geometry>,
pub fill: Option<Fill>,
pub line: Option<Line>,
pub effects: Option<EffectList>,
pub geometry_adjustments: Vec<GeometryAdjustment>,
}
impl ShapeProperties {
pub fn new() -> Self {
Self::default()
}
pub fn with_transform(mut self, transform: Transform2D) -> Self {
self.transform = Some(transform);
self
}
pub fn with_geometry(mut self, geometry: Geometry) -> Self {
self.geometry = Some(geometry);
self
}
pub fn with_fill(mut self, fill: Fill) -> Self {
self.fill = Some(fill);
self
}
pub fn with_line(mut self, line: Line) -> Self {
self.line = Some(line);
self
}
pub fn with_effects(mut self, effects: EffectList) -> Self {
self.effects = Some(effects);
self
}
pub fn with_geometry_adjustments(mut self, adjustments: Vec<GeometryAdjustment>) -> Self {
self.geometry_adjustments = adjustments;
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GeometryAdjustment {
pub name: String,
pub formula: String,
}
impl GeometryAdjustment {
pub fn new(name: impl Into<String>, formula: impl Into<String>) -> Self {
Self {
name: name.into(),
formula: formula.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct EffectList {
pub outer_shadow: Option<OuterShadow>,
pub glow: Option<Glow>,
pub reflection: Option<Reflection>,
pub soft_edge: Option<SoftEdge>,
}
impl EffectList {
pub fn new() -> Self {
Self::default()
}
pub fn with_outer_shadow(mut self, shadow: OuterShadow) -> Self {
self.outer_shadow = Some(shadow);
self
}
pub fn with_glow(mut self, glow: Glow) -> Self {
self.glow = Some(glow);
self
}
pub fn with_reflection(mut self, reflection: Reflection) -> Self {
self.reflection = Some(reflection);
self
}
pub fn with_soft_edge(mut self, soft_edge: SoftEdge) -> Self {
self.soft_edge = Some(soft_edge);
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct OuterShadow {
pub blur_radius_emu: Option<i64>,
pub distance_emu: Option<i64>,
pub direction_60000ths: Option<i32>,
pub color: Color,
}
impl OuterShadow {
pub fn new(color: Color) -> Self {
Self {
blur_radius_emu: None,
distance_emu: None,
direction_60000ths: None,
color,
}
}
pub fn with_blur_radius_emu(mut self, blur_radius_emu: i64) -> Self {
self.blur_radius_emu = Some(blur_radius_emu);
self
}
pub fn with_distance_emu(mut self, distance_emu: i64) -> Self {
self.distance_emu = Some(distance_emu);
self
}
pub fn with_direction_degrees(mut self, degrees: f64) -> Self {
self.direction_60000ths = Some((degrees * 60_000.0).round() as i32);
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Glow {
pub radius_emu: i64,
pub color: Color,
}
impl Glow {
pub fn new(radius_emu: i64, color: Color) -> Self {
Self { radius_emu, color }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Reflection {
pub blur_radius_emu: Option<i64>,
pub distance_emu: Option<i64>,
pub direction_60000ths: Option<i32>,
pub start_alpha_1000ths_percent: Option<i32>,
pub end_alpha_1000ths_percent: Option<i32>,
}
impl Reflection {
pub fn new() -> Self {
Self::default()
}
pub fn with_blur_radius_emu(mut self, blur_radius_emu: i64) -> Self {
self.blur_radius_emu = Some(blur_radius_emu);
self
}
pub fn with_distance_emu(mut self, distance_emu: i64) -> Self {
self.distance_emu = Some(distance_emu);
self
}
pub fn with_direction_degrees(mut self, degrees: f64) -> Self {
self.direction_60000ths = Some((degrees * 60_000.0).round() as i32);
self
}
pub fn with_start_alpha_percent(mut self, percent: f64) -> Self {
self.start_alpha_1000ths_percent = Some((percent * 1000.0).round() as i32);
self
}
pub fn with_end_alpha_percent(mut self, percent: f64) -> Self {
self.end_alpha_1000ths_percent = Some((percent * 1000.0).round() as i32);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SoftEdge {
pub radius_emu: i64,
}
impl SoftEdge {
pub fn new(radius_emu: i64) -> Self {
Self { radius_emu }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Transform2D {
pub offset: Option<(i64, i64)>,
pub extent: Option<(i64, i64)>,
pub rotation_60000ths: i32,
pub flip_horizontal: bool,
pub flip_vertical: bool,
}
impl Transform2D {
pub fn new() -> Self {
Self::default()
}
pub fn with_offset(mut self, x_emu: i64, y_emu: i64) -> Self {
self.offset = Some((x_emu, y_emu));
self
}
pub fn with_extent(mut self, width_emu: i64, height_emu: i64) -> Self {
self.extent = Some((width_emu, height_emu));
self
}
pub fn with_rotation_degrees(mut self, degrees: f64) -> Self {
self.rotation_60000ths = (degrees * 60_000.0).round() as i32;
self
}
pub fn with_flip_horizontal(mut self, flip: bool) -> Self {
self.flip_horizontal = flip;
self
}
pub fn with_flip_vertical(mut self, flip: bool) -> Self {
self.flip_vertical = flip;
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Geometry {
Preset(PresetShape),
Custom(CustomGeometry),
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct CustomGeometry {
pub width_emu: i64,
pub height_emu: i64,
pub commands: Vec<PathCommand>,
}
impl CustomGeometry {
pub fn new(width_emu: i64, height_emu: i64) -> Self {
Self {
width_emu,
height_emu,
commands: Vec::new(),
}
}
pub fn with_command(mut self, command: PathCommand) -> Self {
self.commands.push(command);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PathCommand {
MoveTo { x: i64, y: i64 },
LineTo { x: i64, y: i64 },
CubicBezierTo {
x1: i64,
y1: i64,
x2: i64,
y2: i64,
x: i64,
y: i64,
},
Close,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PresetShape {
Rectangle,
RoundedRectangle,
Ellipse,
Triangle,
RightTriangle,
Diamond,
Parallelogram,
Trapezoid,
Pentagon,
Hexagon,
Heptagon,
Octagon,
Decagon,
Dodecagon,
Star4,
Star5,
Star6,
Star8,
Star10,
Star12,
Line,
Plaque,
Teardrop,
HomePlate,
Chevron,
Pie,
Donut,
BlockArc,
NoSmoking,
RightArrow,
LeftArrow,
UpArrow,
DownArrow,
LeftRightArrow,
UpDownArrow,
BentArrow,
UturnArrow,
Heart,
Sun,
Moon,
SmileyFace,
Cube,
Can,
LightningBolt,
FoldedCorner,
Bevel,
Frame,
Arc,
Chord,
LeftBrace,
RightBrace,
BracePair,
Other(String),
}
impl PresetShape {
pub(crate) fn xml_token(&self) -> &str {
match self {
PresetShape::Rectangle => "rect",
PresetShape::RoundedRectangle => "roundRect",
PresetShape::Ellipse => "ellipse",
PresetShape::Triangle => "triangle",
PresetShape::RightTriangle => "rtTriangle",
PresetShape::Diamond => "diamond",
PresetShape::Parallelogram => "parallelogram",
PresetShape::Trapezoid => "trapezoid",
PresetShape::Pentagon => "pentagon",
PresetShape::Hexagon => "hexagon",
PresetShape::Heptagon => "heptagon",
PresetShape::Octagon => "octagon",
PresetShape::Decagon => "decagon",
PresetShape::Dodecagon => "dodecagon",
PresetShape::Star4 => "star4",
PresetShape::Star5 => "star5",
PresetShape::Star6 => "star6",
PresetShape::Star8 => "star8",
PresetShape::Star10 => "star10",
PresetShape::Star12 => "star12",
PresetShape::Line => "line",
PresetShape::Plaque => "plaque",
PresetShape::Teardrop => "teardrop",
PresetShape::HomePlate => "homePlate",
PresetShape::Chevron => "chevron",
PresetShape::Pie => "pie",
PresetShape::Donut => "donut",
PresetShape::BlockArc => "blockArc",
PresetShape::NoSmoking => "noSmoking",
PresetShape::RightArrow => "rightArrow",
PresetShape::LeftArrow => "leftArrow",
PresetShape::UpArrow => "upArrow",
PresetShape::DownArrow => "downArrow",
PresetShape::LeftRightArrow => "leftRightArrow",
PresetShape::UpDownArrow => "upDownArrow",
PresetShape::BentArrow => "bentArrow",
PresetShape::UturnArrow => "uturnArrow",
PresetShape::Heart => "heart",
PresetShape::Sun => "sun",
PresetShape::Moon => "moon",
PresetShape::SmileyFace => "smileyFace",
PresetShape::Cube => "cube",
PresetShape::Can => "can",
PresetShape::LightningBolt => "lightningBolt",
PresetShape::FoldedCorner => "foldedCorner",
PresetShape::Bevel => "bevel",
PresetShape::Frame => "frame",
PresetShape::Arc => "arc",
PresetShape::Chord => "chord",
PresetShape::LeftBrace => "leftBrace",
PresetShape::RightBrace => "rightBrace",
PresetShape::BracePair => "bracePair",
PresetShape::Other(token) => token,
}
}
pub(crate) fn from_xml_token(token: &str) -> Self {
match token {
"rect" => PresetShape::Rectangle,
"roundRect" => PresetShape::RoundedRectangle,
"ellipse" => PresetShape::Ellipse,
"triangle" => PresetShape::Triangle,
"rtTriangle" => PresetShape::RightTriangle,
"diamond" => PresetShape::Diamond,
"parallelogram" => PresetShape::Parallelogram,
"trapezoid" => PresetShape::Trapezoid,
"pentagon" => PresetShape::Pentagon,
"hexagon" => PresetShape::Hexagon,
"heptagon" => PresetShape::Heptagon,
"octagon" => PresetShape::Octagon,
"decagon" => PresetShape::Decagon,
"dodecagon" => PresetShape::Dodecagon,
"star4" => PresetShape::Star4,
"star5" => PresetShape::Star5,
"star6" => PresetShape::Star6,
"star8" => PresetShape::Star8,
"star10" => PresetShape::Star10,
"star12" => PresetShape::Star12,
"line" => PresetShape::Line,
"plaque" => PresetShape::Plaque,
"teardrop" => PresetShape::Teardrop,
"homePlate" => PresetShape::HomePlate,
"chevron" => PresetShape::Chevron,
"pie" => PresetShape::Pie,
"donut" => PresetShape::Donut,
"blockArc" => PresetShape::BlockArc,
"noSmoking" => PresetShape::NoSmoking,
"rightArrow" => PresetShape::RightArrow,
"leftArrow" => PresetShape::LeftArrow,
"upArrow" => PresetShape::UpArrow,
"downArrow" => PresetShape::DownArrow,
"leftRightArrow" => PresetShape::LeftRightArrow,
"upDownArrow" => PresetShape::UpDownArrow,
"bentArrow" => PresetShape::BentArrow,
"uturnArrow" => PresetShape::UturnArrow,
"heart" => PresetShape::Heart,
"sun" => PresetShape::Sun,
"moon" => PresetShape::Moon,
"smileyFace" => PresetShape::SmileyFace,
"cube" => PresetShape::Cube,
"can" => PresetShape::Can,
"lightningBolt" => PresetShape::LightningBolt,
"foldedCorner" => PresetShape::FoldedCorner,
"bevel" => PresetShape::Bevel,
"frame" => PresetShape::Frame,
"arc" => PresetShape::Arc,
"chord" => PresetShape::Chord,
"leftBrace" => PresetShape::LeftBrace,
"rightBrace" => PresetShape::RightBrace,
"bracePair" => PresetShape::BracePair,
other => PresetShape::Other(other.to_string()),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Color {
Rgb(String),
RgbPercent { red: i64, green: i64, blue: i64 },
Hsl {
hue_60000ths: i32,
saturation_1000ths_percent: i64,
luminance_1000ths_percent: i64,
},
System {
value: String,
last_color: Option<String>,
},
Preset(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Fill {
None,
Solid(Color),
Gradient(GradientFill),
Pattern(PatternFill),
Image(BlipFill),
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct GradientFill {
pub stops: Vec<GradientStop>,
pub angle_60000ths: Option<i32>,
}
impl GradientFill {
pub fn new() -> Self {
Self::default()
}
pub fn with_stop(mut self, stop: GradientStop) -> Self {
self.stops.push(stop);
self
}
pub fn with_angle_degrees(mut self, degrees: f64) -> Self {
self.angle_60000ths = Some((degrees * 60_000.0).round() as i32);
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct GradientStop {
pub position_1000ths_percent: i64,
pub color: Color,
}
impl GradientStop {
pub fn new(position_percent: f64, color: Color) -> Self {
Self {
position_1000ths_percent: (position_percent * 1000.0).round() as i64,
color,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct PatternFill {
pub preset: PresetPattern,
pub foreground: Option<Color>,
pub background: Option<Color>,
}
impl PatternFill {
pub fn new(preset: PresetPattern) -> Self {
Self {
preset,
foreground: None,
background: None,
}
}
pub fn with_foreground(mut self, color: Color) -> Self {
self.foreground = Some(color);
self
}
pub fn with_background(mut self, color: Color) -> Self {
self.background = Some(color);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PresetPattern {
Percent5,
Percent10,
Percent20,
Percent25,
Percent30,
Percent40,
Percent50,
Percent60,
Percent70,
Percent75,
Percent80,
Percent90,
Horizontal,
Vertical,
LightHorizontal,
LightVertical,
DarkHorizontal,
DarkVertical,
NarrowHorizontal,
NarrowVertical,
DashedHorizontal,
DashedVertical,
Cross,
DiagonalDown,
DiagonalUp,
LightDiagonalDown,
LightDiagonalUp,
DarkDiagonalDown,
DarkDiagonalUp,
WideDiagonalDown,
WideDiagonalUp,
DashedDiagonalDown,
DashedDiagonalUp,
DiagonalCross,
SmallCheckerBoard,
LargeCheckerBoard,
SmallGrid,
LargeGrid,
DottedGrid,
SmallConfetti,
LargeConfetti,
HorizontalBrick,
DiagonalBrick,
SolidDiamond,
OpenDiamond,
DottedDiamond,
Plaid,
Sphere,
Weave,
Divot,
Shingle,
Wave,
Trellis,
ZigZag,
}
impl PresetPattern {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
PresetPattern::Percent5 => "pct5",
PresetPattern::Percent10 => "pct10",
PresetPattern::Percent20 => "pct20",
PresetPattern::Percent25 => "pct25",
PresetPattern::Percent30 => "pct30",
PresetPattern::Percent40 => "pct40",
PresetPattern::Percent50 => "pct50",
PresetPattern::Percent60 => "pct60",
PresetPattern::Percent70 => "pct70",
PresetPattern::Percent75 => "pct75",
PresetPattern::Percent80 => "pct80",
PresetPattern::Percent90 => "pct90",
PresetPattern::Horizontal => "horz",
PresetPattern::Vertical => "vert",
PresetPattern::LightHorizontal => "ltHorz",
PresetPattern::LightVertical => "ltVert",
PresetPattern::DarkHorizontal => "dkHorz",
PresetPattern::DarkVertical => "dkVert",
PresetPattern::NarrowHorizontal => "narHorz",
PresetPattern::NarrowVertical => "narVert",
PresetPattern::DashedHorizontal => "dashHorz",
PresetPattern::DashedVertical => "dashVert",
PresetPattern::Cross => "cross",
PresetPattern::DiagonalDown => "dnDiag",
PresetPattern::DiagonalUp => "upDiag",
PresetPattern::LightDiagonalDown => "ltDnDiag",
PresetPattern::LightDiagonalUp => "ltUpDiag",
PresetPattern::DarkDiagonalDown => "dkDnDiag",
PresetPattern::DarkDiagonalUp => "dkUpDiag",
PresetPattern::WideDiagonalDown => "wdDnDiag",
PresetPattern::WideDiagonalUp => "wdUpDiag",
PresetPattern::DashedDiagonalDown => "dashDnDiag",
PresetPattern::DashedDiagonalUp => "dashUpDiag",
PresetPattern::DiagonalCross => "diagCross",
PresetPattern::SmallCheckerBoard => "smCheck",
PresetPattern::LargeCheckerBoard => "lgCheck",
PresetPattern::SmallGrid => "smGrid",
PresetPattern::LargeGrid => "lgGrid",
PresetPattern::DottedGrid => "dotGrid",
PresetPattern::SmallConfetti => "smConfetti",
PresetPattern::LargeConfetti => "lgConfetti",
PresetPattern::HorizontalBrick => "horzBrick",
PresetPattern::DiagonalBrick => "diagBrick",
PresetPattern::SolidDiamond => "solidDmnd",
PresetPattern::OpenDiamond => "openDmnd",
PresetPattern::DottedDiamond => "dotDmnd",
PresetPattern::Plaid => "plaid",
PresetPattern::Sphere => "sphere",
PresetPattern::Weave => "weave",
PresetPattern::Divot => "divot",
PresetPattern::Shingle => "shingle",
PresetPattern::Wave => "wave",
PresetPattern::Trellis => "trellis",
PresetPattern::ZigZag => "zigZag",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"pct5" => PresetPattern::Percent5,
"pct10" => PresetPattern::Percent10,
"pct20" => PresetPattern::Percent20,
"pct25" => PresetPattern::Percent25,
"pct30" => PresetPattern::Percent30,
"pct40" => PresetPattern::Percent40,
"pct50" => PresetPattern::Percent50,
"pct60" => PresetPattern::Percent60,
"pct70" => PresetPattern::Percent70,
"pct75" => PresetPattern::Percent75,
"pct80" => PresetPattern::Percent80,
"pct90" => PresetPattern::Percent90,
"horz" => PresetPattern::Horizontal,
"vert" => PresetPattern::Vertical,
"ltHorz" => PresetPattern::LightHorizontal,
"ltVert" => PresetPattern::LightVertical,
"dkHorz" => PresetPattern::DarkHorizontal,
"dkVert" => PresetPattern::DarkVertical,
"narHorz" => PresetPattern::NarrowHorizontal,
"narVert" => PresetPattern::NarrowVertical,
"dashHorz" => PresetPattern::DashedHorizontal,
"dashVert" => PresetPattern::DashedVertical,
"cross" => PresetPattern::Cross,
"dnDiag" => PresetPattern::DiagonalDown,
"upDiag" => PresetPattern::DiagonalUp,
"ltDnDiag" => PresetPattern::LightDiagonalDown,
"ltUpDiag" => PresetPattern::LightDiagonalUp,
"dkDnDiag" => PresetPattern::DarkDiagonalDown,
"dkUpDiag" => PresetPattern::DarkDiagonalUp,
"wdDnDiag" => PresetPattern::WideDiagonalDown,
"wdUpDiag" => PresetPattern::WideDiagonalUp,
"dashDnDiag" => PresetPattern::DashedDiagonalDown,
"dashUpDiag" => PresetPattern::DashedDiagonalUp,
"diagCross" => PresetPattern::DiagonalCross,
"smCheck" => PresetPattern::SmallCheckerBoard,
"lgCheck" => PresetPattern::LargeCheckerBoard,
"smGrid" => PresetPattern::SmallGrid,
"lgGrid" => PresetPattern::LargeGrid,
"dotGrid" => PresetPattern::DottedGrid,
"smConfetti" => PresetPattern::SmallConfetti,
"lgConfetti" => PresetPattern::LargeConfetti,
"horzBrick" => PresetPattern::HorizontalBrick,
"diagBrick" => PresetPattern::DiagonalBrick,
"solidDmnd" => PresetPattern::SolidDiamond,
"openDmnd" => PresetPattern::OpenDiamond,
"dotDmnd" => PresetPattern::DottedDiamond,
"plaid" => PresetPattern::Plaid,
"sphere" => PresetPattern::Sphere,
"weave" => PresetPattern::Weave,
"divot" => PresetPattern::Divot,
"shingle" => PresetPattern::Shingle,
"wave" => PresetPattern::Wave,
"trellis" => PresetPattern::Trellis,
"zigZag" => PresetPattern::ZigZag,
_ => return None,
})
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Line {
pub width_emu: Option<i64>,
pub fill: Option<Fill>,
pub dash: Option<PresetLineDash>,
pub cap: Option<LineCap>,
pub join: Option<LineJoin>,
pub head_end: Option<LineEnd>,
pub tail_end: Option<LineEnd>,
pub compound: Option<LineCompound>,
}
impl Line {
pub fn new() -> Self {
Self::default()
}
pub fn with_compound(mut self, compound: LineCompound) -> Self {
self.compound = Some(compound);
self
}
pub fn with_width_emu(mut self, width_emu: i64) -> Self {
self.width_emu = Some(width_emu);
self
}
pub fn with_fill(mut self, fill: Fill) -> Self {
self.fill = Some(fill);
self
}
pub fn with_dash(mut self, dash: PresetLineDash) -> Self {
self.dash = Some(dash);
self
}
pub fn with_cap(mut self, cap: LineCap) -> Self {
self.cap = Some(cap);
self
}
pub fn with_join(mut self, join: LineJoin) -> Self {
self.join = Some(join);
self
}
pub fn with_head_end(mut self, end: LineEnd) -> Self {
self.head_end = Some(end);
self
}
pub fn with_tail_end(mut self, end: LineEnd) -> Self {
self.tail_end = Some(end);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PresetLineDash {
Solid,
Dot,
Dash,
LargeDash,
DashDot,
LargeDashDot,
LargeDashDotDot,
SystemDash,
SystemDot,
SystemDashDot,
SystemDashDotDot,
}
impl PresetLineDash {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
PresetLineDash::Solid => "solid",
PresetLineDash::Dot => "dot",
PresetLineDash::Dash => "dash",
PresetLineDash::LargeDash => "lgDash",
PresetLineDash::DashDot => "dashDot",
PresetLineDash::LargeDashDot => "lgDashDot",
PresetLineDash::LargeDashDotDot => "lgDashDotDot",
PresetLineDash::SystemDash => "sysDash",
PresetLineDash::SystemDot => "sysDot",
PresetLineDash::SystemDashDot => "sysDashDot",
PresetLineDash::SystemDashDotDot => "sysDashDotDot",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"solid" => PresetLineDash::Solid,
"dot" => PresetLineDash::Dot,
"dash" => PresetLineDash::Dash,
"lgDash" => PresetLineDash::LargeDash,
"dashDot" => PresetLineDash::DashDot,
"lgDashDot" => PresetLineDash::LargeDashDot,
"lgDashDotDot" => PresetLineDash::LargeDashDotDot,
"sysDash" => PresetLineDash::SystemDash,
"sysDot" => PresetLineDash::SystemDot,
"sysDashDot" => PresetLineDash::SystemDashDot,
"sysDashDotDot" => PresetLineDash::SystemDashDotDot,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LineCap {
Round,
Square,
Flat,
}
impl LineCap {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
LineCap::Round => "rnd",
LineCap::Square => "sq",
LineCap::Flat => "flat",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"rnd" => LineCap::Round,
"sq" => LineCap::Square,
"flat" => LineCap::Flat,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LineCompound {
Simple,
Double,
ThickThin,
ThinThick,
Triple,
}
impl LineCompound {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
LineCompound::Simple => "sng",
LineCompound::Double => "dbl",
LineCompound::ThickThin => "thickThin",
LineCompound::ThinThick => "thinThick",
LineCompound::Triple => "tri",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"sng" => LineCompound::Simple,
"dbl" => LineCompound::Double,
"thickThin" => LineCompound::ThickThin,
"thinThick" => LineCompound::ThinThick,
"tri" => LineCompound::Triple,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineJoin {
Round,
Bevel,
Miter {
limit_1000ths_percent: Option<i64>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct LineEnd {
pub kind: Option<LineEndType>,
pub width: Option<LineEndSize>,
pub length: Option<LineEndSize>,
}
impl LineEnd {
pub fn new() -> Self {
Self::default()
}
pub fn with_kind(mut self, kind: LineEndType) -> Self {
self.kind = Some(kind);
self
}
pub fn with_width(mut self, width: LineEndSize) -> Self {
self.width = Some(width);
self
}
pub fn with_length(mut self, length: LineEndSize) -> Self {
self.length = Some(length);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LineEndType {
None,
Triangle,
Stealth,
Diamond,
Oval,
Arrow,
}
impl LineEndType {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
LineEndType::None => "none",
LineEndType::Triangle => "triangle",
LineEndType::Stealth => "stealth",
LineEndType::Diamond => "diamond",
LineEndType::Oval => "oval",
LineEndType::Arrow => "arrow",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"none" => LineEndType::None,
"triangle" => LineEndType::Triangle,
"stealth" => LineEndType::Stealth,
"diamond" => LineEndType::Diamond,
"oval" => LineEndType::Oval,
"arrow" => LineEndType::Arrow,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LineEndSize {
Small,
Medium,
Large,
}
impl LineEndSize {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
LineEndSize::Small => "sm",
LineEndSize::Medium => "med",
LineEndSize::Large => "lg",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"sm" => LineEndSize::Small,
"med" => LineEndSize::Medium,
"lg" => LineEndSize::Large,
_ => return None,
})
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct BlipFill {
pub relationship_id: Option<String>,
pub mode: Option<BlipFillMode>,
pub crop: Option<CropRect>,
}
impl BlipFill {
pub fn new(relationship_id: impl Into<String>) -> Self {
Self {
relationship_id: Some(relationship_id.into()),
mode: None,
crop: None,
}
}
pub fn with_mode(mut self, mode: BlipFillMode) -> Self {
self.mode = Some(mode);
self
}
pub fn with_crop(mut self, crop: CropRect) -> Self {
self.crop = Some(crop);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct CropRect {
pub left_1000ths_percent: Option<i32>,
pub top_1000ths_percent: Option<i32>,
pub right_1000ths_percent: Option<i32>,
pub bottom_1000ths_percent: Option<i32>,
}
impl CropRect {
pub fn new() -> Self {
Self::default()
}
pub fn with_percent(mut self, left: f64, top: f64, right: f64, bottom: f64) -> Self {
self.left_1000ths_percent = Some((left * 1000.0).round() as i32);
self.top_1000ths_percent = Some((top * 1000.0).round() as i32);
self.right_1000ths_percent = Some((right * 1000.0).round() as i32);
self.bottom_1000ths_percent = Some((bottom * 1000.0).round() as i32);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BlipFillMode {
Stretch,
Tile,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TextBody {
pub properties: TextBodyProperties,
pub paragraphs: Vec<TextParagraph>,
}
impl TextBody {
pub fn new() -> Self {
Self::default()
}
pub fn with_properties(mut self, properties: TextBodyProperties) -> Self {
self.properties = properties;
self
}
pub fn with_paragraph(mut self, paragraph: TextParagraph) -> Self {
self.paragraphs.push(paragraph);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct TextBodyProperties {
pub wrap: Option<TextWrap>,
pub anchor: Option<TextAnchor>,
pub anchor_center: bool,
pub inset_left_emu: Option<i64>,
pub inset_top_emu: Option<i64>,
pub inset_right_emu: Option<i64>,
pub inset_bottom_emu: Option<i64>,
pub autofit: Option<TextAutofit>,
pub vertical_direction: Option<TextVerticalType>,
pub rotation_60000ths: i32,
}
impl TextBodyProperties {
pub fn new() -> Self {
Self::default()
}
pub fn with_wrap(mut self, wrap: TextWrap) -> Self {
self.wrap = Some(wrap);
self
}
pub fn with_anchor(mut self, anchor: TextAnchor) -> Self {
self.anchor = Some(anchor);
self
}
pub fn with_anchor_center(mut self, anchor_center: bool) -> Self {
self.anchor_center = anchor_center;
self
}
pub fn with_insets_emu(mut self, left: i64, top: i64, right: i64, bottom: i64) -> Self {
self.inset_left_emu = Some(left);
self.inset_top_emu = Some(top);
self.inset_right_emu = Some(right);
self.inset_bottom_emu = Some(bottom);
self
}
pub fn with_autofit(mut self, autofit: TextAutofit) -> Self {
self.autofit = Some(autofit);
self
}
pub fn with_vertical_direction(mut self, direction: TextVerticalType) -> Self {
self.vertical_direction = Some(direction);
self
}
pub fn with_rotation_degrees(mut self, degrees: f64) -> Self {
self.rotation_60000ths = (degrees * 60_000.0).round() as i32;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextVerticalType {
Horizontal,
Vertical,
Vertical270,
WordArtVertical,
EastAsianVertical,
MongolianVertical,
WordArtVerticalRightToLeft,
}
impl TextVerticalType {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
TextVerticalType::Horizontal => "horz",
TextVerticalType::Vertical => "vert",
TextVerticalType::Vertical270 => "vert270",
TextVerticalType::WordArtVertical => "wordArtVert",
TextVerticalType::EastAsianVertical => "eaVert",
TextVerticalType::MongolianVertical => "mongolianVert",
TextVerticalType::WordArtVerticalRightToLeft => "wordArtVertRtl",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"horz" => TextVerticalType::Horizontal,
"vert" => TextVerticalType::Vertical,
"vert270" => TextVerticalType::Vertical270,
"wordArtVert" => TextVerticalType::WordArtVertical,
"eaVert" => TextVerticalType::EastAsianVertical,
"mongolianVert" => TextVerticalType::MongolianVertical,
"wordArtVertRtl" => TextVerticalType::WordArtVerticalRightToLeft,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextAutofit {
None,
Shape,
Normal {
font_scale_1000ths_percent: Option<i32>,
line_spacing_reduction_1000ths_percent: Option<i32>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextWrap {
None,
Square,
}
impl TextWrap {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
TextWrap::None => "none",
TextWrap::Square => "square",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"none" => TextWrap::None,
"square" => TextWrap::Square,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextAnchor {
Top,
Center,
Bottom,
Justified,
Distributed,
}
impl TextAnchor {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
TextAnchor::Top => "t",
TextAnchor::Center => "ctr",
TextAnchor::Bottom => "b",
TextAnchor::Justified => "just",
TextAnchor::Distributed => "dist",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"t" => TextAnchor::Top,
"ctr" => TextAnchor::Center,
"b" => TextAnchor::Bottom,
"just" => TextAnchor::Justified,
"dist" => TextAnchor::Distributed,
_ => return None,
})
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TextParagraph {
pub properties: Option<TextParagraphProperties>,
pub runs: Vec<TextRun>,
}
impl TextParagraph {
pub fn new() -> Self {
Self::default()
}
pub fn with_properties(mut self, properties: TextParagraphProperties) -> Self {
self.properties = Some(properties);
self
}
pub fn with_run(mut self, run: TextRun) -> Self {
self.runs.push(run);
self
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TextParagraphProperties {
pub alignment: Option<TextAlign>,
pub margin_left_emu: Option<i64>,
pub margin_right_emu: Option<i64>,
pub indent_emu: Option<i64>,
pub level: Option<u8>,
pub tab_stops: Vec<TabStop>,
pub line_spacing: Option<TextSpacing>,
pub space_before: Option<TextSpacing>,
pub space_after: Option<TextSpacing>,
pub bullet_color: Option<BulletColor>,
pub bullet_size: Option<BulletSize>,
pub bullet_font: Option<BulletFont>,
pub bullet: Option<BulletKind>,
pub default_run_properties: Option<Box<TextRunProperties>>,
}
impl TextParagraphProperties {
pub fn new() -> Self {
Self::default()
}
pub fn with_alignment(mut self, alignment: TextAlign) -> Self {
self.alignment = Some(alignment);
self
}
pub fn with_margins_emu(mut self, left: i64, right: i64) -> Self {
self.margin_left_emu = Some(left);
self.margin_right_emu = Some(right);
self
}
pub fn with_indent_emu(mut self, indent: i64) -> Self {
self.indent_emu = Some(indent);
self
}
pub fn with_level(mut self, level: u8) -> Self {
self.level = Some(level);
self
}
pub fn with_tab_stop(mut self, tab_stop: TabStop) -> Self {
self.tab_stops.push(tab_stop);
self
}
pub fn with_line_spacing(mut self, spacing: TextSpacing) -> Self {
self.line_spacing = Some(spacing);
self
}
pub fn with_space_before(mut self, spacing: TextSpacing) -> Self {
self.space_before = Some(spacing);
self
}
pub fn with_space_after(mut self, spacing: TextSpacing) -> Self {
self.space_after = Some(spacing);
self
}
pub fn with_bullet_color(mut self, color: BulletColor) -> Self {
self.bullet_color = Some(color);
self
}
pub fn with_bullet_size(mut self, size: BulletSize) -> Self {
self.bullet_size = Some(size);
self
}
pub fn with_bullet_font(mut self, font: BulletFont) -> Self {
self.bullet_font = Some(font);
self
}
pub fn with_bullet(mut self, bullet: BulletKind) -> Self {
self.bullet = Some(bullet);
self
}
pub fn with_default_run_properties(mut self, properties: TextRunProperties) -> Self {
self.default_run_properties = Some(Box::new(properties));
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextSpacing {
Percent(i32),
Points(i32),
}
#[derive(Debug, Clone, PartialEq)]
pub enum BulletColor {
FollowText,
Explicit(Color),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BulletSize {
FollowText,
Percent(i32),
Points(i32),
}
#[derive(Debug, Clone, PartialEq)]
pub enum BulletFont {
FollowText,
Typeface(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum BulletKind {
None,
Character(String),
AutoNumber {
scheme: String,
start_at: Option<i32>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TabStop {
pub position_emu: i64,
pub alignment: Option<TabAlignment>,
}
impl TabStop {
pub fn new(position_emu: i64) -> Self {
Self {
position_emu,
alignment: None,
}
}
pub fn with_alignment(mut self, alignment: TabAlignment) -> Self {
self.alignment = Some(alignment);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TabAlignment {
Left,
Center,
Right,
Decimal,
}
impl TabAlignment {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
TabAlignment::Left => "l",
TabAlignment::Center => "ctr",
TabAlignment::Right => "r",
TabAlignment::Decimal => "dec",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"l" => TabAlignment::Left,
"ctr" => TabAlignment::Center,
"r" => TabAlignment::Right,
"dec" => TabAlignment::Decimal,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextAlign {
Left,
Center,
Right,
Justified,
JustifiedLow,
Distributed,
ThaiDistributed,
}
impl TextAlign {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
TextAlign::Left => "l",
TextAlign::Center => "ctr",
TextAlign::Right => "r",
TextAlign::Justified => "just",
TextAlign::JustifiedLow => "justLow",
TextAlign::Distributed => "dist",
TextAlign::ThaiDistributed => "thaiDist",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"l" => TextAlign::Left,
"ctr" => TextAlign::Center,
"r" => TextAlign::Right,
"just" => TextAlign::Justified,
"justLow" => TextAlign::JustifiedLow,
"dist" => TextAlign::Distributed,
"thaiDist" => TextAlign::ThaiDistributed,
_ => return None,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TextRun {
Regular {
text: String,
properties: TextRunProperties,
},
LineBreak {
properties: Option<TextRunProperties>,
},
Field {
id: String,
field_type: Option<String>,
cached_text: String,
properties: TextRunProperties,
},
}
impl TextRun {
pub fn text(text: impl Into<String>) -> Self {
TextRun::Regular {
text: text.into(),
properties: TextRunProperties::new(),
}
}
pub fn text_with_properties(text: impl Into<String>, properties: TextRunProperties) -> Self {
TextRun::Regular {
text: text.into(),
properties,
}
}
pub fn line_break() -> Self {
TextRun::LineBreak { properties: None }
}
pub fn field(
id: impl Into<String>,
field_type: Option<String>,
cached_text: impl Into<String>,
) -> Self {
TextRun::Field {
id: id.into(),
field_type,
cached_text: cached_text.into(),
properties: TextRunProperties::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TextRunProperties {
pub bold: bool,
pub italic: bool,
pub underline: Option<TextUnderline>,
pub strike: Option<TextStrike>,
pub fill: Option<Fill>,
pub font_size_100ths_point: Option<i32>,
pub font_family: Option<String>,
pub hyperlink: Option<Hyperlink>,
pub baseline_1000ths_percent: Option<i32>,
pub highlight: Option<Color>,
pub text_caps: Option<TextCaps>,
pub character_spacing_100ths_point: Option<i32>,
}
impl TextRunProperties {
pub fn new() -> Self {
Self::default()
}
pub fn with_bold(mut self, bold: bool) -> Self {
self.bold = bold;
self
}
pub fn with_italic(mut self, italic: bool) -> Self {
self.italic = italic;
self
}
pub fn with_underline(mut self, underline: TextUnderline) -> Self {
self.underline = Some(underline);
self
}
pub fn with_strike(mut self, strike: TextStrike) -> Self {
self.strike = Some(strike);
self
}
pub fn with_fill(mut self, fill: Fill) -> Self {
self.fill = Some(fill);
self
}
pub fn with_font_size_points(mut self, points: f64) -> Self {
self.font_size_100ths_point = Some((points * 100.0).round() as i32);
self
}
pub fn with_font_family(mut self, font_family: impl Into<String>) -> Self {
self.font_family = Some(font_family.into());
self
}
pub fn with_hyperlink(mut self, hyperlink: Hyperlink) -> Self {
self.hyperlink = Some(hyperlink);
self
}
pub fn with_baseline_percent(mut self, percent: f64) -> Self {
self.baseline_1000ths_percent = Some((percent * 1000.0).round() as i32);
self
}
pub fn with_highlight(mut self, color: Color) -> Self {
self.highlight = Some(color);
self
}
pub fn with_text_caps(mut self, caps: TextCaps) -> Self {
self.text_caps = Some(caps);
self
}
pub fn with_character_spacing_points(mut self, points: f64) -> Self {
self.character_spacing_100ths_point = Some((points * 100.0).round() as i32);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextCaps {
None,
Small,
All,
}
impl TextCaps {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
TextCaps::None => "none",
TextCaps::Small => "small",
TextCaps::All => "all",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"none" => TextCaps::None,
"small" => TextCaps::Small,
"all" => TextCaps::All,
_ => return None,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Hyperlink {
pub relationship_id: Option<String>,
pub tooltip: Option<String>,
}
impl Hyperlink {
pub fn new(relationship_id: impl Into<String>) -> Self {
Self {
relationship_id: Some(relationship_id.into()),
tooltip: None,
}
}
pub fn with_tooltip(mut self, tooltip: impl Into<String>) -> Self {
self.tooltip = Some(tooltip.into());
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextUnderline {
None,
Words,
Single,
Double,
Heavy,
Dotted,
DottedHeavy,
Dash,
DashHeavy,
DashLong,
DashLongHeavy,
DotDash,
DotDashHeavy,
DotDotDash,
DotDotDashHeavy,
Wavy,
WavyHeavy,
WavyDouble,
}
impl TextUnderline {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
TextUnderline::None => "none",
TextUnderline::Words => "words",
TextUnderline::Single => "sng",
TextUnderline::Double => "dbl",
TextUnderline::Heavy => "heavy",
TextUnderline::Dotted => "dotted",
TextUnderline::DottedHeavy => "dottedHeavy",
TextUnderline::Dash => "dash",
TextUnderline::DashHeavy => "dashHeavy",
TextUnderline::DashLong => "dashLong",
TextUnderline::DashLongHeavy => "dashLongHeavy",
TextUnderline::DotDash => "dotDash",
TextUnderline::DotDashHeavy => "dotDashHeavy",
TextUnderline::DotDotDash => "dotDotDash",
TextUnderline::DotDotDashHeavy => "dotDotDashHeavy",
TextUnderline::Wavy => "wavy",
TextUnderline::WavyHeavy => "wavyHeavy",
TextUnderline::WavyDouble => "wavyDbl",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"none" => TextUnderline::None,
"words" => TextUnderline::Words,
"sng" => TextUnderline::Single,
"dbl" => TextUnderline::Double,
"heavy" => TextUnderline::Heavy,
"dotted" => TextUnderline::Dotted,
"dottedHeavy" => TextUnderline::DottedHeavy,
"dash" => TextUnderline::Dash,
"dashHeavy" => TextUnderline::DashHeavy,
"dashLong" => TextUnderline::DashLong,
"dashLongHeavy" => TextUnderline::DashLongHeavy,
"dotDash" => TextUnderline::DotDash,
"dotDashHeavy" => TextUnderline::DotDashHeavy,
"dotDotDash" => TextUnderline::DotDotDash,
"dotDotDashHeavy" => TextUnderline::DotDotDashHeavy,
"wavy" => TextUnderline::Wavy,
"wavyHeavy" => TextUnderline::WavyHeavy,
"wavyDbl" => TextUnderline::WavyDouble,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextStrike {
None,
Single,
Double,
}
impl TextStrike {
pub(crate) fn xml_token(&self) -> &'static str {
match self {
TextStrike::None => "noStrike",
TextStrike::Single => "sngStrike",
TextStrike::Double => "dblStrike",
}
}
pub(crate) fn from_xml_token(token: &str) -> Option<Self> {
Some(match token {
"noStrike" => TextStrike::None,
"sngStrike" => TextStrike::Single,
"dblStrike" => TextStrike::Double,
_ => return None,
})
}
}