use super::editor::{TextEditor, UnsavedAction}; use eframe::egui; impl TextEditor { pub fn has_unsaved_changes(&self) -> bool { self.tabs.iter().any(|tab| tab.is_modified) } pub fn get_unsaved_files(&self) -> Vec { self.tabs .iter() .filter(|tab| tab.is_modified) .map(|tab| tab.title.to_owned()) .collect() } pub fn request_quit(&mut self, ctx: &egui::Context) { if self.has_unsaved_changes() && !self.state_cache { self.pending_unsaved_action = Some(UnsavedAction::Quit); } else { self.clean_quit_requested = true; if let Err(e) = self.save_state_cache() { eprintln!("Failed to save state cache: {e}"); } ctx.send_viewport_cmd(egui::ViewportCommand::Close); } } pub fn force_quit(&mut self, ctx: &egui::Context) { self.force_quit_confirmed = true; if let Err(e) = self.save_state_cache() { eprintln!("Failed to save state cache: {e}"); } ctx.send_viewport_cmd(egui::ViewportCommand::Close); } pub(crate) fn show_unsaved_changes_dialog(&mut self, ctx: &egui::Context) { let mut close_action_now = None; let mut cancel_action = false; let (files_to_list, title, confirmation_text, button_text, action) = if let Some(action) = &self.pending_unsaved_action { match action { UnsavedAction::Quit => { let files = self.get_unsaved_files(); let file_plural = if files.len() > 1 { "s" } else { "" }; ( files, "Unsaved Changes".to_string(), format!("File{file_plural} with unsaved changes:"), "Quit Without Saving".to_string(), action.to_owned(), ) } UnsavedAction::CloseTab(tab_index) => { let file_name = self .tabs .get(*tab_index) .map_or_else(|| "unknown file".to_string(), |tab| tab.title.to_owned()); ( vec![file_name], "Unsaved Changes".to_string(), "This file has unsaved changes:".to_string(), "Close Without Saving".to_string(), action.to_owned(), ) } } } else { return; }; let visuals = &ctx.style().visuals; let error_color = visuals.error_fg_color; egui::Window::new(title) .collapsible(false) .resizable(false) .anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO) .show(ctx, |ui| { ui.vertical_centered(|ui| { ui.add_space(8.0); ui.label(egui::RichText::new(&confirmation_text).size(14.0)); ui.add_space(4.0); for file in &files_to_list { ui.label(egui::RichText::new(file).size(12.0).color(error_color)); } ui.add_space(12.0); ui.horizontal(|ui| { if ui.button("Cancel").clicked() { cancel_action = true; } ui.add_space(8.0); if ui .button(egui::RichText::new(&button_text).color(error_color)) .clicked() { close_action_now = Some(action.to_owned()); } }); ui.add_space(8.0); }); }); if cancel_action { self.pending_unsaved_action = None; } if let Some(action) = close_action_now { match action { UnsavedAction::Quit => { if let Err(e) = self.save_state_cache() { eprintln!("Failed to save state cache: {e}"); } self.force_quit(ctx); } UnsavedAction::CloseTab(tab_index) => { self.close_tab(tab_index); if let Err(e) = self.save_state_cache() { eprintln!("Failed to save state cache: {e}"); } } } self.pending_unsaved_action = None; } } }