use crate::geometry::{Color, Rect};
use crate::painter::Painter;
use crate::theme::Theme;
use crate::widget::Widget;
pub struct Label {
pub rect: Rect,
pub text: String,
pub size: Option<f32>,
pub color: Option<Color>,
pub background: Option<Color>,
}
impl Label {
pub fn new(rect: Rect, text: impl Into<String>) -> Self {
Self {
rect,
text: text.into(),
size: None,
color: None,
background: None,
}
}
pub fn with_color(mut self, color: Color) -> Self {
self.color = Some(color);
self
}
pub fn with_size(mut self, size: f32) -> Self {
self.size = Some(size);
self
}
pub fn with_background(mut self, color: Color) -> Self {
self.background = Some(color);
self
}
}
fn layout_lines(painter: &Painter, text: &str, size: f32, max_width: i32) -> Vec<String> {
let mut lines = Vec::new();
for paragraph in text.split('\n') {
if max_width > 0 {
wrap_paragraph(painter, paragraph, size, max_width, &mut lines);
} else {
lines.push(paragraph.to_string());
}
}
lines
}
fn wrap_paragraph(
painter: &Painter,
paragraph: &str,
size: f32,
max_width: i32,
out: &mut Vec<String>,
) {
let mut current = String::new();
for word in paragraph.split_whitespace() {
if current.is_empty() {
current.push_str(word);
continue;
}
let candidate = format!("{current} {word}");
if painter.measure_text(&candidate, size).w <= max_width {
current = candidate;
} else {
out.push(std::mem::take(&mut current));
current.push_str(word);
}
}
out.push(current);
}
impl Widget for Label {
fn bounds(&self) -> Rect {
self.rect
}
fn layout(&mut self, bounds: Rect) {
self.rect = bounds;
}
fn paint(&mut self, painter: &mut Painter, theme: &Theme) {
if let Some(bg) = self.background {
painter.fill_rect(self.rect, bg);
}
let size = self.size.unwrap_or(theme.font_size);
let color = self.color.unwrap_or(theme.text);
let line_height = painter.measure_text("", size).h.max(1);
let lines = layout_lines(painter, &self.text, size, self.rect.w);
let saved = painter.push_clip(self.rect);
let mut y = self.rect.y;
for line in &lines {
painter.text(self.rect.x, y, line, size, color);
y += line_height;
}
painter.restore_clip(saved);
}
}