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