Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change focused widget with arrow keys #3272

Merged
merged 13 commits into from
Aug 30, 2023

Conversation

TimonPost
Copy link
Contributor

@TimonPost TimonPost commented Aug 23, 2023

We have the use case of gamepad control for a user-facing game menu. This PR makes it possible to change widget focus with the keyboard arrows. It allows integrations to convert joysticks to arrow keys in order to toggle between menu items. It does not add support for gamepad events in egui as this seems like a bigger topic that I desire not to touch.

Initially, I examine the currently focused widget to determine the one with the highest dot product when compared to the desired focus direction. Subsequently, I identify the widget that is nearest to the current one. This process enables the selection of the widget in the desired direction which not only possesses the smallest angle relative to the current widget but also maintains the closest proximity.

The widget selection code can be improved over time ofcourse, there are some potential issues right now:

  • This solution has no sense of the window it exists in, so if a focusable widget in another window is a better candidate it will pick that one.
  • If I click in an input box the Focus::interested_in_focus is not called and thus I do not know what the interactable widgets and their rectangles are. I only know this after using a key like arrow or tab (+shift).

2023-08-23 13-07-13

Closes #1250

@TimonPost TimonPost force-pushed the timon/egui-arrow-gamepad-focus-switching branch from 737f617 to 866ba78 Compare August 23, 2023 11:33
@TimonPost TimonPost marked this pull request as ready for review August 23, 2023 11:45
Copy link
Owner

@emilk emilk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exciting!

The navigation works okish, but I left some ideas on how to improve it

crates/egui/src/memory.rs Outdated Show resolved Hide resolved
crates/egui/src/memory.rs Outdated Show resolved Hide resolved
crates/egui/src/memory.rs Outdated Show resolved Hide resolved
crates/egui/src/memory.rs Outdated Show resolved Hide resolved
crates/egui/src/memory.rs Outdated Show resolved Hide resolved
crates/egui/src/memory.rs Outdated Show resolved Hide resolved
crates/egui/src/memory.rs Outdated Show resolved Hide resolved
crates/egui/src/memory.rs Outdated Show resolved Hide resolved
crates/egui/src/memory.rs Outdated Show resolved Hide resolved
Comment on lines 20 to 22
name2: String,
age: u32,
age2: u32,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert the changes in this file. Use egui_demo_app (cargo r) for a better test of your code!

@TimonPost
Copy link
Contributor Author

TimonPost commented Aug 28, 2023

Thanks a lot for the feedback!

I updated the selection metric to use the ratio and rectangles but it is still not perfect.

focus_candidates.sort_by(|(_, dot1, len1), (_, dot2, len2)| {
    (len1 / dot1).partial_cmp(&(len2 / dot2)).unwrap()
});
focus_candidates.sort_by(|(_, dot1, _), (_, dot2, _)| dot2.partial_cmp(dot1).unwrap());

Not sorting by dot product afterward results in close-by widgets being picked even while they have a big angle. But sorting by dot product sometimes results in widgets further away but higher dot products being selected.

I wonder if other context needs to be brought in to make a better decision.

I don't know how perfect this feature is to be. It mostly works well. For our use case, we probably design the UI to be simple so that this algorithm works fine.

Another issue is that sometimes it's hard to tell where the focus went as it might be a window behind the current window or some widget in a different panel.

The rectangle thing improves the overall behavior so that was a nice change.

@TimonPost TimonPost requested a review from emilk August 28, 2023 14:51
crates/emath/src/range.rs Outdated Show resolved Hide resolved
crates/emath/src/range.rs Outdated Show resolved Hide resolved
@emilk emilk added the egui label Aug 29, 2023
Comment on lines +362 to +365
// The rect is updated at the end of the frame.
self.focus_widgets_cache
.entry(id)
.or_insert(Rect::EVERYTHING);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, no that makes sense 👍

@emilk emilk changed the title Allow widget focus change with keyboard arrows Change focused widget with arrow keys Aug 30, 2023
@emilk
Copy link
Owner

emilk commented Aug 30, 2023

There is still plenty of room for improvement, but this is a good start!

@Jakkestt
Copy link

It allows integrations to convert joysticks to arrow keys in order to toggle between menu items.
How do you do that?

@TimonPost
Copy link
Contributor Author

Gotta make some custom logic to achieve that. E.g detect the cardinal directions of the joystick and map them to key combo's

shouya added a commit to shouya/malakal that referenced this pull request Mar 4, 2024
This feature was introduced in
emilk/egui#3272. Since malakal implements its own
keyboard navigation it conflicts with egui's built-in arrow
navigation and causes the focus to jump around unexpectedly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Gampad and arrow-keys navigation support
3 participants