Skip to main content

fresh/view/controls/toggle/
render.rs

1//! Toggle rendering functions
2
3use ratatui::layout::Rect;
4use ratatui::style::Style;
5use ratatui::text::{Line, Span};
6use ratatui::widgets::Paragraph;
7use ratatui::Frame;
8
9use super::{FocusState, ToggleColors, ToggleLayout, ToggleState};
10
11/// Render a toggle control
12///
13/// # Arguments
14/// * `frame` - The ratatui frame to render to
15/// * `area` - Rectangle where the toggle should be rendered
16/// * `state` - The toggle state
17/// * `colors` - Colors for rendering
18///
19/// # Returns
20/// Layout information for hit testing
21pub fn render_toggle(
22    frame: &mut Frame,
23    area: Rect,
24    state: &ToggleState,
25    colors: &ToggleColors,
26) -> ToggleLayout {
27    render_toggle_aligned(frame, area, state, colors, None)
28}
29
30/// Render a toggle control with optional label width alignment
31///
32/// # Arguments
33/// * `frame` - The ratatui frame to render to
34/// * `area` - Rectangle where the toggle should be rendered
35/// * `state` - The toggle state
36/// * `colors` - Colors for rendering
37/// * `label_width` - Optional minimum label width for alignment
38///
39/// # Returns
40/// Layout information for hit testing
41pub fn render_toggle_aligned(
42    frame: &mut Frame,
43    area: Rect,
44    state: &ToggleState,
45    colors: &ToggleColors,
46    label_width: Option<u16>,
47) -> ToggleLayout {
48    if area.height == 0 || area.width < 4 {
49        return ToggleLayout {
50            checkbox_area: Rect::default(),
51            full_area: area,
52        };
53    }
54
55    // Use focused_fg for text when focused (not focused, which is the bg color)
56    let (bracket_color, _check_color, label_color) = match state.focus {
57        FocusState::Normal => (colors.bracket, colors.checkmark, colors.label),
58        FocusState::Focused => (colors.focused_fg, colors.checkmark, colors.focused_fg),
59        FocusState::Hovered => (colors.focused_fg, colors.checkmark, colors.focused_fg),
60        FocusState::Disabled => (colors.disabled, colors.disabled, colors.disabled),
61    };
62
63    let checkbox = if state.checked { "[x]" } else { "[ ]" };
64
65    // Format: "Label: [x]" with optional padding
66    let actual_label_width = label_width.unwrap_or(state.label.len() as u16);
67    let padded_label = format!(
68        "{:width$}",
69        state.label,
70        width = actual_label_width as usize
71    );
72
73    let line = Line::from(vec![
74        Span::styled(padded_label, Style::default().fg(label_color)),
75        Span::styled(": ", Style::default().fg(label_color)),
76        Span::styled(checkbox, Style::default().fg(bracket_color)),
77    ]);
78
79    let paragraph = Paragraph::new(line);
80    frame.render_widget(paragraph, area);
81
82    // Checkbox position after label
83    let checkbox_start = area.x + actual_label_width + 2; // label + ": "
84    let checkbox_area = Rect::new(checkbox_start, area.y, 3.min(area.width), 1);
85
86    // Full area is label + ": " + checkbox
87    let full_width = (actual_label_width + 2 + 3).min(area.width);
88    let full_area = Rect::new(area.x, area.y, full_width, 1);
89
90    ToggleLayout {
91        checkbox_area,
92        full_area,
93    }
94}