134 lines
4.7 KiB
Rust
134 lines
4.7 KiB
Rust
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<String> {
|
|
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;
|
|
}
|
|
}
|
|
}
|