use crate::{
sys,
ui::{AnyWindow, Layout, TypedWindow, UiGuard, window::WindowData},
};
#[derive(Clone, Copy)]
pub enum NavAction<'n> {
Push(AnyWindow<'n>, bool),
Pop(bool),
PopAll(bool),
Remove(AnyWindow<'n>, bool),
}
pub struct Nav<'n> {
actions: [Option<NavAction<'n>>; Nav::CAPACITY],
len: usize,
ui: &'n mut UiGuard,
}
impl<'n> Nav<'n> {
pub const CAPACITY: usize = 16;
pub fn new(ui: &'n mut UiGuard) -> Self {
Self {
actions: [None; Self::CAPACITY],
len: 0,
ui,
}
}
fn queue(&mut self, action: NavAction<'n>) {
let Some(slot) = self.actions.get_mut(self.len) else {
crate::log::warn!("queue full");
return;
};
*slot = Some(action);
self.len += 1;
}
pub fn push(&mut self, window: impl Into<AnyWindow<'n>>, animated: bool) {
self.queue(NavAction::Push(window.into(), animated));
}
pub fn push_with<W: TypedWindow<'n>>(
&mut self,
window: W,
arg: <W::Layout as Layout<W::Data>>::Arg,
animated: bool,
) {
let window: AnyWindow<'n> = window.into();
unsafe {
let data =
sys::window_get_user_data(window.ptr).cast::<WindowData<W::Layout, W::Data>>();
drop((&raw mut (*data).pending).replace(Some(arg)));
}
self.queue(NavAction::Push(window, animated));
}
pub fn pop(&mut self, animated: bool) {
self.queue(NavAction::Pop(animated));
}
pub fn pop_all(&mut self, animated: bool) {
self.queue(NavAction::PopAll(animated));
}
pub fn remove(&mut self, window: impl Into<AnyWindow<'n>>, animated: bool) {
self.queue(NavAction::Remove(window.into(), animated));
}
}
impl Drop for Nav<'_> {
fn drop(&mut self) {
let actions = &self.actions;
self.ui.os_lend(|| {
for &action in actions.iter().flatten() {
unsafe {
match action {
NavAction::Push(window, animated) => {
sys::window_stack_push(window.ptr, animated);
}
NavAction::Pop(animated) => {
sys::window_stack_pop(animated);
}
NavAction::PopAll(animated) => sys::window_stack_pop_all(animated),
NavAction::Remove(window, animated) => {
sys::window_stack_remove(window.ptr, animated);
}
}
}
}
});
}
}