use oxidize_pdf::advanced_tables::{
AdvancedTableBuilder, AdvancedTableExt, BorderStyle, CellAlignment, CellStyle, HeaderBuilder,
Padding, TableRenderer,
};
use oxidize_pdf::coordinate_system::CoordinateSystem;
use oxidize_pdf::graphics::Color;
use oxidize_pdf::page::{LayoutManager, Page};
use oxidize_pdf::text::Font;
use oxidize_pdf::Document;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
println!("Creating advanced tables with automatic text truncation example PDF...");
let mut doc = Document::new();
let mut page1 = Page::a4(); let mut layout_manager =
LayoutManager::new(&page1, CoordinateSystem::PdfStandard).with_element_spacing(40.0);
create_truncation_demo_table(&mut page1, &mut layout_manager)?;
doc.add_page(page1);
let mut page2 = Page::a4();
let mut layout_manager =
LayoutManager::new(&page2, CoordinateSystem::PdfStandard).with_element_spacing(40.0);
create_financial_table_with_truncation(&mut page2, &mut layout_manager)?;
doc.add_page(page2);
let mut page3 = Page::a4();
let mut layout_manager =
LayoutManager::new(&page3, CoordinateSystem::PdfStandard).with_element_spacing(40.0);
create_inventory_table_with_truncation(&mut page3, &mut layout_manager)?;
doc.add_page(page3);
let output_path = "examples/results/advanced_tables_truncated_example.pdf";
doc.save(output_path)?;
println!("PDF saved to: {}", output_path);
println!("This PDF demonstrates automatic text truncation with ellipsis (...) for text that exceeds cell width");
Ok(())
}
fn create_truncation_demo_table(
page: &mut Page,
layout_manager: &mut LayoutManager,
) -> Result<(), Box<dyn Error>> {
println!("Creating text truncation demonstration table...");
let header_style = CellStyle::new()
.background_color(Color::rgb(0.1, 0.1, 0.3))
.text_color(Color::white())
.font(Font::HelveticaBold)
.font_size(10.0)
.alignment(CellAlignment::Center)
.padding(Padding::uniform(4.0));
let left_style = CellStyle::new()
.font(Font::Helvetica)
.font_size(9.0)
.alignment(CellAlignment::Left)
.padding(Padding::uniform(4.0))
.border(BorderStyle::Solid, 1.0, Color::gray(0.5));
let center_style = CellStyle::new()
.font(Font::Helvetica)
.font_size(9.0)
.alignment(CellAlignment::Center)
.padding(Padding::uniform(4.0))
.border(BorderStyle::Solid, 1.0, Color::gray(0.5));
let right_style = CellStyle::new()
.font(Font::Helvetica)
.font_size(9.0)
.alignment(CellAlignment::Right)
.padding(Padding::uniform(4.0))
.border(BorderStyle::Solid, 1.0, Color::gray(0.5));
let table = AdvancedTableBuilder::new()
.title("Text Truncation Demo - Different Column Widths & Alignments")
.columns(vec![
("Narrow (60pt)", 60.0), ("Medium (80pt)", 80.0), ("Wide (120pt)", 120.0), ("Very Wide (140pt)", 140.0), ]) .header_style(header_style)
.add_row_with_mixed_styles(vec![
(left_style.clone(), "Short text"),
(center_style.clone(), "This is medium length text"),
(right_style.clone(), "This is a longer piece of text that should be truncated"),
(left_style.clone(), "This is an extremely long piece of text that will definitely be truncated with ellipsis"),
])
.add_row_with_mixed_styles(vec![
(center_style.clone(), "Center aligned"),
(right_style.clone(), "Right aligned text that is long"),
(left_style.clone(), "Left aligned very long text string"),
(center_style.clone(), "Center aligned extremely long text that will show truncation behavior"),
])
.add_row_with_mixed_styles(vec![
(right_style.clone(), "Right"),
(left_style.clone(), "Left aligned long text"),
(center_style.clone(), "Center aligned text that is quite long"),
(right_style.clone(), "Right aligned super duper extremely long text that demonstrates truncation"),
])
.add_row_with_mixed_styles(vec![
(left_style.clone(), "A"),
(center_style, "B"),
(right_style, "C"),
(left_style, "D - This text is way too long for the cell and will be truncated"),
])
.build()?;
let renderer = TableRenderer::new();
let table_height = renderer.calculate_table_height(&table);
println!(
"Truncation demo table width: {} points",
table.calculate_width()
);
if let Some(y_position) = layout_manager.add_element(table_height) {
let x_position = layout_manager.center_x(table.calculate_width());
page.add_advanced_table(&table, x_position, y_position)?;
} else {
return Err("Table does not fit on page".into());
}
Ok(())
}
fn create_financial_table_with_truncation(
page: &mut Page,
layout_manager: &mut LayoutManager,
) -> Result<(), Box<dyn Error>> {
println!("Creating financial table with text truncation...");
let header_style = CellStyle::new()
.background_color(Color::rgb(0.2, 0.4, 0.8))
.text_color(Color::white())
.font(Font::HelveticaBold)
.font_size(10.0)
.alignment(CellAlignment::Center)
.padding(Padding::uniform(6.0));
let data_style = CellStyle::new()
.font(Font::Helvetica)
.font_size(9.0)
.padding(Padding::uniform(4.0))
.border(BorderStyle::Solid, 1.0, Color::gray(0.5));
let number_style = CellStyle::new()
.font(Font::Helvetica)
.font_size(9.0)
.alignment(CellAlignment::Right)
.padding(Padding::uniform(4.0))
.border(BorderStyle::Solid, 1.0, Color::gray(0.5));
let table = AdvancedTableBuilder::new()
.title("Quarterly Financial Report - With Auto Text Truncation")
.columns(vec![
("Department", 100.0), ("Q1 Revenue", 80.0),
("Q2 Revenue", 80.0),
("Q3 Revenue", 80.0),
("Total", 80.0), ]) .header_style(header_style)
.add_row_with_mixed_styles(vec![
(data_style.clone(), "Sales & Marketing Department"), (number_style.clone(), "$1,250,000"),
(number_style.clone(), "$1,380,000"),
(number_style.clone(), "$1,520,000"),
(number_style.clone(), "$4,150,000"),
])
.add_row_with_mixed_styles(vec![
(data_style.clone(), "Marketing & Communications"), (number_style.clone(), "$850,000"),
(number_style.clone(), "$920,000"),
(number_style.clone(), "$980,000"),
(number_style.clone(), "$2,750,000"),
])
.add_row_with_mixed_styles(vec![
(data_style.clone(), "Engineering & Development"), (number_style.clone(), "$2,100,000"),
(number_style.clone(), "$2,200,000"),
(number_style.clone(), "$2,350,000"),
(number_style.clone(), "$6,650,000"),
])
.add_row_with_mixed_styles(vec![
(data_style.clone(), "Customer Support Services"), (number_style.clone(), "$450,000"),
(number_style.clone(), "$480,000"),
(number_style.clone(), "$510,000"),
(number_style.clone(), "$1,440,000"),
])
.add_row_with_mixed_styles(vec![
(data_style, "Operations & Logistics"), (number_style.clone(), "$780,000"),
(number_style.clone(), "$820,000"),
(number_style.clone(), "$890,000"),
(number_style, "$2,490,000"),
])
.build()?;
let renderer = TableRenderer::new();
let table_height = renderer.calculate_table_height(&table);
println!("Financial table width: {} points", table.calculate_width());
if let Some(y_position) = layout_manager.add_element(table_height) {
let x_position = layout_manager.center_x(table.calculate_width());
page.add_advanced_table(&table, x_position, y_position)?;
} else {
return Err("Table does not fit on page".into());
}
Ok(())
}
fn create_inventory_table_with_truncation(
page: &mut Page,
layout_manager: &mut LayoutManager,
) -> Result<(), Box<dyn Error>> {
println!("Creating inventory table with text truncation...");
let header_style = CellStyle::new()
.background_color(Color::rgb(0.3, 0.5, 0.3))
.text_color(Color::white())
.font(Font::HelveticaBold)
.font_size(10.0)
.alignment(CellAlignment::Center)
.padding(Padding::uniform(5.0));
let data_style = CellStyle::new()
.font(Font::Helvetica)
.font_size(9.0)
.padding(Padding::uniform(4.0))
.border(BorderStyle::Solid, 1.0, Color::gray(0.5));
let number_style = CellStyle::new()
.font(Font::Helvetica)
.font_size(9.0)
.alignment(CellAlignment::Right)
.padding(Padding::uniform(4.0))
.border(BorderStyle::Solid, 1.0, Color::gray(0.5));
let header_builder = HeaderBuilder::new(7)
.add_level(vec![
("Product Information", 3), ("Stock Levels", 2), ("Pricing", 2), ])
.add_level(vec![
("SKU", 1),
("Name", 1),
("Category", 1),
("In Stock", 1),
("Reserved", 1),
("Cost", 1),
("Retail", 1),
]);
let table = AdvancedTableBuilder::new()
.title("Product Inventory Report - With Text Truncation")
.columns(vec![
("SKU", 50.0), ("Name", 85.0), ("Category", 60.0), ("In Stock", 45.0), ("Reserved", 45.0), ("Cost", 60.0), ("Retail", 60.0), ]) .complex_header(header_builder)
.header_style(header_style)
.add_row_with_mixed_styles(vec![
(data_style.clone(), "PRD-001"),
(
data_style.clone(),
"Professional Gaming Laptop with High-End Graphics",
), (data_style.clone(), "Electronics & Computers"), (number_style.clone(), "45"),
(number_style.clone(), "12"),
(number_style.clone(), "$899.99"),
(number_style.clone(), "$1,299.99"),
])
.add_row_with_mixed_styles(vec![
(data_style.clone(), "PRD-002"),
(
data_style.clone(),
"Wireless Ergonomic Mouse with RGB Lighting",
), (data_style.clone(), "Computer Accessories"), (number_style.clone(), "128"),
(number_style.clone(), "15"),
(number_style.clone(), "$15.50"),
(number_style.clone(), "$39.99"),
])
.add_row_with_mixed_styles(vec![
(data_style.clone(), "PRD-003"),
(
data_style.clone(),
"USB-C Multi-Port Hub with Power Delivery",
), (data_style.clone(), "Connectivity Accessories"), (number_style.clone(), "87"),
(number_style.clone(), "8"),
(number_style.clone(), "$25.00"),
(number_style.clone(), "$59.99"),
])
.add_row_with_mixed_styles(vec![
(data_style.clone(), "PRD-004"),
(data_style.clone(), "27-inch 4K UHD Professional Monitor"), (data_style.clone(), "Displays & Monitors"), (number_style.clone(), "23"),
(number_style.clone(), "5"),
(number_style.clone(), "$180.00"),
(number_style.clone(), "$399.99"),
])
.add_row_with_mixed_styles(vec![
(data_style.clone(), "PRD-005"),
(
data_style.clone(),
"Mechanical Gaming Keyboard with Backlight",
), (data_style, "Input Devices & Keyboards"), (number_style.clone(), "67"),
(number_style.clone(), "10"),
(number_style.clone(), "$45.00"),
(number_style, "$129.99"),
])
.build()?;
let renderer = TableRenderer::new();
let table_height = renderer.calculate_table_height(&table);
println!("Inventory table width: {} points", table.calculate_width());
if let Some(y_position) = layout_manager.add_element(table_height) {
let x_position = layout_manager.center_x(table.calculate_width());
page.add_advanced_table(&table, x_position, y_position)?;
} else {
return Err("Table does not fit on page".into());
}
Ok(())
}