hUI/hui/src/instance.rs

133 lines
4.4 KiB
Rust
Raw Normal View History

2024-02-20 10:49:44 -06:00
use std::collections::VecDeque;
use glam::Vec2;
use crate:: {
layout::{UiDirection, LayoutInfo},
element::{MeasureContext, ProcessContext, UiElement},
event::UiEvent,
state::StateRepo,
2024-02-21 13:13:58 -06:00
draw::{UiDrawCommandList, UiDrawCall},
2024-02-20 10:49:44 -06:00
text::{TextRenderer, FontTextureInfo, FontHandle},
};
2024-02-20 11:19:10 -06:00
/// The main instance of the UI system.\
/// In most cases, you should only have one instance of this struct.
2024-02-20 10:49:44 -06:00
pub struct UiInstance {
//mouse_position: Vec2,
stateful_state: StateRepo,
//event_queue: VecDeque<UiEvent>,
prev_draw_commands: UiDrawCommandList,
draw_commands: UiDrawCommandList,
2024-02-21 13:13:58 -06:00
draw_call: UiDrawCall,
draw_call_modified: bool,
2024-02-20 10:49:44 -06:00
text_renderer: TextRenderer,
events: VecDeque<UiEvent>,
}
impl UiInstance {
2024-02-20 11:19:10 -06:00
/// Crate and initialize a new instance of the UI
///
/// In most cases, you should only do this *once*, during the initialization of your application
2024-02-20 10:49:44 -06:00
pub fn new() -> Self {
UiInstance {
//mouse_position: Vec2::ZERO,
stateful_state: StateRepo::default(),
//event_queue: VecDeque::new(),
// root_elements: Vec::new(),
prev_draw_commands: UiDrawCommandList::default(),
draw_commands: UiDrawCommandList::default(),
2024-02-21 13:13:58 -06:00
draw_call: UiDrawCall::default(),
draw_call_modified: false,
2024-02-20 10:49:44 -06:00
// ftm: FontTextureManager::default(),
text_renderer: TextRenderer::new(),
events: VecDeque::new(),
}
}
2024-02-20 11:19:10 -06:00
/// Parse and add a font from a raw byte slice to the UI\
/// Returns a font handle.
2024-02-20 10:49:44 -06:00
pub fn add_font_from_bytes(&mut self, font: &[u8]) -> FontHandle {
self.text_renderer.add_font_from_bytes(font)
}
2024-02-20 11:19:10 -06:00
/// Add an element or an element tree to the UI
///
/// Use the `max_size` parameter to specify the maximum size of the element\
/// (usually, the size of the window/screen)
2024-02-20 10:49:44 -06:00
pub fn add<T: UiElement>(&mut self, element: T, max_size: Vec2) {
let layout = LayoutInfo {
position: Vec2::ZERO,
max_size,
direction: UiDirection::Vertical,
};
let measure = element.measure(MeasureContext {
state: &self.stateful_state,
layout: &layout,
text_measure: self.text_renderer.to_measure(),
});
element.process(ProcessContext {
measure: &measure,
state: &mut self.stateful_state,
layout: &layout,
draw: &mut self.draw_commands,
text_measure: self.text_renderer.to_measure(),
});
}
2024-02-20 11:19:10 -06:00
/// Prepare the UI for layout and processing
///
/// You must call this function at the beginning of the frame, before adding any elements
2024-02-20 10:49:44 -06:00
pub fn begin(&mut self) {
std::mem::swap(&mut self.prev_draw_commands, &mut self.draw_commands);
2024-02-21 13:13:58 -06:00
self.draw_call_modified = false;
2024-02-20 10:49:44 -06:00
self.draw_commands.commands.clear();
self.text_renderer.reset_frame();
}
2024-02-20 11:19:10 -06:00
/// End the frame and prepare the UI for rendering
///
/// You must call this function at the end of the frame, before rendering the UI
2024-02-20 10:49:44 -06:00
pub fn end(&mut self) {
if self.draw_commands.commands == self.prev_draw_commands.commands {
return
}
2024-02-21 13:13:58 -06:00
self.draw_call = UiDrawCall::build(&self.draw_commands, &mut self.text_renderer);
self.draw_call_modified = true;
2024-02-20 10:49:44 -06:00
}
2024-02-21 13:13:58 -06:00
/// Get the draw call for the current frame
2024-02-20 11:19:10 -06:00
///
/// This function should only be used by the render backend.\
/// You should not call this directly unless you're implementing a custom render backend
///
/// Returns a tuple with a boolean indicating if the draw plan was modified since the last frame
2024-02-21 13:13:58 -06:00
pub fn draw_call(&self) -> (bool, &UiDrawCall) {
(self.draw_call_modified, &self.draw_call)
2024-02-20 10:49:44 -06:00
}
2024-02-20 11:19:10 -06:00
/// Get the font texture for the current frame
///
/// This function should only be used by the render backend.\
/// You should not call this directly unless you're implementing a custom render backend
///
/// Make sure to check `FontTextureInfo::modified` to see if the texture was modified
/// since the last frame before uploading it to the GPU
2024-02-20 10:49:44 -06:00
pub fn font_texture(&self) -> FontTextureInfo {
self.text_renderer.font_texture()
}
2024-02-20 11:19:10 -06:00
/// Push a platform event to the UI event queue
///
/// This function should only be used by the platform backend.\
/// You should not call this directly unless you're implementing a custom platform backend
/// or have a very specific usecase
2024-02-20 10:49:44 -06:00
pub fn push_event(&mut self, event: UiEvent) {
self.events.push_back(event);
}
}
impl Default for UiInstance {
fn default() -> Self {
Self::new()
}
}