Skip to main content

ferroui_diagnostics/diagnostics/
visual_tree_debug.rs

1//! Port of `Diagnostics/VisualTreeDebug.cs`.
2
3use ferroui_base::data::core::ValueTypes;
4use ferroui_base::data::BindingPriority;
5use ferroui_base::diagnostics::FerroObjectDiagnosticExtensions;
6use ferroui_base::{BoxedValue, FerroPropertyRegistry, Visual};
7use ferroui_controls::Control;
8use std::fmt::Write;
9use std::rc::Rc;
10
11/// Prints a visual tree as text, for debugging.
12pub struct VisualTreeDebug;
13
14impl VisualTreeDebug {
15    /// The visual tree of `visual` as text: one line per visual (the name of its type, and the
16    /// classes of a control), the properties of a control that have a value, each with the
17    /// priority of the value, and the children, indented.
18    pub fn print_visual_tree(visual: &Visual) -> String {
19        let mut result = String::new();
20        Self::print_visual_tree_into(visual, &mut result, 0);
21        result
22    }
23
24    fn print_visual_tree_into(visual: &Visual, builder: &mut String, indent: i32) {
25        let control = visual.to_ref().cast::<Control>();
26
27        builder.push_str(&Self::indent(indent - 1));
28
29        if indent > 0 {
30            builder.push_str(" +- ");
31        }
32
33        builder.push_str(visual.get_type().name());
34
35        if let Some(control) = &control {
36            builder.push(' ');
37            // `control.Classes.ToString()`.
38            let classes: BoxedValue = Rc::new(control.classes());
39            builder.push_str(&ValueTypes::to_display_string(Some(&classes)));
40            builder.push('\n');
41
42            for &property in FerroPropertyRegistry::instance().get_registered(control.get_type()).iter() {
43                let value = control.get_diagnostic(property);
44
45                if value.priority() != BindingPriority::Unset {
46                    builder.push_str(&Self::indent(indent));
47                    builder.push_str(" |  ");
48                    builder.push_str(value.property().name());
49                    builder.push_str(" = ");
50                    let shown = ValueTypes::normalize(value.value().clone());
51                    builder.push_str(&ValueTypes::to_display_string(shown.as_ref()));
52                    builder.push_str(" [");
53                    let _ = write!(builder, "{:?}", value.priority());
54                    builder.push_str("]\n");
55                }
56            }
57        } else {
58            builder.push('\n');
59        }
60
61        for child in visual.visual_children().snapshot().iter() {
62            Self::print_visual_tree_into(child, builder, indent + 1);
63        }
64    }
65
66    fn indent(indent: i32) -> String {
67        " ".repeat(indent.max(0) as usize * 4)
68    }
69}