use crate::core::layers::{Anchor, FocusPolicy, LayerKind, LayerOptions};
use crate::view::node::ViewNode;
use std::cell::{Cell, RefCell};
use std::rc::Rc;
thread_local! {
static REBUILD_REQUESTED: Cell<bool> = const { Cell::new(false) };
static REDRAW_REQUESTED: Cell<bool> = const { Cell::new(false) };
static PENDING_LAYER: RefCell<Vec<LayerCmd>> = const { RefCell::new(Vec::new()) };
static WINDOW_CLOSE_REQUESTED: Cell<bool> = const { Cell::new(false) };
}
#[derive(Debug, Clone, Copy)]
pub struct LayerSpec {
pub anchor: Anchor,
pub focus: FocusPolicy,
pub opts: LayerOptions,
}
impl LayerSpec {
pub fn new(anchor: Anchor, focus: FocusPolicy) -> Self {
Self {
anchor,
focus,
opts: LayerOptions::default(),
}
}
pub fn with_backdrop(mut self, color: crate::geometry::Color) -> Self {
self.opts.backdrop = Some(color);
self
}
}
pub(crate) enum LayerCmd {
Show {
kind: LayerKind,
spec: LayerSpec,
view: Box<ViewNode>,
},
Hide { kind: LayerKind },
}
pub fn request_rebuild() {
REBUILD_REQUESTED.with(|r| r.set(true));
}
pub(crate) fn take_rebuild_requested() -> bool {
REBUILD_REQUESTED.with(|r| r.replace(false))
}
pub fn take_rebuild_requested_pub() -> bool {
take_rebuild_requested()
}
pub fn request_redraw() {
REDRAW_REQUESTED.with(|r| r.set(true));
}
pub(crate) fn take_redraw_requested() -> bool {
REDRAW_REQUESTED.with(|r| r.replace(false))
}
pub fn show_layer(
kind: LayerKind,
spec: LayerSpec,
builder: impl FnOnce(&mut crate::widget::BuildContext) -> Box<dyn crate::widget::Widget> + 'static,
) {
let mut ctx =
crate::widget::BuildContext::new(Rc::new(RefCell::new(crate::widget::StateMap::new())));
let widget = builder(&mut ctx);
let view = widget.build(&mut ctx);
PENDING_LAYER.with(|c| {
c.borrow_mut().push(LayerCmd::Show {
kind,
spec,
view: Box::new(view),
});
});
request_rebuild();
}
pub fn show_modal(
builder: impl FnOnce(&mut crate::widget::BuildContext) -> Box<dyn crate::widget::Widget> + 'static,
) {
show_layer(
LayerKind::Modal,
LayerSpec::new(Anchor::ScreenCenter, FocusPolicy::BlockBelow)
.with_backdrop(crate::geometry::Color::rgba(0, 0, 0, 80)),
builder,
);
}
pub fn hide_modal() {
PENDING_LAYER.with(|c| {
c.borrow_mut().push(LayerCmd::Hide {
kind: LayerKind::Modal,
});
});
request_rebuild();
}
pub fn show_overlay(
builder: impl FnOnce(&mut crate::widget::BuildContext) -> Box<dyn crate::widget::Widget> + 'static,
) {
show_layer(
LayerKind::Overlay,
LayerSpec::new(Anchor::None, FocusPolicy::Transparent),
builder,
);
}
pub fn hide_overlay() {
PENDING_LAYER.with(|c| {
c.borrow_mut().push(LayerCmd::Hide {
kind: LayerKind::Overlay,
});
});
request_rebuild();
}
pub(crate) fn take_pending_layers() -> Vec<LayerCmd> {
PENDING_LAYER.with(|c| std::mem::take(&mut *c.borrow_mut()))
}
pub fn request_window_close() {
WINDOW_CLOSE_REQUESTED.with(|c| c.set(true));
}
pub(crate) fn take_window_close_requested() -> bool {
WINDOW_CLOSE_REQUESTED.with(|c| c.replace(false))
}
pub struct State<T> {
inner: std::rc::Rc<std::cell::RefCell<T>>,
}
impl<T> State<T> {
pub fn new(value: T) -> Self {
Self {
inner: std::rc::Rc::new(std::cell::RefCell::new(value)),
}
}
pub fn get(&self) -> std::cell::Ref<'_, T> {
self.inner.borrow()
}
pub fn set(&self, value: T) {
*self.inner.borrow_mut() = value;
request_rebuild();
}
pub fn update<F: FnOnce(&mut T)>(&self, f: F) {
f(&mut self.inner.borrow_mut());
request_rebuild();
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for State<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("State")
.field("value", &*self.get())
.finish()
}
}
impl<T> Clone for State<T> {
fn clone(&self) -> Self {
Self {
inner: std::rc::Rc::clone(&self.inner),
}
}
}