Save changes prompt: arrow keys pick the button, Enter gives it (#683)

In the save-changes prompt, Left and Right pick a button and Enter gives it.
This commit is contained in:
lucas-aguilar89 authored and GitHub committed 2026-10-13 09:27:46 -04:00
1 parent fe1e5f1b95
commit d1a773a684
2 files changed
+41 -5

No files matched your search

+30 -4
View File
@@ -48,6 +48,8 @@ pub struct Documents {
pub closing: Option<usize>,
/// Quitting: the tabs answered so far with Don't Save (`None`: not quitting).
pub quitting: Option<Vec<usize>>,
/// The "save changes?" button the arrow keys have picked; Enter gives it.
pub choice: Answer,
}
impl Documents {
@@ -458,8 +460,9 @@ pub fn layout(n: usize, active: usize, room: f32) -> (usize, usize, f32) {
}
/// What "save changes?" was answered.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum Answer {
#[default]
Save,
DontSave,
Cancel,
@@ -473,6 +476,28 @@ pub fn prompt(app: &mut SolveApp, ctx: &egui::Context) {
let name = tabs_info(app).get(i).map(|x| x.0.clone()).unwrap_or_default();
let name_display = if name == "Untitled" { crate::i18n::tr("ui.untitled") } else { &name };
let mut answer: Option<Answer> = None;
// Left and Right move between the buttons (Save is picked first); Enter gives the picked one.
let order = [Answer::Save, Answer::DontSave, Answer::Cancel];
let (left, right, enter) = ctx.input_mut(|x| {
(
x.consume_key(egui::Modifiers::NONE, egui::Key::ArrowLeft),
x.consume_key(egui::Modifiers::NONE, egui::Key::ArrowRight),
x.consume_key(egui::Modifiers::NONE, egui::Key::Enter),
)
});
let at = order.iter().position(|a| *a == app.docs.choice).unwrap_or(0);
let at = if left {
at.saturating_sub(1)
} else if right {
(at + 1).min(order.len() - 1)
} else {
at
};
let choice = order.get(at).copied().unwrap_or_default();
app.docs.choice = choice;
if enter {
answer = Some(choice);
}
let title = crate::i18n::format("document.save_changes", &[("name", name_display)]);
crate::frame::window(ctx, title, crate::frame::Width::Normal)
.id(egui::Id::new("sc_close_prompt"))
@@ -483,13 +508,13 @@ pub fn prompt(app: &mut SolveApp, ctx: &egui::Context) {
ui.label(crate::i18n::format("document.unsaved_changes", &[("name", name_display)]));
ui.add_space(8.0);
ui.horizontal(|ui| {
if ui.button(crate::i18n::tr("ui.save")).clicked() {
if ui.add(egui::Button::new(crate::i18n::tr("ui.save")).selected(choice == Answer::Save)).clicked() {
answer = Some(Answer::Save);
}
if ui.button(crate::i18n::tr("ui.don_t_save")).clicked() {
if ui.add(egui::Button::new(crate::i18n::tr("ui.don_t_save")).selected(choice == Answer::DontSave)).clicked() {
answer = Some(Answer::DontSave);
}
if ui.button(crate::i18n::tr("ui.cancel")).clicked() {
if ui.add(egui::Button::new(crate::i18n::tr("ui.cancel")).selected(choice == Answer::Cancel)).clicked() {
answer = Some(Answer::Cancel);
}
});
@@ -506,6 +531,7 @@ pub fn prompt(app: &mut SolveApp, ctx: &egui::Context) {
/// Act on the "save changes?" answer (also the control channel's `ui.documents {answer}`).
pub fn answer_prompt(app: &mut SolveApp, answer: Answer) {
let Some(i) = app.docs.closing else { return };
app.docs.choice = Answer::Save;
match answer {
Answer::Save => {
switch(app, i);
@@ -10,7 +10,17 @@
{"expect": {"shown": "Don't Save", "quit_requested": false}},
{"key": "Escape"},
{"expect": {"not_shown": "Don't Save", "quitting": false, "quit_requested": false}},
{"note": "Left and Right pick a button (Save first, stopping at the ends) and Enter gives it."},
{"call": "app.quit"},
{"widget": "Don't Save"},
{"key": "ArrowRight"},
{"key": "ArrowRight"},
{"key": "ArrowRight"},
{"key": "Enter"},
{"expect": {"not_shown": "Don't Save", "quitting": false, "quit_requested": false, "bodies": 1}},
{"call": "app.quit"},
{"key": "ArrowRight"},
{"key": "ArrowRight"},
{"key": "ArrowLeft"},
{"key": "Enter"},
{"expect": {"quit_requested": true}}
]