use std::num::NonZeroUsize;
use codex::styling::MathVariant;
use ecow::EcoString;
use typst_utils::NonZeroExt;
use unicode_math_class::MathClass;
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{
Content, NativeElement, Packed, ShowSet, Smart, StyleChain, Styles, Synthesize, elem,
};
use crate::introspection::{Count, Counter, CounterUpdate, Locatable, Tagged};
use crate::layout::{
AlignElem, Alignment, BlockElem, OuterHAlignment, SpecificAlignment, VAlignment,
};
use crate::math::MathSize;
use crate::model::{Numbering, Outlinable, ParLine, Refable, Supplement};
use crate::text::{FontFamily, FontList, FontWeight, LocalName, Locale, TextElem};
#[elem(Locatable, Tagged, Synthesize, ShowSet, Count, LocalName, Refable, Outlinable)]
pub struct EquationElem {
#[default(false)]
pub block: bool,
pub numbering: Option<Numbering>,
#[default(SpecificAlignment::Both(OuterHAlignment::End, VAlignment::Horizon))]
pub number_align: SpecificAlignment<OuterHAlignment, VAlignment>,
pub supplement: Smart<Option<Supplement>>,
pub alt: Option<EcoString>,
#[required]
pub body: Content,
#[internal]
#[default(MathSize::Text)]
#[ghost]
pub size: MathSize,
#[internal]
#[ghost]
pub variant: Option<MathVariant>,
#[internal]
#[default(false)]
#[ghost]
pub cramped: bool,
#[internal]
#[default(false)]
#[ghost]
pub bold: bool,
#[internal]
#[ghost]
pub italic: Option<bool>,
#[internal]
#[ghost]
pub class: Option<MathClass>,
#[internal]
#[default((70, 50))]
#[ghost]
pub script_scale: (i16, i16),
#[internal]
#[synthesized]
pub locale: Locale,
}
impl Synthesize for Packed<EquationElem> {
fn synthesize(
&mut self,
engine: &mut Engine,
styles: StyleChain,
) -> SourceResult<()> {
let supplement = match self.as_ref().supplement.get_ref(styles) {
Smart::Auto => TextElem::packed(Self::local_name_in(styles)),
Smart::Custom(None) => Content::empty(),
Smart::Custom(Some(supplement)) => {
supplement.resolve(engine, styles, [self.clone().pack()])?
}
};
self.supplement
.set(Smart::Custom(Some(Supplement::Content(supplement))));
self.locale = Some(Locale::get_in(styles));
Ok(())
}
}
impl ShowSet for Packed<EquationElem> {
fn show_set(&self, styles: StyleChain) -> Styles {
let mut out = Styles::new();
if self.block.get(styles) {
out.set(AlignElem::alignment, Alignment::CENTER);
out.set(BlockElem::breakable, false);
out.set(ParLine::numbering, None);
out.set(EquationElem::size, MathSize::Display);
} else {
out.set(EquationElem::size, MathSize::Text);
}
out.set(TextElem::weight, FontWeight::from_number(450));
out.set(
TextElem::font,
FontList(vec![FontFamily::new("New Computer Modern Math")]),
);
out
}
}
impl Count for Packed<EquationElem> {
fn update(&self) -> Option<CounterUpdate> {
(self.block.get(StyleChain::default()) && self.numbering().is_some())
.then(|| CounterUpdate::Step(NonZeroUsize::ONE))
}
}
impl LocalName for Packed<EquationElem> {
const KEY: &'static str = "equation";
}
impl Refable for Packed<EquationElem> {
fn supplement(&self) -> Content {
match self.supplement.get_cloned(StyleChain::default()) {
Smart::Custom(Some(Supplement::Content(content))) => content,
_ => Content::empty(),
}
}
fn counter(&self) -> Counter {
Counter::of(EquationElem::ELEM)
}
fn numbering(&self) -> Option<&Numbering> {
self.numbering.get_ref(StyleChain::default()).as_ref()
}
}
impl Outlinable for Packed<EquationElem> {
fn outlined(&self) -> bool {
self.block.get(StyleChain::default()) && self.numbering().is_some()
}
fn prefix(&self, numbers: Content) -> Content {
let supplement = self.supplement();
if !supplement.is_empty() {
supplement + TextElem::packed('\u{a0}') + numbers
} else {
numbers
}
}
fn body(&self) -> Content {
Content::empty()
}
}