aboutsummaryrefslogtreecommitdiffstats
path: root/default-plugins/compact-bar/src/tooltip.rs
blob: 857b526a45e1e173307d329e5397609417a0f4d5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use crate::keybind_utils::KeybindProcessor;
use zellij_tile::prelude::*;

pub struct TooltipRenderer<'a> {
    mode_info: &'a ModeInfo,
}

impl<'a> TooltipRenderer<'a> {
    pub fn new(mode_info: &'a ModeInfo) -> Self {
        Self { mode_info }
    }

    pub fn render(&self, rows: usize, cols: usize) {
        let current_mode = self.mode_info.mode;

        if current_mode == InputMode::Normal {
            let (text_components, tooltip_rows, tooltip_columns) =
                self.normal_mode_tooltip(current_mode);
            let base_x = cols.saturating_sub(tooltip_columns) / 2;
            let base_y = rows.saturating_sub(tooltip_rows) / 2;

            for (text, ribbon, x, y) in text_components {
                let text_width = text.content().chars().count();
                let ribbon_content_width = ribbon.content().chars().count();
                let ribbon_total_width = ribbon_content_width + 4;
                let total_element_width = text_width + ribbon_total_width + 1;

                // Check if this element would exceed the available columns and render an ellipses
                // if it does
                if base_x + x + total_element_width > cols {
                    let remaining_space = cols.saturating_sub(base_x + x);
                    let ellipsis = Text::new("...").opaque();
                    print_text_with_coordinates(
                        ellipsis,
                        base_x + x,
                        base_y + y,
                        Some(remaining_space),
                        None,
                    );
                    break;
                }

                print_text_with_coordinates(text, base_x + x, base_y + y, None, None);
                print_ribbon_with_coordinates(
                    ribbon,
                    base_x + x + text_width,
                    base_y + y,
                    None,
                    None,
                );
            }
        } else {
            let (table, tooltip_rows, tooltip_columns) = self.other_mode_tooltip(current_mode);
            let base_x = cols.saturating_sub(tooltip_columns) / 2;
            let base_y = rows.saturating_sub(tooltip_rows) / 2;
            print_table_with_coordinates(table, base_x, base_y, None, None);
        }
    }

    pub fn calculate_dimensions(&self, current_mode: InputMode) -> (usize, usize) {
        match current_mode {
            InputMode::Normal => {
                let (_, tooltip_rows, tooltip_cols) = self.normal_mode_tooltip(current_mode);
                (tooltip_rows, tooltip_cols)
            },
            _ => {
                let (_, tooltip_rows, tooltip_cols) = self.other_mode_tooltip(current_mode);
                (tooltip_rows + 1, tooltip_cols) // + 1 for the invisible table title
            },
        }
    }

    fn normal_mode_tooltip(
        &self,
        current_mode: InputMode,
    ) -> (Vec<(Text, Text, usize, usize)>, usize, usize) {
        let actions = KeybindProcessor::get_predetermined_actions(self.mode_info, current_mode);
        let y = 0;
        let mut running_x = 0;
        let mut components = Vec::new();
        let mut max_columns = 0;

        let mut is_first = true;
        for (key, description) in actions {
            let text = if is_first {
                Text::new(format!("{} ", &key)).color_all(3).opaque()
            } else {
                Text::new(format!(" {} ", &key)).color_all(3).opaque()
            };
            let ribbon = Text::new(&description);

            let line_length = if is_first {
                key.chars().count() + description.chars().count()
            } else {
                key.chars().count() + 1 + description.chars().count()
            };

            components.push((text, ribbon, running_x, y));
            running_x += line_length + 5;
            max_columns = max_columns.max(running_x);
            is_first = false;
        }

        let total_rows = 1;
        (components, total_rows, max_columns)
    }

    fn other_mode_tooltip(&self, current_mode: InputMode) -> (Table, usize, usize) {
        let actions = KeybindProcessor::get_predetermined_actions(self.mode_info, current_mode);
        let actions_vec: Vec<_> = actions.into_iter().collect();

        let mut table = Table::new().add_row(vec![" ".to_owned(); 2]);
        let mut row_count = 1; // Start with header row

        if actions_vec.is_empty() {
            let tooltip_text = match self.mode_info.mode {
                InputMode::EnterSearch => "Entering search term...".to_owned(),
                InputMode::RenameTab => "Renaming tab...".to_owned(),
                InputMode::RenamePane => "Renaming pane...".to_owned(),
                _ => {
                    format!("{:?}", self.mode_info.mode)
                },
            };
            let total_width = tooltip_text.chars().count();
            table = table.add_styled_row(vec![Text::new(tooltip_text).color_all(0)]);
            row_count += 1;
            (table, row_count, total_width)
        } else {
            let mut key_width = 0;
            let mut action_width = 0;
            for (key, description) in actions_vec.into_iter() {
                let description_formatted = format!("- {}", description);
                key_width = key_width.max(key.chars().count());
                action_width = action_width.max(description_formatted.chars().count());
                table = table.add_styled_row(vec![
                    Text::new(&key).color_all(3),
                    Text::new(description_formatted),
                ]);
                row_count += 1;
            }

            let total_width = key_width + action_width + 1; // +1 for separator
            (table, row_count, total_width)
        }
    }
}