FPS counter added
This commit is contained in:
17
Cargo.lock
generated
17
Cargo.lock
generated
@@ -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",
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user