diff --git a/headers/os/interface/MenuField.h b/headers/os/interface/MenuField.h index fdd988d4ea..4468d23910 100644 --- a/headers/os/interface/MenuField.h +++ b/headers/os/interface/MenuField.h @@ -42,7 +42,7 @@ public: virtual void AllAttached(); virtual void MouseDown(BPoint where); virtual void KeyDown(const char* bytes, int32 numBytes); - virtual void MakeFocus(bool state); + virtual void MakeFocus(bool focused); virtual void MessageReceived(BMessage* message); virtual void WindowActivated(bool state); virtual void MouseUp(BPoint where); diff --git a/src/kits/interface/BMCPrivate.cpp b/src/kits/interface/BMCPrivate.cpp index 5ceccecd7c..70a04135bc 100644 --- a/src/kits/interface/BMCPrivate.cpp +++ b/src/kits/interface/BMCPrivate.cpp @@ -22,6 +22,12 @@ #include +static const float kPopUpIndicatorWidth = 13.0f; + + +// #pragma mark - _BMCFilter_ + + _BMCFilter_::_BMCFilter_(BMenuField* menuField, uint32 what) : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, what), @@ -52,10 +58,7 @@ _BMCFilter_::Filter(BMessage* message, BHandler** handler) } -// #pragma mark - - - -static const float kPopUpIndicatorWidth = 13.0f; +// #pragma mark - _BMCMenuBar_ _BMCMenuBar_::_BMCMenuBar_(BRect frame, bool fixedSize, BMenuField* menuField) @@ -105,6 +108,9 @@ _BMCMenuBar_::~_BMCMenuBar_() } +// #pragma mark - _BMCMenuBar_ public methods + + BArchivable* _BMCMenuBar_::Instantiate(BMessage* data) { @@ -311,6 +317,9 @@ _BMCMenuBar_::MaxSize() } +// #pragma mark - _BMCMenuBar_ private methods + + void _BMCMenuBar_::_Init() { diff --git a/src/kits/interface/Menu.cpp b/src/kits/interface/Menu.cpp index 4eb9f45105..e4bb30abab 100644 --- a/src/kits/interface/Menu.cpp +++ b/src/kits/interface/Menu.cpp @@ -476,7 +476,7 @@ BMenu::MessageReceived(BMessage* msg) void BMenu::KeyDown(const char* bytes, int32 numBytes) { - // TODO: Test how it works on beos and implement it correctly + // TODO: Test how it works on BeOS R5 and implement this correctly switch (bytes[0]) { case B_UP_ARROW: if (fLayout == B_ITEMS_IN_COLUMN) @@ -484,16 +484,16 @@ BMenu::KeyDown(const char* bytes, int32 numBytes) break; case B_DOWN_ARROW: - { - BMenuBar* bar = dynamic_cast(Supermenu()); - if (bar != NULL && fState == MENU_STATE_CLOSED) { - // tell MenuBar's _Track: - bar->fState = MENU_STATE_KEY_TO_SUBMENU; - } + { + BMenuBar* bar = dynamic_cast(Supermenu()); + if (bar != NULL && fState == MENU_STATE_CLOSED) { + // tell MenuBar's _Track: + bar->fState = MENU_STATE_KEY_TO_SUBMENU; } if (fLayout == B_ITEMS_IN_COLUMN) _SelectNextItem(fSelected, true); break; + } case B_LEFT_ARROW: if (fLayout == B_ITEMS_IN_ROW) @@ -520,7 +520,7 @@ BMenu::KeyDown(const char* bytes, int32 numBytes) if (fLayout == B_ITEMS_IN_ROW) _SelectNextItem(fSelected, true); else { - if (fSelected && fSelected->Submenu()) { + if (fSelected != NULL && fSelected->Submenu() != NULL) { fSelected->Submenu()->_SetStickyMode(true); // fix me: this shouldn't be needed but dynamic menus // aren't getting it set correctly when keyboard @@ -555,19 +555,20 @@ BMenu::KeyDown(const char* bytes, int32 numBytes) case B_ENTER: case B_SPACE: - if (fSelected) { - // preserve for exit handling + if (fSelected != NULL) { fChosenItem = fSelected; + // preserve for exit handling _QuitTracking(false); } break; case B_ESCAPE: _SelectItem(NULL); - if (fState == MENU_STATE_CLOSED && dynamic_cast(Supermenu())) { + if (fState == MENU_STATE_CLOSED + && dynamic_cast(Supermenu())) { // Keyboard may show menu without tracking it - BMessenger msgr(Supermenu()); - msgr.SendMessage(Window()->CurrentMessage()); + BMessenger messenger(Supermenu()); + messenger.SendMessage(Window()->CurrentMessage()); } else _QuitTracking(false); break; @@ -1585,11 +1586,10 @@ BMenu::_Hide() else #endif window->Quit(); - // it's our window, quit it + // it's our window, quit it - - // Delete the menu window used by our submenus _DeleteMenuWindow(); + // Delete the menu window used by our submenus } @@ -1611,8 +1611,8 @@ BMenu::_Track(int* action, long start) bigtime_t navigationAreaTime = 0; fState = MENU_STATE_TRACKING; - // we will use this for keyboard selection: fChosenItem = NULL; + // we will use this for keyboard selection BPoint location; uint32 buttons = 0; @@ -1642,7 +1642,7 @@ BMenu::_Track(int* action, long start) // then if the mouse is inside this menu, // then if it's over a super menu. if (_OverSubmenu(fSelected, screenLocation) - || fState == MENU_STATE_KEY_TO_SUBMENU) { + || fState == MENU_STATE_KEY_TO_SUBMENU) { if (fState == MENU_STATE_TRACKING) { // not if from R.Arrow fState = MENU_STATE_TRACKING_SUBMENU; @@ -1669,7 +1669,7 @@ BMenu::_Track(int* action, long start) fState = MENU_STATE_CLOSED; } else if (submenuAction == MENU_STATE_KEY_LEAVE_SUBMENU) { if (LockLooper()) { - BMenuItem *temp = fSelected; + BMenuItem* temp = fSelected; // close the submenu: _SelectItem(NULL); // but reselect the item itself for user: @@ -1686,14 +1686,16 @@ BMenu::_Track(int* action, long start) _UpdateStateOpenSelect(item, location, navAreaRectAbove, navAreaRectBelow, selectedTime, navigationAreaTime); releasedOnce = true; - } else if (_OverSuper(screenLocation) && fSuper->fState != MENU_STATE_KEY_TO_SUBMENU) { + } else if (_OverSuper(screenLocation) + && fSuper->fState != MENU_STATE_KEY_TO_SUBMENU) { fState = MENU_STATE_TRACKING; UnlockLooper(); break; } else if (fState == MENU_STATE_KEY_LEAVE_SUBMENU) { UnlockLooper(); break; - } else if (fSuper == NULL || fSuper->fState != MENU_STATE_KEY_TO_SUBMENU) { + } else if (fSuper == NULL + || fSuper->fState != MENU_STATE_KEY_TO_SUBMENU) { // Mouse pointer outside menu: // If there's no other submenu opened, // deselect the current selected item @@ -1733,7 +1735,7 @@ BMenu::_Track(int* action, long start) UnlockLooper(); } while (newLocation == location && newButtons == buttons && !(item != NULL && item->Submenu() != NULL - && item->Submenu()->Window() == NULL) + && item->Submenu()->Window() == NULL) && fState == MENU_STATE_TRACKING); if (newLocation != location || newButtons != buttons) { @@ -1754,9 +1756,10 @@ BMenu::_Track(int* action, long start) // keyboard Enter will set this if (fChosenItem != NULL) item = fChosenItem; - else if (fSelected == NULL) + else if (fSelected == NULL) { // needed to cover (rare) mouse/ESC combination item = NULL; + } if (fSelected != NULL && LockLooper()) { _SelectItem(NULL); @@ -2591,12 +2594,12 @@ BMenu::_Uninstall() void -BMenu::_SelectItem(BMenuItem* menuItem, bool showSubmenu, - bool selectFirstItem, bool keyDown) +BMenu::_SelectItem(BMenuItem* item, bool showSubmenu, bool selectFirstItem, + bool keyDown) { // Avoid deselecting and then reselecting the same item // which would cause flickering - if (menuItem != fSelected) { + if (item != fSelected) { if (fSelected != NULL) { fSelected->Select(false); BMenu* subMenu = fSelected->Submenu(); @@ -2604,7 +2607,7 @@ BMenu::_SelectItem(BMenuItem* menuItem, bool showSubmenu, subMenu->_Hide(); } - fSelected = menuItem; + fSelected = item; if (fSelected != NULL) fSelected->Select(true); } @@ -2632,10 +2635,8 @@ BMenu::_SelectNextItem(BMenuItem* item, bool forward) if (nextItem == NULL) return false; - bool openMenu = false; - if (dynamic_cast(this) != NULL) - openMenu = true; - _SelectItem(nextItem, openMenu); + _SelectItem(nextItem, dynamic_cast(this) != NULL); + return true; } @@ -2688,15 +2689,15 @@ BMenu::_SetStickyMode(bool on) fStickyMode = on; - // If we are switching to sticky mode, propagate the status - // back to the super menu - if (fSuper != NULL) + if (fSuper != NULL) { + // propagate the status to the super menu fSuper->_SetStickyMode(on); - else { - // TODO: Ugly hack, but it needs to be done right here in this method + } else { + // TODO: Ugly hack, but it needs to be done in this method BMenuBar* menuBar = dynamic_cast(this); if (on && menuBar != NULL && menuBar->LockLooper()) { - // Steal the focus from the current focus view + // If we are switching to sticky mode, + // steal the focus from the current focus view // (needed to handle keyboard navigation) menuBar->_StealFocus(); menuBar->UnlockLooper(); @@ -2946,8 +2947,9 @@ BMenu::_OkToProceed(BMenuItem* item, bool keyDown) if ((buttons != 0 && stickyMode) || ((dynamic_cast(this) == NULL && (buttons == 0 && !stickyMode)) - || ((_HitTestItems(where) != item) && !keyDown))) + || ((_HitTestItems(where) != item) && !keyDown))) { return false; + } return true; } diff --git a/src/kits/interface/MenuBar.cpp b/src/kits/interface/MenuBar.cpp index 3b7e885076..139123e5cd 100644 --- a/src/kits/interface/MenuBar.cpp +++ b/src/kits/interface/MenuBar.cpp @@ -528,8 +528,10 @@ BMenuItem* BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) { // TODO: Cleanup, merge some "if" blocks if possible - fChosenItem = NULL; + BMenuItem* item = NULL; fState = MENU_STATE_TRACKING; + fChosenItem = NULL; + // we will use this for keyboard selection BPoint where; uint32 buttons; @@ -547,22 +549,19 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) if (!LockLooper()) break; - BMenuItem* menuItem = NULL; - if (dynamic_cast<_BMCMenuBar_*>(this)) - menuItem = ItemAt(0); - else - menuItem = _HitTestItems(where, B_ORIGIN); + item = dynamic_cast<_BMCMenuBar_*>(this) != NULL ? ItemAt(0) + : _HitTestItems(where, B_ORIGIN); + if (_OverSubmenu(fSelected, ConvertToScreen(where)) || fState == MENU_STATE_KEY_TO_SUBMENU) { // call _Track() from the selected sub-menu when the mouse cursor // is over its window - BMenu* menu = fSelected->Submenu(); + BMenu* submenu = fSelected->Submenu(); UnlockLooper(); snoozeAmount = 30000; - bool wasSticky = _IsStickyMode(); - menu->_SetStickyMode(wasSticky); + submenu->_SetStickyMode(_IsStickyMode()); int localAction; - fChosenItem = menu->_Track(&localAction); + fChosenItem = submenu->_Track(&localAction); // The mouse could have meen moved since the last time we // checked its position, or buttons might have been pressed. @@ -577,13 +576,13 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) UnlockLooper(); } - // This code is needed to make menus - // that are children of BMenuFields "sticky" (see ticket #953) + // Needed to make BMenuField child menus "sticky" + // (see ticket #953) if (localAction == MENU_STATE_CLOSED) { if (fExtraRect != NULL && fExtraRect->Contains(where) + && point_distance(newWhere, where) < 9) { // 9 = 3 pixels ^ 2 (since point_distance() returns the // square of the distance) - && point_distance(newWhere, where) < 9) { _SetStickyMode(true); fExtraRect = NULL; } else @@ -591,11 +590,11 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) } if (!LockLooper()) break; - } else if (menuItem != NULL) { - if (menuItem->Submenu() != NULL && menuItem != fSelected) { - if (menuItem->Submenu()->Window() == NULL) { + } else if (item != NULL) { + if (item->Submenu() != NULL && item != fSelected) { + if (item->Submenu()->Window() == NULL) { // open the menu if it's not opened yet - _SelectItem(menuItem); + _SelectItem(item); } else { // Menu was already opened, close it and bail _SelectItem(NULL); @@ -604,9 +603,9 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) } } else { // No submenu, just select the item - _SelectItem(menuItem); + _SelectItem(item); } - } else if (menuItem == NULL && fSelected != NULL + } else if (item == NULL && fSelected != NULL && !_IsStickyMode() && Bounds().Contains(where)) { _SelectItem(NULL); fState = MENU_STATE_TRACKING; @@ -615,38 +614,42 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) UnlockLooper(); if (fState != MENU_STATE_CLOSED) { - // If user doesn't move the mouse, loop here, - // so we don't interfere with keyboard menu navigation - BPoint newLocation = where; + BPoint newWhere = where; uint32 newButtons = buttons; + do { + // If user doesn't move the mouse or change buttons loop + // here so that we don't interfere with keyboard menu + // navigation snooze(snoozeAmount); if (!LockLooper()) break; - GetMouse(&newLocation, &newButtons, true); + + GetMouse(&newWhere, &newButtons); UnlockLooper(); - } while (newLocation == where && newButtons == buttons + } while (newWhere == where && newButtons == buttons && fState == MENU_STATE_TRACKING); - where = newLocation; - buttons = newButtons; - - if (buttons != 0 && _IsStickyMode()) { - if (menuItem == NULL - || (menuItem->Submenu() && menuItem->Submenu()->Window())) { - // clicked outside menu bar or on item with already + if (newButtons != 0 && _IsStickyMode()) { + if (item == NULL || (item->Submenu() != NULL + && item->Submenu()->Window() != NULL)) { + // clicked outside the menu bar or on item with already // open sub menu fState = MENU_STATE_CLOSED; } else _SetStickyMode(false); - } else if (buttons == 0 && !_IsStickyMode()) { + } else if (newButtons == 0 && !_IsStickyMode()) { if ((fSelected != NULL && fSelected->Submenu() == NULL) - || menuItem == NULL) { + || item == NULL) { + // clicked on an item without a submenu or clicked and + // released the mouse button outside the menu bar fChosenItem = fSelected; fState = MENU_STATE_CLOSED; } else _SetStickyMode(true); } + where = newWhere; + buttons = newButtons; } } @@ -656,6 +659,7 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) if (fChosenItem != NULL) fChosenItem->Invoke(); + _RestoreFocus(); UnlockLooper(); } @@ -681,9 +685,9 @@ BMenuBar::_StealFocus() BWindow* window = Window(); if (window != NULL && window->Lock()) { - BView* focus = window->CurrentFocus(); - if (focus != NULL && focus != this) - fPrevFocusToken = _get_object_token_(focus); + BView* focusView = window->CurrentFocus(); + if (focusView != NULL && focusView != this) + fPrevFocusToken = _get_object_token_(focusView); MakeFocus(); window->Unlock(); } @@ -702,7 +706,6 @@ BMenuBar::_RestoreFocus() BView* view = dynamic_cast(handler); if (view != NULL && view->Window() == window) view->MakeFocus(); - } else if (IsFocus()) MakeFocus(false); diff --git a/src/kits/interface/MenuField.cpp b/src/kits/interface/MenuField.cpp index 1a5187ff29..307ecdbcda 100644 --- a/src/kits/interface/MenuField.cpp +++ b/src/kits/interface/MenuField.cpp @@ -47,6 +47,10 @@ #endif +static const float kMinMenuBarWidth = 20.0f; + // found by experimenting on BeOS R5 + + namespace { const char* const kFrameField = "BMenuField:layoutItem:frame"; const char* const kMenuBarItemField = "BMenuField:barItem"; @@ -54,6 +58,9 @@ namespace { } +// #pragma mark - LabelLayoutItem + + class BMenuField::LabelLayoutItem : public BAbstractLayoutItem { public: LabelLayoutItem(BMenuField* parent); @@ -82,6 +89,9 @@ private: }; +// #pragma mark - MenuBarLayoutItem + + class BMenuField::MenuBarLayoutItem : public BAbstractLayoutItem { public: MenuBarLayoutItem(BMenuField* parent); @@ -110,6 +120,9 @@ private: }; +// #pragma mark - LayoutData + + struct BMenuField::LayoutData { LayoutData() : @@ -133,11 +146,7 @@ struct BMenuField::LayoutData { }; -// #pragma mark - - - -static const float kMinMenuBarWidth = 20.0f; - // found by experimenting on BeOS R5 +// #pragma mark - BMenuField using BPrivate::MenuPrivate; @@ -463,14 +472,14 @@ BMenuField::KeyDown(const char* bytes, int32 numBytes) void -BMenuField::MakeFocus(bool state) +BMenuField::MakeFocus(bool focused) { - if (IsFocus() == state) + if (IsFocus() == focused) return; - BView::MakeFocus(state); + BView::MakeFocus(focused); - if (Window()) + if (Window() != NULL) Invalidate(); // TODO: use fLayoutData->label_width }