docx_rs/documents/elements/
style.rs1use serde::Serialize;
2use std::io::Write;
3
4use crate::documents::BuildXML;
5use crate::escape::escape;
6use crate::types::*;
7use crate::xml_builder::*;
8use crate::StyleType;
9
10use super::*;
11
12#[derive(Debug, Clone, PartialEq, Serialize)]
13#[serde(rename_all = "camelCase")]
14pub struct Style {
15 pub style_id: String,
16 pub name: Name,
17 pub style_type: StyleType,
18 pub run_property: RunProperty,
19 pub paragraph_property: ParagraphProperty,
20 pub table_property: TableProperty,
21 pub table_cell_property: TableCellProperty,
22 pub based_on: Option<BasedOn>,
23 pub next: Option<Next>,
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub link: Option<Link>,
26 #[serde(skip_serializing_if = "is_true")]
27 pub q_format: bool,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub ui_priority: Option<usize>,
30 #[serde(skip_serializing_if = "is_false")]
31 pub semi_hidden: bool,
32 #[serde(skip_serializing_if = "is_false")]
33 pub unhide_when_used: bool,
34}
35
36const fn is_true(v: &bool) -> bool {
37 *v
38}
39
40const fn is_false(v: &bool) -> bool {
41 !*v
42}
43
44impl Default for Style {
45 fn default() -> Self {
46 let name = Name::new("");
47 let rpr = RunProperty::new();
48 let ppr = ParagraphProperty::new();
49 Style {
50 style_id: "".to_owned(),
51 style_type: StyleType::Paragraph,
52 name,
53 run_property: rpr,
54 paragraph_property: ppr,
55 table_property: TableProperty::new(),
56 table_cell_property: TableCellProperty::new(),
57 based_on: None,
58 next: None,
59 link: None,
60 q_format: true,
61 ui_priority: None,
62 semi_hidden: false,
63 unhide_when_used: false,
64 }
65 }
66}
67
68impl Style {
69 pub fn new(style_id: impl Into<String>, style_type: StyleType) -> Self {
70 let default = Default::default();
71 Style {
72 style_id: escape(&style_id.into()),
73 style_type,
74 ..default
75 }
76 }
77
78 pub fn name(mut self, name: impl Into<String>) -> Self {
79 self.name = Name::new(name);
80 self
81 }
82
83 pub fn based_on(mut self, base: impl Into<String>) -> Self {
84 self.based_on = Some(BasedOn::new(base));
85 self
86 }
87
88 pub fn next(mut self, next: impl Into<String>) -> Self {
89 self.next = Some(Next::new(next));
90 self
91 }
92
93 pub fn link(mut self, link: impl Into<String>) -> Self {
94 self.link = Some(Link::new(link));
95 self
96 }
97
98 pub fn q_format(mut self, q_format: bool) -> Self {
99 self.q_format = q_format;
100 self
101 }
102
103 pub fn ui_priority(mut self, ui_priority: usize) -> Self {
104 self.ui_priority = Some(ui_priority);
105 self
106 }
107
108 pub fn semi_hidden(mut self) -> Self {
109 self.semi_hidden = true;
110 self
111 }
112
113 pub fn unhide_when_used(mut self) -> Self {
114 self.unhide_when_used = true;
115 self
116 }
117
118 pub fn size(mut self, size: usize) -> Self {
119 self.run_property = self.run_property.size(size);
120 self
121 }
122
123 pub fn color(mut self, color: impl Into<String>) -> Self {
124 self.run_property = self.run_property.color(color);
125 self
126 }
127
128 pub fn theme_color(mut self, theme_color: crate::types::ThemeColor) -> Self {
130 self.run_property = self.run_property.theme_color(theme_color);
131 self
132 }
133
134 pub fn theme_shade(mut self, theme_shade: impl Into<String>) -> Self {
136 self.run_property = self.run_property.theme_shade(theme_shade);
137 self
138 }
139
140 pub fn theme_tint(mut self, theme_tint: impl Into<String>) -> Self {
142 self.run_property = self.run_property.theme_tint(theme_tint);
143 self
144 }
145
146 pub fn highlight(mut self, color: impl Into<String>) -> Self {
147 self.run_property = self.run_property.highlight(color);
148 self
149 }
150
151 pub fn bold(mut self) -> Self {
152 self.run_property = self.run_property.bold();
153 self
154 }
155
156 pub fn italic(mut self) -> Self {
157 self.run_property = self.run_property.italic();
158 self
159 }
160
161 pub fn underline(mut self, line_type: impl Into<String>) -> Self {
162 self.run_property = self.run_property.underline(line_type);
163 self
164 }
165
166 pub fn vanish(mut self) -> Self {
167 self.run_property = self.run_property.vanish();
168 self
169 }
170
171 pub fn text_border(mut self, b: TextBorder) -> Self {
172 self.run_property = self.run_property.text_border(b);
173 self
174 }
175
176 pub fn fonts(mut self, f: RunFonts) -> Self {
177 self.run_property = self.run_property.fonts(f);
178 self
179 }
180
181 pub fn align(mut self, alignment_type: AlignmentType) -> Self {
182 self.paragraph_property = self.paragraph_property.align(alignment_type);
183 self
184 }
185
186 pub fn text_alignment(mut self, alignment_type: TextAlignmentType) -> Self {
187 self.paragraph_property = self.paragraph_property.text_alignment(alignment_type);
188 self
189 }
190
191 pub fn snap_to_grid(mut self, v: bool) -> Self {
192 self.paragraph_property = self.paragraph_property.snap_to_grid(v);
193 self
194 }
195
196 pub fn line_spacing(mut self, spacing: LineSpacing) -> Self {
197 self.paragraph_property = self.paragraph_property.line_spacing(spacing);
198 self
199 }
200
201 pub fn indent(
202 mut self,
203 left: Option<i32>,
204 special_indent: Option<SpecialIndentType>,
205 end: Option<i32>,
206 start_chars: Option<i32>,
207 ) -> Self {
208 self.paragraph_property =
209 self.paragraph_property
210 .indent(left, special_indent, end, start_chars);
211 self
212 }
213
214 pub fn hanging_chars(mut self, chars: i32) -> Self {
215 self.paragraph_property = self.paragraph_property.hanging_chars(chars);
216 self
217 }
218
219 pub fn first_line_chars(mut self, chars: i32) -> Self {
220 self.paragraph_property = self.paragraph_property.first_line_chars(chars);
221 self
222 }
223
224 pub fn outline_lvl(mut self, l: usize) -> Self {
225 self.paragraph_property = self.paragraph_property.outline_lvl(l);
226 self
227 }
228
229 pub fn table_property(mut self, p: TableProperty) -> Self {
230 self.table_property = p;
231 self
232 }
233
234 pub fn table_indent(mut self, v: i32) -> Self {
235 self.table_property = self.table_property.indent(v);
236 self
237 }
238
239 pub fn table_align(mut self, v: TableAlignmentType) -> Self {
240 self.table_property = self.table_property.align(v);
241 self
242 }
243
244 pub fn style(mut self, s: impl Into<String>) -> Self {
245 self.table_property = self.table_property.style(s);
246 self
247 }
248
249 pub fn layout(mut self, t: TableLayoutType) -> Self {
250 self.table_property = self.table_property.layout(t);
251 self
252 }
253
254 pub fn width(mut self, w: usize, t: WidthType) -> Self {
255 self.table_property = self.table_property.width(w, t);
256 self
257 }
258
259 pub fn margins(mut self, margins: TableCellMargins) -> Self {
260 self.table_property = self.table_property.set_margins(margins);
261 self
262 }
263
264 pub fn set_borders(mut self, borders: TableBorders) -> Self {
265 self.table_property = self.table_property.set_borders(borders);
266 self
267 }
268
269 pub fn set_border(mut self, border: TableBorder) -> Self {
270 self.table_property = self.table_property.set_border(border);
271 self
272 }
273
274 pub fn clear_border(mut self, position: TableBorderPosition) -> Self {
275 self.table_property = self.table_property.clear_border(position);
276 self
277 }
278
279 pub fn clear_all_border(mut self) -> Self {
280 self.table_property = self.table_property.clear_all_border();
281 self
282 }
283
284 pub fn table_cell_property(mut self, p: TableCellProperty) -> Self {
285 self.table_cell_property = p;
286 self
287 }
288
289 pub fn wrap(mut self, wrap: impl Into<String>) -> Self {
291 self.paragraph_property.frame_property = Some(FrameProperty {
292 wrap: Some(wrap.into()),
293 ..self.paragraph_property.frame_property.unwrap_or_default()
294 });
295 self
296 }
297
298 pub fn v_anchor(mut self, anchor: impl Into<String>) -> Self {
299 self.paragraph_property.frame_property = Some(FrameProperty {
300 v_anchor: Some(anchor.into()),
301 ..self.paragraph_property.frame_property.unwrap_or_default()
302 });
303 self
304 }
305
306 pub fn h_anchor(mut self, anchor: impl Into<String>) -> Self {
307 self.paragraph_property.frame_property = Some(FrameProperty {
308 h_anchor: Some(anchor.into()),
309 ..self.paragraph_property.frame_property.unwrap_or_default()
310 });
311 self
312 }
313
314 pub fn h_rule(mut self, r: impl Into<String>) -> Self {
315 self.paragraph_property.frame_property = Some(FrameProperty {
316 h_rule: Some(r.into()),
317 ..self.paragraph_property.frame_property.unwrap_or_default()
318 });
319 self
320 }
321
322 pub fn x_align(mut self, align: impl Into<String>) -> Self {
323 self.paragraph_property.frame_property = Some(FrameProperty {
324 x_align: Some(align.into()),
325 ..self.paragraph_property.frame_property.unwrap_or_default()
326 });
327 self
328 }
329
330 pub fn y_align(mut self, align: impl Into<String>) -> Self {
331 self.paragraph_property.frame_property = Some(FrameProperty {
332 y_align: Some(align.into()),
333 ..self.paragraph_property.frame_property.unwrap_or_default()
334 });
335 self
336 }
337
338 pub fn h_space(mut self, x: i32) -> Self {
339 self.paragraph_property.frame_property = Some(FrameProperty {
340 h_space: Some(x),
341 ..self.paragraph_property.frame_property.unwrap_or_default()
342 });
343 self
344 }
345
346 pub fn v_space(mut self, x: i32) -> Self {
347 self.paragraph_property.frame_property = Some(FrameProperty {
348 v_space: Some(x),
349 ..self.paragraph_property.frame_property.unwrap_or_default()
350 });
351 self
352 }
353
354 pub fn frame_x(mut self, x: i32) -> Self {
355 self.paragraph_property.frame_property = Some(FrameProperty {
356 x: Some(x),
357 ..self.paragraph_property.frame_property.unwrap_or_default()
358 });
359 self
360 }
361
362 pub fn frame_y(mut self, y: i32) -> Self {
363 self.paragraph_property.frame_property = Some(FrameProperty {
364 y: Some(y),
365 ..self.paragraph_property.frame_property.unwrap_or_default()
366 });
367 self
368 }
369
370 pub fn frame_width(mut self, n: u32) -> Self {
371 self.paragraph_property.frame_property = Some(FrameProperty {
372 w: Some(n),
373 ..self.paragraph_property.frame_property.unwrap_or_default()
374 });
375 self
376 }
377
378 pub fn frame_height(mut self, n: u32) -> Self {
379 self.paragraph_property.frame_property = Some(FrameProperty {
380 h: Some(n),
381 ..self.paragraph_property.frame_property.unwrap_or_default()
382 });
383 self
384 }
385}
386
387impl BuildXML for Style {
388 fn build_to<W: Write>(
389 &self,
390 stream: crate::xml::writer::EventWriter<W>,
391 ) -> crate::xml::writer::Result<crate::xml::writer::EventWriter<W>> {
392 XMLBuilder::from(stream)
394 .open_style(self.style_type, &self.style_id)?
395 .add_child(&self.name)?
396 .add_child(&self.run_property)?
397 .add_child(&self.paragraph_property)?
398 .apply_if(self.style_type == StyleType::Table, |b| {
399 b.add_child(&self.table_cell_property)?
400 .add_child(&self.table_property)
401 })?
402 .add_optional_child(&self.next)?
403 .add_optional_child(&self.link)?
404 .apply_if(self.q_format, |b| b.add_child(&QFormat::new()))?
405 .apply_if(self.ui_priority.is_some(), |b| {
406 b.ui_priority(self.ui_priority.unwrap_or_default())
407 })?
408 .apply_if(self.semi_hidden, |b| b.semi_hidden())?
409 .apply_if(self.unhide_when_used, |b| b.unhide_when_used())?
410 .add_optional_child(&self.based_on)?
411 .close()?
412 .into_inner()
413 }
414}
415
416#[cfg(test)]
417mod tests {
418
419 use super::*;
420 #[cfg(test)]
421 use pretty_assertions::assert_eq;
422 use std::str;
423
424 #[test]
425 fn test_build() {
426 let c = Style::new("Heading", StyleType::Paragraph).name("Heading1");
427 let b = c.build();
428 assert_eq!(
429 str::from_utf8(&b).unwrap(),
430 r#"<w:style w:type="paragraph" w:styleId="Heading"><w:name w:val="Heading1" /><w:rPr /><w:pPr><w:rPr /></w:pPr><w:qFormat /></w:style>"#
431 );
432 }
433
434 #[test]
435 fn test_build_with_visibility_flags() {
436 let c = Style::new("MyStyle", StyleType::Paragraph)
437 .name("My Style")
438 .q_format(false)
439 .ui_priority(99)
440 .semi_hidden()
441 .unhide_when_used();
442 let b = c.build();
443 assert_eq!(
444 str::from_utf8(&b).unwrap(),
445 r#"<w:style w:type="paragraph" w:styleId="MyStyle"><w:name w:val="My Style" /><w:rPr /><w:pPr><w:rPr /></w:pPr><w:uiPriority w:val="99" /><w:semiHidden /><w:unhideWhenUsed /></w:style>"#
446 );
447 }
448}