Somewhat working frame

This commit is contained in:
emilis 2023-01-14 14:57:23 +00:00
parent b66b5e5123
commit a64048104c
6 changed files with 130 additions and 1817 deletions

1743
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.68" anyhow = "1.0.68"
misskey = "0.2.0" # misskey = "0.2.0"
termion = "2.0.1" termion = "2.0.1"
[dependencies.tokio] [dependencies.tokio]

View File

@ -17,11 +17,9 @@ impl Body {
let event = format!("{}", event); let event = format!("{}", event);
write!( write!(
screen, screen,
"{theme}{clear}{start}{}", "{fr}{}",
env.frame.write(&format!("Event: {}", event), 1, 1), env.frame.writeln(&format!("Event: {}", event), 1, 1),
theme = env.theme.display_string(), fr = env.primary_frame(),
clear = clear::All,
start = env.frame.goto(1, 1)
)?; )?;
screen.flush()?; screen.flush()?;
Ok(()) Ok(())
@ -45,9 +43,9 @@ impl Page for Body {
fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()> { fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()> {
write!( write!(
screen, screen,
"{theme}{clear}{cursor}{fr}", "{hide}{clear}{fr}{cursor}",
theme = env.theme.display_string(), hide = cursor::Hide,
fr = env.frame.frame_str(), fr = env.frame.frame_str(&env.theme, env.theme.primary()),
cursor = env.frame.goto(0, 0), cursor = env.frame.goto(0, 0),
clear = clear::All clear = clear::All
)?; )?;
@ -95,10 +93,8 @@ impl Page for SigninPage {
fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()> { fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()> {
write!( write!(
screen, screen,
"{theme}{clear}{hide_cursor}{frame}", "{frame}{hide_cursor}",
frame = env.frame.frame_str(), frame = env.frame.frame_str(&env.theme, env.theme.primary()),
theme = env.theme.display_string(),
clear = clear::All,
hide_cursor = cursor::Hide, hide_cursor = cursor::Hide,
)?; )?;
screen.flush()?; screen.flush()?;

View File

@ -1,8 +1,12 @@
use termion::cursor; use termion::{clear, cursor};
const ESTIMATED_FRAME_BIT_SIZE: usize = 11; const ESTIMATED_FRAME_BIT_SIZE: usize = 11;
use std::io::Write;
const FRAME_CHAR: char = ' '; use super::theme::Theme;
const FRAME_CHAR_HORIZONTAL: char = 'h';
const FRAME_CHAR_VERTICAL: char = 'v';
pub enum FrameSize { pub enum FrameSize {
ByAbsolute(u16, u16), ByAbsolute(u16, u16),
@ -11,8 +15,9 @@ pub enum FrameSize {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Frame { pub struct Frame {
start: (u16, u16), // (w, h) // Both are (w, h)
end: (u16, u16), // (w, h) start: (u16, u16),
end: (u16, u16),
} }
impl Frame { impl Frame {
@ -22,40 +27,22 @@ impl Frame {
(self.start.0 + x).min(self.end.0 - 1), (self.start.0 + x).min(self.end.0 - 1),
(self.start.1 + y).min(self.end.1 - 1), (self.start.1 + y).min(self.end.1 - 1),
); );
// eprintln!(
// "goto x: {x} y: {y} -> x: {nx} y: {ny}",
// x = x,
// y = y,
// nx = cg.0,
// ny = cg.1
// );
// eprintln!("self start: {:#?} self end: {:#?}", self.start, self.end);
cg.into() cg.into()
} }
pub fn write(&self, s: &str, x: u16, y: u16) -> String { pub fn writeln(&self, s: &str, x: u16, y: u16) -> String {
let words = s.split('\n'); let words = s.split('\n').collect::<Vec<&str>>();
let (width, height) = self.size(); let mut out_words = Vec::with_capacity(words.len());
let mut lines_down = 0; for i in 0..words.len() {
let mut curr_len = width; out_words.push(format!(
let mut write_parts = Vec::with_capacity(s.len() / 5); "{str}{ret}",
write_parts.push(self.goto(x, y)); str = words[i],
for w in words { ret = self.goto(1, y + i as u16 + 1)
// if curr_len + (w.len() as u16) > width { ));
// if y + 1 >= height {
// panic!("out of vertical space")
// }
// lines_down += 1;
// curr_len = 1;
// }
write_parts.push(self.goto(1, lines_down + y));
lines_down += 1;
write_parts.push(w.to_string());
} }
write_parts.concat() out_words.concat()
} }
// (x, y)
#[inline] #[inline]
pub fn size(&self) -> (u16, u16) { pub fn size(&self) -> (u16, u16) {
(self.end.0 - self.start.0, self.end.1 - self.start.1) (self.end.0 - self.start.0, self.end.1 - self.start.1)
@ -63,7 +50,8 @@ impl Frame {
pub fn from_terminal_size() -> Result<Self, anyhow::Error> { pub fn from_terminal_size() -> Result<Self, anyhow::Error> {
let term = termion::terminal_size()?; 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)) Ok(Self::from_bottom_right(term, term))
} }
@ -74,27 +62,32 @@ impl Frame {
} }
} }
pub fn frame_str(&self) -> String { pub fn frame_str(&self, theme: &Theme, body_theme: String) -> String {
let (w_len, h_len) = ( self.goto(0, 0);
(self.end.0 - self.start.0) as usize, let (w_len, h_len) = self.size();
(self.end.1 - self.start.1 - 1) as usize, let width_str = FRAME_CHAR_HORIZONTAL.to_string().repeat(w_len as usize + 1);
); let mut frame = Vec::with_capacity(h_len as usize + 4);
let width_str = FRAME_CHAR.to_string().repeat(w_len + 1); let frame_theme = theme.frame();
let mut frame = String::with_capacity((h_len * 2) + (w_len * 2) * ESTIMATED_FRAME_BIT_SIZE); let body_clear = body_theme.clone() + &clear::CurrentLine.to_string();
frame.push(frame_theme.clone());
let make_line = let make_line =
|y: u16| format!("{left}{}", width_str, left = cursor::Goto(self.start.0, y)); |y: u16| format!("{left}{}", width_str, left = cursor::Goto(self.start.0, y));
frame.push_str(&make_line(self.start.1)); frame.push(make_line(self.start.1));
for y in self.start.1 + 1..self.end.1 { for y in self.start.1 + 1..self.end.1 {
frame.push_str(&format!( frame.push(format!(
"{left}{char}{right}{char}", "{left}{body_clear}{frame_theme}{char}{right}{char}",
left = self.goto(self.start.0, y), body_clear = &body_clear,
right = self.goto(self.end.0, y), frame_theme = &frame_theme,
char = FRAME_CHAR, left = cursor::Goto(self.start.0, y),
right = cursor::Goto(self.start.0 + self.end.0, y),
char = FRAME_CHAR_VERTICAL,
)); ));
} }
frame.push_str(&make_line(self.end.1)); frame.push(make_line(self.end.1));
frame.push_str(&self.goto(1, 1)); frame.push(self.goto(1, 1));
frame frame.push(body_theme);
frame.concat()
} }
} }
@ -105,9 +98,10 @@ impl FrameSize {
let pos = match self { let pos = match self {
FrameSize::ByAbsolute(h, w) => ((*h).min(term_height), (*w).min(term_width)), FrameSize::ByAbsolute(h, w) => ((*h).min(term_height), (*w).min(term_width)),
FrameSize::ByPercent(h, w) => { FrameSize::ByPercent(h, w) => {
// term_height = 100% // term_height = 100%
// x = h% // x = h%
// x = term_height * h / 100 //
// term_height * h / 100 = x
( (
term_height * (*h).min(100) / 100, term_height * (*h).min(100) / 100,
term_width * (*w).min(100) / 100, term_width * (*w).min(100) / 100,

View File

@ -10,7 +10,7 @@ use tokio::time::Instant;
use self::body::Body; use self::body::Body;
use self::frame::Frame; use self::frame::Frame;
use self::theme::Theme; use self::theme::{Color, Theme};
pub mod body; pub mod body;
pub mod frame; pub mod frame;
@ -66,8 +66,8 @@ impl Into<String> for Environment {
fn into(self) -> String { fn into(self) -> String {
format!( format!(
"{frame}{theme}", "{frame}{theme}",
frame = self.frame.frame_str(), frame = self.frame.frame_str(&self.theme, self.theme.primary()),
theme = self.theme.display_string(), theme = self.theme.primary(),
) )
} }
} }
@ -79,6 +79,11 @@ impl Environment {
frame: Frame::from_terminal_size().expect("could not get terminal size"), frame: Frame::from_terminal_size().expect("could not get terminal size"),
} }
} }
#[inline(always)]
pub fn primary_frame(&self) -> String {
self.frame.frame_str(&self.theme, self.theme.primary())
}
} }
impl Screen { impl Screen {
@ -120,7 +125,14 @@ impl Screen {
// Cleanup // Cleanup
let mut scr = self.screen.lock().await; let mut scr = self.screen.lock().await;
write!(scr, "{}{}", cursor::Goto(1, 1), clear::All)?; write!(
scr,
"{color}{clear}{show_cursor}{move_to_start}",
color = Into::<Color>::into("#000000").bg_string(),
move_to_start = cursor::Goto(1, 1),
clear = clear::All,
show_cursor = cursor::Show,
)?;
Ok(()) Ok(())
} }

View File

@ -7,12 +7,23 @@ pub struct Theme {
pub colors: Colors, pub colors: Colors,
} }
#[derive(Clone, Copy, Debug)]
pub struct ColorSet {
pub fg: Color,
pub bg: Color,
}
impl ToString for ColorSet {
#[inline(always)]
fn to_string(&self) -> String {
self.bg.bg_string() + &self.fg.fg_string()
}
}
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct Colors { pub struct Colors {
pub primary_bg: Color, pub primary: ColorSet,
pub frame_bg: Color, pub frame: ColorSet,
pub frame_fg: Color,
pub text: Color,
} }
impl Theme {} impl Theme {}
@ -33,22 +44,20 @@ impl TryFrom<String> for Color {
} }
} }
impl TryFrom<&str> for Color { impl From<&str> for Color {
type Error = anyhow::Error; fn from(value: &str) -> Self {
fn try_from(value: &str) -> Result<Self, Self::Error> {
if value.len() < 6 || value.len() > 7 { if value.len() < 6 || value.len() > 7 {
return Err(anyhow::anyhow!("hex code length invalid: {}", value.len())); panic!("hex code length invalid: {}", value.len());
} }
let mut i = 0; let mut i = 0;
if value.starts_with('#') { if value.starts_with('#') {
i = 1; i = 1;
} }
Ok(Self(color::Rgb( Self(color::Rgb(
u8::from_str_radix(&value[i..i + 2], 16)?, u8::from_str_radix(&value[i..i + 2], 16).expect("red hex"),
u8::from_str_radix(&value[i + 2..i + 4], 16)?, u8::from_str_radix(&value[i + 2..i + 4], 16).expect("green hex"),
u8::from_str_radix(&value[i + 4..i + 6], 16)?, u8::from_str_radix(&value[i + 4..i + 6], 16).expect("blue hex"),
))) ))
} }
} }
@ -56,22 +65,27 @@ impl Default for Theme {
fn default() -> Self { fn default() -> Self {
Self { Self {
colors: Colors { colors: Colors {
primary_bg: "#3b224c".try_into().unwrap(), primary: ColorSet {
text: "#ffe6ff".try_into().unwrap(), fg: "#ffe6ff".into(),
frame_bg: "#330033".try_into().unwrap(), bg: "#3b224c".into(),
frame_fg: "#ffe6ff".try_into().unwrap(), },
frame: ColorSet {
fg: "#ffe6ff".into(),
bg: "#330033".into(),
},
}, },
} }
} }
} }
impl Theme { impl Theme {
#[inline] #[inline(always)]
pub fn display_string(&self) -> String { pub fn primary(&self) -> String {
format!( self.colors.primary.to_string()
"{primary_bg}{text}", }
primary_bg = self.colors.primary_bg.bg_string(),
text = self.colors.text.fg_string() #[inline(always)]
) pub fn frame(&self) -> String {
self.colors.frame.to_string()
} }
} }