cli_prompts/prompts/options/
multioption_prompt.rs

1use crate::{engine::CommandBuffer, prompts::options::Options, style::LabelStyle};
2
3/// Helper trait that simplifies the implementation of the prompts that have multiple options to
4/// choose from. It handles filtering, pagination, drawing prompt header and options.
5pub trait MultiOptionPrompt<T> {
6
7    /// Maximum number of options that can be displayed on the screen
8    fn max_options_count(&self) -> u16;
9
10    /// Returns the reference to the `Options` struct
11    fn options(&self) -> &Options<T>;
12
13    /// Get the index of the option on the screen that is currently selected
14    fn currently_selected_index(&self) -> usize;
15
16    /// Draws the option with the given index and label
17    fn draw_option(
18        &self,
19        option_index: usize,
20        option_label: &str,
21        is_selected: bool,
22        cmd_buffer: &mut impl CommandBuffer,
23    );
24
25    /// Draws the prompt header
26    fn draw_header(&self, cmd_buffer: &mut impl CommandBuffer, is_submitted: bool);
27
28    /// Draws the entire prompt with all the options. Call this from within the `Prompt::draw()`
29    /// method
30    fn draw_multioption(
31        &self,
32        label: &str,
33        is_submitted: bool,
34        label_style: &LabelStyle,
35        cmd_buffer: &mut impl CommandBuffer,
36    ) {
37        label_style.print(label, cmd_buffer);
38        self.draw_header(cmd_buffer, is_submitted);
39
40        if is_submitted {
41            return;
42        }
43
44        cmd_buffer.new_line();
45        let max_options_count: usize = self.max_options_count().into();
46        let mut start_from = self
47            .currently_selected_index()
48            .checked_sub(max_options_count / 2)
49            .unwrap_or(0);
50        start_from = start_from.min(
51            self.options()
52                .filtered_options()
53                .len()
54                .checked_sub(max_options_count)
55                .unwrap_or(0),
56        );
57
58        let displayed_option_indices = self
59            .options()
60            .filtered_options()
61            .iter()
62            .enumerate()
63            .skip(start_from)
64            .take(self.max_options_count().into());
65
66        for (selection_index, option_index) in displayed_option_indices {
67            let is_selected = selection_index == self.currently_selected_index();
68            let option_label = &self.options().transformed_options()[*option_index];
69
70            self.draw_option(*option_index, option_label, is_selected, cmd_buffer);
71            cmd_buffer.new_line();
72        }
73    }
74}