Track the global focus state of the UI (#1859)
* Track the global focus state of the UI * Fix changelog entries * Document the new difference between `Response::has_focus` and `Memory::has_focus`
This commit is contained in:
parent
36a49ffba9
commit
c6c6d2dc5d
6 changed files with 31 additions and 3 deletions
|
@ -17,6 +17,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui-w
|
||||||
* Added support for using `PaintCallback` shapes with the WGPU backend ([#1684](https://github.com/emilk/egui/pull/1684)).
|
* Added support for using `PaintCallback` shapes with the WGPU backend ([#1684](https://github.com/emilk/egui/pull/1684)).
|
||||||
* Added `Contex::request_repaint_after` ([#1694](https://github.com/emilk/egui/pull/1694)).
|
* Added `Contex::request_repaint_after` ([#1694](https://github.com/emilk/egui/pull/1694)).
|
||||||
* `ctrl-h` now acts like backspace in `TextEdit` ([#1812](https://github.com/emilk/egui/pull/1812)).
|
* `ctrl-h` now acts like backspace in `TextEdit` ([#1812](https://github.com/emilk/egui/pull/1812)).
|
||||||
|
* Added `RawInput::has_focus` which backends can set to indicate whether the UI as a whole has the keyboard focus ([#1859](https://github.com/emilk/egui/pull/1859)).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* MSRV (Minimum Supported Rust Version) is now `1.61.0` ([#1846](https://github.com/emilk/egui/pull/1846)).
|
* MSRV (Minimum Supported Rust Version) is now `1.61.0` ([#1846](https://github.com/emilk/egui/pull/1846)).
|
||||||
|
|
|
@ -8,6 +8,7 @@ All notable changes to the `egui-winit` integration will be noted in this file.
|
||||||
* Allow deferred render + surface state initialization for Android ([#1634](https://github.com/emilk/egui/pull/1634)).
|
* Allow deferred render + surface state initialization for Android ([#1634](https://github.com/emilk/egui/pull/1634)).
|
||||||
* Fixed window position persistence ([#1745](https://github.com/emilk/egui/pull/1745)).
|
* Fixed window position persistence ([#1745](https://github.com/emilk/egui/pull/1745)).
|
||||||
* Fixed mouse cursor change on Linux ([#1747](https://github.com/emilk/egui/pull/1747)).
|
* Fixed mouse cursor change on Linux ([#1747](https://github.com/emilk/egui/pull/1747)).
|
||||||
|
* Use the new `RawInput::has_focus` field to indicate whether the window has the keyboard focus ([#1859](https://github.com/emilk/egui/pull/1859)).
|
||||||
|
|
||||||
|
|
||||||
## 0.18.0 - 2022-04-30
|
## 0.18.0 - 2022-04-30
|
||||||
|
|
|
@ -70,9 +70,14 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_wayland_display(wayland_display: Option<*mut c_void>) -> Self {
|
pub fn new_with_wayland_display(wayland_display: Option<*mut c_void>) -> Self {
|
||||||
|
let egui_input = egui::RawInput {
|
||||||
|
has_focus: false, // winit will tell us when we have focus
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
start_time: instant::Instant::now(),
|
start_time: instant::Instant::now(),
|
||||||
egui_input: Default::default(),
|
egui_input,
|
||||||
pointer_pos_in_points: None,
|
pointer_pos_in_points: None,
|
||||||
any_pointer_button_down: false,
|
any_pointer_button_down: false,
|
||||||
current_cursor_icon: egui::CursorIcon::Default,
|
current_cursor_icon: egui::CursorIcon::Default,
|
||||||
|
@ -214,7 +219,8 @@ impl State {
|
||||||
egui_ctx.wants_keyboard_input()
|
egui_ctx.wants_keyboard_input()
|
||||||
|| input.virtual_keycode == Some(winit::event::VirtualKeyCode::Tab)
|
|| input.virtual_keycode == Some(winit::event::VirtualKeyCode::Tab)
|
||||||
}
|
}
|
||||||
WindowEvent::Focused(_) => {
|
WindowEvent::Focused(has_focus) => {
|
||||||
|
self.egui_input.has_focus = *has_focus;
|
||||||
// We will not be given a KeyboardInput event when the modifiers are released while
|
// We will not be given a KeyboardInput event when the modifiers are released while
|
||||||
// the window does not have focus. Unset all modifier state to be safe.
|
// the window does not have focus. Unset all modifier state to be safe.
|
||||||
self.egui_input.modifiers = egui::Modifiers::default();
|
self.egui_input.modifiers = egui::Modifiers::default();
|
||||||
|
|
|
@ -62,6 +62,9 @@ pub struct RawInput {
|
||||||
/// Note: when using `eframe` on Windows you need to enable
|
/// Note: when using `eframe` on Windows you need to enable
|
||||||
/// drag-and-drop support using `eframe::NativeOptions`.
|
/// drag-and-drop support using `eframe::NativeOptions`.
|
||||||
pub dropped_files: Vec<DroppedFile>,
|
pub dropped_files: Vec<DroppedFile>,
|
||||||
|
|
||||||
|
/// The window has the keyboard focus (i.e. is receiving key presses).
|
||||||
|
pub has_focus: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RawInput {
|
impl Default for RawInput {
|
||||||
|
@ -76,6 +79,7 @@ impl Default for RawInput {
|
||||||
events: vec![],
|
events: vec![],
|
||||||
hovered_files: Default::default(),
|
hovered_files: Default::default(),
|
||||||
dropped_files: Default::default(),
|
dropped_files: Default::default(),
|
||||||
|
has_focus: true, // integrations opt into global focus tracking
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +100,7 @@ impl RawInput {
|
||||||
events: std::mem::take(&mut self.events),
|
events: std::mem::take(&mut self.events),
|
||||||
hovered_files: self.hovered_files.clone(),
|
hovered_files: self.hovered_files.clone(),
|
||||||
dropped_files: std::mem::take(&mut self.dropped_files),
|
dropped_files: std::mem::take(&mut self.dropped_files),
|
||||||
|
has_focus: self.has_focus,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +116,7 @@ impl RawInput {
|
||||||
mut events,
|
mut events,
|
||||||
mut hovered_files,
|
mut hovered_files,
|
||||||
mut dropped_files,
|
mut dropped_files,
|
||||||
|
has_focus,
|
||||||
} = newer;
|
} = newer;
|
||||||
|
|
||||||
self.screen_rect = screen_rect.or(self.screen_rect);
|
self.screen_rect = screen_rect.or(self.screen_rect);
|
||||||
|
@ -122,6 +128,7 @@ impl RawInput {
|
||||||
self.events.append(&mut events);
|
self.events.append(&mut events);
|
||||||
self.hovered_files.append(&mut hovered_files);
|
self.hovered_files.append(&mut hovered_files);
|
||||||
self.dropped_files.append(&mut dropped_files);
|
self.dropped_files.append(&mut dropped_files);
|
||||||
|
self.has_focus = has_focus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,6 +548,7 @@ impl RawInput {
|
||||||
events,
|
events,
|
||||||
hovered_files,
|
hovered_files,
|
||||||
dropped_files,
|
dropped_files,
|
||||||
|
has_focus,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
ui.label(format!("screen_rect: {:?} points", screen_rect));
|
ui.label(format!("screen_rect: {:?} points", screen_rect));
|
||||||
|
@ -558,6 +566,7 @@ impl RawInput {
|
||||||
ui.label(format!("modifiers: {:#?}", modifiers));
|
ui.label(format!("modifiers: {:#?}", modifiers));
|
||||||
ui.label(format!("hovered_files: {}", hovered_files.len()));
|
ui.label(format!("hovered_files: {}", hovered_files.len()));
|
||||||
ui.label(format!("dropped_files: {}", dropped_files.len()));
|
ui.label(format!("dropped_files: {}", dropped_files.len()));
|
||||||
|
ui.label(format!("has_focus: {}", has_focus));
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
ui.set_min_height(150.0);
|
ui.set_min_height(150.0);
|
||||||
ui.label(format!("events: {:#?}", events))
|
ui.label(format!("events: {:#?}", events))
|
||||||
|
|
|
@ -350,6 +350,11 @@ impl Memory {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does this widget have keyboard focus?
|
/// Does this widget have keyboard focus?
|
||||||
|
///
|
||||||
|
/// This function does not consider whether the UI as a whole (e.g. window)
|
||||||
|
/// has the keyboard focus. That makes this function suitable for deciding
|
||||||
|
/// widget state that should not be disrupted if the user moves away
|
||||||
|
/// from the window and back.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn has_focus(&self, id: Id) -> bool {
|
pub fn has_focus(&self, id: Id) -> bool {
|
||||||
self.interaction.focus.id == Some(id)
|
self.interaction.focus.id == Some(id)
|
||||||
|
|
|
@ -212,8 +212,14 @@ impl Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This widget has the keyboard focus (i.e. is receiving key presses).
|
/// This widget has the keyboard focus (i.e. is receiving key presses).
|
||||||
|
///
|
||||||
|
/// This function only returns true if the UI as a whole (e.g. window)
|
||||||
|
/// also has the keyboard focus. That makes this function suitable
|
||||||
|
/// for style choices, e.g. a thicker border around focused widgets.
|
||||||
pub fn has_focus(&self) -> bool {
|
pub fn has_focus(&self) -> bool {
|
||||||
self.ctx.memory().has_focus(self.id)
|
// Access input and memory in separate statements to prevent deadlock.
|
||||||
|
let has_global_focus = self.ctx.input().raw.has_focus;
|
||||||
|
has_global_focus && self.ctx.memory().has_focus(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True if this widget has keyboard focus this frame, but didn't last frame.
|
/// True if this widget has keyboard focus this frame, but didn't last frame.
|
||||||
|
|
Loading…
Reference in a new issue