use lunar_math::{Color, Vec2};
#[derive(Debug, Clone)]
pub struct Textbox {
pub text: String,
pub position: Vec2,
pub size: Vec2,
pub font_id: u32,
pub font_size: f32,
pub color: Color,
pub background_color: Option<Color>,
pub padding: f32,
pub typewriter: Option<TypewriterState>,
}
#[derive(Debug, Clone)]
pub struct TypewriterState {
pub visible_chars: usize,
pub char_count: usize,
pub interval: f32,
pub accumulator: f32,
pub complete: bool,
}
impl Textbox {
#[must_use]
pub fn new(text: &str, position: Vec2, size: Vec2) -> Self {
Self {
text: text.to_string(),
position,
size,
font_id: 0,
font_size: 16.0,
color: Color::WHITE,
background_color: None,
padding: 8.0,
typewriter: None,
}
}
pub fn set_font(&mut self, font_id: u32, font_size: f32) -> &mut Self {
self.font_id = font_id;
self.font_size = font_size;
self
}
pub fn set_color(&mut self, color: Color) -> &mut Self {
self.color = color;
self
}
pub fn set_background(&mut self, color: Color) -> &mut Self {
self.background_color = Some(color);
self
}
pub fn set_padding(&mut self, padding: f32) -> &mut Self {
self.padding = padding;
self
}
pub fn start_typewriter(&mut self, interval: f32) {
self.typewriter = Some(TypewriterState {
visible_chars: 0,
char_count: self.text.chars().count(),
interval,
accumulator: 0.0,
complete: false,
});
}
pub fn update_typewriter(&mut self, delta: f32) -> bool {
let Some(state) = &mut self.typewriter else {
return false;
};
if state.complete {
return false;
}
state.accumulator += delta;
while state.accumulator >= state.interval && state.visible_chars < state.char_count {
state.accumulator -= state.interval;
state.visible_chars += 1;
}
if state.visible_chars >= state.char_count {
state.complete = true;
false
} else {
true
}
}
pub fn skip_typewriter(&mut self) {
if let Some(state) = &mut self.typewriter {
state.visible_chars = state.char_count;
state.complete = true;
}
}
#[must_use]
pub fn visible_text(&self) -> &str {
if let Some(state) = &self.typewriter {
let char_count = state.visible_chars;
self.text
.char_indices()
.nth(char_count)
.map_or(&self.text, |(idx, _)| &self.text[..idx])
} else {
&self.text
}
}
}