use ferroui_base::input::ICommandSource;
use ferroui_base::{FerroObject, ObjectType, Ref, TypeInfo};
use std::cell::RefCell;
use std::rc::Rc;
type Adapter = Rc<dyn Fn(&FerroObject) -> Option<Rc<dyn ICommandSource>>>;
ferroui_base::ferro_thread_local! {
static SOURCE_TYPES: RefCell<Vec<(&'static TypeInfo, Adapter)>> = const { RefCell::new(Vec::new()) };
}
pub fn register_command_source<T: ObjectType>(adapter: fn(Ref<T>) -> Rc<dyn ICommandSource>) {
SOURCE_TYPES.with(|types| {
let mut types = types.borrow_mut();
if !types.iter().any(|(type_, _)| *type_ == T::TYPE) {
let adapter: Adapter =
Rc::new(move |object| object.downcast_ref::<T>().map(|target| adapter(FerroObject::ref_of(target))));
types.push((T::TYPE, adapter));
}
});
}
pub fn as_command_source(object: &FerroObject) -> Option<Rc<dyn ICommandSource>> {
let adapter = SOURCE_TYPES.with(|types| {
let types = types.borrow();
let mut current = Some(object.get_type());
while let Some(type_) = current {
if let Some((_, adapter)) = types.iter().find(|(candidate, _)| *candidate == type_) {
return Some(adapter.clone());
}
current = type_.base_type();
}
None
});
adapter.and_then(|adapter| adapter(object))
}