repose_devtools/
lib.rs

1use web_time::Instant;
2
3use repose_core::{Color, Rect, Scene, SceneNode};
4
5pub struct Hud {
6    pub inspector_enabled: bool,
7    pub hovered: Option<Rect>,
8    frame_count: u64,
9    last_frame: Option<Instant>,
10    fps_smooth: f32,
11    pub metrics: Option<Metrics>,
12}
13
14impl Default for Hud {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl Hud {
21    pub fn new() -> Self {
22        Self {
23            inspector_enabled: false,
24            hovered: None,
25            frame_count: 0,
26            last_frame: None,
27            fps_smooth: 0.0,
28            metrics: None,
29        }
30    }
31    pub fn toggle_inspector(&mut self) {
32        self.inspector_enabled = !self.inspector_enabled;
33    }
34    pub fn set_hovered(&mut self, r: Option<Rect>) {
35        self.hovered = r;
36    }
37
38    pub fn overlay(&mut self, scene: &mut Scene) {
39        self.frame_count += 1;
40        // FPS
41        let now = Instant::now();
42        if let Some(prev) = self.last_frame.replace(now) {
43            let dt = (now - prev).as_secs_f32();
44            if dt > 0.0 {
45                let fps = 1.0 / dt;
46                // simple EMA
47                let a = 0.2;
48                self.fps_smooth = if self.fps_smooth == 0.0 {
49                    fps
50                } else {
51                    (1.0 - a) * self.fps_smooth + a * fps
52                };
53            }
54        }
55        let mut lines = vec![
56            format!("frame: {}", self.frame_count),
57            format!("fps: {:.1}", self.fps_smooth),
58        ];
59        if let Some(m) = &self.metrics {
60            lines.push(format!("build+layout: {:.2} ms", m.build_layout_ms));
61            lines.push(format!("nodes: {}", m.scene_nodes));
62        }
63        let text = lines.join("  |  ");
64        scene.nodes.push(SceneNode::Text {
65            rect: Rect {
66                x: 8.0,
67                y: 8.0,
68                w: 200.0,
69                h: 16.0,
70            },
71            text,
72            color: Color::from_hex("#AAAAAA"),
73            size: 14.0,
74        });
75
76        if let Some(r) = self.hovered {
77            scene.nodes.push(SceneNode::Border {
78                rect: r,
79                color: Color::from_hex("#44AAFF"),
80                width: 2.0,
81                radius: 0.0,
82            });
83        }
84    }
85}
86
87#[derive(Clone, Debug, Default)]
88pub struct Metrics {
89    pub build_layout_ms: f32,
90    pub scene_nodes: usize,
91}
92
93pub struct Inspector {
94    pub hud: Hud,
95}
96impl Default for Inspector {
97    fn default() -> Self {
98        Self::new()
99    }
100}
101
102impl Inspector {
103    pub fn new() -> Self {
104        Self { hud: Hud::new() }
105    }
106    pub fn frame(&mut self, scene: &mut Scene) {
107        if self.hud.inspector_enabled {
108            self.hud.overlay(scene);
109        }
110    }
111}