Somewhat working frame
This commit is contained in:
parent
b66b5e5123
commit
a64048104c
File diff suppressed because it is too large
Load Diff
|
@ -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]
|
||||||
|
|
|
@ -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()?;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue