1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
use std::collections::BTreeMap;
#[cfg(feature = "serde")]
use serde::Serialize;
use crate::{
common_types::HexColor,
packaging::relationship::XlsxRelationships,
raw::drawing::{
scheme::color_scheme::XlsxColorScheme,
st_types::{st_percentage_to_float, st_text_point_to_pt},
text::paragraph::paragraph_properties::XlsxParagraphProperties,
},
};
use super::{
auto_numbered_bullet::AutoNumberedBullet, character_bullet::CharacterBullet,
picture_bullet::PictureBullet,
};
/// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.defaultrunproperties?view=openxml-3.0.1
///
/// This element contains all default run level text properties for the text runs within a containing paragraph.
/// These properties are to be used when overriding properties have not been defined within the rPr element
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct Bullet {
/// bullet used in the paragraph
pub r#type: BulletTypeValues,
/// bullet color
///
/// If no bullet color is specified along with this element, then the text color is used.
///
/// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.bulletcolor?view=openxml-3.0.1
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub color: Option<HexColor>,
/// typeface of bullet font
///
/// If no bullet font is specified along with this element then the paragraph font is used.
///
/// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.bulletfont?view=openxml-3.0.1
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub font: Option<String>,
/// Bullet Size
///
/// If no bullet size is specified along with this element then the size of the bullets for a paragraph should be of the same point size as the text run within which each bullet is contained.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub size: Option<BulletSizeTypeValue>,
}
impl Bullet {
pub(crate) fn from_paragraph_properties(
raw: XlsxParagraphProperties,
default: Option<Self>,
drawing_relationship: XlsxRelationships,
image_bytes: BTreeMap<String, Vec<u8>>,
color_scheme: Option<XlsxColorScheme>,
) -> Self {
return Self {
r#type: BulletTypeValues::from_paragraph_properties(
raw.clone(),
if let Some(d) = default.clone() {
Some(d.r#type)
} else {
None
},
drawing_relationship.clone(),
image_bytes.clone(),
color_scheme.clone(),
),
color: if let Some(c) = raw.clone().bullet_color {
c.to_hex(color_scheme.clone(), None)
} else if let Some(d) = default.clone() {
d.color
} else {
None
},
font: if let Some(f) = raw.clone().bullet_font {
f.typeface
} else if let Some(d) = default.clone() {
d.font
} else {
None
},
size: if let Some(s) = raw.clone().bullet_size_percentage {
Some(BulletSizeTypeValue::Percentage(st_percentage_to_float(
s.val.unwrap_or(0) as i64,
)))
} else if let Some(s) = raw.clone().bullet_size_points {
Some(BulletSizeTypeValue::Point(st_text_point_to_pt(
s.val.unwrap_or(0) as i64,
)))
} else if let Some(d) = default.clone() {
d.size
} else {
None
},
};
}
}
impl Bullet {
pub(crate) fn default() -> Self {
Self {
r#type: BulletTypeValues::default(),
color: None,
font: None,
size: None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum BulletTypeValues {
/// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.nobullet?view=openxml-3.0.1
///
/// This element specifies that the paragraph within which it is applied is to have no bullet formatting applied to it.
NoBullet,
/// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.characterbullet?view=openxml-3.0.1
///
/// This element specifies that a character be applied to a set of bullets.
/// These bullets are allowed to be any character in any font that the system is able to support.
CharacterBullet(CharacterBullet),
/// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.autonumberedbullet?view=openxml-3.0.1
///
/// This element specifies that automatic numbered bullet points should be applied to a paragraph.
/// These are not just numbers used as bullet points but instead automatically assigned numbers that are based on both buAutoNum attributes and paragraph level.
AutoNumberedBullet(AutoNumberedBullet),
/// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.picturebullet?view=openxml-3.0.1
///
/// This element specifies that a picture be applied to a set of bullets.
/// This element allows for any standard picture format graphic to be used instead of the typical bullet characters.
PictureBullet(PictureBullet),
}
impl BulletTypeValues {
pub(crate) fn default() -> Self {
Self::NoBullet
}
pub(crate) fn from_paragraph_properties(
raw: XlsxParagraphProperties,
default: Option<Self>,
drawing_relationship: XlsxRelationships,
image_bytes: BTreeMap<String, Vec<u8>>,
color_scheme: Option<XlsxColorScheme>,
) -> Self {
if let Some(bullet) = raw.auto_numbered_bullet.clone() {
return Self::AutoNumberedBullet(AutoNumberedBullet::from_raw(bullet));
};
if let Some(bullet) = raw.character_bullet.clone() {
if let Some(bullet) = CharacterBullet::from_raw(bullet) {
return Self::CharacterBullet(bullet);
}
};
if let Some(bullet) = raw.picture_bullet.clone() {
if let Some(bullet) = PictureBullet::from_raw(
bullet,
drawing_relationship.clone(),
image_bytes.clone(),
color_scheme.clone(),
None,
) {
return Self::PictureBullet(bullet);
}
};
if let Some(default) = default {
return default;
}
return Self::default();
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum BulletSizeTypeValue {
/// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.bulletsizepercentage?view=openxml-3.0.1
///
/// This element specifies the size in percentage of the surrounding text to be used on bullet characters within a given paragraph.
/// The size is specified using a percentage where 1000 is equal to 1 percent of the font size and 100000 is equal to 100 percent font of the font size.
///
/// value range:
/// - a minimum value of greater than or equal to 25000. (25%)
/// - a maximum value of less than or equal to 400000. (400%)
Percentage(f64),
/// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.bulletsizepoints?view=openxml-3.0.1
///
/// This element specifies the size in points to be used on bullet characters within a given paragraph.
/// The size is specified using the points where 100 is equal to 1 point font and 1200 is equal to 12 point font.
///
/// - a minimum value of greater than or equal to 100. (1pt)
/// - a maximum value of less than or equal to 400000. (4000pt)
Point(f64),
}