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()
|
|
|
|
}
|
|
|
|
}
|