use std::{io, time::Duration}; use crate::{ config::{self, keymap::GlobalKeyMap}, lua, sheet::register::Register, state::{window::Window, GlobalState}, tui, tuicursor::TuiCursor, widgets::{logview::LogView, luaeditor::LuaEditor, sheetview::SheetView}, }; use ratatui::{ crossterm::{ event::{self, Event, KeyEvent, KeyEventKind}, ExecutableCommand, }, prelude::*, }; #[derive(Default)] pub struct App { view: SheetView, editor: LuaEditor, logview: LogView, cursor: Option, } impl App { pub fn new() -> Self { let sheet_id = Register::create(10, 50); GlobalState::instance_mut() .view .set_active_sheet(Some(sheet_id)); Self { view: SheetView::new(), editor: LuaEditor::new(), logview: LogView::new(), cursor: None, } } pub fn run(mut self, terminal: &mut tui::Tui) -> io::Result<()> { if let Err(e) = lua::source(&config::constants::USER_RC_PATH) { tui::restore()?; println!("{}", e); return Ok(()); } while !{ GlobalState::instance().exit } { terminal.draw(|frame| { self.render_frame(frame); if let Some(cursor) = &self.cursor { frame.set_cursor(cursor.position.1, cursor.position.0); } })?; if let Some(cursor) = &self.cursor { terminal.backend_mut().execute(cursor.style)?; } self.handle_events()?; } Ok(()) } fn render_frame(&mut self, frame: &mut Frame) { frame.render_widget(self, frame.size()); } fn handle_events(&mut self) -> io::Result<()> { if event::poll(Duration::from_millis(100))? { match event::read()? { Event::Key(key_event) if key_event.kind == KeyEventKind::Press => { self.handle_key_event(key_event) } _ => {} } } Ok(()) } fn handle_key_event(&mut self, event: KeyEvent) { let focus = { GlobalState::instance().active_window }; let populate = GlobalKeyMap::handle(event); if populate { match focus { Window::View => self.view.handle_key_event(event), Window::Editor => self.editor.handle_key_event(event), Window::Log => self.logview.handle_key_event(event), Window::Error => {} } } } fn area(&self, area: Rect) -> (Rect, Option, Option) { let state = GlobalState::instance(); let mut view = area; let mut editor = None; let mut log = None; if state.log.visible { let layout = Layout::vertical([Constraint::Min(1), Constraint::Length(15)]).split(view); view = layout[0]; log = Some(layout[1]); } if state.editor.visible { let layout = Layout::horizontal([Constraint::Min(1), Constraint::Length(80)]).split(view); view = layout[0]; editor = Some(layout[1]); } (view, editor, log) } } impl Widget for &mut App { fn render(self, area: Rect, buf: &mut Buffer) where Self: Sized, { let (view, editor, log) = self.area(area); self.view.render(view, buf); self.cursor = None; if let Some(editor) = editor { self.editor.render(editor, buf); self.cursor = self.editor.render_cursor().map(|c| c.relative_to(editor)); } if let Some(log) = log { self.logview.render(log, buf); } } }