use crate::oxml::ns::{NS_DRAWING_MAIN, NS_PRESENTATION_MAIN};
use crate::oxml::shape::{Connector, GraphicFrame, Group, Pic, Sp};
use crate::oxml::txbody::TextBody;
use crate::oxml::writer::XmlWriter;
#[derive(Clone, Debug, Default)]
pub struct Sld {
pub id: u32,
pub layout_rid: String,
pub name: String,
pub background: Option<SlideBackground>,
pub shapes: Vec<SlideShape>,
pub notes: Option<TextBody>,
pub transition: Option<Transition>,
pub ext_lst: Option<crate::oxml::shape::ExtensionList>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub enum TransitionSpeed {
Slow,
#[default]
Medium,
Fast,
}
impl TransitionSpeed {
pub fn as_str(&self) -> &'static str {
match self {
TransitionSpeed::Slow => "slow",
TransitionSpeed::Medium => "med",
TransitionSpeed::Fast => "fast",
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub enum TransitionType {
Fade { thru_blk: bool },
Push { dir: TransitionDirection },
Wipe { dir: TransitionDirection },
Split {
orient: SplitOrientation,
dir: TransitionDirection,
},
Cover { dir: TransitionDirection },
Pull { dir: TransitionDirection },
Cut { thru_blk: bool },
Zoom { dir: TransitionDirection },
Morph { option: MorphOption },
#[default]
None,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub enum TransitionDirection {
Left,
#[default]
Right,
Up,
Down,
LeftUp,
LeftDown,
RightUp,
RightDown,
}
impl TransitionDirection {
pub fn as_str(&self) -> &'static str {
match self {
TransitionDirection::Left => "l",
TransitionDirection::Right => "r",
TransitionDirection::Up => "u",
TransitionDirection::Down => "d",
TransitionDirection::LeftUp => "lu",
TransitionDirection::LeftDown => "ld",
TransitionDirection::RightUp => "ru",
TransitionDirection::RightDown => "rd",
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub enum SplitOrientation {
#[default]
Horizontal,
Vertical,
}
impl SplitOrientation {
pub fn as_str(&self) -> &'static str {
match self {
SplitOrientation::Horizontal => "horz",
SplitOrientation::Vertical => "vert",
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub enum MorphOption {
#[default]
ByObject,
ByWord,
ByChar,
}
impl MorphOption {
pub fn as_str(&self) -> &'static str {
match self {
MorphOption::ByObject => "byObject",
MorphOption::ByWord => "byWord",
MorphOption::ByChar => "byChar",
}
}
}
#[derive(Clone, Debug, Default)]
pub struct Transition {
pub speed: TransitionSpeed,
pub advance_click: bool,
pub advance_after_ms: Option<u32>,
pub transition_type: TransitionType,
}
impl Transition {
pub fn write_xml(&self, w: &mut XmlWriter) {
let mut attrs: Vec<(&str, &str)> = Vec::new();
attrs.push(("spd", self.speed.as_str()));
if !self.advance_click {
attrs.push(("advClick", "0"));
}
let adv_tm_s;
if let Some(ms) = self.advance_after_ms {
adv_tm_s = ms.to_string();
attrs.push(("advTm", adv_tm_s.as_str()));
}
w.open_with("p:transition", &attrs);
match &self.transition_type {
TransitionType::Fade { thru_blk } => {
if *thru_blk {
w.empty_with("p:fade", &[("thruBlk", "1")]);
} else {
w.empty("p:fade");
}
}
TransitionType::Push { dir } => {
w.empty_with("p:push", &[("dir", dir.as_str())]);
}
TransitionType::Wipe { dir } => {
w.empty_with("p:wipe", &[("dir", dir.as_str())]);
}
TransitionType::Split { orient, dir } => {
w.empty_with(
"p:split",
&[("orient", orient.as_str()), ("dir", dir.as_str())],
);
}
TransitionType::Cover { dir } => {
w.empty_with("p:cover", &[("dir", dir.as_str())]);
}
TransitionType::Pull { dir } => {
w.empty_with("p:pull", &[("dir", dir.as_str())]);
}
TransitionType::Cut { thru_blk } => {
if *thru_blk {
w.empty_with("p:cut", &[("thruBlk", "1")]);
} else {
w.empty("p:cut");
}
}
TransitionType::Zoom { dir } => {
w.empty_with("p:zoom", &[("dir", dir.as_str())]);
}
TransitionType::Morph { option } => {
w.empty_with("p:morph", &[("option", option.as_str())]);
}
TransitionType::None => {}
}
w.close("p:transition");
}
}
#[derive(Clone, Debug)]
pub enum SlideBackground {
Property(BackgroundProperty),
Reference(BackgroundReference),
}
#[derive(Clone, Debug, Default)]
pub struct BackgroundProperty {
pub solid_fill: crate::oxml::color::Color,
}
#[derive(Clone, Debug, Default)]
pub struct BackgroundReference {
pub idx: u32,
pub scheme_color: String,
}
impl SlideBackground {
pub fn solid(color: crate::oxml::color::Color) -> Self {
SlideBackground::Property(BackgroundProperty { solid_fill: color })
}
pub fn follow_master() -> Self {
SlideBackground::Reference(BackgroundReference {
idx: 1001,
scheme_color: "bg1".to_string(),
})
}
pub fn write_xml(&self, w: &mut XmlWriter) {
w.open("p:bg");
match self {
SlideBackground::Property(p) => {
w.open("p:bgPr");
if !matches!(p.solid_fill, crate::oxml::color::Color::None) {
p.solid_fill.write_solid_fill(w);
}
w.close("p:bgPr");
}
SlideBackground::Reference(r) => {
let idx_s = r.idx.to_string();
w.open_with("p:bgRef", &[("idx", idx_s.as_str())]);
w.empty_with("a:schemeClr", &[("val", r.scheme_color.as_str())]);
w.close("p:bgRef");
}
}
w.close("p:bg");
}
}
#[derive(Clone, Debug)]
pub enum SlideShape {
Sp(Sp),
Pic(Pic),
CxnSp(Connector),
Group(Box<Group>),
GraphicFrame(GraphicFrame),
}
impl Sld {
pub fn to_xml(&self) -> String {
let mut w = XmlWriter::with_decl();
let attrs: Vec<(&str, &str)> = vec![
("xmlns:a", NS_DRAWING_MAIN),
("xmlns:p", NS_PRESENTATION_MAIN),
("xmlns:r", crate::oxml::ns::NS_DRAWING_RELS),
];
w.open_with("p:sld", &attrs);
if !self.name.trim().is_empty() {
w.open_with("p:cSld", &[("name", self.name.as_str())]);
} else {
w.open("p:cSld");
}
if let Some(bg) = &self.background {
bg.write_xml(&mut w);
}
w.open("p:spTree");
w.open("p:nvGrpSpPr");
w.empty_with("p:cNvPr", &[("id", "1"), ("name", "")]);
w.empty("p:cNvGrpSpPr");
w.empty("p:nvPr");
w.close("p:nvGrpSpPr");
w.open("p:grpSpPr");
w.empty("a:xfrm");
w.close("p:grpSpPr");
for shape in &self.shapes {
match shape {
SlideShape::Sp(s) => s.write_xml(&mut w),
SlideShape::Pic(p) => p.write_xml(&mut w),
SlideShape::CxnSp(c) => c.write_xml(&mut w),
SlideShape::Group(g) => g.write_xml(&mut w),
SlideShape::GraphicFrame(g) => g.write_xml(&mut w),
}
}
if let Some(ext) = &self.ext_lst {
ext.write_xml(&mut w);
}
w.close("p:spTree");
w.close("p:cSld");
w.empty("p:clrMapOvr");
if let Some(tr) = &self.transition {
tr.write_xml(&mut w);
}
w.close("p:sld");
w.into_string()
}
pub fn set_layout_rid(&mut self, rid: String) {
self.layout_rid = rid;
}
}
pub fn notes_xml(tb: &TextBody) -> String {
let mut w = XmlWriter::with_decl();
let attrs: Vec<(&str, &str)> = vec![
("xmlns:a", NS_DRAWING_MAIN),
("xmlns:p", NS_PRESENTATION_MAIN),
("xmlns:r", crate::oxml::ns::NS_DRAWING_RELS),
];
w.open_with("p:notes", &attrs);
w.open("p:cSld");
w.open("p:spTree");
w.empty_with("p:nvGrpSpPr", &[]);
w.empty_with("p:grpSpPr", &[]);
w.open("p:sp");
w.open("p:nvSpPr");
w.empty_with("p:cNvPr", &[("id", "2"), ("name", "Notes Placeholder")]);
w.empty_with("p:cNvSpPr", &[("txBox", "1")]);
w.open("p:nvPr");
w.empty_with("p:ph", &[("type", "body"), ("idx", "1")]);
w.close("p:nvPr");
w.close("p:nvSpPr");
w.open("p:spPr");
w.open("a:xfrm");
w.empty_with("a:off", &[("x", "0"), ("y", "0")]);
w.empty_with("a:ext", &[("cx", "6858000"), ("cy", "9144000")]);
w.close("a:xfrm");
w.open_with("a:prstGeom", &[("prst", "rect")]);
w.empty("a:avLst");
w.close("a:prstGeom");
w.close("p:spPr");
tb.write_xml(&mut w, "p:txBody");
w.close("p:sp");
w.close("p:spTree");
w.close("p:cSld");
w.empty("p:clrMapOvr");
w.close("p:notes");
w.into_string()
}