Skip to main content

hefesto_widgets/popups/file_browser/
mod.rs

1use ratatui::{
2    buffer::Buffer,
3    layout::Rect,
4    style::{Color, Style},
5    widgets::StatefulWidget,
6};
7
8use crate::popups::FileBrowserState;
9use crate::scroll_list::ScrollList;
10use crate::DEFAULT_HIGHLIGHT;
11
12/// Widget que renderiza una lista de archivos con iconos y estilos.
13///
14/// No incluye chrome de popup. Usá [`FileBrowserPopup`](crate::FileBrowserPopup)
15/// para agregar título, borde, posición, etc.
16///
17/// ## Render
18///
19/// Toma los items de [`FileBrowserState::items`] y los estiliza según
20/// `dir_style` (para directorios) y `file_style` (para archivos).
21///
22/// El filtro por nombre no está disponible en este widget;
23/// está implementado en [`FileBrowserPopup`](crate::FileBrowserPopup).
24#[derive(Clone)]
25pub struct FileBrowser {
26    dir_style: Style,
27    file_style: Style,
28    highlight_style: Style,
29    highlight_symbol: String,
30    dir_icon: String,
31    file_icon: String,
32    max_selected: Option<usize>,
33}
34
35impl FileBrowser {
36    pub fn new() -> Self {
37        Self {
38            dir_style: Style::new().fg(Color::Cyan),
39            file_style: Style::new().fg(Color::White),
40            highlight_style: DEFAULT_HIGHLIGHT,
41            highlight_symbol: crate::HIGHLIGHT_SYMBOL.to_string(),
42            dir_icon: "📁 ".to_string(),
43            file_icon: "📄 ".to_string(),
44            max_selected: None,
45        }
46    }
47
48    pub fn dir_style(mut self, style: Style) -> Self {
49        self.dir_style = style;
50        self
51    }
52
53    pub fn file_style(mut self, style: Style) -> Self {
54        self.file_style = style;
55        self
56    }
57
58    pub fn highlight_style(mut self, style: Style) -> Self {
59        self.highlight_style = style;
60        self
61    }
62
63    pub fn highlight_symbol(mut self, symbol: &str) -> Self {
64        self.highlight_symbol = symbol.to_string();
65        self
66    }
67
68    pub fn dir_icon(mut self, icon: &str) -> Self {
69        self.dir_icon = icon.to_string();
70        self
71    }
72
73    pub fn file_icon(mut self, icon: &str) -> Self {
74        self.file_icon = icon.to_string();
75        self
76    }
77
78    pub fn max_selected(mut self, max: usize) -> Self {
79        self.max_selected = Some(max);
80        self
81    }
82
83    pub fn no_max_selected(mut self) -> Self {
84        self.max_selected = None;
85        self
86    }
87}
88
89impl Default for FileBrowser {
90    fn default() -> Self {
91        Self::new()
92    }
93}
94
95impl StatefulWidget for FileBrowser {
96    type State = FileBrowserState;
97
98    fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
99        let items: Vec<(String, Style)> = state
100            .items
101            .iter()
102            .enumerate()
103            .map(|(i, (text, _))| {
104                let is_dir = state.entries.get(i).map(|e| e.is_dir).unwrap_or(false);
105                let style = if is_dir { self.dir_style } else { self.file_style };
106                (text.clone(), style)
107            })
108            .collect();
109
110        state.choose_popup_state.scroll_list_state.follow = false;
111        state.choose_popup_state.scroll_list_state.select(Some(state.choose_popup_state.cursor));
112
113        let list = ScrollList::new_styled(items)
114            .highlight_style(self.highlight_style)
115            .highlight_symbol(&self.highlight_symbol);
116        list.render(area, buf, &mut state.choose_popup_state.scroll_list_state);
117
118        if let Some(idx) = state.choose_popup_state.scroll_list_state.list_state.selected() {
119            state.choose_popup_state.cursor = idx;
120        }
121    }
122}