Some more changes, fixed bug 487, added a small hysteresis so menus could be more nice to navigate, some corrections in popupmenu

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17134 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini
2006-04-15 12:42:34 +00:00
parent cdc79923d0
commit 36aa2198b7
3 changed files with 49 additions and 52 deletions
+27 -13
View File
@@ -103,6 +103,9 @@ sPropList[] = {
}; };
const char *kEmptyMenuLabel = "<empty>";
BMenu::BMenu(const char *name, menu_layout layout) BMenu::BMenu(const char *name, menu_layout layout)
: BView(BRect(0, 0, 0, 0), name, 0, B_WILL_DRAW), : BView(BRect(0, 0, 0, 0), name, 0, B_WILL_DRAW),
fChosenItem(NULL), fChosenItem(NULL),
@@ -1096,9 +1099,6 @@ BMenu::_show(bool selectFirstItem)
if (dynamic_cast<BMenuWindow *>(window) != NULL) if (dynamic_cast<BMenuWindow *>(window) != NULL)
MoveTo(1, 1); 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(); UpdateWindowViewSize();
window->Show(); window->Show();
@@ -1118,8 +1118,9 @@ BMenu::_hide()
BMenuWindow *window = static_cast<BMenuWindow *>(Window()); BMenuWindow *window = static_cast<BMenuWindow *>(Window());
if (window == NULL || !window->Lock()) if (window == NULL || !window->Lock())
return; return;
SelectItem(NULL); if (fSelected != NULL)
SelectItem(NULL);
window->Hide(); window->Hide();
window->DetachMenu(); window->DetachMenu();
@@ -1135,17 +1136,20 @@ BMenu::_hide()
} }
const bigtime_t kHysteresis = 200000; // TODO: Test and reduce if needed.
BMenuItem * BMenuItem *
BMenu::_track(int *action, bigtime_t trackTime, long start) BMenu::_track(int *action, bigtime_t trackTime, long start)
{ {
// TODO: cleanup // TODO: cleanup
ulong buttons;
BMenuItem *item = NULL; BMenuItem *item = NULL;
int localAction = MENU_ACT_NONE; int localAction = MENU_ACT_NONE;
bigtime_t startTime = system_time(); bigtime_t openTime = system_time();
bigtime_t delay = 200000; // TODO: Test and reduce if needed. bigtime_t closeTime = openTime;
fState = MENU_ACT_NONE;
while (true) { while (true) {
bool locked = LockLooper(); bool locked = LockLooper();
if (!locked) if (!locked)
@@ -1153,21 +1157,26 @@ BMenu::_track(int *action, bigtime_t trackTime, long start)
bigtime_t snoozeAmount = 50000; bigtime_t snoozeAmount = 50000;
BPoint location; BPoint location;
ulong buttons;
GetMouse(&location, &buttons, false); GetMouse(&location, &buttons, false);
BPoint screenLocation = ConvertToScreen(location); BPoint screenLocation = ConvertToScreen(location);
item = HitTestItems(location, B_ORIGIN); item = HitTestItems(location, B_ORIGIN);
if (item != NULL) { if (item != NULL) {
if (item != fSelected) { if (item != fSelected
&& (fState != MENU_ACT_SUBMENU || system_time() > closeTime + kHysteresis)) {
SelectItem(item, -1); SelectItem(item, -1);
startTime = system_time(); openTime = system_time();
fState = MENU_ACT_NONE;
snoozeAmount = 20000; snoozeAmount = 20000;
} else if (system_time() > delay + startTime && item->Submenu() } else if (system_time() > kHysteresis + openTime && item->Submenu()
&& item->Submenu()->Window() == NULL) { && item->Submenu()->Window() == NULL) {
// Open the submenu if it's not opened yet, but only if // Open the submenu if it's not opened yet, but only if
// the mouse pointer stayed over there for some time // the mouse pointer stayed over there for some time
// (hysteresis) // (hysteresis)
SelectItem(item); SelectItem(item);
fState = MENU_ACT_SUBMENU;
closeTime = system_time();
} }
} else { } else {
if (OverSuper(screenLocation)) { if (OverSuper(screenLocation)) {
@@ -1176,8 +1185,11 @@ BMenu::_track(int *action, bigtime_t trackTime, long start)
UnlockLooper(); UnlockLooper();
break; break;
} }
if (fSelected != NULL && !OverSubmenu(fSelected, screenLocation)) if (fSelected != NULL && !OverSubmenu(fSelected, screenLocation)
&& (fState != MENU_ACT_SUBMENU || system_time() > closeTime + kHysteresis)) {
SelectItem(NULL); SelectItem(NULL);
fState = MENU_ACT_NONE;
}
} }
if (fSelected != NULL && OverSubmenu(fSelected, screenLocation)) { 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) if (action != NULL)
*action = localAction; *action = localAction;
+5 -6
View File
@@ -381,7 +381,6 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
BMenuItem *resultItem = NULL; BMenuItem *resultItem = NULL;
BWindow *window = Window(); BWindow *window = Window();
int localAction = MENU_ACT_NONE; int localAction = MENU_ACT_NONE;
bigtime_t startTime = system_time();
while (true) { while (true) {
bigtime_t snoozeAmount = 30000; bigtime_t snoozeAmount = 30000;
bool locked = window->Lock();//WithTimeout(200000) bool locked = window->Lock();//WithTimeout(200000)
@@ -404,6 +403,8 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
if (menuItem->Submenu()->Window() == NULL) { if (menuItem->Submenu()->Window() == NULL) {
// open the menu if it's not opened yet // open the menu if it's not opened yet
SelectItem(menuItem); SelectItem(menuItem);
if (IsStickyMode())
SetStickyMode(false);
} else { } else {
// Menu was already opened, close it and bail // Menu was already opened, close it and bail
SelectItem(NULL); SelectItem(NULL);
@@ -427,7 +428,7 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
snoozeAmount = 0; snoozeAmount = 0;
if (IsStickyMode()) if (IsStickyMode())
menu->SetStickyMode(true); menu->SetStickyMode(true);
resultItem = menu->_track(&localAction, startTime); resultItem = menu->_track(&localAction, system_time());
} }
} else if (menuItem == NULL && !IsStickyMode()) } else if (menuItem == NULL && !IsStickyMode())
SelectItem(NULL); SelectItem(NULL);
@@ -442,11 +443,9 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
if (fSelected != NULL && fSelected->Submenu() == NULL) { if (fSelected != NULL && fSelected->Submenu() == NULL) {
resultItem = fSelected; resultItem = fSelected;
break; break;
} else if (IsStickyPrefOn() && system_time() < startTime + 2000000) { } else if (IsStickyPrefOn())
// 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
SetStickyMode(true); SetStickyMode(true);
} else else
break; break;
} }
+17 -33
View File
@@ -1,30 +1,12 @@
//------------------------------------------------------------------------------ /*
// Copyright (c) 2001-2005, Haiku, Inc. * Copyright 2001-2006, Haiku, Inc.
// * Distributed under the terms of the MIT License.
// Permission is hereby granted, free of charge, to any person obtaining a *
// copy of this software and associated documentation files (the "Software"), * Authors:
// to deal in the Software without restriction, including without limitation * Marc Flerackers ([email protected])
// the rights to use, copy, modify, merge, publish, distribute, sublicense, * Stefano Ceccherini ([email protected])
// 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 ([email protected])
// Stefano Ceccherini ([email protected])
// Description: BPopUpMenu represents a menu that pops up when you
// activate it.
//------------------------------------------------------------------------------
#include <Application.h> #include <Application.h>
#include <Looper.h> #include <Looper.h>
#include <MenuItem.h> #include <MenuItem.h>
@@ -81,8 +63,7 @@ BPopUpMenu::~BPopUpMenu()
if (fTrackThread >= 0) { if (fTrackThread >= 0) {
status_t status; status_t status;
while (wait_for_thread(fTrackThread, &status) == B_INTERRUPTED) while (wait_for_thread(fTrackThread, &status) == B_INTERRUPTED)
; ;
} }
} }
@@ -318,10 +299,10 @@ BPopUpMenu::_go(BPoint where, bool autoInvoke, bool startOpened,
data->lock = sem; data->lock = sem;
// Spawn the tracking thread // 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) if (fTrackThread >= 0)
resume_thread(thread); resume_thread(fTrackThread);
else { else {
// Something went wrong. Cleanup and return NULL // Something went wrong. Cleanup and return NULL
delete_sem(sem); delete_sem(sem);
@@ -344,12 +325,13 @@ BPopUpMenu::_go(BPoint where, bool autoInvoke, bool startOpened,
} }
status_t unused; status_t unused;
while (wait_for_thread(thread, &unused) == B_INTERRUPTED) while (wait_for_thread(fTrackThread, &unused) == B_INTERRUPTED)
; ;
selected = data->selected; selected = data->selected;
delete data; delete data;
} }
return selected; return selected;
@@ -414,6 +396,8 @@ BPopUpMenu::start_track(BPoint where, bool autoInvoke,
be_app->ShowCursor(); be_app->ShowCursor();
fTrackThread = -1;
return result; return result;
} }