use rich_rs::{Console, ConsoleOptions, Renderable, Segments, Text};
use crate::widgets::{Label, Node, Widget, WidgetStyles};
enum StaticContent {
Plain,
Rich(Text),
}
pub struct Static {
label: Label,
content: StaticContent,
}
impl Static {
pub fn new(text: impl Into<String>) -> Self {
Self {
label: Label::new(text).with_markup(true),
content: StaticContent::Plain,
}
}
pub fn class(self, value: impl Into<String>) -> Node {
Node::new(self).class(value)
}
pub fn id(self, value: impl Into<String>) -> Node {
Node::new(self).id(value)
}
pub fn update(&mut self, text: impl Into<String>) {
self.label.set_text(text.into());
self.content = StaticContent::Plain;
}
pub fn update_rich(&mut self, text: Text) {
self.content = StaticContent::Rich(text);
}
pub fn clear(&mut self) {
self.label.set_text(String::new());
self.content = StaticContent::Plain;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn static_update_changes_content() {
let mut widget = Static::new("initial");
widget.update("updated");
assert!(matches!(widget.content, StaticContent::Plain));
}
#[test]
fn static_update_rich_switches_to_rich_variant() {
let mut widget = Static::new("initial");
let text = Text::plain("rich content");
widget.update_rich(text);
assert!(matches!(widget.content, StaticContent::Rich(_)));
}
#[test]
fn static_update_after_rich_reverts_to_plain() {
let mut widget = Static::new("initial");
widget.update_rich(Text::plain("rich"));
widget.update("plain again");
assert!(matches!(widget.content, StaticContent::Plain));
}
#[test]
fn static_clear_sets_plain_empty() {
let mut widget = Static::new("hello");
widget.update_rich(Text::plain("rich"));
widget.clear();
assert!(matches!(widget.content, StaticContent::Plain));
}
#[test]
fn static_layout_height_rich_returns_line_count() {
let mut widget = Static::new("");
let text = Text::plain("line one\nline two\nline three");
widget.update_rich(text);
assert_eq!(widget.layout_height(), Some(3));
}
}
impl Widget for Static {
fn render(&self, console: &Console, options: &ConsoleOptions) -> Segments {
match &self.content {
StaticContent::Plain => Widget::render(&self.label, console, options),
StaticContent::Rich(text) => text.render(console, options),
}
}
fn on_layout(&mut self, width: u16, height: u16) {
self.label.on_layout(width, height);
}
fn layout_height(&self) -> Option<usize> {
match &self.content {
StaticContent::Plain => self.label.layout_height(),
StaticContent::Rich(text) => {
let line_count = text.plain_text().lines().count().max(1);
Some(line_count)
}
}
}
fn content_width(&self) -> Option<usize> {
self.label.content_width()
}
fn styles(&self) -> Option<&WidgetStyles> {
self.label.styles()
}
fn styles_mut(&mut self) -> Option<&mut WidgetStyles> {
self.label.styles_mut()
}
}