From b3d6df5655d6f76fc9a369c8ea194ce83556ef8d Mon Sep 17 00:00:00 2001 From: Antoine POPINEAU Date: Sat, 4 Jul 2020 21:43:55 +0200 Subject: [PATCH] Refactored some UI utility and command prompt into separate modules. --- src/keyboard.rs | 2 +- src/ui/command.rs | 51 ++++++++++++++++++++++++ src/ui/mod.rs | 3 ++ src/ui/prompt.rs | 96 ++++------------------------------------------ src/ui/sessions.rs | 3 +- src/ui/util.rs | 63 ++++++++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 91 deletions(-) create mode 100644 src/ui/command.rs create mode 100644 src/ui/util.rs diff --git a/src/keyboard.rs b/src/keyboard.rs index 93d4621..005c9e9 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -20,7 +20,7 @@ pub fn handle(greeter: &mut Greeter, events: &Events) -> Result<(), Box greeter.cursor_offset += 1, Key::F(2) => { - greeter.new_command = greeter.command.clone().unwrap_or_else(String::new); + greeter.new_command = greeter.command.clone().unwrap_or_default(); greeter.previous_mode = greeter.mode; greeter.mode = Mode::Command; } diff --git a/src/ui/command.rs b/src/ui/command.rs new file mode 100644 index 0000000..b119dbd --- /dev/null +++ b/src/ui/command.rs @@ -0,0 +1,51 @@ +use std::{error::Error, io}; + +use termion::raw::RawTerminal; +use tui::{ + backend::TermionBackend, + layout::{Constraint, Direction, Layout, Rect}, + widgets::{Block, BorderType, Borders, Paragraph, Text}, + Frame, +}; + +use super::prompt_value; +use crate::{ui::util::*, Greeter}; + +const CHANGE_COMMAND: &str = " Change session command "; +const COMMAND: &str = "New command:"; + +pub fn draw(greeter: &mut Greeter, f: &mut Frame>>) -> Result<(u16, u16), Box> { + let size = f.size(); + + let width = greeter.width(); + let height = get_height(&greeter); + let container_padding = greeter.container_padding(); + let x = (size.width - width) / 2; + let y = (size.height - height) / 2; + + let container = Rect::new(x, y, width, height); + let frame = Rect::new(x + container_padding, y + container_padding, width - container_padding, height - container_padding); + + let block = Block::default().title(CHANGE_COMMAND).borders(Borders::ALL).border_type(BorderType::Plain); + + f.render_widget(block, container); + + let constraints = [ + Constraint::Length(1), // Username + ]; + + let chunks = Layout::default().direction(Direction::Vertical).constraints(constraints.as_ref()).split(frame); + let cursor = chunks[0]; + + let command_label_text = [prompt_value(COMMAND)]; + let command_label = Paragraph::new(command_label_text.iter()); + let command_value_text = [Text::raw(&greeter.new_command)]; + let command_value = Paragraph::new(command_value_text.iter()); + + f.render_widget(command_label, chunks[0]); + f.render_widget(command_value, Rect::new(1 + chunks[0].x + COMMAND.len() as u16, chunks[0].y, get_input_width(greeter, COMMAND), 1)); + + let offset = get_cursor_offset(greeter, greeter.new_command.len()); + + Ok((2 + cursor.x + COMMAND.len() as u16 + offset as u16, cursor.y + 1)) +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 33d9710..a77cb81 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,5 +1,7 @@ +mod command; mod prompt; mod sessions; +mod util; use std::{ error::Error, @@ -81,6 +83,7 @@ pub fn draw(terminal: &mut Terminal>>, gr } cursor = match greeter.mode { + Mode::Command => self::command::draw(greeter, &mut f).ok(), Mode::Sessions => self::sessions::draw(greeter, &mut f).ok(), _ => self::prompt::draw(greeter, &mut f).ok(), } diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index 112c75f..476ac4d 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -8,7 +8,7 @@ use tui::{ Frame, }; -use super::prompt_value; +use super::{prompt_value, util::*}; use crate::{info::get_hostname, Greeter, Mode}; const GREETING_INDEX: usize = 0; @@ -18,7 +18,6 @@ const MESSAGE_INDEX: usize = 3; const TITLE: &str = "Authenticate into"; const USERNAME: &str = "Username:"; -const COMMAND: &str = "New command:"; const WORKING: &str = "Please wait..."; pub fn draw(greeter: &mut Greeter, f: &mut Frame>>) -> Result<(u16, u16), Box> { @@ -43,10 +42,10 @@ pub fn draw(greeter: &mut Greeter, f: &mut Frame { - let command_label_text = [prompt_value(COMMAND)]; - let command_label = Paragraph::new(command_label_text.iter()); - let command_value_text = [Text::raw(&greeter.new_command)]; - let command_value = Paragraph::new(command_value_text.iter()); - - f.render_widget(command_label, chunks[USERNAME_INDEX]); - f.render_widget( - command_value, - Rect::new(1 + chunks[USERNAME_INDEX].x + COMMAND.len() as u16, chunks[USERNAME_INDEX].y, get_input_width(greeter, COMMAND), 1), - ); - } - Mode::Username | Mode::Password => { f.render_widget(username_label, chunks[USERNAME_INDEX]); f.render_widget( @@ -120,7 +106,7 @@ pub fn draw(greeter: &mut Greeter, f: &mut Frame {} + _ => {} } match greeter.mode { @@ -140,74 +126,6 @@ pub fn draw(greeter: &mut Greeter, f: &mut Frame { - let offset = get_cursor_offset(greeter, greeter.new_command.len()); - - Ok((2 + cursor.x + COMMAND.len() as u16 + offset as u16, USERNAME_INDEX as u16 + cursor.y)) - } - - Mode::Sessions => Ok((1, 1)), + _ => Ok((1, 1)), } } - -fn get_height(greeter: &Greeter) -> u16 { - let container_padding = greeter.container_padding(); - let prompt_padding = greeter.prompt_padding(); - let (_, message_height) = get_message_height(greeter, 2, 0); - let (_, greeting_height) = get_greeting_height(greeter, 1, 0); - - let initial = match greeter.mode { - Mode::Username | Mode::Command => (2 * container_padding) + 1, - Mode::Password => (2 * container_padding) + prompt_padding + 2, - Mode::Sessions => 0, - }; - - match greeter.mode { - Mode::Command => initial + greeting_height, - _ => initial + greeting_height + message_height, - } -} - -fn get_greeting_height(greeter: &Greeter, padding: u16, fallback: u16) -> (Option, u16) { - if let Some(greeting) = &greeter.greeting { - let width = greeter.width(); - let wrapped = textwrap::fill(greeting, width as usize - 4); - let height = wrapped.trim_end().matches('\n').count(); - - (Some(wrapped), height as u16 + 1 + padding) - } else { - (None, fallback) - } -} - -fn get_input_width(greeter: &Greeter, label: &str) -> u16 { - greeter.width() - label.len() as u16 - 4 - 1 -} - -fn get_message_height(greeter: &Greeter, padding: u16, fallback: u16) -> (Option, u16) { - if let Some(message) = &greeter.message { - let width = greeter.width(); - let wrapped = textwrap::fill(message.trim_end(), width as usize - 4); - let height = wrapped.trim_end().matches('\n').count(); - - (Some(wrapped), height as u16 + padding) - } else { - (None, fallback) - } -} - -fn get_cursor_offset(greeter: &mut Greeter, length: usize) -> i16 { - let mut offset = length as i16 + greeter.cursor_offset; - - if offset < 0 { - offset = 0; - greeter.cursor_offset = -(length as i16); - } - - if offset > length as i16 { - offset = length as i16; - greeter.cursor_offset = 0; - } - - offset -} diff --git a/src/ui/sessions.rs b/src/ui/sessions.rs index e1e5fcc..78b1f3b 100644 --- a/src/ui/sessions.rs +++ b/src/ui/sessions.rs @@ -9,6 +9,7 @@ use tui::{ Frame, }; +use super::util::*; use crate::Greeter; const CHANGE_SESSION: &str = "Change session"; @@ -17,7 +18,7 @@ pub fn draw(greeter: &mut Greeter, f: &mut Frame u16 { + let container_padding = greeter.container_padding(); + let prompt_padding = greeter.prompt_padding(); + let (_, message_height) = get_message_height(greeter, 2, 0); + let (_, greeting_height) = get_greeting_height(greeter, 1, 0); + + let initial = match greeter.mode { + Mode::Username | Mode::Command => (2 * container_padding) + 1, + Mode::Password => (2 * container_padding) + prompt_padding + 2, + Mode::Sessions => (2 * container_padding), + }; + + match greeter.mode { + Mode::Command | Mode::Sessions => initial, + _ => initial + greeting_height + message_height, + } +} + +pub fn get_input_width(greeter: &Greeter, label: &str) -> u16 { + greeter.width() - label.len() as u16 - 4 - 1 +} + +pub fn get_cursor_offset(greeter: &mut Greeter, length: usize) -> i16 { + let mut offset = length as i16 + greeter.cursor_offset; + + if offset < 0 { + offset = 0; + greeter.cursor_offset = -(length as i16); + } + + if offset > length as i16 { + offset = length as i16; + greeter.cursor_offset = 0; + } + + offset +} + +pub fn get_greeting_height(greeter: &Greeter, padding: u16, fallback: u16) -> (Option, u16) { + if let Some(greeting) = &greeter.greeting { + let width = greeter.width(); + let wrapped = textwrap::fill(greeting, width as usize - 4); + let height = wrapped.trim_end().matches('\n').count(); + + (Some(wrapped), height as u16 + 1 + padding) + } else { + (None, fallback) + } +} + +pub fn get_message_height(greeter: &Greeter, padding: u16, fallback: u16) -> (Option, u16) { + if let Some(message) = &greeter.message { + let width = greeter.width(); + let wrapped = textwrap::fill(message.trim_end(), width as usize - 4); + let height = wrapped.trim_end().matches('\n').count(); + + (Some(wrapped), height as u16 + padding) + } else { + (None, fallback) + } +}