use ferroui_base::{FerroObject, ObjectType, TypeInfo};
use std::cell::RefCell;
pub trait ISelectable {
fn is_selected(&self) -> bool;
fn set_is_selected(&self, value: bool);
}
type SelectableCast = for<'a> fn(&'a FerroObject) -> Option<&'a dyn ISelectable>;
ferroui_base::ferro_thread_local! {
static SELECTABLE_TYPES: RefCell<Vec<(&'static TypeInfo, SelectableCast)>> = const { RefCell::new(Vec::new()) };
}
fn cast_selectable<T: ObjectType + ISelectable>(object: &FerroObject) -> Option<&dyn ISelectable> {
object.downcast_ref::<T>().map(|selectable| selectable as &dyn ISelectable)
}
pub fn register_selectable<T: ObjectType + ISelectable>() {
SELECTABLE_TYPES.with(|types| {
let mut types = types.borrow_mut();
if !types.iter().any(|(type_, _)| *type_ == T::TYPE) {
types.push((T::TYPE, cast_selectable::<T> as SelectableCast));
}
});
}
pub fn as_selectable(object: &FerroObject) -> Option<&dyn ISelectable> {
let cast = SELECTABLE_TYPES.with(|types| {
let types = types.borrow();
let mut current = Some(object.get_type());
while let Some(type_) = current {
if let Some((_, cast)) = types.iter().find(|(candidate, _)| *candidate == type_) {
return Some(*cast);
}
current = type_.base_type();
}
None
});
cast.and_then(|cast| cast(object))
}