use ppt_rs::elements::{Color, Position, RgbColor, SchemeColor, Size, Transform, EMU_PER_INCH};
use ppt_rs::generator::shapes::{GradientDirection, GradientFill};
use ppt_rs::generator::{
create_pptx_with_settings,
ArrowSize,
ArrowType,
BulletPoint,
BulletStyle,
ChartBuilder,
ChartSeries,
ChartType,
Connector,
ConnectorLine,
HandoutLayout as GenHandoutLayout,
ImageBuilder,
LineDash,
PenColor,
PresentationSettings,
PrintColorMode,
PrintSettings,
PrintWhat,
ShapeType,
ShowType,
SlideContent,
SlideLayout,
SlideRange,
SlideShowSettings,
TableBuilder,
TableCell,
TableMergeMap,
TableRow,
};
use ppt_rs::opc::Package;
use ppt_rs::parts::{
AppPropertiesPart, ContentTypesPart, HorizontalAlign, LayoutType, MediaFormat, MediaPart,
NotesSlidePart, Part, SlideLayoutPart, SlideMasterPart, TableCellPart, TablePart, TableRowPart,
ThemePart, VerticalAlign,
};
use ppt_rs::prelude::{
circle,
colors,
diamond,
ellipse,
font_sizes,
hex,
inches,
rect,
rounded_rect,
shapes,
themes,
triangle,
ColorValue,
Dimension,
ShapeExt,
};
use ppt_rs::ToXml;
use std::fs;
use std::path::{Path, PathBuf};
fn project_path(relative: &str) -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join(relative)
}
fn load_stock_photos() -> Vec<(Vec<u8>, String, String)> {
const FALLBACK: &[u8] = include_bytes!("assets/diagram.png");
let assets_dir = project_path("examples/assets");
let mut stock_photos: Vec<(Vec<u8>, String, String)> = Vec::new();
if let Ok(entries) = fs::read_dir(&assets_dir) {
let mut files: Vec<_> = entries.flatten().collect();
files.sort_by_key(|e| e.file_name());
for entry in files {
let filename = entry.file_name();
let Some(filename) = filename.to_str() else {
continue;
};
if filename.ends_with(".txt") {
continue;
}
let path = entry.path();
let Some(ext) = path.extension() else {
continue;
};
let ext_str = ext.to_string_lossy().to_lowercase();
if ext_str != "jpg" && ext_str != "jpeg" && ext_str != "png" {
continue;
}
if let Ok(bytes) = fs::read(&path) {
let format = if ext_str == "png" { "PNG" } else { "JPEG" };
let size_kb = bytes.len() as f64 / 1024.0;
stock_photos.push((bytes, format.to_string(), filename.to_string()));
println!(" Loaded: {} ({:.1} KB)", filename, size_kb);
}
}
}
if stock_photos.is_empty() {
println!(
" ⚠ No images in {}; using embedded fallback PNG",
assets_dir.display()
);
stock_photos.push((
FALLBACK.to_vec(),
"PNG".to_string(),
"embedded-diagram.png".to_string(),
));
}
stock_photos
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("╔══════════════════════════════════════════════════════════════╗");
println!("║ PPTX-RS Element Showcase - Complete Coverage ║");
println!("╚══════════════════════════════════════════════════════════════╝\n");
let mut slides = Vec::new();
println!("📐 Slide 1: CenteredTitle Layout + Title Formatting");
slides.push(
SlideContent::new("PPTX-RS Element Showcase")
.layout(SlideLayout::CenteredTitle)
.title_size(54)
.title_bold(true)
.title_color("1F497D"),
);
println!("📐 Slide 2: TitleOnly Layout");
slides.push(
SlideContent::new("Section: Slide Layouts")
.layout(SlideLayout::TitleOnly)
.title_size(48)
.title_bold(true)
.title_color("C0504D"),
);
println!("📝 Slide 3: TitleAndContent + Text Formatting");
slides.push(
SlideContent::new("Text Formatting Options")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.title_italic(true)
.title_underline(true)
.title_size(44)
.add_bullet("Normal text (default)")
.add_bullet("Bold content text")
.add_bullet("Italic content text")
.add_bullet("Underlined content")
.add_bullet("Custom font size (28pt)")
.add_bullet("Custom color (#4F81BD)")
.content_bold(true)
.content_italic(true)
.content_underline(true)
.content_size(28)
.content_color("4F81BD"),
);
println!("📐 Slide 4: TitleAndBigContent Layout");
slides.push(
SlideContent::new("Key Highlights")
.layout(SlideLayout::TitleAndBigContent)
.title_color("1F497D")
.add_bullet("Large content area for emphasis")
.add_bullet("Perfect for key messages")
.add_bullet("Smaller title, bigger content")
.content_bold(true)
.content_size(32),
);
println!("📐 Slide 5: TwoColumn Layout");
slides.push(
SlideContent::new("Two Column Comparison")
.layout(SlideLayout::TwoColumn)
.title_color("1F497D")
.add_bullet("Left Column Item 1")
.add_bullet("Left Column Item 2")
.add_bullet("Left Column Item 3")
.add_bullet("Right Column Item 1")
.add_bullet("Right Column Item 2")
.add_bullet("Right Column Item 3")
.content_size(24),
);
println!("📐 Slide 6: Blank Layout");
slides.push(SlideContent::new("").layout(SlideLayout::Blank));
println!("📊 Slide 7: Table with Cell Styling");
let styled_table = TableBuilder::new(vec![1500000, 1500000, 1500000])
.add_row(TableRow::new(vec![
TableCell::new("Header 1").bold().background_color("1F497D"),
TableCell::new("Header 2").bold().background_color("4F81BD"),
TableCell::new("Header 3").bold().background_color("8064A2"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Bold Cell").bold(),
TableCell::new("Normal Cell"),
TableCell::new("Colored").background_color("9BBB59"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Red BG").background_color("C0504D"),
TableCell::new("Green BG").background_color("9BBB59"),
TableCell::new("Blue BG").background_color("4F81BD"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Row 3 Col 1"),
TableCell::new("Row 3 Col 2"),
TableCell::new("Row 3 Col 3")
.bold()
.background_color("F79646"),
]))
.position(500000, 1800000)
.build();
slides.push(
SlideContent::new("Table with Cell Styling")
.table(styled_table)
.title_color("1F497D"),
);
println!("📈 Slide 8: Chart Types");
let _bar_chart = ChartBuilder::new("Sales by Region", ChartType::Bar)
.categories(vec!["North", "South", "East", "West"])
.add_series(ChartSeries::new("2023", vec![100.0, 80.0, 120.0, 90.0]))
.add_series(ChartSeries::new("2024", vec![120.0, 95.0, 140.0, 110.0]))
.build();
let _line_chart = ChartBuilder::new("Monthly Trend", ChartType::Line)
.categories(vec!["Jan", "Feb", "Mar", "Apr", "May", "Jun"])
.add_series(ChartSeries::new(
"Revenue",
vec![10.0, 12.0, 15.0, 14.0, 18.0, 22.0],
))
.build();
let _pie_chart = ChartBuilder::new("Market Share", ChartType::Pie)
.categories(vec!["Product A", "Product B", "Product C", "Others"])
.add_series(ChartSeries::new("Share", vec![40.0, 30.0, 20.0, 10.0]))
.build();
slides.push(
SlideContent::new("Chart Types: Bar, Line, Pie")
.with_chart()
.title_color("1F497D")
.add_bullet("Bar Chart: Compare categories")
.add_bullet("Line Chart: Show trends over time")
.add_bullet("Pie Chart: Show proportions")
.content_size(24),
);
println!("🔷 Slide 9: Shapes with Fills");
let rect_shape = rect(0.5, 1.75, 2.2, 1.1)
.fill(hex("4F81BD"))
.text("Rectangle");
let ellipse_shape = ellipse(3.3, 1.75, 2.2, 1.1)
.fill(hex("9BBB59"))
.text("Ellipse");
let rounded = rounded_rect(6.0, 1.75, 2.2, 1.1)
.fill(hex("C0504D"))
.text("Rounded");
let triangle_shape = triangle(1.6, 3.3, 1.6, 1.3)
.fill(hex("8064A2"))
.text("Triangle");
let diamond_shape = diamond(4.4, 3.3, 1.6, 1.3)
.fill(hex("F79646"))
.text("Diamond");
slides.push(
SlideContent::new("Shape Types with Color Fills")
.add_shape(rect_shape)
.add_shape(ellipse_shape)
.add_shape(rounded)
.add_shape(triangle_shape)
.add_shape(diamond_shape)
.title_color("1F497D"),
);
println!("🌈 Slide 10: Gradient Fills");
let gradient_h = rect(0.5, 1.75, 2.7, 1.3)
.with_gradient(GradientFill::linear(
"1565C0",
"42A5F5",
GradientDirection::Horizontal,
))
.text("Horizontal");
let gradient_v = rect(3.5, 1.75, 2.7, 1.3)
.with_gradient(GradientFill::linear(
"2E7D32",
"81C784",
GradientDirection::Vertical,
))
.text("Vertical");
let gradient_d = rounded_rect(6.5, 1.75, 2.7, 1.3)
.with_gradient(GradientFill::linear(
"C62828",
"EF9A9A",
GradientDirection::DiagonalDown,
))
.text("Diagonal");
let gradient_3 = ellipse(2.0, 3.5, 2.7, 1.3)
.with_gradient(GradientFill::three_color(
"FF6F00",
"FFC107",
"FFEB3B",
GradientDirection::Horizontal,
))
.text("3-Color");
let gradient_angle = rounded_rect(5.2, 3.5, 2.7, 1.3)
.with_gradient(GradientFill::linear(
"7B1FA2",
"E1BEE7",
GradientDirection::Angle(135),
))
.text("135° Angle");
slides.push(
SlideContent::new("Gradient Fills - Multiple Directions")
.add_shape(gradient_h)
.add_shape(gradient_v)
.add_shape(gradient_d)
.add_shape(gradient_3)
.add_shape(gradient_angle)
.title_color("1F497D"),
);
println!("👻 Slide 11: Transparency Effects");
let base = rect(1.1, 2.0, 3.3, 2.2)
.fill(hex("1565C0"))
.text("Base (100%)");
let trans_25 = rect(2.2, 2.4, 2.7, 1.6)
.fill(ColorValue::from_hex("F44336").transparent(25).to_color())
.stroke(hex("B71C1C"), 2.0)
.text("25% Transparent");
let trans_50 = ellipse(4.9, 2.0, 2.7, 2.2)
.fill(ColorValue::from_hex("4CAF50").transparent(50).to_color())
.stroke(hex("1B5E20"), 2.0)
.text("50% Transparent");
let trans_75 = rounded_rect(6.0, 2.7, 2.7, 1.6)
.fill(ColorValue::from_hex("FF9800").transparent(75).to_color())
.stroke(hex("E65100"), 2.0)
.text("75% Transparent");
slides.push(
SlideContent::new("Transparency Effects - Overlapping Shapes")
.add_shape(base)
.add_shape(trans_25)
.add_shape(trans_50)
.add_shape(trans_75)
.title_color("1F497D"),
);
println!("🔗 Slide 12: Styled Connectors");
let box1 = rounded_rect(0.5, 2.0, 2.0, 0.9)
.with_id(100)
.fill(hex("1565C0"))
.text("Start");
let box2 = rounded_rect(3.8, 2.0, 2.0, 0.9)
.with_id(101)
.fill(hex("2E7D32"))
.text("Process");
let box3 = rounded_rect(7.1, 2.0, 2.0, 0.9)
.with_id(102)
.fill(hex("C62828"))
.text("End");
let conn1 = Connector::straight(2300000, 2200000, 3500000, 2200000)
.with_line(ConnectorLine::new("1565C0", 25400))
.with_end_arrow(ArrowType::Triangle)
.with_arrow_size(ArrowSize::Large);
let conn2 = Connector::elbow(5300000, 2200000, 6500000, 2200000)
.with_line(ConnectorLine::new("2E7D32", 38100).with_dash(LineDash::Dash))
.with_end_arrow(ArrowType::Stealth)
.with_arrow_size(ArrowSize::Medium);
let box4 = ellipse(1.1, 3.5, 1.6, 0.9)
.with_id(103)
.fill(hex("7B1FA2"))
.text("A");
let box5 = ellipse(4.4, 3.5, 1.6, 0.9)
.with_id(104)
.fill(hex("00838F"))
.text("B");
let box6 = ellipse(7.7, 3.5, 1.6, 0.9)
.with_id(105)
.fill(hex("EF6C00"))
.text("C");
let conn3 = Connector::curved(2500000, 3600000, 4000000, 3600000)
.with_line(ConnectorLine::new("7B1FA2", 19050).with_dash(LineDash::DashDot))
.with_arrows(ArrowType::Oval, ArrowType::Diamond);
let conn4 = Connector::straight(5500000, 3600000, 7000000, 3600000)
.with_line(ConnectorLine::new("00838F", 12700).with_dash(LineDash::Dot))
.with_end_arrow(ArrowType::Open);
slides.push(
SlideContent::new("Styled Connectors - Types, Arrows, Dashes")
.add_shape(box1)
.add_shape(box2)
.add_shape(box3)
.add_shape(box4)
.add_shape(box5)
.add_shape(box6)
.add_connector(conn1)
.add_connector(conn2)
.add_connector(conn3)
.add_connector(conn4)
.title_color("1F497D"),
);
println!("🖼️ Slide 13: Images with Shadow Effects");
let stock_photos = load_stock_photos();
let photo_count = stock_photos.len();
let photo1 = &stock_photos[0 % photo_count];
let photo2 = &stock_photos[1 % photo_count];
let photo3 = &stock_photos[2 % photo_count];
let img1_shadow = ImageBuilder::auto(photo1.0.clone())
.size(inches(2.2), inches(2.2))
.at(inches(0.5), inches(1.6))
.shadow()
.build();
let img2_shadow = ImageBuilder::auto(photo2.0.clone())
.size(inches(2.7), inches(2.0))
.at(inches(3.5), inches(1.6))
.shadow()
.build();
let img3_shadow = ImageBuilder::auto(photo3.0.clone())
.size(inches(2.5), inches(2.0))
.at(inches(6.8), inches(1.6))
.shadow()
.build();
slides.push(
SlideContent::new("Image Effects: Shadow (Outer Shadow)")
.add_image(img1_shadow)
.add_image(img2_shadow)
.add_image(img3_shadow)
.title_color("1F497D"),
);
println!("🖼️ Slide 14: Images with Reflection Effects");
let img1_reflection = ImageBuilder::auto(photo1.0.clone())
.size(inches(2.4), inches(2.4))
.at(inches(0.9), inches(1.3))
.reflection()
.build();
let img2_reflection = ImageBuilder::auto(photo2.0.clone())
.size(inches(3.1), inches(2.2))
.at(inches(3.8), inches(1.3))
.reflection()
.build();
let img3_reflection = ImageBuilder::auto(photo3.0.clone())
.size(inches(2.6), inches(2.2))
.at(inches(7.1), inches(1.3))
.reflection()
.build();
slides.push(
SlideContent::new("Image Effects: Reflection (Mirror Effect)")
.add_image(img1_reflection)
.add_image(img2_reflection)
.add_image(img3_reflection)
.title_color("2E75B5"),
);
println!("🖼️ Slide 15: Images with Cropping");
let img1_crop = ImageBuilder::auto(photo1.0.clone())
.size(inches(2.0), inches(2.0))
.at(inches(1.3), inches(2.0))
.crop(0.1, 0.1, 0.1, 0.1)
.build();
let img2_crop = ImageBuilder::auto(photo2.0.clone())
.size(inches(3.8), inches(1.6))
.at(inches(3.8), inches(2.0))
.crop(0.0, 0.2, 0.0, 0.2)
.build();
let img3_crop = ImageBuilder::auto(photo3.0.clone())
.size(inches(2.2), inches(2.2))
.at(inches(7.9), inches(2.0))
.crop(0.15, 0.0, 0.15, 0.0)
.build();
slides.push(
SlideContent::new("Image Cropping: All Sides, Top/Bottom, Left/Right")
.add_image(img1_crop)
.add_image(img2_crop)
.add_image(img3_crop)
.title_color("70AD47"),
);
println!("🖼️ Slide 16: Images with Glow Effects");
let img1_glow = ImageBuilder::auto(photo1.0.clone())
.size(inches(2.4), inches(2.4))
.at(inches(1.0), inches(1.5))
.glow()
.build();
let img2_glow = ImageBuilder::auto(photo2.0.clone())
.size(inches(2.9), inches(2.1))
.at(inches(4.0), inches(1.5))
.glow()
.build();
let img3_glow = ImageBuilder::auto(photo3.0.clone())
.size(inches(2.5), inches(2.1))
.at(inches(7.2), inches(1.5))
.glow()
.build();
slides.push(
SlideContent::new("Image Effects: Glow (Golden Aura)")
.add_image(img1_glow)
.add_image(img2_glow)
.add_image(img3_glow)
.title_color("C55A11"),
);
println!("🖼️ Slide 17: Images with Soft Edges");
let img1_soft = ImageBuilder::auto(photo1.0.clone())
.size(inches(2.4), inches(2.4))
.at(inches(1.0), inches(1.5))
.soft_edges()
.build();
let img2_soft = ImageBuilder::auto(photo2.0.clone())
.size(inches(2.9), inches(2.1))
.at(inches(4.0), inches(1.5))
.soft_edges()
.build();
let img3_soft = ImageBuilder::auto(photo3.0.clone())
.size(inches(2.5), inches(2.1))
.at(inches(7.2), inches(1.5))
.soft_edges()
.build();
slides.push(
SlideContent::new("Image Effects: Soft Edges (Feathered)")
.add_image(img1_soft)
.add_image(img2_soft)
.add_image(img3_soft)
.title_color("9B59B6"),
);
println!("🖼️ Slide 18: Images with Inner Shadow");
let img1_inner = ImageBuilder::auto(photo1.0.clone())
.size(inches(2.4), inches(2.4))
.at(inches(1.0), inches(1.5))
.inner_shadow()
.build();
let img2_inner = ImageBuilder::auto(photo2.0.clone())
.size(inches(2.9), inches(2.1))
.at(inches(4.0), inches(1.5))
.inner_shadow()
.build();
let img3_inner = ImageBuilder::auto(photo3.0.clone())
.size(inches(2.5), inches(2.1))
.at(inches(7.2), inches(1.5))
.inner_shadow()
.build();
slides.push(
SlideContent::new("Image Effects: Inner Shadow (Depth)")
.add_image(img1_inner)
.add_image(img2_inner)
.add_image(img3_inner)
.title_color("E74C3C"),
);
println!("🖼️ Slide 19: Images with Blur Effect");
let img1_blur = ImageBuilder::auto(photo1.0.clone())
.size(inches(2.4), inches(2.4))
.at(inches(1.0), inches(1.5))
.blur()
.build();
let img2_blur = ImageBuilder::auto(photo2.0.clone())
.size(inches(2.9), inches(2.1))
.at(inches(4.0), inches(1.5))
.blur()
.build();
let img3_blur = ImageBuilder::auto(photo3.0.clone())
.size(inches(2.5), inches(2.1))
.at(inches(7.2), inches(1.5))
.blur()
.build();
slides.push(
SlideContent::new("Image Effects: Blur (Artistic)")
.add_image(img1_blur)
.add_image(img2_blur)
.add_image(img3_blur)
.title_color("3498DB"),
);
println!("🖼️ Slide 20: Images with Combined Effects");
let img1_combined = ImageBuilder::auto(photo1.0.clone())
.size(inches(2.4), inches(2.4))
.at(inches(1.0), inches(1.5))
.shadow()
.reflection()
.build();
let img2_combined = ImageBuilder::auto(photo2.0.clone())
.size(inches(2.9), inches(2.1))
.at(inches(4.0), inches(1.5))
.shadow()
.reflection()
.build();
let img3_combined = ImageBuilder::auto(photo3.0.clone())
.size(inches(2.5), inches(2.1))
.at(inches(7.2), inches(1.5))
.shadow()
.reflection()
.build();
slides.push(
SlideContent::new("Combined Effects: Shadow + Reflection")
.add_image(img1_combined)
.add_image(img2_combined)
.add_image(img3_combined)
.title_color("16A085"),
);
println!("📊 Slide 11: Advanced Table (borders, alignment, merged cells)");
let advanced_table = TableBuilder::new(vec![2000000, 2000000, 2000000, 2000000])
.add_row(TableRow::new(vec![
TableCell::new("Q1 2024 Financial Report")
.bold()
.background_color("1F4E79")
.text_color("FFFFFF")
.align_center()
.font_size(14),
TableCell::new("").background_color("1F4E79"),
TableCell::new("").background_color("1F4E79"),
TableCell::new("").background_color("1F4E79"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Category")
.bold()
.background_color("2E75B6")
.text_color("FFFFFF")
.align_center(),
TableCell::new("Revenue")
.bold()
.background_color("2E75B6")
.text_color("FFFFFF")
.align_center(),
TableCell::new("Expenses")
.bold()
.background_color("2E75B6")
.text_color("FFFFFF")
.align_center(),
TableCell::new("Profit")
.bold()
.background_color("2E75B6")
.text_color("FFFFFF")
.align_center(),
]))
.add_row(TableRow::new(vec![
TableCell::new("Product Sales")
.text_color("000000")
.align_left(),
TableCell::new("$1,250,000")
.text_color("2E7D32")
.align_right(),
TableCell::new("$450,000")
.text_color("C62828")
.align_right(),
TableCell::new("$800,000")
.bold()
.text_color("2E7D32")
.align_right(),
]))
.add_row(TableRow::new(vec![
TableCell::new("Services").text_color("000000").align_left(),
TableCell::new("$890,000")
.text_color("2E7D32")
.align_right(),
TableCell::new("$320,000")
.text_color("C62828")
.align_right(),
TableCell::new("$570,000")
.bold()
.text_color("2E7D32")
.align_right(),
]))
.add_row(TableRow::new(vec![
TableCell::new("Total")
.bold()
.background_color("E7E6E6")
.text_color("000000")
.align_left(),
TableCell::new("$2,140,000")
.bold()
.background_color("E7E6E6")
.text_color("000000")
.align_right(),
TableCell::new("$770,000")
.bold()
.background_color("E7E6E6")
.text_color("000000")
.align_right(),
TableCell::new("$1,370,000")
.bold()
.background_color("C6EFCE")
.text_color("006100")
.align_right(),
]))
.position(300000, 1600000)
.build();
slides.push(
SlideContent::new("Financial Report - Advanced Table")
.table(advanced_table)
.title_color("1F4E79")
.title_bold(true),
);
println!("📊 Slide 12: Comparison Matrix Table");
let comparison_table = TableBuilder::new(vec![2000000, 1500000, 1500000, 1500000])
.add_row(TableRow::new(vec![
TableCell::new("Feature")
.bold()
.background_color("4472C4")
.text_color("FFFFFF"),
TableCell::new("Basic")
.bold()
.background_color("4472C4")
.text_color("FFFFFF"),
TableCell::new("Pro")
.bold()
.background_color("4472C4")
.text_color("FFFFFF"),
TableCell::new("Enterprise")
.bold()
.background_color("4472C4")
.text_color("FFFFFF"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Storage").text_color("000000"),
TableCell::new("5 GB").text_color("000000"),
TableCell::new("50 GB").text_color("000000"),
TableCell::new("Unlimited").bold().text_color("2E7D32"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Users").text_color("000000"),
TableCell::new("1").text_color("000000"),
TableCell::new("10").text_color("000000"),
TableCell::new("Unlimited").bold().text_color("2E7D32"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Support").text_color("000000"),
TableCell::new("Email").text_color("000000"),
TableCell::new("24/7 Chat").text_color("000000"),
TableCell::new("Dedicated").bold().text_color("2E7D32"),
]))
.add_row(TableRow::new(vec![
TableCell::new("API Access").text_color("000000"),
TableCell::new("No").text_color("C62828"),
TableCell::new("Yes").text_color("2E7D32"),
TableCell::new("Yes + Priority").bold().text_color("2E7D32"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Price/month")
.bold()
.background_color("F2F2F2")
.text_color("000000"),
TableCell::new("$9")
.bold()
.background_color("F2F2F2")
.text_color("000000"),
TableCell::new("$29")
.bold()
.background_color("F2F2F2")
.text_color("000000"),
TableCell::new("$99")
.bold()
.background_color("F2F2F2")
.text_color("000000"),
]))
.position(500000, 1600000)
.build();
slides.push(
SlideContent::new("Pricing Comparison Matrix")
.table(comparison_table)
.title_color("4472C4")
.title_bold(true),
);
println!("🔷 Slide 13: Process Flow (SmartArt-style)");
let step1 = rounded_rect(0.3, 2.2, 1.5, 0.9)
.fill(hex("4472C4"))
.text("1. Research");
let arrow1 = shapes::arrow_right(2.0, 2.4, 0.4, 0.4).fill(hex("A5A5A5"));
let step2 = rounded_rect(2.5, 2.2, 1.5, 0.9)
.fill(hex("ED7D31"))
.text("2. Design");
let arrow2 = shapes::arrow_right(4.2, 2.4, 0.4, 0.4).fill(hex("A5A5A5"));
let step3 = rounded_rect(4.7, 2.2, 1.5, 0.9)
.fill(hex("70AD47"))
.text("3. Develop");
let arrow3 = shapes::arrow_right(6.3, 2.4, 0.4, 0.4).fill(hex("A5A5A5"));
let step4 = rounded_rect(6.9, 2.2, 1.5, 0.9)
.fill(hex("5B9BD5"))
.text("4. Deploy");
slides.push(
SlideContent::new("Development Process Flow")
.add_shape(step1)
.add_shape(arrow1)
.add_shape(step2)
.add_shape(arrow2)
.add_shape(step3)
.add_shape(arrow3)
.add_shape(step4)
.title_color("1F497D")
.title_bold(true),
);
println!("🔷 Slide 14: Organization Chart");
let ceo = rounded_rect(3.8, 1.5, 2.2, 0.7)
.fill(hex("1F4E79"))
.text("CEO");
let line1 = rect(4.9, 2.2, 0.1, 0.4).fill(hex("A5A5A5"));
let hline = rect(2.1, 2.6, 5.6, 0.05).fill(hex("A5A5A5"));
let cto = rounded_rect(1.1, 2.8, 2.0, 0.5)
.fill(hex("2E75B6"))
.text("CTO");
let cfo = rounded_rect(3.9, 2.8, 2.0, 0.5)
.fill(hex("2E75B6"))
.text("CFO");
let coo = rounded_rect(6.8, 2.8, 2.0, 0.5)
.fill(hex("2E75B6"))
.text("COO");
let vline1 = rect(2.0, 2.7, 0.05, 0.16).fill(hex("A5A5A5"));
let vline2 = rect(4.9, 2.7, 0.05, 0.16).fill(hex("A5A5A5"));
let vline3 = rect(7.7, 2.7, 0.05, 0.16).fill(hex("A5A5A5"));
let eng = rect(0.5, 3.6, 1.3, 0.4)
.fill(hex("BDD7EE"))
.text("Engineering");
let product = rect(2.0, 3.6, 1.3, 0.4).fill(hex("BDD7EE")).text("Product");
slides.push(
SlideContent::new("Organization Structure")
.add_shape(ceo)
.add_shape(line1)
.add_shape(hline)
.add_shape(cto)
.add_shape(cfo)
.add_shape(coo)
.add_shape(vline1)
.add_shape(vline2)
.add_shape(vline3)
.add_shape(eng)
.add_shape(product)
.title_color("1F4E79")
.title_bold(true),
);
println!("🔷 Slide 15: PDCA Cycle Diagram");
let plan = rounded_rect(1.6, 1.75, 2.7, 1.6)
.fill(hex("4472C4"))
.text("PLAN\n\nDefine goals\nand strategy");
let do_box = rounded_rect(4.9, 1.75, 2.7, 1.6)
.fill(hex("ED7D31"))
.text("DO\n\nImplement\nthe plan");
let check = rounded_rect(4.9, 3.6, 2.7, 1.6)
.fill(hex("70AD47"))
.text("CHECK\n\nMeasure\nresults");
let act = rounded_rect(1.6, 3.6, 2.7, 1.6)
.fill(hex("FFC000"))
.text("ACT\n\nAdjust and\nimprove");
let arr1 = shapes::arrow_right(4.5, 2.3, 0.3, 0.3).fill(hex("A5A5A5"));
let arr2 = shapes::arrow_down(6.1, 3.5, 0.3, 0.2).fill(hex("A5A5A5"));
let arr3 = shapes::arrow_left(4.5, 4.2, 0.3, 0.3).fill(hex("A5A5A5"));
let arr4 = shapes::arrow_up(2.8, 3.5, 0.3, 0.2).fill(hex("A5A5A5"));
slides.push(
SlideContent::new("PDCA Continuous Improvement Cycle")
.add_shape(plan)
.add_shape(do_box)
.add_shape(check)
.add_shape(act)
.add_shape(arr1)
.add_shape(arr2)
.add_shape(arr3)
.add_shape(arr4)
.title_color("1F497D")
.title_bold(true),
);
println!("🔷 Slide 16: Pyramid Diagram");
let level5 = shapes::dim(
ShapeType::Trapezoid,
Dimension::Inches(0.5),
Dimension::Inches(4.4),
Dimension::Inches(8.7),
Dimension::Inches(0.7),
)
.fill(hex("C00000"))
.text("Physiological Needs - Food, Water, Shelter");
let level4 = shapes::dim(
ShapeType::Trapezoid,
Dimension::Inches(1.1),
Dimension::Inches(3.7),
Dimension::Inches(7.7),
Dimension::Inches(0.7),
)
.fill(hex("ED7D31"))
.text("Safety Needs - Security, Stability");
let level3 = shapes::dim(
ShapeType::Trapezoid,
Dimension::Inches(1.6),
Dimension::Inches(3.1),
Dimension::Inches(6.6),
Dimension::Inches(0.7),
)
.fill(hex("FFC000"))
.text("Love & Belonging - Relationships");
let level2 = shapes::dim(
ShapeType::Trapezoid,
Dimension::Inches(2.2),
Dimension::Inches(2.4),
Dimension::Inches(5.5),
Dimension::Inches(0.7),
)
.fill(hex("70AD47"))
.text("Esteem - Achievement, Respect");
let level1 = triangle(2.7, 1.6, 4.4, 0.8)
.fill(hex("4472C4"))
.text("Self-Actualization");
slides.push(
SlideContent::new("Maslow's Hierarchy of Needs")
.add_shape(level5)
.add_shape(level4)
.add_shape(level3)
.add_shape(level2)
.add_shape(level1)
.title_color("1F497D")
.title_bold(true),
);
println!("🔷 Slide 17: Venn Diagram");
let circle1 = circle(1.6, 2.0, 3.3).fill(hex("4472C4")).text("Skills");
let circle2 = circle(3.8, 2.0, 3.3).fill(hex("ED7D31")).text("Passion");
let circle3 = circle(2.7, 3.5, 3.3)
.fill(hex("70AD47"))
.text("Market Need");
let center = ellipse(3.5, 3.1, 1.75, 0.9)
.fill(hex("FFFFFF"))
.text("IKIGAI");
slides.push(
SlideContent::new("Finding Your Ikigai - Venn Diagram")
.add_shape(circle1)
.add_shape(circle2)
.add_shape(circle3)
.add_shape(center)
.title_color("1F497D")
.title_bold(true),
);
println!("📊 Slide 18: Project Timeline");
let timeline_table = TableBuilder::new(vec![1500000, 1500000, 1500000, 1500000, 1500000])
.add_row(TableRow::new(vec![
TableCell::new("Q1 2024")
.bold()
.background_color("4472C4")
.text_color("FFFFFF"),
TableCell::new("Q2 2024")
.bold()
.background_color("4472C4")
.text_color("FFFFFF"),
TableCell::new("Q3 2024")
.bold()
.background_color("4472C4")
.text_color("FFFFFF"),
TableCell::new("Q4 2024")
.bold()
.background_color("4472C4")
.text_color("FFFFFF"),
TableCell::new("Q1 2025")
.bold()
.background_color("4472C4")
.text_color("FFFFFF"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Research\n& Planning")
.background_color("BDD7EE")
.text_color("1F497D"),
TableCell::new("Design\nPhase")
.background_color("BDD7EE")
.text_color("1F497D"),
TableCell::new("Development\nSprint 1-3")
.background_color("C6EFCE")
.text_color("006100"),
TableCell::new("Testing\n& QA")
.background_color("FCE4D6")
.text_color("C65911"),
TableCell::new("Launch\n& Support")
.background_color("E2EFDA")
.text_color("375623"),
]))
.add_row(TableRow::new(vec![
TableCell::new("✓ Complete").bold().text_color("2E7D32"),
TableCell::new("✓ Complete").bold().text_color("2E7D32"),
TableCell::new("In Progress").text_color("ED7D31"),
TableCell::new("Planned").text_color("7F7F7F"),
TableCell::new("Planned").text_color("7F7F7F"),
]))
.position(300000, 2000000)
.build();
slides.push(
SlideContent::new("Project Roadmap 2024-2025")
.table(timeline_table)
.title_color("1F497D")
.title_bold(true),
);
println!("🔷 Slide 19: Dashboard with KPIs (Dimension API)");
let kpi1 = shapes::dim(
ShapeType::RoundedRectangle,
Dimension::percent(3.0),
Dimension::percent(23.0),
Dimension::percent(22.0),
Dimension::percent(18.0),
)
.fill(hex("4472C4"))
.text("Revenue\n\n$2.14M\n+15% YoY");
let kpi2 = shapes::dim(
ShapeType::RoundedRectangle,
Dimension::percent(27.0),
Dimension::percent(23.0),
Dimension::percent(22.0),
Dimension::percent(18.0),
)
.fill(hex("70AD47"))
.text("Customers\n\n12,450\n+22% YoY");
let kpi3 = shapes::dim(
ShapeType::RoundedRectangle,
Dimension::percent(51.0),
Dimension::percent(23.0),
Dimension::percent(22.0),
Dimension::percent(18.0),
)
.fill(hex("ED7D31"))
.text("NPS Score\n\n72\n+8 pts");
let kpi4 = shapes::dim(
ShapeType::RoundedRectangle,
Dimension::percent(75.0),
Dimension::percent(23.0),
Dimension::percent(22.0),
Dimension::percent(18.0),
)
.fill(hex("5B9BD5"))
.text("Retention\n\n94%\n+3% YoY");
let status1 = shapes::dim(
ShapeType::Ellipse,
Dimension::percent(14.0),
Dimension::percent(42.0),
Dimension::Inches(0.3),
Dimension::Inches(0.3),
)
.fill(hex("70AD47"));
let status2 = shapes::dim(
ShapeType::Ellipse,
Dimension::percent(38.0),
Dimension::percent(42.0),
Dimension::Inches(0.3),
Dimension::Inches(0.3),
)
.fill(hex("70AD47"));
let status3 = shapes::dim(
ShapeType::Ellipse,
Dimension::percent(62.0),
Dimension::percent(42.0),
Dimension::Inches(0.3),
Dimension::Inches(0.3),
)
.fill(hex("FFC000"));
let status4 = shapes::dim(
ShapeType::Ellipse,
Dimension::percent(86.0),
Dimension::percent(42.0),
Dimension::Inches(0.3),
Dimension::Inches(0.3),
)
.fill(hex("70AD47"));
slides.push(
SlideContent::new("Executive Dashboard - Q1 2024")
.add_shape(kpi1)
.add_shape(kpi2)
.add_shape(kpi3)
.add_shape(kpi4)
.add_shape(status1)
.add_shape(status2)
.add_shape(status3)
.add_shape(status4)
.title_color("1F497D")
.title_bold(true),
);
println!("📝 Slide 20: Summary with Speaker Notes");
slides.push(
SlideContent::new("Summary & Next Steps")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.add_bullet("Completed: Research, Design, Initial Development")
.add_bullet("In Progress: Sprint 3 Development")
.add_bullet("Next: QA Testing Phase (Q4 2024)")
.add_bullet("Launch Target: Q1 2025")
.add_bullet("Key Risks: Resource constraints, Timeline pressure")
.content_size(24)
.notes("Speaker Notes:\n\n1. Emphasize the progress made\n2. Highlight key achievements\n3. Address any concerns about timeline\n4. Open for Q&A")
);
println!("🔢 Slide 21: Bullet Styles (NEW)");
slides.push(
SlideContent::new("Bullet Styles - Numbered List")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.with_bullet_style(BulletStyle::Number)
.add_bullet("First numbered item")
.add_bullet("Second numbered item")
.add_bullet("Third numbered item")
.add_bullet("Fourth numbered item")
.content_size(28),
);
println!("🔤 Slide 22: Lettered Lists (NEW)");
slides.push(
SlideContent::new("Bullet Styles - Lettered Lists")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.add_lettered("Option A - First choice")
.add_lettered("Option B - Second choice")
.add_lettered("Option C - Third choice")
.add_lettered("Option D - Fourth choice")
.content_size(28),
);
println!("🏛️ Slide 23: Roman Numerals (NEW)");
slides.push(
SlideContent::new("Bullet Styles - Roman Numerals")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.with_bullet_style(BulletStyle::RomanUpper)
.add_bullet("Chapter I - Introduction")
.add_bullet("Chapter II - Background")
.add_bullet("Chapter III - Methodology")
.add_bullet("Chapter IV - Results")
.add_bullet("Chapter V - Conclusion")
.content_size(28),
);
println!("⭐ Slide 24: Custom Bullets (NEW)");
slides.push(
SlideContent::new("Bullet Styles - Custom Characters")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.add_styled_bullet("Star bullet point", BulletStyle::Custom('★'))
.add_styled_bullet("Arrow bullet point", BulletStyle::Custom('→'))
.add_styled_bullet("Check bullet point", BulletStyle::Custom('✓'))
.add_styled_bullet("Diamond bullet point", BulletStyle::Custom('◆'))
.add_styled_bullet("Heart bullet point", BulletStyle::Custom('♥'))
.content_size(28),
);
println!("📊 Slide 25: Sub-bullets Hierarchy (NEW)");
slides.push(
SlideContent::new("Bullet Styles - Hierarchical Lists")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.add_bullet("Main Topic 1")
.add_sub_bullet("Supporting detail A")
.add_sub_bullet("Supporting detail B")
.add_bullet("Main Topic 2")
.add_sub_bullet("Supporting detail C")
.add_sub_bullet("Supporting detail D")
.add_bullet("Main Topic 3")
.content_size(24),
);
println!("✏️ Slide 26: Text Enhancements (NEW)");
let strikethrough_bullet =
BulletPoint::new("Strikethrough: This text is crossed out").strikethrough();
let highlight_bullet =
BulletPoint::new("Highlight: Yellow background for emphasis").highlight("FFFF00");
let subscript_bullet = BulletPoint::new("Subscript: H₂O - for chemical formulas").subscript();
let superscript_bullet =
BulletPoint::new("Superscript: x² - for math expressions").superscript();
let bold_colored = BulletPoint::new("Combined: Bold + Red color")
.bold()
.color("FF0000");
let mut text_enhancements_slide = SlideContent::new("Text Enhancements - New Formatting")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.content_size(24);
text_enhancements_slide.bullets.push(strikethrough_bullet);
text_enhancements_slide.bullets.push(highlight_bullet);
text_enhancements_slide.bullets.push(subscript_bullet);
text_enhancements_slide.bullets.push(superscript_bullet);
text_enhancements_slide.bullets.push(bold_colored);
slides.push(text_enhancements_slide);
println!("🔤 Slide 27: Font Size Presets (NEW)");
let large_bullet = BulletPoint::new(&format!(
"LARGE: {}pt - Extra large text",
font_sizes::LARGE
))
.font_size(font_sizes::LARGE);
let heading_bullet = BulletPoint::new(&format!(
"HEADING: {}pt - Section headers",
font_sizes::HEADING
))
.font_size(font_sizes::HEADING);
let body_bullet = BulletPoint::new(&format!("BODY: {}pt - Regular content", font_sizes::BODY))
.font_size(font_sizes::BODY);
let small_bullet = BulletPoint::new(&format!("SMALL: {}pt - Smaller text", font_sizes::SMALL))
.font_size(font_sizes::SMALL);
let caption_bullet = BulletPoint::new(&format!(
"CAPTION: {}pt - Captions and notes",
font_sizes::CAPTION
))
.font_size(font_sizes::CAPTION);
let mut font_size_slide = SlideContent::new("Font Size Presets - Each line different size")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.title_size(font_sizes::TITLE);
font_size_slide.bullets.push(large_bullet);
font_size_slide.bullets.push(heading_bullet);
font_size_slide.bullets.push(body_bullet);
font_size_slide.bullets.push(small_bullet);
font_size_slide.bullets.push(caption_bullet);
slides.push(font_size_slide);
println!("🎨 Slide 28: Theme Colors (NEW)");
let corporate_shape = rect(0.5, 1.75, 2.0, 0.9)
.fill(hex(themes::CORPORATE.primary))
.text("Corporate");
let modern_shape = rect(2.7, 1.75, 2.0, 0.9)
.fill(hex(themes::MODERN.primary))
.text("Modern");
let vibrant_shape = rect(4.9, 1.75, 2.0, 0.9)
.fill(hex(themes::VIBRANT.primary))
.text("Vibrant");
let dark_shape = rect(7.1, 1.75, 2.0, 0.9)
.fill(hex(themes::DARK.primary))
.text("Dark");
let nature_shape = rect(0.5, 3.0, 2.0, 0.9)
.fill(hex(themes::NATURE.primary))
.text("Nature");
let tech_shape = rect(2.7, 3.0, 2.0, 0.9)
.fill(hex(themes::TECH.primary))
.text("Tech");
let carbon_shape = rect(4.9, 3.0, 2.0, 0.9)
.fill(hex(themes::CARBON.primary))
.text("Carbon");
slides.push(
SlideContent::new("Theme Color Palettes")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.add_shape(corporate_shape)
.add_shape(modern_shape)
.add_shape(vibrant_shape)
.add_shape(dark_shape)
.add_shape(nature_shape)
.add_shape(tech_shape)
.add_shape(carbon_shape),
);
println!("🌈 Slide 29: Material & Carbon Colors (NEW)");
let material_red = rect(0.5, 1.75, 1.3, 0.7)
.fill(hex(colors::MATERIAL_RED))
.text("M-Red");
let material_blue = rect(2.1, 1.75, 1.3, 0.7)
.fill(hex(colors::MATERIAL_BLUE))
.text("M-Blue");
let material_green = rect(3.6, 1.75, 1.3, 0.7)
.fill(hex(colors::MATERIAL_GREEN))
.text("M-Green");
let material_orange = rect(5.1, 1.75, 1.3, 0.7)
.fill(hex(colors::MATERIAL_ORANGE))
.text("M-Orange");
let material_purple = rect(6.7, 1.75, 1.3, 0.7)
.fill(hex(colors::MATERIAL_PURPLE))
.text("M-Purple");
let carbon_blue = rect(0.5, 2.7, 1.3, 0.7)
.fill(hex(colors::CARBON_BLUE_60))
.text("C-Blue");
let carbon_green = rect(2.1, 2.7, 1.3, 0.7)
.fill(hex(colors::CARBON_GREEN_50))
.text("C-Green");
let carbon_red = rect(3.6, 2.7, 1.3, 0.7)
.fill(hex(colors::CARBON_RED_60))
.text("C-Red");
let carbon_purple = rect(5.1, 2.7, 1.3, 0.7)
.fill(hex(colors::CARBON_PURPLE_60))
.text("C-Purple");
let carbon_gray = rect(6.7, 2.7, 1.3, 0.7)
.fill(hex(colors::CARBON_GRAY_100))
.text("C-Gray");
slides.push(
SlideContent::new("Material & Carbon Design Colors")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.add_shape(material_red)
.add_shape(material_blue)
.add_shape(material_green)
.add_shape(material_orange)
.add_shape(material_purple)
.add_shape(carbon_blue)
.add_shape(carbon_green)
.add_shape(carbon_red)
.add_shape(carbon_purple)
.add_shape(carbon_gray),
);
println!("🖼️ Slide 30: Image from Base64 (NEW)");
let _red_pixel_base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==";
let _base64_image = ImageBuilder::from_base64(_red_pixel_base64, 914400, 914400, "PNG")
.position(4000000, 2500000)
.build();
slides.push(
SlideContent::new("Image Loading - New Methods")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.add_bullet("Image::new(path) - Load from file path")
.add_bullet("Image::from_base64(data) - Load from base64 string")
.add_bullet("Image::from_bytes(data) - Load from raw bytes")
.add_bullet("ImageBuilder for fluent API configuration")
.add_bullet("Built-in base64 decoder (no external deps)")
.content_size(24),
);
println!("📋 Slide 31: v0.2.1 Feature Summary (NEW)");
slides.push(
SlideContent::new("New Features in v0.2.1")
.layout(SlideLayout::TitleAndContent)
.title_color("1F497D")
.title_bold(true)
.add_numbered("BulletStyle: Number, Letter, Roman, Custom")
.add_numbered("TextFormat: Strikethrough, Highlight")
.add_numbered("TextFormat: Subscript, Superscript")
.add_numbered("Font size presets in prelude")
.add_numbered("Image::from_base64 and from_bytes")
.add_numbered("Theme color palettes (7 themes)")
.add_numbered("Material & Carbon Design colors")
.content_size(24),
);
println!("🎬 Slide 34: Slide Show Settings (Visual)");
let show_speaker = SlideShowSettings::new().pen_color(PenColor::red());
let show_kiosk = SlideShowSettings::kiosk();
let _show_range = SlideShowSettings::new()
.show_type(ShowType::Browsed)
.slide_range(SlideRange::Range { start: 1, end: 10 })
.without_animation(true);
let _speaker_xml = show_speaker.to_xml();
let _kiosk_xml = show_kiosk.to_xml();
let show_table = TableBuilder::new(vec![2000000, 2000000, 2000000, 2000000])
.add_row(TableRow::new(vec![
TableCell::new("Setting")
.bold()
.background_color("1F4E79")
.text_color("FFFFFF"),
TableCell::new("Speaker")
.bold()
.background_color("4472C4")
.text_color("FFFFFF"),
TableCell::new("Kiosk")
.bold()
.background_color("ED7D31")
.text_color("FFFFFF"),
TableCell::new("Browsed")
.bold()
.background_color("70AD47")
.text_color("FFFFFF"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Loop").bold().background_color("D6E4F0"),
TableCell::new("No"),
TableCell::new("Yes").bold().text_color("2E7D32"),
TableCell::new("No"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Narration")
.bold()
.background_color("D6E4F0"),
TableCell::new("Yes"),
TableCell::new("No").text_color("C62828"),
TableCell::new("Yes"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Animation")
.bold()
.background_color("D6E4F0"),
TableCell::new("Yes"),
TableCell::new("Yes"),
TableCell::new("No").text_color("C62828"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Timings").bold().background_color("D6E4F0"),
TableCell::new("Yes"),
TableCell::new("Auto"),
TableCell::new("Yes"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Slide Range")
.bold()
.background_color("D6E4F0"),
TableCell::new("All"),
TableCell::new("All"),
TableCell::new("1-10"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Pen Color")
.bold()
.background_color("D6E4F0"),
TableCell::new("Red").text_color("FF0000"),
TableCell::new("Red").text_color("FF0000"),
TableCell::new("Red").text_color("FF0000"),
]))
.position(300000, 1600000)
.build();
let icon_speaker = rounded_rect(0.3, 4.6, 2.7, 0.7)
.fill(hex("4472C4"))
.text("Speaker: Full control");
let icon_kiosk = rounded_rect(3.4, 4.6, 2.7, 0.7)
.fill(hex("ED7D31"))
.text("Kiosk: Auto-loop");
let icon_browsed = rounded_rect(6.5, 4.6, 2.7, 0.7)
.fill(hex("70AD47"))
.text("Browsed: Scrollbar");
slides.push(
SlideContent::new("Slide Show Settings - Mode Comparison")
.table(show_table)
.add_shape(icon_speaker)
.add_shape(icon_kiosk)
.add_shape(icon_browsed)
.title_color("1F497D")
.title_bold(true),
);
println!("🖨️ Slide 35: Print Settings & Handouts (Visual)");
let print = PrintSettings::new()
.print_what(PrintWhat::Handouts)
.color_mode(PrintColorMode::Grayscale)
.handout_layout(GenHandoutLayout::SlidesPerPage6)
.frame_slides(true)
.header("Q1 2025 Strategy Review")
.footer("Confidential - Internal Use Only")
.print_date(true)
.print_page_numbers(true);
let _prnpr_xml = print.to_prnpr_xml();
let _handout_xml = print.to_handout_master_xml();
let hdr = rect(0.3, 1.6, 4.6, 0.3)
.fill(hex("E7E6E6"))
.text("Q1 2025 Strategy Review");
let s1 = rect(0.4, 2.2, 2.0, 1.2)
.stroke(hex("999999"), 1.0)
.text("Slide 1");
let s2 = rect(2.7, 2.2, 2.0, 1.2)
.stroke(hex("999999"), 1.0)
.text("Slide 2");
let s3 = rect(0.4, 3.5, 2.0, 1.2)
.stroke(hex("999999"), 1.0)
.text("Slide 3");
let s4 = rect(2.7, 3.5, 2.0, 1.2)
.stroke(hex("999999"), 1.0)
.text("Slide 4");
let s5 = rect(0.4, 4.8, 2.0, 1.2)
.stroke(hex("999999"), 1.0)
.text("Slide 5");
let s6 = rect(2.7, 4.8, 2.0, 1.2)
.stroke(hex("999999"), 1.0)
.text("Slide 6");
let ftr = rect(0.3, 6.1, 4.6, 0.3)
.fill(hex("E7E6E6"))
.text("Confidential - Internal Use Only");
let print_table = TableBuilder::new(vec![1800000, 2000000])
.add_row(TableRow::new(vec![
TableCell::new("Print Settings")
.bold()
.background_color("1F4E79")
.text_color("FFFFFF"),
TableCell::new("").background_color("1F4E79"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Print What")
.bold()
.background_color("D6E4F0"),
TableCell::new("Handouts"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Color Mode")
.bold()
.background_color("D6E4F0"),
TableCell::new("Grayscale"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Layout").bold().background_color("D6E4F0"),
TableCell::new("6 slides/page"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Frame Slides")
.bold()
.background_color("D6E4F0"),
TableCell::new("Yes"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Date").bold().background_color("D6E4F0"),
TableCell::new("Yes"),
]))
.add_row(TableRow::new(vec![
TableCell::new("Page Numbers")
.bold()
.background_color("D6E4F0"),
TableCell::new("Yes"),
]))
.position(5000000, 1800000)
.build();
slides.push(
SlideContent::new("Print Handout - 6 Slides Per Page")
.table(print_table)
.add_shape(hdr)
.add_shape(s1)
.add_shape(s2)
.add_shape(s3)
.add_shape(s4)
.add_shape(s5)
.add_shape(s6)
.add_shape(ftr)
.title_color("1F497D")
.title_bold(true),
);
println!("📊 Slide 36: Advanced Table Merging (Visual)");
let mut merge_map = TableMergeMap::new(5, 4);
merge_map.merge_cells(0, 0, 1, 4).unwrap(); merge_map.merge_cells(1, 0, 2, 1).unwrap(); merge_map.merge_cells(3, 0, 2, 1).unwrap();
let state_00 = merge_map.cell_state(0, 0); let state_01 = merge_map.cell_state(0, 1); let state_10 = merge_map.cell_state(1, 0); let state_20 = merge_map.cell_state(2, 0); println!(" ├── (0,0): {}", state_00.to_xml_attrs().trim());
println!(" ├── (0,1): {}", state_01.to_xml_attrs().trim());
println!(" ├── (1,0): {}", state_10.to_xml_attrs().trim());
println!(" └── (2,0): {}", state_20.to_xml_attrs().trim());
let merge_table = TableBuilder::new(vec![1500000, 2000000, 2000000, 2000000])
.add_row(TableRow::new(vec![
TableCell::new("Q1 2025 Revenue Report")
.bold()
.background_color("1F4E79")
.text_color("FFFFFF")
.grid_span(4),
TableCell::new("").background_color("1F4E79").h_merge(),
TableCell::new("").background_color("1F4E79").h_merge(),
TableCell::new("").background_color("1F4E79").h_merge(),
]))
.add_row(TableRow::new(vec![
TableCell::new("Products")
.bold()
.background_color("BDD7EE")
.text_color("1F497D")
.row_span(2),
TableCell::new("Hardware").background_color("E2EFDA"),
TableCell::new("$450,000")
.text_color("2E7D32")
.align_right(),
TableCell::new("+12%")
.bold()
.text_color("2E7D32")
.align_right(),
]))
.add_row(TableRow::new(vec![
TableCell::new("").background_color("BDD7EE").v_merge(),
TableCell::new("Software").background_color("E2EFDA"),
TableCell::new("$680,000")
.text_color("2E7D32")
.align_right(),
TableCell::new("+25%")
.bold()
.text_color("2E7D32")
.align_right(),
]))
.add_row(TableRow::new(vec![
TableCell::new("Services")
.bold()
.background_color("FCE4D6")
.text_color("C65911")
.row_span(2),
TableCell::new("Consulting").background_color("FFF2CC"),
TableCell::new("$320,000")
.text_color("2E7D32")
.align_right(),
TableCell::new("+8%")
.bold()
.text_color("2E7D32")
.align_right(),
]))
.add_row(TableRow::new(vec![
TableCell::new("").background_color("FCE4D6").v_merge(),
TableCell::new("Support").background_color("FFF2CC"),
TableCell::new("$190,000")
.text_color("2E7D32")
.align_right(),
TableCell::new("+5%")
.bold()
.text_color("2E7D32")
.align_right(),
]))
.position(300000, 1600000)
.build();
let legend_anchor = rounded_rect(0.3, 4.8, 2.2, 0.4)
.fill(hex("4472C4"))
.text("Anchor (gridSpan/rowSpan)");
let legend_hmerge = rounded_rect(2.7, 4.8, 2.2, 0.4)
.fill(hex("ED7D31"))
.text("hMerge (col covered)");
let legend_vmerge = rounded_rect(5.1, 4.8, 2.2, 0.4)
.fill(hex("70AD47"))
.text("vMerge (row covered)");
let legend_normal = rounded_rect(7.5, 4.8, 2.2, 0.4)
.fill(hex("A5A5A5"))
.text("Normal (no merge)");
slides.push(
SlideContent::new("Advanced Table Merging - Merged Cells")
.table(merge_table)
.add_shape(legend_anchor)
.add_shape(legend_hmerge)
.add_shape(legend_vmerge)
.add_shape(legend_normal)
.title_color("1F497D")
.title_bold(true),
);
println!("\n⚙️ Building Presentation Settings...");
let show_settings = SlideShowSettings::new()
.show_type(ShowType::Speaker)
.pen_color(PenColor::red())
.use_timings(false);
println!(" ├── Slide Show: Speaker mode, red pen, timings enabled");
println!(" │ └── XML: {} bytes", show_settings.to_xml().len());
let print_settings = PrintSettings::new()
.print_what(PrintWhat::Handouts)
.color_mode(PrintColorMode::Grayscale)
.handout_layout(GenHandoutLayout::SlidesPerPage6)
.frame_slides(true)
.header("Q1 2025 Strategy Review")
.footer("Confidential - Internal Use Only")
.print_date(true)
.print_page_numbers(true);
println!(" └── Print: Handouts, 6/page, grayscale, framed");
println!(
" └── XML: {} bytes",
print_settings.to_prnpr_xml().len()
);
let pres_settings = PresentationSettings::new()
.slide_show(show_settings)
.print(print_settings);
println!(" All settings configured → presProps.xml");
println!("\n📦 Generating PPTX with integrated features...");
let slide_count = slides.len();
let pptx_data = create_pptx_with_settings(
"PPTX-RS Element Showcase",
&slides,
Some(pres_settings),
)?;
let output_path = project_path("comprehensive_demo.pptx");
fs::write(&output_path, &pptx_data)?;
println!(
" ✓ Created {} ({} slides, {} bytes)",
output_path.display(),
slide_count,
pptx_data.len()
);
println!("\n📖 Package Analysis (Read Capability):");
let package = Package::open(&output_path)?;
let paths = package.part_paths();
let slide_count = paths
.iter()
.filter(|p| p.starts_with("ppt/slides/slide") && p.ends_with(".xml"))
.count();
println!(" ├── Total parts: {}", package.part_count());
println!(" ├── Slides: {}", slide_count);
println!(" └── Package opened and analyzed successfully");
println!("\n🧩 Parts API Demonstration:");
println!(" ┌── SlideLayoutPart (11 layout types):");
let layouts = [
LayoutType::Title,
LayoutType::TitleAndContent,
LayoutType::SectionHeader,
LayoutType::TwoContent,
LayoutType::Comparison,
LayoutType::TitleOnly,
LayoutType::Blank,
LayoutType::ContentWithCaption,
LayoutType::PictureWithCaption,
LayoutType::TitleAndVerticalText,
LayoutType::VerticalTitleAndText,
];
for (i, layout_type) in layouts.iter().enumerate() {
let layout = SlideLayoutPart::new(i + 1, *layout_type);
if i < 3 {
println!(
" │ ├── {}: {} ({})",
i + 1,
layout_type.name(),
layout.path()
);
}
}
println!(" │ └── ... and {} more layout types", layouts.len() - 3);
println!(" ├── SlideMasterPart:");
let mut master = SlideMasterPart::new(1);
master.set_name("Custom Master");
master.add_layout_rel_id("rId2");
master.add_layout_rel_id("rId3");
println!(" │ ├── Name: {}", master.name());
println!(" │ ├── Path: {}", master.path());
println!(
" │ └── Layouts: {} linked",
master.layout_rel_ids().len()
);
println!(" ├── ThemePart (colors & fonts):");
let mut theme = ThemePart::new(1);
theme.set_name("Corporate Theme");
theme.set_major_font("Arial");
theme.set_minor_font("Calibri");
theme.set_color("accent1", "FF5733");
theme.set_color("accent2", "33FF57");
let theme_xml = theme.to_xml()?;
println!(" │ ├── Name: {}", theme.name());
println!(" │ ├── Major Font: Arial");
println!(" │ ├── Minor Font: Calibri");
println!(" │ └── XML size: {} bytes", theme_xml.len());
println!(" ├── NotesSlidePart (speaker notes):");
let notes = NotesSlidePart::with_text(
1,
"Remember to:\n- Introduce yourself\n- Explain the agenda\n- Ask for questions",
);
let notes_xml = notes.to_xml()?;
println!(" │ ├── Path: {}", notes.path());
println!(
" │ ├── Text: \"{}...\"",
¬es.notes_text()[..20.min(notes.notes_text().len())]
);
println!(" │ └── XML size: {} bytes", notes_xml.len());
println!(" ├── AppPropertiesPart (metadata):");
let mut app_props = AppPropertiesPart::new();
app_props.set_company("Acme Corporation");
app_props.set_slides(slide_count as u32);
let app_xml = app_props.to_xml()?;
println!(" │ ├── Company: Acme Corporation");
println!(" │ ├── Slides: {}", slide_count);
println!(" │ └── XML size: {} bytes", app_xml.len());
println!(" ├── MediaPart (10 media formats):");
println!(" │ ├── Video: mp4, webm, avi, wmv, mov");
println!(" │ ├── Audio: mp3, wav, wma, m4a, ogg");
let sample_media = MediaPart::new(1, MediaFormat::Mp4, vec![0; 100]);
println!(
" │ └── Sample: {} ({})",
sample_media.path(),
sample_media.format().mime_type()
);
println!(" ├── TablePart (cell formatting):");
let table_part = TablePart::new()
.add_row(TableRowPart::new(vec![
TableCellPart::new("Header 1").bold().background("4472C4"),
TableCellPart::new("Header 2").bold().background("4472C4"),
]))
.add_row(TableRowPart::new(vec![
TableCellPart::new("Data 1").color("333333"),
TableCellPart::new("Data 2").italic(),
]))
.position(EMU_PER_INCH, EMU_PER_INCH * 2)
.size(EMU_PER_INCH * 6, EMU_PER_INCH * 2);
let table_xml = table_part.to_slide_xml(10);
println!(" │ ├── Rows: {}", table_part.rows.len());
println!(" │ ├── Features: bold, italic, colors, backgrounds");
println!(" │ └── XML size: {} bytes", table_xml.len());
println!(" └── ContentTypesPart:");
let mut content_types = ContentTypesPart::new();
content_types.add_presentation();
content_types.add_slide(1);
content_types.add_slide_layout(1);
content_types.add_slide_master(1);
content_types.add_theme(1);
content_types.add_core_properties();
content_types.add_app_properties();
let ct_xml = content_types.to_xml()?;
println!(" ├── Path: {}", content_types.path());
println!(" └── XML size: {} bytes", ct_xml.len());
println!("\n🎨 Elements API Demonstration:");
println!(" ┌── Color Types:");
let rgb = RgbColor::new(255, 87, 51);
let rgb_hex = RgbColor::from_hex("#4472C4").unwrap();
let scheme = SchemeColor::Accent1;
let color = Color::rgb(100, 149, 237);
println!(" │ ├── RgbColor::new(255, 87, 51) → {}", rgb.to_hex());
println!(
" │ ├── RgbColor::from_hex(\"#4472C4\") → {}",
rgb_hex.to_hex()
);
println!(" │ ├── SchemeColor::Accent1 → {}", scheme.as_str());
println!(
" │ └── Color::rgb(100, 149, 237) → XML: {}",
color.to_xml().chars().take(30).collect::<String>()
);
println!(" ├── Position & Size (EMU units):");
let pos = Position::from_inches(1.0, 2.0);
let size = Size::from_inches(4.0, 3.0);
println!(
" │ ├── Position::from_inches(1.0, 2.0) → x={}, y={}",
pos.x, pos.y
);
println!(
" │ ├── Size::from_inches(4.0, 3.0) → w={}, h={}",
size.width, size.height
);
println!(" │ └── EMU_PER_INCH = {}", EMU_PER_INCH);
println!(" └── Transform (position + size + rotation):");
let transform = Transform::from_inches(1.0, 1.5, 3.0, 2.0).with_rotation(45.0);
let transform_xml = transform.to_xml();
println!(" ├── Transform::from_inches(1.0, 1.5, 3.0, 2.0)");
println!(" ├── .with_rotation(45.0)");
println!(
" └── XML: {}...",
&transform_xml[..50.min(transform_xml.len())]
);
println!("\n🚀 Advanced Features Demonstration:");
println!(" ┌── Complex Table Examples:");
println!(" │ ┌── Financial Report Table (5x4 with formatting):");
let financial_table = TablePart::new()
.add_row(TableRowPart::new(vec![TableCellPart::new(
"Q1 2024 Financial Summary",
)
.col_span(4)
.bold()
.center()
.background("1F4E79")
.color("FFFFFF")
.font_size(14)
.font("Arial Black")]))
.add_row(TableRowPart::new(vec![
TableCellPart::new("Category")
.bold()
.center()
.background("2E75B6")
.color("FFFFFF"),
TableCellPart::new("Revenue")
.bold()
.center()
.background("2E75B6")
.color("FFFFFF"),
TableCellPart::new("Expenses")
.bold()
.center()
.background("2E75B6")
.color("FFFFFF"),
TableCellPart::new("Profit")
.bold()
.center()
.background("2E75B6")
.color("FFFFFF"),
]))
.add_row(TableRowPart::new(vec![
TableCellPart::new("Product Sales").align(HorizontalAlign::Left),
TableCellPart::new("$1,250,000")
.align(HorizontalAlign::Right)
.color("2E7D32"),
TableCellPart::new("$450,000")
.align(HorizontalAlign::Right)
.color("C62828"),
TableCellPart::new("$800,000")
.align(HorizontalAlign::Right)
.bold()
.color("2E7D32"),
]))
.add_row(TableRowPart::new(vec![
TableCellPart::new("Services").align(HorizontalAlign::Left),
TableCellPart::new("$890,000")
.align(HorizontalAlign::Right)
.color("2E7D32"),
TableCellPart::new("$320,000")
.align(HorizontalAlign::Right)
.color("C62828"),
TableCellPart::new("$570,000")
.align(HorizontalAlign::Right)
.bold()
.color("2E7D32"),
]))
.add_row(TableRowPart::new(vec![
TableCellPart::new("Total").bold().background("E7E6E6"),
TableCellPart::new("$2,140,000")
.bold()
.align(HorizontalAlign::Right)
.background("E7E6E6"),
TableCellPart::new("$770,000")
.bold()
.align(HorizontalAlign::Right)
.background("E7E6E6"),
TableCellPart::new("$1,370,000")
.bold()
.align(HorizontalAlign::Right)
.background("C6EFCE")
.color("006100"),
]))
.position(EMU_PER_INCH / 2, EMU_PER_INCH * 2)
.size(EMU_PER_INCH * 8, EMU_PER_INCH * 3);
let fin_xml = financial_table.to_slide_xml(100);
println!(" │ │ ├── Merged header spanning 4 columns");
println!(" │ │ ├── Color-coded values (green=positive, red=negative)");
println!(" │ │ ├── Custom fonts and sizes");
println!(" │ │ └── XML: {} bytes", fin_xml.len());
println!(" │ ├── Comparison Matrix (features vs products):");
let _matrix_table = TablePart::new()
.add_row(TableRowPart::new(vec![
TableCellPart::new("Feature")
.bold()
.center()
.background("4472C4")
.color("FFFFFF"),
TableCellPart::new("Basic")
.bold()
.center()
.background("4472C4")
.color("FFFFFF"),
TableCellPart::new("Pro")
.bold()
.center()
.background("4472C4")
.color("FFFFFF"),
TableCellPart::new("Enterprise")
.bold()
.center()
.background("4472C4")
.color("FFFFFF"),
]))
.add_row(TableRowPart::new(vec![
TableCellPart::new("Storage").align(HorizontalAlign::Left),
TableCellPart::new("5 GB").center(),
TableCellPart::new("50 GB").center(),
TableCellPart::new("Unlimited")
.center()
.bold()
.color("2E7D32"),
]))
.add_row(TableRowPart::new(vec![
TableCellPart::new("Users").align(HorizontalAlign::Left),
TableCellPart::new("1").center(),
TableCellPart::new("10").center(),
TableCellPart::new("Unlimited")
.center()
.bold()
.color("2E7D32"),
]))
.add_row(TableRowPart::new(vec![
TableCellPart::new("Support").align(HorizontalAlign::Left),
TableCellPart::new("Email").center(),
TableCellPart::new("24/7 Chat").center(),
TableCellPart::new("Dedicated")
.center()
.bold()
.color("2E7D32"),
]))
.add_row(TableRowPart::new(vec![
TableCellPart::new("Price/mo").bold().background("F2F2F2"),
TableCellPart::new("$9")
.center()
.bold()
.background("F2F2F2"),
TableCellPart::new("$29")
.center()
.bold()
.background("F2F2F2"),
TableCellPart::new("$99")
.center()
.bold()
.background("F2F2F2"),
]));
println!(" │ │ └── 5x4 matrix with alternating styles");
println!(" │ └── Schedule Table (with row spans):");
let _schedule_table = TablePart::new()
.add_row(TableRowPart::new(vec![
TableCellPart::new("Time")
.bold()
.center()
.background("70AD47")
.color("FFFFFF"),
TableCellPart::new("Monday")
.bold()
.center()
.background("70AD47")
.color("FFFFFF"),
TableCellPart::new("Tuesday")
.bold()
.center()
.background("70AD47")
.color("FFFFFF"),
]))
.add_row(TableRowPart::new(vec![
TableCellPart::new("9:00 AM").center().background("E2EFDA"),
TableCellPart::new("Team Standup")
.center()
.row_span(2)
.valign(VerticalAlign::Middle)
.background("BDD7EE"),
TableCellPart::new("Code Review").center(),
]))
.add_row(TableRowPart::new(vec![
TableCellPart::new("10:00 AM").center().background("E2EFDA"),
TableCellPart::merged(),
TableCellPart::new("Sprint Planning")
.center()
.background("FCE4D6"),
]));
println!(" │ └── Row spans for multi-hour events");
println!(" ├── (Animation/SmartArt/3D/VBA/CustomXml/EmbeddedFont/Handout removed in lean refactor)");
println!(" ├── Theme + Master + Layout Integration:");
let mut corp_theme = ThemePart::new(1);
corp_theme.set_name("Corporate Blue");
corp_theme.set_major_font("Segoe UI");
corp_theme.set_minor_font("Segoe UI Light");
corp_theme.set_color("dk1", "000000");
corp_theme.set_color("lt1", "FFFFFF");
corp_theme.set_color("dk2", "1F497D");
corp_theme.set_color("lt2", "EEECE1");
corp_theme.set_color("accent1", "4472C4");
corp_theme.set_color("accent2", "ED7D31");
corp_theme.set_color("accent3", "A5A5A5");
corp_theme.set_color("accent4", "FFC000");
corp_theme.set_color("accent5", "5B9BD5");
corp_theme.set_color("accent6", "70AD47");
let theme_xml = corp_theme.to_xml()?;
println!(" │ ├── Theme: Corporate Blue");
println!(" │ │ ├── Fonts: Segoe UI / Segoe UI Light");
println!(" │ │ ├── 12 color slots defined");
println!(" │ │ └── XML: {} bytes", theme_xml.len());
let mut corp_master = SlideMasterPart::new(1);
corp_master.set_name("Corporate Master");
corp_master.add_layout_rel_id("rId2"); corp_master.add_layout_rel_id("rId3"); corp_master.add_layout_rel_id("rId4"); corp_master.add_layout_rel_id("rId5"); corp_master.add_layout_rel_id("rId6"); corp_master.add_layout_rel_id("rId7"); corp_master.add_layout_rel_id("rId8"); println!(
" │ └── Master: {} with {} layouts linked",
corp_master.name(),
corp_master.layout_rel_ids().len()
);
println!(" ├── Theme + Master + Layout Integration:");
println!("\n╔══════════════════════════════════════════════════════════════╗");
println!("║ Element Coverage Summary ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ LAYOUTS (6 types): ║");
println!("║ ✓ CenteredTitle ✓ TitleOnly ✓ TitleAndContent ║");
println!("║ ✓ TitleAndBigContent ✓ TwoColumn ✓ Blank ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ TEXT FORMATTING: ║");
println!("║ ✓ Bold ✓ Italic ✓ Underline ║");
println!("║ ✓ Font Size ✓ Font Color ✓ Title/Content styles ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ TABLES: ║");
println!("║ ✓ Multiple rows/columns ✓ Bold cells ✓ Background colors║");
println!("║ ✓ Header styling ✓ Position control ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ CHARTS: ║");
println!("║ ✓ Bar Chart ✓ Line Chart ✓ Pie Chart ║");
println!("║ ✓ Multiple series ✓ Categories ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ SHAPES: ║");
println!("║ ✓ Rectangle ✓ Ellipse ✓ RoundedRectangle ║");
println!("║ ✓ Triangle ✓ Diamond ✓ Color fills ║");
println!("║ ✓ Gradient fills ✓ Transparency ✓ Text in shapes ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ CONNECTORS (NEW): ║");
println!("║ ✓ Straight ✓ Elbow ✓ Curved ║");
println!("║ ✓ Arrow types ✓ Dash styles ✓ Line colors/widths ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ IMAGES: ║");
println!("║ ✓ Image placeholders ✓ Position ✓ Dimensions ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ PACKAGE: ║");
println!("║ ✓ Create PPTX ✓ Read PPTX ✓ Analyze contents ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ PARTS API (NEW): ║");
println!("║ ✓ SlideLayoutPart (11 types) ✓ SlideMasterPart ║");
println!("║ ✓ ThemePart (colors/fonts) ✓ NotesSlidePart ║");
println!("║ ✓ AppPropertiesPart ✓ MediaPart (10 formats) ║");
println!("║ ✓ TablePart (cell formatting) ✓ ContentTypesPart ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ ELEMENTS API: ║");
println!("║ ✓ RgbColor ✓ SchemeColor ✓ Color enum ║");
println!("║ ✓ Position ✓ Size ✓ Transform ║");
println!("║ ✓ EMU conversions (inches, cm, mm, pt) ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ ADVANCED FEATURES: ║");
println!("║ ✓ Table borders/alignment ✓ Merged cells ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!("║ DIMENSION API (NEW): ║");
println!("║ ✓ EMU / Inches / Cm / Pt / Ratio / Percent units ║");
println!("║ ✓ from_dimensions() constructor ║");
println!("║ ✓ Fluent .at() and .with_dimensions() chaining ║");
println!("║ ✓ Mixed-unit positioning (e.g. inches + percent) ║");
println!("╠══════════════════════════════════════════════════════════════╣");
println!(
"║ Output: {} ({} slides, {} KB) ║",
output_path.file_name().unwrap().to_string_lossy(),
slide_count,
pptx_data.len() / 1024
);
println!("╚══════════════════════════════════════════════════════════════╝");
Ok(())
}