1#[derive(Debug, Eq, PartialEq, Hash, Clone)]
14pub struct InspectorElementId {
15 #[cfg(any(feature = "inspector", debug_assertions))]
17 pub path: std::rc::Rc<InspectorElementPath>,
18 #[cfg(any(feature = "inspector", debug_assertions))]
20 pub instance_id: usize,
21}
22
23impl Into<InspectorElementId> for &InspectorElementId {
24 fn into(self) -> InspectorElementId {
25 self.clone()
26 }
27}
28
29#[cfg(any(feature = "inspector", debug_assertions))]
30pub use conditional::*;
31
32#[cfg(any(feature = "inspector", debug_assertions))]
33mod conditional {
34 use super::*;
35 use crate::{AnyElement, App, Context, Empty, IntoElement, Render, Window};
36 use collections::{FxHashMap, TypeIdHashMap, hash_map::Entry};
37 use std::any::{Any, TypeId};
38
39 #[derive(Debug, Eq, PartialEq, Hash)]
44 pub struct InspectorElementPath {
45 #[cfg(any(feature = "inspector", debug_assertions))]
48 pub global_id: crate::GlobalElementId,
49 #[cfg(any(feature = "inspector", debug_assertions))]
51 pub source_location: &'static std::panic::Location<'static>,
52 }
53
54 impl Clone for InspectorElementPath {
55 fn clone(&self) -> Self {
56 Self {
57 global_id: self.global_id.clone(),
58 source_location: self.source_location,
59 }
60 }
61 }
62
63 impl Into<InspectorElementPath> for &InspectorElementPath {
64 fn into(self) -> InspectorElementPath {
65 self.clone()
66 }
67 }
68
69 pub type InspectorRenderer =
75 Box<dyn Fn(&mut Inspector, &mut Window, &mut Context<Inspector>) -> AnyElement>;
76
77 pub struct Inspector {
82 active_element: Option<InspectedElement>,
83 pub(crate) pick_depth: Option<f32>,
84 renderers: TypeIdHashMap<InspectorElementRenderer>,
85 }
86
87 struct InspectedElement {
88 id: InspectorElementId,
89 states: TypeIdHashMap<Box<dyn Any>>,
90 }
91
92 impl InspectedElement {
93 fn new(id: InspectorElementId) -> Self {
94 InspectedElement {
95 id,
96 states: Default::default(),
97 }
98 }
99 }
100
101 impl Inspector {
102 pub(crate) fn new() -> Self {
103 Self {
104 active_element: None,
105 pick_depth: Some(0.0),
106 renderers: TypeIdHashMap::default(),
107 }
108 }
109
110 pub(crate) fn select(&mut self, id: InspectorElementId, window: &mut Window) {
111 self.set_active_element_id(id, window);
112 self.pick_depth = None;
113 }
114
115 pub(crate) fn hover(&mut self, id: InspectorElementId, window: &mut Window) {
116 if self.is_picking() {
117 let changed = self.set_active_element_id(id, window);
118 if changed {
119 self.pick_depth = Some(0.0);
120 }
121 }
122 }
123
124 pub(crate) fn set_active_element_id(
125 &mut self,
126 id: InspectorElementId,
127 window: &mut Window,
128 ) -> bool {
129 let changed = Some(&id) != self.active_element_id();
130 if changed {
131 self.active_element = Some(InspectedElement::new(id));
132 window.refresh();
133 }
134 changed
135 }
136
137 pub fn active_element_id(&self) -> Option<&InspectorElementId> {
140 self.active_element.as_ref().map(|e| &e.id)
141 }
142
143 pub(crate) fn with_active_element_state<T: 'static, R>(
144 &mut self,
145 window: &mut Window,
146 f: impl FnOnce(&mut Option<T>, &mut Window) -> R,
147 ) -> R {
148 let Some(active_element) = &mut self.active_element else {
149 return f(&mut None, window);
150 };
151
152 let type_id = TypeId::of::<T>();
153 let mut inspector_state = active_element
154 .states
155 .remove(&type_id)
156 .map(|state| *state.downcast().unwrap());
157
158 let result = f(&mut inspector_state, window);
159
160 if let Some(inspector_state) = inspector_state {
161 active_element
162 .states
163 .insert(type_id, Box::new(inspector_state));
164 }
165
166 result
167 }
168
169 pub fn start_picking(&mut self) {
172 self.pick_depth = Some(0.0);
173 }
174
175 pub fn is_picking(&self) -> bool {
177 self.pick_depth.is_some()
178 }
179
180 pub fn render_inspector_states(
186 &mut self,
187 window: &mut Window,
188 cx: &mut Context<Self>,
189 ) -> Vec<AnyElement> {
190 let mut elements = Vec::new();
191 if let Some(active_element) = self.active_element.take() {
192 for (type_id, state) in &active_element.states {
193 let renderer = match self.renderers.entry(*type_id) {
194 Entry::Occupied(entry) => entry.into_mut(),
195 Entry::Vacant(entry) => {
196 let Some(factory) = cx
197 .inspector_element_registry
198 .factories_by_type_id
199 .remove(type_id)
200 else {
201 continue;
202 };
203 let renderer = factory(window, cx);
204 cx.inspector_element_registry
205 .factories_by_type_id
206 .insert(*type_id, factory);
207 entry.insert(renderer)
208 }
209 };
210 elements.push(renderer(
211 active_element.id.clone(),
212 state.as_ref(),
213 window,
214 cx,
215 ));
216 }
217
218 self.active_element = Some(active_element);
219 }
220
221 elements
222 }
223 }
224
225 impl Render for Inspector {
226 fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
227 if let Some(inspector_renderer) = cx.inspector_renderer.take() {
228 let result = inspector_renderer(self, window, cx);
229 cx.inspector_renderer = Some(inspector_renderer);
230 result
231 } else {
232 Empty.into_any_element()
233 }
234 }
235 }
236
237 #[derive(Default)]
238 pub(crate) struct InspectorElementRegistry {
239 factories_by_type_id:
240 FxHashMap<TypeId, Box<dyn Fn(&mut Window, &mut App) -> InspectorElementRenderer>>,
241 }
242
243 impl InspectorElementRegistry {
244 pub fn register<T: 'static, R: IntoElement, F>(
246 &mut self,
247 factory: impl 'static + Fn(&mut Window, &mut App) -> F,
248 ) where
249 F: 'static + FnMut(InspectorElementId, &T, &mut Window, &mut App) -> R,
250 {
251 self.factories_by_type_id.insert(
252 TypeId::of::<T>(),
253 Box::new(move |window, cx| {
254 let mut renderer = factory(window, cx);
255 Box::new(move |id, value, window, cx| {
256 let value = value
257 .downcast_ref()
258 .expect("registered inspector state type");
259 renderer(id, value, window, cx).into_any_element()
260 })
261 }),
262 );
263 }
264 }
265
266 type InspectorElementRenderer =
267 Box<dyn FnMut(InspectorElementId, &dyn Any, &mut Window, &mut App) -> AnyElement>;
268}
269
270#[cfg(any(feature = "inspector", debug_assertions))]
274pub mod inspector_reflection {
275 use std::any::Any;
276
277 #[derive(Clone, Copy)]
284 pub struct FunctionReflection<T> {
285 pub name: &'static str,
287 pub function: fn(Box<dyn Any>) -> Box<dyn Any>,
289 pub documentation: Option<&'static str>,
291 pub _type: std::marker::PhantomData<T>,
293 }
294
295 impl<T: 'static> FunctionReflection<T> {
296 pub fn invoke(&self, value: T) -> T {
303 let boxed = Box::new(value) as Box<dyn Any>;
304 let result = (self.function)(boxed);
305 *result
306 .downcast::<T>()
307 .expect("Type mismatch in reflection invoke")
308 }
309 }
310}