Skip to main content

a2ui_tui/components/
divider.rs

1//! Divider component — renders a horizontal or vertical separator line.
2
3use ratatui::{
4    Frame,
5    layout::Rect,
6    style::{Color, Style},
7    widgets::Paragraph,
8};
9
10use a2ui_base::model::component_context::ComponentContext;
11use crate::component_impl::TuiComponent;
12
13/// Divider component implementation.
14///
15/// Renders a horizontal `─────` line or a vertical `│` character
16/// in a dim color to visually separate content.
17/// Applies a default 1-cell margin.
18pub struct DividerComponent;
19
20impl TuiComponent for DividerComponent {
21    fn name(&self) -> &'static str {
22        "Divider"
23    }
24
25    fn render(
26        &self,
27        ctx: &ComponentContext,
28        area: Rect,
29        frame: &mut Frame,
30        _render_child: &mut dyn FnMut(&str, Rect, &mut Frame, &str),
31        _measure_child: &mut dyn FnMut(&str, &str, u16) -> Option<u16>,
32    ) {
33        let comp_model = match ctx.components.get(&ctx.component_id) {
34            Some(m) => m,
35            None => return,
36        };
37
38        // Apply default 1-cell margin on all sides (never collapses to zero).
39        let inner = crate::layout_engine::padded_content(area);
40
41        if inner.width == 0 || inner.height == 0 {
42            return;
43        }
44
45        let axis: Option<String> = comp_model.get_property("axis");
46        let dim_style = Style::default().fg(Color::DarkGray);
47
48        match axis.as_deref() {
49            Some("vertical") => {
50                // Vertical divider: render a column of '│' characters.
51                let line: String = "│".repeat(inner.height as usize);
52                let paragraph = Paragraph::new(line).style(dim_style);
53                frame.render_widget(paragraph, inner);
54            }
55            _ => {
56                // Horizontal divider (default): render a line of '─' characters.
57                let line: String = "─".repeat(inner.width as usize);
58                let paragraph = Paragraph::new(line).style(dim_style);
59                frame.render_widget(paragraph, inner);
60            }
61        }
62    }
63
64    fn natural_height(
65        &self,
66        ctx: &ComponentContext,
67        _available_width: u16,
68        _measure_child: &mut dyn FnMut(&str, &str, u16) -> Option<u16>,
69    ) -> Option<u16> {
70        // Read the axis property: a vertical divider fills its column (no
71        // intrinsic height); a horizontal divider is a single line + 2-cell
72        // margin.
73        let comp_model = ctx.components.get(&ctx.component_id)?;
74        let axis: Option<String> = comp_model.get_property("axis");
75        match axis.as_deref() {
76            Some("vertical") => None,
77            _ => Some(3),
78        }
79    }
80}