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 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
use super::*;
// noinspection SpellCheckingInspection
impl MathElement for MathOperator {
fn tag_name(&self) -> &'static str {
"mo"
}
fn get_attributes(&self) -> &BTreeMap<String, String> {
&self.attributes
}
fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
&mut self.attributes
}
}
// noinspection SpellCheckingInspection
impl MathOperator {
/// Create a simple math operator without any attributes.
pub fn new<S>(text: S) -> Self
where
S: ToString,
{
Self { operator: text.to_string(), attributes: Default::default() }
}
/// Mark the operator as a fence (such as parentheses). There is no visual effect for this attribute.
pub fn mark_fence(self) -> Self {
self.with_attribute("fence", true)
}
/// Mark the operator as a separator (such as commas). There is no visual effect for this attribute.
pub fn mark_separator(self) -> Self {
self.with_attribute("separator", true)
}
/// Mark the operator should be drawn bigger when math-style is set to normal.
pub fn mark_large_operator(self) -> Self {
self.with_attribute("largeop", true)
}
/// Mark the operator stretches to the size of the adjacent element.
pub fn mark_stretchy(self) -> Self {
self.with_attribute("stretchy", true)
}
/// Mark the stretchy operator should be vertically symmetric around the imaginary math axis (centered fraction line).
pub fn mark_symmetric(self) -> Self {
self.mark_stretchy().with_attribute("symmetric", true)
}
/// Config the space before and after the operator.
pub fn with_space(self, lhs: f32, rhs: f32) -> Self {
self.with_attribute("lspace", lhs).with_attribute("rspace", rhs)
}
/// Config the minimun and maximum size of the operator when it is stretchy.
pub fn with_size(self, min: f32, max: f32) -> Self {
self.mark_stretchy().with_attribute("minsize", min).with_attribute("maxsize", max)
}
}
impl Default for MathSpace {
fn default() -> Self {
MathSpace::new(1.0)
}
}
// noinspection SpellCheckingInspection
impl MathElement for MathSpace {
fn tag_name(&self) -> &'static str {
"mspace"
}
fn get_attributes(&self) -> &BTreeMap<String, String> {
&self.attributes
}
fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
&mut self.attributes
}
}
impl MathSpace {
/// Create a simple math space without any attributes, the unit is `rem`.
pub fn new(width: f32) -> Self {
let mut attributes = BTreeMap::new();
attributes.insert("width".to_string(), format!("{}rem", width));
Self { attributes }
}
}
impl MathSqrt {
/// Create a new square root element with the given base and the given left and right fence characters.
pub fn sqrt(base: MathML) -> Self {
Self { base, surd: None }
}
/// Create a new square root element with the given base and the given left and right fence characters.
pub fn surd(base: MathML, power: MathML) -> Self {
Self { base, surd: Some(power) }
}
}
// noinspection SpellCheckingInspection
impl MathElement for MathMultiScript {
fn tag_name(&self) -> &'static str {
if self.is_sub_super_script() {
"msubsup"
}
else if self.is_sub_script() {
"msub"
}
else if self.is_super_script() {
"msup"
}
else {
"mmultiscripts"
}
}
fn get_attributes(&self) -> &BTreeMap<String, String> {
&self.attributes
}
fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
&mut self.attributes
}
}
impl MathMultiScript {
/// Create a new multi script element with the given base and the given left and right fence characters.
pub fn new(base: MathML, lu: Vec<MathML>, ld: Vec<MathML>, ru: Vec<MathML>, rd: Vec<MathML>) -> Self {
Self { base, ru, rd, lu, ld, attributes: BTreeMap::new() }
}
/// Create a new multi script element with the given base and the given left and right fence characters.
pub fn sub_script(base: MathML, sub: MathML) -> Self {
MathMultiScript::new(base, vec![], vec![], vec![], vec![sub])
}
/// Create a new multi script element with the given base and the given left and right fence characters.
pub fn is_sub_script(&self) -> bool {
self.lu.is_empty() && self.ld.is_empty() && self.ru.is_empty() && self.rd.len() == 1
}
/// Create a new multi script element with the given base and the given left and right fence characters.
pub fn super_script(base: MathML, sup: MathML) -> Self {
MathMultiScript::new(base, vec![], vec![], vec![sup], vec![])
}
/// Create a new multi script element with the given base and the given left and right fence characters.
pub fn is_super_script(&self) -> bool {
self.lu.is_empty() && self.ld.is_empty() && self.ru.len() == 1 && self.rd.is_empty()
}
/// Create a new multi script element with the given base and the given left and right fence characters.
pub fn sub_super_script(base: MathML, sub: MathML, sup: MathML) -> Self {
MathMultiScript::new(base, vec![], vec![], vec![sup], vec![sub])
}
/// Create a new multi script element with the given base and the given left and right fence characters.
pub fn is_sub_super_script(&self) -> bool {
self.lu.is_empty() && self.ld.is_empty() && self.ru.len() == 1 && self.rd.len() == 1
}
}
impl MathFenced {
/// Create a new fenced element with the given base and the given left and right fence characters.
pub fn new<I>(base: I, lhs: char, rhs: char) -> Self
where
I: IntoIterator<Item = MathML>,
{
Self { base: base.into_iter().collect(), open: lhs, close: rhs, separators: String::new() }
}
/// Create a new fenced element with the given base and the given left and right fence characters.
pub fn parentheses<I>(base: I) -> Self
where
I: IntoIterator<Item = MathML>,
{
Self::new(base, '(', ')')
}
/// Create a new fenced element with the given base and the given left and right fence characters.
pub fn brackets<I>(base: I) -> Self
where
I: IntoIterator<Item = MathML>,
{
Self::new(base, '[', ']')
}
/// Create a new fenced element with the given base and the given left and right fence characters.
pub fn curly<I>(base: I) -> Self
where
I: IntoIterator<Item = MathML>,
{
Self::new(base, '{', '}')
}
/// A string of characters to be inserted between consecutive pairs of elements in the list.
pub fn with_separators<S>(mut self, separators: S) -> Self
where
S: ToString,
{
self.separators = separators.to_string();
self
}
}
// noinspection SpellCheckingInspection
impl MathElement for MathUnderOver {
fn tag_name(&self) -> &'static str {
match (&self.under, &self.over) {
(Some(_), Some(_)) => "munderover",
(Some(_), None) => "munder",
(None, Some(_)) => "mover",
(None, None) => unreachable!("MathUnderOver must have at least one of under or over"),
}
}
fn get_attributes(&self) -> &BTreeMap<String, String> {
&self.attributes
}
fn mut_attributes(&mut self) -> &mut BTreeMap<String, String> {
&mut self.attributes
}
}
// noinspection SpellCheckingInspection
impl MathUnderOver {
/// Creates a new `MathUnderOver` element with the given base and optional under and over elements.
pub fn under(base: MathML, under: MathML) -> Self {
Self { base, under: Some(under), over: None, attributes: BTreeMap::new() }
}
/// Creates a new `MathUnderOver` element with the given base and optional under and over elements.
pub fn over(base: MathML, over: MathML) -> Self {
Self { base, under: None, over: Some(over), attributes: BTreeMap::new() }
}
/// Creates a new `MathUnderOver` element with the given base and optional under and over elements.
pub fn under_over(base: MathML, under: MathML, over: MathML) -> Self {
Self { base, under: Some(under), over: Some(over), attributes: BTreeMap::new() }
}
/// Creates a new `MathUnderOver` element with the given base and optional under and over elements.
pub fn with_accent_over(self) -> Self {
self.with_attribute("accent", true)
}
/// Creates a new `MathUnderOver` element with the given base and optional under and over elements.
pub fn with_accent_under(self) -> Self {
self.with_attribute("accentunder", true)
}
}
impl MathML {
/// Create a new MathML element with the given tag name.
pub fn operation<S>(text: S) -> Self
where
S: ToString,
{
MathOperator::new(text).into()
}
}