use ribir_geom::Size;
use super::{WidgetCtx, WidgetCtxImpl};
use crate::{
prelude::{Point, ProviderCtx},
widget::{BoxClamp, WidgetTree},
widget_tree::WidgetId,
};
pub struct MeasureCtx<'a> {
pub(crate) id: WidgetId,
pub(crate) tree: &'a mut WidgetTree,
pub(crate) provider_ctx: ProviderCtx,
pub(crate) laid_out_queue: &'a mut Vec<WidgetId>,
}
pub struct PlaceCtx<'a> {
pub(crate) id: WidgetId,
pub(crate) tree: &'a mut WidgetTree,
pub(crate) provider_ctx: &'a mut ProviderCtx,
}
impl<'a> WidgetCtxImpl for MeasureCtx<'a> {
#[inline]
fn id(&self) -> WidgetId { self.id }
#[inline]
fn tree(&self) -> &WidgetTree { self.tree }
}
impl<'a> WidgetCtxImpl for PlaceCtx<'a> {
#[inline]
fn id(&self) -> WidgetId { self.id }
#[inline]
fn tree(&self) -> &WidgetTree { self.tree }
}
impl<'a> MeasureCtx<'a> {
pub(crate) fn new(
id: WidgetId, tree: &'a mut WidgetTree, laid_out_queue: &'a mut Vec<WidgetId>,
) -> Self {
let provider_ctx = if let Some(p) = id.parent(tree) {
ProviderCtx::collect_from(p, tree)
} else {
ProviderCtx::default()
};
Self { id, tree, provider_ctx, laid_out_queue }
}
pub(crate) fn perform_layout(&mut self, clamp: BoxClamp) -> Size {
self
.get_calculated_size(self.id, clamp)
.unwrap_or_else(|| {
let tree2 = unsafe { &*(self.tree as *mut WidgetTree) };
let id = self.id();
{
let info = self.tree.store.layout_info_or_default(id);
info.clamp = clamp;
}
debug_assert!(clamp.min.is_finite());
let size = id.assert_get(tree2).measure(clamp, self);
debug_assert!(size.is_finite());
let info = self.tree.store.layout_info_or_default(id);
info.size = Some(size);
{
let mut layout_ctx =
PlaceCtx { id, tree: self.tree, provider_ctx: &mut self.provider_ctx };
layout_ctx.perform_place(size);
}
self.provider_ctx.pop_providers_for(id);
self.laid_out_queue.push(id);
size
})
}
pub fn layout_child(&mut self, child: WidgetId, clamp: BoxClamp) -> Size {
self
.get_calculated_size(child, clamp)
.unwrap_or_else(|| {
let id = std::mem::replace(&mut self.id, child);
let size = self.perform_layout(clamp);
self.id = id;
size
})
}
pub fn clamp(&self) -> BoxClamp {
self
.tree
.store
.layout_info(self.id())
.unwrap()
.clamp
}
#[inline]
pub fn update_size(&mut self, child: WidgetId, size: Size) {
self.tree.store.layout_info_or_default(child).size = Some(size);
}
pub fn split_children(&mut self) -> (&mut Self, impl Iterator<Item = WidgetId> + '_) {
let tree = unsafe { &*(self.tree as *mut WidgetTree) };
let id = self.id;
(self, id.children(tree))
}
pub fn perform_single_child_layout(&mut self, clamp: BoxClamp) -> Option<Size> {
self
.single_child()
.map(|child| self.layout_child(child, clamp))
}
pub fn assert_perform_single_child_layout(&mut self, clamp: BoxClamp) -> Size {
let child = self.assert_single_child();
self.layout_child(child, clamp)
}
#[inline]
pub fn force_child_relayout(&mut self, child: WidgetId) -> bool {
assert_eq!(child.parent(self.tree), Some(self.id));
self.tree.store.force_layout(child).is_some()
}
fn get_calculated_size(&self, child: WidgetId, clamp: BoxClamp) -> Option<Size> {
let info = self.tree.store.layout_info(child)?;
if info.clamp == clamp { info.size } else { None }
}
}
impl<'a> PlaceCtx<'a> {
pub(crate) fn perform_place(&mut self, size: Size) {
let tree2 = unsafe { &*(self.tree as *mut WidgetTree) };
let id = self.id;
for child in id.children(tree2) {
self.tree.store.layout_info_or_default(child).pos = Point::zero();
}
id.assert_get(tree2).place_children(size, self);
let mut buffer = smallvec::SmallVec::new();
self
.provider_ctx
.push_providers_for(id, tree2, &mut buffer);
for child in id.children(tree2) {
self.id = child;
let store = unsafe { &mut (*(&mut *self.tree as *mut WidgetTree)).store };
let pos = store.layout_info_or_default(child).pos;
let pos = child.assert_get(tree2).adjust_position(pos, self);
store.layout_info_or_default(child).pos = pos;
}
self.provider_ctx.pop_providers_for(id);
self.id = id;
}
#[inline]
pub fn update_position(&mut self, child: WidgetId, pos: Point) {
self.tree.store.layout_info_or_default(child).pos = pos;
}
#[inline]
pub fn position(&mut self, child: WidgetId) -> Option<Point> {
self
.tree
.store
.layout_info(child)
.map(|info| info.pos)
}
#[inline]
pub fn clamp(&self) -> BoxClamp {
self
.tree
.store
.layout_info(self.id)
.unwrap()
.clamp
}
pub fn split_children(&mut self) -> (&mut Self, impl Iterator<Item = WidgetId> + '_) {
let tree = unsafe { &*(self.tree as *mut WidgetTree) };
let id = self.id;
(self, id.children(tree))
}
pub fn widget_box_size(&self, widget: WidgetId) -> Option<Size> {
self
.tree
.store
.layout_info(widget)
.and_then(|info| info.size)
}
}
impl<'w> AsRef<ProviderCtx> for MeasureCtx<'w> {
fn as_ref(&self) -> &ProviderCtx { &self.provider_ctx }
}
impl<'w> AsMut<ProviderCtx> for MeasureCtx<'w> {
fn as_mut(&mut self) -> &mut ProviderCtx { &mut self.provider_ctx }
}
impl<'a> AsRef<ProviderCtx> for PlaceCtx<'a> {
fn as_ref(&self) -> &ProviderCtx { self.provider_ctx }
}
impl<'a> AsMut<ProviderCtx> for PlaceCtx<'a> {
fn as_mut(&mut self) -> &mut ProviderCtx { self.provider_ctx }
}