1use rdocx_oxml::borders::CT_PBdr;
4use rdocx_oxml::shared::ST_Jc;
5
6use crate::line::LayoutLine;
7use crate::output::Color;
8use crate::table::TableBlock;
9
10#[derive(Debug, Clone)]
12pub enum LayoutBlock {
13 Paragraph(ParagraphBlock),
14 Table(TableBlock),
15}
16
17impl LayoutBlock {
18 pub fn total_height(&self) -> f64 {
20 match self {
21 LayoutBlock::Paragraph(p) => p.total_height(),
22 LayoutBlock::Table(t) => t.total_height(),
23 }
24 }
25
26 pub fn content_height(&self) -> f64 {
28 match self {
29 LayoutBlock::Paragraph(p) => p.content_height(),
30 LayoutBlock::Table(t) => t.content_height(),
31 }
32 }
33
34 pub fn space_before(&self) -> f64 {
35 match self {
36 LayoutBlock::Paragraph(p) => p.space_before,
37 LayoutBlock::Table(_) => 0.0,
38 }
39 }
40
41 pub fn space_after(&self) -> f64 {
42 match self {
43 LayoutBlock::Paragraph(p) => p.space_after,
44 LayoutBlock::Table(_) => 0.0,
45 }
46 }
47
48 pub fn keep_next(&self) -> bool {
49 match self {
50 LayoutBlock::Paragraph(p) => p.keep_next,
51 LayoutBlock::Table(_) => false,
52 }
53 }
54
55 pub fn keep_lines(&self) -> bool {
56 match self {
57 LayoutBlock::Paragraph(p) => p.keep_lines,
58 LayoutBlock::Table(_) => false,
59 }
60 }
61
62 pub fn page_break_before(&self) -> bool {
63 match self {
64 LayoutBlock::Paragraph(p) => p.page_break_before,
65 LayoutBlock::Table(_) => false,
66 }
67 }
68
69 pub fn widow_control(&self) -> bool {
70 match self {
71 LayoutBlock::Paragraph(p) => p.widow_control,
72 LayoutBlock::Table(_) => false,
73 }
74 }
75}
76
77#[derive(Debug, Clone)]
79pub struct ParagraphBlock {
80 pub lines: Vec<LayoutLine>,
82 pub space_before: f64,
84 pub space_after: f64,
86 pub borders: Option<CT_PBdr>,
88 pub shading: Option<Color>,
90 pub indent_left: f64,
92 pub indent_right: f64,
94 pub jc: Option<ST_Jc>,
96 pub keep_next: bool,
98 pub keep_lines: bool,
100 pub page_break_before: bool,
102 pub widow_control: bool,
104 pub heading_level: Option<u32>,
106 pub heading_text: Option<String>,
108}
109
110impl ParagraphBlock {
111 pub fn content_height(&self) -> f64 {
113 self.lines.iter().map(|l| l.height).sum()
114 }
115
116 pub fn total_height(&self) -> f64 {
118 self.space_before + self.content_height() + self.space_after
119 }
120
121 pub fn line_count(&self) -> usize {
123 self.lines.len()
124 }
125}
126
127pub fn build_paragraph_block(
129 lines: Vec<LayoutLine>,
130 space_before: f64,
131 space_after: f64,
132 borders: Option<CT_PBdr>,
133 shading: Option<Color>,
134 indent_left: f64,
135 indent_right: f64,
136 jc: Option<ST_Jc>,
137 keep_next: bool,
138 keep_lines: bool,
139 page_break_before: bool,
140 widow_control: bool,
141) -> ParagraphBlock {
142 ParagraphBlock {
143 lines,
144 space_before,
145 space_after,
146 borders,
147 shading,
148 indent_left,
149 indent_right,
150 jc,
151 keep_next,
152 keep_lines,
153 page_break_before,
154 widow_control,
155 heading_level: None,
156 heading_text: None,
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn paragraph_block_height() {
166 let block = ParagraphBlock {
167 lines: vec![
168 LayoutLine {
169 items: vec![],
170 width: 0.0,
171 ascent: 10.0,
172 descent: 3.0,
173 height: 13.0,
174 indent_left: 0.0,
175 available_width: 468.0,
176 is_last: false,
177 },
178 LayoutLine {
179 items: vec![],
180 width: 0.0,
181 ascent: 10.0,
182 descent: 3.0,
183 height: 13.0,
184 indent_left: 0.0,
185 available_width: 468.0,
186 is_last: true,
187 },
188 ],
189 space_before: 6.0,
190 space_after: 8.0,
191 borders: None,
192 shading: None,
193 indent_left: 0.0,
194 indent_right: 0.0,
195 jc: None,
196 keep_next: false,
197 keep_lines: false,
198 page_break_before: false,
199 widow_control: true,
200 heading_level: None,
201 heading_text: None,
202 };
203 assert!((block.content_height() - 26.0).abs() < 0.01);
204 assert!((block.total_height() - 40.0).abs() < 0.01);
205 }
206}