Skip to main content

khora_core/ui/
editor_overlay.rs

1// Copyright 2025 eraflo
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Abstract trait for editor overlay rendering.
16//!
17//! The [`EditorOverlay`] trait defines the interface for rendering an immediate-mode
18//! UI overlay on top of the engine's 3D scene. The concrete implementation lives in
19//! `khora-infra` (e.g., `EguiOverlay` backed by egui + wgpu).
20//!
21//! # Architecture
22//!
23//! ```text
24//! khora-core   → EditorOverlay trait (this file)
25//! khora-infra  → EguiOverlay : impl EditorOverlay (egui + custom wgpu renderer)
26//! khora-sdk    → EngineState integrates the overlay into the frame loop
27//! khora-editor → Application that builds the editor UI via the shared context
28//! ```
29
30use std::any::Any;
31use std::fmt;
32
33/// Descriptor for the current screen state, passed to the overlay each frame.
34#[derive(Debug, Clone, Copy)]
35pub struct OverlayScreenDescriptor {
36    /// Width of the render target in physical pixels.
37    pub width_px: u32,
38    /// Height of the render target in physical pixels.
39    pub height_px: u32,
40    /// HiDPI scale factor (physical pixels per logical point).
41    pub scale_factor: f32,
42}
43
44/// Error type for overlay operations.
45#[derive(Debug)]
46pub struct OverlayError(pub String);
47
48impl fmt::Display for OverlayError {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        write!(f, "OverlayError: {}", self.0)
51    }
52}
53
54impl std::error::Error for OverlayError {}
55
56/// Abstract trait for an editor UI overlay rendered on top of the 3D scene.
57///
58/// The overlay manages its own UI context (e.g., `egui::Context`) and renderer.
59/// It processes input events, builds UI each frame, and renders the result
60/// as a final pass over the swapchain texture.
61///
62/// # Lifecycle per frame
63///
64/// 1. [`handle_window_event`](Self::handle_window_event) — called for each raw
65///    window event (winit). Returns `true` if the overlay consumed the event.
66/// 2. [`begin_frame`](Self::begin_frame) — starts a new UI frame.
67/// 3. *(Application builds UI using the context returned by [`ui_context`](Self::ui_context))*
68/// 4. [`end_frame_and_render`](Self::end_frame_and_render) — finalizes the UI,
69///    tessellates, and renders onto the current render target.
70pub trait EditorOverlay: Send + Sync {
71    /// Process a raw window event for the overlay.
72    ///
73    /// The `event` parameter is a type-erased `winit::event::WindowEvent`.
74    ///
75    /// Returns `true` if the overlay consumed the event (e.g., the cursor is
76    /// over an overlay panel). When `true`, the engine should **not** forward
77    /// the event to the game's input system.
78    fn handle_window_event(&mut self, window: &dyn Any, event: &dyn Any) -> bool;
79
80    /// Starts a new overlay frame.
81    ///
82    /// `window` is a type-erased `winit::window::Window` reference, used by
83    /// the input translation layer to read screen size and scale factor.
84    ///
85    /// Must be called exactly once per frame, before the application builds its UI.
86    fn begin_frame(&mut self, window: &dyn Any, screen: OverlayScreenDescriptor);
87
88    /// Returns the UI context as a type-erased reference.
89    ///
90    /// The concrete type is `egui::Context` for the egui backend.
91    /// The editor (`khora-editor`) downcasts this to build its panels.
92    fn ui_context(&self) -> &dyn Any;
93
94    /// Ends the current frame and renders the overlay.
95    ///
96    /// `render_state` is a type-erased struct containing the GPU resources
97    /// needed for rendering (device, queue, encoder, target view, etc.).
98    /// The concrete type depends on the backend.
99    fn end_frame_and_render(&mut self, render_state: &mut dyn Any) -> Result<(), OverlayError>;
100
101    /// Returns `true` if the overlay wants exclusive pointer input this frame.
102    ///
103    /// When `true`, pointer events (clicks, drags) should not be forwarded to the game.
104    fn wants_pointer_input(&self) -> bool;
105
106    /// Returns `true` if the overlay wants exclusive keyboard input this frame.
107    ///
108    /// When `true`, keyboard events should not be forwarded to the game.
109    fn wants_keyboard_input(&self) -> bool;
110
111    /// Downcasting support.
112    fn as_any(&self) -> &dyn Any;
113
114    /// Mutable downcasting support.
115    fn as_any_mut(&mut self) -> &mut dyn Any;
116}