Skip to content

Commit

Permalink
Fix focus problems
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasmerlin committed Nov 14, 2024
1 parent 0b7f8de commit d4019c3
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 13 deletions.
3 changes: 2 additions & 1 deletion crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1160,7 +1160,8 @@ impl Context {
/// same widget, then `allow_focus` should only be true once (like in [`Ui::new`] (true) and [`Ui::remember_min_rect`] (false)).
#[allow(clippy::too_many_arguments)]
pub(crate) fn create_widget(&self, w: WidgetRect, allow_focus: bool) -> Response {
let interested_in_focus = w.enabled && w.sense.focusable && w.layer_id.allow_interaction();
let interested_in_focus =
w.enabled && w.sense.focusable && self.memory(|mem| mem.allows_interaction(w.layer_id));

// Remember this widget
self.write(|ctx| {
Expand Down
1 change: 1 addition & 0 deletions crates/egui/src/layers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl LayerId {
}

#[inline(always)]
#[deprecated = "Use `Memory::allows_interaction` instead"]
pub fn allow_interaction(&self) -> bool {
self.order.allow_interaction()
}
Expand Down
38 changes: 26 additions & 12 deletions crates/egui/src/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ impl Focus {
self.id_previous_frame == Some(id)
}

fn interested_in_focus(&mut self, id: Id, layer_id: LayerId) {
fn interested_in_focus(&mut self, id: Id) {
#[cfg(feature = "accesskit")]
{
if self.id_requested_by_accesskit == Some(id.accesskit_id()) {
Expand Down Expand Up @@ -687,6 +687,10 @@ impl Focus {
self.top_modal_layer_current_frame = Some(layer_id);
}

pub(crate) fn top_modal_layer(&self) -> Option<LayerId> {
self.top_modal_layer
}

fn reset_focus(&mut self) {
self.focus_direction = FocusDirection::None;
}
Expand Down Expand Up @@ -888,6 +892,24 @@ impl Memory {
}
}

/// Does this layer allow interaction?
/// Returns true if
/// - the layer is not behind a modal layer
/// - the [`Order`] allows interaction
pub fn allows_interaction(&self, layer_id: LayerId) -> bool {
let is_above_modal_layer =
if let Some(modal_layer) = self.focus().and_then(|f| f.top_modal_layer) {
matches!(
self.areas().compare_order(layer_id, modal_layer),
std::cmp::Ordering::Equal | std::cmp::Ordering::Greater
)
} else {
true
};
let ordering_allows_interaction = layer_id.order.allow_interaction();
is_above_modal_layer && ordering_allows_interaction
}

/// Register this widget as being interested in getting keyboard focus.
/// This will allow the user to select it with tab and shift-tab.
/// This is normally done automatically when handling interactions,
Expand All @@ -899,24 +921,16 @@ impl Memory {
/// Pass in the `layer_id` of the layer that the widget is in.
#[inline(always)]
pub fn interested_in_focus(&mut self, id: Id, layer_id: LayerId) {
// If the widget is on a layer below the current modal layer, ignore it.
if let Some(modal_layer) = self.focus().and_then(|f| f.top_modal_layer) {
if matches!(
self.areas().compare_order(layer_id, modal_layer),
std::cmp::Ordering::Less
) {
return;
}
if !self.allows_interaction(layer_id) {
return;
}

self.focus_mut().interested_in_focus(id, layer_id);
self.focus_mut().interested_in_focus(id);
}

/// Limit focus to widgets on the given layer and above.
/// If this is called multiple times per frame, the top layer wins.
pub fn set_modal_layer(&mut self, layer_id: LayerId) {
if let Some(current) = self.focus().and_then(|f| f.top_modal_layer_current_frame) {
dbg!(self.areas().compare_order(layer_id, current));
if matches!(
self.areas().compare_order(layer_id, current),
std::cmp::Ordering::Less
Expand Down

0 comments on commit d4019c3

Please sign in to comment.