#![allow(static_mut_refs)]
use std::ptr::NonNull;
use crate::{local_sender::LocalSender, prelude::*};
pub struct BuildCtx {
tree: NonNull<WidgetTree>,
provider_ctx: ProviderCtx,
children: Vec<(WidgetId, Widget<'static>)>,
}
impl BuildCtx {
pub fn window(&self) -> Rc<Window> { self.tree().window() }
pub fn color() -> Variant<Color> { Variant::new(BuildCtx::get()).unwrap() }
pub fn container_color() -> VariantMap<ContainerColor, impl Fn(&ContainerColor) -> Color> {
Variant::new(BuildCtx::get())
.unwrap()
.map(|c: &ContainerColor| c.0)
}
pub fn is_valid_widget(&self, id: WidgetId) -> bool { !id.is_dropped(self.tree()) }
pub fn dirty(&self, id: WidgetId) {
let tree = self.tree();
let scope = id.assert_get(tree).dirty_phase();
let scope = if scope == DirtyPhase::LayoutSubtree { scope } else { DirtyPhase::Layout };
tree.dirty_marker().mark(id, scope);
}
pub(crate) fn tree(&self) -> &WidgetTree {
unsafe { self.tree.as_ref() }
}
pub(crate) fn tree_mut(&mut self) -> &mut WidgetTree {
let mut tree = self.tree;
unsafe { tree.as_mut() }
}
pub(crate) fn tree_ptr(&self) -> NonNull<WidgetTree> { self.tree }
pub(crate) fn build(&mut self, widget: Widget<'_>) -> WidgetId {
let size = self.children.len();
let root = widget.call(self);
loop {
if self.children.len() == size {
break;
}
if let Some((p, child)) = self.children.pop() {
let c = child.call(self);
p.append(c, self.tree_mut());
}
}
root
}
pub(crate) fn build_parent(&mut self, parent: Widget<'_>, children: Vec<Widget<'_>>) -> WidgetId {
let root = self.build(parent);
let p = root.single_leaf(self.tree_mut());
for c in children.into_iter().rev() {
let c: Widget<'static> = unsafe { std::mem::transmute(c) };
self.children.push((p, c));
}
root
}
}
static mut CTX: Option<LocalSender<BuildCtx>> = None;
impl BuildCtx {
pub fn try_get() -> Option<&'static BuildCtx> { unsafe { CTX.as_deref() } }
pub fn get() -> &'static BuildCtx {
BuildCtx::try_get().expect("Not during the widget building process.")
}
pub(crate) fn get_mut() -> &'static mut BuildCtx {
unsafe {
CTX
.as_deref_mut()
.expect("Not during the widget building process.")
}
}
#[must_use]
pub(crate) fn init_for(startup: WidgetId, tree: NonNull<WidgetTree>) -> BuildCtxInitdGuard {
Self::set_for(startup, tree);
BuildCtxInitdGuard
}
#[must_use]
pub(crate) fn init(ctx: BuildCtx) -> BuildCtxInitdGuard {
BuildCtx::set(ctx);
BuildCtxInitdGuard
}
pub(crate) fn set_for(startup: WidgetId, tree: NonNull<WidgetTree>) {
let t = unsafe { tree.as_ref() };
let provider_ctx = ProviderCtx::collect_from(startup, t);
let ctx = BuildCtx { tree, children: <_>::default(), provider_ctx };
BuildCtx::set(ctx);
}
pub(crate) fn set(ctx: BuildCtx) { unsafe { CTX = Some(LocalSender::new(ctx)) } }
pub(crate) fn clear() {
if let Some(ctx) = BuildCtx::try_get() {
assert!(ctx.children.is_empty());
}
unsafe { CTX = None }
}
pub(crate) fn empty(tree: NonNull<WidgetTree>) -> Self {
Self { tree, children: <_>::default(), provider_ctx: <_>::default() }
}
}
pub(crate) struct BuildCtxInitdGuard;
impl Drop for BuildCtxInitdGuard {
fn drop(&mut self) { BuildCtx::clear() }
}
impl AsRef<ProviderCtx> for BuildCtx {
fn as_ref(&self) -> &ProviderCtx { &self.provider_ctx }
}
impl AsMut<ProviderCtx> for BuildCtx {
fn as_mut(&mut self) -> &mut ProviderCtx { &mut self.provider_ctx }
}