use ratatui::{ buffer::Buffer, layout::Rect, style::{Color, Modifier, Style}, widgets::{Block, Borders, Widget}, }; use crate::model::Model; use crate::ui::app::AppMode; pub struct FormulaPanel<'a> { pub model: &'a Model, pub mode: &'a AppMode, pub cursor: usize, } impl<'a> FormulaPanel<'a> { pub fn new(model: &'a Model, mode: &'a AppMode, cursor: usize) -> Self { Self { model, mode, cursor, } } } impl<'a> Widget for FormulaPanel<'a> { fn render(self, area: Rect, buf: &mut Buffer) { let is_active = matches!( self.mode, AppMode::FormulaPanel | AppMode::FormulaEdit { .. } ); let border_style = if is_active { Style::default().fg(Color::Yellow) } else { Style::default().fg(Color::DarkGray) }; let block = Block::default() .borders(Borders::ALL) .border_style(border_style) .title(" Formulas [n]ew [d]elete "); let inner = block.inner(area); block.render(area, buf); let formulas = self.model.formulas(); if formulas.is_empty() { buf.set_string( inner.x, inner.y, "(no formulas — press 'n' to add)", Style::default().fg(Color::DarkGray), ); return; } for (i, formula) in formulas.iter().enumerate() { if inner.y + i as u16 >= inner.y + inner.height { break; } let is_selected = i == self.cursor && is_active; let style = if is_selected { Style::default() .fg(Color::Black) .bg(Color::Yellow) .add_modifier(Modifier::BOLD) } else { Style::default().fg(Color::Green) }; let text = format!(" {} = {:?}", formula.target, formula.raw); let truncated = if text.len() > inner.width as usize { format!("{}…", &text[..inner.width as usize - 1]) } else { text }; buf.set_string(inner.x, inner.y + i as u16, &truncated, style); } // Formula edit mode if let AppMode::FormulaEdit { buffer } = self.mode { let y = inner.y + inner.height.saturating_sub(2); buf.set_string( inner.x, y, "┄ Enter formula (Name = expr): ", Style::default().fg(Color::Yellow), ); let y = y + 1; let prompt = format!("> {buffer}█"); buf.set_string(inner.x, y, &prompt, Style::default().fg(Color::Green)); } } }