use eframe::egui; /// Estado da execução do FFmpeg. #[derive(Default, PartialEq)] pub enum ExecutionState { #[default] Idle, Running, Success, Error(String), } /// Painel de execução: botão "Gerar MKV", progresso e erros. pub struct ExecutionPanel { pub state: ExecutionState, pub log_lines: Vec, } impl ExecutionPanel { pub fn new() -> Self { ExecutionPanel { state: ExecutionState::Idle, log_lines: Vec::new(), } } pub fn add_log(&mut self, line: String) { self.log_lines.push(line); // Limita o histórico de log if self.log_lines.len() > 200 { self.log_lines.remove(0); } } /// Renderiza o painel. Retorna `true` se o botão "Gerar MKV" foi clicado. pub fn ui(&mut self, ui: &mut egui::Ui, can_generate: bool) -> bool { let mut clicked = false; ui.group(|ui| { ui.heading("Gerar arquivo"); let is_running = self.state == ExecutionState::Running; if ui .add_enabled( can_generate && !is_running, egui::Button::new(if is_running { "Processando…" } else { "Gerar MKV" }), ) .clicked() { clicked = true; } match &self.state { ExecutionState::Idle => {} ExecutionState::Running => { ui.spinner(); ui.label("Processando..."); } ExecutionState::Success => { ui.colored_label(egui::Color32::GREEN, "✓ Arquivo gerado com sucesso!"); } ExecutionState::Error(msg) => { ui.colored_label(egui::Color32::RED, "✗ Erro durante o processamento:"); ui.add( egui::TextEdit::multiline(&mut msg.as_str()) .desired_rows(4) .desired_width(f32::INFINITY), ); } } // Log de progresso if !self.log_lines.is_empty() { ui.collapsing("Log detalhado", |ui| { egui::ScrollArea::vertical() .max_height(150.0) .show(ui, |ui| { for line in &self.log_lines { ui.label(egui::RichText::new(line).monospace().size(11.0)); } }); }); } }); clicked } }