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]
anyhow = "1.0.68"
misskey = "0.2.0"
# misskey = "0.2.0"
termion = "2.0.1"
[dependencies.tokio]

View File

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

View File

@ -1,8 +1,12 @@
use termion::cursor;
use termion::{clear, cursor};
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 {
ByAbsolute(u16, u16),
@ -11,8 +15,9 @@ pub enum FrameSize {
#[derive(Debug, Clone, Copy)]
pub struct Frame {
start: (u16, u16), // (w, h)
end: (u16, u16), // (w, h)
// Both are (w, h)
start: (u16, u16),
end: (u16, u16),
}
impl Frame {
@ -22,40 +27,22 @@ impl Frame {
(self.start.0 + x).min(self.end.0 - 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()
}
pub fn write(&self, s: &str, x: u16, y: u16) -> String {
let words = s.split('\n');
let (width, height) = self.size();
let mut lines_down = 0;
let mut curr_len = width;
let mut write_parts = Vec::with_capacity(s.len() / 5);
write_parts.push(self.goto(x, y));
for w in words {
// 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());
pub fn writeln(&self, s: &str, x: u16, y: u16) -> String {
let words = s.split('\n').collect::<Vec<&str>>();
let mut out_words = Vec::with_capacity(words.len());
for i in 0..words.len() {
out_words.push(format!(
"{str}{ret}",
str = words[i],
ret = self.goto(1, y + i as u16 + 1)
));
}
write_parts.concat()
out_words.concat()
}
// (x, y)
#[inline]
pub fn size(&self) -> (u16, u16) {
(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> {
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))
}
@ -74,27 +62,32 @@ impl Frame {
}
}
pub fn frame_str(&self) -> String {
let (w_len, h_len) = (
(self.end.0 - self.start.0) as usize,
(self.end.1 - self.start.1 - 1) as usize,
);
let width_str = FRAME_CHAR.to_string().repeat(w_len + 1);
let mut frame = String::with_capacity((h_len * 2) + (w_len * 2) * ESTIMATED_FRAME_BIT_SIZE);
pub fn frame_str(&self, theme: &Theme, body_theme: String) -> String {
self.goto(0, 0);
let (w_len, h_len) = self.size();
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 frame_theme = theme.frame();
let body_clear = body_theme.clone() + &clear::CurrentLine.to_string();
frame.push(frame_theme.clone());
let make_line =
|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 {
frame.push_str(&format!(
"{left}{char}{right}{char}",
left = self.goto(self.start.0, y),
right = self.goto(self.end.0, y),
char = FRAME_CHAR,
frame.push(format!(
"{left}{body_clear}{frame_theme}{char}{right}{char}",
body_clear = &body_clear,
frame_theme = &frame_theme,
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_str(&self.goto(1, 1));
frame
frame.push(make_line(self.end.1));
frame.push(self.goto(1, 1));
frame.push(body_theme);
frame.concat()
}
}
@ -105,9 +98,10 @@ impl FrameSize {
let pos = match self {
FrameSize::ByAbsolute(h, w) => ((*h).min(term_height), (*w).min(term_width)),
FrameSize::ByPercent(h, w) => {
// term_height = 100%
// x = h%
// x = term_height * h / 100
// term_height = 100%
// x = h%
//
// term_height * h / 100 = x
(
term_height * (*h).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::frame::Frame;
use self::theme::Theme;
use self::theme::{Color, Theme};
pub mod body;
pub mod frame;
@ -66,8 +66,8 @@ impl Into<String> for Environment {
fn into(self) -> String {
format!(
"{frame}{theme}",
frame = self.frame.frame_str(),
theme = self.theme.display_string(),
frame = self.frame.frame_str(&self.theme, self.theme.primary()),
theme = self.theme.primary(),
)
}
}
@ -79,6 +79,11 @@ impl Environment {
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 {
@ -120,7 +125,14 @@ impl Screen {
// Cleanup
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(())
}

View File

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