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