155 lines
5.0 KiB
Rust
155 lines
5.0 KiB
Rust
// client/src/components/common/status_line.rs
|
|
use crate::config::colors::themes::Theme;
|
|
use crate::state::app::state::AppState;
|
|
use ratatui::{
|
|
layout::Rect,
|
|
style::Style,
|
|
text::{Line, Span, Text},
|
|
widgets::{Paragraph, Wrap},
|
|
Frame,
|
|
};
|
|
use std::path::Path;
|
|
use unicode_width::UnicodeWidthStr;
|
|
|
|
pub fn render_status_line(
|
|
f: &mut Frame,
|
|
area: Rect,
|
|
current_dir: &str,
|
|
theme: &Theme,
|
|
is_edit_mode: bool,
|
|
current_fps: f64,
|
|
app_state: &AppState,
|
|
) {
|
|
#[cfg(feature = "ui-debug")]
|
|
{
|
|
if let Some(debug_state) = &app_state.debug_state {
|
|
let paragraph = if debug_state.is_error {
|
|
// --- THIS IS THE CRITICAL LOGIC FOR ERRORS ---
|
|
// 1. Create a `Text` object, which can contain multiple lines.
|
|
let error_text = Text::from(debug_state.displayed_message.clone());
|
|
|
|
// 2. Create a Paragraph from the Text and TELL IT TO WRAP.
|
|
Paragraph::new(error_text)
|
|
.wrap(Wrap { trim: true }) // This line makes the text break into new rows.
|
|
.style(Style::default().bg(theme.highlight).fg(theme.bg))
|
|
} else {
|
|
// --- This is for normal, single-line info messages ---
|
|
Paragraph::new(debug_state.displayed_message.as_str())
|
|
.style(Style::default().fg(theme.accent).bg(theme.bg))
|
|
};
|
|
f.render_widget(paragraph, area);
|
|
} else {
|
|
// Fallback for when debug state is None
|
|
let paragraph = Paragraph::new("").style(Style::default().bg(theme.bg));
|
|
f.render_widget(paragraph, area);
|
|
}
|
|
return; // Stop here and don't render the normal status line.
|
|
}
|
|
|
|
// --- The normal status line rendering logic (unchanged) ---
|
|
let program_info = format!("komp_ac v{}", env!("CARGO_PKG_VERSION"));
|
|
let mode_text = if is_edit_mode { "[EDIT]" } else { "[READ-ONLY]" };
|
|
|
|
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) {
|
|
current_dir.replacen(&home_dir, "~", 1)
|
|
} else {
|
|
current_dir.to_string()
|
|
};
|
|
|
|
let available_width = area.width as usize;
|
|
let mode_width = UnicodeWidthStr::width(mode_text);
|
|
let program_info_width = UnicodeWidthStr::width(program_info.as_str());
|
|
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_str = if UnicodeWidthStr::width(display_dir.as_str())
|
|
<= remaining_width_for_dir
|
|
{
|
|
display_dir
|
|
} else {
|
|
let dir_name = Path::new(current_dir)
|
|
.file_name()
|
|
.and_then(|n| n.to_str())
|
|
.unwrap_or(current_dir);
|
|
if UnicodeWidthStr::width(dir_name) <= remaining_width_for_dir {
|
|
dir_name.to_string()
|
|
} else {
|
|
dir_name
|
|
.chars()
|
|
.take(remaining_width_for_dir)
|
|
.collect::<String>()
|
|
}
|
|
};
|
|
|
|
let mut current_content_width = mode_width
|
|
+ separator_width
|
|
+ UnicodeWidthStr::width(dir_display_text_str.as_str())
|
|
+ separator_width
|
|
+ program_info_width;
|
|
if show_fps {
|
|
current_content_width += separator_width + fps_width;
|
|
}
|
|
|
|
let mut line_spans = vec![
|
|
Span::styled(mode_text, Style::default().fg(theme.accent)),
|
|
Span::styled(separator, Style::default().fg(theme.border)),
|
|
Span::styled(
|
|
dir_display_text_str.as_str(),
|
|
Style::default().fg(theme.fg),
|
|
),
|
|
Span::styled(separator, Style::default().fg(theme.border)),
|
|
Span::styled(
|
|
program_info.as_str(),
|
|
Style::default().fg(theme.secondary),
|
|
),
|
|
];
|
|
|
|
if show_fps {
|
|
line_spans
|
|
.push(Span::styled(separator, Style::default().fg(theme.border)));
|
|
line_spans.push(Span::styled(
|
|
fps_text.as_str(),
|
|
Style::default().fg(theme.secondary),
|
|
));
|
|
}
|
|
|
|
let padding_needed = available_width.saturating_sub(current_content_width);
|
|
if padding_needed > 0 {
|
|
line_spans.push(Span::styled(
|
|
" ".repeat(padding_needed),
|
|
Style::default().bg(theme.bg),
|
|
));
|
|
}
|
|
|
|
let paragraph =
|
|
Paragraph::new(Line::from(line_spans)).style(Style::default().bg(theme.bg));
|
|
|
|
f.render_widget(paragraph, area);
|
|
}
|