Added a main menu
This commit is contained in:
parent
908fe2f166
commit
ca9b0a7e0b
6 changed files with 210 additions and 52 deletions
|
@ -1,6 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use color_eyre::{eyre::Ok, Result};
|
||||
use color_eyre::{Result, eyre::Ok};
|
||||
use rand::seq::SliceRandom;
|
||||
use ratatui::{
|
||||
DefaultTerminal, Frame,
|
||||
|
@ -10,37 +10,53 @@ use ratatui::{
|
|||
text::Line,
|
||||
widgets::{Bar, BarChart, BarGroup, Block},
|
||||
};
|
||||
use tokio::{sync::mpsc::{UnboundedReceiver, UnboundedSender}, time::sleep};
|
||||
use tokio::{
|
||||
sync::mpsc::{UnboundedReceiver, UnboundedSender},
|
||||
time::sleep,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
algorithm::{self},
|
||||
tui::Message,
|
||||
};
|
||||
|
||||
pub enum SortingMessage{
|
||||
Tick
|
||||
pub enum SortingMessage {
|
||||
Tick,
|
||||
Finished,
|
||||
Start,
|
||||
}
|
||||
|
||||
pub struct DrawableVec {
|
||||
vec: Vec<u32>,
|
||||
event_rx: UnboundedReceiver<SortingMessage>,
|
||||
event_tx: UnboundedSender<Message>,
|
||||
algo: String
|
||||
algo: String,
|
||||
}
|
||||
|
||||
impl DrawableVec {
|
||||
pub fn new(event_tx: UnboundedSender<Message>, event_rx: UnboundedReceiver<SortingMessage>, vec: Vec<u32>) -> DrawableVec {
|
||||
pub fn new(
|
||||
event_tx: UnboundedSender<Message>,
|
||||
event_rx: UnboundedReceiver<SortingMessage>,
|
||||
vec: Vec<u32>,
|
||||
) -> DrawableVec {
|
||||
return DrawableVec {
|
||||
vec,
|
||||
event_rx,
|
||||
event_tx: event_tx.clone(),
|
||||
algo: "radixSortMSD".to_string(),
|
||||
algo: "insertSort".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn run(mut self) -> Result<()> {
|
||||
loop {
|
||||
let event = self.event_rx.recv().await;
|
||||
match event {
|
||||
Some(SortingMessage::Start) => break,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
algorithm::sort(self.algo.clone(), &mut self).await?;
|
||||
sleep(Duration::from_secs(100000)).await;
|
||||
self.event_tx.send(Message::SimulationFinished)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -52,17 +68,27 @@ impl DrawableVec {
|
|||
self.vec.swap(a, b);
|
||||
self.event_tx.send(Message::SwapEvent(a, b))?;
|
||||
|
||||
self.event_rx.recv().await;
|
||||
self.wait_for_next_tick().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set(&mut self, i:usize, elem:u32) -> Result<()>{
|
||||
pub async fn set(&mut self, i: usize, elem: u32) -> Result<()> {
|
||||
self.vec[i] = elem;
|
||||
self.event_tx.send(Message::SetEvent(i, elem))?;
|
||||
|
||||
self.event_rx.recv().await;
|
||||
self.wait_for_next_tick().await;
|
||||
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
async fn wait_for_next_tick(&mut self) {
|
||||
loop {
|
||||
match self.event_rx.recv().await {
|
||||
Some(SortingMessage::Tick) => break,
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lessThan(&self, a: usize, b: usize) -> bool {
|
||||
|
@ -73,30 +99,30 @@ impl DrawableVec {
|
|||
self.vec.iter()
|
||||
}
|
||||
|
||||
pub fn get(&mut self, i:usize)-> u32{
|
||||
pub fn get(&mut self, i: usize) -> u32 {
|
||||
*self.vec.get(i).unwrap()
|
||||
}
|
||||
|
||||
pub fn randomize(&mut self){
|
||||
pub fn randomize(&mut self) {
|
||||
self.vec.shuffle(&mut rand::rng());
|
||||
}
|
||||
pub fn isSorted(&mut self) -> bool{
|
||||
let mut prev:u32 = 0;
|
||||
pub fn isSorted(&mut self) -> bool {
|
||||
let mut prev: u32 = 0;
|
||||
for bar in self.elements() {
|
||||
if *bar < prev{
|
||||
if *bar < prev {
|
||||
return false;
|
||||
}else{
|
||||
} else {
|
||||
prev = *bar;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn lessThanEqual(&mut self, a:usize, b:u32) -> bool{
|
||||
return self.get(a) <= b
|
||||
pub fn lessThanEqual(&mut self, a: usize, b: u32) -> bool {
|
||||
return self.get(a) <= b;
|
||||
}
|
||||
|
||||
pub fn getListClone(&self) -> Vec<u32>{
|
||||
pub fn getListClone(&self) -> Vec<u32> {
|
||||
self.vec.clone()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ mod drawableVec;
|
|||
mod fps_counter;
|
||||
mod algorithm;
|
||||
mod tui;
|
||||
|
||||
mod pages;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
|
|
35
src/pages/main.rs
Normal file
35
src/pages/main.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use crate::tui::State;
|
||||
|
||||
use color_eyre::eyre::Ok;
|
||||
use ratatui::{Frame, Terminal};
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use ratatui::prelude::CrosstermBackend;
|
||||
use ratatui::widgets::{Block, Paragraph, Widget};
|
||||
|
||||
use color_eyre::Result;
|
||||
|
||||
pub struct MainView {}
|
||||
|
||||
impl MainView {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
pub fn render(&self,frame:&mut Frame<'_>, state: & State, area: &Rect, fps: u64) -> Result<()> {
|
||||
let [layout] = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([
|
||||
Constraint::Fill(1)
|
||||
])
|
||||
.areas(*area);
|
||||
|
||||
let widget = Paragraph::new("HELLO")
|
||||
.block(Block::bordered().title(format!(" Esc to Quit. FPS: {} ", fps)));
|
||||
|
||||
frame.render_widget(widget, layout);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
17
src/pages/mod.rs
Normal file
17
src/pages/mod.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use main::MainView;
|
||||
use ratatui::{layout::Rect, prelude::CrosstermBackend, widgets::Widget, Terminal};
|
||||
|
||||
use color_eyre::Result;
|
||||
use sorting::SortingView;
|
||||
|
||||
use crate::tui::State;
|
||||
|
||||
pub(crate) mod main;
|
||||
pub (crate) mod sorting;
|
||||
|
||||
|
||||
pub enum Pages {
|
||||
Main(MainView),
|
||||
SortingView(SortingView)
|
||||
}
|
||||
|
31
src/pages/sorting.rs
Normal file
31
src/pages/sorting.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use crate::graphics::vertical_barchart;
|
||||
use crate::tui::State;
|
||||
|
||||
use color_eyre::eyre::Ok;
|
||||
use ratatui::{Frame, Terminal};
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use ratatui::prelude::CrosstermBackend;
|
||||
use ratatui::widgets::{Block, Widget};
|
||||
|
||||
use color_eyre::Result;
|
||||
|
||||
pub struct SortingView {}
|
||||
|
||||
impl SortingView {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
pub fn render(&self, frame: &mut Frame<'_>, state: &State , area: &Rect, fps: u64) -> Result<()> {
|
||||
let [layout] = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([
|
||||
Constraint::Fill(1)
|
||||
])
|
||||
.areas(*area);
|
||||
let widget = vertical_barchart(&state.vec, area.width)
|
||||
.block(Block::bordered().title(format!(" Esc to Quit. FPS: {} ", fps)));
|
||||
|
||||
frame.render_widget(widget, layout);
|
||||
Ok(())
|
||||
}
|
||||
}
|
109
src/tui.rs
109
src/tui.rs
|
@ -1,10 +1,21 @@
|
|||
use std::{fmt::format, time::Duration};
|
||||
|
||||
use crate::pages::Pages;
|
||||
use crate::pages::{main::MainView, sorting::SortingView};
|
||||
use crate::{
|
||||
drawableVec::{self, DrawableVec, SortingMessage},
|
||||
fps_counter::FpsCounter,
|
||||
graphics::vertical_barchart,
|
||||
};
|
||||
use color_eyre::{Result, eyre::Ok};
|
||||
use crossterm::event::{Event, KeyCode, KeyEventKind, MouseEventKind};
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::{rand_core::impls, seq::SliceRandom};
|
||||
use ratatui::{
|
||||
layout::{Constraint, Layout, Margin}, prelude::CrosstermBackend, style::Stylize, widgets::Block, Terminal
|
||||
Terminal,
|
||||
layout::{Constraint, Layout, Margin},
|
||||
prelude::CrosstermBackend,
|
||||
style::Stylize,
|
||||
widgets::Block,
|
||||
};
|
||||
use tokio::{
|
||||
sync::mpsc::{self, UnboundedReceiver, UnboundedSender},
|
||||
|
@ -18,6 +29,12 @@ pub enum Message {
|
|||
StartSimulation,
|
||||
SwapEvent(usize, usize),
|
||||
SetEvent(usize, u32),
|
||||
SwapGui,
|
||||
SimulationFinished
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
pub vec: Vec<u32>,
|
||||
}
|
||||
|
||||
pub struct Tui {
|
||||
|
@ -26,16 +43,12 @@ pub struct Tui {
|
|||
frame_rate: f64,
|
||||
event_rx: UnboundedReceiver<Message>,
|
||||
event_tx: UnboundedSender<Message>,
|
||||
sorting_tx: UnboundedSender<SortingMessage>,
|
||||
sorting_tx: Option<UnboundedSender<SortingMessage>>,
|
||||
should_exit: bool,
|
||||
vec: Vec<u32>,
|
||||
fps_counter: FpsCounter,
|
||||
state: State,
|
||||
page: Pages,
|
||||
}
|
||||
use crate::{
|
||||
drawableVec::{self, DrawableVec, SortingMessage},
|
||||
fps_counter::FpsCounter,
|
||||
graphics::vertical_barchart,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum UpdateCommand {
|
||||
|
@ -48,12 +61,10 @@ impl Tui {
|
|||
let terminal = ratatui::init();
|
||||
let (event_tx, event_rx): (UnboundedSender<Message>, UnboundedReceiver<Message>) =
|
||||
mpsc::unbounded_channel();
|
||||
let (sorting_tx, sorting_rx) = mpsc::unbounded_channel();
|
||||
let mut vec = (Vec::from_iter(1..50));
|
||||
vec.shuffle(&mut rand::rng());
|
||||
let drawableVec = DrawableVec::new(event_tx.clone(), sorting_rx, vec.clone());
|
||||
|
||||
let sorter = tokio::spawn(drawableVec.run());
|
||||
let page = MainView::new();
|
||||
|
||||
Ok(Self {
|
||||
terminal,
|
||||
|
@ -61,10 +72,11 @@ impl Tui {
|
|||
frame_rate: 60.,
|
||||
event_rx,
|
||||
event_tx,
|
||||
sorting_tx,
|
||||
sorting_tx: None,
|
||||
should_exit: false,
|
||||
vec: vec,
|
||||
fps_counter: FpsCounter::new(),
|
||||
page: Pages::Main(page),
|
||||
state: State { vec },
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -77,7 +89,10 @@ impl Tui {
|
|||
tokio::select! {
|
||||
_tick = tick_interval.tick() => {
|
||||
self.event_tx.send(Message::Tick)?;
|
||||
self.sorting_tx.send(SortingMessage::Tick)?
|
||||
match &self.sorting_tx {
|
||||
Some(tx) => tx.send(SortingMessage::Tick)?,
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
_frame = frame_interval.tick() => {
|
||||
self.event_tx.send(Message::Render)?
|
||||
|
@ -114,13 +129,40 @@ impl Tui {
|
|||
self.fps_counter.tick();
|
||||
Ok(UpdateCommand::None)
|
||||
}
|
||||
Message::StartSimulation => todo!(),
|
||||
Message::StartSimulation => {
|
||||
match &self.sorting_tx {
|
||||
Some(tx) => tx.send(SortingMessage::Start)?,
|
||||
None => (),
|
||||
}
|
||||
Ok(UpdateCommand::None)
|
||||
}
|
||||
Message::SwapEvent(a, b) => {
|
||||
self.vec.swap(a, b);
|
||||
self.state.vec.swap(a, b);
|
||||
Ok(UpdateCommand::None)
|
||||
}
|
||||
Message::SetEvent(i, e) => {
|
||||
self.vec.insert(i, e);
|
||||
self.state.vec.insert(i, e);
|
||||
Ok(UpdateCommand::None)
|
||||
}
|
||||
Message::SwapGui => {
|
||||
self.page = match self.page {
|
||||
Pages::Main(_) => {
|
||||
let (sorting_tx, sorting_rx) = mpsc::unbounded_channel();
|
||||
self.sorting_tx = Some(sorting_tx);
|
||||
let drawable_vec = DrawableVec::new(
|
||||
self.event_tx.clone(),
|
||||
sorting_rx,
|
||||
self.state.vec.clone(),
|
||||
);
|
||||
tokio::spawn(drawable_vec.run());
|
||||
Pages::SortingView(SortingView::new())
|
||||
}
|
||||
Pages::SortingView(_) => Pages::Main(MainView::new()),
|
||||
};
|
||||
Ok(UpdateCommand::None)
|
||||
}
|
||||
Message::SimulationFinished => {
|
||||
self.sorting_tx = None;
|
||||
Ok(UpdateCommand::None)
|
||||
}
|
||||
}
|
||||
|
@ -128,18 +170,20 @@ impl Tui {
|
|||
|
||||
fn view(&mut self) -> Result<()> {
|
||||
self.terminal.draw(|frame| {
|
||||
let [title, vertical] =
|
||||
Layout::vertical([Constraint::Length(1), Constraint::Fill(1)])
|
||||
.spacing(1)
|
||||
.areas(frame.area());
|
||||
let [title, vertical] = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)])
|
||||
.spacing(1)
|
||||
.areas(frame.area());
|
||||
frame.render_widget("Sorting!".bold().into_centered_line(), title);
|
||||
frame.render_widget(
|
||||
vertical_barchart(&self.vec, vertical.inner(Margin::new(10, 0)).width).block(
|
||||
Block::bordered()
|
||||
.title(format!(" Esc to Quit. FPS: {} ", self.fps_counter.fps)),
|
||||
),
|
||||
vertical,
|
||||
);
|
||||
|
||||
match &self.page {
|
||||
Pages::Main(main_view) => {
|
||||
let _ = main_view.render(frame, &self.state, &vertical, self.fps_counter.fps);
|
||||
}
|
||||
Pages::SortingView(sorting_view) => {
|
||||
let _ =
|
||||
sorting_view.render(frame, &self.state, &vertical, self.fps_counter.fps);
|
||||
}
|
||||
};
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
|
@ -151,7 +195,12 @@ impl Tui {
|
|||
if key.kind == KeyEventKind::Press && key.code == KeyCode::Esc {
|
||||
self.event_tx.send(Message::Quit)?;
|
||||
} else if key.kind == KeyEventKind::Press && key.code == KeyCode::Enter {
|
||||
self.event_tx.send(Message::StartSimulation)?;
|
||||
match &self.sorting_tx {
|
||||
Some(tx) => tx.send(SortingMessage::Start)?,
|
||||
None => (),
|
||||
};
|
||||
} else if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('a') {
|
||||
self.event_tx.send(Message::SwapGui)?;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
Loading…
Reference in a new issue