diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 06d3270..0059172 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,3 +1,4 @@ +use std::cmp; use crate::app::{App}; use crossterm::{ event::{self, DisableMouseCapture, EnableMouseCapture, Event, read}, @@ -24,8 +25,20 @@ enum SetupInputPosition { Ok } -pub struct UI { +#[derive(Clone, Copy)] +enum MainInputPosition { + Status, + Rooms, + Messages, + MessageCompose, + RoomInfo +} + +pub struct UI<'a> { terminal: Terminal>, + + input_position: MainInputPosition, + message_compose: TextArea<'a>, } fn terminal_prepare() -> Result { @@ -43,8 +56,7 @@ fn draw_main_status_block(frame: &mut Frame>, area: Rec content.extend(Text::styled("settings", Style::default().fg(Color::LightMagenta).add_modifier(Modifier::ITALIC | Modifier::UNDERLINED))); let panel = Paragraph::new(content) - .block( - Block::default() + .block(Block::default() .title("Status") .borders(Borders::ALL)) .alignment(Alignment::Left); @@ -79,8 +91,7 @@ fn draw_main_messages_block(frame: &mut Frame>, area: R }; let panel = Paragraph::new(messages) - .block( - Block::default() + .block(Block::default() .title("Messages") .borders(Borders::ALL)) .alignment(Alignment::Left) @@ -90,14 +101,6 @@ fn draw_main_messages_block(frame: &mut Frame>, area: R frame.render_widget(panel, area); } -fn draw_main_message_compose_block(frame: &mut Frame>, area: Rect) { - let panel = Block::default() - .title("Message Compose") - .borders(Borders::ALL); - - frame.render_widget(panel, area); -} - fn draw_main_room_info_block(frame: &mut Frame>, area: Rect) { let panel = Block::default() .title("Room Info") @@ -106,6 +109,10 @@ fn draw_main_room_info_block(frame: &mut Frame>, area: frame.render_widget(panel, area); } +fn draw_main_message_compose_block(frame: &mut Frame>, area: Rect, textarea: &TextArea) { + frame.render_widget(textarea.widget(), area); +} + fn textarea_activate(textarea: &mut TextArea) { textarea.set_cursor_line_style(Style::default().add_modifier(Modifier::UNDERLINED)); textarea.set_cursor_style(Style::default().add_modifier(Modifier::REVERSED)); @@ -129,7 +136,7 @@ fn textarea_inactivate(textarea: &mut TextArea) { } -impl UI { +impl UI<'_> { pub fn new() -> Self { let stdout = terminal_prepare().expect("failed to prepare terminal"); let backend = CrosstermBackend::new(stdout); @@ -137,12 +144,22 @@ impl UI { terminal.clear().expect("failed to clear screen"); + let mut message_compose = TextArea::default(); + message_compose.set_block( + Block::default() + .title("Message Compose") + .borders(Borders::ALL)); + Self { - terminal + terminal, + input_position: MainInputPosition::Rooms, + message_compose, } } - fn draw_main(&mut self, app: &App) -> Result<()> { + pub fn main_update(&'_ mut self, app: &App) -> Result<()> { + // TODO: make thread safe + let chunk = self.terminal.size()?; let main_chunks = Layout::default() @@ -157,7 +174,7 @@ impl UI { let middle_chunks = Layout::default() .direction(Direction::Vertical) - .constraints([Constraint::Min(4), Constraint::Length(3)].as_ref()) + .constraints([Constraint::Min(4), Constraint::Length(cmp::min(2 + self.message_compose.lines().len() as u16, 8))].as_ref()) .split(main_chunks[1]); let right_chunks = Layout::default() @@ -165,12 +182,11 @@ impl UI { .constraints([Constraint::Min(4)].as_ref()) .split(main_chunks[2]); - self.terminal.draw(|frame| { draw_main_status_block(frame, left_chunks[0], app); draw_main_rooms_block(frame, left_chunks[1]); draw_main_messages_block(frame, middle_chunks[0], app); - draw_main_message_compose_block(frame, middle_chunks[1]); + draw_main_message_compose_block(frame, middle_chunks[1], &self.message_compose); draw_main_room_info_block(frame, right_chunks[0]); })?; @@ -178,15 +194,34 @@ impl UI { } pub async fn main(&mut self, app: &mut App) -> Result<()> { - self.draw_main(app)?; - Ok(()) + textarea_activate(&mut self.message_compose); + + loop { + self.main_update(app)?; + + match Input::from(read()?.clone()) { + Input { key: Key::Esc, .. } => return Ok(()), + Input { + key: Key::Tab, + .. + } => { + // TODO: calc input_position + self.input_position = MainInputPosition::MessageCompose; + } + input => { + match self.input_position { + MainInputPosition::MessageCompose => { self.message_compose.input(input); }, + _ => continue, + } + } + }; + } } pub async fn setup(&mut self, app: &mut App) -> Result<()> { let mut input_index = SetupInputPosition::Homeserver; let mut strings: Vec = Vec::new(); strings.resize(3, "".to_string()); - self.terminal.show_cursor()?; let content_ok_active = Span::styled("OK", Style::default().add_modifier(Modifier::UNDERLINED)); let content_ok_inactive = Span::styled("OK", Style::default().fg(Color::DarkGray)); @@ -223,8 +258,7 @@ impl UI { let mut ok = Paragraph::new(match input_index { SetupInputPosition::Ok => content_ok_active.clone(), _ => content_ok_inactive.clone(), - }) - .alignment(Alignment::Center); + }).alignment(Alignment::Center); // define a 32 * 6 chunk in the middle of the screen let mut chunk = self.terminal.size()?;