FPS counter added

This commit is contained in:
filipriec
2025-04-15 18:11:26 +02:00
parent d8c2b9089b
commit 09068fd4e5
5 changed files with 63 additions and 48 deletions

17
Cargo.lock generated
View File

@@ -432,6 +432,7 @@ dependencies = [
"prost", "prost",
"ratatui", "ratatui",
"serde", "serde",
"time",
"tokio", "tokio",
"toml", "toml",
"tonic", "tonic",
@@ -713,9 +714,9 @@ dependencies = [
[[package]] [[package]]
name = "deranged" name = "deranged"
version = "0.3.11" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
dependencies = [ dependencies = [
"powerfmt", "powerfmt",
] ]
@@ -3212,9 +3213,9 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.39" version = "0.3.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8" checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
dependencies = [ dependencies = [
"deranged", "deranged",
"itoa", "itoa",
@@ -3229,15 +3230,15 @@ dependencies = [
[[package]] [[package]]
name = "time-core" name = "time-core"
version = "0.1.3" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.20" version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
dependencies = [ dependencies = [
"num-conv", "num-conv",
"time-core", "time-core",

View File

@@ -15,6 +15,7 @@ lazy_static = "1.5.0"
prost = "0.13.5" prost = "0.13.5"
ratatui = "0.29.0" ratatui = "0.29.0"
serde = { version = "1.0.218", features = ["derive"] } serde = { version = "1.0.218", features = ["derive"] }
time = "0.3.41"
tokio = { version = "1.43.0", features = ["full", "macros"] } tokio = { version = "1.43.0", features = ["full", "macros"] }
toml = "0.8.20" toml = "0.8.20"
tonic = "0.12.3" tonic = "0.12.3"

View File

@@ -1,11 +1,11 @@
// src/client/components/handlers/status_line.rs
use ratatui::{ use ratatui::{
widgets::Paragraph,
style::Style, style::Style,
layout::Rect, layout::Rect,
Frame, Frame,
text::{Line, Span}, text::{Line, Span},
widgets::Paragraph,
}; };
use unicode_width::UnicodeWidthStr;
use crate::config::colors::themes::Theme; use crate::config::colors::themes::Theme;
use std::path::Path; use std::path::Path;
@@ -15,17 +15,11 @@ pub fn render_status_line(
current_dir: &str, current_dir: &str,
theme: &Theme, theme: &Theme,
is_edit_mode: bool, is_edit_mode: bool,
current_fps: f64,
) { ) {
// Program name and version
let program_info = format!("multieko2 v{}", env!("CARGO_PKG_VERSION")); let program_info = format!("multieko2 v{}", env!("CARGO_PKG_VERSION"));
let mode_text = if is_edit_mode { "[EDIT]" } else { "[READ-ONLY]" };
let mode_text = if is_edit_mode {
"[EDIT]"
} else {
"[READ-ONLY]"
};
// Shorten the current directory path
let home_dir = dirs::home_dir().map(|p| p.to_string_lossy().into_owned()).unwrap_or_default(); let home_dir = dirs::home_dir().map(|p| p.to_string_lossy().into_owned()).unwrap_or_default();
let display_dir = if current_dir.starts_with(&home_dir) { let display_dir = if current_dir.starts_with(&home_dir) {
current_dir.replacen(&home_dir, "~", 1) current_dir.replacen(&home_dir, "~", 1)
@@ -33,47 +27,51 @@ pub fn render_status_line(
current_dir.to_string() current_dir.to_string()
}; };
// Create the full status line text
let full_text = format!("{} | {} | {}", mode_text, display_dir, program_info);
// Check if the full text fits in the available width
let available_width = area.width as usize; let available_width = area.width as usize;
let mut display_text = if full_text.len() <= available_width { let mode_width = UnicodeWidthStr::width(mode_text);
// If it fits, use the full text let program_info_width = UnicodeWidthStr::width(program_info.as_str());
full_text let fps_text = format!("{:.0} FPS", current_fps);
let fps_width = UnicodeWidthStr::width(fps_text.as_str());
let separator = " | ";
let separator_width = UnicodeWidthStr::width(separator);
let fixed_width_with_fps = mode_width + separator_width + separator_width +
program_info_width + separator_width + fps_width;
let show_fps = fixed_width_with_fps < available_width;
let remaining_width_for_dir = available_width.saturating_sub(
mode_width + separator_width + separator_width + program_info_width +
if show_fps { separator_width + fps_width } else { 0 }
);
let dir_display_text = if UnicodeWidthStr::width(display_dir.as_str()) <= remaining_width_for_dir {
display_dir
} else { } else {
// If it doesn't fit, prioritize mode and program info, and show only the directory name
let dir_name = Path::new(current_dir) let dir_name = Path::new(current_dir)
.file_name() .file_name()
.and_then(|n| n.to_str()) .and_then(|n| n.to_str())
.unwrap_or(current_dir); .unwrap_or(current_dir);
format!("{} | {} | {}", mode_text, dir_name, program_info) if UnicodeWidthStr::width(dir_name) <= remaining_width_for_dir {
dir_name.to_string()
} else {
dir_name.chars().take(remaining_width_for_dir).collect()
}
}; };
// If even the shortened version overflows, truncate it let mut spans = vec![
if display_text.len() > available_width {
display_text = display_text.chars().take(available_width).collect();
}
// Create the status line text using Line and Span
let status_line = Line::from(vec![
Span::styled(mode_text, Style::default().fg(theme.accent)), Span::styled(mode_text, Style::default().fg(theme.accent)),
Span::styled(" | ", Style::default().fg(theme.border)), Span::styled(" | ", Style::default().fg(theme.border)),
Span::styled( Span::styled(dir_display_text, Style::default().fg(theme.fg)),
display_text.split(" | ").nth(1).unwrap_or(""), // Directory part
Style::default().fg(theme.fg),
),
Span::styled(" | ", Style::default().fg(theme.border)), Span::styled(" | ", Style::default().fg(theme.border)),
Span::styled( Span::styled(program_info, Style::default().fg(theme.secondary)),
program_info, ];
Style::default()
.fg(theme.secondary)
.add_modifier(ratatui::style::Modifier::BOLD),
),
]);
// Render the status line if show_fps {
let paragraph = Paragraph::new(status_line) spans.push(Span::styled(" | ", Style::default().fg(theme.border)));
spans.push(Span::styled(fps_text, Style::default().fg(theme.secondary)));
}
let paragraph = Paragraph::new(Line::from(spans))
.style(Style::default().bg(theme.bg)); .style(Style::default().bg(theme.bg));
f.render_widget(paragraph, area); f.render_widget(paragraph, area);

View File

@@ -39,6 +39,7 @@ pub fn render_ui(
command_input: &str, command_input: &str,
command_mode: bool, command_mode: bool,
command_message: &str, command_message: &str,
current_fps: f64,
app_state: &AppState, app_state: &AppState,
) { ) {
render_background(f, f.area(), theme); render_background(f, f.area(), theme);
@@ -175,6 +176,6 @@ pub fn render_ui(
render_buffer_list(f, area, theme, buffer_state); render_buffer_list(f, area, theme, buffer_state);
} }
} }
render_status_line(f, status_line_area, current_dir, theme, is_edit_mode); render_status_line(f, status_line_area, current_dir, theme, is_edit_mode, current_fps);
render_command_line(f, command_line_area, command_input, command_mode, theme, command_message); render_command_line(f, command_line_area, command_input, command_mode, theme, command_message);
} }

View File

@@ -20,6 +20,7 @@ use crate::state::app::state::AppState;
// Import SaveOutcome // Import SaveOutcome
use crate::tui::terminal::{EventReader, TerminalCore}; use crate::tui::terminal::{EventReader, TerminalCore};
use crate::ui::handlers::render::render_ui; use crate::ui::handlers::render::render_ui;
use std::time::Instant;
use crossterm::cursor::SetCursorStyle; use crossterm::cursor::SetCursorStyle;
pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> { pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
@@ -51,6 +52,10 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
.await?; .await?;
form_state.reset_to_empty(); form_state.reset_to_empty();
// --- FPS Calculation State ---
let mut last_frame_time = Instant::now();
let mut current_fps = 0.0;
loop { loop {
// Determine edit mode based on EventHandler state // Determine edit mode based on EventHandler state
let is_edit_mode = event_handler.is_edit_mode; let is_edit_mode = event_handler.is_edit_mode;
@@ -92,6 +97,7 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
&event_handler.command_input, &event_handler.command_input,
event_handler.command_mode, event_handler.command_mode,
&event_handler.command_message, &event_handler.command_message,
current_fps,
&app_state, &app_state,
); );
})?; })?;
@@ -302,6 +308,14 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
// terminal.cleanup()?; // Optional: Drop handles this // terminal.cleanup()?; // Optional: Drop handles this
return Ok(()); return Ok(());
} }
// --- FPS Calculation ---
let now = Instant::now();
let frame_duration = now.duration_since(last_frame_time);
last_frame_time = now;
if frame_duration.as_secs_f64() > 1e-6 {
current_fps = 1.0 / frame_duration.as_secs_f64();
}
} }
} }