#![allow(static_mut_refs)]
use std::ptr::NonNull;
use smallvec::SmallVec;
use widget_id::{RenderQueryable, new_node};
use crate::{local_sender::LocalSender, prelude::*};
pub struct BuildCtx {
pub(crate) providers: SmallVec<[WidgetId; 1]>,
pub(crate) current_providers: SmallVec<[Box<dyn Query>; 1]>,
pub(crate) tree: NonNull<WidgetTree>,
}
impl BuildCtx {
pub fn window(&self) -> Sc<Window> { self.tree().window() }
pub fn provider_handle(&self) -> ProviderHandle {
ProviderHandle { wnd_id: self.window().id(), widget: *self.providers.last().unwrap() }
}
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 alloc(&mut self, node: Box<dyn RenderQueryable>) -> WidgetId {
new_node(&mut self.tree_mut().arena, node)
}
}
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 mut providers: SmallVec<[WidgetId; 1]> = startup
.ancestors(t)
.filter(|id| id.queryable(t))
.collect();
providers.reverse();
let ctx = BuildCtx { tree, providers, current_providers: <_>::default() };
BuildCtx::set(ctx);
}
pub(crate) fn set(ctx: BuildCtx) { unsafe { CTX = Some(LocalSender::new(ctx)) } }
pub(crate) fn clear() { unsafe { CTX = None } }
}
pub(crate) struct BuildCtxInitdGuard;
impl Drop for BuildCtxInitdGuard {
fn drop(&mut self) { BuildCtx::clear() }
}