#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum InlineEditOutcome {
Editing,
Submit,
Cancel,
}
pub(crate) fn resolve(
ui: &egui::Ui,
response: &egui::Response,
first_frame: bool,
) -> InlineEditOutcome {
if first_frame {
response.request_focus();
return InlineEditOutcome::Editing;
}
let (enter, escape) = ui.input(|i| {
(
i.key_pressed(egui::Key::Enter),
i.key_pressed(egui::Key::Escape),
)
});
if escape {
return InlineEditOutcome::Cancel;
}
if response.lost_focus() && enter {
return InlineEditOutcome::Submit;
}
if response.clicked_elsewhere() || response.lost_focus() {
return InlineEditOutcome::Cancel;
}
InlineEditOutcome::Editing
}
#[cfg(test)]
mod tests {
use super::*;
fn run(frames: Vec<Vec<egui::Event>>) -> Vec<InlineEditOutcome> {
let ctx = egui::Context::default();
let mut buffer = "name".to_string();
let mut outcomes = Vec::new();
for (n, events) in frames.into_iter().enumerate() {
let mut out = ctx.run_ui(
egui::RawInput {
screen_rect: Some(egui::Rect::from_min_size(
egui::Pos2::ZERO,
egui::vec2(800.0, 600.0),
)),
events,
..Default::default()
},
|ui| {
egui::CentralPanel::default().show(ui, |ui| {
let response = ui.add(egui::TextEdit::singleline(&mut buffer));
outcomes.push(resolve(ui, &response, n == 0));
});
},
);
out.textures_delta.clear();
}
outcomes
}
fn key(key: egui::Key) -> egui::Event {
egui::Event::Key {
key,
physical_key: None,
pressed: true,
repeat: false,
modifiers: Default::default(),
}
}
fn click(pos: egui::Pos2, pressed: bool) -> egui::Event {
egui::Event::PointerButton {
pos,
button: egui::PointerButton::Primary,
pressed,
modifiers: Default::default(),
}
}
#[test]
fn enter_submits() {
let out = run(vec![vec![], vec![], vec![key(egui::Key::Enter)]]);
assert_eq!(out.last(), Some(&InlineEditOutcome::Submit));
}
#[test]
fn escape_cancels() {
let out = run(vec![vec![], vec![], vec![key(egui::Key::Escape)]]);
assert_eq!(out.last(), Some(&InlineEditOutcome::Cancel));
}
#[test]
fn a_click_away_cancels_never_submits() {
let away = egui::pos2(700.0, 500.0);
let out = run(vec![
vec![],
vec![],
vec![egui::Event::PointerMoved(away)],
vec![click(away, true)],
vec![click(away, false)],
]);
assert!(
out.contains(&InlineEditOutcome::Cancel),
"click-away must cancel: {out:?}"
);
assert!(!out.contains(&InlineEditOutcome::Submit), "never submit");
}
}