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:
+27
-13
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user