added selectable instance to tui
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
mod app;
|
||||
mod mod_list;
|
||||
mod status;
|
||||
mod instance;
|
||||
|
||||
pub use app::run;
|
||||
|
||||
@@ -3,12 +3,15 @@ use std::io;
|
||||
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
|
||||
use ratatui::{
|
||||
DefaultTerminal, Frame,
|
||||
layout::Rect,
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
style::Style,
|
||||
widgets::{Block, Borders, StatefulWidget, TableState, Widget},
|
||||
};
|
||||
|
||||
use crate::{tui::mod_list::ModList, types::RootConfig};
|
||||
use crate::{
|
||||
tui::{instance::InstanceSelect, mod_list::ModList, status::StatusBar},
|
||||
types::RootConfig,
|
||||
};
|
||||
|
||||
pub fn run(root_config: &mut RootConfig) -> anyhow::Result<()> {
|
||||
ratatui::run(|terminal| App::new(root_config).run(terminal))?;
|
||||
@@ -21,6 +24,7 @@ struct App<'a> {
|
||||
exit: bool,
|
||||
|
||||
mod_list_state: TableState,
|
||||
selected_instance: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a> App<'a> {
|
||||
@@ -31,6 +35,7 @@ impl<'a> App<'a> {
|
||||
Self {
|
||||
root_config,
|
||||
mod_list_state: state,
|
||||
selected_instance: None,
|
||||
exit: false,
|
||||
}
|
||||
}
|
||||
@@ -67,6 +72,12 @@ impl<'a> App<'a> {
|
||||
KeyCode::Down | KeyCode::Char('j') => {
|
||||
self.mod_list_state.select_next();
|
||||
}
|
||||
KeyCode::Right | KeyCode::Char('l') => {
|
||||
self.next_instance();
|
||||
}
|
||||
KeyCode::Left | KeyCode::Char('h') => {
|
||||
self.prev_instance();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +85,58 @@ impl<'a> App<'a> {
|
||||
fn exit(&mut self) {
|
||||
self.exit = true;
|
||||
}
|
||||
|
||||
fn next_instance(&mut self) {
|
||||
let mut instances = self.root_config.instances();
|
||||
instances.sort();
|
||||
|
||||
if instances.is_empty() {
|
||||
self.selected_instance = None;
|
||||
return;
|
||||
}
|
||||
|
||||
let next = match &self.selected_instance {
|
||||
None => instances.first().cloned(),
|
||||
Some(curr) => {
|
||||
let idx = instances.iter().position(|x| x == curr);
|
||||
match idx {
|
||||
Some(i) => {
|
||||
let next_index = (i + 1) % instances.len();
|
||||
instances.get(next_index).cloned()
|
||||
}
|
||||
None => instances.first().cloned(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.selected_instance = next;
|
||||
}
|
||||
|
||||
fn prev_instance(&mut self) {
|
||||
let mut instances = self.root_config.instances();
|
||||
instances.sort();
|
||||
|
||||
if instances.is_empty() {
|
||||
self.selected_instance = None;
|
||||
return;
|
||||
}
|
||||
|
||||
let prev = match &self.selected_instance {
|
||||
None => instances.last().cloned(),
|
||||
Some(curr) => {
|
||||
let idx = instances.iter().position(|x| x == curr);
|
||||
match idx {
|
||||
Some(i) => {
|
||||
let prev_index = if i == 0 { instances.len() - 1 } else { i - 1 };
|
||||
instances.get(prev_index).cloned()
|
||||
}
|
||||
None => Some(instances[instances.len() - 1].clone()),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.selected_instance = prev;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for &mut App<'a> {
|
||||
@@ -81,15 +144,28 @@ impl<'a> Widget for &mut App<'a> {
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Length(3),
|
||||
Constraint::Min(1),
|
||||
Constraint::Length(1), // single line for keybindings
|
||||
])
|
||||
.split(area);
|
||||
|
||||
InstanceSelect::new(self.selected_instance.clone()).render(chunks[0], buf);
|
||||
|
||||
let list_block = Block::default()
|
||||
.title("Mod list")
|
||||
.borders(Borders::ALL)
|
||||
.style(Style::default());
|
||||
|
||||
ModList::new(self.root_config).block(list_block).render(
|
||||
area,
|
||||
chunks[1],
|
||||
buf,
|
||||
&mut self.mod_list_state,
|
||||
);
|
||||
|
||||
StatusBar.render(chunks[2], buf);
|
||||
}
|
||||
}
|
||||
|
||||
30
src/tui/instance.rs
Normal file
30
src/tui/instance.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
use ratatui::{
|
||||
style::Style,
|
||||
widgets::{Block, Borders, Paragraph, Widget},
|
||||
};
|
||||
|
||||
pub struct InstanceSelect {
|
||||
selected: Option<String>,
|
||||
}
|
||||
|
||||
impl InstanceSelect {
|
||||
pub fn new(selected: Option<String>) -> Self {
|
||||
Self { selected }
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for InstanceSelect {
|
||||
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let list_block = Block::default()
|
||||
.title("Instance")
|
||||
.borders(Borders::ALL)
|
||||
.style(Style::default());
|
||||
|
||||
Paragraph::new(self.selected.unwrap_or("None".to_owned()))
|
||||
.block(list_block)
|
||||
.render(area, buf);
|
||||
}
|
||||
}
|
||||
12
src/tui/status.rs
Normal file
12
src/tui/status.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
use ratatui::{text::Line, widgets::Widget};
|
||||
|
||||
pub struct StatusBar;
|
||||
|
||||
impl Widget for StatusBar {
|
||||
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer)
|
||||
where
|
||||
Self: Sized {
|
||||
|
||||
Line::from("Up Down Left right").render(area, buf);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user