1use std::{error::Error, fmt::Write, time::{SystemTime, UNIX_EPOCH}};
2
3use ratatui::{style::Stylize, widgets::{Block, Paragraph, Widget}};
4
5pub struct FPS {
8 prev_time: u128,
9 fps_text: String
10}
11
12impl FPS {
13 pub fn new() -> Result<Self, Box<dyn Error>>{
15 Ok(Self{
16 prev_time: FPS::now_millis()?,
17 fps_text: String::with_capacity(1024)
18 })
19 }
20
21 pub fn wait_for_fps(&self, expected_fps: u128) -> Result<u64, Box<dyn Error>> {
25 let now = Self::now_millis()?;
26 let dif = now - self.prev_time;
27 if expected_fps>0 && dif > 1000/expected_fps {
28 Ok(0)
29 }else{
30 Ok(1000/expected_fps as u64)
31 }
32 }
33
34 fn now_millis ()-> Result<u128, Box<dyn Error>> {
35 let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
36 Ok(now.as_millis())
37 }
38
39 fn set_fps(&mut self) -> Result<(), Box<dyn Error>> {
40 let now = FPS::now_millis()?;
41 let time_passed = now - self.prev_time;
42 self.prev_time = now;
43 let mut fps = 1;
44 if time_passed >0 {
45 fps = 1000/time_passed;
46 }
47 self.fps_text.clear();
48 write!(&mut self.fps_text, "{} FPS", fps)?;
49 Ok(())
50 }
51}
52
53impl Widget for &mut FPS {
55 fn render(self,
56 area: ratatui::prelude::Rect,
57 buf: &mut ratatui::prelude::Buffer) where Self: Sized {
58 self.set_fps().unwrap();
59 let text = Paragraph::new(self.fps_text.as_str()).bold()
60 .green();
61
62 let mut new_area = area.clone();
63 if area.height >= 3 {
64 let len_of_str = self.fps_text.len()+2;
65 if (len_of_str as u16) < area.width {
66 new_area.width = len_of_str as u16
67 }
68 new_area.height = 3;
69 text.block(Block::bordered()).render(new_area,buf);
70 return;
71 }
72
73 new_area.width = self.fps_text.len() as u16;
74 text.render(area,buf);
75 }
76}