Skip to content

Commit e392fba

Browse files
authored
Refactor: break up input.rs into many files (emilk#8230)
1 parent 3334420 commit e392fba

16 files changed

Lines changed: 1415 additions & 1381 deletions

crates/egui/src/data/input.rs

Lines changed: 0 additions & 1381 deletions
This file was deleted.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/// A file dropped into egui.
2+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
3+
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
4+
pub struct DroppedFile {
5+
/// Set by the `egui-winit` backend.
6+
pub path: Option<std::path::PathBuf>,
7+
8+
/// Name of the file. Set by the `eframe` web backend.
9+
pub name: String,
10+
11+
/// With the `eframe` web backend, this is set to the mime-type of the file (if available).
12+
pub mime: String,
13+
14+
/// Set by the `eframe` web backend.
15+
pub last_modified: Option<std::time::SystemTime>,
16+
17+
/// Set by the `eframe` web backend.
18+
pub bytes: Option<std::sync::Arc<[u8]>>,
19+
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
use epaint::ColorImage;
2+
3+
use crate::{
4+
Key,
5+
emath::{Pos2, Vec2},
6+
};
7+
8+
use super::{
9+
ImeEvent, Modifiers, MouseWheelUnit, PointerButton, TouchDeviceId, TouchId, TouchPhase,
10+
};
11+
12+
/// An input event generated by the integration.
13+
///
14+
/// This only covers events that egui cares about.
15+
#[derive(Clone, Debug, PartialEq)]
16+
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
17+
pub enum Event {
18+
/// The integration detected a "copy" event (e.g. Cmd+C).
19+
Copy,
20+
21+
/// The integration detected a "cut" event (e.g. Cmd+X).
22+
Cut,
23+
24+
/// The integration detected a "paste" event (e.g. Cmd+V).
25+
Paste(String),
26+
27+
/// Text input, e.g. via keyboard.
28+
///
29+
/// When the user presses enter/return, do not send a [`Text`](Event::Text) (just [`Key::Enter`]).
30+
Text(String),
31+
32+
/// A key was pressed or released.
33+
///
34+
/// ## Note for integration authors
35+
///
36+
/// Key events that has been processed by IMEs should not be sent to `egui`.
37+
Key {
38+
/// Most of the time, it's the logical key, heeding the active keymap -- for instance, if the user has Dvorak
39+
/// keyboard layout, it will be taken into account.
40+
///
41+
/// If it's impossible to determine the logical key on desktop platforms (say, in case of non-Latin letters),
42+
/// `key` falls back to the value of the corresponding physical key. This is necessary for proper work of
43+
/// standard shortcuts that only respond to Latin-based bindings (such as `Ctrl` + `V`).
44+
key: Key,
45+
46+
/// The physical key, corresponding to the actual position on the keyboard.
47+
///
48+
/// This ignores keymaps, so it is not recommended to use this.
49+
/// The only thing it makes sense for is things like games,
50+
/// where e.g. the physical location of WSAD on QWERTY should always map to movement,
51+
/// even if the user is using Dvorak or AZERTY.
52+
///
53+
/// `eframe` does not (yet) implement this on web.
54+
physical_key: Option<Key>,
55+
56+
/// Was it pressed or released?
57+
pressed: bool,
58+
59+
/// If this is a `pressed` event, is it a key-repeat?
60+
///
61+
/// On many platforms, holding down a key produces many repeated "pressed" events for it, so called key-repeats.
62+
/// Sometimes you will want to ignore such events, and this lets you do that.
63+
///
64+
/// egui will automatically detect such repeat events and mark them as such here.
65+
/// Therefore, if you are writing an egui integration, you do not need to set this (just set it to `false`).
66+
repeat: bool,
67+
68+
/// The state of the modifier keys at the time of the event.
69+
modifiers: Modifiers,
70+
},
71+
72+
/// The mouse or touch moved to a new place.
73+
PointerMoved(Pos2),
74+
75+
/// The mouse moved, the units are unspecified.
76+
/// Represents the actual movement of the mouse, without acceleration or clamped by screen edges.
77+
/// `PointerMoved` and `MouseMoved` can be sent at the same time.
78+
/// This event is optional. If the integration can not determine unfiltered motion it should not send this event.
79+
MouseMoved(Vec2),
80+
81+
/// A mouse button was pressed or released (or a touch started or stopped).
82+
PointerButton {
83+
/// Where is the pointer?
84+
pos: Pos2,
85+
86+
/// What mouse button? For touches, use [`PointerButton::Primary`].
87+
button: PointerButton,
88+
89+
/// Was it the button/touch pressed this frame, or released?
90+
pressed: bool,
91+
92+
/// The state of the modifier keys at the time of the event.
93+
modifiers: Modifiers,
94+
},
95+
96+
/// The mouse left the screen, or the last/primary touch input disappeared.
97+
///
98+
/// This means there is no longer a cursor on the screen for hovering etc.
99+
///
100+
/// On touch-up first send `PointerButton{pressed: false, …}` followed by `PointerLeft`.
101+
PointerGone,
102+
103+
/// Zoom scale factor this frame (e.g. from a pinch gesture).
104+
///
105+
/// * `zoom = 1`: no change.
106+
/// * `zoom < 1`: pinch together
107+
/// * `zoom > 1`: pinch spread
108+
///
109+
/// Note that egui also implement zooming by holding `Ctrl` and scrolling the mouse wheel,
110+
/// so integration need NOT emit this `Zoom` event in those cases, just [`Self::MouseWheel`].
111+
///
112+
/// As a user, check [`crate::InputState::smooth_scroll_delta`] to see if the user did any zooming this frame.
113+
Zoom(f32),
114+
115+
/// Rotation in radians this frame, measuring clockwise (e.g. from a rotation gesture).
116+
Rotate(f32),
117+
118+
/// IME Event
119+
Ime(ImeEvent),
120+
121+
/// On touch screens, report this *in addition to*
122+
/// [`Self::PointerMoved`], [`Self::PointerButton`], [`Self::PointerGone`]
123+
Touch {
124+
/// Hashed device identifier (if available; may be zero).
125+
/// Can be used to separate touches from different devices.
126+
device_id: TouchDeviceId,
127+
128+
/// Unique identifier of a finger/pen. Value is stable from touch down
129+
/// to lift-up
130+
id: TouchId,
131+
132+
/// One of: start move end cancel.
133+
phase: TouchPhase,
134+
135+
/// Position of the touch (or where the touch was last detected)
136+
pos: Pos2,
137+
138+
/// Describes how hard the touch device was pressed. May always be `None` if the platform does
139+
/// not support pressure sensitivity.
140+
/// The value is in the range from 0.0 (no pressure) to 1.0 (maximum pressure).
141+
force: Option<f32>,
142+
},
143+
144+
/// A raw mouse wheel event as sent by the backend.
145+
///
146+
/// Used for scrolling.
147+
MouseWheel {
148+
/// The unit of `delta`: points, lines, or pages.
149+
unit: MouseWheelUnit,
150+
151+
/// The direction of the vector indicates how to move the _content_ that is being viewed.
152+
/// So if you get positive values, the content being viewed should move to the right and down,
153+
/// revealing new things to the left and up.
154+
///
155+
/// A positive X-value indicates the content is being moved right,
156+
/// as when swiping right on a touch-screen or track-pad with natural scrolling.
157+
///
158+
/// A positive Y-value indicates the content is being moved down,
159+
/// as when swiping down on a touch-screen or track-pad with natural scrolling.
160+
delta: Vec2,
161+
162+
/// The phase of the scroll, useful for trackpads.
163+
///
164+
/// If unknown set this to [`TouchPhase::Move`].
165+
phase: TouchPhase,
166+
167+
/// The state of the modifier keys at the time of the event.
168+
modifiers: Modifiers,
169+
},
170+
171+
/// The native window gained or lost focused (e.g. the user clicked alt-tab).
172+
WindowFocused(bool),
173+
174+
/// An assistive technology (e.g. screen reader) requested an action.
175+
AccessKitActionRequest(accesskit::ActionRequest),
176+
177+
/// The reply of a screenshot requested with [`crate::ViewportCommand::Screenshot`].
178+
Screenshot {
179+
viewport_id: crate::ViewportId,
180+
181+
/// Whatever was passed to [`crate::ViewportCommand::Screenshot`].
182+
user_data: crate::UserData,
183+
184+
image: std::sync::Arc<ColorImage>,
185+
},
186+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use super::Event;
2+
3+
// TODO(emilk): generalize this to a proper event filter.
4+
/// Controls which events that a focused widget will have exclusive access to.
5+
///
6+
/// Currently this only controls a few special keyboard events,
7+
/// but in the future this `struct` should be extended into a full callback thing.
8+
///
9+
/// Any events not covered by the filter are given to the widget, but are not exclusive.
10+
#[derive(Clone, Copy, Debug)]
11+
pub struct EventFilter {
12+
/// If `true`, pressing tab will act on the widget,
13+
/// and NOT move focus away from the focused widget.
14+
///
15+
/// Default: `false`
16+
pub tab: bool,
17+
18+
/// If `true`, pressing horizontal arrows will act on the
19+
/// widget, and NOT move focus away from the focused widget.
20+
///
21+
/// Default: `false`
22+
pub horizontal_arrows: bool,
23+
24+
/// If `true`, pressing vertical arrows will act on the
25+
/// widget, and NOT move focus away from the focused widget.
26+
///
27+
/// Default: `false`
28+
pub vertical_arrows: bool,
29+
30+
/// If `true`, pressing escape will act on the widget,
31+
/// and NOT surrender focus from the focused widget.
32+
///
33+
/// Default: `false`
34+
pub escape: bool,
35+
}
36+
37+
#[expect(clippy::derivable_impls)] // let's be explicit
38+
impl Default for EventFilter {
39+
fn default() -> Self {
40+
Self {
41+
tab: false,
42+
horizontal_arrows: false,
43+
vertical_arrows: false,
44+
escape: false,
45+
}
46+
}
47+
}
48+
49+
impl EventFilter {
50+
pub fn matches(&self, event: &Event) -> bool {
51+
if let Event::Key { key, .. } = event {
52+
match key {
53+
crate::Key::Tab => self.tab,
54+
crate::Key::ArrowUp | crate::Key::ArrowDown => self.vertical_arrows,
55+
crate::Key::ArrowRight | crate::Key::ArrowLeft => self.horizontal_arrows,
56+
crate::Key::Escape => self.escape,
57+
_ => true,
58+
}
59+
} else {
60+
true
61+
}
62+
}
63+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// A file about to be dropped into egui.
2+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
3+
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
4+
pub struct HoveredFile {
5+
/// Set by the `egui-winit` backend.
6+
pub path: Option<std::path::PathBuf>,
7+
8+
/// With the `eframe` web backend, this is set to the mime-type of the file (if available).
9+
pub mime: String,
10+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// IME event.
2+
///
3+
/// See <https://docs.rs/winit/latest/winit/event/enum.Ime.html>
4+
#[derive(Clone, Debug, Eq, PartialEq)]
5+
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
6+
pub enum ImeEvent {
7+
/// Notifies when the IME was enabled.
8+
#[deprecated = "No longer used by egui"]
9+
Enabled,
10+
11+
/// A new IME candidate is being suggested.
12+
///
13+
/// An empty preedit string indicates that the IME has been dismissed, while
14+
/// a non-empty preedit string indicates that the IME is active.
15+
Preedit(String),
16+
17+
/// IME composition ended with this final result.
18+
///
19+
/// The IME is considered dismissed after this event.
20+
Commit(String),
21+
22+
/// Notifies when the IME was disabled.
23+
#[deprecated = "No longer used by egui"]
24+
Disabled,
25+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use crate::Key;
2+
3+
use super::{ModifierNames, Modifiers};
4+
5+
/// A keyboard shortcut, e.g. `Ctrl+Alt+W`.
6+
///
7+
/// Can be used with [`crate::InputState::consume_shortcut`]
8+
/// and [`crate::Context::format_shortcut`].
9+
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
10+
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
11+
pub struct KeyboardShortcut {
12+
pub modifiers: Modifiers,
13+
14+
pub logical_key: Key,
15+
}
16+
17+
impl KeyboardShortcut {
18+
pub const fn new(modifiers: Modifiers, logical_key: Key) -> Self {
19+
Self {
20+
modifiers,
21+
logical_key,
22+
}
23+
}
24+
25+
pub fn format(&self, names: &ModifierNames<'_>, is_mac: bool) -> String {
26+
let mut s = names.format(&self.modifiers, is_mac);
27+
if !s.is_empty() {
28+
s += names.concat;
29+
}
30+
if names.is_short {
31+
s += self.logical_key.symbol_or_name();
32+
} else {
33+
s += self.logical_key.name();
34+
}
35+
s
36+
}
37+
}
38+
39+
#[test]
40+
fn format_kb_shortcut() {
41+
let cmd_shift_f = KeyboardShortcut::new(Modifiers::COMMAND | Modifiers::SHIFT, Key::F);
42+
assert_eq!(
43+
cmd_shift_f.format(&ModifierNames::NAMES, false),
44+
"Ctrl+Shift+F"
45+
);
46+
assert_eq!(
47+
cmd_shift_f.format(&ModifierNames::NAMES, true),
48+
"Shift+Cmd+F"
49+
);
50+
assert_eq!(cmd_shift_f.format(&ModifierNames::SYMBOLS, false), "⌃⇧F");
51+
assert_eq!(cmd_shift_f.format(&ModifierNames::SYMBOLS, true), "⇧⌘F");
52+
}

crates/egui/src/data/input/mod.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//! The input needed by egui.
2+
3+
mod dropped_file;
4+
mod event;
5+
mod event_filter;
6+
mod hovered_file;
7+
mod ime_event;
8+
mod keyboard_shortcut;
9+
mod modifier_names;
10+
mod modifiers;
11+
mod mouse_wheel_unit;
12+
mod pointer_button;
13+
mod raw_input;
14+
mod safe_area_insets;
15+
mod touch;
16+
mod viewport_info;
17+
18+
pub use self::{
19+
dropped_file::DroppedFile,
20+
event::Event,
21+
event_filter::EventFilter,
22+
hovered_file::HoveredFile,
23+
ime_event::ImeEvent,
24+
keyboard_shortcut::KeyboardShortcut,
25+
modifier_names::ModifierNames,
26+
modifiers::Modifiers,
27+
mouse_wheel_unit::MouseWheelUnit,
28+
pointer_button::{NUM_POINTER_BUTTONS, PointerButton},
29+
raw_input::RawInput,
30+
safe_area_insets::SafeAreaInsets,
31+
touch::{TouchDeviceId, TouchId, TouchPhase},
32+
viewport_info::{ViewportEvent, ViewportInfo},
33+
};

0 commit comments

Comments
 (0)