fix: held keys save, copy and close only once
This commit is contained in:
1 parent
bf8e0500eb
commit
f6723b9740
1 file changed
+73
-4
+73
-4
@@ -172,16 +172,19 @@ impl Editor {
|
|||||||
|
|
||||||
fn keys(&mut self, ctx: &egui::Context) {
|
fn keys(&mut self, ctx: &egui::Context) {
|
||||||
let shift_cmd = Modifiers::COMMAND | Modifiers::SHIFT;
|
let shift_cmd = Modifiers::COMMAND | Modifiers::SHIFT;
|
||||||
let pressed = |m: Modifiers, k: Key| ctx.input_mut(|i| i.consume_key(m, k));
|
// Holding a key must not save, copy or close again and again; undo
|
||||||
// Most specific first: consume_key ignores extra Shift.
|
// and redo may repeat.
|
||||||
|
let pressed = |m: Modifiers, k: Key| ctx.input_mut(|i| take_press(&mut i.events, m, k));
|
||||||
|
let repeating = |m: Modifiers, k: Key| ctx.input_mut(|i| i.consume_key(m, k));
|
||||||
|
// Most specific first: extra Shift is ignored.
|
||||||
if pressed(shift_cmd, Key::S) {
|
if pressed(shift_cmd, Key::S) {
|
||||||
self.save(true);
|
self.save(true);
|
||||||
} else if pressed(Modifiers::COMMAND, Key::S) && self.save(false) && self.confirm_close {
|
} else if pressed(Modifiers::COMMAND, Key::S) && self.save(false) && self.confirm_close {
|
||||||
self.close(ctx);
|
self.close(ctx);
|
||||||
}
|
}
|
||||||
if pressed(shift_cmd, Key::Z) || pressed(Modifiers::COMMAND, Key::Y) {
|
if repeating(shift_cmd, Key::Z) || repeating(Modifiers::COMMAND, Key::Y) {
|
||||||
self.doc.redo();
|
self.doc.redo();
|
||||||
} else if pressed(Modifiers::COMMAND, Key::Z) {
|
} else if repeating(Modifiers::COMMAND, Key::Z) {
|
||||||
self.doc.undo();
|
self.doc.undo();
|
||||||
}
|
}
|
||||||
if pressed(Modifiers::COMMAND, Key::C) {
|
if pressed(Modifiers::COMMAND, Key::C) {
|
||||||
@@ -344,6 +347,27 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes presses of `key` with `modifiers` (extra Shift and Alt ignored,
|
||||||
|
/// like egui's `consume_key`). True only for a fresh press: key repeats are
|
||||||
|
/// swallowed without counting.
|
||||||
|
fn take_press(events: &mut Vec<egui::Event>, modifiers: Modifiers, key: Key) -> bool {
|
||||||
|
let mut fresh = false;
|
||||||
|
events.retain(|event| match event {
|
||||||
|
egui::Event::Key {
|
||||||
|
key: k,
|
||||||
|
pressed: true,
|
||||||
|
repeat,
|
||||||
|
modifiers: m,
|
||||||
|
..
|
||||||
|
} if *k == key && m.matches_logically(modifiers) => {
|
||||||
|
fresh |= !repeat;
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
});
|
||||||
|
fresh
|
||||||
|
}
|
||||||
|
|
||||||
/// Draws one primitive on the canvas.
|
/// Draws one primitive on the canvas.
|
||||||
fn paint(painter: &egui::Painter, prim: &Prim, scale: f32, to_pos: impl Fn(shape::P) -> Pos2) {
|
fn paint(painter: &egui::Painter, prim: &Prim, scale: f32, to_pos: impl Fn(shape::P) -> Pos2) {
|
||||||
let color = |c: &[u8; 4]| Color32::from_rgba_unmultiplied(c[0], c[1], c[2], c[3]);
|
let color = |c: &[u8; 4]| Color32::from_rgba_unmultiplied(c[0], c[1], c[2], c[3]);
|
||||||
@@ -390,3 +414,48 @@ impl eframe::App for Editor {
|
|||||||
egui::CentralPanel::no_frame().show(ui, |ui| self.canvas(ui));
|
egui::CentralPanel::no_frame().show(ui, |ui| self.canvas(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn key(key: Key, modifiers: Modifiers, repeat: bool) -> egui::Event {
|
||||||
|
egui::Event::Key {
|
||||||
|
key,
|
||||||
|
physical_key: None,
|
||||||
|
pressed: true,
|
||||||
|
repeat,
|
||||||
|
modifiers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn held_keys_act_once() {
|
||||||
|
let mut events = vec![
|
||||||
|
key(Key::Escape, Modifiers::NONE, false),
|
||||||
|
key(Key::Escape, Modifiers::NONE, true),
|
||||||
|
key(Key::Escape, Modifiers::NONE, true),
|
||||||
|
];
|
||||||
|
assert!(take_press(&mut events, Modifiers::NONE, Key::Escape));
|
||||||
|
assert!(events.is_empty(), "repeats are swallowed too");
|
||||||
|
let mut repeats = vec![key(Key::Escape, Modifiers::NONE, true)];
|
||||||
|
assert!(!take_press(&mut repeats, Modifiers::NONE, Key::Escape));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn modifiers_match_like_consume_key() {
|
||||||
|
let mut events = vec![key(Key::S, Modifiers::COMMAND | Modifiers::SHIFT, false)];
|
||||||
|
assert!(!take_press(
|
||||||
|
&mut events,
|
||||||
|
Modifiers::COMMAND | Modifiers::ALT,
|
||||||
|
Key::S
|
||||||
|
));
|
||||||
|
assert!(
|
||||||
|
take_press(&mut events, Modifiers::COMMAND, Key::S),
|
||||||
|
"extra Shift ignored"
|
||||||
|
);
|
||||||
|
let mut plain = vec![key(Key::S, Modifiers::NONE, false)];
|
||||||
|
assert!(!take_press(&mut plain, Modifiers::COMMAND, Key::S));
|
||||||
|
assert_eq!(plain.len(), 1, "other events stay");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user