323 lines
8.2 KiB
Rust
323 lines
8.2 KiB
Rust
use std::io::{Stdout, Write};
|
|
|
|
use termion::{clear, cursor, raw::RawTerminal};
|
|
|
|
use super::{
|
|
compose::{Component, Components, HorizontalAlignment, Text},
|
|
frame::Frame,
|
|
theme::ColorSet,
|
|
Environment, Event, Page,
|
|
};
|
|
|
|
type Result<T> = std::result::Result<T, anyhow::Error>;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Body {
|
|
Echo,
|
|
Signin(SigninPage),
|
|
}
|
|
|
|
impl Body {
|
|
fn echo(
|
|
env: Environment,
|
|
screen: &mut RawTerminal<Stdout>,
|
|
event: Event,
|
|
) -> Result<()> {
|
|
let echo_comps =
|
|
Components::break_into(format!("Event: {}", event))
|
|
.nextline_after_text(
|
|
0,
|
|
HorizontalAlignment::Left,
|
|
env.frame.inner_size().0,
|
|
);
|
|
write!(screen, "{}", env.frame.make(echo_comps))?;
|
|
screen.flush()?;
|
|
Ok(())
|
|
}
|
|
|
|
fn echo_init(
|
|
&self,
|
|
env: Environment,
|
|
screen: &mut RawTerminal<Stdout>,
|
|
) -> Result<()> {
|
|
write!(
|
|
screen,
|
|
"{hide}{clear}{fr}{cursor}",
|
|
clear = clear::All,
|
|
hide = cursor::Hide,
|
|
fr = env.frame.frame_str(env.theme.windows.primary),
|
|
cursor = env.frame.goto(0, 0),
|
|
)?;
|
|
screen.flush()?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Page for Body {
|
|
fn receive_event(
|
|
&mut self,
|
|
env: Environment,
|
|
screen: &mut RawTerminal<Stdout>,
|
|
event: Event,
|
|
) -> Result<()> {
|
|
match self {
|
|
Body::Signin(b) => b.receive_event(env, screen, event)?,
|
|
Body::Echo => Body::echo(env, screen, event)?,
|
|
};
|
|
Ok(())
|
|
}
|
|
|
|
fn init(
|
|
&mut self,
|
|
env: Environment,
|
|
screen: &mut RawTerminal<Stdout>,
|
|
) -> Result<()> {
|
|
match self {
|
|
Body::Echo => self.echo_init(env, screen),
|
|
Body::Signin(signin) => signin.init(env, screen),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Default)]
|
|
pub struct SigninPage {
|
|
hostname: String,
|
|
token: String,
|
|
cursor: SigninCursorLocation,
|
|
frame: Option<Frame>,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
enum SigninCursorLocation {
|
|
Hostname,
|
|
Token,
|
|
Ok,
|
|
}
|
|
|
|
impl Default for SigninCursorLocation {
|
|
fn default() -> Self {
|
|
Self::Hostname
|
|
}
|
|
}
|
|
|
|
impl SigninPage {
|
|
#[inline]
|
|
fn next(&mut self) {
|
|
self.cursor = match self.cursor {
|
|
SigninCursorLocation::Hostname => {
|
|
SigninCursorLocation::Token
|
|
}
|
|
SigninCursorLocation::Token => SigninCursorLocation::Ok,
|
|
SigninCursorLocation::Ok => {
|
|
SigninCursorLocation::Hostname
|
|
}
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn previous(&mut self) {
|
|
self.cursor = match self.cursor {
|
|
SigninCursorLocation::Hostname => {
|
|
SigninCursorLocation::Ok
|
|
}
|
|
SigninCursorLocation::Token => {
|
|
SigninCursorLocation::Hostname
|
|
}
|
|
SigninCursorLocation::Ok => SigninCursorLocation::Token,
|
|
}
|
|
}
|
|
|
|
fn draw(
|
|
&self,
|
|
highlight: ColorSet,
|
|
normal: ColorSet,
|
|
) -> Components {
|
|
const HEADER_Y: u16 = 1;
|
|
const HOSTNAME_Y: u16 = 3;
|
|
const TOKEN_Y: u16 = 4;
|
|
const OK_Y: u16 = 6;
|
|
let frame = self.frame.unwrap();
|
|
let (w, _) = frame.inner_size();
|
|
let exp_w = w - (w / 3);
|
|
|
|
let (hostname_theme, token_theme, ok_theme) = match self
|
|
.cursor
|
|
{
|
|
SigninCursorLocation::Hostname => {
|
|
(highlight, normal, normal)
|
|
}
|
|
SigninCursorLocation::Token => {
|
|
(normal, highlight, normal)
|
|
}
|
|
SigninCursorLocation::Ok => (normal, normal, highlight),
|
|
};
|
|
|
|
vec![
|
|
frame
|
|
.prefix_centered_goto(
|
|
vec![Component::String(Text::Normal(
|
|
"login kk".into(),
|
|
))]
|
|
.into(),
|
|
HEADER_Y,
|
|
)
|
|
.0,
|
|
frame
|
|
.prefix_centered_goto(
|
|
self.field(
|
|
hostname_theme,
|
|
normal,
|
|
exp_w,
|
|
"hostname",
|
|
&self.hostname,
|
|
),
|
|
HOSTNAME_Y,
|
|
)
|
|
.0,
|
|
frame
|
|
.prefix_centered_goto(
|
|
self.field(
|
|
token_theme,
|
|
normal,
|
|
exp_w,
|
|
"token",
|
|
&self.token,
|
|
),
|
|
TOKEN_Y,
|
|
)
|
|
.0,
|
|
vec![Component::Theme(ok_theme)],
|
|
HorizontalAlignment::Center
|
|
.align(Text::Normal("[ok]".into()), w, OK_Y)
|
|
.0,
|
|
vec![Component::Theme(normal)],
|
|
]
|
|
.into_iter()
|
|
.flatten()
|
|
.collect::<Vec<Component>>()
|
|
.into()
|
|
}
|
|
|
|
#[inline]
|
|
fn field<C>(
|
|
&self,
|
|
color: ColorSet,
|
|
normal: ColorSet,
|
|
exp_width: u16,
|
|
field: C,
|
|
field_content: C,
|
|
) -> Components
|
|
where
|
|
C: Into<String>,
|
|
{
|
|
let (field, field_content) =
|
|
(field.into(), field_content.into());
|
|
let budget_for_content = exp_width - field.len() as u16 - 3;
|
|
vec![
|
|
Component::String((field + &": ").into()),
|
|
Component::Theme(color),
|
|
Component::String(Text::LimitedOrPadded(
|
|
field_content,
|
|
'_',
|
|
budget_for_content,
|
|
)),
|
|
Component::Theme(normal),
|
|
]
|
|
.into()
|
|
}
|
|
|
|
fn del(&mut self) {
|
|
match self.cursor {
|
|
SigninCursorLocation::Hostname => {
|
|
self.hostname.pop();
|
|
}
|
|
SigninCursorLocation::Token => {
|
|
self.token.pop();
|
|
}
|
|
SigninCursorLocation::Ok => {}
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn char(&mut self, c: char) {
|
|
if ['\t', '\n', '\r'].contains(&c) {
|
|
return;
|
|
}
|
|
match self.cursor {
|
|
SigninCursorLocation::Hostname => {
|
|
self.hostname.push(c);
|
|
}
|
|
SigninCursorLocation::Token => {
|
|
self.token.push(c);
|
|
}
|
|
SigninCursorLocation::Ok => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Page for SigninPage {
|
|
fn receive_event(
|
|
&mut self,
|
|
env: Environment,
|
|
screen: &mut RawTerminal<Stdout>,
|
|
event: Event,
|
|
) -> Result<()> {
|
|
match event {
|
|
Event::Key(key) => match key {
|
|
termion::event::Key::Char(c) => self.char(c),
|
|
termion::event::Key::Up => self.previous(),
|
|
termion::event::Key::Down => self.next(),
|
|
termion::event::Key::Backspace => self.del(),
|
|
termion::event::Key::Delete => {}
|
|
termion::event::Key::Left => {}
|
|
termion::event::Key::Right => {}
|
|
//
|
|
_ => {}
|
|
},
|
|
}
|
|
|
|
let fr = self.frame.unwrap();
|
|
write!(
|
|
screen,
|
|
"{}{}{}",
|
|
env.primary_frame(),
|
|
fr.frame_str(env.theme.windows.subwin),
|
|
fr.make(self.draw(
|
|
env.theme.windows.highlight,
|
|
env.theme.windows.subwin
|
|
))
|
|
)?;
|
|
screen.flush()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn init(
|
|
&mut self,
|
|
env: Environment,
|
|
screen: &mut RawTerminal<Stdout>,
|
|
) -> Result<()> {
|
|
self.frame = Some(env.frame.sub(
|
|
env.theme.frames.inner,
|
|
super::frame::FrameSize::ByAbsolute(70, 10),
|
|
));
|
|
write!(
|
|
screen,
|
|
"{frame}{subframe}{content}{hide_cursor}",
|
|
frame = env.frame.frame_str(env.theme.windows.primary),
|
|
subframe = self
|
|
.frame
|
|
.unwrap()
|
|
.frame_str(env.theme.windows.subwin),
|
|
hide_cursor = cursor::Hide,
|
|
content = self.frame.unwrap().make(self.draw(
|
|
env.theme.windows.highlight,
|
|
env.theme.windows.subwin
|
|
))
|
|
)?;
|
|
screen.flush()?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|