use crate::core::style::TextStyle;
use crate::core::{Color, Position, Rect, Style};
use crate::ontology::*;
use crate::runtime::Frame;
use crate::widget::Widget;
pub struct Container {
style: Style,
title: Option<String>,
agent_id: String,
}
impl Container {
#[must_use]
pub fn new() -> Self {
Self {
style: Style::default(),
title: None,
agent_id: String::new(),
}
}
pub fn style(mut self, style: Style) -> Self {
self.style = style;
self
}
pub fn bg(mut self, color: Color) -> Self {
self.style.background = Some(color);
self
}
pub fn fg(mut self, color: Color) -> Self {
self.style.foreground = Some(color);
self
}
pub fn rounded(mut self, radius: f32) -> Self {
self.style.border_radius = Some(radius);
self
}
pub fn border(mut self, color: Color, width: f32) -> Self {
self.style.border_color = Some(color);
self.style.border_width = Some(width);
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn agent_id(mut self, id: impl Into<String>) -> Self {
self.agent_id = id.into();
self
}
}
impl Default for Container {
fn default() -> Self {
Self::new()
}
}
impl Discoverable for Container {
fn schema(&self) -> WidgetSchema {
let mut schema = WidgetSchema::new(
"Container",
"A styled layout container",
SemanticRole::Container,
);
schema.usage_hint = Some("Container::new().title(\"Section\")".into());
schema.tags = vec!["container".into(), "layout".into(), "group".into()];
schema
}
fn capabilities(&self) -> Vec<AgentCapability> {
vec![]
}
fn actions(&self) -> Vec<AgentAction> {
vec![]
}
fn semantic_role(&self) -> SemanticRole {
SemanticRole::Container
}
fn agent_state(&self) -> serde_json::Value {
serde_json::json!({ "title": self.title })
}
fn execute_action(
&mut self,
_action: &str,
_params: &serde_json::Value,
) -> Result<serde_json::Value, String> {
Err("Container has no actions".to_string())
}
fn agent_id(&self) -> Option<&str> {
if self.agent_id.is_empty() {
None
} else {
Some(&self.agent_id)
}
}
fn accessibility_label(&self) -> Option<String> {
self.title.clone()
}
}
impl Widget for Container {
fn render(self, area: Rect, frame: &mut Frame<'_>) {
if !self.agent_id.is_empty() {
let mut node = UiNode::new("Container", SemanticRole::Container)
.with_id(&self.agent_id)
.with_bounds(area.into());
if let Some(ref title) = self.title {
node = node.with_property("title", serde_json::json!(title));
}
frame.register_widget(node);
}
let bg = self.style.background.unwrap_or(Color::TRANSPARENT);
let radius = self.style.border_radius.unwrap_or(0.0);
if bg.a > 0.0 {
frame.painter().fill_rect(area, bg, radius);
}
if let (Some(border), Some(border_w)) = (self.style.border_color, self.style.border_width) {
if border.a > 0.0 && border_w > 0.0 {
frame.painter().stroke_rect(area, border, border_w, radius);
}
}
if let Some(title) = &self.title {
let ts = TextStyle {
font_size: 18.0,
color: Color::WHITE,
..Default::default()
};
frame
.painter()
.text(Position::new(area.x + 4.0, area.y + 4.0), title, &ts);
}
}
}