Skip to content

Commit c1569ed

Browse files
authored
Add Ui.input_mut & InputState.ignore_key (#1212)
1 parent c8c871f commit c1569ed

File tree

5 files changed

+86
-48
lines changed

5 files changed

+86
-48
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
88
## Unreleased
99

1010
### Added ⭐
11+
* `Ui::input_mut` to modify how subsequent widgets see the `InputState` and a convenience method `InputState::consume_key` for shortcuts or hotkeys ([#1212](https://github.com/emilk/egui/pull/1212)).
1112
* Much improved font selection ([#1154](https://github.com/emilk/egui/pull/1154)):
1213
* You can now select any font size and family using `RichText::size` amd `RichText::family` and the new `FontId`.
1314
* Easily change text styles with `Style::text_styles`.

egui/src/data/input.rs

+36
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,42 @@ pub struct Modifiers {
264264
}
265265

266266
impl Modifiers {
267+
pub fn new() -> Self {
268+
Default::default()
269+
}
270+
271+
pub fn alt(self, value: bool) -> Self {
272+
Self { alt: value, ..self }
273+
}
274+
275+
pub fn ctrl(self, value: bool) -> Self {
276+
Self {
277+
ctrl: value,
278+
..self
279+
}
280+
}
281+
282+
pub fn shift(self, value: bool) -> Self {
283+
Self {
284+
shift: value,
285+
..self
286+
}
287+
}
288+
289+
pub fn mac_cmd(self, value: bool) -> Self {
290+
Self {
291+
mac_cmd: value,
292+
..self
293+
}
294+
}
295+
296+
pub fn command(self, value: bool) -> Self {
297+
Self {
298+
command: value,
299+
..self
300+
}
301+
}
302+
267303
#[inline(always)]
268304
pub fn is_none(&self) -> bool {
269305
self == &Self::default()

egui/src/input_state.rs

+18
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,24 @@ impl InputState {
192192
self.pointer.wants_repaint() || self.scroll_delta != Vec2::ZERO || !self.events.is_empty()
193193
}
194194

195+
/// Ignore a key if it was pressed or released this frame. Useful for hotkeys.
196+
/// Matches on both key press and key release, consuming them and removing them from `self.events`.
197+
/// Returns true if the key was pressed this frame (even if the key release was consumed).
198+
pub fn consume_key(&mut self, modifiers: Modifiers, key: Key) -> bool {
199+
self.events.retain(|event| {
200+
!matches!(
201+
event,
202+
Event::Key {
203+
key: ev_key,
204+
modifiers: ev_mods,
205+
..
206+
} if *ev_key == key && *ev_mods == modifiers
207+
)
208+
});
209+
210+
self.keys_down.remove(&key)
211+
}
212+
195213
/// Was the given key pressed this frame?
196214
pub fn key_pressed(&self, desired_key: Key) -> bool {
197215
self.num_presses(desired_key) > 0

egui/src/ui.rs

+15
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,21 @@ impl Ui {
338338
self.ctx().input()
339339
}
340340

341+
/// The [`InputState`] of the [`Context`] associated with this [`Ui`].
342+
/// Equivalent to `.ctx().input_mut()`.
343+
///
344+
/// Note that this locks the [`Context`], so be careful with if-let bindings
345+
/// like for [`Self::input()`].
346+
/// ```
347+
/// # egui::__run_test_ui(|ui| {
348+
/// ui.input_mut().consume_key(egui::Modifiers::default(), egui::Key::Enter);
349+
/// # });
350+
/// ```
351+
#[inline]
352+
pub fn input_mut(&self) -> RwLockWriteGuard<'_, InputState> {
353+
self.ctx().input_mut()
354+
}
355+
341356
/// The [`Memory`] of the [`Context`] associated with this ui.
342357
/// Equivalent to `.ctx().memory()`.
343358
#[inline]

egui_demo_lib/src/easy_mark/easy_mark_editor.rs

+16-48
Original file line numberDiff line numberDiff line change
@@ -117,59 +117,27 @@ impl EasyMarkEditor {
117117

118118
fn shortcuts(ui: &Ui, code: &mut dyn TextBuffer, ccursor_range: &mut CCursorRange) -> bool {
119119
let mut any_change = false;
120-
for event in &ui.input().events {
121-
if let Event::Key {
122-
key,
123-
pressed: true,
124-
modifiers,
125-
} = event
120+
for (key, surrounding) in [
121+
(Key::B, "*"), // *bold*
122+
(Key::C, "`"), // `code`
123+
(Key::I, "/"), // /italics/
124+
(Key::L, "$"), // $subscript$
125+
(Key::R, "^"), // ^superscript^
126+
(Key::S, "~"), // ~strikethrough~
127+
(Key::U, "_"), // _underline_
128+
] {
129+
if ui
130+
.input_mut()
131+
.consume_key(egui::Modifiers::new().command(true), key)
126132
{
127-
if modifiers.command_only() {
128-
match &key {
129-
// toggle *bold*
130-
Key::B => {
131-
toggle_surrounding(code, ccursor_range, "*");
132-
any_change = true;
133-
}
134-
// toggle `code`
135-
Key::C => {
136-
toggle_surrounding(code, ccursor_range, "`");
137-
any_change = true;
138-
}
139-
// toggle /italics/
140-
Key::I => {
141-
toggle_surrounding(code, ccursor_range, "/");
142-
any_change = true;
143-
}
144-
// toggle $lowered$
145-
Key::L => {
146-
toggle_surrounding(code, ccursor_range, "$");
147-
any_change = true;
148-
}
149-
// toggle ^raised^
150-
Key::R => {
151-
toggle_surrounding(code, ccursor_range, "^");
152-
any_change = true;
153-
}
154-
// toggle ~strikethrough~
155-
Key::S => {
156-
toggle_surrounding(code, ccursor_range, "~");
157-
any_change = true;
158-
}
159-
// toggle _underline_
160-
Key::U => {
161-
toggle_surrounding(code, ccursor_range, "_");
162-
any_change = true;
163-
}
164-
_ => {}
165-
}
166-
}
167-
}
133+
toggle_surrounding(code, ccursor_range, surrounding);
134+
any_change = true;
135+
};
168136
}
169137
any_change
170138
}
171139

172-
/// E.g. toggle *strong* with `toggle(&mut text, &mut cursor, "*")`
140+
/// E.g. toggle *strong* with `toggle_surrounding(&mut text, &mut cursor, "*")`
173141
fn toggle_surrounding(
174142
code: &mut dyn TextBuffer,
175143
ccursor_range: &mut CCursorRange,

0 commit comments

Comments
 (0)