diff --git a/src/display/body.rs b/src/display/body.rs index 5e33df9..7377556 100644 --- a/src/display/body.rs +++ b/src/display/body.rs @@ -81,33 +81,60 @@ pub struct SigninPage { hostname: String, username: String, cursor: SigninCursorLocation, - cursor_position: u16, frame: Option, } #[derive(Debug, Clone)] enum SigninCursorLocation { - Hostname, - Username, - Next, + Hostname(u16), + Ok, } impl Default for SigninCursorLocation { fn default() -> Self { - Self::Hostname + Self::Ok } } impl SigninPage { #[inline] - fn draw(&self) -> String { + fn draw(&self, highlight: ColorSet, normal: ColorSet) -> String { + const HEADER_Y: u16 = 1; + const HOSTNAME_Y: u16 = 3; + const OK_Y: u16 = 5; let frame = self.frame.unwrap(); + let fr_width = frame.size().0; + let total_width = fr_width / 3; + format!( - "{header}{hostname}", - header = frame.write_centered("login kk", 1) - hostname = frame.write_centered("instance:", 3), + "{header}{hostname}{retheme}{ok}", + header = frame.write_centered("login kk", HEADER_Y), + hostname = frame.write_centered( + &self.field_str( + highlight, + total_width, + "hostname", + "", + ), + HOSTNAME_Y, + ), + retheme = normal.to_string(), + ok = frame.write_centered("[ok]", OK_Y), ) } + + #[inline] + fn field_str( + &self, + color: ColorSet, + width: u16, + field: &str, + field_content: &str, + ) -> String { + let unpadded = format!("{field}: {field_content}",); + let len = field.len() + field_content.len() + 2; + unpadded + &"_".repeat(width as usize - len) + } } impl Page for SigninPage { @@ -140,22 +167,25 @@ impl Page for SigninPage { screen: &mut RawTerminal, ) -> Result<()> { self.frame = Some(env.frame.sub( - env.theme.colors.subwin, - super::frame::FrameSize::ByPercent(80, 80), + env.theme.colors.subframe, + super::frame::FrameSize::ByPercent(50, 50), 2, )); write!( screen, - "{theme}{clear}{frame}{subframe}{show_cursor}{content}", + "{theme}{clear}{frame}{subframe}{content}{hide_cursor}", theme = env.theme.frame(), clear = clear::All, frame = env.frame.frame_str(env.theme.primary()), subframe = self .frame .unwrap() - .frame_str(ColorSet::default().to_string()), - show_cursor = cursor::Show, - content = self.draw(), + .frame_str(env.theme.colors.subwin.to_string()), + hide_cursor = cursor::Hide, + content = self.draw( + env.theme.colors.highlight, + env.theme.colors.subwin + ), )?; screen.flush()?; diff --git a/src/display/compose.rs b/src/display/compose.rs new file mode 100644 index 0000000..c5d88b7 --- /dev/null +++ b/src/display/compose.rs @@ -0,0 +1,64 @@ +use std::ops::Deref; + +use super::{frame::Frame, theme::ColorSet}; + +#[derive(Clone, Debug)] +pub enum Component { + String(String), + Goto(u16, u16), + Theme(ColorSet), + Clear, +} + +impl Component { + pub fn prepare_for(&self, frame: &Frame) -> String { + match self { + Component::String(s) => s.to_owned(), + Component::Goto(x, y) => frame.goto(*x, *y), + Component::Theme(c) => c.to_string(), + Component::Clear => termion::clear::All.to_string(), + } + } +} + +#[derive(Clone, Debug)] +pub struct Components(Vec); + +impl Deref for Components { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From> for Components { + fn from(value: Vec) -> Self { + Self(value) + } +} + +impl From for Components { + fn from(value: Component) -> Self { + Self(vec![value]) + } +} + +impl Components { + pub fn str_len(&self) -> u16 { + let mut len_cnt: u16 = 0; + for elem in &self.0 { + if let Component::String(s) = elem { + len_cnt += s.len() as u16; + } + } + len_cnt + } + + pub fn concat_for(self, frame: &Frame) -> String { + self.0 + .into_iter() + .map(|component| component.prepare_for(frame)) + .collect::() + } +} diff --git a/src/display/frame.rs b/src/display/frame.rs index 0ce7a2e..25e4a8e 100644 --- a/src/display/frame.rs +++ b/src/display/frame.rs @@ -28,10 +28,14 @@ impl Frame { &self, theme: ColorSet, size: FrameSize, - width: u16, + border: u16, ) -> Frame { let (p_width, p_height) = self.size(); - size.abs_size((p_width - 1, p_height - 1), theme, width) + let sub_size = size.abs_size(( + p_width - self.border * 2, + p_height - self.border * 2, + )); + self.child_centered(sub_size, border, theme) } #[inline(always)] @@ -61,6 +65,8 @@ impl Frame { #[inline(always)] fn write_centered_clear(&self, s: &str) -> String { let width = self.size().0 as usize; + let limit = width - self.border as usize * 2; + let s = if s.len() > limit { &s[..limit] } else { s }; let len = s.len(); let base_size = ((width - len) / 2) - self.border as usize; format!( @@ -81,6 +87,8 @@ impl Frame { #[inline(always)] fn write_clear_to_end(&self, s: &str) -> String { + let limit = (self.size().0 - self.border * 2) as usize; + let s = if s.len() > limit { &s[..limit] } else { s }; let clear_length = self.size().0 as usize - s.len() - (self.border * 2) as usize; @@ -115,6 +123,10 @@ impl Frame { #[inline(always)] pub fn size(&self) -> (u16, u16) { + eprintln!( + "end.0: {}, start.0: {}, end.1: {}, start.1: {}", + self.end.0, self.start.0, self.end.1, self.start.1 + ); (self.end.0 - self.start.0, self.end.1 - self.start.1) } @@ -124,24 +136,71 @@ impl Frame { width: u16, ) -> Result { let term = termion::terminal_size()?; - // Swap term dimensions to use x/y - // let term = (term.1, term.0); Ok(Self::from_bottom_right(term, term, width, theme)) } + #[inline(always)] + fn child_centered( + &self, + (pos_w, pos_h): (u16, u16), + border: u16, + theme: ColorSet, + ) -> Frame { + let parent_offset = self.border / 2; + let (parent_w, parent_h) = self.size(); + let (parent_w, parent_h) = + (parent_w - self.border, parent_h - self.border); + let start = ( + 1.max( + (parent_w - pos_w) / 2 + + ((parent_w - pos_w) % 2) + + parent_offset, + ), + 1.max( + (parent_h - pos_h) / 2 + + ((parent_h - pos_h) % 2) + + parent_offset, + ), + ); + let frame = Self { + end: (start.0 + pos_w, start.1 + pos_h), + start, + border, + theme, + }; + frame + } + #[inline(always)] fn from_bottom_right( (pos_w, pos_h): (u16, u16), (term_w, term_h): (u16, u16), - width: u16, + border: u16, theme: ColorSet, ) -> Self { - Self { - start: (1.max(term_w - pos_w), 1.max(term_h - pos_h)), - end: (pos_w, pos_h), - border: width, + let start = (1.max(term_w - pos_w), 1.max(term_h - pos_h)); + let frame = Self { + end: (start.0 + pos_w, start.1 + pos_h), + start, + border, theme, + }; + if frame.start.0 > frame.end.0 || frame.start.1 > frame.end.1 + { + eprintln!( + "pos_w {}, pos_h {}, term_w {}, term_h {}, border {}", + pos_w, pos_h, term_w, term_h, border + ); + panic!( + "start.0: {} end.0: {}, start.1: {}, end.1: {}", + frame.start.0, + frame.end.0, + frame.start.1, + frame.end.1 + ); } + + frame } pub fn frame_str(&self, body_theme: String) -> String { @@ -188,14 +247,12 @@ impl FrameSize { fn abs_size( &self, (term_width, term_height): (u16, u16), - theme: ColorSet, - width: u16, - ) -> Frame { - let pos = match self { - FrameSize::ByAbsolute(h, w) => { + ) -> (u16, u16) { + match self { + FrameSize::ByAbsolute(w, h) => { ((*w).min(term_width), (*h).min(term_height)) } - FrameSize::ByPercent(h, w) => { + FrameSize::ByPercent(w, h) => { // term_height = 100% // x = h% // @@ -205,12 +262,6 @@ impl FrameSize { term_height * (*h).min(100) / 100, ) } - }; - Frame::from_bottom_right( - pos, - (term_width, term_height), - width, - theme, - ) + } } } diff --git a/src/display/mod.rs b/src/display/mod.rs index 50e3ab0..9e8cb04 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -13,6 +13,7 @@ use self::frame::Frame; use self::theme::{Color, Theme}; pub mod body; +pub mod compose; pub mod frame; pub mod theme; type Result = std::result::Result; @@ -54,11 +55,7 @@ impl Display for Event { ) -> std::fmt::Result { match self { Event::Key(key) => { - write!( - f, - "{}", - format!("{:#?}", key) - ) + write!(f, "{}", format!("{:#?}", key)) } } } @@ -167,7 +164,7 @@ impl Screen { clear = clear::All, show_cursor = cursor::Show, )?; - scr.flush(); + scr.flush()?; Ok(()) } diff --git a/src/display/theme.rs b/src/display/theme.rs index 562f3f0..b0bcd56 100644 --- a/src/display/theme.rs +++ b/src/display/theme.rs @@ -33,7 +33,9 @@ impl ToString for ColorSet { pub struct Colors { pub primary: ColorSet, pub frame: ColorSet, + pub subframe: ColorSet, pub subwin: ColorSet, + pub highlight: ColorSet, } impl Theme {} @@ -86,7 +88,18 @@ impl Default for Theme { fg: "#ffe6ff".into(), bg: "#330033".into(), }, - subwin: ColorSet{ fg: "#ffe6ff".into(), bg: "#110011".into() }, + subframe: ColorSet{ + fg: "#ffe6ff".into(), + bg: "#110011".into() + }, + highlight: ColorSet{ + fg: "#ffffff".into(), + bg: "#0000ff".into() + }, + subwin: ColorSet{ + fg: "#ffffff".into(), + bg: "#000000".into(), + }, }, } }