bevy_ui/layout/
debug.rs

1use core::fmt::Write;
2
3use taffy::{NodeId, TraversePartialTree};
4
5use bevy_ecs::prelude::Entity;
6use bevy_platform::collections::HashMap;
7
8use crate::layout::ui_surface::UiSurface;
9
10/// Prints a debug representation of the computed layout of the UI layout tree for each window.
11pub fn print_ui_layout_tree(ui_surface: &UiSurface) {
12    let taffy_to_entity: HashMap<NodeId, Entity> = ui_surface
13        .entity_to_taffy
14        .iter()
15        .map(|(entity, node)| (node.id, *entity))
16        .collect();
17    for (&entity, &viewport_node) in &ui_surface.root_entity_to_viewport_node {
18        let mut out = String::new();
19        print_node(
20            ui_surface,
21            &taffy_to_entity,
22            entity,
23            viewport_node,
24            false,
25            String::new(),
26            &mut out,
27        );
28
29        tracing::info!("Layout tree for camera entity: {entity}\n{out}");
30    }
31}
32
33/// Recursively navigates the layout tree printing each node's information.
34fn print_node(
35    ui_surface: &UiSurface,
36    taffy_to_entity: &HashMap<NodeId, Entity>,
37    entity: Entity,
38    node: NodeId,
39    has_sibling: bool,
40    lines_string: String,
41    acc: &mut String,
42) {
43    let tree = &ui_surface.taffy;
44    let layout = tree.layout(node).unwrap();
45    let style = tree.style(node).unwrap();
46
47    let num_children = tree.child_count(node);
48
49    let display_variant = match (num_children, style.display) {
50        (_, taffy::style::Display::None) => "NONE",
51        (0, _) => "LEAF",
52        (_, taffy::style::Display::Flex) => "FLEX",
53        (_, taffy::style::Display::Grid) => "GRID",
54        (_, taffy::style::Display::Block) => "BLOCK",
55    };
56
57    let fork_string = if has_sibling {
58        "├── "
59    } else {
60        "└── "
61    };
62    writeln!(
63        acc,
64        "{lines}{fork} {display} [x: {x:<4} y: {y:<4} width: {width:<4} height: {height:<4}] ({entity}) {measured}",
65        lines = lines_string,
66        fork = fork_string,
67        display = display_variant,
68        x = layout.location.x,
69        y = layout.location.y,
70        width = layout.size.width,
71        height = layout.size.height,
72        measured = if tree.get_node_context(node).is_some() { "measured" } else { "" }
73    ).ok();
74    let bar = if has_sibling { "│   " } else { "    " };
75    let new_string = lines_string + bar;
76
77    // Recurse into children
78    for (index, child_node) in tree.children(node).unwrap().iter().enumerate() {
79        let has_sibling = index < num_children - 1;
80        let child_entity = taffy_to_entity.get(child_node).unwrap();
81        print_node(
82            ui_surface,
83            taffy_to_entity,
84            *child_entity,
85            *child_node,
86            has_sibling,
87            new_string.clone(),
88            acc,
89        );
90    }
91}