[prev in list] [next in list] [prev in thread] [next in thread] 

List:       haiku-commits
Subject:    [haiku-commits] Change in haiku[master]: Interface kit: rewrite menu logic by using input event
From:       Gerrit <review () review ! haiku-os ! org>
Date:       2020-02-27 3:03:20
Message-ID: gerrit.1582772598000.Ia693570e9bf4cbea33cd7d71bd5e7249c089959f () review ! haiku-os ! org
[Download RAW message or body]

From X512 <danger_mail@list.ru>:

X512 has uploaded this change for review. ( https://review.haiku-os.org/c/haiku/+/2284 )


Change subject: Interface kit: rewrite menu logic by using input event
......................................................................

Interface kit: rewrite menu logic by using input event

WIP, DON'T MERGE

Keyboard navigation is implemented:
	* Alt+Esc opens menu.
	* Arrow keys are used to move to previous/next item and enter/leave submenu.
	* Character key invoke or enter item with underlined character.
	* Enter invoke menu, Esc leave current menu.

TODO:
	* Fix mouse deadlock.
	* Close menu when clicked outside.
	* Fix sticky mode.
	* Scroll menu on keyboard navigation.
	* Fix freeze when dymanically building submenu

Change-Id: Ia693570e9bf4cbea33cd7d71bd5e7249c089959f
---
M headers/os/interface/Menu.h
M headers/private/interface/MenuPrivate.h
M src/kits/interface/Menu.cpp
M src/kits/interface/MenuBar.cpp
4 files changed, 243 insertions(+), 417 deletions(-)



  git pull ssh://git.haiku-os.org:22/haiku refs/changes/84/2284/1

diff --git a/headers/os/interface/Menu.h b/headers/os/interface/Menu.h
index dcb8ab6..e465a33 100644
--- a/headers/os/interface/Menu.h
+++ b/headers/os/interface/Menu.h
@@ -17,6 +17,7 @@


 namespace BPrivate {
+	class MenuTrackState;
 	class BMenuWindow;
 	class ExtraMenuData;
 	class TriggerList;
@@ -190,7 +191,7 @@
 			bool				_Show(bool selectFirstItem = false,
 									bool keyDown = false);
 			void				_Hide();
-			BMenuItem*			_Track(int* action, long start = -1);
+			BMenuItem*			_Track(int32* action, int32 start = -1);

 			void				_UpdateNavigationArea(BPoint position,
 									BRect& navAreaRectAbove,
@@ -281,7 +282,7 @@
 	static	uint32				sCommandKey;
 	static	uint32				sMenuKey;

-			BMenuItem*			fChosenItem;
+			BPrivate::MenuTrackState* fTrackState;
 			BList				fItems;
 			BRect				fPad;
 			BMenuItem*			fSelected;
diff --git a/headers/private/interface/MenuPrivate.h b/headers/private/interface/MenuPrivate.h
index 4627b70..e819fc8 100644
--- a/headers/private/interface/MenuPrivate.h
+++ b/headers/private/interface/MenuPrivate.h
@@ -11,6 +11,7 @@


 #include <Menu.h>
+#include <Locker.h>


 enum menu_states {
@@ -21,6 +22,10 @@
 	MENU_STATE_CLOSED = 5
 };

+enum menu_track_command {
+	MENU_TRACK_COMMAND_DONE = 0
+};
+

 class BBitmap;
 class BMenu;
@@ -78,6 +83,19 @@

 };

+struct MenuTrackState {
+	thread_id trackThread;
+	BLocker locker;
+	bool quit;
+	BMenu* rootMenu;
+	BMenu* curMenu;
+	BMenuItem *invokedItem;
+	BRect navAreaRectAbove;
+	BRect navAreaRectBelow;
+	bigtime_t selectedTime;
+	bigtime_t navigationAreaTime;
+};
+
 };	// namespace BPrivate


diff --git a/src/kits/interface/Menu.cpp b/src/kits/interface/Menu.cpp
index 079918b..288638d 100644
--- a/src/kits/interface/Menu.cpp
+++ b/src/kits/interface/Menu.cpp
@@ -39,6 +39,7 @@
 #include <SystemCatalog.h>
 #include <UnicodeChar.h>
 #include <Window.h>
+#include <AutoLocker.h>

 #include <AppServerLink.h>
 #include <binary_compatibility/Interface.h>
@@ -226,7 +227,7 @@
 BMenu::BMenu(const char* name, menu_layout layout)
 	:
 	BView(BRect(0, 0, 0, 0), name, 0, B_WILL_DRAW),
-	fChosenItem(NULL),
+	fTrackState(NULL),
 	fPad(std::max(14.0f, be_plain_font->Size() + 2.0f), 2.0f, 20.0f, 0.0f),
 	fSelected(NULL),
 	fCachedMenuWindow(NULL),
@@ -261,7 +262,7 @@
 BMenu::BMenu(const char* name, float width, float height)
 	:
 	BView(BRect(0.0f, 0.0f, 0.0f, 0.0f), name, 0, B_WILL_DRAW),
-	fChosenItem(NULL),
+	fTrackState(NULL),
 	fPad(14.0f, 2.0f, 20.0f, 0.0f),
 	fSelected(NULL),
 	fCachedMenuWindow(NULL),
@@ -296,7 +297,7 @@
 BMenu::BMenu(BMessage* archive)
 	:
 	BView(archive),
-	fChosenItem(NULL),
+	fTrackState(NULL),
 	fPad(14.0f, 2.0f, 20.0f, 0.0f),
 	fSelected(NULL),
 	fCachedMenuWindow(NULL),
@@ -453,6 +454,10 @@
 void
 BMenu::MessageReceived(BMessage* message)
 {
+	if (fTrackState == NULL) {
+		BView::MessageReceived(message);
+		return;
+	}
 	switch (message->what) {
 		case B_MOUSE_WHEEL_CHANGED:
 		{
@@ -479,6 +484,58 @@
 			break;
 		}

+		case B_MOUSE_DOWN:
+			if (fStickyMode) {
+				if (fSelected != NULL) {
+					_InvokeItem(fSelected);
+				}
+				_QuitTracking(false);
+			}
+			BView::MessageReceived(message);
+			break;
+		case B_MOUSE_UP:
+			if (!fStickyMode) {
+				if (fSelected != NULL) {
+					_InvokeItem(fSelected);
+				}
+				_QuitTracking(false);
+			}
+			BView::MessageReceived(message);
+			break;
+		case B_MOUSE_MOVED: {
+			BPoint where = B_ORIGIN;
+			int32 buttons = 0;
+			int32 transit = B_OUTSIDE_VIEW;
+
+			message->FindPoint("be:view_where", &where);
+			message->FindInt32("buttons", &buttons);
+			message->FindInt32("be:transit", &transit);
+
+			if (fTrackState == NULL) {
+				BView::MessageReceived(message);
+				return;
+			}
+
+			AutoLocker<BLocker> locker(fTrackState->locker);
+
+			BMenuItem *oldSelected = fSelected;
+			BMenuItem* item = _HitTestItems(where, B_ORIGIN);
+			if (item == NULL) {
+				if ((fSelected != NULL) && (fSelected->Submenu() == NULL)) {
+					_SelectItem(NULL);
+				}
+			} else {
+				_UpdateStateOpenSelect(item, where, fTrackState->navAreaRectAbove,
+					fTrackState->navAreaRectBelow, fTrackState->selectedTime, fTrackState->navigationAreaTime);
+			}
+
+			if (fSelected != oldSelected)
+				fTrackState->curMenu = this;
+
+			BView::MessageReceived(message);
+			break;
+		}
+
 		default:
 			BView::MessageReceived(message);
 			break;
@@ -490,63 +547,70 @@
 BMenu::KeyDown(const char* bytes, int32 numBytes)
 {
 	// TODO: Test how it works on BeOS R5 and implement this correctly
+
+	if (fTrackState == NULL)
+		return;
+
+	AutoLocker<BLocker> locker(fTrackState->locker);
+
+	if (fTrackState->curMenu != this) {
+		BMessenger messenger(fTrackState->curMenu);
+		messenger.SendMessage(Window()->CurrentMessage());
+		return;
+	}
 	switch (bytes[0]) {
 		case B_UP_ARROW:
-			if (fLayout == B_ITEMS_IN_COLUMN)
+			if (fLayout == B_ITEMS_IN_COLUMN) {
 				_SelectNextItem(fSelected, false);
+			} else if (fLayout == B_ITEMS_IN_ROW || fLayout == B_ITEMS_IN_MATRIX) {
+				if (Supermenu() != NULL) {
+					_SelectItem(NULL);
+					fTrackState->curMenu = Supermenu();
+				} else {
+					_QuitTracking(false);
+				}
+			}
 			break;

 		case B_DOWN_ARROW:
-		{
-			BMenuBar* bar = dynamic_cast<BMenuBar*>(Supermenu());
-			if (bar != NULL && fState == MENU_STATE_CLOSED) {
-				// tell MenuBar's _Track:
-				bar->fState = MENU_STATE_KEY_TO_SUBMENU;
-			}
-			if (fLayout == B_ITEMS_IN_COLUMN)
+			if (fLayout == B_ITEMS_IN_COLUMN) {
 				_SelectNextItem(fSelected, true);
-			break;
-		}
-
-		case B_LEFT_ARROW:
-			if (fLayout == B_ITEMS_IN_ROW)
-				_SelectNextItem(fSelected, false);
-			else {
-				// this case has to be handled a bit specially.
-				BMenuItem* item = Superitem();
-				if (item) {
-					if (dynamic_cast<BMenuBar*>(Supermenu())) {
-						// If we're at the top menu below the menu bar, pass
-						// the keypress to the menu bar so we can move to
-						// another top level menu.
-						BMessenger messenger(Supermenu());
-						messenger.SendMessage(Window()->CurrentMessage());
-					} else {
-						// tell _Track
-						fState = MENU_STATE_KEY_LEAVE_SUBMENU;
+			} else if (fLayout == B_ITEMS_IN_ROW || fLayout == B_ITEMS_IN_MATRIX) {
+				if (fSelected != NULL) {
+					BMenu* subMenu = fSelected->Submenu();
+					if (subMenu != NULL && subMenu->LockLooper()) {
+						subMenu->_SelectNextItem(subMenu->fSelected, true);
+						subMenu->UnlockLooper();
+						fTrackState->curMenu = subMenu;
 					}
 				}
 			}
 			break;

+		case B_LEFT_ARROW:
+			if (fLayout == B_ITEMS_IN_ROW || fLayout == B_ITEMS_IN_MATRIX) {
+				_SelectNextItem(fSelected, false);
+			} else if (fLayout == B_ITEMS_IN_COLUMN) {
+				if (Supermenu() != NULL) {
+					_SelectItem(NULL);
+					fTrackState->curMenu = Supermenu();
+				} else {
+					_QuitTracking(false);
+				}
+			}
+			break;
+
 		case B_RIGHT_ARROW:
-			if (fLayout == B_ITEMS_IN_ROW)
+			if (fLayout == B_ITEMS_IN_ROW || fLayout == B_ITEMS_IN_MATRIX) {
 				_SelectNextItem(fSelected, true);
-			else {
-				if (fSelected != NULL && fSelected->Submenu() != NULL) {
-					fSelected->Submenu()->_SetStickyMode(true);
-						// fix me: this shouldn't be needed but dynamic menus
-						// aren't getting it set correctly when keyboard
-						// navigating, which aborts the attach
-					fState = MENU_STATE_KEY_TO_SUBMENU;
-					_SelectItem(fSelected, true, true, true);
-				} else if (dynamic_cast<BMenuBar*>(Supermenu())) {
-					// if we have no submenu and we're an
-					// item in the top menu below the menubar,
-					// pass the keypress to the menubar
-					// so you can use the keypress to switch menus.
-					BMessenger messenger(Supermenu());
-					messenger.SendMessage(Window()->CurrentMessage());
+			} else if (fLayout == B_ITEMS_IN_COLUMN) {
+				if (fSelected != NULL) {
+					BMenu* subMenu = fSelected->Submenu();
+					if (subMenu != NULL && subMenu->LockLooper()) {
+						subMenu->_SelectNextItem(subMenu->fSelected, true);
+						subMenu->UnlockLooper();
+						fTrackState->curMenu = subMenu;
+					}
 				}
 			}
 			break;
@@ -569,21 +633,18 @@
 		case B_ENTER:
 		case B_SPACE:
 			if (fSelected != NULL) {
-				fChosenItem = fSelected;
-					// preserve for exit handling
+				_InvokeItem(fSelected);
 				_QuitTracking(false);
 			}
 			break;

 		case B_ESCAPE:
-			_SelectItem(NULL);
-			if (fState == MENU_STATE_CLOSED
-				&& dynamic_cast<BMenuBar*>(Supermenu())) {
-				// Keyboard may show menu without tracking it
-				BMessenger messenger(Supermenu());
-				messenger.SendMessage(Window()->CurrentMessage());
-			} else
+			if (Supermenu() != NULL) {
+				_SelectItem(NULL);
+				fTrackState->curMenu = Supermenu();
+			} else {
 				_QuitTracking(false);
+			}
 			break;

 		default:
@@ -595,8 +656,18 @@
 				if (item->fTriggerIndex < 0 || item->fTrigger != trigger)
 					continue;

-				_InvokeItem(item);
-				_QuitTracking(false);
+				if (item->Submenu()) {
+					_SelectItem(item, true, false, true);
+					BMenu* subMenu = fSelected->Submenu();
+					if (subMenu != NULL && subMenu->LockLooper()) {
+						subMenu->_SelectNextItem(subMenu->fSelected, true);
+						subMenu->UnlockLooper();
+						fTrackState->curMenu = subMenu;
+					}
+				} else {
+					_InvokeItem(item);
+					_QuitTracking(false);
+				}
 				break;
 			}
 			break;
@@ -1299,7 +1370,7 @@
 	menu_layout layout, bool resizeToFit)
 	:
 	BView(frame, name, resizingMode, flags),
-	fChosenItem(NULL),
+	fTrackState(NULL),
 	fSelected(NULL),
 	fCachedMenuWindow(NULL),
 	fSuper(NULL),
@@ -1402,7 +1473,7 @@

 	_SetStickyMode(sticky);

-	int action;
+	int32 action;
 	BMenuItem* menuItem = _Track(&action);

 	fExtraRect = NULL;
@@ -1550,6 +1621,7 @@
 			addAborted = _AddDynamicItems(keyDown);

 		if (addAborted) {
+			printf("addAborted\n");
 			if (ourWindow)
 				window->Quit();
 			else
@@ -1569,6 +1641,7 @@

 		// Menu didn't have the time to add its items: aborting...
 		if (fAttachAborted) {
+			printf("fAttachAborted\n");
 			window->DetachMenu();
 			// TODO: Probably not needed, we can just let _hide() quit the
 			// window.
@@ -1582,6 +1655,9 @@
 		_UpdateWindowViewSize(true);
 		window->Show();

+		if (Supermenu() != NULL)
+			fTrackState = Supermenu()->fTrackState;
+
 		if (selectFirstItem)
 			_SelectItem(ItemAt(0), false);

@@ -1602,6 +1678,8 @@
 	if (fSelected != NULL)
 		_SelectItem(NULL);

+	fTrackState = NULL;
+
 	window->Hide();
 	window->DetachMenu();
 		// we don't want to be deleted when the window is removed
@@ -1622,189 +1700,67 @@
 // #pragma mark - mouse tracking


-const static bigtime_t kOpenSubmenuDelay = 0;
 const static bigtime_t kNavigationAreaTimeout = 1000000;


 BMenuItem*
-BMenu::_Track(int* action, long start)
+BMenu::_Track(int32* action, int32 start)
 {
-	// TODO: cleanup
+	if (fTrackState != NULL) {
+		printf("Track: already entered\n");
+		return NULL;
+	}
+	printf("+Track\n");
+	printf("sticky: %d\n", fStickyMode);
+	_SetStickyMode(true); // !!!
+	BPrivate::MenuTrackState trackState;
 	BMenuItem* item = NULL;
-	BRect navAreaRectAbove;
-	BRect navAreaRectBelow;
-	bigtime_t selectedTime = system_time();
-	bigtime_t navigationAreaTime = 0;
+	BMenuItem* startItem = ItemAt(start);
+	thread_id senderThread;
+	bool run = true;

-	fState = MENU_STATE_TRACKING;
-	fChosenItem = NULL;
-		// we will use this for keyboard selection
+	fTrackState = &trackState;
+	fTrackState->trackThread = find_thread(NULL);
+	fTrackState->quit = false;
+	fTrackState->rootMenu = this;
+	fTrackState->curMenu = this;
+	fTrackState->invokedItem = NULL;
+	fTrackState->navAreaRectAbove = BRect();
+	fTrackState->navAreaRectBelow = BRect();

-	BPoint location;
-	uint32 buttons = 0;
 	if (LockLooper()) {
-		GetMouse(&location, &buttons);
+		if (startItem != NULL)
+			_SelectItem(startItem, true, false, true);
+		else {
+			BPoint where;
+			GetMouse(&where, NULL);
+			_SelectItem(_HitTestItems(where, B_ORIGIN), true, false, true);
+		}
 		UnlockLooper();
 	}
-
-	bool releasedOnce = buttons == 0;
-	while (fState != MENU_STATE_CLOSED) {
-		if (_CustomTrackingWantsToQuit())
+	while (run) {
+		int32 cmd = receive_data(&senderThread, NULL, 0);
+		switch (cmd) {
+		case MENU_TRACK_COMMAND_DONE:
+			run = false;
 			break;
-
-		if (!LockLooper())
-			break;
-
-		BMenuWindow* window = static_cast<BMenuWindow*>(Window());
-		BPoint screenLocation = ConvertToScreen(location);
-		if (window->CheckForScrolling(screenLocation)) {
-			UnlockLooper();
-			continue;
-		}
-
-		// The order of the checks is important
-		// to be able to handle overlapping menus:
-		// first we check if mouse is inside a submenu,
-		// then if the mouse is inside this menu,
-		// then if it's over a super menu.
-		if (_OverSubmenu(fSelected, screenLocation)
-			|| fState == MENU_STATE_KEY_TO_SUBMENU) {
-			if (fState == MENU_STATE_TRACKING) {
-				// not if from R.Arrow
-				fState = MENU_STATE_TRACKING_SUBMENU;
-			}
-			navAreaRectAbove = BRect();
-			navAreaRectBelow = BRect();
-
-			// Since the submenu has its own looper,
-			// we can unlock ours. Doing so also make sure
-			// that our window gets any update message to
-			// redraw itself
-			UnlockLooper();
-
-			// To prevent NULL access violation, ensure a menu has actually
-			// been selected and that it has a submenu. Because keyboard and
-			// mouse interactions set selected items differently, the menu
-			// tracking thread needs to be careful in triggering the navigation
-			// to the submenu.
-			if (fSelected != NULL) {
-				BMenu* submenu = fSelected->Submenu();
-				int submenuAction = MENU_STATE_TRACKING;
-				if (submenu != NULL) {
-					submenu->_SetStickyMode(_IsStickyMode());
-
-					// The following call blocks until the submenu
-					// gives control back to us, either because the mouse
-					// pointer goes out of the submenu's bounds, or because
-					// the user closes the menu
-					BMenuItem* submenuItem = submenu->_Track(&submenuAction);
-					if (submenuAction == MENU_STATE_CLOSED) {
-						item = submenuItem;
-						fState = MENU_STATE_CLOSED;
-					} else if (submenuAction == MENU_STATE_KEY_LEAVE_SUBMENU) {
-						if (LockLooper()) {
-							BMenuItem* temp = fSelected;
-							// close the submenu:
-							_SelectItem(NULL);
-							// but reselect the item itself for user:
-							_SelectItem(temp, false);
-							UnlockLooper();
-						}
-						// cancel  key-nav state
-						fState = MENU_STATE_TRACKING;
-					} else
-						fState = MENU_STATE_TRACKING;
-				}
-			}
-			if (!LockLooper())
-				break;
-		} else if ((item = _HitTestItems(location, B_ORIGIN)) != NULL) {
-			_UpdateStateOpenSelect(item, location, navAreaRectAbove,
-				navAreaRectBelow, selectedTime, navigationAreaTime);
-			releasedOnce = true;
-		} else if (_OverSuper(screenLocation)
-			&& fSuper->fState != MENU_STATE_KEY_TO_SUBMENU) {
-			fState = MENU_STATE_TRACKING;
-			UnlockLooper();
-			break;
-		} else if (fState == MENU_STATE_KEY_LEAVE_SUBMENU) {
-			UnlockLooper();
-			break;
-		} else if (fSuper == NULL
-			|| fSuper->fState != MENU_STATE_KEY_TO_SUBMENU) {
-			// Mouse pointer outside menu:
-			// If there's no other submenu opened,
-			// deselect the current selected item
-			if (fSelected != NULL
-				&& (fSelected->Submenu() == NULL
-					|| fSelected->Submenu()->Window() == NULL)) {
-				_SelectItem(NULL);
-				fState = MENU_STATE_TRACKING;
-			}
-
-			if (fSuper != NULL) {
-				// Give supermenu the chance to continue tracking
-				*action = fState;
-				UnlockLooper();
-				return NULL;
-			}
-		}
-
-		UnlockLooper();
-
-		if (releasedOnce)
-			_UpdateStateClose(item, location, buttons);
-
-		if (fState != MENU_STATE_CLOSED) {
-			bigtime_t snoozeAmount = 50000;
-
-			BPoint newLocation = location;
-			uint32 newButtons = buttons;
-
-			// If user doesn't move the mouse, loop here,
-			// so we don't interfere with keyboard menu navigation
-			do {
-				snooze(snoozeAmount);
-				if (!LockLooper())
-					break;
-				GetMouse(&newLocation, &newButtons, true);
-				UnlockLooper();
-			} while (newLocation == location && newButtons == buttons
-				&& !(item != NULL && item->Submenu() != NULL
-					&& item->Submenu()->Window() == NULL)
-				&& fState == MENU_STATE_TRACKING);
-
-			if (newLocation != location || newButtons != buttons) {
-				if (!releasedOnce && newButtons == 0 && buttons != 0)
-					releasedOnce = true;
-				location = newLocation;
-				buttons = newButtons;
-			}
-
-			if (releasedOnce)
-				_UpdateStateClose(item, location, buttons);
 		}
 	}

-	if (action != NULL)
-		*action = fState;
+	item = fTrackState->invokedItem;

-	// keyboard Enter will set this
-	if (fChosenItem != NULL)
-		item = fChosenItem;
-	else if (fSelected == NULL) {
-		// needed to cover (rare) mouse/ESC combination
-		item = NULL;
-	}
-
-	if (fSelected != NULL && LockLooper()) {
+	if (LockLooper()) {
+		// hide submenus
 		_SelectItem(NULL);
 		UnlockLooper();
 	}

+	fTrackState = NULL;
+
 	// delete the menu window recycled for all the child menus
 	_DeleteMenuWindow();

+	printf("-Track\n");
 	return item;
 }

@@ -1889,9 +1845,10 @@
 	BRect& navAreaRectAbove, BRect& navAreaRectBelow, bigtime_t& selectedTime,
 	bigtime_t& navigationAreaTime)
 {
-	if (fState == MENU_STATE_CLOSED)
+	if (fLayout != B_ITEMS_IN_COLUMN) {
+		_SelectItem(item, true);
 		return;
-
+	}
 	if (item != fSelected) {
 		if (navigationAreaTime == 0)
 			navigationAreaTime = system_time();
@@ -1954,8 +1911,7 @@
 			selectedTime = system_time();
 			navigationAreaTime = 0;
 		}
-	} else if (fSelected->Submenu() != NULL &&
-		system_time() - selectedTime > kOpenSubmenuDelay) {
+	} else if (fSelected->Submenu() != NULL) {
 		_SelectItem(fSelected, true);

 		if (!navAreaRectAbove.IsValid() && !navAreaRectBelow.IsValid()) {
@@ -1964,9 +1920,6 @@
 				navAreaRectBelow);
 		}
 	}
-
-	if (fState != MENU_STATE_TRACKING)
-		fState = MENU_STATE_TRACKING;
 }


@@ -2378,7 +2331,7 @@

 	BPoint point;
 	if (superMenu->Layout() == B_ITEMS_IN_COLUMN)
-		point = superItem->Frame().RightTop() + BPoint(1.0f, 1.0f);
+		point = superItem->Frame().RightTop() + BPoint(1.0f, 0.0f);
 	else
 		point = superItem->Frame().LeftBottom() + BPoint(1.0f, 1.0f);

@@ -2497,10 +2450,34 @@
 	if (!item->IsEnabled())
 		return;

+	// called from BWindow for shortcut handling
+	if (now) {
+		// Lock the root menu window before calling BMenuItem::Invoke()
+		BMenu* parent = this;
+		BMenu* rootMenu = NULL;
+		do {
+			rootMenu = parent;
+			parent = rootMenu->Supermenu();
+		} while (parent != NULL);
+
+		if (rootMenu->LockLooper()) {
+			item->Invoke();
+			rootMenu->UnlockLooper();
+		}
+		return;
+	}
+
+	{
+		if (fTrackState == NULL)
+			return;
+		AutoLocker<BLocker> locker(fTrackState->locker);
+		if (fTrackState->invokedItem != NULL)
+			return;
+		fTrackState->invokedItem = item;
+	}
+
 	// Do the "selected" animation
-	// TODO: Doesn't work. This is supposed to highlight
-	// and dehighlight the item, works on beos but not on haiku.
-	if (!item->Submenu() && LockLooper()) {
+	if (LockLooper()) {
 		snooze(50000);
 		item->Select(true);
 		Window()->UpdateIfNeeded();
@@ -2515,19 +2492,6 @@
 		Window()->UpdateIfNeeded();
 		UnlockLooper();
 	}
-
-	// Lock the root menu window before calling BMenuItem::Invoke()
-	BMenu* parent = this;
-	BMenu* rootMenu = NULL;
-	do {
-		rootMenu = parent;
-		parent = rootMenu->Supermenu();
-	} while (parent != NULL);
-
-	if (rootMenu->LockLooper()) {
-		item->Invoke();
-		rootMenu->UnlockLooper();
-	}
 }


@@ -2680,6 +2644,7 @@
 		if (subMenu != NULL && subMenu->Window() == NULL) {
 			if (!subMenu->_Show(selectFirstItem, keyDown)) {
 				// something went wrong, deselect the item
+				printf("_SelectItem: can't show submenu\n");
 				fSelected->Select(false);
 				fSelected = NULL;
 			}
@@ -2698,7 +2663,7 @@
 	if (nextItem == NULL)
 		return false;

-	_SelectItem(nextItem, dynamic_cast<BMenuBar*>(this) != NULL);
+	_SelectItem(nextItem, true, false, true);

 	if (LockLooper()) {
 		be_app->ObscureCursor();
@@ -3000,24 +2965,7 @@
 bool
 BMenu::_OkToProceed(BMenuItem* item, bool keyDown)
 {
-	BPoint where;
-	uint32 buttons;
-	GetMouse(&where, &buttons, false);
-	bool stickyMode = _IsStickyMode();
-	// Quit if user clicks the mouse button in sticky mode
-	// or releases the mouse button in nonsticky mode
-	// or moves the pointer over another item
-	// TODO: I added the check for BMenuBar to solve a problem with Deskbar.
-	// BeOS seems to do something similar. This could also be a bug in
-	// Deskbar, though.
-	if ((buttons != 0 && stickyMode)
-		|| ((dynamic_cast<BMenuBar*>(this) == NULL
-			&& (buttons == 0 && !stickyMode))
-		|| ((_HitTestItems(where) != item) && !keyDown))) {
-		return false;
-	}
-
-	return true;
+	return true; /* !!! */
 }


@@ -3037,27 +2985,11 @@
 void
 BMenu::_QuitTracking(bool onlyThis)
 {
-	_SelectItem(NULL);
-	if (BMenuBar* menuBar = dynamic_cast<BMenuBar*>(this))
-		menuBar->_RestoreFocus();
-
-	fState = MENU_STATE_CLOSED;
-
-	if (!onlyThis) {
-		// Close the whole menu hierarchy
-		if (Supermenu() != NULL)
-			Supermenu()->fState = MENU_STATE_CLOSED;
-
-		if (_IsStickyMode())
-			_SetStickyMode(false);
-
-		if (LockLooper()) {
-			be_app->ShowCursor();
-			UnlockLooper();
-		}
-	}
-
-	_Hide();
+	if (fTrackState == NULL)
+		return;
+	AutoLocker<BLocker> locker(fTrackState->locker);
+	fTrackState->quit = true;
+	send_data(fTrackState->trackThread, MENU_TRACK_COMMAND_DONE, NULL, 0);
 }


diff --git a/src/kits/interface/MenuBar.cpp b/src/kits/interface/MenuBar.cpp
index 791cbc4..81cae9d 100644
--- a/src/kits/interface/MenuBar.cpp
+++ b/src/kits/interface/MenuBar.cpp
@@ -173,6 +173,9 @@
 void
 BMenuBar::WindowActivated(bool state)
 {
+	if (!state) {
+		BPrivate::MenuPrivate(this).QuitTracking(false);
+	}
 	BView::WindowActivated(state);
 }

@@ -550,152 +553,24 @@
 BMenuItem*
 BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu)
 {
-	// TODO: Cleanup, merge some "if" blocks if possible
 	BMenuItem* item = NULL;
-	fState = MENU_STATE_TRACKING;
-	fChosenItem = NULL;
-		// we will use this for keyboard selection

-	BPoint where;
-	uint32 buttons;
-	if (LockLooper()) {
-		if (startIndex != -1) {
-			be_app->ObscureCursor();
-			_SelectItem(ItemAt(startIndex), true, false);
-		}
-		GetMouse(&where, &buttons);
-		UnlockLooper();
-	}
-
-	while (fState != MENU_STATE_CLOSED) {
-		bigtime_t snoozeAmount = 40000;
-		if (!LockLooper())
-			break;
-
-		item = dynamic_cast<_BMCMenuBar_*>(this) != NULL ? ItemAt(0)
-			: _HitTestItems(where, B_ORIGIN);
-
-		if (_OverSubmenu(fSelected, ConvertToScreen(where))
-			|| fState == MENU_STATE_KEY_TO_SUBMENU) {
-			// call _Track() from the selected sub-menu when the mouse cursor
-			// is over its window
-			BMenu* submenu = fSelected->Submenu();
-			UnlockLooper();
-			snoozeAmount = 30000;
-			submenu->_SetStickyMode(_IsStickyMode());
-			int localAction;
-			fChosenItem = submenu->_Track(&localAction);
-
-			// The mouse could have meen moved since the last time we
-			// checked its position, or buttons might have been pressed.
-			// Unfortunately our child menus don't tell
-			// us the new position.
-			// TODO: Maybe have a shared struct between all menus
-			// where to store the current mouse position ?
-			// (Or just use the BView mouse hooks)
-			BPoint newWhere;
-			if (LockLooper()) {
-				GetMouse(&newWhere, &buttons);
-				UnlockLooper();
-			}
-
-			// Needed to make BMenuField child menus "sticky"
-			// (see ticket #953)
-			if (localAction == MENU_STATE_CLOSED) {
-				if (fExtraRect != NULL && fExtraRect->Contains(where)
-					&& point_distance(newWhere, where) < 9) {
-					// 9 = 3 pixels ^ 2 (since point_distance() returns the
-					// square of the distance)
-					_SetStickyMode(true);
-					fExtraRect = NULL;
-				} else
-					fState = MENU_STATE_CLOSED;
-			}
-			if (!LockLooper())
-				break;
-		} else if (item != NULL) {
-			if (item->Submenu() != NULL && item != fSelected) {
-				if (item->Submenu()->Window() == NULL) {
-					// open the menu if it's not opened yet
-					_SelectItem(item);
-				} else {
-					// Menu was already opened, close it and bail
-					_SelectItem(NULL);
-					fState = MENU_STATE_CLOSED;
-					fChosenItem = NULL;
-				}
-			} else {
-				// No submenu, just select the item
-				_SelectItem(item);
-			}
-		} else if (item == NULL && fSelected != NULL
-			&& !_IsStickyMode() && Bounds().Contains(where)) {
-			_SelectItem(NULL);
-			fState = MENU_STATE_TRACKING;
-		}
-
-		UnlockLooper();
-
-		if (fState != MENU_STATE_CLOSED) {
-			BPoint newWhere = where;
-			uint32 newButtons = buttons;
-
-			do {
-				// If user doesn't move the mouse or change buttons loop
-				// here so that we don't interfere with keyboard menu
-				// navigation
-				snooze(snoozeAmount);
-				if (!LockLooper())
-					break;
-
-				GetMouse(&newWhere, &newButtons);
-				UnlockLooper();
-			} while (newWhere == where && newButtons == buttons
-				&& fState == MENU_STATE_TRACKING);
-
-			if (newButtons != 0 && _IsStickyMode()) {
-				if (item == NULL || (item->Submenu() != NULL
-						&& item->Submenu()->Window() != NULL)) {
-					// clicked outside the menu bar or on item with already
-					// open sub menu
-					fState = MENU_STATE_CLOSED;
-				} else
-					_SetStickyMode(false);
-			} else if (newButtons == 0 && !_IsStickyMode()) {
-				if ((fSelected != NULL && fSelected->Submenu() == NULL)
-					|| item == NULL) {
-					// clicked on an item without a submenu or clicked and
-					// released the mouse button outside the menu bar
-					fChosenItem = fSelected;
-					fState = MENU_STATE_CLOSED;
-				} else
-					_SetStickyMode(true);
-			}
-			where = newWhere;
-			buttons = newButtons;
-		}
-	}
+	item = BMenu::_Track(action, startIndex);

 	if (LockLooper()) {
 		if (fSelected != NULL)
 			_SelectItem(NULL);

-		if (fChosenItem != NULL)
-			fChosenItem->Invoke();
+		if (item != NULL)
+			item->Invoke();

 		_RestoreFocus();
 		UnlockLooper();
 	}

-	if (_IsStickyMode())
-		_SetStickyMode(false);
-
 	_DeleteMenuWindow();

-	if (action != NULL)
-		*action = fState;
-
-	return fChosenItem;
+	return item;
 }



--
To view, visit https://review.haiku-os.org/c/haiku/+/2284
To unsubscribe, or for help writing mail filters, visit https://review.haiku-os.org/settings

Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: Ia693570e9bf4cbea33cd7d71bd5e7249c089959f
Gerrit-Change-Number: 2284
Gerrit-PatchSet: 1
Gerrit-Owner: X512 <danger_mail@list.ru>
Gerrit-MessageType: newchange

[Attachment #3 (text/html)]

<p>X512 has uploaded this change for <strong>review</strong>.</p><p><a \
href="https://review.haiku-os.org/c/haiku/+/2284">View Change</a></p><pre \
style="font-family: monospace,monospace; white-space: pre-wrap;">Interface kit: \
rewrite menu logic by using input event<br><br>WIP, DON&#39;T MERGE<br><br>Keyboard \
navigation is implemented:<br>	* Alt+Esc opens menu.<br>	* Arrow keys are used to \
move to previous/next item and enter/leave submenu.<br>	* Character key invoke or \
enter item with underlined character.<br>	* Enter invoke menu, Esc leave current \
menu.<br><br>TODO:<br>	* Fix mouse deadlock.<br>	* Close menu when clicked \
outside.<br>	* Fix sticky mode.<br>	* Scroll menu on keyboard navigation.<br>	* Fix \
freeze when dymanically building submenu<br><br>Change-Id: \
Ia693570e9bf4cbea33cd7d71bd5e7249c089959f<br>---<br>M \
headers/os/interface/Menu.h<br>M headers/private/interface/MenuPrivate.h<br>M \
src/kits/interface/Menu.cpp<br>M src/kits/interface/MenuBar.cpp<br>4 files changed, \
243 insertions(+), 417 deletions(-)<br><br></pre><pre style="font-family: \
monospace,monospace; white-space: pre-wrap;">git pull ssh://git.haiku-os.org:22/haiku \
refs/changes/84/2284/1</pre><pre style="font-family: monospace,monospace; \
white-space: pre-wrap;"><span>diff --git a/headers/os/interface/Menu.h \
b/headers/os/interface/Menu.h</span><br><span>index dcb8ab6..e465a33 \
100644</span><br><span>--- a/headers/os/interface/Menu.h</span><br><span>+++ \
b/headers/os/interface/Menu.h</span><br><span>@@ -17,6 +17,7 @@</span><br><span> \
</span><br><span> </span><br><span> namespace BPrivate {</span><br><span \
style="color: hsl(120, 100%, 40%);">+	class MenuTrackState;</span><br><span> 	class \
BMenuWindow;</span><br><span> 	class ExtraMenuData;</span><br><span> 	class \
TriggerList;</span><br><span>@@ -190,7 +191,7 @@</span><br><span> \
bool				_Show(bool selectFirstItem = false,</span><br><span> 									bool keyDown = \
false);</span><br><span> 			void				_Hide();</span><br><span style="color: hsl(0, \
100%, 40%);">-			BMenuItem*			_Track(int* action, long start = -1);</span><br><span \
style="color: hsl(120, 100%, 40%);">+			BMenuItem*			_Track(int32* action, int32 \
start = -1);</span><br><span> </span><br><span> \
void				_UpdateNavigationArea(BPoint position,</span><br><span> 									BRect&amp; \
navAreaRectAbove,</span><br><span>@@ -281,7 +282,7 @@</span><br><span> \
static	uint32				sCommandKey;</span><br><span> \
static	uint32				sMenuKey;</span><br><span> </span><br><span style="color: hsl(0, \
100%, 40%);">-			BMenuItem*			fChosenItem;</span><br><span style="color: hsl(120, \
100%, 40%);">+			BPrivate::MenuTrackState* fTrackState;</span><br><span> \
BList				fItems;</span><br><span> 			BRect				fPad;</span><br><span> \
BMenuItem*			fSelected;</span><br><span>diff --git \
a/headers/private/interface/MenuPrivate.h \
b/headers/private/interface/MenuPrivate.h</span><br><span>index 4627b70..e819fc8 \
100644</span><br><span>--- \
a/headers/private/interface/MenuPrivate.h</span><br><span>+++ \
b/headers/private/interface/MenuPrivate.h</span><br><span>@@ -11,6 +11,7 \
@@</span><br><span> </span><br><span> </span><br><span> #include \
&lt;Menu.h&gt;</span><br><span style="color: hsl(120, 100%, 40%);">+#include \
&lt;Locker.h&gt;</span><br><span> </span><br><span> </span><br><span> enum \
menu_states {</span><br><span>@@ -21,6 +22,10 @@</span><br><span> 	MENU_STATE_CLOSED \
= 5</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, \
100%, 40%);">+enum menu_track_command {</span><br><span style="color: hsl(120, 100%, \
40%);">+	MENU_TRACK_COMMAND_DONE = 0</span><br><span style="color: hsl(120, 100%, \
40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> \
</span><br><span> class BBitmap;</span><br><span> class BMenu;</span><br><span>@@ \
-78,6 +83,19 @@</span><br><span> </span><br><span> };</span><br><span> \
</span><br><span style="color: hsl(120, 100%, 40%);">+struct MenuTrackState \
{</span><br><span style="color: hsl(120, 100%, 40%);">+	thread_id \
trackThread;</span><br><span style="color: hsl(120, 100%, 40%);">+	BLocker \
locker;</span><br><span style="color: hsl(120, 100%, 40%);">+	bool \
quit;</span><br><span style="color: hsl(120, 100%, 40%);">+	BMenu* \
rootMenu;</span><br><span style="color: hsl(120, 100%, 40%);">+	BMenu* \
curMenu;</span><br><span style="color: hsl(120, 100%, 40%);">+	BMenuItem \
*invokedItem;</span><br><span style="color: hsl(120, 100%, 40%);">+	BRect \
navAreaRectAbove;</span><br><span style="color: hsl(120, 100%, 40%);">+	BRect \
navAreaRectBelow;</span><br><span style="color: hsl(120, 100%, 40%);">+	bigtime_t \
selectedTime;</span><br><span style="color: hsl(120, 100%, 40%);">+	bigtime_t \
navigationAreaTime;</span><br><span style="color: hsl(120, 100%, \
40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> \
};	// namespace BPrivate</span><br><span> </span><br><span> </span><br><span>diff \
--git a/src/kits/interface/Menu.cpp \
b/src/kits/interface/Menu.cpp</span><br><span>index 079918b..288638d \
100644</span><br><span>--- a/src/kits/interface/Menu.cpp</span><br><span>+++ \
b/src/kits/interface/Menu.cpp</span><br><span>@@ -39,6 +39,7 @@</span><br><span> \
#include &lt;SystemCatalog.h&gt;</span><br><span> #include \
&lt;UnicodeChar.h&gt;</span><br><span> #include &lt;Window.h&gt;</span><br><span \
style="color: hsl(120, 100%, 40%);">+#include &lt;AutoLocker.h&gt;</span><br><span> \
</span><br><span> #include &lt;AppServerLink.h&gt;</span><br><span> #include \
&lt;binary_compatibility/Interface.h&gt;</span><br><span>@@ -226,7 +227,7 \
@@</span><br><span> BMenu::BMenu(const char* name, menu_layout \
layout)</span><br><span> 	:</span><br><span> 	BView(BRect(0, 0, 0, 0), name, 0, \
B_WILL_DRAW),</span><br><span style="color: hsl(0, 100%, \
40%);">-	fChosenItem(NULL),</span><br><span style="color: hsl(120, 100%, \
40%);">+	fTrackState(NULL),</span><br><span> 	fPad(std::max(14.0f, \
be_plain_font-&gt;Size() + 2.0f), 2.0f, 20.0f, 0.0f),</span><br><span> \
fSelected(NULL),</span><br><span> 	fCachedMenuWindow(NULL),</span><br><span>@@ -261,7 \
+262,7 @@</span><br><span> BMenu::BMenu(const char* name, float width, float \
height)</span><br><span> 	:</span><br><span> 	BView(BRect(0.0f, 0.0f, 0.0f, 0.0f), \
name, 0, B_WILL_DRAW),</span><br><span style="color: hsl(0, 100%, \
40%);">-	fChosenItem(NULL),</span><br><span style="color: hsl(120, 100%, \
40%);">+	fTrackState(NULL),</span><br><span> 	fPad(14.0f, 2.0f, 20.0f, \
0.0f),</span><br><span> 	fSelected(NULL),</span><br><span> \
fCachedMenuWindow(NULL),</span><br><span>@@ -296,7 +297,7 @@</span><br><span> \
BMenu::BMenu(BMessage* archive)</span><br><span> 	:</span><br><span> \
BView(archive),</span><br><span style="color: hsl(0, 100%, \
40%);">-	fChosenItem(NULL),</span><br><span style="color: hsl(120, 100%, \
40%);">+	fTrackState(NULL),</span><br><span> 	fPad(14.0f, 2.0f, 20.0f, \
0.0f),</span><br><span> 	fSelected(NULL),</span><br><span> \
fCachedMenuWindow(NULL),</span><br><span>@@ -453,6 +454,10 @@</span><br><span> \
void</span><br><span> BMenu::MessageReceived(BMessage* message)</span><br><span> \
{</span><br><span style="color: hsl(120, 100%, 40%);">+	if (fTrackState == NULL) \
{</span><br><span style="color: hsl(120, 100%, \
40%);">+		BView::MessageReceived(message);</span><br><span style="color: hsl(120, \
100%, 40%);">+		return;</span><br><span style="color: hsl(120, 100%, \
40%);">+	}</span><br><span> 	switch (message-&gt;what) {</span><br><span> 		case \
B_MOUSE_WHEEL_CHANGED:</span><br><span> 		{</span><br><span>@@ -479,6 +484,58 \
@@</span><br><span> 			break;</span><br><span> 		}</span><br><span> </span><br><span \
style="color: hsl(120, 100%, 40%);">+		case B_MOUSE_DOWN:</span><br><span \
style="color: hsl(120, 100%, 40%);">+			if (fStickyMode) {</span><br><span \
style="color: hsl(120, 100%, 40%);">+				if (fSelected != NULL) {</span><br><span \
style="color: hsl(120, 100%, 40%);">+					_InvokeItem(fSelected);</span><br><span \
style="color: hsl(120, 100%, 40%);">+				}</span><br><span style="color: hsl(120, \
100%, 40%);">+				_QuitTracking(false);</span><br><span style="color: hsl(120, 100%, \
40%);">+			}</span><br><span style="color: hsl(120, 100%, \
40%);">+			BView::MessageReceived(message);</span><br><span style="color: hsl(120, \
100%, 40%);">+			break;</span><br><span style="color: hsl(120, 100%, 40%);">+		case \
B_MOUSE_UP:</span><br><span style="color: hsl(120, 100%, 40%);">+			if (!fStickyMode) \
{</span><br><span style="color: hsl(120, 100%, 40%);">+				if (fSelected != NULL) \
{</span><br><span style="color: hsl(120, 100%, \
40%);">+					_InvokeItem(fSelected);</span><br><span style="color: hsl(120, 100%, \
40%);">+				}</span><br><span style="color: hsl(120, 100%, \
40%);">+				_QuitTracking(false);</span><br><span style="color: hsl(120, 100%, \
40%);">+			}</span><br><span style="color: hsl(120, 100%, \
40%);">+			BView::MessageReceived(message);</span><br><span style="color: hsl(120, \
100%, 40%);">+			break;</span><br><span style="color: hsl(120, 100%, 40%);">+		case \
B_MOUSE_MOVED: {</span><br><span style="color: hsl(120, 100%, 40%);">+			BPoint where \
= B_ORIGIN;</span><br><span style="color: hsl(120, 100%, 40%);">+			int32 buttons = \
0;</span><br><span style="color: hsl(120, 100%, 40%);">+			int32 transit = \
B_OUTSIDE_VIEW;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span \
style="color: hsl(120, 100%, \
40%);">+			message-&gt;FindPoint(&quot;be:view_where&quot;, \
&amp;where);</span><br><span style="color: hsl(120, 100%, \
40%);">+			message-&gt;FindInt32(&quot;buttons&quot;, &amp;buttons);</span><br><span \
style="color: hsl(120, 100%, 40%);">+			message-&gt;FindInt32(&quot;be:transit&quot;, \
&amp;transit);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span \
style="color: hsl(120, 100%, 40%);">+			if (fTrackState == NULL) {</span><br><span \
style="color: hsl(120, 100%, \
40%);">+				BView::MessageReceived(message);</span><br><span style="color: hsl(120, \
100%, 40%);">+				return;</span><br><span style="color: hsl(120, 100%, \
40%);">+			}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span \
style="color: hsl(120, 100%, 40%);">+			AutoLocker&lt;BLocker&gt; \
locker(fTrackState-&gt;locker);</span><br><span style="color: hsl(120, 100%, \
40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+			BMenuItem \
*oldSelected = fSelected;</span><br><span style="color: hsl(120, 100%, \
40%);">+			BMenuItem* item = _HitTestItems(where, B_ORIGIN);</span><br><span \
style="color: hsl(120, 100%, 40%);">+			if (item == NULL) {</span><br><span \
style="color: hsl(120, 100%, 40%);">+				if ((fSelected != NULL) &amp;&amp; \
(fSelected-&gt;Submenu() == NULL)) {</span><br><span style="color: hsl(120, 100%, \
40%);">+					_SelectItem(NULL);</span><br><span style="color: hsl(120, 100%, \
40%);">+				}</span><br><span style="color: hsl(120, 100%, 40%);">+			} else \
{</span><br><span style="color: hsl(120, 100%, \
40%);">+				_UpdateStateOpenSelect(item, where, \
fTrackState-&gt;navAreaRectAbove,</span><br><span style="color: hsl(120, 100%, \
40%);">+					fTrackState-&gt;navAreaRectBelow, fTrackState-&gt;selectedTime, \
fTrackState-&gt;navigationAreaTime);</span><br><span style="color: hsl(120, 100%, \
40%);">+			}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span \
style="color: hsl(120, 100%, 40%);">+			if (fSelected != oldSelected)</span><br><span \
style="color: hsl(120, 100%, 40%);">+				fTrackState-&gt;curMenu = \
this;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span \
style="color: hsl(120, 100%, \
40%);">+			BView::MessageReceived(message);</span><br><span style="color: hsl(120, \
100%, 40%);">+			break;</span><br><span style="color: hsl(120, 100%, \
40%);">+		}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> \
default:</span><br><span> 			BView::MessageReceived(message);</span><br><span> \
break;</span><br><span>@@ -490,63 +547,70 @@</span><br><span> BMenu::KeyDown(const \
char* bytes, int32 numBytes)</span><br><span> {</span><br><span> 	// TODO: Test how \
it works on BeOS R5 and implement this correctly</span><br><span style="color: \
hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+	if \
(fTrackState == NULL)</span><br><span style="color: hsl(120, 100%, \
40%);">+		return;</span><br><span style="color: hsl(120, 100%, \
40%);">+</span><br><span style="color: hsl(120, 100%, \
40%);">+	AutoLocker&lt;BLocker&gt; locker(fTrackState-&gt;locker);</span><br><span \
style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, \
40%);">+	if (fTrackState-&gt;curMenu != this) {</span><br><span style="color: \
hsl(120, 100%, 40%);">+		BMessenger \
messenger(fTrackState-&gt;curMenu);</span><br><span style="color: hsl(120, 100%, \
40%);">+		messenger.SendMessage(Window()-&gt;CurrentMessage());</span><br><span \
style="color: hsl(120, 100%, 40%);">+		return;</span><br><span style="color: hsl(120, \
100%, 40%);">+	}</span><br><span> 	switch (bytes[0]) {</span><br><span> 		case \
B_UP_ARROW:</span><br><span style="color: hsl(0, 100%, 40%);">-			if (fLayout == \
B_ITEMS_IN_COLUMN)</span><br><span style="color: hsl(120, 100%, 40%);">+			if \
(fLayout == B_ITEMS_IN_COLUMN) {</span><br><span> 				_SelectNextItem(fSelected, \
false);</span><br><span style="color: hsl(120, 100%, 40%);">+			} else if (fLayout == \
B_ITEMS_IN_ROW || fLayout == B_ITEMS_IN_MATRIX) {</span><br><span style="color: \
hsl(120, 100%, 40%);">+				if (Supermenu() != NULL) {</span><br><span style="color: \
hsl(120, 100%, 40%);">+					_SelectItem(NULL);</span><br><span style="color: hsl(120, \
100%, 40%);">+					fTrackState-&gt;curMenu = Supermenu();</span><br><span \
style="color: hsl(120, 100%, 40%);">+				} else {</span><br><span style="color: \
hsl(120, 100%, 40%);">+					_QuitTracking(false);</span><br><span style="color: \
hsl(120, 100%, 40%);">+				}</span><br><span style="color: hsl(120, 100%, \
40%);">+			}</span><br><span> 			break;</span><br><span> </span><br><span> 		case \
B_DOWN_ARROW:</span><br><span style="color: hsl(0, 100%, 40%);">-		{</span><br><span \
style="color: hsl(0, 100%, 40%);">-			BMenuBar* bar = \
dynamic_cast&lt;BMenuBar*&gt;(Supermenu());</span><br><span style="color: hsl(0, \
100%, 40%);">-			if (bar != NULL &amp;&amp; fState == MENU_STATE_CLOSED) \
{</span><br><span style="color: hsl(0, 100%, 40%);">-				// tell MenuBar&#39;s \
_Track:</span><br><span style="color: hsl(0, 100%, 40%);">-				bar-&gt;fState = \
MENU_STATE_KEY_TO_SUBMENU;</span><br><span style="color: hsl(0, 100%, \
40%);">-			}</span><br><span style="color: hsl(0, 100%, 40%);">-			if (fLayout == \
B_ITEMS_IN_COLUMN)</span><br><span style="color: hsl(120, 100%, 40%);">+			if \
(fLayout == B_ITEMS_IN_COLUMN) {</span><br><span> 				_SelectNextItem(fSelected, \
true);</span><br><span style="color: hsl(0, 100%, 40%);">-			break;</span><br><span \
style="color: hsl(0, 100%, 40%);">-		}</span><br><span style="color: hsl(0, 100%, \
40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-		case \
B_LEFT_ARROW:</span><br><span style="color: hsl(0, 100%, 40%);">-			if (fLayout == \
B_ITEMS_IN_ROW)</span><br><span style="color: hsl(0, 100%, \

<div style="display:none"> Gerrit-Project: haiku </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: \
Ia693570e9bf4cbea33cd7d71bd5e7249c089959f </div> <div style="display:none"> \
Gerrit-Change-Number: 2284 </div> <div style="display:none"> Gerrit-PatchSet: 1 \
</div> <div style="display:none"> Gerrit-Owner: X512 &lt;danger_mail@list.ru&gt; \
</div> <div style="display:none"> Gerrit-MessageType: newchange </div>



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic