office-toolkit 1.0.0

A Rust library to create, read, and modify Microsoft Office documents (Word/Excel/PowerPoint) in the modern Open XML (OOXML) format.
Documentation
//! PowerPoint tables: a plain grid, a table with merged cells, and a
//! table using a custom style with banding/first-row emphasis. One slide
//! per feature.
//!
//! Run with: `cargo run -p office-toolkit --example pptx_tables`

use std::path::{Path, PathBuf};

use office_toolkit::SaveToFile;
use office_toolkit::drawing::{Color, Fill, TextBody, TextParagraph, TextRun};
use office_toolkit::powerpoint::{
    Shape, SlideTable, SlideTableStyle, TableCell, TableRow, TableStylePart,
};
use office_toolkit::prelude::*;

fn main() -> office_toolkit::Result<()> {
    let path = output_path("pptx_tables.pptx");

    let plain_table = SlideTable::new(2, "Plain table", 5_000_000, 1_500_000)
        .with_offset(838_200, 838_200)
        .with_column_widths(vec![2_500_000, 2_500_000])
        .with_row(
            TableRow::new(500_000)
                .with_cell(cell("Name"))
                .with_cell(cell("Score")),
        )
        .with_row(
            TableRow::new(500_000)
                .with_cell(cell("Alice"))
                .with_cell(cell("92")),
        )
        .with_row(
            TableRow::new(500_000)
                .with_cell(cell("Bob"))
                .with_cell(cell("87")),
        );

    let merged_table = SlideTable::new(2, "Merged cells", 5_000_000, 1_000_000)
        .with_offset(838_200, 838_200)
        .with_column_widths(vec![1_667_000, 1_667_000, 1_666_000])
        .with_row(
            TableRow::new(500_000)
                .with_cell(cell("Spanning header").with_horizontal_span(3))
                .with_cell(TableCell::horizontally_merged())
                .with_cell(TableCell::horizontally_merged()),
        )
        .with_row(
            TableRow::new(500_000)
                .with_cell(cell("A"))
                .with_cell(cell("B"))
                .with_cell(cell("C")),
        );

    let styled_table = SlideTable::new(2, "Styled table", 5_000_000, 1_500_000)
        .with_offset(838_200, 838_200)
        .with_style_id("{66BB4812-77A1-49B3-BDF9-0CCEB564D7B5}")
        .with_style_first_row(true)
        .with_style_band_rows(true)
        .with_column_widths(vec![2_500_000, 2_500_000])
        .with_row(
            TableRow::new(500_000)
                .with_cell(cell("Header A"))
                .with_cell(cell("Header B")),
        )
        .with_row(
            TableRow::new(500_000)
                .with_cell(cell("1"))
                .with_cell(cell("2")),
        )
        .with_row(
            TableRow::new(500_000)
                .with_cell(cell("3"))
                .with_cell(cell("4")),
        );

    let presentation = Presentation::new()
        .with_table_style(
            SlideTableStyle::new(
                "{66BB4812-77A1-49B3-BDF9-0CCEB564D7B5}",
                "Custom Table Style",
            )
            .with_first_row(
                TableStylePart::new()
                    .with_fill(Fill::Solid(Color::Rgb("2E74B5".to_string())))
                    .with_bold(true)
                    .with_text_color(Color::Rgb("FFFFFF".to_string())),
            )
            .with_band1_horizontal(
                TableStylePart::new().with_fill(Fill::Solid(Color::Rgb("F2F2F2".to_string()))),
            ),
        )
        .with_slide(Slide::new().with_shape(Shape::Table(plain_table)))
        .with_slide(Slide::new().with_shape(Shape::Table(merged_table)))
        .with_slide(Slide::new().with_shape(Shape::Table(styled_table)));

    presentation.save_to_file(&path)?;
    println!("Wrote {}", path.display());
    Ok(())
}

fn cell(text: &str) -> TableCell {
    TableCell::new().with_text_body(
        TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(text))),
    )
}

/// Every example in this directory writes its output under
/// `tests-data/output/`, resolved relative to this crate's own manifest so
/// it works no matter what directory `cargo run` was invoked from.
fn output_path(filename: &str) -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("../../tests-data/output")
        .join(filename)
}