1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-29 20:35:13 +00:00

LibGUI: Allow widget sibling navigation with arrow keys

There's no spatial navigation here, Left/Up moves to the previous
sibling in the tab order, while Right/Down moves to the next.

The arrow keys keep focus within the same parent widget, unlike the tab
key which cycles through all focusable widgets in the window.

This makes GUI::MessageBox feel a bit nicer since you can now arrow
between the Yes/No/Cancel buttons. :^)
This commit is contained in:
Andreas Kling 2021-01-02 01:54:30 +01:00
parent 7d72168b14
commit b4af4a4085
2 changed files with 27 additions and 11 deletions

View file

@ -445,13 +445,25 @@ void Widget::hide_event(HideEvent&)
void Widget::keydown_event(KeyEvent& event)
{
if (!event.alt() && !event.ctrl() && !event.logo() && event.key() == KeyCode::Key_Tab) {
if (event.shift())
focus_previous_widget(FocusSource::Keyboard);
else
focus_next_widget(FocusSource::Keyboard);
event.accept();
return;
if (!event.alt() && !event.ctrl() && !event.logo()) {
if (event.key() == KeyCode::Key_Tab) {
if (event.shift())
focus_previous_widget(FocusSource::Keyboard, false);
else
focus_next_widget(FocusSource::Keyboard, false);
event.accept();
return;
}
if (!event.shift() && (event.key() == KeyCode::Key_Left || event.key() == KeyCode::Key_Up)) {
focus_previous_widget(FocusSource::Keyboard, true);
event.accept();
return;
}
if (!event.shift() && (event.key() == KeyCode::Key_Right || event.key() == KeyCode::Key_Down)) {
focus_next_widget(FocusSource::Keyboard, true);
event.accept();
return;
}
}
event.ignore();
}
@ -822,9 +834,11 @@ void Widget::set_updates_enabled(bool enabled)
update();
}
void Widget::focus_previous_widget(FocusSource source)
void Widget::focus_previous_widget(FocusSource source, bool siblings_only)
{
auto focusable_widgets = window()->focusable_widgets(source);
if (siblings_only)
focusable_widgets.remove_all_matching([this](auto& entry) { return entry->parent() != parent(); });
for (int i = focusable_widgets.size() - 1; i >= 0; --i) {
if (focusable_widgets[i] != this)
continue;
@ -835,9 +849,11 @@ void Widget::focus_previous_widget(FocusSource source)
}
}
void Widget::focus_next_widget(FocusSource source)
void Widget::focus_next_widget(FocusSource source, bool siblings_only)
{
auto focusable_widgets = window()->focusable_widgets(source);
if (siblings_only)
focusable_widgets.remove_all_matching([this](auto& entry) { return entry->parent() != parent(); });
for (size_t i = 0; i < focusable_widgets.size(); ++i) {
if (focusable_widgets[i] != this)
continue;