diff --git a/headers/private/interface/MenuPrivate.h b/headers/private/interface/MenuPrivate.h index 71e13ae60f..3cf85afac5 100644 --- a/headers/private/interface/MenuPrivate.h +++ b/headers/private/interface/MenuPrivate.h @@ -2,10 +2,10 @@ #define __MENU_PRIVATE_H -enum menu_actions { - MENU_ACT_NONE = 0, - MENU_ACT_SUBMENU = 1, - MENU_ACT_CLOSE = 5 +enum menu_states { + MENU_STATE_TRACKING = 0, + MENU_STATE_TRACKING_SUBMENU = 1, + MENU_STATE_CLOSED = 5 }; diff --git a/src/kits/interface/Menu.cpp b/src/kits/interface/Menu.cpp index 169202271e..de94810604 100644 --- a/src/kits/interface/Menu.cpp +++ b/src/kits/interface/Menu.cpp @@ -236,47 +236,21 @@ BMenu::Archive(BMessage *data, bool deep) const { status_t err = BView::Archive(data, deep); - if (err < B_OK) - return err; - - if (Layout() != B_ITEMS_IN_ROW) { + if (err == B_OK && Layout() != B_ITEMS_IN_ROW) err = data->AddInt32("_layout", Layout()); - - if (err < B_OK) - return err; - } - - err = data->AddBool("_rsize_to_fit", fResizeToFit); - - if (err < B_OK) - return err; - - err = data->AddBool("_disable", !IsEnabled()); - - if (err < B_OK) - return err; - - err = data->AddBool("_radio", IsRadioMode()); - - if (err < B_OK) - return err; - - err = data->AddBool("_trig_disabled", AreTriggersEnabled()); - - if (err < B_OK) - return err; - - err = data->AddBool("_dyn_label", fDynamicName); - - if (err < B_OK) - return err; - - err = data->AddFloat("_maxwidth", fMaxContentWidth); - - if (err < B_OK) - return err; - - if (deep) { + if (err == B_OK) + err = data->AddBool("_rsize_to_fit", fResizeToFit); + if (err == B_OK) + err = data->AddBool("_disable", !IsEnabled()); + if (err == B_OK) + err = data->AddBool("_radio", IsRadioMode()); + if (err == B_OK) + err = data->AddBool("_trig_disabled", AreTriggersEnabled()); + if (err == B_OK) + err = data->AddBool("_dyn_label", fDynamicName); + if (err == B_OK) + err = data->AddFloat("_maxwidth", fMaxContentWidth); + if (err == B_OK && deep) { // TODO store items and rects } @@ -1129,7 +1103,7 @@ BMenu::_show(bool selectFirstItem) UpdateWindowViewSize(); window->Show(); - + if (selectFirstItem) SelectItem(ItemAt(0)); @@ -1175,9 +1149,17 @@ BMenu::_track(int *action, bigtime_t trackTime, long start) bigtime_t openTime = system_time(); bigtime_t closeTime = openTime; - fState = MENU_ACT_NONE; - + fState = MENU_STATE_TRACKING; + if (fSuper != NULL) + fSuper->fState = MENU_STATE_TRACKING_SUBMENU; + while (true) { + if (fExtraMenuData != NULL && fExtraMenuData->trackingHook != NULL + && fExtraMenuData->trackingState != NULL) { + bool result = fExtraMenuData->trackingHook(this, fExtraMenuData->trackingState); + //printf("tracking hook returned %s\n", result ? "true" : "false"); + } + bool locked = LockLooper(); if (!locked) break; @@ -1190,37 +1172,35 @@ BMenu::_track(int *action, bigtime_t trackTime, long start) BPoint screenLocation = ConvertToScreen(location); item = HitTestItems(location, B_ORIGIN); if (item != NULL) { - if (item != fSelected - && (fState != MENU_ACT_SUBMENU || system_time() > closeTime + kHysteresis)) { + if (item != fSelected && system_time() > closeTime + kHysteresis) { SelectItem(item, -1); openTime = system_time(); - fState = MENU_ACT_NONE; - snoozeAmount = 20000; } else if (system_time() > kHysteresis + openTime && item->Submenu() != NULL && item->Submenu()->Window() == NULL) { // Open the submenu if it's not opened yet, but only if // the mouse pointer stayed over there for some time // (hysteresis) SelectItem(item); - fState = MENU_ACT_SUBMENU; closeTime = system_time(); } + fState = MENU_STATE_TRACKING; } - // Track the submenu if (fSelected != NULL && OverSubmenu(fSelected, screenLocation)) { UnlockLooper(); locked = false; - int submenuAction = MENU_ACT_NONE; + int submenuAction = MENU_STATE_TRACKING; + BMenu *submenu = fSelected->Submenu(); if (IsStickyMode()) - fSelected->Submenu()->SetStickyMode(true); - BMenuItem *submenuItem = fSelected->Submenu()->_track(&submenuAction, trackTime); - if (submenuAction == MENU_ACT_CLOSE) { + submenu->SetStickyMode(true); + BMenuItem *submenuItem = submenu->_track(&submenuAction, trackTime); + if (submenuAction == MENU_STATE_CLOSED) { item = submenuItem; fState = submenuAction; break; } + locked = LockLooper(); if (!locked) break; @@ -1228,29 +1208,38 @@ BMenu::_track(int *action, bigtime_t trackTime, long start) if (item == NULL) { if (OverSuper(screenLocation)) { - fState = MENU_ACT_NONE; + fState = MENU_STATE_TRACKING; UnlockLooper(); break; } + if (fSelected != NULL && !OverSubmenu(fSelected, screenLocation) - && (fState != MENU_ACT_SUBMENU || system_time() > closeTime + kHysteresis)) { + && system_time() > closeTime + kHysteresis + && fState != MENU_STATE_TRACKING_SUBMENU) { SelectItem(NULL); - fState = MENU_ACT_NONE; + fState = MENU_STATE_TRACKING; + } + + if (fSuper != NULL) { + if (locked) + UnlockLooper(); + *action = fState; + return NULL; } } - + if (locked) UnlockLooper(); - + if (buttons != 0 && IsStickyMode()) { - fState = MENU_ACT_CLOSE; + fState = MENU_STATE_CLOSED; break; } else if (buttons == 0 && !IsStickyMode()) { if (system_time() < trackTime + 1000000 || (fExtraRect != NULL && fExtraRect->Contains(location))) SetStickyMode(true); else { - fState = MENU_ACT_CLOSE; + fState = MENU_STATE_CLOSED; break; } } @@ -1261,7 +1250,7 @@ BMenu::_track(int *action, bigtime_t trackTime, long start) if (action != NULL) *action = fState; - if (LockLooper()) { + if (fSelected != NULL && LockLooper()) { SelectItem(NULL); UnlockLooper(); } @@ -1918,7 +1907,8 @@ BMenu::UpdateWindowViewSize(bool upWind) window->ResizeTo(Bounds().Width() + 2, Bounds().Height() + 2); else { CacheFontInfo(); - window->ResizeTo(StringWidth(kEmptyMenuLabel) + 5, fFontHeight + 6); + window->ResizeTo(StringWidth(kEmptyMenuLabel) + fPad.left + fPad.right, + fFontHeight + fPad.top + fPad.bottom); } window->MoveTo(frame.LeftTop()); } diff --git a/src/kits/interface/MenuBar.cpp b/src/kits/interface/MenuBar.cpp index 798fd0c752..f2089d1556 100644 --- a/src/kits/interface/MenuBar.cpp +++ b/src/kits/interface/MenuBar.cpp @@ -378,16 +378,16 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) // TODO: Cleanup, merge some "if" blocks if possible BMenuItem *resultItem = NULL; BWindow *window = Window(); - int localAction = MENU_ACT_NONE; + int localAction = MENU_STATE_TRACKING; while (true) { - bigtime_t snoozeAmount = 30000; + bigtime_t snoozeAmount = 40000; bool locked = window->Lock();//WithTimeout(200000) if (!locked) break; BPoint where; ulong buttons; - GetMouse(&where, &buttons); + GetMouse(&where, &buttons, true); BMenuItem *menuItem = HitTestItems(where, B_ORIGIN); if (menuItem != NULL) { // Select item if: @@ -406,7 +406,7 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) } else { // Menu was already opened, close it and bail SelectItem(NULL); - localAction = MENU_ACT_CLOSE; + localAction = MENU_STATE_CLOSED; resultItem = NULL; } } else { @@ -423,18 +423,20 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) if (menu != NULL) { window->Unlock(); locked = false; - snoozeAmount = 0; + snoozeAmount = 30000; if (IsStickyMode()) menu->SetStickyMode(true); resultItem = menu->_track(&localAction, system_time()); } - } else if (menuItem == NULL && !IsStickyMode()) + } else if (menuItem == NULL && !IsStickyMode()) { SelectItem(NULL); + fState = MENU_STATE_TRACKING; + } if (locked) window->Unlock(); - if (localAction == MENU_ACT_CLOSE || (buttons != 0 && IsStickyMode() && menuItem == NULL)) + if (localAction == MENU_STATE_CLOSED || (buttons != 0 && IsStickyMode() && menuItem == NULL)) break; else if (buttons == 0 && !IsStickyMode()) { // On an item without a submenu @@ -446,7 +448,7 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) } if (snoozeAmount > 0) - snooze(snoozeAmount); + snooze(snoozeAmount); } if (window->Lock()) {