From 200b9143b30c6fe4044279fb0aa7d1d4d6c287be Mon Sep 17 00:00:00 2001 From: antifallobst Date: Mon, 10 Jul 2023 00:10:51 +0200 Subject: [PATCH] feature (ui): added a cli panel to contoll the UI similar to what you have when hitting colon in vim --- src/app/event.rs | 24 +++++++++++++++ src/app/status.rs | 4 +++ src/ui/mod.rs | 76 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 99 insertions(+), 5 deletions(-) diff --git a/src/app/event.rs b/src/app/event.rs index e5fa8b7..b2ce11b 100644 --- a/src/app/event.rs +++ b/src/app/event.rs @@ -132,6 +132,13 @@ impl Event { }) => { app.ui.cycle_main_input_position_rev(); } + crossterm::event::Event::Key(KeyEvent { + code: KeyCode::Char('c'), + modifiers: KeyModifiers::CONTROL, + .. + }) => { + app.ui.cli_enable(); + } input => match app.ui.input_position() { ui::MainInputPosition::MessageCompose => { match input { @@ -239,6 +246,23 @@ impl Event { _ => (), }; } + ui::MainInputPosition::CLI => { + if let Some(cli) = &mut app.ui.cli { + match input { + crossterm::event::Event::Key(KeyEvent { + code: KeyCode::Enter, + .. + }) => { + let cli_event = cli.lines()[0].clone(); + app.status.cli_event(cli_event); + app.ui.cli_disable(); + } + _ => { + cli.input(tui_textarea::Input::from(input)); + } + }; + }; + } _ => (), }, }; diff --git a/src/app/status.rs b/src/app/status.rs index 6b2d3fc..7247ba9 100644 --- a/src/app/status.rs +++ b/src/app/status.rs @@ -206,4 +206,8 @@ impl Status { pub fn set_state(&mut self, state: State) { self.state = state; } + + pub fn cli_event(&mut self, event: String) { + info!("CLI Event: {}", event); + } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index b4f6356..636f1fc 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -32,13 +32,14 @@ pub enum SetupInputPosition { Ok, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] pub enum MainInputPosition { Status, Rooms, Messages, MessageCompose, RoomInfo, + CLI, } pub struct SetupUI<'a> { @@ -55,6 +56,7 @@ pub struct UI<'a> { input_position: MainInputPosition, pub rooms_state: ListState, pub message_compose: TextArea<'a>, + pub cli: Option>, pub setup_ui: Option>, } @@ -266,6 +268,7 @@ impl UI<'_> { input_position: MainInputPosition::Rooms, rooms_state: ListState::default(), message_compose, + cli: None, setup_ui: None, } } @@ -276,17 +279,25 @@ impl UI<'_> { MainInputPosition::Rooms => MainInputPosition::Messages, MainInputPosition::Messages => MainInputPosition::MessageCompose, MainInputPosition::MessageCompose => MainInputPosition::RoomInfo, - MainInputPosition::RoomInfo => MainInputPosition::Status, + MainInputPosition::RoomInfo => match self.cli { + Some(_) => MainInputPosition::CLI, + None => MainInputPosition::Status, + }, + MainInputPosition::CLI => MainInputPosition::Status, }; } pub fn cycle_main_input_position_rev(&mut self) { self.input_position = match self.input_position { - MainInputPosition::Status => MainInputPosition::RoomInfo, + MainInputPosition::Status => match self.cli { + Some(_) => MainInputPosition::CLI, + None => MainInputPosition::RoomInfo, + }, MainInputPosition::Rooms => MainInputPosition::Status, MainInputPosition::Messages => MainInputPosition::Rooms, MainInputPosition::MessageCompose => MainInputPosition::Messages, MainInputPosition::RoomInfo => MainInputPosition::MessageCompose, + MainInputPosition::CLI => MainInputPosition::RoomInfo, }; } @@ -303,8 +314,31 @@ impl UI<'_> { ); } + pub fn cli_enable(&mut self) { + self.input_position = MainInputPosition::CLI; + if self.cli.is_some() { + return; + } + let mut cli = TextArea::default(); + cli.set_block(Block::default().borders(Borders::ALL)); + self.cli = Some(cli); + } + + pub fn cli_disable(&mut self) { + if self.input_position == MainInputPosition::CLI { + self.cycle_main_input_position(); + } + self.cli = None; + } + pub async fn update(&mut self, status: &Status) -> Result<()> { - let chunk = self.terminal.size()?; + let chunks = match self.cli { + Some(_) => Layout::default() + .direction(Direction::Vertical) + .constraints([Constraint::Min(10), Constraint::Length(3)].as_ref()) + .split(self.terminal.size()?), + None => vec![self.terminal.size()?], + }; let main_chunks = Layout::default() .direction(Direction::Horizontal) @@ -316,7 +350,7 @@ impl UI<'_> { ] .as_ref(), ) - .split(chunk); + .split(chunks[0]); let left_chunks = Layout::default() .direction(Direction::Vertical) @@ -450,6 +484,9 @@ impl UI<'_> { let colors = match self.input_position { MainInputPosition::Status => { textarea_inactivate(&mut self.message_compose); + if let Some(cli) = &mut self.cli { + textarea_inactivate(cli); + } vec![ Color::White, Color::DarkGray, @@ -460,6 +497,9 @@ impl UI<'_> { } MainInputPosition::Rooms => { textarea_inactivate(&mut self.message_compose); + if let Some(cli) = &mut self.cli { + textarea_inactivate(cli); + } vec![ Color::DarkGray, Color::White, @@ -470,6 +510,9 @@ impl UI<'_> { } MainInputPosition::Messages => { textarea_inactivate(&mut self.message_compose); + if let Some(cli) = &mut self.cli { + textarea_inactivate(cli); + } vec![ Color::DarkGray, Color::DarkGray, @@ -480,6 +523,9 @@ impl UI<'_> { } MainInputPosition::MessageCompose => { textarea_activate(&mut self.message_compose); + if let Some(cli) = &mut self.cli { + textarea_inactivate(cli); + } vec![ Color::DarkGray, Color::DarkGray, @@ -490,6 +536,9 @@ impl UI<'_> { } MainInputPosition::RoomInfo => { textarea_inactivate(&mut self.message_compose); + if let Some(cli) = &mut self.cli { + textarea_inactivate(cli); + } vec![ Color::DarkGray, Color::DarkGray, @@ -498,6 +547,19 @@ impl UI<'_> { Color::White, ] } + MainInputPosition::CLI => { + textarea_inactivate(&mut self.message_compose); + if let Some(cli) = &mut self.cli { + textarea_activate(cli); + } + vec![ + Color::DarkGray, + Color::DarkGray, + Color::DarkGray, + Color::DarkGray, + Color::DarkGray, + ] + } }; // initiate the widgets @@ -555,6 +617,10 @@ impl UI<'_> { frame.render_stateful_widget(rooms_panel, left_chunks[1], &mut self.rooms_state); frame.render_stateful_widget(messages_panel, middle_chunks[0], &mut messages_state); frame.render_widget(self.message_compose.widget(), middle_chunks[1]); + match &self.cli { + Some(cli) => frame.render_widget(cli.widget(), chunks[1]), + None => (), + }; frame.render_widget(room_info_panel, right_chunks[0]); })?;