pub(crate) mod vml_drawing;
use std::io::Read;
use std::path::Path;
use quick_xml::{se};
use serde::{Deserialize, Serialize};
use crate::api::cell::location::{Location, LocationRange};
use crate::api::relationship::Rel;
use crate::file::{XlsxFileType, XlsxFileWriter};
use crate::xml::io::insert::Insert;
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename(serialize = "xdr:wsDr", deserialize = "wsDr"))]
pub(crate) struct Drawings {
#[serde(rename(serialize = "@xmlns:xdr", deserialize = "@xmlns:xdr"), default, skip_serializing_if = "String::is_empty")]
xmlns_xdr: String,
#[serde(rename(serialize = "@xmlns:a", deserialize = "@xmlns:a"), default, skip_serializing_if = "String::is_empty")]
xmlns_a: String,
#[serde(rename(serialize = "xdr:twoCellAnchor", deserialize = "twoCellAnchor"), default)]
pub(crate) drawing: Vec<Drawing>
}
impl Default for Drawings {
fn default() -> Self {
Self {
xmlns_xdr: "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing".to_string(),
xmlns_a: "http://schemas.openxmlformats.org/drawingml/2006/main".to_string(),
drawing: vec![],
}
}
}
impl Drawings {
pub(crate) fn next_id(&self) -> u32 {
let id = 1 + self.drawing.len() as u32;
id
}
pub(crate) fn add_drawing<L: LocationRange>(&mut self, from_to: L, r_id: u32) {
self.drawing.push(Drawing::new(from_to, r_id));
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub(crate) struct Drawing {
#[serde(rename = "@editAs", default, skip_serializing_if = "String::is_empty")]
edit_as: String,
#[serde(rename(serialize = "xdr:from", deserialize = "from"))]
from: DrawingLocation,
#[serde(rename(serialize = "xdr:to", deserialize = "to"))]
to: DrawingLocation,
#[serde(rename(serialize = "xdr:pic", deserialize = "pic"))]
pic: Picture,
#[serde(rename(serialize = "xdr:clientData", deserialize = "clientData"))]
client_data: ClientData,
}
impl Drawing {
fn new<L: LocationRange>(from_to: L, r_id: u32) -> Drawing {
let (from_row, from_col, to_row, to_col) = from_to.to_range();
Drawing {
edit_as: String::from("oneCell"),
from: DrawingLocation::from_location((from_row, from_col)),
to: DrawingLocation::from_location((to_row, to_col)),
pic: Picture::from_id(r_id),
client_data: ClientData::default(),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
struct DrawingLocation {
#[serde(rename(serialize = "xdr:col", deserialize = "col"))]
col: u32,
#[serde(rename(serialize = "xdr:colOff", deserialize = "colOff"))]
col_off: u32,
#[serde(rename(serialize = "xdr:row", deserialize = "row"))]
row: u32,
#[serde(rename(serialize = "xdr:rowOff", deserialize = "rowOff"))]
row_off: u32
}
impl DrawingLocation {
fn from_location<L: Location>(loc: L) -> DrawingLocation {
let (row, col) = loc.to_location();
DrawingLocation {
col: col - 1,
row: row - 1,
col_off: 0,
row_off: 0,
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
struct Picture {
#[serde(rename(serialize = "xdr:nvPicPr", deserialize = "nvPicPr"))]
pic_pr: PicPr,
#[serde(rename(serialize = "xdr:blipFill", deserialize = "blipFill"))]
blip_fill: BlipFill,
#[serde(rename(serialize = "xdr:spPr", deserialize = "spPr"))]
sp_pr: SpPr,
}
impl Picture {
fn from_id(r_id: u32) -> Self {
Self {
pic_pr: PicPr::from_id(r_id),
blip_fill: BlipFill::from_id(r_id),
sp_pr: SpPr::default(),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
struct PicPr {
#[serde(rename(serialize = "xdr:cNvPr", deserialize = "cNvPr"))]
c_nv_pr: CNvPr,
#[serde(rename(serialize = "xdr:cNvPicPr", deserialize = "cNvPicPr"))]
c_nv_pic_pr: CNvPicPr,
}
impl PicPr {
fn from_id(id: u32) -> Self {
Self {
c_nv_pr: CNvPr::from_id(id),
c_nv_pic_pr: Default::default(),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
struct CNvPr {
#[serde(rename = "@id")]
id: String,
#[serde(rename = "@name")]
name: String,
}
impl CNvPr {
fn from_id(id: u32) -> Self {
Self {
id: id.to_string(),
name: format!("Picture {id}"),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
struct CNvPicPr {
#[serde(rename(serialize = "a:picLocks", deserialize = "picLocks"))]
pic_locks: PicLocks,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
struct PicLocks {
#[serde(rename = "@noChangeAspect")]
no_change_aspect: u8,
}
impl Default for PicLocks {
fn default() -> Self {
Self {
no_change_aspect: 1,
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
struct BlipFill {
#[serde(rename(serialize = "a:blip", deserialize = "blip"))]
blip: Blip,
#[serde(rename(serialize = "a:stretch", deserialize = "stretch"))]
stretch: Stretch,
}
impl BlipFill {
fn from_id(r_id: u32) -> Self {
Self {
blip: Blip::from_id(r_id),
stretch: Default::default(),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
struct Blip {
#[serde(rename(serialize = "@xmlns:r", deserialize = "@xmlns:r"), default, skip_serializing_if = "String::is_empty")]
xmlns_r: String,
#[serde(rename(serialize = "@r:embed", deserialize = "@embed"))]
r_embed: Rel,
}
impl Default for Blip {
fn default() -> Self {
Self {
xmlns_r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships".to_string(),
r_embed: Default::default(),
}
}
}
impl Blip {
fn from_id(r_id: u32) -> Blip {
Blip {
xmlns_r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships".to_string(),
r_embed: Rel::from_id(r_id),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
struct Stretch {
#[serde(rename(serialize = "a:fillRect", deserialize = "fillRect"))]
fill_rect: FillRect,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
struct FillRect {}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
struct SpPr {
#[serde(rename(serialize = "a:prstGeom", deserialize = "prstGeom"))]
prst_geom: PrstGeom,
}
#[derive(Debug, Clone ,Deserialize, Serialize)]
struct PrstGeom {
#[serde(rename(serialize = "a:avLst", deserialize = "avLst"))]
av_lst: AvLst,
#[serde(rename(serialize = "@prst", deserialize = "@prst"))]
prst: String,
}
impl Default for PrstGeom {
fn default() -> Self {
Self {
av_lst: Default::default(),
prst: "rect".to_string(),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
struct AvLst {}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
struct ClientData {}
impl Drawings {
pub(crate) fn save<P: AsRef<Path>>(&self, file_path: P, drawing_id: u32) {
let xml = se::to_string_with_root("xdr:wsDr", &self).unwrap();
let mut xml = format!("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n{}", xml);
let mut content = String::new();
if let Ok(_) = XlsxFileWriter::read_from(&file_path, XlsxFileType::Drawings(drawing_id), &mut content) {
if content.len() > 0 {
self.insert(&mut content);
xml = content.clone();
}
}
let mut file = XlsxFileWriter::from_path(file_path, XlsxFileType::Drawings(drawing_id)).unwrap();
file.write_all(xml.as_ref()).unwrap();
}
}