zng_wgt_inspector/live/
data_model.rs
1use std::{fmt, ops, sync::Arc};
2
3use parking_lot::Mutex;
4use zng_app::widget::{
5 builder::WidgetType,
6 info::WidgetInfoTree,
7 inspector::{InspectorInfo, WidgetInfoInspectorExt},
8};
9use zng_var::{WeakVar, types::WeakArcVar};
10use zng_view_api::window::FrameId;
11use zng_wgt::prelude::*;
12
13#[derive(Default)]
14pub struct InspectedTreeData {
15 widgets: IdMap<WidgetId, InspectedWidget>,
16 latest_frame: Option<ArcVar<FrameId>>,
17}
18
19#[derive(Clone)]
21pub struct InspectedTree {
22 tree: ArcVar<WidgetInfoTree>,
23 data: Arc<Mutex<InspectedTreeData>>,
24}
25impl fmt::Debug for InspectedTree {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 f.debug_struct("InspectedTree")
28 .field("tree", &self.tree.get())
29 .finish_non_exhaustive()
30 }
31}
32impl PartialEq for InspectedTree {
33 fn eq(&self, other: &Self) -> bool {
34 self.tree.var_ptr() == other.tree.var_ptr()
35 }
36}
37impl InspectedTree {
38 pub fn new(tree: WidgetInfoTree) -> Self {
40 Self {
41 data: Arc::new(Mutex::new(InspectedTreeData::default())),
42 tree: var(tree),
43 }
44 }
45
46 pub fn update(&self, tree: WidgetInfoTree) {
52 assert_eq!(self.tree.with(|t| t.window_id()), tree.window_id());
53
54 self.tree.set(tree.clone());
56
57 let mut data = self.data.lock();
58 let mut removed = false;
59 for (k, v) in data.widgets.iter() {
60 if let Some(w) = tree.get(*k) {
61 v.update(w);
62 } else {
63 v.removed.set(true);
64 removed = true;
65 }
66 }
67 data.widgets
69 .retain(|k, v| v.info.strong_count() > 1 && (!removed || tree.get(*k).is_some()));
70
71 if let Some(f) = &data.latest_frame {
72 if f.strong_count() == 1 {
73 data.latest_frame = None;
74 } else {
75 f.set(tree.stats().last_frame);
76 }
77 }
78 }
79
80 pub fn update_render(&self) {
82 let mut data = self.data.lock();
83 if let Some(f) = &data.latest_frame {
84 if f.strong_count() == 1 {
85 data.latest_frame = None;
86 } else {
87 f.set(self.tree.with(|t| t.stats().last_frame));
88 }
89 }
90 }
91
92 pub fn downgrade(&self) -> WeakInspectedTree {
94 WeakInspectedTree {
95 tree: self.tree.downgrade(),
96 data: Arc::downgrade(&self.data),
97 }
98 }
99
100 pub fn inspect(&self, widget_id: WidgetId) -> Option<InspectedWidget> {
102 match self.data.lock().widgets.entry(widget_id) {
103 IdEntry::Occupied(e) => Some(e.get().clone()),
104 IdEntry::Vacant(e) => self.tree.with(|t| {
105 t.get(widget_id)
106 .map(|w| e.insert(InspectedWidget::new(w, self.downgrade())).clone())
107 }),
108 }
109 }
110
111 pub fn inspect_root(&self) -> InspectedWidget {
113 self.inspect(self.tree.with(|t| t.root().id())).unwrap()
114 }
115
116 pub fn last_frame(&self) -> impl Var<FrameId> {
120 let mut data = self.data.lock();
121 data.latest_frame
122 .get_or_insert_with(|| var(self.tree.with(|t| t.stats().last_frame)))
123 .clone()
124 }
125}
126
127#[derive(Clone)]
129pub struct WeakInspectedTree {
130 tree: WeakArcVar<WidgetInfoTree>,
131 data: std::sync::Weak<Mutex<InspectedTreeData>>,
132}
133impl WeakInspectedTree {
134 pub fn upgrade(&self) -> Option<InspectedTree> {
136 Some(InspectedTree {
137 tree: self.tree.upgrade()?,
138 data: self.data.upgrade()?,
139 })
140 }
141}
142
143struct InspectedWidgetCache {
144 tree: WeakInspectedTree,
145 children: Option<BoxedVar<Vec<InspectedWidget>>>,
146 parent_property_name: Option<BoxedVar<Txt>>,
147}
148
149#[derive(Clone)]
153pub struct InspectedWidget {
154 info: ArcVar<WidgetInfo>,
155 removed: ArcVar<bool>,
156 cache: Arc<Mutex<InspectedWidgetCache>>,
157}
158impl fmt::Debug for InspectedWidget {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 f.debug_struct("InspectedWidget")
161 .field("info", &self.info.get())
162 .field("removed", &self.removed.get())
163 .finish_non_exhaustive()
164 }
165}
166impl PartialEq for InspectedWidget {
167 fn eq(&self, other: &Self) -> bool {
168 self.info.var_ptr() == other.info.var_ptr()
169 }
170}
171impl Eq for InspectedWidget {}
172impl InspectedWidget {
173 fn new(info: WidgetInfo, tree: WeakInspectedTree) -> Self {
175 Self {
176 info: var(info),
177 removed: var(false),
178 cache: Arc::new(Mutex::new(InspectedWidgetCache {
179 tree,
180 children: None,
181 parent_property_name: None,
182 })),
183 }
184 }
185
186 fn update(&self, info: WidgetInfo) {
192 assert_eq!(self.info.with(|i| i.id()), info.id());
193 self.info.set(info);
194
195 let mut cache = self.cache.lock();
196 if let Some(c) = &cache.children {
197 if c.strong_count() == 1 {
198 cache.children = None;
199 }
200 }
201 if let Some(c) = &cache.parent_property_name {
202 if c.strong_count() == 1 {
203 cache.parent_property_name = None;
204 }
205 }
206 }
207
208 pub fn info(&self) -> impl Var<WidgetInfo> {
218 self.info.read_only()
219 }
220
221 pub fn id(&self) -> WidgetId {
223 self.info.with(|i| i.id())
224 }
225
226 pub fn descendants_len(&self) -> impl Var<usize> {
233 self.info.map(|w| w.descendants_len()).actual_var()
234 }
235
236 pub fn wgt_type(&self) -> impl Var<Option<WidgetType>> {
238 self.info.map(|w| Some(w.inspector_info()?.builder.widget_type())).actual_var()
239 }
240
241 pub fn wgt_macro_name(&self) -> impl Var<Txt> {
243 self.info
244 .map(|w| match w.inspector_info().map(|i| i.builder.widget_type()) {
245 Some(t) => formatx!("{}!", t.name()),
246 None => Txt::from_static("<widget>!"),
247 })
248 .actual_var()
249 }
250
251 pub fn parent_property_name(&self) -> impl Var<Txt> {
255 let mut cache = self.cache.lock();
256 cache
257 .parent_property_name
258 .get_or_insert_with(|| {
259 self.info
260 .map(|w| {
261 Txt::from_static(
262 w.parent_property()
263 .map(|(p, _)| w.parent().unwrap().inspect_property(p).unwrap().property().name)
264 .unwrap_or(""),
265 )
266 })
267 .actual_var()
268 .boxed()
269 })
270 .clone()
271 }
272
273 pub fn children(&self) -> impl Var<Vec<InspectedWidget>> {
275 let mut cache = self.cache.lock();
276 let cache = &mut *cache;
277 cache
278 .children
279 .get_or_insert_with(|| {
280 let tree = cache.tree.clone();
281 self.info
282 .map(move |w| {
283 if let Some(tree) = tree.upgrade() {
284 assert_eq!(&tree.tree.get(), w.tree());
285
286 w.children().map(|w| tree.inspect(w.id()).unwrap()).collect()
287 } else {
288 vec![]
289 }
290 })
291 .actual_var()
292 .boxed()
293 })
294 .clone()
295 }
296
297 pub fn inspector_info(&self) -> impl Var<Option<InspectedInfo>> {
301 self.info.map(move |w| w.inspector_info().map(InspectedInfo)).actual_var().boxed()
302 }
303
304 pub fn render_watcher<T: VarValue>(&self, mut probe: impl FnMut(&WidgetInfo) -> T + Send + 'static) -> impl Var<T> {
306 merge_var!(
307 self.info.clone(),
308 self.cache.lock().tree.upgrade().unwrap().last_frame(),
309 move |w, _| probe(w)
310 )
311 }
312}
313
314#[derive(Clone)]
316pub struct InspectedInfo(pub Arc<InspectorInfo>);
317impl fmt::Debug for InspectedInfo {
318 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319 fmt::Debug::fmt(&self.0, f)
320 }
321}
322impl PartialEq for InspectedInfo {
323 fn eq(&self, other: &Self) -> bool {
324 Arc::ptr_eq(&self.0, &other.0)
325 }
326}
327impl ops::Deref for InspectedInfo {
328 type Target = InspectorInfo;
329
330 fn deref(&self) -> &Self::Target {
331 &self.0
332 }
333}