From 85e661dbf099e66c3e5f32a20eac1ec1b03114b6 Mon Sep 17 00:00:00 2001 From: Stefano Ceccherini Date: Thu, 10 Jan 2008 14:06:11 +0000 Subject: [PATCH] Merged (parts of, for now) patches from Rene Gollent and Christof Lutteroth, which improve menu keyboard navigation. Sorry for the delay, I had these patches sitting on my hard drive for a while. At least now you can open a menu with ALT + ESC, navigate it with the arrow keys, and invoke an item. Various issues still exist, including: menubars don't get the keydown messages, and if you keep the mouse over the menu while navigating with the keyboard, nothing will happen. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23339 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/interface/Menu.cpp | 66 ++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/src/kits/interface/Menu.cpp b/src/kits/interface/Menu.cpp index 5f7926fa1b..b150781200 100644 --- a/src/kits/interface/Menu.cpp +++ b/src/kits/interface/Menu.cpp @@ -1,10 +1,11 @@ /* - * Copyright 2001-2007, Haiku, Inc. + * Copyright 2001-2008, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: * Marc Flerackers (mflerackers@androme.be) - * Stefano Ceccherini (burton666@libero.it) + * Stefano Ceccherini (stefano.ceccherini@gmail.com) + * Rene Gollent (anevilyak@gmail.com) */ #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -831,11 +833,36 @@ BMenu::KeyDown(const char *bytes, int32 numBytes) case B_LEFT_ARROW: if (fLayout == B_ITEMS_IN_ROW) _SelectNextItem(fSelected, false); + else { + // this case has to be handled a bit specially. + BMenuItem *item = Superitem(); + if (item) { + if (dynamic_cast(Supermenu())) { + // if we're at the top menu below the menu bar, pass the keypress to + // the menu bar so we can move to another top level menu + BMessenger msgr(Supermenu()); + msgr.SendMessage(Window()->CurrentMessage()); + } else + Supermenu()->_SelectItem(item, false, false); + } + } break; case B_RIGHT_ARROW: if (fLayout == B_ITEMS_IN_ROW) _SelectNextItem(fSelected, true); + else { + if (fSelected && fSelected->Submenu()) { + _SelectItem(fSelected, true, true); + } else if (dynamic_cast(Supermenu())) { + // if we have no submenu and we're an + // item in the top menu below the menubar, + // pass the keypress to the menubar + // so you can use the keypress to switch menus. + BMessenger msgr(Supermenu()); + msgr.SendMessage(Window()->CurrentMessage()); + } + } break; case B_ENTER: @@ -2121,11 +2148,14 @@ BMenu::_SelectItem(BMenuItem* menuItem, bool showSubmenu, bool selectFirstItem) bool BMenu::_SelectNextItem(BMenuItem *item, bool forward) { + if (CountItems() == 0) // cannot select next item in an empty menu + return false; + BMenuItem *nextItem = _NextItem(item, forward); if (nextItem == NULL) return false; - _SelectItem(nextItem); + _SelectItem(nextItem, false); return true; } @@ -2133,21 +2163,34 @@ BMenu::_SelectNextItem(BMenuItem *item, bool forward) BMenuItem * BMenu::_NextItem(BMenuItem *item, bool forward) const { - if (item == NULL) { + /*if (item == NULL) { if (forward) return ItemAt(CountItems() - 1); return ItemAt(0); } +*/ + // go to next item, and skip over disabled items such as separators + int32 index = fItems.IndexOf(item); + if (index < 0) + index = 0; - int32 index = fItems.IndexOf(item); - if (forward) - index++; - else - index--; + int32 startIndex = index; + do { + if (forward) + index++; + else + index--; + + // cycle through menu items + if (index < 0) + index = CountItems() - 1; + else if(index >= fItems.CountItems()) + index = 0; + } while (!ItemAt(index)->IsEnabled() && index != startIndex); - if (index < 0 || index >= fItems.CountItems()) - return NULL; + if (index == startIndex) // we are back where we started and no item was enabled + return false; return ItemAt(index); } @@ -2343,6 +2386,7 @@ BMenu::QuitTracking() fChosenItem = NULL; fState = MENU_STATE_CLOSED; + _Hide(); }