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) } } }