//! Console panel for displaying output and error messages //! //! Shows a scrollable log of messages with color coding. use eframe::egui; use crate::gui::state::{GuiState, MessageKind}; /// Console panel for output messages pub struct ConsolePanel { /// Whether to auto-scroll to bottom auto_scroll: bool, } impl ConsolePanel { pub fn new() -> Self { Self { auto_scroll: true } } pub fn show(&mut self, ui: &mut egui::Ui, state: &mut GuiState) { // Header with title and buttons ui.horizontal(|ui| { ui.heading("Console"); ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { if ui.button("Clear").clicked() { state.clear_console(); } ui.checkbox(&mut self.auto_scroll, "Auto-scroll"); ui.label(format!("{} messages", state.console_messages.len())); }); }); ui.separator(); // Scrollable message area let scroll_area = egui::ScrollArea::vertical() .auto_shrink([false, false]) .stick_to_bottom(self.auto_scroll); scroll_area.show(ui, |ui| { if state.console_messages.is_empty() { ui.label("(no messages)"); } else { for message in &state.console_messages { let color = match message.kind { MessageKind::Info => egui::Color32::LIGHT_GRAY, MessageKind::Success => egui::Color32::from_rgb(100, 200, 100), MessageKind::Error => egui::Color32::from_rgb(255, 100, 100), MessageKind::Warning => egui::Color32::from_rgb(255, 200, 100), }; let prefix = match message.kind { MessageKind::Info => ">", MessageKind::Success => "+", MessageKind::Error => "!", MessageKind::Warning => "?", }; ui.horizontal(|ui| { ui.label( egui::RichText::new(prefix) .color(color) .monospace(), ); ui.label( egui::RichText::new(&message.text) .color(color) .monospace(), ); }); } } }); } } impl Default for ConsolePanel { fn default() -> Self { Self::new() } }