pub struct TableColumn {
pub width: ColumnWidth,
pub align: Align,
}Fields§
§width: ColumnWidth§align: AlignImplementations§
Source§impl TableColumn
impl TableColumn
Sourcepub fn fixed(width: f32) -> TableColumn
pub fn fixed(width: f32) -> TableColumn
Examples found in repository?
examples/invoice.rs (line 101)
20fn main() {
21 let mut items = vec![
22 LineItem {
23 description: "Beratungsleistung Projekt Alpha".to_string(),
24 qty: 8,
25 unit_price_cents: 12_000,
26 },
27 LineItem {
28 description: "Lizenz Software-Paket (jährlich)".to_string(),
29 qty: 1,
30 unit_price_cents: 49_900,
31 },
32 LineItem {
33 description: "Individuelle Anpassung / Customizing".to_string(),
34 qty: 3,
35 unit_price_cents: 15_000,
36 },
37 ];
38 // A few filler positions so the table is guaranteed to span more than
39 // one page, demonstrating the header-repeat-on-split behavior.
40 for i in 1..=25 {
41 items.push(LineItem {
42 description: format!("Zusatzposition {i:02}"),
43 qty: 1,
44 unit_price_cents: 990,
45 });
46 }
47
48 let net_total: i64 = items.iter().map(|i| i.qty as i64 * i.unit_price_cents).sum();
49 let vat_rate = 19;
50 let vat_total = net_total * vat_rate / 100;
51 let gross_total = net_total + vat_total;
52
53 let top_margin = 15.0 * MM;
54 let mut doc = Document::new(PageFormat::A4)
55 .margin(Margin::symmetric(20.0 * MM, top_margin))
56 .footer(Footer::new(30.0, |ctx| {
57 Column::new()
58 .gap(2.0)
59 .child(Line::new())
60 .child(
61 Row::new()
62 .gap(20.0)
63 .child(Text::new("Musterbank · IBAN DE12 3456 7890 1234 5678 90 · BIC MUSTDEFF").size(8.0))
64 .child(Text::new("USt-IdNr. DE123456789").size(8.0).flex(1.0)),
65 )
66 .child(Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages)).size(8.0))
67 .into()
68 }));
69
70 // --- DIN 5008 Form A window-envelope address block ----------------
71 // Window starts ~45mm from the top, ~20mm from the left
72 // (`plan/02-elementcatalog-and-features.md`); ~85x40mm matches a
73 // typical C6/5-long window envelope opening. Position/size are a
74 // documented convention for this recipe, not parsed from any norm
75 // document — a caller with different envelope stock adjusts these.
76 doc.add(Spacer::new(45.0 * MM - top_margin));
77 doc.add(
78 Column::new()
79 .gap(2.0)
80 .width(85.0 * MM)
81 .height(40.0 * MM)
82 .child(Text::new("Muster GmbH · Musterstraße 1 · 12345 Musterstadt").size(7.0))
83 .child(Spacer::new(8.0))
84 .child(Text::new("Empfänger GmbH"))
85 .child(Text::new("Frau Erika Mustermann"))
86 .child(Text::new("Beispielweg 42"))
87 .child(Text::new("54321 Beispielstadt")),
88 );
89 doc.add(Spacer::new(10.0 * MM));
90
91 doc.add(Text::new("Rechnung").heading1());
92 doc.add(Text::new(
93 "Rechnungsnummer: RE-2026-0142 Rechnungsdatum: 20.08.2026 Leistungsdatum: 20.08.2026",
94 ));
95 doc.add(Spacer::new(10.0));
96
97 doc.add(
98 Table::new()
99 .columns([
100 TableColumn::flex(1.0),
101 TableColumn::fixed(50.0).align(Align::End),
102 TableColumn::fixed(65.0).align(Align::End),
103 TableColumn::fixed(70.0).align(Align::End),
104 ])
105 .header(["Beschreibung", "Menge", "Einzelpreis", "Gesamt"])
106 .striped(Color::rgb(0xF5, 0xF5, 0xF5))
107 .rows(items.iter().map(|item| {
108 let total = item.qty as i64 * item.unit_price_cents;
109 vec![
110 Element::from(item.description.as_str()),
111 Element::from(item.qty.to_string()),
112 Element::from(format_currency_de(item.unit_price_cents)),
113 Element::from(format_currency_de(total)),
114 ]
115 })),
116 );
117
118 doc.add(Spacer::new(14.0));
119
120 // --- summary block (Netto/USt/Brutto), right-aligned --------------
121 // Recipe (`plan/02-elementcatalog-and-features.md`): an outer, full-
122 // width auto Column with `.align(Align::End)` positions the fixed-
123 // width (200pt) inner summary Column at the right edge; within it,
124 // each label gets `.flex(1.0)` to push its value to that block's own
125 // right edge. No special "summary block" element needed.
126 doc.add(
127 Column::new()
128 .align(Align::End)
129 .child(Column::new().gap(2.0).width(200.0).children(vec![
130 Element::from(
131 Row::new()
132 .child(Text::new("Nettosumme").flex(1.0))
133 .child(Text::new(format_currency_de(net_total))),
134 ),
135 Element::from(
136 Row::new()
137 .child(Text::new(format!("zzgl. {vat_rate}% USt.")).flex(1.0))
138 .child(Text::new(format_currency_de(vat_total))),
139 ),
140 Element::from(Line::new()),
141 Element::from(
142 Row::new()
143 .child(Text::new("Gesamtbetrag").bold().flex(1.0))
144 .child(Text::new(format_currency_de(gross_total)).bold()),
145 ),
146 ])),
147 );
148
149 let bytes = doc.render().expect("render should succeed");
150 std::fs::write("invoice.pdf", &bytes).expect("write invoice.pdf");
151 println!("wrote invoice.pdf ({} bytes)", bytes.len());
152}Sourcepub fn flex(weight: f32) -> TableColumn
pub fn flex(weight: f32) -> TableColumn
Examples found in repository?
examples/invoice.rs (line 100)
20fn main() {
21 let mut items = vec![
22 LineItem {
23 description: "Beratungsleistung Projekt Alpha".to_string(),
24 qty: 8,
25 unit_price_cents: 12_000,
26 },
27 LineItem {
28 description: "Lizenz Software-Paket (jährlich)".to_string(),
29 qty: 1,
30 unit_price_cents: 49_900,
31 },
32 LineItem {
33 description: "Individuelle Anpassung / Customizing".to_string(),
34 qty: 3,
35 unit_price_cents: 15_000,
36 },
37 ];
38 // A few filler positions so the table is guaranteed to span more than
39 // one page, demonstrating the header-repeat-on-split behavior.
40 for i in 1..=25 {
41 items.push(LineItem {
42 description: format!("Zusatzposition {i:02}"),
43 qty: 1,
44 unit_price_cents: 990,
45 });
46 }
47
48 let net_total: i64 = items.iter().map(|i| i.qty as i64 * i.unit_price_cents).sum();
49 let vat_rate = 19;
50 let vat_total = net_total * vat_rate / 100;
51 let gross_total = net_total + vat_total;
52
53 let top_margin = 15.0 * MM;
54 let mut doc = Document::new(PageFormat::A4)
55 .margin(Margin::symmetric(20.0 * MM, top_margin))
56 .footer(Footer::new(30.0, |ctx| {
57 Column::new()
58 .gap(2.0)
59 .child(Line::new())
60 .child(
61 Row::new()
62 .gap(20.0)
63 .child(Text::new("Musterbank · IBAN DE12 3456 7890 1234 5678 90 · BIC MUSTDEFF").size(8.0))
64 .child(Text::new("USt-IdNr. DE123456789").size(8.0).flex(1.0)),
65 )
66 .child(Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages)).size(8.0))
67 .into()
68 }));
69
70 // --- DIN 5008 Form A window-envelope address block ----------------
71 // Window starts ~45mm from the top, ~20mm from the left
72 // (`plan/02-elementcatalog-and-features.md`); ~85x40mm matches a
73 // typical C6/5-long window envelope opening. Position/size are a
74 // documented convention for this recipe, not parsed from any norm
75 // document — a caller with different envelope stock adjusts these.
76 doc.add(Spacer::new(45.0 * MM - top_margin));
77 doc.add(
78 Column::new()
79 .gap(2.0)
80 .width(85.0 * MM)
81 .height(40.0 * MM)
82 .child(Text::new("Muster GmbH · Musterstraße 1 · 12345 Musterstadt").size(7.0))
83 .child(Spacer::new(8.0))
84 .child(Text::new("Empfänger GmbH"))
85 .child(Text::new("Frau Erika Mustermann"))
86 .child(Text::new("Beispielweg 42"))
87 .child(Text::new("54321 Beispielstadt")),
88 );
89 doc.add(Spacer::new(10.0 * MM));
90
91 doc.add(Text::new("Rechnung").heading1());
92 doc.add(Text::new(
93 "Rechnungsnummer: RE-2026-0142 Rechnungsdatum: 20.08.2026 Leistungsdatum: 20.08.2026",
94 ));
95 doc.add(Spacer::new(10.0));
96
97 doc.add(
98 Table::new()
99 .columns([
100 TableColumn::flex(1.0),
101 TableColumn::fixed(50.0).align(Align::End),
102 TableColumn::fixed(65.0).align(Align::End),
103 TableColumn::fixed(70.0).align(Align::End),
104 ])
105 .header(["Beschreibung", "Menge", "Einzelpreis", "Gesamt"])
106 .striped(Color::rgb(0xF5, 0xF5, 0xF5))
107 .rows(items.iter().map(|item| {
108 let total = item.qty as i64 * item.unit_price_cents;
109 vec![
110 Element::from(item.description.as_str()),
111 Element::from(item.qty.to_string()),
112 Element::from(format_currency_de(item.unit_price_cents)),
113 Element::from(format_currency_de(total)),
114 ]
115 })),
116 );
117
118 doc.add(Spacer::new(14.0));
119
120 // --- summary block (Netto/USt/Brutto), right-aligned --------------
121 // Recipe (`plan/02-elementcatalog-and-features.md`): an outer, full-
122 // width auto Column with `.align(Align::End)` positions the fixed-
123 // width (200pt) inner summary Column at the right edge; within it,
124 // each label gets `.flex(1.0)` to push its value to that block's own
125 // right edge. No special "summary block" element needed.
126 doc.add(
127 Column::new()
128 .align(Align::End)
129 .child(Column::new().gap(2.0).width(200.0).children(vec![
130 Element::from(
131 Row::new()
132 .child(Text::new("Nettosumme").flex(1.0))
133 .child(Text::new(format_currency_de(net_total))),
134 ),
135 Element::from(
136 Row::new()
137 .child(Text::new(format!("zzgl. {vat_rate}% USt.")).flex(1.0))
138 .child(Text::new(format_currency_de(vat_total))),
139 ),
140 Element::from(Line::new()),
141 Element::from(
142 Row::new()
143 .child(Text::new("Gesamtbetrag").bold().flex(1.0))
144 .child(Text::new(format_currency_de(gross_total)).bold()),
145 ),
146 ])),
147 );
148
149 let bytes = doc.render().expect("render should succeed");
150 std::fs::write("invoice.pdf", &bytes).expect("write invoice.pdf");
151 println!("wrote invoice.pdf ({} bytes)", bytes.len());
152}Sourcepub fn align(self, align: Align) -> TableColumn
pub fn align(self, align: Align) -> TableColumn
Examples found in repository?
examples/invoice.rs (line 101)
20fn main() {
21 let mut items = vec![
22 LineItem {
23 description: "Beratungsleistung Projekt Alpha".to_string(),
24 qty: 8,
25 unit_price_cents: 12_000,
26 },
27 LineItem {
28 description: "Lizenz Software-Paket (jährlich)".to_string(),
29 qty: 1,
30 unit_price_cents: 49_900,
31 },
32 LineItem {
33 description: "Individuelle Anpassung / Customizing".to_string(),
34 qty: 3,
35 unit_price_cents: 15_000,
36 },
37 ];
38 // A few filler positions so the table is guaranteed to span more than
39 // one page, demonstrating the header-repeat-on-split behavior.
40 for i in 1..=25 {
41 items.push(LineItem {
42 description: format!("Zusatzposition {i:02}"),
43 qty: 1,
44 unit_price_cents: 990,
45 });
46 }
47
48 let net_total: i64 = items.iter().map(|i| i.qty as i64 * i.unit_price_cents).sum();
49 let vat_rate = 19;
50 let vat_total = net_total * vat_rate / 100;
51 let gross_total = net_total + vat_total;
52
53 let top_margin = 15.0 * MM;
54 let mut doc = Document::new(PageFormat::A4)
55 .margin(Margin::symmetric(20.0 * MM, top_margin))
56 .footer(Footer::new(30.0, |ctx| {
57 Column::new()
58 .gap(2.0)
59 .child(Line::new())
60 .child(
61 Row::new()
62 .gap(20.0)
63 .child(Text::new("Musterbank · IBAN DE12 3456 7890 1234 5678 90 · BIC MUSTDEFF").size(8.0))
64 .child(Text::new("USt-IdNr. DE123456789").size(8.0).flex(1.0)),
65 )
66 .child(Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages)).size(8.0))
67 .into()
68 }));
69
70 // --- DIN 5008 Form A window-envelope address block ----------------
71 // Window starts ~45mm from the top, ~20mm from the left
72 // (`plan/02-elementcatalog-and-features.md`); ~85x40mm matches a
73 // typical C6/5-long window envelope opening. Position/size are a
74 // documented convention for this recipe, not parsed from any norm
75 // document — a caller with different envelope stock adjusts these.
76 doc.add(Spacer::new(45.0 * MM - top_margin));
77 doc.add(
78 Column::new()
79 .gap(2.0)
80 .width(85.0 * MM)
81 .height(40.0 * MM)
82 .child(Text::new("Muster GmbH · Musterstraße 1 · 12345 Musterstadt").size(7.0))
83 .child(Spacer::new(8.0))
84 .child(Text::new("Empfänger GmbH"))
85 .child(Text::new("Frau Erika Mustermann"))
86 .child(Text::new("Beispielweg 42"))
87 .child(Text::new("54321 Beispielstadt")),
88 );
89 doc.add(Spacer::new(10.0 * MM));
90
91 doc.add(Text::new("Rechnung").heading1());
92 doc.add(Text::new(
93 "Rechnungsnummer: RE-2026-0142 Rechnungsdatum: 20.08.2026 Leistungsdatum: 20.08.2026",
94 ));
95 doc.add(Spacer::new(10.0));
96
97 doc.add(
98 Table::new()
99 .columns([
100 TableColumn::flex(1.0),
101 TableColumn::fixed(50.0).align(Align::End),
102 TableColumn::fixed(65.0).align(Align::End),
103 TableColumn::fixed(70.0).align(Align::End),
104 ])
105 .header(["Beschreibung", "Menge", "Einzelpreis", "Gesamt"])
106 .striped(Color::rgb(0xF5, 0xF5, 0xF5))
107 .rows(items.iter().map(|item| {
108 let total = item.qty as i64 * item.unit_price_cents;
109 vec![
110 Element::from(item.description.as_str()),
111 Element::from(item.qty.to_string()),
112 Element::from(format_currency_de(item.unit_price_cents)),
113 Element::from(format_currency_de(total)),
114 ]
115 })),
116 );
117
118 doc.add(Spacer::new(14.0));
119
120 // --- summary block (Netto/USt/Brutto), right-aligned --------------
121 // Recipe (`plan/02-elementcatalog-and-features.md`): an outer, full-
122 // width auto Column with `.align(Align::End)` positions the fixed-
123 // width (200pt) inner summary Column at the right edge; within it,
124 // each label gets `.flex(1.0)` to push its value to that block's own
125 // right edge. No special "summary block" element needed.
126 doc.add(
127 Column::new()
128 .align(Align::End)
129 .child(Column::new().gap(2.0).width(200.0).children(vec![
130 Element::from(
131 Row::new()
132 .child(Text::new("Nettosumme").flex(1.0))
133 .child(Text::new(format_currency_de(net_total))),
134 ),
135 Element::from(
136 Row::new()
137 .child(Text::new(format!("zzgl. {vat_rate}% USt.")).flex(1.0))
138 .child(Text::new(format_currency_de(vat_total))),
139 ),
140 Element::from(Line::new()),
141 Element::from(
142 Row::new()
143 .child(Text::new("Gesamtbetrag").bold().flex(1.0))
144 .child(Text::new(format_currency_de(gross_total)).bold()),
145 ),
146 ])),
147 );
148
149 let bytes = doc.render().expect("render should succeed");
150 std::fs::write("invoice.pdf", &bytes).expect("write invoice.pdf");
151 println!("wrote invoice.pdf ({} bytes)", bytes.len());
152}Trait Implementations§
Source§impl Clone for TableColumn
impl Clone for TableColumn
Source§fn clone(&self) -> TableColumn
fn clone(&self) -> TableColumn
Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreimpl Copy for TableColumn
Auto Trait Implementations§
impl Freeze for TableColumn
impl RefUnwindSafe for TableColumn
impl Send for TableColumn
impl Sync for TableColumn
impl Unpin for TableColumn
impl UnsafeUnpin for TableColumn
impl UnwindSafe for TableColumn
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more