use crate::layout::box_model::{IntrinsicSize, LayoutConstraint};
use crate::text::TextEngine;
use crate::view::paint::TextStyle;
pub trait Measurable: Send + Sync {
fn measure(&self, constraint: &LayoutConstraint) -> IntrinsicSize;
fn clone_box(&self) -> Box<dyn Measurable>;
}
impl Clone for Box<dyn Measurable> {
fn clone(&self) -> Self {
self.clone_box()
}
}
impl std::fmt::Debug for dyn Measurable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Measurable").finish()
}
}
#[derive(Clone, Debug)]
pub struct TextMeasure {
pub content: String,
pub style: TextStyle,
pub extra_width: f32,
pub fixed_height: Option<f32>,
}
impl TextMeasure {
pub fn new(content: impl Into<String>, font_size: f64) -> Self {
Self {
content: content.into(),
style: TextStyle {
font_size,
..TextStyle::default()
},
extra_width: 0.0,
fixed_height: None,
}
}
pub fn with_style(mut self, style: TextStyle) -> Self {
self.style = style;
self
}
pub fn with_extra_width(mut self, w: f32) -> Self {
self.extra_width = w;
self
}
pub fn with_fixed_height(mut self, h: f32) -> Self {
self.fixed_height = Some(h);
self
}
}
impl Measurable for TextMeasure {
fn measure(&self, constraint: &LayoutConstraint) -> IntrinsicSize {
let mut style = self.style.clone();
if style.wrap {
style.max_width = if constraint.max_width < f32::MAX {
Some((constraint.max_width - self.extra_width.max(0.0)) as f64)
} else {
None
};
}
let (mw, mh) = TextEngine::measure_text(&self.content, &style);
let w = (mw as f32 + self.extra_width).clamp(constraint.min_width, constraint.max_width);
let h = match self.fixed_height {
Some(h) => h.clamp(constraint.min_height, constraint.max_height),
None => mh as f32,
};
IntrinsicSize::new(w, h)
}
fn clone_box(&self) -> Box<dyn Measurable> {
Box::new(self.clone())
}
}
#[derive(Clone, Copy, Debug)]
pub struct FixedMeasure {
pub size: IntrinsicSize,
}
impl FixedMeasure {
pub fn new(size: IntrinsicSize) -> Self {
Self { size }
}
}
impl Measurable for FixedMeasure {
fn measure(&self, constraint: &LayoutConstraint) -> IntrinsicSize {
IntrinsicSize::new(
self.size
.width
.clamp(constraint.min_width, constraint.max_width),
self.size
.height
.clamp(constraint.min_height, constraint.max_height),
)
}
fn clone_box(&self) -> Box<dyn Measurable> {
Box::new(*self)
}
}
#[derive(Clone, Copy, Debug)]
pub struct EmptyMeasure;
impl Measurable for EmptyMeasure {
fn measure(&self, _constraint: &LayoutConstraint) -> IntrinsicSize {
IntrinsicSize::zero()
}
fn clone_box(&self) -> Box<dyn Measurable> {
Box::new(*self)
}
}