Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-tdrn committed Feb 11, 2024
1 parent c7b437d commit 4cdf8c8
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 2 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ name = "ttl"
path = "src/main.rs"

[dependencies]
crossterm = "0.27.0"
ratatui = { version = "0.26.0", features = ["all-widgets"] }
5 changes: 5 additions & 0 deletions src/action.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub enum Action {
CharacterInput(char),
Restart,
Quit,
}
31 changes: 29 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
fn main() {
println!("Hello, world!");
pub mod action;
pub mod model;
pub mod terminal;
pub mod view;

use model::Model;

use terminal::*;

fn main() -> std::io::Result<()> {
let mut model = Model::default();

let mut terminal = create_terminal()?;

while !model.should_quit {
model.frame_statistics.new_frame();

terminal.draw(|frame| {
model.view(frame);
})?;

if let Some(action) = poll_terminal() {
model.update(action);
}
}

destroy_terminal()?;

Ok(())
}
55 changes: 55 additions & 0 deletions src/model.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use crate::action::Action;

#[derive(Default)]
pub struct Model {
pub frame_statistics: FrameStatistics,
pub config: Config,
pub should_quit: bool,
}

impl Model {
pub fn update(&mut self, action: Action) {
match action {
Action::Quit => self.should_quit = true,
_ => (),
}
}
}

pub struct Config {
pub show_frame_statistics: bool,
}

impl Default for Config {
fn default() -> Self {
Config {
show_frame_statistics: true,
}
}
}

pub struct FrameStatistics {
pub frame_begin: std::time::Instant,
pub last_frame_duration: std::time::Duration,
pub average_frame_duration: std::time::Duration,
}

impl FrameStatistics {
pub fn new_frame(&mut self) {
let new_frame_begin = std::time::Instant::now();
self.last_frame_duration = new_frame_begin - self.frame_begin;
self.frame_begin = new_frame_begin;
self.average_frame_duration =
self.average_frame_duration.mul_f64(0.8) + self.last_frame_duration.mul_f64(0.2);
}
}

impl Default for FrameStatistics {
fn default() -> Self {
FrameStatistics {
frame_begin: std::time::Instant::now(),
last_frame_duration: std::time::Duration::default(),
average_frame_duration: std::time::Duration::default(),
}
}
}
53 changes: 53 additions & 0 deletions src/terminal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use crossterm::{
event::{self, Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers},
ExecutableCommand,
};

use crate::action::Action;

pub fn create_terminal(
) -> std::io::Result<ratatui::prelude::Terminal<ratatui::prelude::CrosstermBackend<std::io::Stdout>>>
{
std::io::stdout().execute(crossterm::terminal::EnterAlternateScreen)?;
crossterm::terminal::enable_raw_mode()?;

let mut terminal = ratatui::prelude::Terminal::new(ratatui::prelude::CrosstermBackend::new(
std::io::stdout(),
))?;

terminal.clear()?;

Ok(terminal)
}

pub fn poll_terminal() -> Option<Action> {
if let Ok(true) = event::poll(std::time::Duration::from_millis(10)) {
} else {
return None;
}

let Ok(Event::Key(KeyEvent {
code,
modifiers,
kind: KeyEventKind::Press,
state: _,
})) = event::read()
else {
return None;
};

match (modifiers, code) {
(KeyModifiers::NONE, KeyCode::Esc)
| (KeyModifiers::CONTROL, KeyCode::Char('c'))
| (KeyModifiers::CONTROL, KeyCode::Char('q')) => Some(Action::Quit),
(KeyModifiers::NONE, KeyCode::Char(c)) => Some(Action::CharacterInput(c)),
_ => None,
}
}

pub fn destroy_terminal() -> std::io::Result<()> {
std::io::stdout().execute(crossterm::terminal::LeaveAlternateScreen)?;
crossterm::terminal::disable_raw_mode()?;

Ok(())
}
21 changes: 21 additions & 0 deletions src/view.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use crate::model::Model;

use ratatui::{prelude::*, style::*, widgets::*};

impl Model {
pub fn view(&self, frame: &mut ratatui::Frame) {
let average_frametime = self.frame_statistics.average_frame_duration.as_millis();
let average_fps = 1_000 / std::cmp::max(average_frametime, 1);

frame.render_widget(
Block::default()
.title(format!(
"Frametime {}ms ({}FPS)",
average_frametime, average_fps
))
.title_alignment(Alignment::Right)
.borders(Borders::ALL),
frame.size(),
);
}
}
2 changes: 2 additions & 0 deletions typos.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[default.extend-words]
"ratatui" = "ratatui"

0 comments on commit 4cdf8c8

Please sign in to comment.