hopefully improved menu tracking. Among other things, this fixes bug 461

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17204 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini
2006-04-22 17:56:21 +00:00
parent 34108ddc58
commit 05e515d56c
3 changed files with 66 additions and 74 deletions
+4 -4
View File
@@ -2,10 +2,10 @@
#define __MENU_PRIVATE_H #define __MENU_PRIVATE_H
enum menu_actions { enum menu_states {
MENU_ACT_NONE = 0, MENU_STATE_TRACKING = 0,
MENU_ACT_SUBMENU = 1, MENU_STATE_TRACKING_SUBMENU = 1,
MENU_ACT_CLOSE = 5 MENU_STATE_CLOSED = 5
}; };
+52 -62
View File
@@ -236,47 +236,21 @@ BMenu::Archive(BMessage *data, bool deep) const
{ {
status_t err = BView::Archive(data, deep); status_t err = BView::Archive(data, deep);
if (err < B_OK) if (err == B_OK && Layout() != B_ITEMS_IN_ROW)
return err;
if (Layout() != B_ITEMS_IN_ROW) {
err = data->AddInt32("_layout", Layout()); err = data->AddInt32("_layout", Layout());
if (err == B_OK)
if (err < B_OK) err = data->AddBool("_rsize_to_fit", fResizeToFit);
return err; if (err == B_OK)
} err = data->AddBool("_disable", !IsEnabled());
if (err == B_OK)
err = data->AddBool("_rsize_to_fit", fResizeToFit); err = data->AddBool("_radio", IsRadioMode());
if (err == B_OK)
if (err < B_OK) err = data->AddBool("_trig_disabled", AreTriggersEnabled());
return err; if (err == B_OK)
err = data->AddBool("_dyn_label", fDynamicName);
err = data->AddBool("_disable", !IsEnabled()); if (err == B_OK)
err = data->AddFloat("_maxwidth", fMaxContentWidth);
if (err < B_OK) if (err == B_OK && deep) {
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) {
// TODO store items and rects // TODO store items and rects
} }
@@ -1129,7 +1103,7 @@ BMenu::_show(bool selectFirstItem)
UpdateWindowViewSize(); UpdateWindowViewSize();
window->Show(); window->Show();
if (selectFirstItem) if (selectFirstItem)
SelectItem(ItemAt(0)); SelectItem(ItemAt(0));
@@ -1175,9 +1149,17 @@ BMenu::_track(int *action, bigtime_t trackTime, long start)
bigtime_t openTime = system_time(); bigtime_t openTime = system_time();
bigtime_t closeTime = openTime; bigtime_t closeTime = openTime;
fState = MENU_ACT_NONE; fState = MENU_STATE_TRACKING;
if (fSuper != NULL)
fSuper->fState = MENU_STATE_TRACKING_SUBMENU;
while (true) { 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(); bool locked = LockLooper();
if (!locked) if (!locked)
break; break;
@@ -1190,37 +1172,35 @@ BMenu::_track(int *action, bigtime_t trackTime, long start)
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 && system_time() > closeTime + kHysteresis) {
&& (fState != MENU_ACT_SUBMENU || system_time() > closeTime + kHysteresis)) {
SelectItem(item, -1); SelectItem(item, -1);
openTime = system_time(); openTime = system_time();
fState = MENU_ACT_NONE;
snoozeAmount = 20000;
} else if (system_time() > kHysteresis + openTime && item->Submenu() != NULL } else if (system_time() > kHysteresis + openTime && item->Submenu() != NULL
&& 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(); closeTime = system_time();
} }
fState = MENU_STATE_TRACKING;
} }
// Track the submenu // Track the submenu
if (fSelected != NULL && OverSubmenu(fSelected, screenLocation)) { if (fSelected != NULL && OverSubmenu(fSelected, screenLocation)) {
UnlockLooper(); UnlockLooper();
locked = false; locked = false;
int submenuAction = MENU_ACT_NONE; int submenuAction = MENU_STATE_TRACKING;
BMenu *submenu = fSelected->Submenu();
if (IsStickyMode()) if (IsStickyMode())
fSelected->Submenu()->SetStickyMode(true); submenu->SetStickyMode(true);
BMenuItem *submenuItem = fSelected->Submenu()->_track(&submenuAction, trackTime); BMenuItem *submenuItem = submenu->_track(&submenuAction, trackTime);
if (submenuAction == MENU_ACT_CLOSE) { if (submenuAction == MENU_STATE_CLOSED) {
item = submenuItem; item = submenuItem;
fState = submenuAction; fState = submenuAction;
break; break;
} }
locked = LockLooper(); locked = LockLooper();
if (!locked) if (!locked)
break; break;
@@ -1228,29 +1208,38 @@ BMenu::_track(int *action, bigtime_t trackTime, long start)
if (item == NULL) { if (item == NULL) {
if (OverSuper(screenLocation)) { if (OverSuper(screenLocation)) {
fState = MENU_ACT_NONE; fState = MENU_STATE_TRACKING;
UnlockLooper(); UnlockLooper();
break; break;
} }
if (fSelected != NULL && !OverSubmenu(fSelected, screenLocation) 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); SelectItem(NULL);
fState = MENU_ACT_NONE; fState = MENU_STATE_TRACKING;
}
if (fSuper != NULL) {
if (locked)
UnlockLooper();
*action = fState;
return NULL;
} }
} }
if (locked) if (locked)
UnlockLooper(); UnlockLooper();
if (buttons != 0 && IsStickyMode()) { if (buttons != 0 && IsStickyMode()) {
fState = MENU_ACT_CLOSE; fState = MENU_STATE_CLOSED;
break; break;
} else if (buttons == 0 && !IsStickyMode()) { } else if (buttons == 0 && !IsStickyMode()) {
if (system_time() < trackTime + 1000000 if (system_time() < trackTime + 1000000
|| (fExtraRect != NULL && fExtraRect->Contains(location))) || (fExtraRect != NULL && fExtraRect->Contains(location)))
SetStickyMode(true); SetStickyMode(true);
else { else {
fState = MENU_ACT_CLOSE; fState = MENU_STATE_CLOSED;
break; break;
} }
} }
@@ -1261,7 +1250,7 @@ BMenu::_track(int *action, bigtime_t trackTime, long start)
if (action != NULL) if (action != NULL)
*action = fState; *action = fState;
if (LockLooper()) { if (fSelected != NULL && LockLooper()) {
SelectItem(NULL); SelectItem(NULL);
UnlockLooper(); UnlockLooper();
} }
@@ -1918,7 +1907,8 @@ BMenu::UpdateWindowViewSize(bool upWind)
window->ResizeTo(Bounds().Width() + 2, Bounds().Height() + 2); window->ResizeTo(Bounds().Width() + 2, Bounds().Height() + 2);
else { else {
CacheFontInfo(); 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()); window->MoveTo(frame.LeftTop());
} }
+10 -8
View File
@@ -378,16 +378,16 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
// TODO: Cleanup, merge some "if" blocks if possible // TODO: Cleanup, merge some "if" blocks if possible
BMenuItem *resultItem = NULL; BMenuItem *resultItem = NULL;
BWindow *window = Window(); BWindow *window = Window();
int localAction = MENU_ACT_NONE; int localAction = MENU_STATE_TRACKING;
while (true) { while (true) {
bigtime_t snoozeAmount = 30000; bigtime_t snoozeAmount = 40000;
bool locked = window->Lock();//WithTimeout(200000) bool locked = window->Lock();//WithTimeout(200000)
if (!locked) if (!locked)
break; break;
BPoint where; BPoint where;
ulong buttons; ulong buttons;
GetMouse(&where, &buttons); GetMouse(&where, &buttons, true);
BMenuItem *menuItem = HitTestItems(where, B_ORIGIN); BMenuItem *menuItem = HitTestItems(where, B_ORIGIN);
if (menuItem != NULL) { if (menuItem != NULL) {
// Select item if: // Select item if:
@@ -406,7 +406,7 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
} else { } else {
// Menu was already opened, close it and bail // Menu was already opened, close it and bail
SelectItem(NULL); SelectItem(NULL);
localAction = MENU_ACT_CLOSE; localAction = MENU_STATE_CLOSED;
resultItem = NULL; resultItem = NULL;
} }
} else { } else {
@@ -423,18 +423,20 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
if (menu != NULL) { if (menu != NULL) {
window->Unlock(); window->Unlock();
locked = false; locked = false;
snoozeAmount = 0; snoozeAmount = 30000;
if (IsStickyMode()) if (IsStickyMode())
menu->SetStickyMode(true); menu->SetStickyMode(true);
resultItem = menu->_track(&localAction, system_time()); resultItem = menu->_track(&localAction, system_time());
} }
} else if (menuItem == NULL && !IsStickyMode()) } else if (menuItem == NULL && !IsStickyMode()) {
SelectItem(NULL); SelectItem(NULL);
fState = MENU_STATE_TRACKING;
}
if (locked) if (locked)
window->Unlock(); window->Unlock();
if (localAction == MENU_ACT_CLOSE || (buttons != 0 && IsStickyMode() && menuItem == NULL)) if (localAction == MENU_STATE_CLOSED || (buttons != 0 && IsStickyMode() && menuItem == NULL))
break; break;
else if (buttons == 0 && !IsStickyMode()) { else if (buttons == 0 && !IsStickyMode()) {
// On an item without a submenu // On an item without a submenu
@@ -446,7 +448,7 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
} }
if (snoozeAmount > 0) if (snoozeAmount > 0)
snooze(snoozeAmount); snooze(snoozeAmount);
} }
if (window->Lock()) { if (window->Lock()) {