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};
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 }
70
71 struct InspectedElement {
72 id: InspectorElementId,
73 states: TypeIdHashMap<Box<dyn Any>>,
74 }
75
76 impl InspectedElement {
77 fn new(id: InspectorElementId) -> Self {
78 InspectedElement {
79 id,
80 states: Default::default(),
81 }
82 }
83 }
84
85 impl Inspector {
86 pub(crate) fn new() -> Self {
87 Self {
88 active_element: None,
89 pick_depth: Some(0.0),
90 }
91 }
92
93 pub(crate) fn select(&mut self, id: InspectorElementId, window: &mut Window) {
94 self.set_active_element_id(id, window);
95 self.pick_depth = None;
96 }
97
98 pub(crate) fn hover(&mut self, id: InspectorElementId, window: &mut Window) {
99 if self.is_picking() {
100 let changed = self.set_active_element_id(id, window);
101 if changed {
102 self.pick_depth = Some(0.0);
103 }
104 }
105 }
106
107 pub(crate) fn set_active_element_id(
108 &mut self,
109 id: InspectorElementId,
110 window: &mut Window,
111 ) -> bool {
112 let changed = Some(&id) != self.active_element_id();
113 if changed {
114 self.active_element = Some(InspectedElement::new(id));
115 window.refresh();
116 }
117 changed
118 }
119
120 pub fn active_element_id(&self) -> Option<&InspectorElementId> {
122 self.active_element.as_ref().map(|e| &e.id)
123 }
124
125 pub(crate) fn with_active_element_state<'w, T: 'static, R>(
126 &mut self,
127 window: &mut Window<'w>,
128 f: impl FnOnce(&mut Option<T>, &mut Window<'w>) -> R,
129 ) -> R {
130 let Some(active_element) = &mut self.active_element else {
131 return f(&mut None, window);
132 };
133
134 let type_id = TypeId::of::<T>();
135 let mut inspector_state = active_element
136 .states
137 .remove(&type_id)
138 .map(|state| *state.downcast().unwrap());
139
140 let result = f(&mut inspector_state, window);
141
142 if let Some(inspector_state) = inspector_state {
143 active_element
144 .states
145 .insert(type_id, Box::new(inspector_state));
146 }
147
148 result
149 }
150
151 pub fn start_picking(&mut self) {
153 self.pick_depth = Some(0.0);
154 }
155
156 pub fn is_picking(&self) -> bool {
158 self.pick_depth.is_some()
159 }
160
161 pub fn render_inspector_states(
163 &mut self,
164 window: &mut Window,
165 cx: &mut Context<Self>,
166 ) -> Vec<AnyElement> {
167 let mut elements = Vec::new();
168 if let Some(active_element) = self.active_element.take() {
169 for (type_id, state) in &active_element.states {
170 if let Some(render_inspector) = cx
171 .inspector_element_registry
172 .renderers_by_type_id
173 .remove(type_id)
174 {
175 let mut element = (render_inspector)(
176 active_element.id.clone(),
177 state.as_ref(),
178 window,
179 cx,
180 );
181 elements.push(element);
182 cx.inspector_element_registry
183 .renderers_by_type_id
184 .insert(*type_id, render_inspector);
185 }
186 }
187
188 self.active_element = Some(active_element);
189 }
190
191 elements
192 }
193 }
194
195 impl Render for Inspector {
196 fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
197 if let Some(inspector_renderer) = cx.inspector_renderer.take() {
198 let result = inspector_renderer(self, window, cx);
199 cx.inspector_renderer = Some(inspector_renderer);
200 result
201 } else {
202 Empty.into_any_element()
203 }
204 }
205 }
206
207 #[derive(Default)]
208 pub(crate) struct InspectorElementRegistry {
209 renderers_by_type_id: FxHashMap<
210 TypeId,
211 Box<dyn Fn(InspectorElementId, &dyn Any, &mut Window, &mut App) -> AnyElement>,
212 >,
213 }
214
215 impl InspectorElementRegistry {
216 pub fn register<T: 'static, R: IntoElement>(
217 &mut self,
218 f: impl 'static + Fn(InspectorElementId, &T, &mut Window, &mut App) -> R,
219 ) {
220 self.renderers_by_type_id.insert(
221 TypeId::of::<T>(),
222 Box::new(move |id, value, window, cx| {
223 let value = value.downcast_ref().unwrap();
224 f(id, value, window, cx).into_any_element()
225 }),
226 );
227 }
228 }
229}
230
231#[cfg(any(feature = "inspector", debug_assertions))]
233pub mod inspector_reflection {
234 use std::any::Any;
235
236 #[derive(Clone, Copy)]
239 pub struct FunctionReflection<T> {
240 pub name: &'static str,
242 pub function: fn(Box<dyn Any>) -> Box<dyn Any>,
244 pub documentation: Option<&'static str>,
246 pub _type: std::marker::PhantomData<T>,
248 }
249
250 impl<T: 'static> FunctionReflection<T> {
251 pub fn invoke(&self, value: T) -> T {
253 let boxed = Box::new(value) as Box<dyn Any>;
254 let result = (self.function)(boxed);
255 *result
256 .downcast::<T>()
257 .expect("Type mismatch in reflection invoke")
258 }
259 }
260}