mathml_core/operators/
constructors.rs

1use super::*;
2
3impl MathElement for MathOperator {
4    fn tag_name(&self) -> &'static str {
5        "mo"
6    }
7
8    fn get_attributes(&self) -> &BTreeMap<String, String> {
9        &self.attributes
10    }
11
12    fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
13        &mut self.attributes
14    }
15}
16
17impl MathOperator {
18    /// Create a simple math operator without any attributes.
19    pub fn new<S>(text: S) -> Self
20    where
21        S: ToString,
22    {
23        Self { operator: text.to_string(), attributes: Default::default() }
24    }
25    /// Mark the operator as a fence (such as parentheses). There is no visual effect for this attribute.
26    pub fn mark_fence(self) -> Self {
27        self.with_attribute("fence", true)
28    }
29    ///  Mark the operator as a separator (such as commas). There is no visual effect for this attribute.
30    pub fn mark_separator(self) -> Self {
31        self.with_attribute("separator", true)
32    }
33    /// Mark the operator should be drawn bigger when math-style is set to normal.
34    pub fn mark_large_operator(self) -> Self {
35        self.with_attribute("largeop", true)
36    }
37    /// Mark the operator stretches to the size of the adjacent element.
38    pub fn mark_stretchy(self) -> Self {
39        self.with_attribute("stretchy", true)
40    }
41    /// Mark the stretchy operator should be vertically symmetric around the imaginary math axis (centered fraction line).
42    pub fn mark_symmetric(self) -> Self {
43        self.mark_stretchy().with_attribute("symmetric", true)
44    }
45    /// Config the space before and after the operator.
46    pub fn with_space(self, lhs: f32, rhs: f32) -> Self {
47        self.with_attribute("lspace", lhs).with_attribute("rspace", rhs)
48    }
49    /// Config the minimum and maximum size of the operator when it is stretchy.
50    pub fn with_size(self, min: f32, max: f32) -> Self {
51        self.mark_stretchy().with_attribute("minsize", min).with_attribute("maxsize", max)
52    }
53}
54
55impl Default for MathSpace {
56    fn default() -> Self {
57        MathSpace::new(1.0)
58    }
59}
60
61impl MathElement for MathSpace {
62    fn tag_name(&self) -> &'static str {
63        "mspace"
64    }
65
66    fn get_attributes(&self) -> &BTreeMap<String, String> {
67        &self.attributes
68    }
69
70    fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
71        &mut self.attributes
72    }
73}
74
75impl MathSpace {
76    /// Create a simple math space without any attributes, the unit is `rem`.
77    pub fn new(width: f32) -> Self {
78        let mut attributes = BTreeMap::new();
79        attributes.insert("width".to_string(), format!("{}rem", width));
80        Self { attributes }
81    }
82}
83
84impl MathElement for MathSqrt {
85    fn tag_name(&self) -> &'static str {
86        if self.surd.is_none() { "msqrt" } else { "mroot" }
87    }
88
89    fn get_attributes(&self) -> &BTreeMap<String, String> {
90        todo!()
91    }
92
93    fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
94        todo!()
95    }
96}
97
98impl MathSqrt {
99    /// Create a new square root element with the given base and the given left and right fence characters.
100    pub fn sqrt(base: MathML) -> Self {
101        Self { base, surd: None }
102    }
103    /// Create a new square root element with the given base and the given left and right fence characters.
104    pub fn surd(base: MathML, power: MathML) -> Self {
105        Self { base, surd: Some(power) }
106    }
107}
108
109impl MathElement for MathMultiScript {
110    fn tag_name(&self) -> &'static str {
111        if self.is_sub_super_script() {
112            "msubsup"
113        }
114        else if self.is_sub_script() {
115            "msub"
116        }
117        else if self.is_super_script() {
118            "msup"
119        }
120        else {
121            "mmultiscripts"
122        }
123    }
124
125    fn get_attributes(&self) -> &BTreeMap<String, String> {
126        &self.attributes
127    }
128
129    fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
130        &mut self.attributes
131    }
132}
133
134impl MathMultiScript {
135    /// Create a new multi script element with the given base and the given left and right fence characters.
136    pub fn new(base: MathML, lu: Vec<MathML>, ld: Vec<MathML>, ru: Vec<MathML>, rd: Vec<MathML>) -> Self {
137        Self { base, ru, rd, lu, ld, attributes: BTreeMap::new() }
138    }
139    /// Create a new multi script element with the given base and the given left and right fence characters.
140    pub fn sub_script(base: MathML, sub: MathML) -> Self {
141        MathMultiScript::new(base, vec![], vec![], vec![], vec![sub])
142    }
143    /// Create a new multi script element with the given base and the given left and right fence characters.
144    pub fn is_sub_script(&self) -> bool {
145        self.lu.is_empty() && self.ld.is_empty() && self.ru.is_empty() && self.rd.len() == 1
146    }
147    /// Create a new multi script element with the given base and the given left and right fence characters.
148    pub fn super_script(base: MathML, sup: MathML) -> Self {
149        MathMultiScript::new(base, vec![], vec![], vec![sup], vec![])
150    }
151    /// Create a new multi script element with the given base and the given left and right fence characters.
152    pub fn is_super_script(&self) -> bool {
153        self.lu.is_empty() && self.ld.is_empty() && self.ru.len() == 1 && self.rd.is_empty()
154    }
155    /// Create a new multi script element with the given base and the given left and right fence characters.
156    pub fn sub_super_script(base: MathML, sub: MathML, sup: MathML) -> Self {
157        MathMultiScript::new(base, vec![], vec![], vec![sup], vec![sub])
158    }
159    /// Create a new multi script element with the given base and the given left and right fence characters.
160    pub fn is_sub_super_script(&self) -> bool {
161        self.lu.is_empty() && self.ld.is_empty() && self.ru.len() == 1 && self.rd.len() == 1
162    }
163}
164
165impl MathFenced {
166    /// Create a new fenced element with the given base and the given left and right fence characters.
167    pub fn new<I>(base: I, lhs: char, rhs: char) -> Self
168    where
169        I: IntoIterator<Item = MathML>,
170    {
171        Self { base: base.into_iter().collect(), open: lhs, close: rhs, separators: String::new() }
172    }
173    /// Create a new fenced element with the given base and the given left and right fence characters.
174    pub fn parentheses<I>(base: I) -> Self
175    where
176        I: IntoIterator<Item = MathML>,
177    {
178        Self::new(base, '(', ')')
179    }
180    /// Create a new fenced element with the given base and the given left and right fence characters.
181    pub fn brackets<I>(base: I) -> Self
182    where
183        I: IntoIterator<Item = MathML>,
184    {
185        Self::new(base, '[', ']')
186    }
187    /// Create a new fenced element with the given base and the given left and right fence characters.
188    pub fn curly<I>(base: I) -> Self
189    where
190        I: IntoIterator<Item = MathML>,
191    {
192        Self::new(base, '{', '}')
193    }
194    /// A string of characters to be inserted between consecutive pairs of elements in the list.
195    pub fn with_separators<S>(mut self, separators: S) -> Self
196    where
197        S: ToString,
198    {
199        self.separators = separators.to_string();
200        self
201    }
202}
203
204impl MathElement for MathUnderOver {
205    fn tag_name(&self) -> &'static str {
206        match (&self.under, &self.over) {
207            (Some(_), Some(_)) => "munderover",
208            (Some(_), None) => "munder",
209            (None, Some(_)) => "mover",
210            (None, None) => unreachable!("MathUnderOver must have at least one of under or over"),
211        }
212    }
213
214    fn get_attributes(&self) -> &BTreeMap<String, String> {
215        &self.attributes
216    }
217
218    fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
219        &mut self.attributes
220    }
221}
222
223impl MathUnderOver {
224    /// Creates a new `MathUnderOver` element with the given base and optional under and over elements.
225    pub fn under(base: MathML, under: MathML) -> Self {
226        Self { base, under: Some(under), over: None, attributes: BTreeMap::new() }
227    }
228    /// Creates a new `MathUnderOver` element with the given base and optional under and over elements.
229    pub fn over(base: MathML, over: MathML) -> Self {
230        Self { base, under: None, over: Some(over), attributes: BTreeMap::new() }
231    }
232    /// Creates a new `MathUnderOver` element with the given base and optional under and over elements.
233    pub fn under_over(base: MathML, under: MathML, over: MathML) -> Self {
234        Self { base, under: Some(under), over: Some(over), attributes: BTreeMap::new() }
235    }
236    /// Creates a new `MathUnderOver` element with the given base and optional under and over elements.
237    pub fn with_accent_over(self) -> Self {
238        self.with_attribute("accent", true)
239    }
240    /// Creates a new `MathUnderOver` element with the given base and optional under and over elements.
241    pub fn with_accent_under(self) -> Self {
242        self.with_attribute("accentunder", true)
243    }
244}
245
246impl MathML {
247    /// Create a new MathML element with the given tag name.
248    pub fn operation<S>(text: S) -> Self
249    where
250        S: ToString,
251    {
252        MathOperator::new(text).into()
253    }
254}