use ratatui::{
buffer::Buffer,
layout::{Constraint, Layout, Rect},
style::{Modifier, Style},
text::Line,
widgets::{Block, Borders, Clear, List, ListItem, ListState, Widget},
};
use std::borrow::Cow;
use super::state::InteractiveState;
use crate::render_context::RenderContext;
use crate::styled_string::TuiAction;
impl<'a> InteractiveState<'a> {
pub(super) fn render_theme_picker(
&mut self,
buf: &mut Buffer,
area: Rect,
selected_index: usize,
) {
self.render_cache.actions.clear();
let modal_area = centered_rect(60, 70, area);
Clear.render(modal_area, buf);
let themes = RenderContext::available_themes();
let list_inner_y = modal_area.y + 1;
for (i, theme_name) in themes.iter().enumerate() {
let item_y = list_inner_y + i as u16;
if item_y < modal_area.y + modal_area.height.saturating_sub(1) {
let item_rect = Rect {
x: modal_area.x + 1, y: item_y,
width: modal_area.width.saturating_sub(2), height: 1,
};
self.render_cache.actions.push((
item_rect,
TuiAction::SelectTheme(Cow::Owned(theme_name.clone())),
));
}
}
let items: Vec<ListItem> = themes
.iter()
.map(|theme_name| ListItem::new(Line::from(format!(" {}", theme_name))))
.collect();
let mut list_state = ListState::default();
list_state.select(Some(selected_index));
let block = Block::default()
.title(" Select Theme ")
.borders(Borders::ALL)
.style(self.theme.help_bg_style);
let list = List::new(items)
.block(block)
.highlight_style(
Style::default()
.bg(self
.theme
.breadcrumb_style
.bg
.unwrap_or(ratatui::style::Color::Blue))
.add_modifier(Modifier::BOLD),
)
.highlight_symbol("> ");
ratatui::widgets::StatefulWidget::render(list, modal_area, buf, &mut list_state);
if let Some(cursor_pos) = self.viewport.cursor_pos {
if modal_area.contains(cursor_pos) {
let relative_y = cursor_pos.y.saturating_sub(list_inner_y);
let hovered_index = relative_y as usize;
if hovered_index < themes.len() && hovered_index != selected_index {
let hover_y = list_inner_y + hovered_index as u16;
let marker_x = modal_area.x + 1;
if let Some(cell) = buf.cell_mut((marker_x, hover_y)) {
cell.set_char('>');
}
for x in (modal_area.x + 1)..(modal_area.x + modal_area.width - 1) {
if let Some(cell) = buf.cell_mut((x, hover_y)) {
cell.modifier.insert(ratatui::style::Modifier::BOLD);
}
}
}
}
}
let instruction_y = modal_area.y + modal_area.height.saturating_sub(2);
if instruction_y < area.height {
let instructions = " ↑/↓:Navigate Enter:Save Esc:Cancel ";
let instruction_x =
modal_area.x + (modal_area.width.saturating_sub(instructions.len() as u16)) / 2;
for (i, ch) in instructions.chars().enumerate() {
let x = instruction_x + i as u16;
if x < modal_area.x + modal_area.width {
if let Some(cell) = buf.cell_mut((x, instruction_y)) {
cell.set_char(ch);
cell.set_style(self.theme.status_hint_style);
}
}
}
}
}
}
fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
let popup_layout = Layout::vertical([
Constraint::Percentage((100 - percent_y) / 2),
Constraint::Percentage(percent_y),
Constraint::Percentage((100 - percent_y) / 2),
])
.split(r);
Layout::horizontal([
Constraint::Percentage((100 - percent_x) / 2),
Constraint::Percentage(percent_x),
Constraint::Percentage((100 - percent_x) / 2),
])
.split(popup_layout[1])[1]
}