2024-02-17 14:43:46 -06:00
|
|
|
use std::any::Any;
|
|
|
|
use crate::{
|
2024-02-26 08:13:03 -06:00
|
|
|
draw::UiDrawCommandList, layout::LayoutInfo, measure::Response, state::StateRepo, text::TextMeasure, UiInstance
|
2024-02-17 14:43:46 -06:00
|
|
|
};
|
|
|
|
|
2024-02-19 16:13:35 -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
|
2024-02-17 21:04:02 -06:00
|
|
|
pub struct MeasureContext<'a> {
|
|
|
|
pub state: &'a StateRepo,
|
|
|
|
pub layout: &'a LayoutInfo,
|
|
|
|
pub text_measure: TextMeasure<'a>,
|
|
|
|
}
|
|
|
|
|
2024-02-20 11:19:10 -06:00
|
|
|
/// Context for the `Element::process` function
|
2024-02-17 21:04:02 -06:00
|
|
|
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,
|
2024-02-17 21:04:02 -06:00
|
|
|
pub text_measure: TextMeasure<'a>,
|
|
|
|
}
|
|
|
|
|
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-02-17 14:43:46 -06:00
|
|
|
fn name(&self) -> &'static str { "UiElement" }
|
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
|
|
|
|
|
|
|
/// Check if the element has state
|
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
|
|
|
|
|
|
|
/// Check if the element has no state
|
2024-02-17 14:43:46 -06:00
|
|
|
fn is_stateless(&self) -> bool { self.state_id().is_none() }
|
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
|
2024-02-17 21:04:02 -06:00
|
|
|
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.
|
2024-02-17 21:04:02 -06:00
|
|
|
fn process(&self, ctx: ProcessContext);
|
2024-02-17 14:43:46 -06:00
|
|
|
}
|
2024-02-25 18:15:55 -06:00
|
|
|
|
|
|
|
pub struct ElementList(pub Vec<Box<dyn UiElement>>);
|
|
|
|
|
|
|
|
impl ElementList {
|
2024-02-26 08:13:03 -06:00
|
|
|
pub fn add(&mut self, element: impl UiElement + 'static) {
|
2024-02-25 18:15:55 -06:00
|
|
|
self.0.push(Box::new(element))
|
|
|
|
}
|
|
|
|
|
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-02-26 09:33:55 -06:00
|
|
|
// impl<T: FnOnce(&mut ElementList)> From<T> for ElementList {
|
|
|
|
// fn from(cb: T) -> Self {
|
|
|
|
// let mut list = ElementList(Vec::new());
|
|
|
|
// cb(&mut list);
|
|
|
|
// list
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// impl<T: UiElement + 'static> From<T> for ElementList {
|
|
|
|
// fn from(value: T) -> Self {
|
|
|
|
// ElementList(vec![Box::new(value)])
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// impl From<Vec<Box<dyn UiElement>>> for ElementList {
|
|
|
|
// fn from(value: Vec<Box<dyn UiElement>>) -> Self {
|
|
|
|
// Self(value)
|
|
|
|
// }
|
|
|
|
// }
|
2024-02-25 18:15:55 -06:00
|
|
|
|
2024-02-26 08:13:03 -06:00
|
|
|
pub trait UiElementExt: UiElement {
|
|
|
|
fn add_child(self, ui: &mut ElementList);
|
|
|
|
fn add_root(self, ui: &mut UiInstance, resolution: glam::Vec2);
|
2024-02-25 18:15:55 -06:00
|
|
|
}
|
|
|
|
|
2024-02-26 08:13:03 -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-02-26 08:13:03 -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
|
|
|
}
|