yog_ui/lib.rs
1//! yog-ui — retained-mode UI framework for Yog mods.
2//!
3//! Flexbox-inspired layout engine + GPU rendering via [`yog-gfx`].
4//! Use for custom inventories, guide books, tooltips, HUD overlays.
5//!
6//! # Quick start
7//! ```ignore
8//! use yog_ui::{UiRoot, widget, Align, FlexDir, Units};
9//!
10//! let ui = UiRoot::new("mymod:main_menu")
11//! .style(|s| s.bg(0x88332211).padding(8.0, 8.0, 8.0, 8.0))
12//! .child(
13//! widget::panel(FlexDir::Column).gap(4.0)
14//! .child(widget::label("Hello, World!").color(0xFF_DDAA00))
15//! .child(widget::button("Click me").on_click("mymod:btn_click"))
16//! );
17//! ```
18
19mod layout;
20pub mod widget;
21
22pub use layout::{Align, FlexDir, LayoutNode, Rect, Size};
23pub use widget::Widget;
24
25use yog_gfx::GfxContext;
26
27/// Top-level UI tree. Build it, call [`layout`], then [`render`] each frame.
28pub struct UiRoot {
29 pub id: String,
30 pub root: Widget,
31 pub(crate) layout_root: LayoutNode,
32 pub needs_layout: bool,
33}
34
35impl UiRoot {
36 pub fn new(id: impl Into<String>, root: Widget) -> Self {
37 Self { id: id.into(), root, layout_root: LayoutNode::default(), needs_layout: true }
38 }
39
40 /// Recalculate layout. Call after changing the tree or on window resize.
41 pub fn layout(&mut self, screen_w: f32, screen_h: f32) {
42 self.layout_root = layout::compute(&self.root, screen_w, screen_h);
43 self.needs_layout = false;
44 }
45
46 /// Render the UI tree. Must be called from within `on_hud_render` or
47 /// `on_world_render` (HUD mode).
48 pub fn render(&self, ctx: &GfxContext) {
49 // TODO: render the layout tree via yog-gfx draw2d
50 let _ = ctx;
51 }
52
53 /// Find the deepest widget at `(mx, my)` in screen coordinates.
54 pub fn hit_test(&self, mx: f32, my: f32) -> Option<&LayoutNode> {
55 layout::hit_test(&self.layout_root, mx, my)
56 }
57}