use crate::core::cache_man::CacheManager;
use crate::entities::node::Node;
use crate::entities::Project;
use crate::entities::frame::{Frame, PixelFormat};
use crate::core::event_bus::BoxedEvent;
use crate::core::player::Player;
use crate::widgets::viewport::ViewportState;
use eframe::egui;
use std::sync::Arc;
#[derive(Default)]
pub struct StatusBar {
pub current_message: String,
}
impl StatusBar {
pub fn new() -> Self {
Self::default()
}
pub fn update(&mut self, ctx: &egui::Context) {
let _ = ctx;
}
pub fn render(
&self,
ctx: &egui::Context,
frame: Option<&Frame>,
player: &Player,
project: &Project,
viewport_state: &ViewportState,
render_time_ms: f32,
cache_manager: Option<&Arc<CacheManager>>,
mut dispatch: impl FnMut(BoxedEvent),
) {
egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
ui.horizontal(|ui| {
if let Some(frame) = frame {
if let Some(path) = frame.file() {
if let Some(filename) = path.file_name().and_then(|n| n.to_str()) {
ui.monospace(filename);
} else {
ui.monospace("---");
}
} else {
ui.monospace("No file");
}
} else {
ui.monospace("No file");
}
ui.separator();
if let Some(img) = frame {
ui.monospace(format!("{:>4}x{:<4}", img.width(), img.height()));
} else {
ui.monospace(" 0x0 ");
}
ui.separator();
if let Some(img) = frame {
ui.monospace(Self::format_pixel_format(img.pixel_format()));
} else {
ui.monospace("---");
}
ui.separator();
ui.monospace(format!("{:>6.1}%", viewport_state.zoom * 100.0));
ui.separator();
ui.monospace(format!("{:.1}ms", render_time_ms));
ui.separator();
if let Some(manager) = cache_manager {
let (usage, limit) = manager.mem();
let usage_mb = usage / 1024 / 1024;
let limit_mb = limit / 1024 / 1024;
let percent = if limit > 0 {
(usage as f64 / limit as f64 * 100.0) as u32
} else {
0
};
log::trace!("StatusBar: cache_manager present, usage={}MB, limit={}MB", usage_mb, limit_mb);
ui.monospace(format!("Mem: {}/{}MB ({}%)", usage_mb, limit_mb, percent));
ui.separator();
} else {
log::warn!("StatusBar: cache_manager is None!");
}
let mut loop_enabled = player.loop_enabled();
if ui.checkbox(&mut loop_enabled, "Loop").changed() {
dispatch(Box::new(crate::core::player_events::SetLoopEvent(loop_enabled)));
}
ui.separator();
let base_fps = player.fps_base();
let play_fps = player.fps_play();
ui.monospace(format!("{:.0}/{:.0} fps", base_fps, play_fps));
if let Some(comp_uuid) = player.active_comp() {
let media = project.media.read().unwrap_or_else(|e| e.into_inner());
if let Some(comp) = media.get(&comp_uuid) {
ui.separator();
let start = comp._in();
let end = comp._out();
let (play_start, play_end) = comp.play_range(true);
let current = comp.frame();
ui.monospace(format!(
"<{} | {} <{}> {} | {}>",
start, play_start, current, play_end, end
));
}
}
if !self.current_message.is_empty() {
ui.separator();
ui.monospace(&self.current_message);
}
});
});
}
fn format_pixel_format(format: PixelFormat) -> &'static str {
match format {
PixelFormat::Rgba8 => "RGBA u8",
PixelFormat::RgbaF16 => "RGBA f16",
PixelFormat::RgbaF32 => "RGBA f32",
}
}
}