use cranpose_core::NodeId;
use cranpose_foundation::ModifierNodeContext;
use cranpose_ui_layout::{Constraints, Measurable, Placeable};
use std::cell::{Cell, RefCell};
use std::rc::Rc;
use crate::layout::{LayoutNodeContext, MeasurePolicy, MeasureResult};
use crate::modifier::{Point, Size};
pub trait NodeCoordinator: Measurable {
fn total_content_offset(&self) -> Point;
}
pub struct LayoutModifierCoordinator<'a> {
node: Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
wrapped: Box<dyn NodeCoordinator + 'a>,
measured_size: Cell<Size>,
accumulated_offset: Cell<Point>,
context: Rc<RefCell<LayoutNodeContext>>,
}
impl<'a> LayoutModifierCoordinator<'a> {
#[allow(private_interfaces)]
pub fn new(
node: Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
wrapped: Box<dyn NodeCoordinator + 'a>,
context: Rc<RefCell<LayoutNodeContext>>,
) -> Self {
Self {
node,
wrapped,
measured_size: Cell::new(Size::default()),
accumulated_offset: Cell::new(Point::default()),
context,
}
}
}
impl<'a> NodeCoordinator for LayoutModifierCoordinator<'a> {
fn total_content_offset(&self) -> Point {
self.accumulated_offset.get()
}
}
impl<'a> Measurable for LayoutModifierCoordinator<'a> {
fn measure(&self, constraints: Constraints) -> Placeable {
let node_borrow = self.node.borrow();
let result = {
if let Some(layout_node) = node_borrow.as_layout_node() {
match self.context.try_borrow_mut() {
Ok(mut context) => {
layout_node.measure(&mut *context, self.wrapped.as_ref(), constraints)
}
Err(_) => {
let mut temp = LayoutNodeContext::new();
let result =
layout_node.measure(&mut temp, self.wrapped.as_ref(), constraints);
if let Ok(mut shared) = self.context.try_borrow_mut() {
for kind in temp.take_invalidations() {
shared.invalidate(kind);
}
}
result
}
}
} else {
let placeable = self.wrapped.measure(constraints);
let child_accumulated = self.wrapped.total_content_offset();
self.accumulated_offset.set(child_accumulated);
return Placeable::value_with_offset(
placeable.width(),
placeable.height(),
NodeId::default(),
(child_accumulated.x, child_accumulated.y),
);
}
};
self.measured_size.set(result.size);
let local_offset = Point {
x: result.placement_offset_x,
y: result.placement_offset_y,
};
let child_accumulated = self.wrapped.total_content_offset();
let accumulated = Point {
x: local_offset.x + child_accumulated.x,
y: local_offset.y + child_accumulated.y,
};
self.accumulated_offset.set(accumulated);
Placeable::value_with_offset(
result.size.width,
result.size.height,
NodeId::default(),
(accumulated.x, accumulated.y),
)
}
fn min_intrinsic_width(&self, height: f32) -> f32 {
let node_borrow = self.node.borrow();
if let Some(layout_node) = node_borrow.as_layout_node() {
layout_node.min_intrinsic_width(self.wrapped.as_ref(), height)
} else {
self.wrapped.min_intrinsic_width(height)
}
}
fn max_intrinsic_width(&self, height: f32) -> f32 {
let node_borrow = self.node.borrow();
if let Some(layout_node) = node_borrow.as_layout_node() {
layout_node.max_intrinsic_width(self.wrapped.as_ref(), height)
} else {
self.wrapped.max_intrinsic_width(height)
}
}
fn min_intrinsic_height(&self, width: f32) -> f32 {
let node_borrow = self.node.borrow();
if let Some(layout_node) = node_borrow.as_layout_node() {
layout_node.min_intrinsic_height(self.wrapped.as_ref(), width)
} else {
self.wrapped.min_intrinsic_height(width)
}
}
fn max_intrinsic_height(&self, width: f32) -> f32 {
let node_borrow = self.node.borrow();
if let Some(layout_node) = node_borrow.as_layout_node() {
layout_node.max_intrinsic_height(self.wrapped.as_ref(), width)
} else {
self.wrapped.max_intrinsic_height(width)
}
}
}
pub struct InnerCoordinator<'a> {
measure_policy: Rc<dyn MeasurePolicy>,
measurables: &'a [Box<dyn Measurable>],
measured_size: Cell<Size>,
result_holder: Rc<RefCell<Option<MeasureResult>>>,
}
impl<'a> InnerCoordinator<'a> {
pub fn new(
measure_policy: Rc<dyn MeasurePolicy>,
measurables: &'a [Box<dyn Measurable>],
result_holder: Rc<RefCell<Option<MeasureResult>>>,
) -> Self {
Self {
measure_policy,
measurables,
measured_size: Cell::new(Size::ZERO),
result_holder,
}
}
}
impl<'a> NodeCoordinator for InnerCoordinator<'a> {
fn total_content_offset(&self) -> Point {
Point::default()
}
}
impl<'a> Measurable for InnerCoordinator<'a> {
fn measure(&self, constraints: Constraints) -> Placeable {
let result = self.measure_policy.measure(self.measurables, constraints);
let size = result.size;
self.measured_size.set(size);
*self.result_holder.borrow_mut() = Some(result);
Placeable::value(size.width, size.height, NodeId::default())
}
fn min_intrinsic_width(&self, height: f32) -> f32 {
self.measure_policy
.min_intrinsic_width(self.measurables, height)
}
fn max_intrinsic_width(&self, height: f32) -> f32 {
self.measure_policy
.max_intrinsic_width(self.measurables, height)
}
fn min_intrinsic_height(&self, width: f32) -> f32 {
self.measure_policy
.min_intrinsic_height(self.measurables, width)
}
fn max_intrinsic_height(&self, width: f32) -> f32 {
self.measure_policy
.max_intrinsic_height(self.measurables, width)
}
}