ferroui_controls/
i_command_source.rs1use ferroui_base::input::ICommandSource;
11use ferroui_base::{FerroObject, ObjectType, Ref, TypeInfo};
12use std::cell::RefCell;
13use std::rc::Rc;
14
15type Adapter = Rc<dyn Fn(&FerroObject) -> Option<Rc<dyn ICommandSource>>>;
16
17ferroui_base::ferro_thread_local! {
18 static SOURCE_TYPES: RefCell<Vec<(&'static TypeInfo, Adapter)>> = const { RefCell::new(Vec::new()) };
19}
20
21pub fn register_command_source<T: ObjectType>(adapter: fn(Ref<T>) -> Rc<dyn ICommandSource>) {
24 SOURCE_TYPES.with(|types| {
25 let mut types = types.borrow_mut();
26 if !types.iter().any(|(type_, _)| *type_ == T::TYPE) {
27 let adapter: Adapter =
28 Rc::new(move |object| object.downcast_ref::<T>().map(|target| adapter(FerroObject::ref_of(target))));
29 types.push((T::TYPE, adapter));
30 }
31 });
32}
33
34pub fn as_command_source(object: &FerroObject) -> Option<Rc<dyn ICommandSource>> {
37 let adapter = SOURCE_TYPES.with(|types| {
38 let types = types.borrow();
39 let mut current = Some(object.get_type());
40 while let Some(type_) = current {
41 if let Some((_, adapter)) = types.iter().find(|(candidate, _)| *candidate == type_) {
42 return Some(adapter.clone());
43 }
44 current = type_.base_type();
45 }
46 None
47 });
48 adapter.and_then(|adapter| adapter(object))
49}