Ticket #1621: menus.diff
File menus.diff, 27.1 KB (added by , 17 years ago) |
---|
-
src/kits/interface/MenuField.cpp
8 8 * Ingo Weinhold <bonefish@cs.tu-berlin.de> 9 9 */ 10 10 11 #include <stdio.h> 11 12 #include <stdlib.h> 12 13 #include <string.h> 13 14 … … 296 297 void 297 298 BMenuField::MouseDown(BPoint where) 298 299 { 300 printf("BMenuField::MouseDown()\n"); 299 301 if (!fMenuBar->Frame().Contains(where)) 300 302 return; 301 303 304 printf("Inside menubar's frame\n"); 302 305 BRect bounds = fMenuBar->ConvertFromParent(Bounds()); 303 306 304 307 fMenuBar->StartMenuBar(0, false, true, &bounds); -
src/kits/interface/PopUpMenu.cpp
16 16 17 17 #include <new> 18 18 19 #include <stdio.h> 19 20 20 21 struct popup_menu_data { 21 22 BPopUpMenu *object; … … 110 111 void 111 112 BPopUpMenu::MouseDown(BPoint point) 112 113 { 113 B View::MouseDown(point);114 BMenu::MouseDown(point); 114 115 } 115 116 116 117 117 118 void 118 119 BPopUpMenu::MouseUp(BPoint point) 119 120 { 120 B View::MouseUp(point);121 BMenu::MouseUp(point); 121 122 } 122 123 123 124 124 125 void 125 126 BPopUpMenu::MouseMoved(BPoint point, uint32 code, const BMessage *msg) 126 127 { 127 B View::MouseMoved(point, code, msg);128 BMenu::MouseMoved(point, code, msg); 128 129 } 129 130 130 131 … … 388 389 window->UpdateIfNeeded(); 389 390 } 390 391 391 392 status_t unused; 392 393 while (wait_for_thread(fTrackThread, &unused) == B_INTERRUPTED) 393 394 ; 394 395 -
src/kits/interface/BMCPrivate.cpp
35 35 filter_result 36 36 _BMCFilter_::Filter(BMessage *message, BHandler **handler) 37 37 { 38 if (message->what == B_MOUSE_DOWN) {38 /*if (message->what == B_MOUSE_DOWN) { 39 39 if (BView *view = dynamic_cast<BView *>(*handler)) { 40 40 BPoint point; 41 41 message->FindPoint("be:view_where", &point); 42 view->ConvertToParent(&point); 43 message->ReplacePoint("be:view_where", point); 44 *handler = fMenuField; 42 if (view->Bounds().Contains(point)) { 43 view->ConvertToParent(&point); 44 message->ReplacePoint("be:view_where", point); 45 *handler = fMenuField; 46 } 45 47 } 46 } 48 }*/ 47 49 48 50 return B_DISPATCH_MESSAGE; 49 51 } … … 228 230 229 231 230 232 void 233 _BMCMenuBar_::MouseDown(BPoint where) 234 { 235 thread_info info; 236 if (fMenuField->fMenuTaskID >= 0 237 && get_thread_info(fMenuField->fMenuTaskID, &info) == B_OK 238 && !Bounds().Contains(where)) { 239 BMenu::MouseDown(where); 240 } else if (Bounds().Contains(where)) { 241 BPoint point = where; 242 ConvertToParent(&point); 243 fMenuField->MouseDown(point); 244 } 245 } 246 247 248 void 249 _BMCMenuBar_::MouseUp(BPoint where) 250 { 251 if (!Bounds().Contains(where)) 252 BMenu::MouseUp(where); 253 } 254 255 256 void 257 _BMCMenuBar_::MouseMoved(BPoint where, uint32 code, const BMessage *message) 258 { 259 printf("BMC MouseMoved\n"); 260 // Eat the first mousemoved event 261 /*if (!fMoved) 262 fMoved = true; 263 else 264 BMenuBar::MouseMoved(where, code, message);*/ 265 } 266 267 268 void 231 269 _BMCMenuBar_::FrameResized(float width, float height) 232 270 { 233 271 // we need to take care of resizing and cleaning up -
src/kits/interface/Menu.cpp
4 4 * 5 5 * Authors: 6 6 * Marc Flerackers (mflerackers@androme.be) 7 * Stefano Ceccherini ( burton666@libero.it)7 * Stefano Ceccherini (stefano.ceccherini@gmail.com) 8 8 */ 9 9 10 10 #include <new> 11 11 #include <ctype.h> 12 12 #include <string.h> 13 13 14 #define DEBUG 1 15 16 #include <Application.h> 14 17 #include <Debug.h> 15 18 #include <File.h> 16 19 #include <FindDirectory.h> … … 183 186 fAscent(-1.0f), 184 187 fDescent(-1.0f), 185 188 fFontHeight(-1.0f), 186 f State(0),189 fTrackingMenu(NULL), 187 190 fLayout(layout), 188 191 fExtraRect(NULL), 189 192 fMaxContentWidth(0.0f), 190 193 fInitMatrixSize(NULL), 191 194 fExtraMenuData(NULL), 195 fTrackData(NULL), 192 196 fTrigger(0), 193 197 fResizeToFit(true), 194 198 fUseCachedMenuLayout(false), … … 216 220 fAscent(-1.0f), 217 221 fDescent(-1.0f), 218 222 fFontHeight(-1.0f), 219 f State(0),223 fTrackingMenu(NULL), 220 224 fLayout(B_ITEMS_IN_MATRIX), 221 225 fExtraRect(NULL), 222 226 fMaxContentWidth(0.0f), 223 227 fInitMatrixSize(NULL), 224 228 fExtraMenuData(NULL), 229 fTrackData(NULL), 225 230 fTrigger(0), 226 231 fResizeToFit(true), 227 232 fUseCachedMenuLayout(false), … … 248 253 delete fInitMatrixSize; 249 254 delete fExtraMenuData; 250 255 delete fLayoutData; 256 delete fTrackData; 251 257 } 252 258 253 259 … … 262 268 fAscent(-1.0f), 263 269 fDescent(-1.0f), 264 270 fFontHeight(-1.0f), 265 f State(0),271 fTrackingMenu(NULL), 266 272 fLayout(B_ITEMS_IN_ROW), 267 273 fExtraRect(NULL), 268 274 fMaxContentWidth(0.0f), 269 275 fInitMatrixSize(NULL), 270 276 fExtraMenuData(NULL), 277 fTrackData(NULL), 271 278 fTrigger(0), 272 279 fResizeToFit(true), 273 280 fUseCachedMenuLayout(false), … … 285 292 } 286 293 287 294 288 BArchivable *295 BArchivable * 289 296 BMenu::Instantiate(BMessage* archive) 290 297 { 291 298 if (validate_instantiation(archive, "BMenu")) … … 877 884 } 878 885 879 886 887 void 888 BMenu::MouseDown(BPoint where) 889 { 890 PRINT(("%s MouseDown()\n", Name())); 891 if (!Bounds().Contains(where)) { 892 // The only case where this can happen is in the tracking menu, 893 // as it's the only one with an event mask set to receive 894 // mouse events outside its bounds. 895 ASSERT(fTrackingMenu == this); 896 if (fTrackData && !fTrackData->InsideMenu()) 897 _StopTracking(); 898 } 899 } 900 901 902 void 903 BMenu::MouseUp(BPoint where) 904 { 905 PRINT(("%s MouseUp(). fTrackingMenu = %p\n", Name(), fTrackingMenu)); 906 if (fTrackingMenu == NULL) 907 return; 908 909 if (_CustomTrackingWantsToQuit()) { 910 fTrackingMenu->_StopTracking(); 911 return; 912 } 913 914 BRect *extraRect = fExtraRect; 915 fExtraRect = NULL; 916 917 if (extraRect != NULL && extraRect->Contains(where)) { 918 printf("BMenu Inside the extra rect\n"); 919 //fTrackingMenu->_SetStickyMode(true); 920 return; 921 } 922 923 // Either we are inside our own bounds, or we are the tracking menu. 924 // In both cases, we need to stop tracking. 925 if (Bounds().Contains(where) 926 || (fTrackData && !fTrackData->InsideMenu())) 927 fTrackingMenu->_StopTracking(fSelected); 928 } 929 930 931 void 932 BMenu::MouseMoved(BPoint where, uint32 code, const BMessage* message) 933 { 934 PRINT(("%s MouseMoved (code: %ld)\n", Name(), code)); 935 if (fTrackingMenu != NULL && fTrackingMenu != this) { 936 ASSERT(fTrackingMenu->fTrackData != NULL); 937 if (code == B_ENTERED_VIEW) 938 fTrackingMenu->fTrackData->SetInsideMenu(true); 939 else if (code == B_EXITED_VIEW) 940 fTrackingMenu->fTrackData->SetInsideMenu(false); 941 } 942 943 BMenuItem *item = _HitTestItems(where); 944 if (item != NULL) 945 _SelectItem(item); 946 947 if (fTrackingMenu != NULL && _CustomTrackingWantsToQuit()) 948 fTrackingMenu->_StopTracking(); 949 } 950 951 880 952 BSize 881 953 BMenu::MinSize() 882 954 { … … 1080 1152 fAscent(-1.0f), 1081 1153 fDescent(-1.0f), 1082 1154 fFontHeight(-1.0f), 1083 f State(0),1155 fTrackingMenu(NULL), 1084 1156 fLayout(layout), 1085 1157 fExtraRect(NULL), 1086 1158 fMaxContentWidth(0.0f), 1087 1159 fInitMatrixSize(NULL), 1088 1160 fExtraMenuData(NULL), 1161 fTrackData(NULL), 1089 1162 fTrigger(0), 1090 1163 fResizeToFit(resizeToFit), 1091 1164 fUseCachedMenuLayout(false), … … 1251 1324 archive->FindFloat("_maxwidth", &fMaxContentWidth); 1252 1325 1253 1326 BMessage msg; 1254 1327 for (int32 i = 0; archive->FindMessage("_items", i, &msg) == B_OK; i++) { 1255 1328 BArchivable *object = instantiate_object(&msg); 1256 1329 if (BMenuItem *item = dynamic_cast<BMenuItem *>(object)) { 1257 1330 BRect bounds; … … 1284 1357 if (window == NULL) { 1285 1358 // Menu windows get the BMenu's handler name 1286 1359 window = new (nothrow) BMenuWindow(Name()); 1287 ourWindow = true;1360 ourWindow = true; 1288 1361 } 1289 1362 1290 1363 if (window == NULL) … … 1313 1386 1314 1387 _UpdateWindowViewSize(true); 1315 1388 window->Show(); 1316 1389 window->Activate(); 1390 1317 1391 if (selectFirstItem) 1318 1392 _SelectItem(ItemAt(0)); 1319 1393 … … 1354 1428 1355 1429 1356 1430 BMenuItem * 1357 BMenu::_Track(int *action, long start )1431 BMenu::_Track(int *action, long startIndex) 1358 1432 { 1359 // TODO: cleanup 1360 BMenuItem *item = NULL; 1361 bigtime_t openTime = system_time(); 1362 bigtime_t closeTime = 0; 1433 PRINT(("%s _Track()\n", Name())); 1363 1434 1364 f State = MENU_STATE_TRACKING;1365 if (f Super != NULL)1366 fSuper->fState = MENU_STATE_TRACKING_SUBMENU;1435 fTrackData = new (std::nothrow) BPrivate::TrackData(); 1436 if (fTrackData == NULL) 1437 return NULL; 1367 1438 1368 while (true) { 1369 if (_CustomTrackingWantsToQuit()) 1370 break; 1439 fTrackingMenu = this; 1440 fChosenItem = NULL; 1371 1441 1372 bool locked = LockLooper(); 1373 if (!locked) 1374 break; 1375 1376 bigtime_t snoozeAmount = 50000; 1377 BPoint location; 1378 uint32 buttons; 1379 GetMouse(&location, &buttons, true); 1380 1381 BMenuWindow *window = static_cast<BMenuWindow *>(Window()); 1382 1383 BPoint screenLocation = ConvertToScreen(location); 1384 if (window->CheckForScrolling(screenLocation)) { 1385 item = NULL; 1386 } else { 1387 item = _HitTestItems(location, B_ORIGIN); 1388 if (item != NULL) 1389 _UpdateStateOpenSelect(item, openTime, closeTime); 1390 } 1391 1392 // Track the submenu 1393 if (_OverSubmenu(fSelected, screenLocation)) { 1394 UnlockLooper(); 1395 locked = false; 1396 int submenuAction = MENU_STATE_TRACKING; 1397 BMenu *submenu = fSelected->Submenu(); 1398 bool wasSticky = _IsStickyMode(); 1399 if (wasSticky) 1400 submenu->_SetStickyMode(true); 1401 BMenuItem *submenuItem = submenu->_Track(&submenuAction); 1402 1403 // check if the user started holding down a mouse button in a submenu 1404 if (wasSticky && !_IsStickyMode()) { 1405 buttons = 1; 1406 // buttons must have been pressed in the meantime 1407 } 1408 1409 if (submenuAction == MENU_STATE_CLOSED) { 1410 item = submenuItem; 1411 fState = submenuAction; 1412 break; 1413 } 1414 1415 locked = LockLooper(); 1416 if (!locked) 1417 break; 1418 } else if (item == NULL) { 1419 if (_OverSuper(screenLocation)) { 1420 fState = MENU_STATE_TRACKING; 1421 UnlockLooper(); 1422 break; 1423 } 1424 1425 if (!_OverSubmenu(fSelected, screenLocation) 1426 && system_time() > closeTime + kHysteresis 1427 && fState != MENU_STATE_TRACKING_SUBMENU) { 1428 _SelectItem(NULL); 1429 fState = MENU_STATE_TRACKING; 1430 } 1431 1432 if (fSuper != NULL) { 1433 // Give supermenu the chance to continue tracking 1434 *action = fState; 1435 if (locked) 1436 UnlockLooper(); 1437 1438 return NULL; 1439 } 1440 } 1441 1442 if (locked) 1443 UnlockLooper(); 1444 1445 _UpdateStateClose(item, location, buttons); 1446 1447 if (fState == MENU_STATE_CLOSED) 1448 break; 1449 1450 snooze(snoozeAmount); 1451 } 1452 1453 if (action != NULL) 1454 *action = fState; 1455 1456 if (fSelected != NULL && LockLooper()) { 1457 _SelectItem(NULL); 1442 if (startIndex != -1) 1443 be_app->ObscureCursor(); 1444 if (LockLooper()) { 1445 if (startIndex != -1) 1446 _SelectItem(ItemAt(startIndex), true, true); 1447 SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); 1458 1448 UnlockLooper(); 1459 } 1449 } 1450 1451 fTrackData->Block(); 1452 // Will be released from another thread 1460 1453 1461 if (_IsStickyMode()) 1462 _SetStickyMode(false); 1454 _Hide(); 1463 1455 1464 // delete the menu window recycled for all the child menus 1465 _DeleteMenuWindow(); 1456 delete fTrackData; 1457 fTrackData = NULL; 1458 fTrackingMenu = NULL; 1466 1459 1467 return item; 1460 PRINT(("%s _Track exits\n", Name())); 1461 return fChosenItem; 1468 1462 } 1469 1463 1470 1464 1471 1465 void 1472 BMenu::_UpdateStateOpenSelect(BMenuItem* item, bigtime_t& openTime, 1473 bigtime_t& closeTime) 1466 BMenu::_StopTracking(BMenuItem *chosen) 1474 1467 { 1475 if (fState == MENU_STATE_CLOSED) 1468 // TODO: Added mostly for debugging reasons. 1469 // We might want to be less strict, and just 1470 // call _StopTracking on the correct menu ourselves 1471 if (fTrackingMenu == NULL || fTrackingMenu != this) 1476 1472 return; 1477 1473 1478 if (item != fSelected && system_time() > closeTime + kHysteresis) { 1479 _SelectItem(item, false); 1480 openTime = system_time(); 1481 } else if (system_time() > kHysteresis + openTime && item->Submenu() != NULL 1482 && item->Submenu()->Window() == NULL) { 1483 // Open the submenu if it's not opened yet, but only if 1484 // the mouse pointer stayed over there for some time 1485 // (hysteresis) 1486 _SelectItem(item); 1487 closeTime = system_time(); 1474 1475 fChosenItem = chosen; 1476 1477 if (LockLooper()) { 1478 SetEventMask(0, 0); 1479 UnlockLooper(); 1488 1480 } 1489 if (fState != MENU_STATE_TRACKING)1490 fState = MENU_STATE_TRACKING;1491 }1492 1481 1493 1494 void 1495 BMenu::_UpdateStateClose(BMenuItem* item, const BPoint& where, 1496 const uint32& buttons) 1497 { 1498 if (fState == MENU_STATE_CLOSED) 1499 return; 1500 1501 if (buttons != 0 && _IsStickyMode()) { 1502 if (item == NULL) 1503 fState = MENU_STATE_CLOSED; 1504 else { 1505 BMenu *supermenu = Supermenu(); 1506 for(; supermenu; supermenu = supermenu->Supermenu()) 1507 supermenu->_SetStickyMode(false); 1508 _SetStickyMode(false); 1509 } 1510 } else if (buttons == 0 && !_IsStickyMode()) { 1511 if (fExtraRect != NULL && fExtraRect->Contains(where)) { 1512 _SetStickyMode(true); 1513 fExtraRect = NULL; 1514 // This code should be executed only once 1515 } else 1516 fState = MENU_STATE_CLOSED; 1517 } 1482 if (fTrackData) 1483 fTrackData->Release(); 1518 1484 } 1519 1485 1520 1486 … … 1920 1886 int 1921 1887 BMenu::State(BMenuItem **item) const 1922 1888 { 1923 if (fState == MENU_STATE_TRACKING || fState == MENU_STATE_CLOSED) 1924 return fState; 1925 1926 if (fSelected != NULL && fSelected->Submenu() != NULL) 1927 return fSelected->Submenu()->State(item); 1928 1929 return fState; 1889 return 0; 1930 1890 } 1931 1891 1932 1892 … … 1991 1951 if (fCachedMenuWindow == NULL) { 1992 1952 char windowName[64]; 1993 1953 snprintf(windowName, 64, "%s cached menu", Name()); 1994 fCachedMenuWindow = new ( nothrow) BMenuWindow(windowName);1954 fCachedMenuWindow = new (std::nothrow) BMenuWindow(windowName); 1995 1955 } 1996 1956 1997 1957 return fCachedMenuWindow; … … 2089 2049 if (fSelected != NULL) { 2090 2050 fSelected->Select(false); 2091 2051 BMenu *subMenu = fSelected->Submenu(); 2092 if (subMenu != NULL && subMenu->Window() != NULL)2052 if (subMenu != NULL) 2093 2053 subMenu->_Hide(); 2094 2054 } 2095 2055 … … 2101 2061 if (fSelected != NULL && showSubmenu) { 2102 2062 BMenu *subMenu = fSelected->Submenu(); 2103 2063 if (subMenu != NULL && subMenu->Window() == NULL) { 2104 if (!subMenu->_Show(selectFirstItem)) { 2064 if (subMenu->_Show(selectFirstItem)) { 2065 subMenu->fTrackingMenu = fTrackingMenu; 2066 } else { 2105 2067 // something went wrong, deselect the item 2106 2068 fSelected->Select(false); 2107 2069 fSelected = NULL; … … 2158 2120 { 2159 2121 if (fStickyMode != on) { 2160 2122 // TODO: Ugly hack, but it needs to be done right here in this method 2161 BMenuBar *menuBar = dynamic_cast<BMenuBar *>(this);2123 /*BMenuBar *menuBar = dynamic_cast<BMenuBar *>(this); 2162 2124 if (on && menuBar != NULL && menuBar->LockLooper()) { 2163 2125 // Steal the focus from the current focus view 2164 2126 // (needed to handle keyboard navigation) 2165 2127 menuBar->_StealFocus(); 2166 2128 menuBar->UnlockLooper(); 2167 } 2129 }*/ 2168 2130 2169 2131 fStickyMode = on; 2170 2132 } … … 2335 2297 menuBar->_RestoreFocus(); 2336 2298 2337 2299 fChosenItem = NULL; 2338 fState = MENU_STATE_CLOSED;2339 2300 } 2340 2301 2341 2302 2303 // TrackData 2304 namespace BPrivate { 2305 2306 TrackData::TrackData() 2307 { 2308 fQuitSem = create_sem(0, "PSYCHO menu quit sem"); 2309 fInside = 0; 2310 } 2311 2312 2313 TrackData::~TrackData() 2314 { 2315 Release(); 2316 } 2317 2318 2319 void 2320 TrackData::SetInsideMenu(bool inside) 2321 { 2322 int32 value = inside ? 1 : -1; 2323 atomic_add(&fInside, value); 2324 } 2325 2326 2327 bool 2328 TrackData::InsideMenu() const 2329 { 2330 return fInside > 0; 2331 } 2332 2333 2334 void 2335 TrackData::Block() 2336 { 2337 while (acquire_sem(fQuitSem) == B_INTERRUPTED) 2338 ; 2339 } 2340 2341 2342 void 2343 TrackData::Release() 2344 { 2345 if (fQuitSem >= 0) { 2346 delete_sem(fQuitSem); 2347 fQuitSem = -1; 2348 } 2349 } 2350 2351 }; 2352 2342 2353 // #pragma mark - 2343 2354 2344 2355 -
src/kits/interface/Window.cpp
1041 1041 1042 1042 // Close an eventually opened menu, if this click targets the 1043 1043 // preferred handler, and unless the target is the menu itself 1044 BMenu *menu = dynamic_cast<BMenu *>(fFocus);1044 /*BMenu *menu = dynamic_cast<BMenu *>(fFocus); 1045 1045 if (menu != NULL && menu != view && PreferredHandler() == target 1046 1046 && menu->State() != MENU_STATE_CLOSED) { 1047 1047 menu->QuitTracking(); 1048 1048 return; 1049 } 1049 }*/ 1050 1050 1051 1051 if (view != NULL) { 1052 1052 BPoint where; -
src/kits/interface/MenuBar.cpp
202 202 void 203 203 BMenuBar::MouseDown(BPoint where) 204 204 { 205 if (fTracking) 206 return; 205 if (!fTracking) { 206 BWindow *window = Window(); 207 if (!window->IsActive() || !window->IsFront()) { 208 window->Activate(); 209 window->UpdateIfNeeded(); 210 } 211 212 StartMenuBar(-1, false, false); 207 213 208 BWindow *window = Window();209 if (!window->IsActive() || !window->IsFront()) {210 window->Activate();211 window->UpdateIfNeeded();214 } else if (!Bounds().Contains(where)) { 215 if (fTrackData && !fTrackData->InsideMenu()) 216 _StopTracking(); 217 return; 212 218 } 213 214 StartMenuBar(-1, false, false);219 220 MouseMoved(where, B_INSIDE_VIEW, NULL); 215 221 } 216 222 217 223 218 224 void 219 BMenuBar:: WindowActivated(bool state)225 BMenuBar::MouseUp(BPoint where) 220 226 { 221 BView::WindowActivated(state); 227 if (fTracking) { 228 BRect *extraRect = fExtraRect; 229 fExtraRect = NULL; 230 if (extraRect != NULL && extraRect->Contains(where)) { 231 printf("Inside the extra rect\n"); 232 // do nothing. 233 } else if ((fTrackData && !fTrackData->InsideMenu()) 234 && (!Bounds().Contains(where) 235 || (fSelected == NULL || fSelected->Submenu() == NULL))) { 236 // If mouse was released outside the menubar, 237 // or inside in a zone where there are no items, 238 // or on an item which doesn't have a submenu 239 // (cf. Menu preflet), stop tracking. 240 _StopTracking(fSelected); 241 } 242 } else 243 BView::MouseUp(where); 222 244 } 223 245 224 246 247 void 248 BMenuBar::MouseMoved(BPoint where, uint32 code, const BMessage* message) 249 { 250 BMessage *currentMessage = Window()->CurrentMessage(); 251 int32 buttons = 0; 252 currentMessage->FindInt32("buttons", &buttons); 253 254 if (fTracking && buttons != 0) { 255 BMenuItem *item = _HitTestItems(where); 256 if (item != NULL) 257 _SelectItem(item); 258 } else 259 BView::MouseMoved(where, code, message); 260 } 261 262 225 263 void 226 BMenuBar:: MouseUp(BPoint where)264 BMenuBar::WindowActivated(bool state) 227 265 { 228 BView:: MouseUp(where);266 BView::WindowActivated(state); 229 267 } 230 268 231 269 … … 384 422 385 423 fPrevFocusToken = -1; 386 424 fTracking = true; 387 425 388 426 window->MenusBeginning(); 389 427 390 428 fMenuSem = create_sem(0, "window close sem"); 391 429 _set_menu_sem_(window, fMenuSem); 392 430 … … 459 497 460 498 BMenuItem * 461 499 BMenuBar::_Track(int32 *action, int32 startIndex, bool showMenu) 462 { 463 // TODO: Cleanup, merge some "if" blocks if possible 464 fChosenItem = NULL; 500 { 501 BMenuItem *item = BMenu::_Track((int*)action, (int)startIndex); 465 502 466 503 BWindow *window = Window(); 467 fState = MENU_STATE_TRACKING;468 469 if (startIndex != -1) {470 be_app->ObscureCursor();471 if (window->Lock()) {472 _SelectItem(ItemAt(startIndex), true, true);473 window->Unlock();474 }475 }476 477 while (true) {478 bigtime_t snoozeAmount = 40000;479 bool locked = (Window() != NULL && window->Lock());//WithTimeout(200000)480 if (!locked)481 break;482 483 BPoint where;484 uint32 buttons;485 GetMouse(&where, &buttons, true);486 487 BMenuItem *menuItem = _HitTestItems(where, B_ORIGIN);488 if (menuItem != NULL) {489 // Select item if:490 // - no previous selection491 // - nonsticky mode and different selection,492 // - clicked in sticky mode493 if (fSelected == NULL494 || (!_IsStickyMode() && menuItem != fSelected)495 || (buttons != 0 && _IsStickyMode())) {496 if (menuItem->Submenu() != NULL) {497 if (menuItem->Submenu()->Window() == NULL) {498 // open the menu if it's not opened yet499 _SelectItem(menuItem);500 if (_IsStickyMode())501 _SetStickyMode(false);502 } else {503 // Menu was already opened, close it and bail504 _SelectItem(NULL);505 fState = MENU_STATE_CLOSED;506 fChosenItem = NULL;507 }508 } else {509 // No submenu, just select the item510 _SelectItem(menuItem);511 }512 }513 }514 515 if (_OverSubmenu(fSelected, ConvertToScreen(where))) {516 // call _Track() from the selected sub-menu when the mouse cursor517 // is over its window518 BMenu *menu = fSelected->Submenu();519 window->Unlock();520 locked = false;521 snoozeAmount = 30000;522 bool wasSticky = _IsStickyMode();523 if (wasSticky)524 menu->_SetStickyMode(true);525 int localAction;526 fChosenItem = menu->_Track(&localAction);527 if (menu->State(NULL) == MENU_STATE_TRACKING528 && menu->_IsStickyMode())529 menu->_SetStickyMode(false);530 531 // check if the user started holding down a mouse button in a submenu532 if (wasSticky && !_IsStickyMode()) {533 buttons = 1;534 // buttons must have been pressed in the meantime535 }536 537 // This code is needed to make menus538 // that are children of BMenuFields "sticky" (see ticket #953)539 if (localAction == MENU_STATE_CLOSED) {540 // The mouse could have meen moved since the last time we541 // checked its position. Unfortunately our child menus don't tell542 // us the new position.543 // TODO: Maybe have a shared struct between all menus544 // where to store the current mouse position ?545 BPoint newWhere;546 uint32 newButtons;547 if (window->Lock()) {548 GetMouse(&newWhere, &newButtons);549 window->Unlock();550 }551 552 if (fExtraRect != NULL && fExtraRect->Contains(where)553 // 9 = 3 pixels ^ 2 (since point_distance() returns the square of the distance)554 && point_distance(newWhere, where) < 9) {555 _SetStickyMode(true);556 fExtraRect = NULL;557 } else558 fState = MENU_STATE_CLOSED;559 }560 } else if (menuItem == NULL && fSelected != NULL561 && !_IsStickyMode() && fState != MENU_STATE_TRACKING_SUBMENU) {562 _SelectItem(NULL);563 fState = MENU_STATE_TRACKING;564 }565 566 if (locked)567 window->Unlock();568 569 if (fState == MENU_STATE_CLOSED570 || (buttons != 0 && _IsStickyMode() && menuItem == NULL))571 break;572 else if (buttons == 0 && !_IsStickyMode()) {573 if ((fSelected != NULL && fSelected->Submenu() == NULL)574 || menuItem == NULL) {575 fChosenItem = fSelected;576 break;577 } else578 _SetStickyMode(true);579 }580 581 if (snoozeAmount > 0)582 snooze(snoozeAmount);583 }584 585 504 if (window->Lock()) { 586 if (fSelected != NULL) 587 _SelectItem(NULL); 588 589 if (fChosenItem != NULL) 590 fChosenItem->Invoke(); 591 _RestoreFocus(); 505 _SelectItem(NULL); 506 if (item != NULL) 507 item->Invoke(); 508 SetEventMask(0, 0); 509 //_RestoreFocus(); 592 510 window->Unlock(); 593 511 } 594 595 if (_IsStickyMode()) 596 _SetStickyMode(false); 597 598 _DeleteMenuWindow(); 599 600 if (action != NULL) 601 *action = fState; 602 603 return fChosenItem; 512 return item; 604 513 } 605 514 606 515 -
headers/os/interface/Menu.h
18 18 namespace BPrivate { 19 19 class BMenuWindow; 20 20 class ExtraMenuData; 21 class TrackData; 21 22 class TriggerList; 22 23 } 23 24 … … 104 105 virtual void MessageReceived(BMessage* message); 105 106 virtual void KeyDown(const char* bytes, int32 numBytes); 106 107 virtual void Draw(BRect updateRect); 108 virtual void MouseDown(BPoint where); 109 virtual void MouseUp(BPoint where); 110 virtual void MouseMoved(BPoint where, uint32 code, 111 const BMessage* message); 107 112 virtual BSize MinSize(); 108 113 virtual BSize MaxSize(); 109 114 virtual BSize PreferredSize(); … … 178 183 void _InitData(BMessage* archive); 179 184 bool _Show(bool selectFirstItem = false); 180 185 void _Hide(); 186 181 187 BMenuItem* _Track(int* action, long start = -1); 188 void _StopTracking(BMenuItem *chosen = NULL); 182 189 183 void _UpdateStateOpenSelect(BMenuItem* item,184 bigtime_t& openTime, bigtime_t& closeTime);185 void _UpdateStateClose(BMenuItem* item,186 const BPoint& where, const uint32& buttons);187 188 190 bool _AddItem(BMenuItem* item, int32 index); 189 191 bool _RemoveItems(int32 index, int32 count, 190 192 BMenuItem* item, bool deleteItems = false); … … 250 252 float fAscent; 251 253 float fDescent; 252 254 float fFontHeight; 253 uint32 fState;255 BMenu* fTrackingMenu; 254 256 menu_layout fLayout; 255 257 BRect* fExtraRect; 256 258 float fMaxContentWidth; … … 259 261 260 262 LayoutData* fLayoutData; 261 263 262 int32 _reserved;263 264 BPrivate::TrackData* fTrackData; 265 264 266 char fTrigger; 265 267 bool fResizeToFit; 266 268 bool fUseCachedMenuLayout; -
headers/os/interface/MenuBar.h
47 47 virtual void MouseDown(BPoint where); 48 48 virtual void WindowActivated(bool state); 49 49 virtual void MouseUp(BPoint where); 50 virtual void MouseMoved(BPoint where, uint32 state, 51 const BMessage *message); 50 52 virtual void FrameMoved(BPoint newPosition); 51 53 virtual void FrameResized(float newWidth, float newHeight); 52 54 -
headers/private/interface/BMCPrivate.h
41 41 42 42 virtual void AttachedToWindow(); 43 43 virtual void Draw(BRect updateRect); 44 virtual void MouseDown(BPoint where); 45 virtual void MouseUp(BPoint where); 46 virtual void MouseMoved(BPoint where, uint32 code, const BMessage *message); 44 47 virtual void FrameResized(float width, float height); 45 48 virtual void MessageReceived(BMessage* msg); 46 49 virtual void MakeFocus(bool focused = true); … … 55 58 56 59 BMenuField *fMenuField; 57 60 bool fFixedSize; 58 BMessageRunner *fRunner;59 61 bool fShowPopUpMarker; 62 bool fMoved; 63 BMessageRunner *fRunner; 60 64 float fPreviousWidth; 65 61 66 }; 62 67 63 68 #endif // _BMC_PRIVATE_H -
headers/private/interface/MenuPrivate.h
1 /* 2 * Copyright 2001-2006, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stefano Ceccherini (stefano.ceccherini@gmail.com) 7 */ 1 8 #ifndef __MENU_PRIVATE_H 2 9 #define __MENU_PRIVATE_H 3 10 … … 8 15 MENU_STATE_CLOSED = 5 9 16 }; 10 17 18 namespace BPrivate { 11 19 20 class TrackData { 21 public: 22 TrackData(); 23 ~TrackData(); 24 25 void SetInsideMenu(bool inside); 26 bool InsideMenu() const; 27 28 void Block(); 29 void Release(); 30 private: 31 sem_id fQuitSem; 32 int32 fInside; 33 }; 34 35 }; 36 12 37 extern const char *kEmptyMenuLabel; 13 38 14 15 39 #endif // __MENU_PRIVATE_H -
src/servers/app/WindowLayer.cpp
855 855 fDesktop->ActivateWindow(this); 856 856 857 857 // eat the click if we don't accept first click 858 if ((Flags() & B_WILL_ACCEPT_FIRST_CLICK) == 0 859 || (Flags() & B_AVOID_FOCUS) != 0) 858 if (fFeel != kMenuWindowFeel 859 && ((Flags() & B_WILL_ACCEPT_FIRST_CLICK) == 0 860 || (Flags() & B_AVOID_FOCUS) != 0)) 860 861 return; 861 862 } 862 863 -
src/servers/app/Desktop.cpp
1171 1171 EventTarget* 1172 1172 Desktop::KeyboardEventTarget() 1173 1173 { 1174 #if 0 1174 1175 WindowLayer* window = _CurrentWindows().LastWindow(); 1175 1176 if (window != NULL && window->Feel() == kMenuWindowFeel) 1176 1177 return &window->EventTarget(); 1177 1178 #endif 1178 1179 if (FocusWindow() != NULL) 1179 1180 return &FocusWindow()->EventTarget(); 1180 1181