hUI/hui/src/element.rs

116 lines
3.7 KiB
Rust
Raw Normal View History

2024-03-01 18:07:53 -06:00
//! element API and built-in elements like `Container`, `Button`, `Text`, etc.
2024-02-17 14:43:46 -06:00
use std::any::Any;
use crate::{
2024-03-06 19:04:24 -06:00
draw::{atlas::ImageCtx, UiDrawCommandList},
2024-03-11 12:40:11 -05:00
input::InputCtx,
layout::LayoutInfo,
measure::Response,
2024-03-11 19:26:48 -05:00
signal::SignalStore,
state::StateRepo,
text::{FontHandle, TextMeasure},
2024-03-11 12:40:11 -05:00
UiInstance,
2024-02-17 14:43:46 -06:00
};
mod builtin;
2024-02-17 14:43:46 -06:00
pub use builtin::*;
2024-02-20 11:19:10 -06:00
/// Context for the `Element::measure` function
pub struct MeasureContext<'a> {
pub state: &'a StateRepo,
pub layout: &'a LayoutInfo,
pub text_measure: TextMeasure<'a>,
pub current_font: FontHandle,
2024-03-06 19:04:24 -06:00
pub images: ImageCtx<'a>,
2024-03-11 12:40:11 -05:00
//XXX: should measure have a reference to input?
//pub input: InputCtx<'a>,
}
2024-02-20 11:19:10 -06:00
/// Context for the `Element::process` function
pub struct ProcessContext<'a> {
pub measure: &'a Response,
pub state: &'a mut StateRepo,
pub layout: &'a LayoutInfo,
2024-02-19 14:12:12 -06:00
pub draw: &'a mut UiDrawCommandList,
pub text_measure: TextMeasure<'a>,
pub current_font: FontHandle,
2024-03-06 19:04:24 -06:00
pub images: ImageCtx<'a>,
2024-03-11 12:40:11 -05:00
pub input: InputCtx<'a>,
2024-03-11 19:26:48 -05:00
pub signal: &'a mut SignalStore,
}
2024-02-17 14:43:46 -06:00
pub trait UiElement {
2024-02-20 11:19:10 -06:00
/// Get the name of the element, for example "Button" or "ProgressBar"
2024-03-06 10:19:35 -06:00
fn name(&self) -> &'static str;
2024-02-20 11:19:10 -06:00
/// Get the unique id used for internal state management\
/// This value must be unique for each instance of the element
///
/// If the element is stateless, this function should return `None`
2024-02-17 14:43:46 -06:00
fn state_id(&self) -> Option<u64> { None }
2024-02-20 11:19:10 -06:00
2024-03-06 10:19:35 -06:00
/// Check if the element has state.\
/// Should not be overridden
2024-02-17 14:43:46 -06:00
fn is_stateful(&self) -> bool { self.state_id().is_some() }
2024-02-20 11:19:10 -06:00
2024-03-06 10:19:35 -06:00
/// Check if the element has no state\
/// Should not be overridden
fn is_stateless(&self) -> bool { !self.is_stateful() }
2024-02-20 11:19:10 -06:00
/// Initialize the state of the element\
/// This function should be called exactly once during the lifetime of the element,
/// or if the state gets reset
///
/// This function will not get called for stateless elements
2024-02-17 14:43:46 -06:00
fn init_state(&self) -> Option<Box<dyn Any>> { None }
2024-02-20 11:19:10 -06:00
/// Measure step, guaranteed to be called before the `process` step\
/// May be called multiple times per single frame, so it should not contain any expensive calls\
/// This function may not mutate any state.\
///
/// This function should return the size of the element along with any hints or layout metadata
fn measure(&self, ctx: MeasureContext) -> Response;
2024-02-20 11:19:10 -06:00
/// Process step, guaranteed to be called after the `measure` step\
/// You should process the user inputs and render the element here.
fn process(&self, ctx: ProcessContext);
2024-02-17 14:43:46 -06:00
}
2024-02-25 18:15:55 -06:00
/// A list of elements\
/// Use the [`add`](`ElementList::add`) method to add elements to the list
2024-02-25 18:15:55 -06:00
pub struct ElementList(pub Vec<Box<dyn UiElement>>);
impl ElementList {
/// Add an element to the list
pub fn add(&mut self, element: impl UiElement + 'static) {
2024-02-25 18:15:55 -06:00
self.0.push(Box::new(element))
}
/// Create a new `ElementList` from a callback\
/// The callback will be called with a reference to the newly list
2024-02-26 09:33:55 -06:00
pub(crate) fn from_callback(cb: impl FnOnce(&mut ElementList)) -> Self {
2024-02-25 18:15:55 -06:00
let mut list = ElementList(Vec::new());
cb(&mut list);
list
}
}
2024-03-01 18:07:53 -06:00
/// Extension trait for [`UiElement`] that adds the [`add_child`] and [`add_root`] methods
pub trait UiElementExt: UiElement {
2024-02-26 13:04:52 -06:00
/// Add element as a child/nested element.
fn add_child(self, ui: &mut ElementList);
2024-02-26 13:04:52 -06:00
/// Add element as a ui root.
fn add_root(self, ui: &mut UiInstance, max_size: glam::Vec2);
2024-02-25 18:15:55 -06:00
}
impl<T: UiElement + 'static> UiElementExt for T {
fn add_child(self, ui: &mut ElementList) {
2024-02-25 18:20:52 -06:00
ui.add(self)
2024-02-25 18:15:55 -06:00
}
2024-03-01 18:07:53 -06:00
fn add_root(self, ui: &mut UiInstance, max_size: glam::Vec2) {
ui.add(self, max_size);
}
2024-02-25 18:15:55 -06:00
}