keyboard input

This commit is contained in:
2024-09-21 19:08:03 +02:00
parent f47f3575de
commit 56d1691397
5 changed files with 85 additions and 64 deletions
+53 -27
View File
@@ -1,5 +1,9 @@
use std::io::{self, Write};
use crossterm::terminal::{self, disable_raw_mode, enable_raw_mode};
use std::{
io::{self, Read, Write},
str::from_utf8,
};
pub mod key;
pub mod ui;
#[derive(Clone)]
@@ -7,11 +11,10 @@ pub struct ComponentWrapper<T> {
pub component: T,
pub x: usize,
pub y: usize,
cleared_frame: String,
}
pub trait Component {
fn render(&mut self) -> String {
fn render(&self) -> String {
String::new()
}
fn run(&mut self, x: usize, y: usize) -> String {
@@ -27,31 +30,8 @@ impl<T: Component> ComponentWrapper<T> {
component,
x: 0,
y: 0,
cleared_frame: String::new(),
}
}
pub fn render(&mut self) {
self.clean();
self.cleared_frame.clear();
for (i, d) in format!("{}", self.component.render())
.split("\n")
.enumerate()
{
print!("\x1B[{};{}H{}", self.y + (i + 1), self.x, d);
self.cleared_frame += format!(
"\x1B[{};{}H{}",
self.y + (i + 1),
self.x,
" ".repeat(d.len())
)
.as_str();
}
flush();
}
pub fn clean(&self) {
print!("{}", self.cleared_frame);
flush();
}
pub fn run(&mut self) -> String {
self.component.run(self.x, self.y)
}
@@ -65,3 +45,49 @@ pub fn clear() {
pub fn flush() {
io::stdout().flush().unwrap();
}
pub fn render_frame<T: Component>(components: Vec<ComponentWrapper<T>>) {
clear();
let (w, h) = terminal::size().unwrap();
let mut frame: Vec<String> = vec![" ".repeat(w as usize); h as usize - 1];
for c in components {
for (i, line) in c.component.render().split("\n").enumerate() {
frame[c.y + i] = render_line(frame[c.y + i].clone(), line.to_string(), c.x);
}
}
print!("{}", frame.join("\n"));
flush();
}
fn render_line(frame_line: String, line: String, x: usize) -> String {
let mut result = String::new();
if x >= frame_line.len() {
return result;
}
let lchars: Vec<char> = line.chars().collect();
for (i, c) in frame_line.chars().enumerate() {
if i >= x && lchars.len() > (i - x) {
result += lchars[i - x].to_string().as_str();
} else {
result += c.to_string().as_str();
}
}
result
}
fn read_key_() -> String {
let mut buf = [0u8; 2];
io::stdin().read(&mut buf).unwrap();
let mut res = from_utf8(&buf).unwrap().to_string();
if !res.ends_with("\0") {
res += read_key_().as_str()
}
return res.strip_suffix("\0").unwrap_or(&res).to_string();
}
pub fn read_key() -> String {
enable_raw_mode().unwrap();
let res = read_key_();
disable_raw_mode().unwrap();
return res;
}
+3 -4
View File
@@ -1,7 +1,6 @@
use osui::{self, ui};
use osui::{self, render_frame, ui};
fn main() {
osui::clear();
let mut txt = ui::text("hello, world!");
txt.render();
let txt = ui::text("Hello World!");
render_frame(vec![txt.clone()]);
}
+22 -26
View File
@@ -1,8 +1,6 @@
use crate::{Component, ComponentWrapper};
use k_board::{keyboard::Keyboard, keys::Keys};
use crate::{flush, key, read_key, Component, ComponentWrapper};
impl Component for String {
fn render(&mut self) -> String {
fn render(&self) -> String {
self.clone()
}
}
@@ -11,51 +9,49 @@ pub fn text(text: &str) -> ComponentWrapper<String> {
ComponentWrapper::new(text.to_string())
}
#[derive(Clone)]
pub struct Input {
pub max_length: usize,
}
impl Component for Input {
fn render(&mut self) -> String {
fn render(&self) -> String {
format!(
" {}\n|{}|\n {}\x1b[1A\x1b[{}D",
" {}\n|{}|\n {}",
"_".repeat(self.max_length),
" ".repeat(self.max_length),
"‾".repeat(self.max_length),
self.max_length
)
}
fn run(&mut self, x: usize, y: usize) -> String {
print!("\x1B[{};{}H", y + 2, x + 2);
flush();
let mut input = String::new();
loop {
let key = Keyboard::new().read_key();
if key == Keys::Enter {
return input;
}
if input.len() < self.max_length {
match key {
Keys::Char(c) => {
match read_key().as_str() {
key::ENTER => {
print!("\n\n");
return input;
}
key::BACKSPACE => {
if input.len() > 0 {
input.pop();
print!("\x1b[1D \x1b[1D");
flush();
}
}
c => {
if input.len() < self.max_length {
input += c.to_string().as_str();
print!("{c}");
flush();
}
Keys::Space => {
input += " ";
print!(" ");
}
Keys::Delete => {
if input.len() > 0 {
input.pop();
print!("\x1b[1D \x1b[1D");
}
}
_ => {}
}
}
}
}
}
pub fn input(max_length: usize) -> ComponentWrapper<Input> {
pub fn input_box(max_length: usize) -> ComponentWrapper<Input> {
ComponentWrapper::new(Input { max_length })
}