diff --git a/crates/voltex_editor/src/ui_context.rs b/crates/voltex_editor/src/ui_context.rs index 814e6b7..f469817 100644 --- a/crates/voltex_editor/src/ui_context.rs +++ b/crates/voltex_editor/src/ui_context.rs @@ -41,6 +41,8 @@ pub struct UiContext { pub dragging: Option<(u32, u64)>, pub drag_start: (f32, f32), pub(crate) drag_started: bool, + /// TTF font for high-quality text rendering (None = bitmap fallback). + pub ttf_font: Option, } impl UiContext { @@ -70,6 +72,7 @@ impl UiContext { dragging: None, drag_start: (0.0, 0.0), drag_started: false, + ttf_font: None, } } @@ -141,4 +144,41 @@ impl UiContext { && self.mouse_y >= y && self.mouse_y < y + h } + + /// Draw text using TTF font if available, otherwise bitmap font fallback. + pub fn draw_text(&mut self, text: &str, x: f32, y: f32, color: [u8; 4]) { + if let Some(ref mut ttf) = self.ttf_font { + let ascender = ttf.ascender; + let mut cx = x; + for ch in text.chars() { + let info = ttf.glyph(ch).clone(); + if info.width > 0.0 && info.height > 0.0 { + let gx = cx + info.bearing_x; + let gy = y + ascender - info.bearing_y; + let (u0, v0, u1, v1) = (info.uv[0], info.uv[1], info.uv[2], info.uv[3]); + self.draw_list.add_rect_uv(gx, gy, info.width, info.height, u0, v0, u1, v1, color); + } + cx += info.advance; + } + } else { + // Bitmap font fallback + let gw = self.font.glyph_width as f32; + let gh = self.font.glyph_height as f32; + let mut cx = x; + for ch in text.chars() { + let (u0, v0, u1, v1) = self.font.glyph_uv(ch); + self.draw_list.add_rect_uv(cx, y, gw, gh, u0, v0, u1, v1, color); + cx += gw; + } + } + } + + /// Calculate text width using TTF or bitmap font. + pub fn ttf_text_width(&mut self, text: &str) -> f32 { + if let Some(ref mut ttf) = self.ttf_font { + ttf.text_width(text) + } else { + text.len() as f32 * self.font.glyph_width as f32 + } + } } diff --git a/examples/editor_demo/src/main.rs b/examples/editor_demo/src/main.rs index fbd9c07..7fe450f 100644 --- a/examples/editor_demo/src/main.rs +++ b/examples/editor_demo/src/main.rs @@ -227,9 +227,20 @@ impl ApplicationHandler for EditorDemoApp { let window = VoltexWindow::new(event_loop, &config); let gpu = GpuContext::new(window.handle.clone()); - let ui = UiContext::new(gpu.config.width as f32, gpu.config.height as f32); + let mut ui = UiContext::new(gpu.config.width as f32, gpu.config.height as f32); let ui_renderer = UiRenderer::new(&gpu.device, &gpu.queue, gpu.surface_format, &ui.font); + // Try to load TTF font + let ttf_data = std::fs::read("C:/Windows/Fonts/arial.ttf") + .or_else(|_| std::fs::read("C:/Windows/Fonts/consola.ttf")) + .or_else(|_| std::fs::read("C:/Windows/Fonts/malgun.ttf")) + .ok(); + if let Some(data) = ttf_data { + if let Ok(font) = voltex_editor::TtfFont::new(&data, 14.0) { + ui.ttf_font = Some(font); + } + } + let dock = DockTree::new( DockNode::split( Axis::Horizontal, 0.25,