Render list of rooms
This commit is contained in:
parent
2d31d3d4e2
commit
e5910f45b4
2 changed files with 98 additions and 16 deletions
|
|
@ -1,16 +1,21 @@
|
||||||
mod rooms;
|
mod rooms;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::io::Stdout;
|
use std::io::Stdout;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crossterm::event::{Event, EventStream, KeyCode, KeyEvent, MouseEvent, MouseEventKind};
|
use crossterm::event::{Event, EventStream, KeyCode, KeyEvent, MouseEvent, MouseEventKind};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use tokio::sync::mpsc::error::TryRecvError;
|
use tokio::sync::mpsc::error::TryRecvError;
|
||||||
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
use tui::backend::CrosstermBackend;
|
use tui::backend::CrosstermBackend;
|
||||||
use tui::layout::{Constraint, Direction, Layout};
|
use tui::layout::{Constraint, Direction, Layout};
|
||||||
use tui::widgets::Paragraph;
|
use tui::widgets::Paragraph;
|
||||||
use tui::{Frame, Terminal};
|
use tui::{Frame, Terminal};
|
||||||
|
|
||||||
|
use crate::room::Room;
|
||||||
|
|
||||||
use self::rooms::{Rooms, RoomsState};
|
use self::rooms::{Rooms, RoomsState};
|
||||||
|
|
||||||
pub type Backend = CrosstermBackend<Stdout>;
|
pub type Backend = CrosstermBackend<Stdout>;
|
||||||
|
|
@ -28,6 +33,7 @@ enum EventHandleResult {
|
||||||
|
|
||||||
pub struct Ui {
|
pub struct Ui {
|
||||||
event_tx: UnboundedSender<UiEvent>,
|
event_tx: UnboundedSender<UiEvent>,
|
||||||
|
rooms: HashMap<String, Arc<Mutex<Room>>>,
|
||||||
rooms_state: RoomsState,
|
rooms_state: RoomsState,
|
||||||
log: Vec<String>,
|
log: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
@ -36,6 +42,7 @@ impl Ui {
|
||||||
fn new(event_tx: UnboundedSender<UiEvent>) -> Self {
|
fn new(event_tx: UnboundedSender<UiEvent>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
event_tx,
|
event_tx,
|
||||||
|
rooms: HashMap::new(),
|
||||||
rooms_state: RoomsState::default(),
|
rooms_state: RoomsState::default(),
|
||||||
log: vec!["Hello world!".to_string()],
|
log: vec!["Hello world!".to_string()],
|
||||||
}
|
}
|
||||||
|
|
@ -155,7 +162,8 @@ impl Ui {
|
||||||
])
|
])
|
||||||
.split(frame.size());
|
.split(frame.size());
|
||||||
|
|
||||||
frame.render_stateful_widget(Rooms::new(), outer[0], &mut self.rooms_state);
|
// frame.render_stateful_widget(Rooms::new(&self.rooms), outer[0], &mut self.rooms_state);
|
||||||
|
frame.render_stateful_widget(Rooms::dummy(), outer[0], &mut self.rooms_state);
|
||||||
|
|
||||||
let scroll = if self.log.len() as u16 > outer[1].height {
|
let scroll = if self.log.len() as u16 > outer[1].height {
|
||||||
self.log.len() as u16 - outer[1].height
|
self.log.len() as u16 - outer[1].height
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,62 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use tokio::sync::Mutex;
|
||||||
use tui::buffer::Buffer;
|
use tui::buffer::Buffer;
|
||||||
use tui::layout::Rect;
|
use tui::layout::Rect;
|
||||||
use tui::style::{Modifier, Style};
|
use tui::style::{Color, Modifier, Style};
|
||||||
use tui::widgets::{Block, Borders, StatefulWidget, Widget};
|
use tui::text::{Span, Spans};
|
||||||
|
use tui::widgets::{Block, Borders, Paragraph, StatefulWidget, Widget};
|
||||||
|
|
||||||
pub struct Rooms {}
|
use crate::room::Room;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
struct RoomInfo {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Rooms {
|
||||||
|
rooms: Vec<RoomInfo>,
|
||||||
|
selected: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Rooms {
|
impl Rooms {
|
||||||
pub fn new() -> Self {
|
pub fn new(rooms: &HashMap<String, Arc<Mutex<Room>>>) -> Self {
|
||||||
Self {}
|
let mut rooms = rooms
|
||||||
|
.iter()
|
||||||
|
.map(|(name, _room)| RoomInfo { name: name.clone() })
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
rooms.sort();
|
||||||
|
Self {
|
||||||
|
rooms,
|
||||||
|
selected: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select(mut self, name: &str) -> Self {
|
||||||
|
for (i, room) in self.rooms.iter().enumerate() {
|
||||||
|
if room.name == name {
|
||||||
|
self.selected = Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dummy() -> Self {
|
||||||
|
fn r(s: &str) -> RoomInfo {
|
||||||
|
RoomInfo {
|
||||||
|
name: s.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rooms = vec![r("xkcd"), r("test"), r("welcome"), r("music")];
|
||||||
|
rooms.sort();
|
||||||
|
Rooms {
|
||||||
|
rooms,
|
||||||
|
selected: None,
|
||||||
|
}
|
||||||
|
.select("welcome")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -17,12 +64,44 @@ impl StatefulWidget for Rooms {
|
||||||
type State = RoomsState;
|
type State = RoomsState;
|
||||||
|
|
||||||
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
||||||
|
let title_style = Style::default().add_modifier(Modifier::BOLD);
|
||||||
|
let empty_style = Style::default()
|
||||||
|
.fg(Color::Gray)
|
||||||
|
.add_modifier(Modifier::ITALIC);
|
||||||
|
let room_style = Style::default().fg(Color::LightBlue);
|
||||||
|
let selected_room_style = room_style.add_modifier(Modifier::BOLD);
|
||||||
|
|
||||||
state.width = cmp::min(state.width, area.width);
|
state.width = cmp::min(state.width, area.width);
|
||||||
|
|
||||||
// let left = Rect {
|
// Actual room names
|
||||||
// width: area.width - 1,
|
let left = Rect {
|
||||||
// ..area
|
width: area.width - 1,
|
||||||
// };
|
..area
|
||||||
|
};
|
||||||
|
let mut lines = vec![Spans::from(Span::styled("Rooms", title_style))];
|
||||||
|
if self.rooms.is_empty() {
|
||||||
|
lines.push(Spans::from(vec![
|
||||||
|
Span::raw("\r\n"),
|
||||||
|
Span::styled("none", empty_style),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
for (i, room) in self.rooms.iter().enumerate() {
|
||||||
|
let name = format!("&{}", room.name);
|
||||||
|
if Some(i) == self.selected {
|
||||||
|
lines.push(Spans::from(vec![
|
||||||
|
Span::raw("\n>"),
|
||||||
|
Span::styled(name, selected_room_style),
|
||||||
|
]));
|
||||||
|
} else {
|
||||||
|
lines.push(Spans::from(vec![
|
||||||
|
Span::raw("\n "),
|
||||||
|
Span::styled(name, room_style),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Paragraph::new(lines).render(left, buf);
|
||||||
|
|
||||||
|
// The panel's border
|
||||||
let right = Rect {
|
let right = Rect {
|
||||||
x: area.right() - 1,
|
x: area.right() - 1,
|
||||||
width: 1,
|
width: 1,
|
||||||
|
|
@ -40,10 +119,10 @@ impl StatefulWidget for Rooms {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Figure out some sort of scroll offset solution
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RoomsState {
|
pub struct RoomsState {
|
||||||
width: u16,
|
width: u16,
|
||||||
offset: u16,
|
|
||||||
hovering: bool,
|
hovering: bool,
|
||||||
dragging: bool,
|
dragging: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +131,6 @@ impl Default for RoomsState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
width: 24,
|
width: 24,
|
||||||
offset: 0,
|
|
||||||
hovering: false,
|
hovering: false,
|
||||||
dragging: false,
|
dragging: false,
|
||||||
}
|
}
|
||||||
|
|
@ -72,10 +150,6 @@ impl RoomsState {
|
||||||
self.dragging = active;
|
self.dragging = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dragging(&self) -> bool {
|
|
||||||
self.dragging
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn drag_to(&mut self, width: u16) {
|
pub fn drag_to(&mut self, width: u16) {
|
||||||
if self.dragging {
|
if self.dragging {
|
||||||
self.width = width;
|
self.width = width;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue