Create very basic text input
This commit is contained in:
parent
95d1f3295f
commit
28c3241fd9
4 changed files with 81 additions and 106 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -202,6 +202,7 @@ dependencies = [
|
|||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"tui",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -18,3 +18,4 @@ tokio-tungstenite = { version = "0.16.1", features = [
|
|||
"rustls-tls-native-roots",
|
||||
] }
|
||||
tui = "0.17.0"
|
||||
unicode-width = "0.1.9"
|
||||
|
|
|
|||
|
|
@ -2,124 +2,48 @@ mod config;
|
|||
mod never;
|
||||
mod replies;
|
||||
mod room;
|
||||
mod textline;
|
||||
|
||||
use std::io::{self, Stdout};
|
||||
|
||||
use config::Config;
|
||||
use crossterm::event::{DisableMouseCapture, EnableMouseCapture};
|
||||
use crossterm::event::{DisableMouseCapture, EnableMouseCapture, Event, KeyCode};
|
||||
use crossterm::execute;
|
||||
use crossterm::terminal::{EnterAlternateScreen, LeaveAlternateScreen};
|
||||
use palette::rgb::Rgb;
|
||||
use palette::{FromColor, Hsl, Srgb};
|
||||
use tui::backend::CrosstermBackend;
|
||||
use tui::layout::{Constraint, Direction, Layout};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::text::{Span, Spans};
|
||||
use tui::widgets::{Block, Borders, List, ListItem, ListState, Paragraph};
|
||||
use tui::Terminal;
|
||||
use textline::{TextLine, TextLineState};
|
||||
use tui::backend::{Backend, CrosstermBackend};
|
||||
use tui::{Frame, Terminal};
|
||||
|
||||
async fn run(terminal: &mut Terminal<CrosstermBackend<Stdout>>) -> anyhow::Result<()> {
|
||||
terminal.draw(|f| {
|
||||
let hchunks = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([
|
||||
Constraint::Length(20),
|
||||
Constraint::Length(2),
|
||||
Constraint::Min(0),
|
||||
Constraint::Length(2),
|
||||
Constraint::Length(20),
|
||||
])
|
||||
.split(f.size());
|
||||
#[derive(Debug, Default)]
|
||||
struct Ui {
|
||||
text: TextLineState,
|
||||
}
|
||||
|
||||
// Borders
|
||||
f.render_widget(Block::default().borders(Borders::LEFT), hchunks[1]);
|
||||
f.render_widget(Block::default().borders(Borders::LEFT), hchunks[3]);
|
||||
impl Ui {
|
||||
fn draw<B: Backend>(&mut self, f: &mut Frame<B>) {
|
||||
f.render_stateful_widget(TextLine, f.size(), &mut self.text);
|
||||
self.text.set_cursor(f, f.size());
|
||||
}
|
||||
}
|
||||
|
||||
// Room list
|
||||
let room_style = Style::default().fg(Color::LightBlue);
|
||||
let mut state = ListState::default();
|
||||
// state.select(Some(1));
|
||||
f.render_stateful_widget(
|
||||
List::new(vec![
|
||||
ListItem::new(Span::styled(
|
||||
"Cove",
|
||||
Style::default().add_modifier(Modifier::BOLD),
|
||||
)),
|
||||
ListItem::new(Span::styled("&dunno", room_style)),
|
||||
ListItem::new(Span::styled("&test", room_style)),
|
||||
ListItem::new(" "),
|
||||
ListItem::new(Span::styled(
|
||||
"Euphoria",
|
||||
Style::default().add_modifier(Modifier::BOLD),
|
||||
)),
|
||||
ListItem::new(Span::styled("&xkcd", room_style)),
|
||||
ListItem::new(Span::styled("&music", room_style)),
|
||||
ListItem::new(Span::styled("&bots", room_style)),
|
||||
ListItem::new(" "),
|
||||
ListItem::new(Span::styled(
|
||||
"Instant",
|
||||
Style::default().add_modifier(Modifier::BOLD),
|
||||
)),
|
||||
ListItem::new(Span::styled("&welcome", room_style)),
|
||||
]),
|
||||
// .highlight_style(Style::default().add_modifier(Modifier::BOLD))
|
||||
// .highlight_symbol(">"),
|
||||
hchunks[0],
|
||||
&mut state,
|
||||
);
|
||||
// f.render_widget(Paragraph::new("foo"), hchunks[0]);
|
||||
fn run(terminal: &mut Terminal<CrosstermBackend<Stdout>>) -> anyhow::Result<()> {
|
||||
let mut ui = Ui::default();
|
||||
loop {
|
||||
terminal.draw(|f| ui.draw(f))?;
|
||||
|
||||
// Nick list
|
||||
let nchunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Length(1), Constraint::Min(0)])
|
||||
.split(hchunks[4]);
|
||||
f.render_widget(
|
||||
Paragraph::new(Spans::from(vec![
|
||||
Span::styled("Users", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw(" "),
|
||||
Span::styled("(13)", Style::default().fg(Color::Gray)),
|
||||
])),
|
||||
nchunks[0],
|
||||
);
|
||||
fn userstyle(r: u8, g: u8, b: u8) -> Style {
|
||||
let rgb = Srgb::new(r, g, b).into_format::<f32>();
|
||||
let mut hsl = Hsl::from_color(rgb);
|
||||
hsl.saturation = 1.0;
|
||||
hsl.lightness = 0.7;
|
||||
let rgb = Rgb::from_color(hsl).into_format::<u8>();
|
||||
Style::default().fg(Color::Rgb(rgb.red, rgb.green, rgb.blue))
|
||||
let event = crossterm::event::read()?;
|
||||
|
||||
if let Event::Key(k) = event {
|
||||
if k.code == KeyCode::Esc {
|
||||
break;
|
||||
}
|
||||
}
|
||||
f.render_widget(
|
||||
List::new([
|
||||
ListItem::new(Span::styled("TerryTvType", userstyle(192, 242, 238))),
|
||||
ListItem::new(Span::styled("r*4", userstyle(192, 211, 242))),
|
||||
ListItem::new(Span::styled("Swedish", userstyle(192, 242, 207))),
|
||||
ListItem::new(Span::styled("Garmy", userstyle(242, 225, 192))),
|
||||
ListItem::new(Span::styled("SRP", userstyle(242, 219, 192))),
|
||||
ListItem::new(Span::styled("C", userstyle(192, 218, 242))),
|
||||
ListItem::new(Span::styled("fill", userstyle(192, 197, 242))),
|
||||
ListItem::new(Span::styled("ohnezo", userstyle(242, 203, 192))),
|
||||
ListItem::new(Span::styled("Sumärzru", userstyle(242, 223, 192))),
|
||||
ListItem::new(Span::styled("SuperGeek", userstyle(192, 242, 203))),
|
||||
ListItem::new(Span::styled("certainlyhominid", userstyle(192, 242, 209))),
|
||||
ListItem::new(Span::styled("Plugh", userstyle(192, 242, 215))),
|
||||
ListItem::new(Span::styled(
|
||||
"🎼\u{fe0e}🎷🎷🎷🎼\u{fe0e}",
|
||||
userstyle(242, 192, 192),
|
||||
)),
|
||||
]),
|
||||
nchunks[1],
|
||||
);
|
||||
})?;
|
||||
let _ = crossterm::event::read();
|
||||
|
||||
ui.text.process_input(event);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let config = Config::load();
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let mut terminal = Terminal::new(CrosstermBackend::new(io::stdout()))?;
|
||||
|
||||
crossterm::terminal::enable_raw_mode()?;
|
||||
|
|
@ -130,7 +54,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
)?;
|
||||
|
||||
// Defer error handling so the terminal always gets restored properly
|
||||
let result = run(&mut terminal).await;
|
||||
let result = run(&mut terminal);
|
||||
|
||||
crossterm::terminal::disable_raw_mode()?;
|
||||
execute!(
|
||||
|
|
|
|||
49
cove-tui/src/textline.rs
Normal file
49
cove-tui/src/textline.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
use std::cmp;
|
||||
|
||||
use crossterm::event::{Event, KeyCode};
|
||||
use tui::backend::Backend;
|
||||
use tui::buffer::Buffer;
|
||||
use tui::layout::Rect;
|
||||
use tui::widgets::{Paragraph, StatefulWidget, Widget};
|
||||
use tui::Frame;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
/// A simple single-line text box.
|
||||
pub struct TextLine;
|
||||
|
||||
impl StatefulWidget for TextLine {
|
||||
type State = TextLineState;
|
||||
|
||||
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
||||
Paragraph::new(&state.content as &str).render(area, buf);
|
||||
// Paragraph::new("foo").render(area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/// State for [`TextLine`].
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TextLineState {
|
||||
content: String,
|
||||
}
|
||||
|
||||
impl TextLineState {
|
||||
pub fn set_cursor<B: Backend>(&self, f: &mut Frame<B>, area: Rect) {
|
||||
let x = area.x + (self.content.width() as u16);
|
||||
let x = cmp::min(x, area.x + area.width);
|
||||
f.set_cursor(x, area.y);
|
||||
}
|
||||
|
||||
pub fn process_input(&mut self, event: Event) {
|
||||
if let Event::Key(k) = event {
|
||||
match k.code {
|
||||
KeyCode::Backspace => {
|
||||
self.content.pop();
|
||||
}
|
||||
KeyCode::Char(c) => {
|
||||
self.content.push(c);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue