use std::collections::BTreeMap;
use zenith_core::{
Diagnostic, Dimension, PropertyValue, ResolvedToken, ResolvedValue, Span, Unit, dim_to_px,
};
use crate::ir::BlendMode;
pub(super) fn rotation_degrees(rotate: Option<&Dimension>) -> Option<f64> {
rotate.map(|d| d.value).filter(|a| *a != 0.0)
}
pub(super) fn blend_mode_ir(s: Option<&str>) -> Option<BlendMode> {
match s {
Some("multiply") => Some(BlendMode::Multiply),
Some("screen") => Some(BlendMode::Screen),
Some("overlay") => Some(BlendMode::Overlay),
Some("darken") => Some(BlendMode::Darken),
Some("lighten") => Some(BlendMode::Lighten),
Some("color-dodge") => Some(BlendMode::ColorDodge),
Some("color-burn") => Some(BlendMode::ColorBurn),
Some("hard-light") => Some(BlendMode::HardLight),
Some("soft-light") => Some(BlendMode::SoftLight),
Some("difference") => Some(BlendMode::Difference),
Some("exclusion") => Some(BlendMode::Exclusion),
_ => None,
}
}
pub(super) fn unsupported_unit_diag(
kind: &str,
node_id: &str,
field: &str,
span: Option<Span>,
) -> Diagnostic {
Diagnostic::advisory(
"scene.unsupported_unit",
format!(
"{} '{}' field '{}' uses an unsupported unit; the {} is skipped",
kind, node_id, field, kind
),
span,
Some(node_id.to_owned()),
)
}
pub(super) fn missing_geometry_diag(kind: &str, node_id: &str, span: Option<Span>) -> Diagnostic {
Diagnostic::advisory(
"scene.missing_geometry",
format!(
"{kind} '{node_id}' is missing one or more geometry properties (x, y, w, h); \
skipped"
),
span,
Some(node_id.to_owned()),
)
}
#[derive(Clone, Copy)]
pub(super) struct AxisTarget<'a> {
pub(super) kind: &'a str,
pub(super) node_id: &'a str,
pub(super) axis: &'a str,
}
pub(super) fn resolve_anchored_axis(
target: AxisTarget<'_>,
dim: Option<&PropertyValue>,
resolved: &BTreeMap<String, ResolvedToken>,
anchor_val: Option<f64>,
span: Option<Span>,
diagnostics: &mut Vec<Diagnostic>,
) -> Option<f64> {
match dim {
Some(prop) => match resolve_geometry_px(Some(prop), resolved) {
Some(v) => Some(v),
None => {
diagnostics.push(unsupported_unit_diag(
target.kind,
target.node_id,
target.axis,
span,
));
None
}
},
None => match anchor_val {
Some(v) => Some(v),
None => {
diagnostics.push(missing_geometry_diag(target.kind, target.node_id, span));
None
}
},
}
}
pub(super) fn px(v: f64) -> Dimension {
Dimension {
value: v,
unit: Unit::Px,
}
}
pub(super) fn px_prop(v: f64) -> PropertyValue {
PropertyValue::Dimension(px(v))
}
pub(super) fn resolve_property_dimension_px(
prop: Option<&PropertyValue>,
resolved: &BTreeMap<String, ResolvedToken>,
default: f64,
) -> f64 {
match prop {
Some(PropertyValue::TokenRef(token_id)) => match resolved.get(token_id.as_str()) {
Some(rt) => match &rt.value {
ResolvedValue::Dimension(dim) => dim_to_px(dim.value, &dim.unit).unwrap_or(default),
ResolvedValue::Color(_)
| ResolvedValue::CmykColor { .. }
| ResolvedValue::Number(_)
| ResolvedValue::FontFamily(_)
| ResolvedValue::FontWeight(_)
| ResolvedValue::Gradient(_)
| ResolvedValue::Shadow(_)
| ResolvedValue::Filter(_)
| ResolvedValue::Mask(_) => default,
},
None => default,
},
Some(PropertyValue::Dimension(dim)) => dim_to_px(dim.value, &dim.unit).unwrap_or(default),
Some(PropertyValue::Literal(_)) | Some(PropertyValue::DataRef(_)) | None => default,
}
}
pub(super) fn resolve_geometry_px(
prop: Option<&PropertyValue>,
resolved: &BTreeMap<String, ResolvedToken>,
) -> Option<f64> {
match prop? {
PropertyValue::TokenRef(id) => match resolved.get(id.as_str()) {
Some(rt) => match &rt.value {
ResolvedValue::Dimension(d) => dim_to_px(d.value, &d.unit),
ResolvedValue::Color(_)
| ResolvedValue::CmykColor { .. }
| ResolvedValue::Number(_)
| ResolvedValue::FontFamily(_)
| ResolvedValue::FontWeight(_)
| ResolvedValue::Gradient(_)
| ResolvedValue::Shadow(_)
| ResolvedValue::Filter(_)
| ResolvedValue::Mask(_) => None,
},
None => None,
},
PropertyValue::Dimension(d) => dim_to_px(d.value, &d.unit),
PropertyValue::Literal(_) | PropertyValue::DataRef(_) => None,
}
}