ongoing frame work, still experimenting
This commit is contained in:
parent
0b9f43b9d2
commit
b66b5e5123
|
@ -357,17 +357,6 @@ dependencies = [
|
|||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fed"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"misskey",
|
||||
"signal-hook",
|
||||
"termion",
|
||||
"tokio 1.24.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flume"
|
||||
version = "0.9.2"
|
||||
|
@ -669,6 +658,16 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kk"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"misskey",
|
||||
"termion",
|
||||
"tokio 1.24.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -1417,16 +1416,6 @@ dependencies = [
|
|||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
|
|
|
@ -2,11 +2,7 @@ use std::io::{Stdout, Write};
|
|||
|
||||
use termion::{clear, cursor, raw::RawTerminal};
|
||||
|
||||
use super::{
|
||||
frame::{self, FrameDef},
|
||||
theme::Theme,
|
||||
Event, Page,
|
||||
};
|
||||
use super::{Environment, Event, Page};
|
||||
|
||||
type Result<T> = std::result::Result<T, anyhow::Error>;
|
||||
|
||||
|
@ -17,15 +13,15 @@ pub enum Body {
|
|||
}
|
||||
|
||||
impl Body {
|
||||
fn echo(theme: Theme, screen: &mut RawTerminal<Stdout>, event: Event) -> Result<()> {
|
||||
fn echo(env: Environment, screen: &mut RawTerminal<Stdout>, event: Event) -> Result<()> {
|
||||
let event = format!("{}", event);
|
||||
write!(
|
||||
screen,
|
||||
"{theme}{clear}{start}Event: {}",
|
||||
event,
|
||||
theme = theme.display_string(),
|
||||
"{theme}{clear}{start}{}",
|
||||
env.frame.write(&format!("Event: {}", event), 1, 1),
|
||||
theme = env.theme.display_string(),
|
||||
clear = clear::All,
|
||||
start = cursor::Goto(1, 1)
|
||||
start = env.frame.goto(1, 1)
|
||||
)?;
|
||||
screen.flush()?;
|
||||
Ok(())
|
||||
|
@ -35,24 +31,24 @@ impl Body {
|
|||
impl Page for Body {
|
||||
fn receive_event(
|
||||
&mut self,
|
||||
theme: Theme,
|
||||
env: Environment,
|
||||
screen: &mut RawTerminal<Stdout>,
|
||||
event: Event,
|
||||
) -> Result<()> {
|
||||
match self {
|
||||
Body::Signin(b) => b.receive_event(theme, screen, event)?,
|
||||
Body::Echo => Body::echo(theme, screen, event)?,
|
||||
Body::Signin(b) => b.receive_event(env, screen, event)?,
|
||||
Body::Echo => Body::echo(env, screen, event)?,
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(&self, theme: Theme, screen: &mut RawTerminal<Stdout>) -> Result<()> {
|
||||
fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()> {
|
||||
write!(
|
||||
screen,
|
||||
"{theme}{cursor}{clear}{fr}",
|
||||
fr = frame::draw_frame(theme, FrameDef::ByPercent(90, 90)),
|
||||
theme = theme.display_string(),
|
||||
cursor = cursor::Goto(1, 1),
|
||||
"{theme}{clear}{cursor}{fr}",
|
||||
theme = env.theme.display_string(),
|
||||
fr = env.frame.frame_str(),
|
||||
cursor = env.frame.goto(0, 0),
|
||||
clear = clear::All
|
||||
)?;
|
||||
screen.flush()?;
|
||||
|
@ -89,20 +85,19 @@ impl SigninPage {
|
|||
impl Page for SigninPage {
|
||||
fn receive_event(
|
||||
&mut self,
|
||||
theme: Theme,
|
||||
env: Environment,
|
||||
screen: &mut RawTerminal<Stdout>,
|
||||
event: Event,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(&self, theme: Theme, screen: &mut RawTerminal<Stdout>) -> Result<()> {
|
||||
let fr = frame::draw_frame(theme, FrameDef::ByPercent(40, 40));
|
||||
fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()> {
|
||||
write!(
|
||||
screen,
|
||||
"{theme}{clear}{hide_cursor}{frame}",
|
||||
frame = fr,
|
||||
theme = theme.display_string(),
|
||||
frame = env.frame.frame_str(),
|
||||
theme = env.theme.display_string(),
|
||||
clear = clear::All,
|
||||
hide_cursor = cursor::Hide,
|
||||
)?;
|
||||
|
|
|
@ -1,34 +1,85 @@
|
|||
use std::{io, process};
|
||||
use termion::cursor;
|
||||
|
||||
use termion::{color, cursor, screen::IntoAlternateScreen};
|
||||
|
||||
use super::theme::Theme;
|
||||
const ESTIMATED_FRAME_BIT_SIZE: usize = 11;
|
||||
|
||||
pub enum FrameDef {
|
||||
const FRAME_CHAR: char = ' ';
|
||||
|
||||
pub enum FrameSize {
|
||||
ByAbsolute(u16, u16),
|
||||
ByPercent(u16, u16),
|
||||
}
|
||||
|
||||
struct Frame {
|
||||
start: (u16, u16),
|
||||
end: (u16, u16),
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Frame {
|
||||
start: (u16, u16), // (w, h)
|
||||
end: (u16, u16), // (w, h)
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
fn from_bottom_right(pos: (u16, u16), term: (u16, u16)) -> Self {
|
||||
#[inline]
|
||||
pub fn goto(&self, x: u16, y: u16) -> String {
|
||||
let cg = cursor::Goto(
|
||||
(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());
|
||||
}
|
||||
write_parts.concat()
|
||||
}
|
||||
|
||||
// (x, y)
|
||||
#[inline]
|
||||
pub fn size(&self) -> (u16, u16) {
|
||||
(self.end.0 - self.start.0, self.end.1 - self.start.1)
|
||||
}
|
||||
|
||||
pub fn from_terminal_size() -> Result<Self, anyhow::Error> {
|
||||
let term = termion::terminal_size()?;
|
||||
|
||||
Ok(Self::from_bottom_right(term, term))
|
||||
}
|
||||
|
||||
fn from_bottom_right((pos_h, pos_w): (u16, u16), (term_h, term_w): (u16, u16)) -> Self {
|
||||
Self {
|
||||
start: (term.0 - pos.0, term.1 - pos.1),
|
||||
end: pos,
|
||||
start: (1.max(term_w - pos_w), 1.max(term_h - pos_h)),
|
||||
end: (pos_w, pos_h),
|
||||
}
|
||||
}
|
||||
|
||||
fn frame_str(&self, frame_char: char) -> String {
|
||||
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 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);
|
||||
let make_line =
|
||||
|y: u16| format!("{left}{}", width_str, left = cursor::Goto(self.start.0, y));
|
||||
|
@ -36,67 +87,33 @@ impl Frame {
|
|||
for y in self.start.1 + 1..self.end.1 {
|
||||
frame.push_str(&format!(
|
||||
"{left}{char}{right}{char}",
|
||||
left = cursor::Goto(self.start.0, y),
|
||||
right = cursor::Goto(self.end.0, y),
|
||||
char = frame_char,
|
||||
left = self.goto(self.start.0, y),
|
||||
right = self.goto(self.end.0, y),
|
||||
char = FRAME_CHAR,
|
||||
));
|
||||
}
|
||||
frame.push_str(&make_line(self.end.1));
|
||||
frame.push_str(&self.goto(1, 1));
|
||||
frame
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Frame;
|
||||
|
||||
#[test]
|
||||
fn test_idk() {
|
||||
let x = Frame::from_bottom_right((16, 16), (32, 32)).frame_str('=');
|
||||
println!("starting");
|
||||
println!("{}", x);
|
||||
println!("ending");
|
||||
assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl FrameDef {
|
||||
impl FrameSize {
|
||||
fn abs_size(&self) -> Frame {
|
||||
let (term_height, term_width) =
|
||||
termion::terminal_size().expect("could not get terminal size");
|
||||
let pos = match self {
|
||||
FrameDef::ByAbsolute(h, w) => {
|
||||
let (mut h, mut w) = (*h, *w);
|
||||
if h > term_height {
|
||||
h = term_height;
|
||||
}
|
||||
if w > term_width {
|
||||
w = term_width;
|
||||
}
|
||||
(h, w)
|
||||
}
|
||||
FrameDef::ByPercent(h, w) => {
|
||||
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
|
||||
let (h, w) = (
|
||||
if *h > 100 { 100 } else { *h },
|
||||
if *w > 100 { 100 } else { *w },
|
||||
);
|
||||
// (h * 100 / term_height, w * 100 / term_width)
|
||||
(term_height * h / 100, term_width * w / 100)
|
||||
(
|
||||
term_height * (*h).min(100) / 100,
|
||||
term_width * (*w).min(100) / 100,
|
||||
)
|
||||
}
|
||||
};
|
||||
Frame::from_bottom_right(pos, (term_height, term_width))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_frame(theme: Theme, frame_size: FrameDef) -> String {
|
||||
let frame_specs = frame_size.abs_size();
|
||||
format!(
|
||||
"{fg}{bg}{frame}",
|
||||
fg = theme.colors.frame_fg.fg_string(),
|
||||
bg = theme.colors.frame_bg.bg_string(),
|
||||
frame = frame_specs.frame_str('='),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use tokio::sync::Mutex;
|
|||
use tokio::time::Instant;
|
||||
|
||||
use self::body::Body;
|
||||
use self::frame::Frame;
|
||||
use self::theme::Theme;
|
||||
|
||||
pub mod body;
|
||||
|
@ -46,15 +47,40 @@ impl From<Key> for Event {
|
|||
}
|
||||
|
||||
pub trait Page {
|
||||
fn init(&self, theme: Theme, screen: &mut RawTerminal<Stdout>) -> Result<()>;
|
||||
fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()>;
|
||||
fn receive_event(
|
||||
&mut self,
|
||||
theme: Theme,
|
||||
env: Environment,
|
||||
screen: &mut RawTerminal<Stdout>,
|
||||
event: Event,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Environment {
|
||||
pub theme: Theme,
|
||||
pub frame: Frame,
|
||||
}
|
||||
|
||||
impl Into<String> for Environment {
|
||||
fn into(self) -> String {
|
||||
format!(
|
||||
"{frame}{theme}",
|
||||
frame = self.frame.frame_str(),
|
||||
theme = self.theme.display_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Environment {
|
||||
fn initial_must(theme: Theme) -> Self {
|
||||
Self {
|
||||
theme,
|
||||
frame: Frame::from_terminal_size().expect("could not get terminal size"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Screen {
|
||||
pub fn new(theme: Theme) -> Result<Self> {
|
||||
let screen = Mutex::new(io::stdout().into_raw_mode()?);
|
||||
|
@ -72,21 +98,24 @@ impl Screen {
|
|||
}
|
||||
|
||||
pub async fn start(mut self) -> Result<()> {
|
||||
let env = Environment::initial_must(self.theme);
|
||||
{
|
||||
let mut scr = self.screen.lock().await;
|
||||
self.body.init(self.theme, &mut scr)?;
|
||||
self.body.init(env, &mut scr)?;
|
||||
}
|
||||
|
||||
while let Some(ev) = self.events_ch.recv().await {
|
||||
let mut scr = self.screen.lock().await;
|
||||
if let Event::Interrupt = ev {
|
||||
if let Some(last) = self.last_interrupt && last.elapsed().as_millis() < 500 {
|
||||
self.events_ch.close();
|
||||
break;
|
||||
if let Some(last) = self.last_interrupt {
|
||||
if last.elapsed().as_millis() < 500 {
|
||||
self.events_ch.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.last_interrupt = Some(Instant::now());
|
||||
}
|
||||
self.body.receive_event(self.theme, &mut scr, ev)?;
|
||||
self.body.receive_event(env, &mut scr, ev)?;
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
|
|
|
@ -66,6 +66,7 @@ impl Default for Theme {
|
|||
}
|
||||
|
||||
impl Theme {
|
||||
#[inline]
|
||||
pub fn display_string(&self) -> String {
|
||||
format!(
|
||||
"{primary_bg}{text}",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#![feature(let_chains)]
|
||||
use std::process;
|
||||
|
||||
use display::theme::Theme;
|
||||
|
|
Loading…
Reference in New Issue