Skip to main content

dreamwell_runtime/
runtime_ui.rs

1// Runtime UI — optional egui overlay for debug HUD, console, and dev tools.
2// Feature-gated behind `ui`. When disabled, all methods are no-ops.
3//
4// Usage: create RuntimeUi at startup, call handle_event() in the input phase,
5// run() in the render phase, and draw() to get paint jobs.
6
7#[cfg(feature = "ui")]
8use egui_winit::EventResponse;
9
10/// Runtime UI state. No-op when `ui` feature is disabled.
11pub struct RuntimeUi {
12    #[cfg(feature = "ui")]
13    ctx: egui::Context,
14    #[cfg(feature = "ui")]
15    winit_state: Option<egui_winit::State>,
16    #[cfg(feature = "ui")]
17    renderer: Option<egui_wgpu::Renderer>,
18    /// Whether the debug HUD is visible.
19    pub hud_visible: bool,
20}
21
22impl RuntimeUi {
23    /// Create runtime UI. Call after window creation.
24    pub fn new() -> Self {
25        Self {
26            #[cfg(feature = "ui")]
27            ctx: egui::Context::default(),
28            #[cfg(feature = "ui")]
29            winit_state: None,
30            #[cfg(feature = "ui")]
31            renderer: None,
32            hud_visible: false,
33        }
34    }
35
36    /// Initialize egui integration with the window and device.
37    #[cfg(feature = "ui")]
38    pub fn init(&mut self, window: &winit::window::Window, device: &wgpu::Device, surface_format: wgpu::TextureFormat) {
39        let viewport_id = self.ctx.viewport_id();
40        self.winit_state = Some(egui_winit::State::new(
41            self.ctx.clone(),
42            viewport_id,
43            window,
44            None,
45            None,
46            None,
47        ));
48        self.renderer = Some(egui_wgpu::Renderer::new(device, surface_format, None, 1, false));
49    }
50
51    /// Handle a winit event. Returns true if egui consumed the event.
52    #[cfg(feature = "ui")]
53    pub fn handle_event(&mut self, window: &winit::window::Window, event: &winit::event::WindowEvent) -> bool {
54        if let Some(ref mut state) = self.winit_state {
55            let response = state.on_window_event(window, event);
56            response.consumed
57        } else {
58            false
59        }
60    }
61
62    /// Handle a winit event (no-op when feature disabled).
63    #[cfg(not(feature = "ui"))]
64    pub fn handle_event(&mut self, _window: &winit::window::Window, _event: &winit::event::WindowEvent) -> bool {
65        false
66    }
67
68    /// Toggle HUD visibility (bound to F3).
69    pub fn toggle_hud(&mut self) {
70        self.hud_visible = !self.hud_visible;
71    }
72}
73
74impl Default for RuntimeUi {
75    fn default() -> Self {
76        Self::new()
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn runtime_ui_default() {
86        let ui = RuntimeUi::new();
87        assert!(!ui.hud_visible);
88    }
89
90    #[test]
91    fn toggle_hud() {
92        let mut ui = RuntimeUi::new();
93        ui.toggle_hud();
94        assert!(ui.hud_visible);
95        ui.toggle_hud();
96        assert!(!ui.hud_visible);
97    }
98}