#[derive(Debug, Default, Clone, PartialEq)]
pub struct Document {
pub blocks: Vec<Block>,
pub header: Option<HeaderFooter>,
pub footer: Option<HeaderFooter>,
pub header_first: Option<HeaderFooter>,
pub footer_first: Option<HeaderFooter>,
pub header_even: Option<HeaderFooter>,
pub footer_even: Option<HeaderFooter>,
pub page_setup: PageSetup,
pub styles: Vec<Style>,
pub numbering_definitions: Vec<NumberingDefinition>,
pub footnotes: Vec<Note>,
pub endnotes: Vec<Note>,
pub comments: Vec<Comment>,
pub theme: Option<Theme>,
pub track_changes: bool,
pub properties: DocumentProperties,
pub protection: Option<ProtectionKind>,
pub extended_properties: ExtendedProperties,
pub custom_properties: Vec<(String, CustomPropertyValue)>,
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct DocumentProperties {
pub title: Option<String>,
pub subject: Option<String>,
pub creator: Option<String>,
pub keywords: Option<String>,
pub description: Option<String>,
pub last_modified_by: Option<String>,
pub revision: Option<String>,
pub created: Option<String>,
pub modified: Option<String>,
pub category: Option<String>,
pub content_status: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProtectionKind {
ReadOnly,
Comments,
TrackedChanges,
Forms,
}
impl ProtectionKind {
pub fn attribute_value(self) -> &'static str {
match self {
ProtectionKind::ReadOnly => "readOnly",
ProtectionKind::Comments => "comments",
ProtectionKind::TrackedChanges => "trackedChanges",
ProtectionKind::Forms => "forms",
}
}
pub fn from_attribute_value(value: &str) -> Option<Self> {
match value {
"readOnly" => Some(ProtectionKind::ReadOnly),
"comments" => Some(ProtectionKind::Comments),
"trackedChanges" => Some(ProtectionKind::TrackedChanges),
"forms" => Some(ProtectionKind::Forms),
_ => None,
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct ExtendedProperties {
pub company: Option<String>,
pub manager: Option<String>,
}
impl ExtendedProperties {
pub fn new() -> Self {
Self::default()
}
pub fn with_company(mut self, company: impl Into<String>) -> Self {
self.company = Some(company.into());
self
}
pub fn with_manager(mut self, manager: impl Into<String>) -> Self {
self.manager = Some(manager.into());
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum CustomPropertyValue {
Text(String),
Bool(bool),
Int(i32),
Number(f64),
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct HeaderFooter {
pub blocks: Vec<Block>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PageSetup {
pub width_twips: u32,
pub height_twips: u32,
pub orientation: Orientation,
pub margin_top_twips: u32,
pub margin_bottom_twips: u32,
pub margin_left_twips: u32,
pub margin_right_twips: u32,
pub margin_header_twips: u32,
pub margin_footer_twips: u32,
pub margin_gutter_twips: u32,
pub columns: Option<u32>,
}
impl Default for PageSetup {
fn default() -> Self {
Self {
width_twips: 11_906,
height_twips: 16_838,
orientation: Orientation::Portrait,
margin_top_twips: 1_417,
margin_bottom_twips: 1_417,
margin_left_twips: 1_417,
margin_right_twips: 1_417,
margin_header_twips: 708,
margin_footer_twips: 708,
margin_gutter_twips: 0,
columns: None,
}
}
}
impl PageSetup {
pub fn new() -> Self {
Self::default()
}
pub fn with_size_twips(mut self, width_twips: u32, height_twips: u32) -> Self {
self.width_twips = width_twips;
self.height_twips = height_twips;
self
}
pub fn with_orientation(mut self, orientation: Orientation) -> Self {
self.orientation = orientation;
self
}
pub fn with_margins_twips(mut self, top: u32, bottom: u32, left: u32, right: u32) -> Self {
self.margin_top_twips = top;
self.margin_bottom_twips = bottom;
self.margin_left_twips = left;
self.margin_right_twips = right;
self
}
pub fn with_header_footer_margins_twips(mut self, header: u32, footer: u32) -> Self {
self.margin_header_twips = header;
self.margin_footer_twips = footer;
self
}
pub fn with_gutter_twips(mut self, gutter: u32) -> Self {
self.margin_gutter_twips = gutter;
self
}
pub fn with_columns(mut self, columns: u32) -> Self {
self.columns = Some(columns);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Orientation {
Portrait,
Landscape,
}
impl Orientation {
pub fn attribute_value(self) -> &'static str {
match self {
Orientation::Portrait => "portrait",
Orientation::Landscape => "landscape",
}
}
pub fn from_attribute_value(value: &str) -> Option<Self> {
match value {
"portrait" => Some(Orientation::Portrait),
"landscape" => Some(Orientation::Landscape),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Block {
Paragraph(Paragraph),
Table(Table),
StructuredDocumentTag(StructuredDocumentTag),
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Paragraph {
pub runs: Vec<Run>,
pub alignment: Option<Alignment>,
pub style_id: Option<String>,
pub numbering_id: Option<u32>,
pub numbering_level: u8,
pub line_spacing: Option<u32>,
pub space_before: Option<u32>,
pub space_after: Option<u32>,
pub shading_color: Option<String>,
pub border: bool,
pub keep_with_next: bool,
pub keep_lines_together: bool,
pub page_break_before: bool,
pub tabs: Vec<TabStop>,
pub contextual_spacing: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TabStop {
pub position_twips: i32,
pub alignment: TabStopAlignment,
pub leader: Option<TabLeader>,
}
impl TabStop {
pub fn new(position_twips: i32) -> Self {
Self {
position_twips,
alignment: TabStopAlignment::Left,
leader: None,
}
}
pub fn with_alignment(mut self, alignment: TabStopAlignment) -> Self {
self.alignment = alignment;
self
}
pub fn with_leader(mut self, leader: TabLeader) -> Self {
self.leader = Some(leader);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TabStopAlignment {
Left,
Center,
Right,
Decimal,
Bar,
}
impl TabStopAlignment {
pub fn attribute_value(self) -> &'static str {
match self {
TabStopAlignment::Left => "left",
TabStopAlignment::Center => "center",
TabStopAlignment::Right => "right",
TabStopAlignment::Decimal => "decimal",
TabStopAlignment::Bar => "bar",
}
}
pub fn from_attribute_value(value: &str) -> Option<Self> {
match value {
"left" => Some(TabStopAlignment::Left),
"center" => Some(TabStopAlignment::Center),
"right" => Some(TabStopAlignment::Right),
"decimal" => Some(TabStopAlignment::Decimal),
"bar" => Some(TabStopAlignment::Bar),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TabLeader {
Dot,
Hyphen,
Underscore,
Heavy,
MiddleDot,
}
impl TabLeader {
pub fn attribute_value(self) -> &'static str {
match self {
TabLeader::Dot => "dot",
TabLeader::Hyphen => "hyphen",
TabLeader::Underscore => "underscore",
TabLeader::Heavy => "heavy",
TabLeader::MiddleDot => "middleDot",
}
}
pub fn from_attribute_value(value: &str) -> Option<Self> {
match value {
"dot" => Some(TabLeader::Dot),
"hyphen" => Some(TabLeader::Hyphen),
"underscore" => Some(TabLeader::Underscore),
"heavy" => Some(TabLeader::Heavy),
"middleDot" => Some(TabLeader::MiddleDot),
_ => None,
}
}
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Run {
pub content: RunContent,
pub bold: bool,
pub italic: bool,
pub underline: Option<UnderlineStyle>,
pub underline_color: Option<String>,
pub color: Option<String>,
pub font_size: Option<u16>,
pub font_family: Option<String>,
pub highlight: Option<Highlight>,
pub strike: bool,
pub vertical_align: Option<VerticalAlign>,
pub small_caps: bool,
pub all_caps: bool,
pub shading_color: Option<String>,
pub text_border: bool,
pub character_spacing: Option<i16>,
pub vertical_position: Option<i16>,
pub hidden: bool,
pub style_id: Option<String>,
pub hyperlink: Option<Hyperlink>,
pub comment_ids: Vec<u32>,
pub bookmarks: Vec<Bookmark>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Bookmark {
pub id: u32,
pub name: String,
}
impl Bookmark {
pub fn new(id: u32, name: impl Into<String>) -> Self {
Self {
id,
name: name.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Hyperlink {
External(String),
Internal(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Style {
pub id: String,
pub name: String,
pub kind: StyleKind,
pub based_on: Option<String>,
pub bold: bool,
pub italic: bool,
pub underline: Option<UnderlineStyle>,
pub underline_color: Option<String>,
pub color: Option<String>,
pub font_size: Option<u16>,
pub font_family: Option<String>,
pub highlight: Option<Highlight>,
pub strike: bool,
pub vertical_align: Option<VerticalAlign>,
pub small_caps: bool,
pub all_caps: bool,
pub shading_color: Option<String>,
pub text_border: bool,
pub character_spacing: Option<i16>,
pub vertical_position: Option<i16>,
pub hidden: bool,
pub alignment: Option<Alignment>,
pub line_spacing: Option<u32>,
pub space_before: Option<u32>,
pub space_after: Option<u32>,
pub paragraph_shading_color: Option<String>,
pub paragraph_border: bool,
pub keep_with_next: bool,
pub keep_lines_together: bool,
pub page_break_before: bool,
pub tabs: Vec<TabStop>,
pub contextual_spacing: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StyleKind {
Paragraph,
Character,
}
impl StyleKind {
pub fn attribute_value(self) -> &'static str {
match self {
StyleKind::Paragraph => "paragraph",
StyleKind::Character => "character",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NumberingDefinition {
pub id: u32,
pub levels: Vec<ListLevel>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ListLevel {
pub format: NumberFormat,
pub text: String,
pub indent_twips: i32,
pub hanging_twips: i32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NumberFormat {
Bullet,
Decimal,
LowerLetter,
UpperLetter,
LowerRoman,
UpperRoman,
}
impl NumberFormat {
pub fn attribute_value(self) -> &'static str {
match self {
NumberFormat::Bullet => "bullet",
NumberFormat::Decimal => "decimal",
NumberFormat::LowerLetter => "lowerLetter",
NumberFormat::UpperLetter => "upperLetter",
NumberFormat::LowerRoman => "lowerRoman",
NumberFormat::UpperRoman => "upperRoman",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NoteReference {
Footnote(u32),
Endnote(u32),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NoteKind {
Footnote,
Endnote,
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Note {
pub id: u32,
pub blocks: Vec<Block>,
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Comment {
pub id: u32,
pub author: Option<String>,
pub initials: Option<String>,
pub date: Option<String>,
pub blocks: Vec<Block>,
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct StructuredDocumentTag {
pub id: Option<i32>,
pub tag: Option<String>,
pub alias: Option<String>,
pub blocks: Vec<Block>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Theme {
pub name: String,
pub colors: ColorScheme,
pub fonts: FontScheme,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ColorScheme {
pub dark1: String,
pub light1: String,
pub dark2: String,
pub light2: String,
pub accent1: String,
pub accent2: String,
pub accent3: String,
pub accent4: String,
pub accent5: String,
pub accent6: String,
pub hyperlink: String,
pub followed_hyperlink: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FontScheme {
pub major_latin: String,
pub minor_latin: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Highlight {
Black,
Blue,
Cyan,
DarkBlue,
DarkCyan,
DarkGray,
DarkGreen,
DarkMagenta,
DarkRed,
DarkYellow,
Green,
LightGray,
Magenta,
Red,
White,
Yellow,
}
impl Highlight {
pub fn attribute_value(self) -> &'static str {
match self {
Highlight::Black => "black",
Highlight::Blue => "blue",
Highlight::Cyan => "cyan",
Highlight::DarkBlue => "darkBlue",
Highlight::DarkCyan => "darkCyan",
Highlight::DarkGray => "darkGray",
Highlight::DarkGreen => "darkGreen",
Highlight::DarkMagenta => "darkMagenta",
Highlight::DarkRed => "darkRed",
Highlight::DarkYellow => "darkYellow",
Highlight::Green => "green",
Highlight::LightGray => "lightGray",
Highlight::Magenta => "magenta",
Highlight::Red => "red",
Highlight::White => "white",
Highlight::Yellow => "yellow",
}
}
pub fn from_attribute_value(value: &str) -> Option<Self> {
match value {
"black" => Some(Highlight::Black),
"blue" => Some(Highlight::Blue),
"cyan" => Some(Highlight::Cyan),
"darkBlue" => Some(Highlight::DarkBlue),
"darkCyan" => Some(Highlight::DarkCyan),
"darkGray" => Some(Highlight::DarkGray),
"darkGreen" => Some(Highlight::DarkGreen),
"darkMagenta" => Some(Highlight::DarkMagenta),
"darkRed" => Some(Highlight::DarkRed),
"darkYellow" => Some(Highlight::DarkYellow),
"green" => Some(Highlight::Green),
"lightGray" => Some(Highlight::LightGray),
"magenta" => Some(Highlight::Magenta),
"red" => Some(Highlight::Red),
"white" => Some(Highlight::White),
"yellow" => Some(Highlight::Yellow),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VerticalAlign {
Superscript,
Subscript,
}
impl VerticalAlign {
pub fn attribute_value(self) -> &'static str {
match self {
VerticalAlign::Superscript => "superscript",
VerticalAlign::Subscript => "subscript",
}
}
pub fn from_attribute_value(value: &str) -> Option<Self> {
match value {
"superscript" => Some(VerticalAlign::Superscript),
"subscript" => Some(VerticalAlign::Subscript),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnderlineStyle {
Single,
Words,
Double,
Thick,
Dotted,
DottedHeavy,
Dash,
DashedHeavy,
DashLong,
DashLongHeavy,
DotDash,
DashDotHeavy,
DotDotDash,
DashDotDotHeavy,
Wave,
WavyHeavy,
WavyDouble,
}
impl UnderlineStyle {
pub fn attribute_value(self) -> &'static str {
match self {
UnderlineStyle::Single => "single",
UnderlineStyle::Words => "words",
UnderlineStyle::Double => "double",
UnderlineStyle::Thick => "thick",
UnderlineStyle::Dotted => "dotted",
UnderlineStyle::DottedHeavy => "dottedHeavy",
UnderlineStyle::Dash => "dash",
UnderlineStyle::DashedHeavy => "dashedHeavy",
UnderlineStyle::DashLong => "dashLong",
UnderlineStyle::DashLongHeavy => "dashLongHeavy",
UnderlineStyle::DotDash => "dotDash",
UnderlineStyle::DashDotHeavy => "dashDotHeavy",
UnderlineStyle::DotDotDash => "dotDotDash",
UnderlineStyle::DashDotDotHeavy => "dashDotDotHeavy",
UnderlineStyle::Wave => "wave",
UnderlineStyle::WavyHeavy => "wavyHeavy",
UnderlineStyle::WavyDouble => "wavyDouble",
}
}
pub fn from_attribute_value(value: &str) -> Option<Self> {
match value {
"single" => Some(UnderlineStyle::Single),
"words" => Some(UnderlineStyle::Words),
"double" => Some(UnderlineStyle::Double),
"thick" => Some(UnderlineStyle::Thick),
"dotted" => Some(UnderlineStyle::Dotted),
"dottedHeavy" => Some(UnderlineStyle::DottedHeavy),
"dash" => Some(UnderlineStyle::Dash),
"dashedHeavy" => Some(UnderlineStyle::DashedHeavy),
"dashLong" => Some(UnderlineStyle::DashLong),
"dashLongHeavy" => Some(UnderlineStyle::DashLongHeavy),
"dotDash" => Some(UnderlineStyle::DotDash),
"dashDotHeavy" => Some(UnderlineStyle::DashDotHeavy),
"dotDotDash" => Some(UnderlineStyle::DotDotDash),
"dashDotDotHeavy" => Some(UnderlineStyle::DashDotDotHeavy),
"wave" => Some(UnderlineStyle::Wave),
"wavyHeavy" => Some(UnderlineStyle::WavyHeavy),
"wavyDouble" => Some(UnderlineStyle::WavyDouble),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum RunContent {
Text(String),
Image(Box<Image>),
Field(Field),
NoteReference(NoteReference),
NoteMarker(NoteKind),
Chart(Box<EmbeddedChart>),
Break(BreakKind),
CarriageReturn,
}
impl Default for RunContent {
fn default() -> Self {
RunContent::Text(String::new())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BreakKind {
Page,
Column,
TextWrapping,
}
impl BreakKind {
pub fn attribute_value(self) -> &'static str {
match self {
BreakKind::Page => "page",
BreakKind::Column => "column",
BreakKind::TextWrapping => "textWrapping",
}
}
pub fn from_attribute_value(value: Option<&str>) -> Self {
match value {
Some("page") => BreakKind::Page,
Some("column") => BreakKind::Column,
_ => BreakKind::TextWrapping,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Field {
PageNumber,
TotalPages,
}
impl Field {
pub fn instruction(self) -> &'static str {
match self {
Field::PageNumber => "PAGE",
Field::TotalPages => "NUMPAGES",
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Image {
pub data: Vec<u8>,
pub format: ImageFormat,
pub width_emu: i64,
pub height_emu: i64,
pub description: String,
pub shape_properties: Option<drawing::ShapeProperties>,
}
pub const EMU_PER_INCH: i64 = 914_400;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ImageFormat {
Png,
Jpeg,
Gif,
Bmp,
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Table {
pub rows: Vec<TableRow>,
pub column_widths: Vec<u32>,
pub border_color: Option<String>,
pub alignment: Option<Alignment>,
pub indent_twips: Option<u32>,
pub style_id: Option<String>,
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct TableRow {
pub cells: Vec<TableCell>,
pub repeat_as_header_row: bool,
pub height_twips: Option<u32>,
pub cant_split: bool,
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct TableCell {
pub blocks: Vec<Block>,
pub horizontal_span: Option<u32>,
pub vertical_merge: Option<VerticalMerge>,
pub border: bool,
pub shading_color: Option<String>,
pub vertical_alignment: Option<CellVerticalAlign>,
pub margin_top_twips: Option<u32>,
pub margin_left_twips: Option<u32>,
pub margin_bottom_twips: Option<u32>,
pub margin_right_twips: Option<u32>,
pub text_direction: Option<TextDirection>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VerticalMerge {
Restart,
Continue,
}
impl VerticalMerge {
pub fn attribute_value(self) -> &'static str {
match self {
VerticalMerge::Restart => "restart",
VerticalMerge::Continue => "continue",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CellVerticalAlign {
Top,
Center,
Bottom,
}
impl CellVerticalAlign {
pub fn attribute_value(self) -> &'static str {
match self {
CellVerticalAlign::Top => "top",
CellVerticalAlign::Center => "center",
CellVerticalAlign::Bottom => "bottom",
}
}
pub fn from_attribute_value(value: &str) -> Option<Self> {
match value {
"top" => Some(CellVerticalAlign::Top),
"center" => Some(CellVerticalAlign::Center),
"bottom" => Some(CellVerticalAlign::Bottom),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextDirection {
TopToBottom,
BottomToTop,
}
impl TextDirection {
pub fn attribute_value(self) -> &'static str {
match self {
TextDirection::TopToBottom => "tbRl",
TextDirection::BottomToTop => "btLr",
}
}
pub fn from_attribute_value(value: &str) -> Option<Self> {
match value {
"tbRl" => Some(TextDirection::TopToBottom),
"btLr" => Some(TextDirection::BottomToTop),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Alignment {
Left,
Center,
Right,
Justify,
}
impl Document {
pub fn new() -> Self {
Self::default()
}
pub fn with_paragraph(mut self, paragraph: Paragraph) -> Self {
self.blocks.push(Block::Paragraph(paragraph));
self
}
pub fn with_table(mut self, table: Table) -> Self {
self.blocks.push(Block::Table(table));
self
}
pub fn add_paragraph(&mut self, text: impl Into<String>) -> &mut Paragraph {
self.blocks
.push(Block::Paragraph(Paragraph::with_text(text)));
let Some(Block::Paragraph(paragraph)) = self.blocks.last_mut() else {
unreachable!("the block just pushed is always a Block::Paragraph")
};
paragraph
}
pub fn paragraphs(&self) -> impl Iterator<Item = &Paragraph> {
self.blocks.iter().filter_map(|block| match block {
Block::Paragraph(paragraph) => Some(paragraph),
Block::Table(_) | Block::StructuredDocumentTag(_) => None,
})
}
pub fn tables(&self) -> impl Iterator<Item = &Table> {
self.blocks.iter().filter_map(|block| match block {
Block::Table(table) => Some(table),
Block::Paragraph(_) | Block::StructuredDocumentTag(_) => None,
})
}
pub fn with_header(mut self, header: HeaderFooter) -> Self {
self.header = Some(header);
self
}
pub fn with_footer(mut self, footer: HeaderFooter) -> Self {
self.footer = Some(footer);
self
}
pub fn with_header_first(mut self, header: HeaderFooter) -> Self {
self.header_first = Some(header);
self
}
pub fn with_footer_first(mut self, footer: HeaderFooter) -> Self {
self.footer_first = Some(footer);
self
}
pub fn with_header_even(mut self, header: HeaderFooter) -> Self {
self.header_even = Some(header);
self
}
pub fn with_footer_even(mut self, footer: HeaderFooter) -> Self {
self.footer_even = Some(footer);
self
}
pub fn with_page_setup(mut self, page_setup: PageSetup) -> Self {
self.page_setup = page_setup;
self
}
pub fn with_style(mut self, style: Style) -> Self {
self.styles.push(style);
self
}
pub fn with_numbering_definition(mut self, definition: NumberingDefinition) -> Self {
self.numbering_definitions.push(definition);
self
}
pub fn with_footnote(mut self, note: Note) -> Self {
self.footnotes.push(note);
self
}
pub fn with_endnote(mut self, note: Note) -> Self {
self.endnotes.push(note);
self
}
pub fn with_comment(mut self, comment: Comment) -> Self {
self.comments.push(comment);
self
}
pub fn with_structured_document_tag(mut self, sdt: StructuredDocumentTag) -> Self {
self.blocks.push(Block::StructuredDocumentTag(sdt));
self
}
pub fn with_theme(mut self, theme: Theme) -> Self {
self.theme = Some(theme);
self
}
pub fn with_track_changes(mut self, track_changes: bool) -> Self {
self.track_changes = track_changes;
self
}
pub fn with_properties(mut self, properties: DocumentProperties) -> Self {
self.properties = properties;
self
}
pub fn with_protection(mut self, protection: ProtectionKind) -> Self {
self.protection = Some(protection);
self
}
pub fn with_extended_properties(mut self, extended_properties: ExtendedProperties) -> Self {
self.extended_properties = extended_properties;
self
}
pub fn with_custom_property(
mut self,
name: impl Into<String>,
value: CustomPropertyValue,
) -> Self {
self.custom_properties.push((name.into(), value));
self
}
}
impl DocumentProperties {
pub fn new() -> Self {
Self::default()
}
pub fn with_title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn with_subject(mut self, subject: impl Into<String>) -> Self {
self.subject = Some(subject.into());
self
}
pub fn with_creator(mut self, creator: impl Into<String>) -> Self {
self.creator = Some(creator.into());
self
}
pub fn with_keywords(mut self, keywords: impl Into<String>) -> Self {
self.keywords = Some(keywords.into());
self
}
pub fn with_description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn with_last_modified_by(mut self, last_modified_by: impl Into<String>) -> Self {
self.last_modified_by = Some(last_modified_by.into());
self
}
pub fn with_revision(mut self, revision: impl Into<String>) -> Self {
self.revision = Some(revision.into());
self
}
pub fn with_created(mut self, created: impl Into<String>) -> Self {
self.created = Some(created.into());
self
}
pub fn with_modified(mut self, modified: impl Into<String>) -> Self {
self.modified = Some(modified.into());
self
}
pub fn with_category(mut self, category: impl Into<String>) -> Self {
self.category = Some(category.into());
self
}
pub fn with_content_status(mut self, content_status: impl Into<String>) -> Self {
self.content_status = Some(content_status.into());
self
}
}
impl HeaderFooter {
pub fn new() -> Self {
Self::default()
}
pub fn with_paragraph(mut self, paragraph: Paragraph) -> Self {
self.blocks.push(Block::Paragraph(paragraph));
self
}
pub fn with_table(mut self, table: Table) -> Self {
self.blocks.push(Block::Table(table));
self
}
pub fn with_structured_document_tag(mut self, sdt: StructuredDocumentTag) -> Self {
self.blocks.push(Block::StructuredDocumentTag(sdt));
self
}
pub fn paragraphs(&self) -> impl Iterator<Item = &Paragraph> {
self.blocks.iter().filter_map(|block| match block {
Block::Paragraph(paragraph) => Some(paragraph),
Block::Table(_) | Block::StructuredDocumentTag(_) => None,
})
}
pub fn tables(&self) -> impl Iterator<Item = &Table> {
self.blocks.iter().filter_map(|block| match block {
Block::Table(table) => Some(table),
Block::Paragraph(_) | Block::StructuredDocumentTag(_) => None,
})
}
}
impl Note {
pub fn new(id: u32) -> Self {
Self {
id,
blocks: Vec::new(),
}
}
pub fn footnote_with_text(id: u32, text: impl Into<String>) -> Self {
Self::with_marker_and_text(id, NoteKind::Footnote, text)
}
pub fn endnote_with_text(id: u32, text: impl Into<String>) -> Self {
Self::with_marker_and_text(id, NoteKind::Endnote, text)
}
fn with_marker_and_text(id: u32, kind: NoteKind, text: impl Into<String>) -> Self {
Self {
id,
blocks: vec![Block::Paragraph(
Paragraph::new()
.with_run(Run::with_note_marker(kind))
.with_run(Run::new(" "))
.with_run(Run::new(text)),
)],
}
}
pub fn with_paragraph(mut self, paragraph: Paragraph) -> Self {
self.blocks.push(Block::Paragraph(paragraph));
self
}
pub fn with_table(mut self, table: Table) -> Self {
self.blocks.push(Block::Table(table));
self
}
pub fn paragraphs(&self) -> impl Iterator<Item = &Paragraph> {
self.blocks.iter().filter_map(|block| match block {
Block::Paragraph(paragraph) => Some(paragraph),
Block::Table(_) | Block::StructuredDocumentTag(_) => None,
})
}
pub fn tables(&self) -> impl Iterator<Item = &Table> {
self.blocks.iter().filter_map(|block| match block {
Block::Table(table) => Some(table),
Block::Paragraph(_) | Block::StructuredDocumentTag(_) => None,
})
}
}
impl Comment {
pub fn new(id: u32) -> Self {
Self {
id,
..Self::default()
}
}
pub fn with_text(id: u32, text: impl Into<String>) -> Self {
Self {
id,
blocks: vec![Block::Paragraph(Paragraph::with_text(text))],
..Self::default()
}
}
pub fn with_author(mut self, author: impl Into<String>) -> Self {
self.author = Some(author.into());
self
}
pub fn with_initials(mut self, initials: impl Into<String>) -> Self {
self.initials = Some(initials.into());
self
}
pub fn with_date(mut self, date: impl Into<String>) -> Self {
self.date = Some(date.into());
self
}
pub fn with_paragraph(mut self, paragraph: Paragraph) -> Self {
self.blocks.push(Block::Paragraph(paragraph));
self
}
pub fn with_table(mut self, table: Table) -> Self {
self.blocks.push(Block::Table(table));
self
}
pub fn paragraphs(&self) -> impl Iterator<Item = &Paragraph> {
self.blocks.iter().filter_map(|block| match block {
Block::Paragraph(paragraph) => Some(paragraph),
Block::Table(_) | Block::StructuredDocumentTag(_) => None,
})
}
pub fn tables(&self) -> impl Iterator<Item = &Table> {
self.blocks.iter().filter_map(|block| match block {
Block::Table(table) => Some(table),
Block::Paragraph(_) | Block::StructuredDocumentTag(_) => None,
})
}
}
impl StructuredDocumentTag {
pub fn new() -> Self {
Self::default()
}
pub fn with_id(mut self, id: i32) -> Self {
self.id = Some(id);
self
}
pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
self.tag = Some(tag.into());
self
}
pub fn with_alias(mut self, alias: impl Into<String>) -> Self {
self.alias = Some(alias.into());
self
}
pub fn with_paragraph(mut self, paragraph: Paragraph) -> Self {
self.blocks.push(Block::Paragraph(paragraph));
self
}
pub fn with_table(mut self, table: Table) -> Self {
self.blocks.push(Block::Table(table));
self
}
pub fn paragraphs(&self) -> impl Iterator<Item = &Paragraph> {
self.blocks.iter().filter_map(|block| match block {
Block::Paragraph(paragraph) => Some(paragraph),
Block::Table(_) | Block::StructuredDocumentTag(_) => None,
})
}
pub fn tables(&self) -> impl Iterator<Item = &Table> {
self.blocks.iter().filter_map(|block| match block {
Block::Table(table) => Some(table),
Block::Paragraph(_) | Block::StructuredDocumentTag(_) => None,
})
}
}
impl Theme {
pub fn new(name: impl Into<String>, colors: ColorScheme, fonts: FontScheme) -> Self {
Self {
name: name.into(),
colors,
fonts,
}
}
pub fn office_default() -> Self {
Self::new(
"Office",
ColorScheme::office_default(),
FontScheme::office_default(),
)
}
}
impl ColorScheme {
#[allow(clippy::too_many_arguments)]
pub fn new(
dark1: impl Into<String>,
light1: impl Into<String>,
dark2: impl Into<String>,
light2: impl Into<String>,
accent1: impl Into<String>,
accent2: impl Into<String>,
accent3: impl Into<String>,
accent4: impl Into<String>,
accent5: impl Into<String>,
accent6: impl Into<String>,
hyperlink: impl Into<String>,
followed_hyperlink: impl Into<String>,
) -> Self {
Self {
dark1: dark1.into(),
light1: light1.into(),
dark2: dark2.into(),
light2: light2.into(),
accent1: accent1.into(),
accent2: accent2.into(),
accent3: accent3.into(),
accent4: accent4.into(),
accent5: accent5.into(),
accent6: accent6.into(),
hyperlink: hyperlink.into(),
followed_hyperlink: followed_hyperlink.into(),
}
}
pub fn office_default() -> Self {
Self::new(
"000000", "FFFFFF", "1F497D", "EEECE1", "4F81BD", "C0504D", "9BBB59", "8064A2",
"4BACC6", "F79646", "0000FF", "800080",
)
}
}
impl FontScheme {
pub fn new(major_latin: impl Into<String>, minor_latin: impl Into<String>) -> Self {
Self {
major_latin: major_latin.into(),
minor_latin: minor_latin.into(),
}
}
pub fn office_default() -> Self {
Self::new("Cambria", "Calibri")
}
}
impl Paragraph {
pub fn new() -> Self {
Self::default()
}
pub fn with_text(text: impl Into<String>) -> Self {
Self {
runs: vec![Run::new(text)],
..Self::default()
}
}
pub fn with_run(mut self, run: Run) -> Self {
self.runs.push(run);
self
}
pub fn with_alignment(mut self, alignment: Alignment) -> Self {
self.alignment = Some(alignment);
self
}
pub fn with_style_id(mut self, style_id: impl Into<String>) -> Self {
self.style_id = Some(style_id.into());
self
}
pub fn with_numbering(mut self, numbering_id: u32, level: u8) -> Self {
self.numbering_id = Some(numbering_id);
self.numbering_level = level;
self
}
pub fn with_line_spacing(mut self, line_spacing: u32) -> Self {
self.line_spacing = Some(line_spacing);
self
}
pub fn with_space_before(mut self, space_before: u32) -> Self {
self.space_before = Some(space_before);
self
}
pub fn with_space_after(mut self, space_after: u32) -> Self {
self.space_after = Some(space_after);
self
}
pub fn with_shading_color(mut self, shading_color: impl Into<String>) -> Self {
self.shading_color = Some(shading_color.into());
self
}
pub fn with_border(mut self, border: bool) -> Self {
self.border = border;
self
}
pub fn with_keep_with_next(mut self, keep_with_next: bool) -> Self {
self.keep_with_next = keep_with_next;
self
}
pub fn with_keep_lines_together(mut self, keep_lines_together: bool) -> Self {
self.keep_lines_together = keep_lines_together;
self
}
pub fn with_page_break_before(mut self, page_break_before: bool) -> Self {
self.page_break_before = page_break_before;
self
}
pub fn with_tab(mut self, tab: TabStop) -> Self {
self.tabs.push(tab);
self
}
pub fn with_contextual_spacing(mut self, contextual_spacing: bool) -> Self {
self.contextual_spacing = contextual_spacing;
self
}
pub fn text(&self) -> String {
self.runs.iter().filter_map(Run::text).collect()
}
}
impl Run {
pub fn new(text: impl Into<String>) -> Self {
Self {
content: RunContent::Text(text.into()),
..Self::default()
}
}
pub fn with_image(image: Image) -> Self {
Self {
content: RunContent::Image(Box::new(image)),
..Self::default()
}
}
pub fn with_chart(chart: EmbeddedChart) -> Self {
Self {
content: RunContent::Chart(Box::new(chart)),
..Self::default()
}
}
pub fn with_field(field: Field) -> Self {
Self {
content: RunContent::Field(field),
..Self::default()
}
}
pub fn with_break(kind: BreakKind) -> Self {
Self {
content: RunContent::Break(kind),
..Self::default()
}
}
pub fn with_carriage_return() -> Self {
Self {
content: RunContent::CarriageReturn,
..Self::default()
}
}
pub fn text(&self) -> Option<&str> {
match &self.content {
RunContent::Text(text) => Some(text.as_str()),
RunContent::Image(_)
| RunContent::Chart(_)
| RunContent::Field(_)
| RunContent::NoteReference(_)
| RunContent::NoteMarker(_)
| RunContent::Break(_)
| RunContent::CarriageReturn => None,
}
}
pub fn image(&self) -> Option<&Image> {
match &self.content {
RunContent::Image(image) => Some(image.as_ref()),
RunContent::Text(_)
| RunContent::Chart(_)
| RunContent::Field(_)
| RunContent::NoteReference(_)
| RunContent::NoteMarker(_)
| RunContent::Break(_)
| RunContent::CarriageReturn => None,
}
}
pub fn chart(&self) -> Option<&EmbeddedChart> {
match &self.content {
RunContent::Chart(chart) => Some(chart.as_ref()),
RunContent::Text(_)
| RunContent::Image(_)
| RunContent::Field(_)
| RunContent::NoteReference(_)
| RunContent::NoteMarker(_)
| RunContent::Break(_)
| RunContent::CarriageReturn => None,
}
}
pub fn field(&self) -> Option<Field> {
match &self.content {
RunContent::Field(field) => Some(*field),
RunContent::Text(_)
| RunContent::Image(_)
| RunContent::Chart(_)
| RunContent::NoteReference(_)
| RunContent::NoteMarker(_)
| RunContent::Break(_)
| RunContent::CarriageReturn => None,
}
}
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: UnderlineStyle) -> Self {
self.underline = Some(underline);
self
}
pub fn with_underline_color(mut self, underline_color: impl Into<String>) -> Self {
self.underline_color = Some(underline_color.into());
self
}
pub fn with_color(mut self, color: impl Into<String>) -> Self {
self.color = Some(color.into());
self
}
pub fn with_font_size(mut self, font_size: u16) -> Self {
self.font_size = Some(font_size);
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_highlight(mut self, highlight: Highlight) -> Self {
self.highlight = Some(highlight);
self
}
pub fn with_strike(mut self, strike: bool) -> Self {
self.strike = strike;
self
}
pub fn with_vertical_align(mut self, vertical_align: VerticalAlign) -> Self {
self.vertical_align = Some(vertical_align);
self
}
pub fn with_small_caps(mut self, small_caps: bool) -> Self {
self.small_caps = small_caps;
self
}
pub fn with_all_caps(mut self, all_caps: bool) -> Self {
self.all_caps = all_caps;
self
}
pub fn with_shading_color(mut self, shading_color: impl Into<String>) -> Self {
self.shading_color = Some(shading_color.into());
self
}
pub fn with_text_border(mut self, text_border: bool) -> Self {
self.text_border = text_border;
self
}
pub fn with_character_spacing(mut self, character_spacing: i16) -> Self {
self.character_spacing = Some(character_spacing);
self
}
pub fn with_vertical_position(mut self, vertical_position: i16) -> Self {
self.vertical_position = Some(vertical_position);
self
}
pub fn with_hidden(mut self, hidden: bool) -> Self {
self.hidden = hidden;
self
}
pub fn with_style_id(mut self, style_id: impl Into<String>) -> Self {
self.style_id = Some(style_id.into());
self
}
pub fn with_hyperlink(mut self, hyperlink: Hyperlink) -> Self {
self.hyperlink = Some(hyperlink);
self
}
pub fn with_comment(mut self, comment_id: u32) -> Self {
self.comment_ids.push(comment_id);
self
}
pub fn with_bookmark(mut self, bookmark: Bookmark) -> Self {
self.bookmarks.push(bookmark);
self
}
pub fn with_note_reference(reference: NoteReference) -> Self {
let style_id = match reference {
NoteReference::Footnote(_) => "FootnoteReference",
NoteReference::Endnote(_) => "EndnoteReference",
};
Self {
content: RunContent::NoteReference(reference),
style_id: Some(style_id.to_string()),
..Self::default()
}
}
pub fn with_note_marker(kind: NoteKind) -> Self {
let style_id = match kind {
NoteKind::Footnote => "FootnoteReference",
NoteKind::Endnote => "EndnoteReference",
};
Self {
content: RunContent::NoteMarker(kind),
style_id: Some(style_id.to_string()),
..Self::default()
}
}
}
impl Image {
pub fn new(
data: impl Into<Vec<u8>>,
format: ImageFormat,
width_emu: i64,
height_emu: i64,
) -> Self {
Self {
data: data.into(),
format,
width_emu,
height_emu,
description: String::new(),
shape_properties: None,
}
}
pub fn from_pixels(
data: impl Into<Vec<u8>>,
format: ImageFormat,
width_px: u32,
height_px: u32,
) -> Self {
const DEFAULT_DPI: i64 = 96;
Self::new(
data,
format,
(i64::from(width_px) * EMU_PER_INCH) / DEFAULT_DPI,
(i64::from(height_px) * EMU_PER_INCH) / DEFAULT_DPI,
)
}
pub fn with_description(mut self, description: impl Into<String>) -> Self {
self.description = description.into();
self
}
pub fn with_shape_properties(mut self, shape_properties: drawing::ShapeProperties) -> Self {
self.shape_properties = Some(shape_properties);
self
}
}
impl ImageFormat {
pub fn extension(self) -> &'static str {
match self {
ImageFormat::Png => "png",
ImageFormat::Jpeg => "jpg",
ImageFormat::Gif => "gif",
ImageFormat::Bmp => "bmp",
}
}
pub fn content_type(self) -> &'static str {
match self {
ImageFormat::Png => "image/png",
ImageFormat::Jpeg => "image/jpeg",
ImageFormat::Gif => "image/gif",
ImageFormat::Bmp => "image/bmp",
}
}
pub fn from_extension(name: &str) -> Option<Self> {
match name.rsplit('.').next()?.to_lowercase().as_str() {
"png" => Some(ImageFormat::Png),
"jpg" | "jpeg" => Some(ImageFormat::Jpeg),
"gif" => Some(ImageFormat::Gif),
"bmp" => Some(ImageFormat::Bmp),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct EmbeddedChart {
pub chart_space: chart::ChartSpace,
pub width_emu: i64,
pub height_emu: i64,
pub name: String,
}
impl EmbeddedChart {
pub fn new(chart_space: chart::ChartSpace, width_emu: i64, height_emu: i64) -> Self {
Self {
chart_space,
width_emu,
height_emu,
name: String::new(),
}
}
pub fn with_name(mut self, name: impl Into<String>) -> Self {
self.name = name.into();
self
}
}
impl Table {
pub fn new() -> Self {
Self::default()
}
pub fn with_row(mut self, row: TableRow) -> Self {
self.rows.push(row);
self
}
pub fn with_column_widths(mut self, column_widths: Vec<u32>) -> Self {
self.column_widths = column_widths;
self
}
pub fn with_border_color(mut self, border_color: impl Into<String>) -> Self {
self.border_color = Some(border_color.into());
self
}
pub fn with_alignment(mut self, alignment: Alignment) -> Self {
self.alignment = Some(alignment);
self
}
pub fn with_indent_twips(mut self, indent_twips: u32) -> Self {
self.indent_twips = Some(indent_twips);
self
}
pub fn with_style_id(mut self, style_id: impl Into<String>) -> Self {
self.style_id = Some(style_id.into());
self
}
}
impl TableRow {
pub fn new() -> Self {
Self::default()
}
pub fn with_cell(mut self, cell: TableCell) -> Self {
self.cells.push(cell);
self
}
pub fn with_repeat_as_header_row(mut self, repeat_as_header_row: bool) -> Self {
self.repeat_as_header_row = repeat_as_header_row;
self
}
pub fn with_height_twips(mut self, height_twips: u32) -> Self {
self.height_twips = Some(height_twips);
self
}
pub fn with_cant_split(mut self, cant_split: bool) -> Self {
self.cant_split = cant_split;
self
}
}
impl TableCell {
pub fn new() -> Self {
Self::default()
}
pub fn with_text(text: impl Into<String>) -> Self {
Self {
blocks: vec![Block::Paragraph(Paragraph::with_text(text))],
..Self::default()
}
}
pub fn with_paragraph(mut self, paragraph: Paragraph) -> Self {
self.blocks.push(Block::Paragraph(paragraph));
self
}
pub fn with_table(mut self, table: Table) -> Self {
self.blocks.push(Block::Table(table));
self
}
pub fn paragraphs(&self) -> impl Iterator<Item = &Paragraph> {
self.blocks.iter().filter_map(|block| match block {
Block::Paragraph(paragraph) => Some(paragraph),
Block::Table(_) | Block::StructuredDocumentTag(_) => None,
})
}
pub fn tables(&self) -> impl Iterator<Item = &Table> {
self.blocks.iter().filter_map(|block| match block {
Block::Table(table) => Some(table),
Block::Paragraph(_) | Block::StructuredDocumentTag(_) => None,
})
}
pub fn with_horizontal_span(mut self, horizontal_span: u32) -> Self {
self.horizontal_span = Some(horizontal_span);
self
}
pub fn with_vertical_merge(mut self, vertical_merge: VerticalMerge) -> Self {
self.vertical_merge = Some(vertical_merge);
self
}
pub fn with_border(mut self, border: bool) -> Self {
self.border = border;
self
}
pub fn with_shading_color(mut self, shading_color: impl Into<String>) -> Self {
self.shading_color = Some(shading_color.into());
self
}
pub fn with_vertical_alignment(mut self, vertical_alignment: CellVerticalAlign) -> Self {
self.vertical_alignment = Some(vertical_alignment);
self
}
pub fn with_margins_twips(mut self, top: u32, left: u32, bottom: u32, right: u32) -> Self {
self.margin_top_twips = Some(top);
self.margin_left_twips = Some(left);
self.margin_bottom_twips = Some(bottom);
self.margin_right_twips = Some(right);
self
}
pub fn with_text_direction(mut self, text_direction: TextDirection) -> Self {
self.text_direction = Some(text_direction);
self
}
pub fn text(&self) -> String {
self.paragraphs()
.map(Paragraph::text)
.collect::<Vec<_>>()
.join("\n")
}
}
impl Style {
pub fn new(id: impl Into<String>, name: impl Into<String>, kind: StyleKind) -> Self {
Self {
id: id.into(),
name: name.into(),
kind,
based_on: None,
bold: false,
italic: false,
underline: None,
underline_color: None,
color: None,
font_size: None,
font_family: None,
highlight: None,
strike: false,
vertical_align: None,
small_caps: false,
all_caps: false,
shading_color: None,
text_border: false,
character_spacing: None,
vertical_position: None,
hidden: false,
alignment: None,
line_spacing: None,
space_before: None,
space_after: None,
paragraph_shading_color: None,
paragraph_border: false,
keep_with_next: false,
keep_lines_together: false,
page_break_before: false,
tabs: Vec::new(),
contextual_spacing: false,
}
}
pub fn with_based_on(mut self, style_id: impl Into<String>) -> Self {
self.based_on = Some(style_id.into());
self
}
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: UnderlineStyle) -> Self {
self.underline = Some(underline);
self
}
pub fn with_underline_color(mut self, underline_color: impl Into<String>) -> Self {
self.underline_color = Some(underline_color.into());
self
}
pub fn with_color(mut self, color: impl Into<String>) -> Self {
self.color = Some(color.into());
self
}
pub fn with_font_size(mut self, font_size: u16) -> Self {
self.font_size = Some(font_size);
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_highlight(mut self, highlight: Highlight) -> Self {
self.highlight = Some(highlight);
self
}
pub fn with_strike(mut self, strike: bool) -> Self {
self.strike = strike;
self
}
pub fn with_vertical_align(mut self, vertical_align: VerticalAlign) -> Self {
self.vertical_align = Some(vertical_align);
self
}
pub fn with_small_caps(mut self, small_caps: bool) -> Self {
self.small_caps = small_caps;
self
}
pub fn with_all_caps(mut self, all_caps: bool) -> Self {
self.all_caps = all_caps;
self
}
pub fn with_shading_color(mut self, shading_color: impl Into<String>) -> Self {
self.shading_color = Some(shading_color.into());
self
}
pub fn with_text_border(mut self, text_border: bool) -> Self {
self.text_border = text_border;
self
}
pub fn with_character_spacing(mut self, character_spacing: i16) -> Self {
self.character_spacing = Some(character_spacing);
self
}
pub fn with_vertical_position(mut self, vertical_position: i16) -> Self {
self.vertical_position = Some(vertical_position);
self
}
pub fn with_hidden(mut self, hidden: bool) -> Self {
self.hidden = hidden;
self
}
pub fn with_alignment(mut self, alignment: Alignment) -> Self {
self.alignment = Some(alignment);
self
}
pub fn with_line_spacing(mut self, line_spacing: u32) -> Self {
self.line_spacing = Some(line_spacing);
self
}
pub fn with_space_before(mut self, space_before: u32) -> Self {
self.space_before = Some(space_before);
self
}
pub fn with_space_after(mut self, space_after: u32) -> Self {
self.space_after = Some(space_after);
self
}
pub fn with_paragraph_shading_color(
mut self,
paragraph_shading_color: impl Into<String>,
) -> Self {
self.paragraph_shading_color = Some(paragraph_shading_color.into());
self
}
pub fn with_paragraph_border(mut self, paragraph_border: bool) -> Self {
self.paragraph_border = paragraph_border;
self
}
pub fn with_keep_with_next(mut self, keep_with_next: bool) -> Self {
self.keep_with_next = keep_with_next;
self
}
pub fn with_keep_lines_together(mut self, keep_lines_together: bool) -> Self {
self.keep_lines_together = keep_lines_together;
self
}
pub fn with_page_break_before(mut self, page_break_before: bool) -> Self {
self.page_break_before = page_break_before;
self
}
pub fn with_tab(mut self, tab: TabStop) -> Self {
self.tabs.push(tab);
self
}
pub fn with_contextual_spacing(mut self, contextual_spacing: bool) -> Self {
self.contextual_spacing = contextual_spacing;
self
}
}
impl NumberingDefinition {
pub fn new(id: u32, levels: Vec<ListLevel>) -> Self {
Self { id, levels }
}
pub fn bullet(id: u32) -> Self {
Self::new(
id,
vec![
ListLevel::new(NumberFormat::Bullet, "\u{2022}", 720, 360), ListLevel::new(NumberFormat::Bullet, "\u{25E6}", 1440, 360), ListLevel::new(NumberFormat::Bullet, "\u{25AA}", 2160, 360), ],
)
}
pub fn decimal(id: u32) -> Self {
Self::new(
id,
vec![
ListLevel::new(NumberFormat::Decimal, "%1.", 360, 360),
ListLevel::new(NumberFormat::Decimal, "%1.%2.", 792, 432),
ListLevel::new(NumberFormat::Decimal, "%1.%2.%3.", 1224, 504),
],
)
}
}
impl ListLevel {
pub fn new(
format: NumberFormat,
text: impl Into<String>,
indent_twips: i32,
hanging_twips: i32,
) -> Self {
Self {
format,
text: text.into(),
indent_twips,
hanging_twips,
}
}
}