64 lines
2.2 KiB
Rust

use {
super::{GridSelector, GridSelectorState},
ratatui::{
buffer::Buffer,
layout::{Alignment, Constraint, Direction, Flex, Layout, Rect},
style::Style,
widgets::{Block, Borders, Paragraph, StatefulWidget, Widget},
},
std::rc::Rc,
unicode_width::UnicodeWidthStr,
};
impl StatefulWidget for GridSelector {
type State = GridSelectorState;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut GridSelectorState) {
let rows_layout = rows_layout(state, area);
let largest_item = largest_item(state);
for (i, row) in rows_layout.iter().enumerate() {
let row_items = state.items.iter().skip(i * state.columns).take(state.columns);
let columns_layout = columns_layout(row, row_items.len(), largest_item);
for (j, item) in row_items.enumerate() {
let main_index = i * state.columns + j;
let color = self.get_color(main_index, state);
let type_block =
Block::default().borders(Borders::ALL).border_style(Style::default().fg(color));
Paragraph::new(item.clone())
.style(Style::default().fg(color))
.alignment(Alignment::Left)
.block(type_block)
.render(columns_layout[j], buf);
}
}
}
}
fn rows_layout(state: &GridSelectorState, area: Rect) -> Rc<[Rect]> {
let row_count = (state.items.len() as f32 / state.columns as f32).ceil() as usize;
Layout::default()
.direction(Direction::Vertical)
.constraints((0..row_count).map(|_| Constraint::Length(3)).collect::<Vec<_>>())
.spacing(0)
.split(area)
}
fn columns_layout(row: &Rect, row_item_count: usize, largest_item: u16) -> Rc<[Rect]> {
Layout::default()
.direction(Direction::Horizontal)
.flex(Flex::Center)
.constraints(
(0..row_item_count).map(|_| Constraint::Length(largest_item + 3)).collect::<Vec<_>>(),
)
.split(*row)
}
fn largest_item(state: &GridSelectorState) -> u16 {
state.items.iter().map(|item| UnicodeWidthStr::width(item.as_ref())).max().unwrap_or(0) as u16
}