use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; use tui::{layout::{Alignment, Constraint, Direction, Layout}, style::{Color, Style}, widgets::{Block, BorderType, Borders, Paragraph}, Terminal}; use crate::state::AppState; pub struct Canvas<T: tui::backend::Backend> { top_row: usize, terminal: Terminal<T>, } impl<T: tui::backend::Backend> Canvas<T> { pub fn new(terminal: Terminal<T>) -> Self { enable_raw_mode().unwrap(); Self { top_row: 0, terminal } } pub fn render(&mut self, app_state: &AppState) -> Result<(), anyhow::Error> { self.terminal.draw(|rect| { let size = rect.size(); let chunks = Layout::default() .direction(Direction::Vertical) .margin(2) .constraints( [ Constraint::Min(2), Constraint::Length(3), // Constraint::Length(3), ] .as_ref(), ) .split(size); let title = Paragraph::new( app_state .path .clone() .map(|path| path.to_string_lossy().into_owned()) .unwrap_or("No file opened".to_owned()), ) .style(Style::default().fg(Color::LightCyan)) .alignment(Alignment::Center) .block( Block::default() .borders(Borders::ALL) .style(Style::default().fg(Color::White)) .border_type(BorderType::Plain), ); rect.render_widget(title, chunks[1]); /* let cp = Paragraph::new(COPYRIGHT) .style(Style::default().fg(Color::LightCyan)) .alignment(Alignment::Center) .block( Block::default() .borders(Borders::ALL) .style(Style::default().fg(Color::White)) .title("Copyright") .border_type(BorderType::Plain), ); rect.render_widget(cp, chunks[2]); */ let (row, column) = app_state.cursor.addr(); if row == self.top_row && row >= 1 { self.top_row -= 1; } else if row - self.top_row == (chunks[0].height - 1).into() { self.top_row += 1; } let contents = Paragraph::new(app_state.contents.contents()).scroll((self.top_row as u16, 0)); rect.render_widget(contents, chunks[0]); rect.set_cursor(chunks[0].x + column as u16, chunks[0].y + (row - self.top_row) as u16); })?; Ok(()) } } impl<T: tui::backend::Backend> Drop for Canvas<T> { fn drop(&mut self) { let _ = disable_raw_mode(); let _ = self.terminal.show_cursor(); } }