Skip to content

Commit

Permalink
Fixed shift-tab to direct parent
Browse files Browse the repository at this point in the history
Closes #224
  • Loading branch information
ecton committed Nov 28, 2024
1 parent 5e2819a commit 3a4b37a
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 7 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Widgets of 0-size are now still rendered, even though all the drawing
operations will be clipped away. This allows the `ComponentProbe` to still
actively probe when placed in a location and given no space.
- Focus order when reversing now correctly evaluates direct parent widgets.
Prior to this change, placing a button inside of a button would not allow
shift-tab to focus the outer button when focus was on the inner button.

### Added

Expand Down
47 changes: 40 additions & 7 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,14 @@ impl<'context> EventContext<'context> {
}

fn next_focus_after(&mut self, mut focus: MountedWidget, advance: bool) -> Option<WidgetId> {
// First, look within the current focus for any focusable children.
// First, look within the current focus for any focusable children if we
// are advancing the focus. If we are reversing, we will wait to
// consider children as part of the reverse scan.
let stop_at = focus.id();
if let Some(focus) = self.next_focus_within(&focus, None, stop_at, advance) {
return Some(focus);
if advance {
if let Some(focus) = self.next_focus_within(&focus, None, stop_at, advance) {
return Some(focus);
}
}

// Now, look for the next widget in each hierarchy
Expand All @@ -354,6 +358,16 @@ impl<'context> EventContext<'context> {
let Some(parent) = focus.parent() else {
break focus;
};
// If we're reversing focus, we need to consider the parent itself
// as a focus target.
let accept_focus = !advance
&& parent
.lock()
.as_widget()
.accept_focus(&mut self.for_other(&parent));
if accept_focus {
return Some(parent.id());
}
focus = parent;
};

Expand Down Expand Up @@ -415,20 +429,39 @@ impl<'context> EventContext<'context> {
children.next();
}

// Check each child if it can accept focus. When advancing, this is done
// before evaluating the children's children, but when reversing this is
// done after evaluating the children's children.
for child in children {
let mut child_context = self.for_other(&child);
let accept_focus = child.lock().as_widget().accept_focus(&mut child_context);
drop(child_context);
let accept_focus = advance
&& child
.lock()
.as_widget()
.accept_focus(&mut self.for_other(&child));
if accept_focus {
return Some(child.id());
} else if stop_at == child.id() {
} else if stop_at == child.id() && advance {
// We cycled completely, and the original widget didn't accept
// focus.
return None;
} else if let Some(next_focus) = self.widget().explicit_focus_target(advance) {
return Some(next_focus.id());
} else if let Some(focus) = self.next_focus_within(&child, None, stop_at, advance) {
return Some(focus);
} else if !advance {
// When we are reversing, we needed to evaluate this child's
// children first. After checking its children, we need to also
// check that this isn't the stop_at widget before we try
// focusing this child.
if stop_at == child.id() {
return None;
} else if child
.lock()
.as_widget()
.accept_focus(&mut self.for_other(&child))
{
return Some(child.id());
}
}
}

Expand Down

0 comments on commit 3a4b37a

Please sign in to comment.