diff --git a/src/drawableVec.rs b/src/drawableVec.rs index 14ec054..32e0b50 100644 --- a/src/drawableVec.rs +++ b/src/drawableVec.rs @@ -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, event_rx: UnboundedReceiver, event_tx: UnboundedSender, - algo: String + algo: String, } impl DrawableVec { - pub fn new(event_tx: UnboundedSender, event_rx: UnboundedReceiver, vec: Vec) -> DrawableVec { + pub fn new( + event_tx: UnboundedSender, + event_rx: UnboundedReceiver, + vec: Vec, + ) -> 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{ + pub fn getListClone(&self) -> Vec { self.vec.clone() } } diff --git a/src/main.rs b/src/main.rs index 2b13745..0d56edc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ mod drawableVec; mod fps_counter; mod algorithm; mod tui; - +mod pages; #[tokio::main] async fn main() -> Result<()> { diff --git a/src/pages/main.rs b/src/pages/main.rs new file mode 100644 index 0000000..a78d619 --- /dev/null +++ b/src/pages/main.rs @@ -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(()) + } +} + + + diff --git a/src/pages/mod.rs b/src/pages/mod.rs new file mode 100644 index 0000000..77e58e3 --- /dev/null +++ b/src/pages/mod.rs @@ -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) +} + diff --git a/src/pages/sorting.rs b/src/pages/sorting.rs new file mode 100644 index 0000000..ee0334a --- /dev/null +++ b/src/pages/sorting.rs @@ -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(()) + } +} diff --git a/src/tui.rs b/src/tui.rs index 947dce9..4c1c187 100644 --- a/src/tui.rs +++ b/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, } pub struct Tui { @@ -26,16 +43,12 @@ pub struct Tui { frame_rate: f64, event_rx: UnboundedReceiver, event_tx: UnboundedSender, - sorting_tx: UnboundedSender, + sorting_tx: Option>, should_exit: bool, - vec: Vec, 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, UnboundedReceiver) = 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)?; } } _ => {}