diff --git a/src/kits/interface/Menu.cpp b/src/kits/interface/Menu.cpp index c5b2d9d91c..f69a725a33 100644 --- a/src/kits/interface/Menu.cpp +++ b/src/kits/interface/Menu.cpp @@ -103,6 +103,9 @@ sPropList[] = { }; +const char *kEmptyMenuLabel = ""; + + BMenu::BMenu(const char *name, menu_layout layout) : BView(BRect(0, 0, 0, 0), name, 0, B_WILL_DRAW), fChosenItem(NULL), @@ -1096,9 +1099,6 @@ BMenu::_show(bool selectFirstItem) if (dynamic_cast(window) != NULL) MoveTo(1, 1); - // TODO: for some reason, Window() can already be NULL at this point, - // which causes a crash in one of the following functions... - // Does this still happens ? UpdateWindowViewSize(); window->Show(); @@ -1118,8 +1118,9 @@ BMenu::_hide() BMenuWindow *window = static_cast(Window()); if (window == NULL || !window->Lock()) return; - - SelectItem(NULL); + + if (fSelected != NULL) + SelectItem(NULL); window->Hide(); window->DetachMenu(); @@ -1135,17 +1136,20 @@ BMenu::_hide() } +const bigtime_t kHysteresis = 200000; // TODO: Test and reduce if needed. + + BMenuItem * BMenu::_track(int *action, bigtime_t trackTime, long start) { // TODO: cleanup - ulong buttons; BMenuItem *item = NULL; int localAction = MENU_ACT_NONE; - bigtime_t startTime = system_time(); - bigtime_t delay = 200000; // TODO: Test and reduce if needed. - + bigtime_t openTime = system_time(); + bigtime_t closeTime = openTime; + + fState = MENU_ACT_NONE; while (true) { bool locked = LockLooper(); if (!locked) @@ -1153,21 +1157,26 @@ BMenu::_track(int *action, bigtime_t trackTime, long start) bigtime_t snoozeAmount = 50000; BPoint location; + ulong buttons; GetMouse(&location, &buttons, false); BPoint screenLocation = ConvertToScreen(location); item = HitTestItems(location, B_ORIGIN); if (item != NULL) { - if (item != fSelected) { + if (item != fSelected + && (fState != MENU_ACT_SUBMENU || system_time() > closeTime + kHysteresis)) { SelectItem(item, -1); - startTime = system_time(); + openTime = system_time(); + fState = MENU_ACT_NONE; snoozeAmount = 20000; - } else if (system_time() > delay + startTime && item->Submenu() + } else if (system_time() > kHysteresis + openTime && item->Submenu() && 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(); } } else { if (OverSuper(screenLocation)) { @@ -1176,8 +1185,11 @@ BMenu::_track(int *action, bigtime_t trackTime, long start) UnlockLooper(); break; } - if (fSelected != NULL && !OverSubmenu(fSelected, screenLocation)) + if (fSelected != NULL && !OverSubmenu(fSelected, screenLocation) + && (fState != MENU_ACT_SUBMENU || system_time() > closeTime + kHysteresis)) { SelectItem(NULL); + fState = MENU_ACT_NONE; + } } if (fSelected != NULL && OverSubmenu(fSelected, screenLocation)) { @@ -1212,6 +1224,8 @@ BMenu::_track(int *action, bigtime_t trackTime, long start) } } + fState = MENU_ACT_CLOSE; + if (action != NULL) *action = localAction; diff --git a/src/kits/interface/MenuBar.cpp b/src/kits/interface/MenuBar.cpp index 4bfeb72c58..d7abf693ba 100644 --- a/src/kits/interface/MenuBar.cpp +++ b/src/kits/interface/MenuBar.cpp @@ -381,7 +381,6 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) BMenuItem *resultItem = NULL; BWindow *window = Window(); int localAction = MENU_ACT_NONE; - bigtime_t startTime = system_time(); while (true) { bigtime_t snoozeAmount = 30000; bool locked = window->Lock();//WithTimeout(200000) @@ -404,6 +403,8 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) if (menuItem->Submenu()->Window() == NULL) { // open the menu if it's not opened yet SelectItem(menuItem); + if (IsStickyMode()) + SetStickyMode(false); } else { // Menu was already opened, close it and bail SelectItem(NULL); @@ -427,7 +428,7 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) snoozeAmount = 0; if (IsStickyMode()) menu->SetStickyMode(true); - resultItem = menu->_track(&localAction, startTime); + resultItem = menu->_track(&localAction, system_time()); } } else if (menuItem == NULL && !IsStickyMode()) SelectItem(NULL); @@ -442,11 +443,9 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) if (fSelected != NULL && fSelected->Submenu() == NULL) { resultItem = fSelected; break; - } else if (IsStickyPrefOn() && system_time() < startTime + 2000000) { - // Don't switch to sticky mode if user kept the mouse pressed for too long - // TODO: Delay could be smaller, but then it wouldn't be noticeable on QEMU on my machine + } else if (IsStickyPrefOn()) SetStickyMode(true); - } else + else break; } diff --git a/src/kits/interface/PopUpMenu.cpp b/src/kits/interface/PopUpMenu.cpp index 6a9515b10b..a46a8c7d7c 100644 --- a/src/kits/interface/PopUpMenu.cpp +++ b/src/kits/interface/PopUpMenu.cpp @@ -1,30 +1,12 @@ -//------------------------------------------------------------------------------ -// Copyright (c) 2001-2005, Haiku, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -// -// File Name: PopUpMenu.cpp -// Author: Marc Flerackers (mflerackers@androme.be) -// Stefano Ceccherini (burton666@libero.it) -// Description: BPopUpMenu represents a menu that pops up when you -// activate it. -//------------------------------------------------------------------------------ +/* + * Copyright 2001-2006, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Marc Flerackers (mflerackers@androme.be) + * Stefano Ceccherini (burton666@libero.it) + */ + #include #include #include @@ -81,8 +63,7 @@ BPopUpMenu::~BPopUpMenu() if (fTrackThread >= 0) { status_t status; while (wait_for_thread(fTrackThread, &status) == B_INTERRUPTED) - ; - + ; } } @@ -318,10 +299,10 @@ BPopUpMenu::_go(BPoint where, bool autoInvoke, bool startOpened, data->lock = sem; // Spawn the tracking thread - thread_id thread = spawn_thread(entry, "popup", B_NORMAL_PRIORITY, data); + fTrackThread = spawn_thread(entry, "popup", B_NORMAL_PRIORITY, data); - if (thread >= 0) - resume_thread(thread); + if (fTrackThread >= 0) + resume_thread(fTrackThread); else { // Something went wrong. Cleanup and return NULL delete_sem(sem); @@ -344,12 +325,13 @@ BPopUpMenu::_go(BPoint where, bool autoInvoke, bool startOpened, } status_t unused; - while (wait_for_thread(thread, &unused) == B_INTERRUPTED) + while (wait_for_thread(fTrackThread, &unused) == B_INTERRUPTED) ; selected = data->selected; delete data; + } return selected; @@ -414,6 +396,8 @@ BPopUpMenu::start_track(BPoint where, bool autoInvoke, be_app->ShowCursor(); + fTrackThread = -1; + return result; }