use std::cell::RefCell;
use std::rc::Rc;
use ui_core::{LayoutItem, SurfacePlacement};
pub type SurfaceContent = Rc<dyn Fn() -> Box<dyn LayoutItem>>;
pub fn surface_content(build: impl Fn() -> Box<dyn LayoutItem> + 'static) -> SurfaceContent {
Rc::new(build)
}
pub trait SurfaceControl {
fn close(&self);
fn is_closing(&self) -> bool;
fn rebuild(&self) {}
}
pub trait SurfaceHost {
fn open(&self, placement: SurfacePlacement, content: SurfaceContent) -> SurfaceToken;
}
pub struct SurfaceToken {
control: Box<dyn SurfaceControl>,
}
impl SurfaceToken {
pub fn new(control: Box<dyn SurfaceControl>) -> Self {
Self { control }
}
pub fn close(&self) {
self.control.close();
}
pub fn is_closing(&self) -> bool {
self.control.is_closing()
}
pub fn rebuild(&self) {
self.control.rebuild();
}
}
impl Drop for SurfaceToken {
fn drop(&mut self) {
self.control.close();
}
}
thread_local! {
static SURFACE_HOST: RefCell<Option<Box<dyn SurfaceHost>>> = const { RefCell::new(None) };
}
pub fn set_surface_host(host: Box<dyn SurfaceHost>) {
SURFACE_HOST.with(|h| *h.borrow_mut() = Some(host));
}
pub fn has_surface_host() -> bool {
SURFACE_HOST.with(|h| h.borrow().is_some())
}
pub fn open_surface(placement: SurfacePlacement, content: SurfaceContent) -> SurfaceToken {
SURFACE_HOST.with(|h| match h.borrow().as_ref() {
Some(host) => host.open(placement, content),
None => {
tracing::warn!(
"telar::open_surface: no SurfaceHost installed on this thread; surface ignored"
);
SurfaceToken::new(Box::new(NoopControl))
}
})
}
struct NoopControl;
impl SurfaceControl for NoopControl {
fn close(&self) {}
fn is_closing(&self) -> bool {
true
}
}