Extract rooms widget and state

This commit is contained in:
Joscha 2022-02-23 22:32:52 +01:00
parent 980f78f9a7
commit 2d31d3d4e2
2 changed files with 103 additions and 21 deletions

View file

@ -1,3 +1,5 @@
mod rooms;
use std::io::Stdout; use std::io::Stdout;
use crossterm::event::{Event, EventStream, KeyCode, KeyEvent, MouseEvent, MouseEventKind}; use crossterm::event::{Event, EventStream, KeyCode, KeyEvent, MouseEvent, MouseEventKind};
@ -6,9 +8,11 @@ use tokio::sync::mpsc::error::TryRecvError;
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
use tui::backend::CrosstermBackend; use tui::backend::CrosstermBackend;
use tui::layout::{Constraint, Direction, Layout}; use tui::layout::{Constraint, Direction, Layout};
use tui::widgets::{Block, Borders, Paragraph}; use tui::widgets::Paragraph;
use tui::{Frame, Terminal}; use tui::{Frame, Terminal};
use self::rooms::{Rooms, RoomsState};
pub type Backend = CrosstermBackend<Stdout>; pub type Backend = CrosstermBackend<Stdout>;
#[derive(Debug)] #[derive(Debug)]
@ -24,8 +28,7 @@ enum EventHandleResult {
pub struct Ui { pub struct Ui {
event_tx: UnboundedSender<UiEvent>, event_tx: UnboundedSender<UiEvent>,
rooms_width: u16, rooms_state: RoomsState,
rooms_dragging: bool,
log: Vec<String>, log: Vec<String>,
} }
@ -33,8 +36,7 @@ impl Ui {
fn new(event_tx: UnboundedSender<UiEvent>) -> Self { fn new(event_tx: UnboundedSender<UiEvent>) -> Self {
Self { Self {
event_tx, event_tx,
rooms_width: 24, rooms_state: RoomsState::default(),
rooms_dragging: false,
log: vec!["Hello world!".to_string()], log: vec!["Hello world!".to_string()],
} }
} }
@ -130,17 +132,13 @@ impl Ui {
} }
async fn handle_mouse_event(&mut self, event: MouseEvent) -> anyhow::Result<EventHandleResult> { async fn handle_mouse_event(&mut self, event: MouseEvent) -> anyhow::Result<EventHandleResult> {
let rooms_width = event.column + 1;
let over_rooms = self.rooms_state.width() == rooms_width;
match event.kind { match event.kind {
MouseEventKind::Down(_) if event.column == self.rooms_width => { MouseEventKind::Moved => self.rooms_state.hover(over_rooms),
self.rooms_dragging = true; MouseEventKind::Down(_) => self.rooms_state.drag(over_rooms),
} MouseEventKind::Up(_) => self.rooms_state.drag(false),
MouseEventKind::Up(_) => { MouseEventKind::Drag(_) => self.rooms_state.drag_to(rooms_width),
self.rooms_dragging = false;
}
MouseEventKind::Drag(_) if self.rooms_dragging => {
self.rooms_width = event.column;
}
// MouseEventKind::Moved => todo!(),
// MouseEventKind::ScrollDown => todo!(), // MouseEventKind::ScrollDown => todo!(),
// MouseEventKind::ScrollUp => todo!(), // MouseEventKind::ScrollUp => todo!(),
_ => {} _ => {}
@ -152,23 +150,23 @@ impl Ui {
let outer = Layout::default() let outer = Layout::default()
.direction(Direction::Horizontal) .direction(Direction::Horizontal)
.constraints([ .constraints([
Constraint::Length(self.rooms_width), Constraint::Length(self.rooms_state.width()),
Constraint::Length(1),
Constraint::Min(0), Constraint::Min(0),
]) ])
.split(frame.size()); .split(frame.size());
frame.render_widget(Block::default().borders(Borders::RIGHT), outer[1]); frame.render_stateful_widget(Rooms::new(), outer[0], &mut self.rooms_state);
let scroll = if self.log.len() as u16 > outer[2].height { let scroll = if self.log.len() as u16 > outer[1].height {
self.log.len() as u16 - outer[2].height self.log.len() as u16 - outer[1].height
} else { } else {
0 0
}; };
frame.render_widget( frame.render_widget(
Paragraph::new(self.log.join("\n")).scroll((scroll, 0)), Paragraph::new(self.log.join("\n")).scroll((scroll, 0)),
outer[2], outer[1],
); );
Ok(()) Ok(())
} }
} }

84
cove-tui/src/ui/rooms.rs Normal file
View file

@ -0,0 +1,84 @@
use std::cmp;
use tui::buffer::Buffer;
use tui::layout::Rect;
use tui::style::{Modifier, Style};
use tui::widgets::{Block, Borders, StatefulWidget, Widget};
pub struct Rooms {}
impl Rooms {
pub fn new() -> Self {
Self {}
}
}
impl StatefulWidget for Rooms {
type State = RoomsState;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
state.width = cmp::min(state.width, area.width);
// let left = Rect {
// width: area.width - 1,
// ..area
// };
let right = Rect {
x: area.right() - 1,
width: 1,
..area
};
let style = if state.hovering {
Style::default().add_modifier(Modifier::REVERSED)
} else {
Style::default()
};
Block::default()
.borders(Borders::RIGHT)
.style(style)
.render(right, buf);
}
}
#[derive(Debug)]
pub struct RoomsState {
width: u16,
offset: u16,
hovering: bool,
dragging: bool,
}
impl Default for RoomsState {
fn default() -> Self {
Self {
width: 24,
offset: 0,
hovering: false,
dragging: false,
}
}
}
impl RoomsState {
pub fn width(&self) -> u16 {
self.width
}
pub fn hover(&mut self, active: bool) {
self.hovering = active;
}
pub fn drag(&mut self, active: bool) {
self.dragging = active;
}
pub fn dragging(&self) -> bool {
self.dragging
}
pub fn drag_to(&mut self, width: u16) {
if self.dragging {
self.width = width;
}
}
}