use crate::core::ElementId;
use crate::layout::Layout;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, Default)]
pub struct Dimensions {
pub width: f32,
pub height: f32,
}
impl From<Layout> for Dimensions {
fn from(layout: Layout) -> Self {
Self {
width: layout.width,
height: layout.height,
}
}
}
#[derive(Clone, Default)]
pub struct MeasureContext {
layouts: HashMap<ElementId, Layout>,
}
impl MeasureContext {
pub fn new() -> Self {
Self {
layouts: HashMap::new(),
}
}
pub fn set_layouts(&mut self, layouts: HashMap<ElementId, Layout>) {
self.layouts = layouts;
}
pub fn measure(&self, element_id: ElementId) -> Option<Dimensions> {
self.layouts
.get(&element_id)
.map(|layout| Dimensions::from(*layout))
}
}
thread_local! {
static MEASURE_CONTEXT: std::cell::RefCell<Option<MeasureContext>> = const { std::cell::RefCell::new(None) };
}
pub(crate) fn set_measure_context(ctx: Option<MeasureContext>) {
MEASURE_CONTEXT.with(|c| {
*c.borrow_mut() = ctx;
});
}
fn get_measure_context() -> Option<MeasureContext> {
MEASURE_CONTEXT.with(|c| c.borrow().clone())
}
pub fn measure_element(element_id: ElementId) -> Option<Dimensions> {
get_measure_context().and_then(|ctx| ctx.measure(element_id))
}
pub fn use_measure() -> (MeasureRef, impl Fn() -> Option<Dimensions>) {
use crate::hooks::use_signal;
let element_id = use_signal(|| None::<ElementId>);
let element_id_clone = element_id.clone();
let measure_ref = MeasureRef { element_id };
let get_dimensions = move || element_id_clone.get().and_then(measure_element);
(measure_ref, get_dimensions)
}
#[derive(Clone)]
pub struct MeasureRef {
element_id: crate::hooks::Signal<Option<ElementId>>,
}
impl MeasureRef {
pub fn set(&self, id: ElementId) {
self.element_id.set(Some(id));
}
pub fn get(&self) -> Option<ElementId> {
self.element_id.get()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::{Element, ElementType};
use crate::layout::LayoutEngine;
#[test]
fn test_dimensions_from_layout() {
let layout = Layout {
x: 0.0,
y: 0.0,
width: 100.0,
height: 50.0,
};
let dims = Dimensions::from(layout);
assert_eq!(dims.width, 100.0);
assert_eq!(dims.height, 50.0);
}
#[test]
fn test_measure_context() {
let mut element = Element::new(ElementType::Box);
element.style.width = crate::core::Dimension::Points(80.0);
element.style.height = crate::core::Dimension::Points(24.0);
let mut engine = LayoutEngine::new();
engine.compute(&element, 100, 100);
let mut ctx = MeasureContext::new();
ctx.set_layouts(engine.get_all_layouts());
let dims = ctx.measure(element.id);
assert!(dims.is_some());
let dims = dims.unwrap();
assert_eq!(dims.width, 80.0);
assert_eq!(dims.height, 24.0);
}
}