use ndkm::{Grapher, Window as ANWin}; use std::{ cell::{Cell, RefCell}, collections::HashMap, rc::Rc, }; use thunderdome::{Arena, Index}; use crate::Platform; use super::WinRef; pub type RcDynWinDelegate = Rc>; pub struct WinFrame(pub Key); impl ndkm::FrameDelegate for WinFrame { fn on_frame(&self, frame_time_nanos: i64) { with_win(self.0, |win| { win.nanos.set(frame_time_nanos); if win.dirty.get() && win.anwin().is_some() { win.dirty.set(false); log::debug!("on_frame with dirty"); win.delegate()?.req_draw(win.win_ref(), win.frame_nano()); } Some(()) }); } } pub struct Win { pub(super) key_: String, delegate: Option, anwin: Option, pub(super) scale_factor: Option, grapher: Grapher, frame: Option>, dirty: Cell, nanos: Cell, } impl Win { pub fn win_ref(&self) -> WinRef { WinRef(self.anwin.as_ref(), self) } pub fn delegate(&self) -> Option<&RcDynWinDelegate> { self.delegate.as_ref() } pub fn anwin(&self) -> Option<&ANWin> { self.anwin.as_ref() } pub fn dirty(&self, src: &str) { if false == self.dirty.get() { log::debug!("{} dirtied by {src}", &self.key_); self.dirty.set(true); if let Some(frame) = &self.frame { self.grapher.frame(frame) } } } pub fn frame_ms(&self) -> i64 { const NANOS_PER_MS: i64 = 1000000; self.nanos.get() / NANOS_PER_MS } pub fn frame_nano(&self) -> i64 { self.nanos.get() } } pub type Key = Index; thread_local! { static CACHE:RefCell> = Default::default(); static REG:RefCell>=Default::default(); } pub fn reg_window(name: impl AsRef, delegate: RcDynWinDelegate) { REG.with_borrow_mut(|regs| { regs.insert(name.as_ref().to_string(), delegate); }) } pub fn new_window(name: impl AsRef) -> Key { // TODO check main thread let delegate = REG.with_borrow(|regs| regs.get(name.as_ref()).cloned()); let key = name.as_ref(); CACHE.with_borrow_mut(|vars| { for (idx, win) in vars.iter() { if win.key_ == key.as_ref() { log::warn!("Duplicated Activity with same Window"); return idx; } } let key = key.to_string(); let key = vars.insert(Win { key_: key.clone(), delegate, anwin: None, scale_factor: None, grapher: Grapher::::singleton(), frame: None, dirty: Cell::new(false), nanos: Cell::new(0), }); let frame = Rc::new(WinFrame(key.clone())); if let Some(win) = vars.get_mut(key) { win.frame = Some(frame); } key }) } pub fn del_window(key: Key) { // TODO check main thread CACHE.with_borrow_mut(|vars| { let ret = vars.remove(key); std::mem::drop(ret); }) } pub(crate) fn replace_anwin(key: Key, mut awin: Option) -> Option { with_win_mut(key, |win| { if let Some(awin) = awin.take() { win.anwin.replace(awin) } else { win.anwin.take() } }) } pub(crate) fn with_win_mut(key: Key, mut fun: impl FnMut(&mut Win) -> Option) -> Option { CACHE.with_borrow_mut(|vars| vars.get_mut(key).map(|win| fun(win)).flatten()) } pub(crate) fn with_win(key: Key, mut fun: impl FnMut(&Win) -> Option) -> Option { CACHE.with_borrow(|vars| vars.get(key).map(|win| fun(win)).flatten()) } pub(crate) fn with_wins(mut fun: impl FnMut(&Arena) -> T) -> T { CACHE.with_borrow(|vars: &Arena| fun(vars)) }