Skip to main content

promkit_widgets/
listbox.rs

1use promkit_core::{Pane, PaneFactory, grapheme::StyledGraphemes};
2
3#[path = "listbox/listbox.rs"]
4mod inner;
5pub use inner::Listbox;
6pub mod config;
7pub use config::Config;
8
9/// Represents the state of a `Listbox` component, including its appearance and behavior.
10/// This state includes the currently selected item, styles for active and inactive items,
11/// and the number of lines available for rendering the listbox.
12#[derive(Clone)]
13pub struct State {
14    /// The `Listbox` component to be rendered.
15    pub listbox: Listbox,
16    /// Configuration for rendering and behavior.
17    pub config: Config,
18}
19
20impl PaneFactory for State {
21    fn create_pane(&self, width: u16, height: u16) -> Pane {
22        let height = match self.config.lines {
23            Some(lines) => lines.min(height as usize),
24            None => height as usize,
25        };
26
27        let matrix = self
28            .listbox
29            .items()
30            .iter()
31            .enumerate()
32            .filter(|(i, _)| *i >= self.listbox.position() && *i < self.listbox.position() + height)
33            .map(|(i, item)| {
34                if i == self.listbox.position() {
35                    let init = StyledGraphemes::from_iter([
36                        &StyledGraphemes::from(&self.config.cursor),
37                        item,
38                    ]);
39                    if let Some(style) = &self.config.active_item_style {
40                        init.apply_style(*style)
41                    } else {
42                        init
43                    }
44                } else {
45                    let init = StyledGraphemes::from_iter([
46                        &StyledGraphemes::from(
47                            " ".repeat(StyledGraphemes::from(&self.config.cursor).widths()),
48                        ),
49                        item,
50                    ]);
51                    if let Some(style) = &self.config.inactive_item_style {
52                        init.apply_style(*style)
53                    } else {
54                        init
55                    }
56                }
57            })
58            .fold((vec![], 0), |(mut acc, pos), item| {
59                let rows = item.matrixify(width as usize, height, 0).0;
60                if pos < self.listbox.position() + height {
61                    acc.extend(rows);
62                }
63                (acc, pos + 1)
64            });
65
66        Pane::new(matrix.0, 0)
67    }
68}