use std::{any::TypeId, marker::PhantomData}; use crate::{ layout::{FnTag, Ui, UiMsg, UiMsgSender, Widget, WidgetLike, WidgetTag}, util::{Id, RefCounter}, }; pub struct AnyWidget; /// An identifier for a widget that can index a UI to get the associated widget. /// It should always remain valid; it keeps a ref count and removes the widget from the UI if all /// references are dropped. /// /// W does not need to implement widget so that AnyWidget is valid; /// Instead, add generic bounds on methods that take an ID if they need specific data. #[repr(C)] pub struct WidgetId { pub(super) ty: TypeId, pub(super) id: Id, counter: RefCounter, send: UiMsgSender, _pd: PhantomData, } impl std::fmt::Debug for WidgetId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.id.fmt(f) } } impl Clone for WidgetId { fn clone(&self) -> Self { Self { id: self.id.duplicate(), ty: self.ty, counter: self.counter.clone(), send: self.send.clone(), _pd: PhantomData, } } } impl WidgetId { pub(super) fn new(id: Id, ty: TypeId, send: UiMsgSender) -> Self { Self { ty, id, counter: RefCounter::new(), send, _pd: PhantomData, } } pub fn erase_type(self) -> WidgetId { self.cast_type() } pub fn as_any(&self) -> &WidgetId { // safety: self is repr(C) and generic only used for phantom data unsafe { std::mem::transmute(self) } } pub(super) fn cast_type(self) -> WidgetId { // safety: self is repr(C) and generic only used for phantom data unsafe { std::mem::transmute(self) } } pub fn refs(&self) -> u32 { self.counter.refs() } } impl Drop for WidgetId { fn drop(&mut self) { if self.counter.drop() { let _ = self.send.send(UiMsg::FreeWidget(self.id.duplicate())); } } } pub struct IdTag; // pub trait WidgetIdFn = FnOnce(&mut Ui) -> WidgetId; macro_rules! WidgetIdFnRet { ($W:ty, $Ctx:ty) => { impl FnOnce(&mut $crate::layout::Ui<$Ctx>) -> $crate::layout::WidgetId<$W> }; ($W:ty, $Ctx:ty, $($use:tt)*) => { impl FnOnce(&mut $crate::layout::Ui<$Ctx>) -> $crate::layout::WidgetId<$W> + use<$($use)*> }; } pub(crate) use WidgetIdFnRet; pub trait Idable { type Widget: Widget; fn set(self, ui: &mut Ui, id: &WidgetId); fn id<'a>( self, id: &WidgetId, ) -> WidgetIdFnRet!(Self::Widget, Ctx, 'a, Self, Ctx, Tag) where Self: Sized, { let id = id.clone(); move |ui| { self.set(ui, &id); id } } } impl, Ctx> Idable for W { type Widget = W; fn set(self, ui: &mut Ui, id: &WidgetId) { ui.set(id, self); } } impl) -> W, W: Widget, Ctx> Idable for F { type Widget = W; fn set(self, ui: &mut Ui, id: &WidgetId) { let w = self(ui); ui.set(id, w); } } impl WidgetLike for WidgetId { type Widget = W; fn add(self, _: &mut Ui) -> WidgetId { self } } impl) -> WidgetId, Ctx> WidgetLike for F { type Widget = W; fn add(self, ui: &mut Ui) -> WidgetId { self(ui) } }