254 lines · 8.5 KB · Rust
RawDownload
/// A unique identifier for an element that can be inspected.#[derive(Debug, Eq, PartialEq, Hash, Clone)]pub struct InspectorElementId {    /// Stable part of the ID.    #[cfg(any(feature = "inspector", debug_assertions))]    pub path: std::rc::Rc<InspectorElementPath>,    /// Disambiguates elements that have the same path.    #[cfg(any(feature = "inspector", debug_assertions))]    pub instance_id: usize,} impl Into<InspectorElementId> for &InspectorElementId {    fn into(self) -> InspectorElementId {        self.clone()    }} #[cfg(any(feature = "inspector", debug_assertions))]pub use conditional::*; #[cfg(any(feature = "inspector", debug_assertions))]mod conditional {    use super::*;    use crate::{AnyElement, App, Context, Empty, IntoElement, Render, Window};    use collections::{FxHashMap, TypeIdHashMap};    use std::any::{Any, TypeId};     /// `GlobalElementId` qualified by source location of element construction.    #[derive(Debug, Eq, PartialEq, Hash)]    pub struct InspectorElementPath {        /// The path to the nearest ancestor element that has an `ElementId`.        #[cfg(any(feature = "inspector", debug_assertions))]        pub global_id: crate::GlobalElementId,        /// Source location where this element was constructed.        #[cfg(any(feature = "inspector", debug_assertions))]        pub source_location: &'static std::panic::Location<'static>,    }     impl Clone for InspectorElementPath {        fn clone(&self) -> Self {            Self {                global_id: self.global_id.clone(),                source_location: self.source_location,            }        }    }     impl Into<InspectorElementPath> for &InspectorElementPath {        fn into(self) -> InspectorElementPath {            self.clone()        }    }     /// Function set on `App` to render the inspector UI.    pub type InspectorRenderer =        Box<dyn Fn(&mut Inspector, &mut Window, &mut Context<Inspector>) -> AnyElement>;     /// Manages inspector state - which element is currently selected and whether the inspector is    /// in picking mode.    pub struct Inspector {        active_element: Option<InspectedElement>,        pub(crate) pick_depth: Option<f32>,    }     struct InspectedElement {        id: InspectorElementId,        states: TypeIdHashMap<Box<dyn Any>>,    }     impl InspectedElement {        fn new(id: InspectorElementId) -> Self {            InspectedElement {                id,                states: Default::default(),            }        }    }     impl Inspector {        pub(crate) fn new() -> Self {            Self {                active_element: None,                pick_depth: Some(0.0),            }        }         pub(crate) fn select(&mut self, id: InspectorElementId, window: &mut Window) {            self.set_active_element_id(id, window);            self.pick_depth = None;        }         pub(crate) fn hover(&mut self, id: InspectorElementId, window: &mut Window) {            if self.is_picking() {                let changed = self.set_active_element_id(id, window);                if changed {                    self.pick_depth = Some(0.0);                }            }        }         pub(crate) fn set_active_element_id(            &mut self,            id: InspectorElementId,            window: &mut Window,        ) -> bool {            let changed = Some(&id) != self.active_element_id();            if changed {                self.active_element = Some(InspectedElement::new(id));                window.refresh();            }            changed        }         /// ID of the currently hovered or selected element.        pub fn active_element_id(&self) -> Option<&InspectorElementId> {            self.active_element.as_ref().map(|e| &e.id)        }         pub(crate) fn with_active_element_state<T: 'static, R>(            &mut self,            window: &mut Window,            f: impl FnOnce(&mut Option<T>, &mut Window) -> R,        ) -> R {            let Some(active_element) = &mut self.active_element else {                return f(&mut None, window);            };             let type_id = TypeId::of::<T>();            let mut inspector_state = active_element                .states                .remove(&type_id)                .map(|state| *state.downcast().unwrap());             let result = f(&mut inspector_state, window);             if let Some(inspector_state) = inspector_state {                active_element                    .states                    .insert(type_id, Box::new(inspector_state));            }             result        }         /// Starts element picking mode, allowing the user to select elements by clicking.        pub fn start_picking(&mut self) {            self.pick_depth = Some(0.0);        }         /// Returns whether the inspector is currently in picking mode.        pub fn is_picking(&self) -> bool {            self.pick_depth.is_some()        }         /// Renders elements for all registered inspector states of the active inspector element.        pub fn render_inspector_states(            &mut self,            window: &mut Window,            cx: &mut Context<Self>,        ) -> Vec<AnyElement> {            let mut elements = Vec::new();            if let Some(active_element) = self.active_element.take() {                for (type_id, state) in &active_element.states {                    if let Some(render_inspector) = cx                        .inspector_element_registry                        .renderers_by_type_id                        .remove(type_id)                    {                        let mut element = (render_inspector)(                            active_element.id.clone(),                            state.as_ref(),                            window,                            cx,                        );                        elements.push(element);                        cx.inspector_element_registry                            .renderers_by_type_id                            .insert(*type_id, render_inspector);                    }                }                 self.active_element = Some(active_element);            }             elements        }    }     impl Render for Inspector {        fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {            if let Some(inspector_renderer) = cx.inspector_renderer.take() {                let result = inspector_renderer(self, window, cx);                cx.inspector_renderer = Some(inspector_renderer);                result            } else {                Empty.into_any_element()            }        }    }     #[derive(Default)]    pub(crate) struct InspectorElementRegistry {        renderers_by_type_id: FxHashMap<            TypeId,            Box<dyn Fn(InspectorElementId, &dyn Any, &mut Window, &mut App) -> AnyElement>,        >,    }     impl InspectorElementRegistry {        pub fn register<T: 'static, R: IntoElement>(            &mut self,            f: impl 'static + Fn(InspectorElementId, &T, &mut Window, &mut App) -> R,        ) {            self.renderers_by_type_id.insert(                TypeId::of::<T>(),                Box::new(move |id, value, window, cx| {                    let value = value.downcast_ref().unwrap();                    f(id, value, window, cx).into_any_element()                }),            );        }    }} /// Provides definitions used by `#[derive_inspector_reflection]`.#[cfg(any(feature = "inspector", debug_assertions))]pub mod inspector_reflection {    use std::any::Any;     /// Reification of a function that has the signature `fn some_fn(T) -> T`. Provides the name,    /// documentation, and ability to invoke the function.    #[derive(Clone, Copy)]    pub struct FunctionReflection<T> {        /// The name of the function        pub name: &'static str,        /// The method        pub function: fn(Box<dyn Any>) -> Box<dyn Any>,        /// Documentation for the function        pub documentation: Option<&'static str>,        /// `PhantomData` for the type of the argument and result        pub _type: std::marker::PhantomData<T>,    }     impl<T: 'static> FunctionReflection<T> {        /// Invoke this method on a value and return the result.        pub fn invoke(&self, value: T) -> T {            let boxed = Box::new(value) as Box<dyn Any>;            let result = (self.function)(boxed);            *result                .downcast::<T>()                .expect("Type mismatch in reflection invoke")        }    }}