Changeset 561 for trunk/src/gui/widgets/qmenu.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/gui/widgets/qmenu.cpp
r305 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtGui module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 66 66 #include "qwidgetaction.h" 67 67 #include "qtoolbutton.h" 68 #include "qpushbutton.h" 69 #include <private/qpushbutton_p.h> 68 70 #include <private/qaction_p.h> 71 #include <private/qsoftkeymanager_p.h> 69 72 #ifdef QT3_SUPPORT 70 73 #include <qmenudata.h> … … 151 154 { 152 155 Q_Q(QMenu); 153 activationRecursionGuard = false;154 156 #ifndef QT_NO_WHATSTHIS 155 157 q->setAttribute(Qt::WA_CustomWhatsThis); … … 163 165 scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone; 164 166 } 167 168 #ifdef QT_SOFTKEYS_ENABLED 169 selectAction = QSoftKeyManager::createKeyedAction(QSoftKeyManager::SelectSoftKey, Qt::Key_Select, q); 170 cancelAction = QSoftKeyManager::createKeyedAction(QSoftKeyManager::CancelSoftKey, Qt::Key_Back, q); 171 selectAction->setVisible(false); // Don't show these in the menu 172 cancelAction->setVisible(false); 173 q->addAction(selectAction); 174 q->addAction(cancelAction); 175 #endif 176 } 177 178 int QMenuPrivate::scrollerHeight() const 179 { 180 Q_Q(const QMenu); 181 return qMax(QApplication::globalStrut().height(), q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q)); 182 } 183 184 // Windows, OS/2 and KDE allows menus to cover the taskbar, while GNOME and Mac don't 185 QRect QMenuPrivate::popupGeometry(const QWidget *widget) const 186 { 187 #if defined(Q_WS_WIN) || defined(Q_WS_PM) 188 return QApplication::desktop()->screenGeometry(widget); 189 #elif defined Q_WS_X11 190 if (X11->desktopEnvironment == DE_KDE) 191 return QApplication::desktop()->screenGeometry(widget); 192 else 193 return QApplication::desktop()->availableGeometry(widget); 194 #else 195 return QApplication::desktop()->availableGeometry(widget); 196 #endif 165 197 } 166 198 … … 195 227 } 196 228 197 void QMenuPrivate:: calcActionRects(QMap<QAction*, QRect> &actionRects, QList<QAction*> &actionList) const229 void QMenuPrivate::updateActionRects() const 198 230 { 199 231 Q_Q(const QMenu); 200 if (!itemsDirty) { 201 actionRects = this->actionRects; 202 actionList = this->actionList; 232 if (!itemsDirty) 203 233 return; 204 } 205 206 actionRects.clear(); 207 actionList.clear(); 208 QList<QAction*> items = filterActions(q->actions()); 234 235 q->ensurePolished(); 236 237 //let's reinitialize the buffer 238 actionRects.resize(actions.count()); 239 actionRects.fill(QRect()); 240 241 //let's try to get the last visible action 242 int lastVisibleAction = actions.count() - 1; 243 for(;lastVisibleAction >= 0; --lastVisibleAction) { 244 const QAction *action = actions.at(lastVisibleAction); 245 if (action->isVisible()) { 246 //removing trailing separators 247 if (action->isSeparator() && collapsibleSeparators) 248 continue; 249 break; 250 } 251 } 252 209 253 int max_column_width = 0, 210 dh = popupGeometry(QApplication::desktop()->screenNumber(q)).height(), 211 ncols = 1, 254 dh = popupGeometry(q).height(), 212 255 y = 0; 213 const int hmargin = q->style()->pixelMetric(QStyle::PM_MenuHMargin, 0, q), 214 vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q), 215 icone = q->style()->pixelMetric(QStyle::PM_SmallIconSize, 0, q); 256 QStyle *style = q->style(); 257 QStyleOption opt; 258 opt.init(q); 259 const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q), 260 vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q), 261 icone = style->pixelMetric(QStyle::PM_SmallIconSize, &opt, q); 262 const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, q); 263 const int deskFw = style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, &opt, q); 264 265 const int sfcMargin = style->sizeFromContents(QStyle::CT_Menu, &opt, QApplication::globalStrut(), q).width() - QApplication::globalStrut().width(); 266 const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin)); 267 const int tearoffHeight = tearoff ? style->pixelMetric(QStyle::PM_MenuTearoffHeight, &opt, q) : 0; 216 268 217 269 //for compatability now - will have to refactor this away.. … … 219 271 maxIconWidth = 0; 220 272 hasCheckableItems = false; 221 for(int i = 0; i < items.count(); i++) { 222 QAction *action = items.at(i); 223 if (widgetItems.value(action)) 273 ncols = 1; 274 sloppyAction = 0; 275 276 for (int i = 0; i < actions.count(); ++i) { 277 QAction *action = actions.at(i); 278 if (action->isSeparator() || !action->isVisible() || widgetItems.contains(action)) 224 279 continue; 280 //..and some members 225 281 hasCheckableItems |= action->isCheckable(); 226 282 QIcon is = action->icon(); 227 283 if (!is.isNull()) { 228 uint miw = maxIconWidth; 229 maxIconWidth = qMax<uint>(miw, icone + 4); 284 maxIconWidth = qMax<uint>(maxIconWidth, icone + 4); 230 285 } 231 286 } … … 233 288 //calculate size 234 289 QFontMetrics qfm = q->fontMetrics(); 235 for(int i = 0; i < items.count(); i++) { 236 QAction *action = items.at(i); 237 238 QFontMetrics fm(action->font().resolve(q->font())); 239 QSize sz; 290 bool previousWasSeparator = true; // this is true to allow removing the leading separators 291 for(int i = 0; i <= lastVisibleAction; i++) { 292 QAction *action = actions.at(i); 293 294 if (!action->isVisible() || 295 (collapsibleSeparators && previousWasSeparator && action->isSeparator())) 296 continue; // we continue, this action will get an empty QRect 297 298 previousWasSeparator = action->isSeparator(); 240 299 241 300 //let the style modify the above size.. 242 301 QStyleOptionMenuItem opt; 243 302 q->initStyleOption(&opt, action); 244 opt.rect = q->rect(); 245 303 const QFontMetrics &fm = opt.fontMetrics; 304 305 QSize sz; 246 306 if (QWidget *w = widgetItems.value(action)) { 247 sz =w->sizeHint().expandedTo(w->minimumSize()).expandedTo(w->minimumSizeHint()).boundedTo(w->maximumSize());307 sz = w->sizeHint().expandedTo(w->minimumSize()).expandedTo(w->minimumSizeHint()).boundedTo(w->maximumSize()); 248 308 } else { 249 309 //calc what I think the size is.. … … 263 323 #endif 264 324 } 265 int w = fm.boundingRect(QRect(), Qt::TextSingleLine, s).width(); 266 w -= s.count(QLatin1Char('&')) * fm.width(QLatin1Char('&')); 267 w += s.count(QLatin1String("&&")) * fm.width(QLatin1Char('&')); 268 sz.setWidth(w); 325 sz.setWidth(fm.boundingRect(QRect(), Qt::TextSingleLine | Qt::TextShowMnemonic, s).width()); 269 326 sz.setHeight(qMax(fm.height(), qfm.height())); 270 327 … … 276 333 } 277 334 } 278 sz = q->style()->sizeFromContents(QStyle::CT_MenuItem, &opt, sz, q);335 sz = style->sizeFromContents(QStyle::CT_MenuItem, &opt, sz, q); 279 336 } 280 337 281 338 282 339 if (!sz.isEmpty()) { 283 max_column_width = qMax(m ax_column_width, sz.width());340 max_column_width = qMax(min_column_width, qMax(max_column_width, sz.width())); 284 341 //wrapping 285 342 if (!scroll && 286 y+sz.height()+vmargin > dh - ( q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q)* 2)) {343 y+sz.height()+vmargin > dh - (deskFw * 2)) { 287 344 ncols++; 288 345 y = vmargin; 289 346 } 290 347 y += sz.height(); 291 //append item 292 actionRects.insert(action, QRect(0, 0, sz.width(), sz.height())); 293 actionList.append(action); 294 } 295 } 296 297 if (tabWidth) 298 max_column_width += tabWidth; //finally add in the tab width 348 //update the item 349 actionRects[i] = QRect(0, 0, sz.width(), sz.height()); 350 } 351 } 352 353 max_column_width += tabWidth; //finally add in the tab width 299 354 300 355 //calculate position 301 int x = hmargin; 302 y = vmargin; 303 304 for(int i = 0; i < actionList.count(); i++) { 305 QAction *action = actionList.at(i); 306 QRect &rect = actionRects[action]; 356 const int base_y = vmargin + fw + topmargin + 357 (scroll ? scroll->scrollOffset : 0) + 358 tearoffHeight; 359 int x = hmargin + fw + leftmargin; 360 y = base_y; 361 362 for(int i = 0; i < actions.count(); i++) { 363 QRect &rect = actionRects[i]; 307 364 if (rect.isNull()) 308 365 continue; 309 366 if (!scroll && 310 y+rect.height() > dh - (q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q) * 2)) { 311 ncols--; 312 if (ncols < 0) 313 qWarning("QMenu: Column calculation mismatch (%d)", ncols); 367 y+rect.height() > dh - deskFw * 2) { 314 368 x += max_column_width + hmargin; 315 y = vmargin;369 y = base_y; 316 370 } 317 371 rect.translate(x, y); //move 318 372 rect.setWidth(max_column_width); //uniform width 373 374 //we need to update the widgets geometry 375 if (QWidget *widget = widgetItems.value(actions.at(i))) { 376 widget->setGeometry(rect); 377 widget->setVisible(actions.at(i)->isVisible()); 378 } 379 319 380 y += rect.height(); 320 381 } 321 }322 323 void QMenuPrivate::updateActions()324 {325 Q_Q(const QMenu);326 if (!itemsDirty)327 return;328 sloppyAction = 0;329 calcActionRects(actionRects, actionList);330 for (QHash<QAction *, QWidget *>::ConstIterator item = widgetItems.constBegin(),331 end = widgetItems.constEnd(); item != end; ++item) {332 QAction *action = item.key();333 QWidget *widget = item.value();334 widget->setGeometry(actionRect(action));335 widget->setVisible(action->isVisible());336 }337 ncols = 1;338 int last_left = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q);339 if (!scroll) {340 for(int i = 0; i < actionList.count(); i++) {341 int left = actionRects.value(actionList.at(i)).left();342 if (left > last_left) {343 last_left = left;344 ncols++;345 }346 }347 }348 382 itemsDirty = 0; 349 383 } 350 384 351 QList<QAction *> QMenuPrivate::filterActions(const QList<QAction *> &actions) const352 {353 QList<QAction *> visibleActions;354 int i = 0;355 while (i < actions.count()) {356 QAction *action = actions.at(i);357 if (!action->isVisible()) {358 ++i;359 continue;360 }361 if (!action->isSeparator() || !collapsibleSeparators) {362 visibleActions.append(action);363 ++i;364 continue;365 }366 367 // no leading separators368 if (!visibleActions.isEmpty())369 visibleActions.append(action);370 371 // skip double/tripple/etc. separators372 while (i < actions.count()373 && (!actions.at(i)->isVisible() || actions.at(i)->isSeparator()))374 ++i;375 }376 377 if (collapsibleSeparators) {378 // remove trailing separators379 while (!visibleActions.isEmpty() && visibleActions.last()->isSeparator())380 visibleActions.removeLast();381 }382 383 return visibleActions;384 }385 386 385 QRect QMenuPrivate::actionRect(QAction *act) const 387 386 { 388 Q_Q(const QMenu); 389 QRect ret = actionRects.value(act); 390 if (ret.isNull()) 391 return ret; 392 if (scroll) 393 ret.translate(0, scroll->scrollOffset); 394 if (tearoff) 395 ret.translate(0, q->style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, q)); 396 const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q); 397 ret.translate(fw+leftmargin, fw+topmargin); 398 return ret; 399 } 387 int index = actions.indexOf(act); 388 if (index == -1) 389 return QRect(); 390 391 updateActionRects(); 392 393 //we found the action 394 return actionRects.at(index); 395 } 396 397 #if defined(Q_WS_MAC) 398 static const qreal MenuFadeTimeInSec = 0.150; 399 #endif 400 400 401 401 void QMenuPrivate::hideUpToMenuBar() 402 402 { 403 403 Q_Q(QMenu); 404 bool fadeMenus = q->style()->styleHint(QStyle::SH_Menu_FadeOutOnHide); 404 405 if (!tornoff) { 405 406 QWidget *caused = causedPopup.widget; … … 416 417 caused = m->d_func()->causedPopup.widget; 417 418 if (!m->d_func()->tornoff) 418 hideMenu(m); 419 m->d_func()->setCurrentAction(0); 420 } else { 421 #ifndef QT_NO_TOOLBUTTON 422 if (qobject_cast<QToolButton*>(caused) == 0) 423 #endif 424 qWarning("QMenu: Internal error"); 425 caused = 0; 419 hideMenu(m, fadeMenus); 420 if (!fadeMenus) // Mac doesn't clear the action until after hidden. 421 m->d_func()->setCurrentAction(0); 422 } else { caused = 0; 426 423 } 427 424 } 425 #if defined(Q_WS_MAC) 426 if (fadeMenus) { 427 QEventLoop eventLoop; 428 QTimer::singleShot(int(MenuFadeTimeInSec * 1000), &eventLoop, SLOT(quit())); 429 QMacWindowFader::currentFader()->performFade(); 430 eventLoop.exec(); 431 } 432 #endif 428 433 } 429 434 setCurrentAction(0); 430 435 } 431 436 432 void QMenuPrivate::hideMenu(QMenu *menu )437 void QMenuPrivate::hideMenu(QMenu *menu, bool justRegister) 433 438 { 434 439 if (!menu) 435 440 return; 436 437 441 #if !defined(QT_NO_EFFECTS) 438 442 menu->blockSignals(true); … … 440 444 // Flash item which is about to trigger (if any). 441 445 if (menu->style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem) 442 && currentAction && currentAction == actionAboutToTrigger ) {443 446 && currentAction && currentAction == actionAboutToTrigger 447 && menu->actions().contains(currentAction)) { 444 448 QEventLoop eventLoop; 445 449 QAction *activeAction = currentAction; 446 450 447 // Deselect and wait 60 ms.448 451 menu->setActiveAction(0); 449 452 QTimer::singleShot(60, &eventLoop, SLOT(quit())); … … 459 462 if (menu->style()->styleHint(QStyle::SH_Menu_FadeOutOnHide)) { 460 463 // ### Qt 4.4: 461 // Should be something like: q->transitionWindow(Qt::FadeOutTransition, 150);464 // Should be something like: q->transitionWindow(Qt::FadeOutTransition, MenuFadeTimeInSec); 462 465 // Hopefully we'll integrate qt/research/windowtransitions into main before 4.4. 463 466 // Talk to Richard, Trenton or Bjoern. 464 467 #if defined(Q_WS_MAC) 465 macWindowFade(qt_mac_window_for(menu)); // FIXME - what is the default duration for view animations 466 467 // Wait for the transition to complete. 468 QEventLoop eventLoop; 469 QTimer::singleShot(150, &eventLoop, SLOT(quit())); 470 eventLoop.exec(); 468 if (justRegister) { 469 QMacWindowFader::currentFader()->setFadeDuration(MenuFadeTimeInSec); 470 QMacWindowFader::currentFader()->registerWindowToFade(menu); 471 } else { 472 macWindowFade(qt_mac_window_for(menu), MenuFadeTimeInSec); 473 } 474 471 475 #endif // Q_WS_MAC 472 476 } … … 474 478 menu->blockSignals(false); 475 479 #endif // QT_NO_EFFECTS 476 menu->hide(); 480 if (!justRegister) 481 menu->hide(); 477 482 } 478 483 … … 514 519 { 515 520 Q_Q(QMenu); 516 const int scrollerHeight = q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q); 517 for(int i = 0, saccum = 0; i < actionList.count(); i++) { 518 QAction *act = actionList[i]; 521 updateActionRects(); 522 for(int i = 0, saccum = 0; i < actions.count(); i++) { 523 const QRect &rect = actionRects.at(i); 524 if (rect.isNull()) 525 continue; 519 526 if (scroll && scroll->scrollFlags & QMenuScroller::ScrollUp) { 520 saccum -= actionRects.value(act).height();521 if (saccum > scroll->scrollOffset -scrollerHeight)527 saccum -= rect.height(); 528 if (saccum > scroll->scrollOffset - scrollerHeight()) 522 529 continue; 523 530 } 531 QAction *act = actions.at(i); 524 532 if (!act->isSeparator() && 525 533 (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q) … … 536 544 Q_Q(QMenu); 537 545 tearoffHighlighted = 0; 538 if (action == currentAction && !(action && action->menu() && action->menu() != activeMenu)) { 539 if(QMenu *menu = qobject_cast<QMenu*>(causedPopup.widget)) { 540 if(causedPopup.action && menu->d_func()->activeMenu == q) 541 menu->d_func()->setCurrentAction(causedPopup.action, 0, reason, false); 546 if (action == currentAction) { 547 if (!action || !action->menu() || action->menu() == activeMenu) { 548 if(QMenu *menu = qobject_cast<QMenu*>(causedPopup.widget)) { 549 if(causedPopup.action && menu->d_func()->activeMenu == q) 550 menu->d_func()->setCurrentAction(causedPopup.action, 0, reason, false); 551 } 542 552 } 543 553 return; … … 554 564 #endif 555 565 #ifdef QT3_SUPPORT 556 emitHighlighted = (action && action != currentAction);566 emitHighlighted = action; 557 567 #endif 558 568 currentAction = action; … … 569 579 } 570 580 q->update(actionRect(action)); 571 QWidget *widget = widgetItems.value(action);572 581 573 582 if (reason == SelectedFromKeyboard) { 583 QWidget *widget = widgetItems.value(action); 574 584 if (widget) { 575 585 if (widget->focusPolicy() != Qt::NoFocus) … … 579 589 // get the focus 580 590 // Since the menu is a pop-up, it uses the popup reason. 581 if (!q->hasFocus()) 591 if (!q->hasFocus()) { 582 592 q->setFocus(Qt::PopupFocusReason); 593 } 583 594 } 584 595 } … … 589 600 #ifndef QT_NO_STATUSTIP 590 601 } else if (previousAction) { 591 QWidget *w = causedPopup.widget; 592 while (QMenu *m = qobject_cast<QMenu*>(w)) 593 w = m->d_func()->causedPopup.widget; 594 if (w) { 595 QString empty; 596 QStatusTipEvent tip(empty); 597 QApplication::sendEvent(w, &tip); 598 } 602 previousAction->d_func()->showStatusText(topCausedWidget(), QString()); 599 603 #endif 600 604 } … … 610 614 } 611 615 616 //return the top causedPopup.widget that is not a QMenu 617 QWidget *QMenuPrivate::topCausedWidget() const 618 { 619 QWidget* top = causedPopup.widget; 620 while (QMenu* m = qobject_cast<QMenu *>(top)) 621 top = m->d_func()->causedPopup.widget; 622 return top; 623 } 624 612 625 QAction *QMenuPrivate::actionAt(QPoint p) const 613 626 { … … 615 628 return 0; 616 629 617 for(int i = 0; i < actionList.count(); i++) { 618 QAction *act = actionList[i]; 619 if (actionRect(act).contains(p)) 620 return act; 630 for(int i = 0; i < actionRects.count(); i++) { 631 if (actionRects.at(i).contains(p)) 632 return actions.at(i); 621 633 } 622 634 return 0; … … 640 652 } 641 653 654 655 void QMenuPrivate::updateLayoutDirection() 656 { 657 Q_Q(QMenu); 658 //we need to mimic the cause of the popup's layout direction 659 //to allow setting it on a mainwindow for example 660 //we call setLayoutDirection_helper to not overwrite a user-defined value 661 if (!q->testAttribute(Qt::WA_SetLayoutDirection)) { 662 if (QWidget *w = causedPopup.widget) 663 setLayoutDirection_helper(w->layoutDirection()); 664 else if (QWidget *w = q->parentWidget()) 665 setLayoutDirection_helper(w->layoutDirection()); 666 else 667 setLayoutDirection_helper(QApplication::layoutDirection()); 668 } 669 } 670 671 642 672 /*! 643 673 Returns the action associated with this menu. … … 692 722 if (!scroll || !scroll->scrollFlags) 693 723 return; 724 updateActionRects(); 694 725 int newOffset = 0; 695 const int scrollHeight = q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q); 696 const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollHeight : 0; 697 const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollHeight : 0; 726 const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollerHeight() : 0; 727 const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollerHeight() : 0; 698 728 const int vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q); 699 729 const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q); 700 730 701 731 if (location == QMenuScroller::ScrollTop) { 702 for(int i = 0, saccum = 0; i < actionList.count(); i++) { 703 QAction *act = actionList.at(i); 704 if (act == action) { 732 for(int i = 0, saccum = 0; i < actions.count(); i++) { 733 if (actions.at(i) == action) { 705 734 newOffset = topScroll - saccum; 706 735 break; 707 736 } 708 saccum += actionRects. value(act).height();737 saccum += actionRects.at(i).height(); 709 738 } 710 739 } else { 711 for(int i = 0, saccum = 0; i < actionList.count(); i++) { 712 QAction *act = actionList.at(i); 713 saccum += actionRects.value(act).height(); 714 if (act == action) { 740 for(int i = 0, saccum = 0; i < actions.count(); i++) { 741 saccum += actionRects.at(i).height(); 742 if (actions.at(i) == action) { 715 743 if (location == QMenuScroller::ScrollCenter) 716 744 newOffset = ((q->height() / 2) - botScroll) - (saccum - topScroll); … … 721 749 } 722 750 if(newOffset) 723 newOffset -= fw *2;751 newOffset -= fw * 2; 724 752 } 725 753 … … 729 757 newScrollFlags |= QMenuScroller::ScrollUp; 730 758 int saccum = newOffset; 731 for(int i = 0; i < action List.count(); i++) {732 saccum += actionRects. value(actionList.at(i)).height();759 for(int i = 0; i < actionRects.count(); i++) { 760 saccum += actionRects.at(i).height(); 733 761 if (saccum > q->height()) { 734 762 newScrollFlags |= QMenuScroller::ScrollDown; … … 748 776 newOffset -= vmargin; 749 777 750 QRect screen = popupGeometry( QApplication::desktop()->screenNumber(q));778 QRect screen = popupGeometry(q); 751 779 const int desktopFrame = q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q); 752 780 if (q->height() < screen.height()-(desktopFrame*2)-1) { … … 781 809 782 810 //actually update flags 783 scroll->scrollOffset = newOffset; 784 if (scroll->scrollOffset > 0) 785 scroll->scrollOffset = 0; 811 const int delta = qMin(0, newOffset) - scroll->scrollOffset; //make sure the new offset is always negative 812 if (!itemsDirty && delta) { 813 //we've scrolled so we need to update the action rects 814 for (int i = 0; i < actionRects.count(); ++i) { 815 QRect ¤t = actionRects[i]; 816 current.moveTop(current.top() + delta); 817 818 //we need to update the widgets geometry 819 if (QWidget *w = widgetItems.value(actions.at(i))) 820 w->setGeometry(current); 821 } 822 } 823 scroll->scrollOffset += delta; 786 824 scroll->scrollFlags = newScrollFlags; 787 825 if (active) … … 794 832 { 795 833 Q_Q(QMenu); 834 updateActionRects(); 796 835 if(location == QMenuScroller::ScrollBottom) { 797 for(int i = actionList.size()-1; i >= 0; --i) { 798 QAction *act = actionList.at(i); 836 for(int i = actions.size()-1; i >= 0; --i) { 837 QAction *act = actions.at(i); 838 if (actionRects.at(i).isNull()) 839 continue; 799 840 if (!act->isSeparator() && 800 841 (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q) … … 808 849 } 809 850 } else if(location == QMenuScroller::ScrollTop) { 810 for(int i = 0; i < actionList.size(); ++i) { 811 QAction *act = actionList.at(i); 851 for(int i = 0; i < actions.size(); ++i) { 852 QAction *act = actions.at(i); 853 if (actionRects.at(i).isNull()) 854 continue; 812 855 if (!act->isSeparator() && 813 856 (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q) … … 829 872 if (!scroll || !(scroll->scrollFlags & direction)) //not really possible... 830 873 return; 831 const int scrollHeight = q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q);832 const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scroll Height: 0;833 const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scroll Height: 0;874 updateActionRects(); 875 const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollerHeight() : 0; 876 const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollerHeight() : 0; 834 877 const int vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q); 835 878 const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q); 836 879 const int offset = topScroll ? topScroll-vmargin : 0; 837 880 if (direction == QMenuScroller::ScrollUp) { 838 for(int i = 0, saccum = 0; i < actionList.count(); i++) { 839 QAction *act = actionList.at(i); 840 const int iHeight = actionRects.value(act).height(); 841 saccum -= iHeight; 881 for(int i = 0, saccum = 0; i < actions.count(); i++) { 882 saccum -= actionRects.at(i).height(); 842 883 if (saccum <= scroll->scrollOffset-offset) { 843 scrollMenu(act , page ? QMenuScroller::ScrollBottom : QMenuScroller::ScrollTop, active);884 scrollMenu(actions.at(i), page ? QMenuScroller::ScrollBottom : QMenuScroller::ScrollTop, active); 844 885 break; 845 886 } … … 847 888 } else if (direction == QMenuScroller::ScrollDown) { 848 889 bool scrolled = false; 849 for(int i = 0, saccum = 0; i < actionList.count(); i++) { 850 QAction *act = actionList.at(i); 851 const int iHeight = actionRects.value(act).height(); 890 for(int i = 0, saccum = 0; i < actions.count(); i++) { 891 const int iHeight = actionRects.at(i).height(); 852 892 saccum -= iHeight; 853 893 if (saccum <= scroll->scrollOffset-offset) { 854 894 const int scrollerArea = q->height() - botScroll - fw*2; 855 895 int visible = (scroll->scrollOffset-offset) - saccum; 856 for(i++ ; i < actionList.count(); i++) { 857 act = actionList.at(i); 858 const int iHeight = actionRects.value(act).height(); 859 visible += iHeight; 896 for(i++ ; i < actions.count(); i++) { 897 visible += actionRects.at(i).height(); 860 898 if (visible > scrollerArea - topScroll) { 861 899 scrolled = true; 862 scrollMenu(act , page ? QMenuScroller::ScrollTop : QMenuScroller::ScrollBottom, active);900 scrollMenu(actions.at(i), page ? QMenuScroller::ScrollTop : QMenuScroller::ScrollBottom, active); 863 901 break; 864 902 } … … 883 921 bool isScroll = false; 884 922 if (pos.x() >= 0 && pos.x() < q->width()) { 885 const int scrollerHeight = q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q);886 923 for(int dir = QMenuScroller::ScrollUp; dir <= QMenuScroller::ScrollDown; dir = dir << 1) { 887 924 if (scroll->scrollFlags & dir) { 888 925 if (dir == QMenuScroller::ScrollUp) 889 isScroll = (pos.y() <= scrollerHeight );926 isScroll = (pos.y() <= scrollerHeight()); 890 927 else if (dir == QMenuScroller::ScrollDown) 891 isScroll = (pos.y() >= q->height() -scrollerHeight);928 isScroll = (pos.y() >= q->height() - scrollerHeight()); 892 929 if (isScroll) { 893 930 scroll->scrollDirection = dir; … … 898 935 } 899 936 if (isScroll) { 900 if (!scroll->scrollTimer) 901 scroll->scrollTimer = new QBasicTimer; 902 scroll->scrollTimer->start(50, q); 937 scroll->scrollTimer.start(50, q); 903 938 return true; 904 } else if (scroll->scrollTimer && scroll->scrollTimer->isActive()){905 scroll->scrollTimer ->stop();939 } else { 940 scroll->scrollTimer.stop(); 906 941 } 907 942 } … … 910 945 QRect tearRect(0, 0, q->width(), q->style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, q)); 911 946 if (scroll && scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) 912 tearRect.translate(0, q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q));947 tearRect.translate(0, scrollerHeight()); 913 948 q->update(tearRect); 914 949 if (tearRect.contains(pos) && hasMouseMoved(e->globalPos())) { … … 957 992 } 958 993 994 class ExceptionGuard 995 { 996 public: 997 inline ExceptionGuard(bool *w = 0) : watched(w) { Q_ASSERT(!(*watched)); *watched = true; } 998 inline ~ExceptionGuard() { *watched = false; } 999 inline operator bool() { return *watched; } 1000 private: 1001 bool *watched; 1002 }; 1003 959 1004 void QMenuPrivate::activateCausedStack(const QList<QPointer<QWidget> > &causedStack, QAction *action, QAction::ActionEvent action_e, bool self) 960 1005 { 961 Q_ASSERT(!activationRecursionGuard); 962 activationRecursionGuard = true; 1006 ExceptionGuard guard(&activationRecursionGuard); 963 1007 #ifdef QT3_SUPPORT 964 1008 const int actionId = q_func()->findIdForAction(action); … … 1005 1049 } 1006 1050 } 1007 activationRecursionGuard = false;1008 1051 } 1009 1052 … … 1035 1078 hideUpToMenuBar(); 1036 1079 } else { 1037 for(QWidget *widget = qApp->activePopupWidget(); widget; ) {1080 for(QWidget *widget = QApplication::activePopupWidget(); widget; ) { 1038 1081 if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) { 1039 1082 if(qmenu == q) … … 1069 1112 } 1070 1113 #endif 1071 QWidget *w = causedPopup.widget; 1072 while (QMenu *m = qobject_cast<QMenu*>(w)) 1073 w = m->d_func()->causedPopup.widget; 1074 action->showStatusText(w); 1114 action->showStatusText(topCausedWidget()); 1075 1115 } else { 1076 1116 actionAboutToTrigger = 0; … … 1082 1122 Q_Q(QMenu); 1083 1123 if (QAction *action = qobject_cast<QAction *>(q->sender())) { 1124 QWeakPointer<QAction> actionGuard = action; 1084 1125 #ifdef QT3_SUPPORT 1085 1126 //we store it here because the action might be deleted/changed by connected slots … … 1091 1132 #endif 1092 1133 1093 if (!activationRecursionGuard ) {1134 if (!activationRecursionGuard && actionGuard) { 1094 1135 //in case the action has not been activated by the mouse 1095 1136 //we check the parent hierarchy … … 1165 1206 option->palette.setCurrentColorGroup(QPalette::Disabled); 1166 1207 1167 option->font = action->font(); 1208 option->font = action->font().resolve(font()); 1209 option->fontMetrics = QFontMetrics(option->font); 1168 1210 1169 1211 if (d->currentAction && d->currentAction == action && !d->currentAction->isSeparator()) { … … 1209 1251 bars, context menus, and other popup menus. 1210 1252 1211 \ingroup application1253 \ingroup mainwindow-classes 1212 1254 \ingroup basicwidgets 1213 \mainclass 1255 1214 1256 1215 1257 A menu widget is a selection menu. It can be either a pull-down … … 1303 1345 It is not possible to display an icon in a native menu on Windows Mobile. 1304 1346 1347 \section1 QMenu on Mac OS X with Qt build against Cocoa 1348 1349 QMenu can be inserted only once in a menu/menubar. Subsequent insertions will 1350 have no effect or will result in a disabled menu item. 1351 1305 1352 See the \l{mainwindows/menus}{Menus} example for an example of how 1306 1353 to use QMenuBar and QMenu in your application. … … 1360 1407 { 1361 1408 Q_D(QMenu); 1362 for (QHash<QAction *, QWidget *>::ConstIterator item = d->widgetItems.constBegin(), 1363 end = d->widgetItems.constEnd(); item != end; ++item) { 1364 QWidgetAction *action = static_cast<QWidgetAction *>(item.key()); 1365 QWidget *widget = item.value(); 1366 if (action && widget) 1409 QHash<QAction *, QWidget *>::iterator it = d->widgetItems.begin(); 1410 for (; it != d->widgetItems.end(); ++it) { 1411 if (QWidget *widget = it.value()) { 1412 QWidgetAction *action = static_cast<QWidgetAction *>(it.key()); 1367 1413 action->releaseWidget(widget); 1368 } 1369 d->widgetItems.clear(); 1414 *it = 0; 1415 } 1416 } 1370 1417 1371 1418 if (d->eventLoop) 1372 1419 d->eventLoop->exit(); 1373 if (d->tornPopup) 1374 d->tornPopup->close(); 1420 hideTearOffMenu(); 1375 1421 } 1376 1422 … … 1583 1629 if (d->tearoff == b) 1584 1630 return; 1585 if (!b && d->tornPopup)1586 d->tornPopup->close();1631 if (!b) 1632 hideTearOffMenu(); 1587 1633 d->tearoff = b; 1588 1634 … … 1619 1665 void QMenu::hideTearOffMenu() 1620 1666 { 1621 if ( d_func()->tornPopup)1622 d_func()->tornPopup->close();1667 if (QWidget *w = d_func()->tornPopup) 1668 w->close(); 1623 1669 } 1624 1670 … … 1718 1764 { 1719 1765 Q_D(const QMenu); 1720 ensurePolished(); 1721 QMap<QAction*, QRect> actionRects; 1722 QList<QAction*> actionList; 1723 d->calcActionRects(actionRects, actionList); 1766 d->updateActionRects(); 1724 1767 1725 1768 QSize s; 1726 QStyleOption opt(0); 1727 opt.rect = rect(); 1728 opt.palette = palette(); 1729 opt.state = QStyle::State_None; 1730 for (QMap<QAction*, QRect>::const_iterator i = actionRects.constBegin(); 1731 i != actionRects.constEnd(); ++i) { 1732 if (i.value().bottom() > s.height()) 1733 s.setHeight(i.value().y()+i.value().height()); 1734 if (i.value().right() > s.width()) 1735 s.setWidth(i.value().right()); 1736 } 1737 if (d->tearoff) 1738 s.rheight() += style()->pixelMetric(QStyle::PM_MenuTearoffHeight, &opt, this); 1739 if (const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, this)) { 1740 s.rwidth() += fw*2; 1741 s.rheight() += fw*2; 1769 for (int i = 0; i < d->actionRects.count(); ++i) { 1770 const QRect &rect = d->actionRects.at(i); 1771 if (rect.isNull()) 1772 continue; 1773 if (rect.bottom() >= s.height()) 1774 s.setHeight(rect.y() + rect.height()); 1775 if (rect.right() >= s.width()) 1776 s.setWidth(rect.x() + rect.width()); 1742 1777 } 1743 1778 // Note that the action rects calculated above already include 1744 1779 // the top and left margins, so we only need to add margins for 1745 1780 // the bottom and right. 1746 s.rwidth() += style()->pixelMetric(QStyle::PM_MenuHMargin, &opt, this); 1747 s.rheight() += style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, this); 1748 1749 s += QSize(d->leftmargin + d->rightmargin, d->topmargin + d->bottommargin); 1781 QStyleOption opt(0); 1782 opt.init(this); 1783 const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, this); 1784 s.rwidth() += style()->pixelMetric(QStyle::PM_MenuHMargin, &opt, this) + fw + d->rightmargin; 1785 s.rheight() += style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, this) + fw + d->bottommargin; 1750 1786 1751 1787 return style()->sizeFromContents(QStyle::CT_Menu, &opt, … … 1777 1813 d->motions = 0; 1778 1814 d->doChildEffects = true; 1815 d->updateLayoutDirection(); 1779 1816 1780 1817 #ifndef QT_NO_MENUBAR 1781 1818 // if this menu is part of a chain attached to a QMenuBar, set the 1782 1819 // _NET_WM_WINDOW_TYPE_DROPDOWN_MENU X11 window type 1783 QWidget* top = this; 1784 while (QMenu* m = qobject_cast<QMenu *>(top)) 1785 top = m->d_func()->causedPopup.widget; 1786 setAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu, qobject_cast<QMenuBar *>(top) != 0); 1820 setAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu, qobject_cast<QMenuBar *>(d->topCausedWidget()) != 0); 1787 1821 #endif 1788 1822 1789 1823 ensurePolished(); // Get the right font 1790 1824 emit aboutToShow(); 1791 d->updateActions(); 1792 QPoint pos = p; 1825 const bool actionListChanged = d->itemsDirty; 1826 d->updateActionRects(); 1827 QPoint pos; 1828 QPushButton *causedButton = qobject_cast<QPushButton*>(d->causedPopup.widget); 1829 if (actionListChanged && causedButton) 1830 pos = QPushButtonPrivate::get(causedButton)->adjustedMenuPosition(); 1831 else 1832 pos = p; 1833 1793 1834 QSize size = sizeHint(); 1794 QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(p)); 1835 QRect screen; 1836 #ifndef QT_NO_GRAPHICSVIEW 1837 bool isEmbedded = d->nearestGraphicsProxyWidget(this); 1838 if (isEmbedded) 1839 screen = d->popupGeometry(this); 1840 else 1841 #endif 1842 screen = d->popupGeometry(QApplication::desktop()->screenNumber(p)); 1843 1795 1844 const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this); 1796 1845 bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen); 1846 #ifdef QT_KEYPAD_NAVIGATION 1847 if (!atAction && QApplication::keypadNavigationEnabled()) { 1848 // Try to have one item activated 1849 if (d->defaultAction && d->defaultAction->isEnabled()) { 1850 atAction = d->defaultAction; 1851 // TODO: This works for first level menus, not yet sub menus 1852 } else { 1853 foreach (QAction *action, d->actions) 1854 if (action->isEnabled()) { 1855 atAction = action; 1856 break; 1857 } 1858 } 1859 d->currentAction = atAction; 1860 } 1861 #endif 1797 1862 if (d->ncols > 1) { 1798 1863 pos.setY(screen.top()+desktopFrame); 1799 1864 } else if (atAction) { 1800 for(int i =0, above_height=0; i<(int)d->actionList.count(); i++) {1801 QAction *action = d->action List.at(i);1865 for(int i = 0, above_height = 0; i < d->actions.count(); i++) { 1866 QAction *action = d->actions.at(i); 1802 1867 if (action == atAction) { 1803 int newY = pos.y() -above_height;1868 int newY = pos.y() - above_height; 1804 1869 if (d->scroll && newY < desktopFrame) { 1805 1870 d->scroll->scrollFlags = d->scroll->scrollFlags … … 1813 1878 && !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, 0, this)) { 1814 1879 int below_height = above_height + d->scroll->scrollOffset; 1815 for(int i2 = i; i2 < (int)d->actionList.count(); i2++)1816 below_height += d->actionRects. value(d->actionList.at(i2)).height();1880 for(int i2 = i; i2 < d->actionRects.count(); i2++) 1881 below_height += d->actionRects.at(i2).height(); 1817 1882 size.setHeight(below_height); 1818 1883 } 1819 1884 break; 1820 1885 } else { 1821 above_height += d->actionRects. value(action).height();1886 above_height += d->actionRects.at(i).height(); 1822 1887 } 1823 1888 } … … 1830 1895 if (adjustToDesktop) { 1831 1896 //handle popup falling "off screen" 1832 if ( qApp->layoutDirection() == Qt::RightToLeft) {1897 if (isRightToLeft()) { 1833 1898 if(snapToMouse) //position flowing left from the mouse 1834 1899 pos.setX(mouse.x()-size.width()); 1900 1901 #ifndef QT_NO_MENUBAR 1902 //if in a menubar, it should be right-aligned 1903 if (qobject_cast<QMenuBar*>(d->causedPopup.widget)) 1904 pos.rx() -= size.width(); 1905 #endif //QT_NO_MENUBAR 1835 1906 1836 1907 if (pos.x() < screen.left()+desktopFrame) … … 1840 1911 } else { 1841 1912 if (pos.x()+size.width()-1 > screen.right()-desktopFrame) 1842 pos.setX( qMin(p.x()+size.width(), screen.right()-desktopFrame-size.width()+1));1913 pos.setX(screen.right()-desktopFrame-size.width()+1); 1843 1914 if (pos.x() < screen.left()+desktopFrame) 1844 pos.setX( qMax(p.x(), screen.left() + desktopFrame));1915 pos.setX(screen.left() + desktopFrame); 1845 1916 } 1846 1917 if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) { … … 1868 1939 setGeometry(QRect(pos, size)); 1869 1940 #ifndef QT_NO_EFFECTS 1870 int hGuess = qApp->layoutDirection() == Qt::RightToLeft? QEffects::LeftScroll : QEffects::RightScroll;1941 int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll; 1871 1942 int vGuess = QEffects::DownScroll; 1872 if ( qApp->layoutDirection() == Qt::RightToLeft) {1943 if (isRightToLeft()) { 1873 1944 if ((snapToMouse && (pos.x() + size.width()/2 > mouse.x())) || 1874 1945 (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width()/2 > d->causedPopup.widget->x())) … … 2026 2097 { 2027 2098 QMenu menu(parent); 2028 for(QList<QAction*>::ConstIterator it = actions.constBegin(); it != actions.constEnd(); ++it) 2029 menu.addAction((*it)); 2099 menu.addActions(actions); 2030 2100 return menu.exec(pos, at); 2031 2101 } … … 2077 2147 d->causedPopup.widget = 0; 2078 2148 d->causedPopup.action = 0; 2149 if (d->scroll) 2150 d->scroll->scrollTimer.stop(); //make sure the timer stops 2079 2151 } 2080 2152 … … 2085 2157 { 2086 2158 Q_D(QMenu); 2159 d->updateActionRects(); 2087 2160 QPainter p(this); 2088 2161 QRegion emptyArea = QRegion(rect()); … … 2097 2170 2098 2171 //draw the items that need updating.. 2099 for (int i = 0; i < d->action List.count(); ++i) {2100 QAction *action = d->action List.at(i);2101 QRect adjustedActionRect = d->actionRect (action);2172 for (int i = 0; i < d->actions.count(); ++i) { 2173 QAction *action = d->actions.at(i); 2174 QRect adjustedActionRect = d->actionRects.at(i); 2102 2175 if (!e->rect().intersects(adjustedActionRect) 2103 2176 || d->widgetItems.value(action)) … … 2117 2190 //draw the scroller regions.. 2118 2191 if (d->scroll) { 2119 const int scrollerHeight = style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, this);2120 2192 menuOpt.menuItemType = QStyleOptionMenuItem::Scroller; 2121 2193 menuOpt.state |= QStyle::State_Enabled; 2122 2194 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) { 2123 menuOpt.rect.setRect(fw, fw, width() - (fw * 2), scrollerHeight);2195 menuOpt.rect.setRect(fw, fw, width() - (fw * 2), d->scrollerHeight()); 2124 2196 emptyArea -= QRegion(menuOpt.rect); 2125 2197 p.setClipRect(menuOpt.rect); … … 2127 2199 } 2128 2200 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown) { 2129 menuOpt.rect.setRect(fw, height() - scrollerHeight- fw, width() - (fw * 2),2130 scrollerHeight);2201 menuOpt.rect.setRect(fw, height() - d->scrollerHeight() - fw, width() - (fw * 2), 2202 d->scrollerHeight()); 2131 2203 emptyArea -= QRegion(menuOpt.rect); 2132 2204 menuOpt.state |= QStyle::State_DownArrow; … … 2141 2213 style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this)); 2142 2214 if (d->scroll && d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) 2143 menuOpt.rect.translate(0, style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, this));2215 menuOpt.rect.translate(0, d->scrollerHeight()); 2144 2216 emptyArea -= QRegion(menuOpt.rect); 2145 2217 p.setClipRect(menuOpt.rect); … … 2235 2307 action->menu()->d_func()->setFirstActionActive(); 2236 2308 else { 2237 #if defined(Q_WS_WIN) && !defined(QT_NO_MENUBAR)2309 #if defined(Q_WS_WIN) 2238 2310 //On Windows only context menus can be activated with the right button 2239 bool isContextMenu = true; 2240 const QWidget *cause = d->causedPopup.widget; 2241 while (cause) { 2242 //if the popup was caused by either QMenuBar or a QToolButton, it is not a context menu 2243 if (qobject_cast<const QMenuBar *>(cause) || qobject_cast<const QToolButton *>(cause)) { 2244 isContextMenu = false; 2245 break; 2246 } else if (const QMenu *menu = qobject_cast<const QMenu *>(cause)) { 2247 cause = menu->d_func()->causedPopup.widget; 2248 } else { 2249 break; 2250 } 2251 } 2252 if (e->button() == Qt::LeftButton || (e->button() == Qt::RightButton && isContextMenu)) 2311 if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0) 2253 2312 #endif 2254 2313 d->activateAction(action, QAction::Trigger); … … 2299 2358 Q_D(QMenu); 2300 2359 switch (e->type()) { 2360 case QEvent::Polish: 2361 d->updateLayoutDirection(); 2362 break; 2301 2363 case QEvent::ShortcutOverride: { 2302 2364 QKeyEvent *kev = static_cast<QKeyEvent*>(e); … … 2331 2393 } 2332 2394 d->itemsDirty = 1; 2333 d->updateAction s();2395 d->updateActionRects(); 2334 2396 break; } 2335 2397 case QEvent::Show: 2336 2398 d->mouseDown = 0; 2337 d->updateAction s();2399 d->updateActionRects(); 2338 2400 if (d->currentAction) 2339 2401 d->popupAction(d->currentAction, 0, false); … … 2371 2433 { 2372 2434 Q_D(QMenu); 2435 d->updateActionRects(); 2373 2436 int key = e->key(); 2374 2437 if (isRightToLeft()) { // in reverse mode open/close key for submenues are reversed … … 2422 2485 if (!d->currentAction) { 2423 2486 if(key == Qt::Key_Down) { 2424 for(int i = 0; i < d->actionList.size(); ++i) { 2425 QAction *act = d->actionList.at(i); 2487 for(int i = 0; i < d->actions.count(); ++i) { 2488 QAction *act = d->actions.at(i); 2489 if (d->actionRects.at(i).isNull()) 2490 continue; 2426 2491 if (!act->isSeparator() && 2427 2492 (style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this) … … 2432 2497 } 2433 2498 } else { 2434 for(int i = d->actionList.size()-1; i >= 0; --i) { 2435 QAction *act = d->actionList.at(i); 2499 for(int i = d->actions.count()-1; i >= 0; --i) { 2500 QAction *act = d->actions.at(i); 2501 if (d->actionRects.at(i).isNull()) 2502 continue; 2436 2503 if (!act->isSeparator() && 2437 2504 (style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this) … … 2443 2510 } 2444 2511 } else { 2445 for(int i =0, y=0; !nextAction && i < (int)d->actionList.count(); i++) {2446 QAction *act = d->action List.at(i);2512 for(int i = 0, y = 0; !nextAction && i < d->actions.count(); i++) { 2513 QAction *act = d->actions.at(i); 2447 2514 if (act == d->currentAction) { 2448 2515 if (key == Qt::Key_Up) { … … 2453 2520 if (d->scroll) 2454 2521 scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom; 2455 next_i = d->action List.count()-1;2522 next_i = d->actionRects.count()-1; 2456 2523 } 2457 QAction *next = d->action List.at(next_i);2524 QAction *next = d->actions.at(next_i); 2458 2525 if (next == d->currentAction) 2459 2526 break; 2527 if (d->actionRects.at(next_i).isNull()) 2528 continue; 2460 2529 if (next->isSeparator() || 2461 2530 (!next->isEnabled() && … … 2464 2533 nextAction = next; 2465 2534 if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)) { 2466 int topVisible = style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, this);2535 int topVisible = d->scrollerHeight(); 2467 2536 if (d->tearoff) 2468 2537 topVisible += style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this); 2469 if (((y + d->scroll->scrollOffset) - topVisible) <= d->actionRects. value(nextAction).height())2538 if (((y + d->scroll->scrollOffset) - topVisible) <= d->actionRects.at(next_i).height()) 2470 2539 scroll_loc = QMenuPrivate::QMenuScroller::ScrollTop; 2471 2540 } … … 2475 2544 d->tearoffHighlighted = 1; 2476 2545 } else { 2477 y += d->actionRects. value(act).height();2546 y += d->actionRects.at(i).height(); 2478 2547 for(int next_i = i+1; true; next_i++) { 2479 if (next_i == d->action List.count()) {2548 if (next_i == d->actionRects.count()) { 2480 2549 if(!style()->styleHint(QStyle::SH_Menu_SelectionWrap, 0, this)) 2481 2550 break; … … 2484 2553 next_i = 0; 2485 2554 } 2486 QAction *next = d->action List.at(next_i);2555 QAction *next = d->actions.at(next_i); 2487 2556 if (next == d->currentAction) 2488 2557 break; 2558 if (d->actionRects.at(next_i).isNull()) 2559 continue; 2489 2560 if (next->isSeparator() || 2490 2561 (!next->isEnabled() && … … 2493 2564 nextAction = next; 2494 2565 if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)) { 2495 const int scrollerHeight = style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, this); 2496 int bottomVisible = height()-scrollerHeight; 2566 int bottomVisible = height() - d->scrollerHeight(); 2497 2567 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) 2498 bottomVisible -= scrollerHeight;2568 bottomVisible -= d->scrollerHeight(); 2499 2569 if (d->tearoff) 2500 2570 bottomVisible -= style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this); 2501 if ((y + d->scroll->scrollOffset + d->actionRects. value(nextAction).height()) > bottomVisible)2571 if ((y + d->scroll->scrollOffset + d->actionRects.at(next_i).height()) > bottomVisible) 2502 2572 scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom; 2503 2573 } … … 2507 2577 break; 2508 2578 } 2509 y += d->actionRects. value(act).height();2579 y += d->actionRects.at(i).height(); 2510 2580 } 2511 2581 } 2512 2582 if (nextAction) { 2513 2583 if (d->scroll && scroll_loc != QMenuPrivate::QMenuScroller::ScrollStay) { 2514 if (d->scroll->scrollTimer) 2515 d->scroll->scrollTimer->stop(); 2584 d->scroll->scrollTimer.stop(); 2516 2585 d->scrollMenu(nextAction, scroll_loc); 2517 2586 } … … 2562 2631 d->hideMenu(this); 2563 2632 #ifndef QT_NO_MENUBAR 2564 if (QMenuBar *mb = qobject_cast<QMenuBar*>( qApp->focusWidget())) {2633 if (QMenuBar *mb = qobject_cast<QMenuBar*>(QApplication::focusWidget())) { 2565 2634 mb->d_func()->setKeyboardMode(false); 2566 2635 } … … 2635 2704 d->searchBufferTimer.start(2000, this); 2636 2705 d->searchBuffer += e->text(); 2637 for(int i = 0; i < d->action List.size(); ++i) {2706 for(int i = 0; i < d->actions.size(); ++i) { 2638 2707 int match_count = 0; 2639 register QAction *act = d->actionList.at(i); 2708 if (d->actionRects.at(i).isNull()) 2709 continue; 2710 QAction *act = d->actions.at(i); 2640 2711 const QString act_text = act->text(); 2641 2712 for(int c = 0; c < d->searchBuffer.size(); ++c) { … … 2654 2725 QAction *first = 0, *currentSelected = 0, *firstAfterCurrent = 0; 2655 2726 QChar c = e->text().at(0).toUpper(); 2656 for(int i = 0; i < d->actionList.size(); ++i) { 2657 register QAction *act = d->actionList.at(i); 2727 for(int i = 0; i < d->actions.size(); ++i) { 2728 if (d->actionRects.at(i).isNull()) 2729 continue; 2730 QAction *act = d->actions.at(i); 2658 2731 QKeySequence sequence = QKeySequence::mnemonic(act->text()); 2659 2732 int key = sequence[0] & 0xffff; … … 2690 2763 } 2691 2764 if (!key_consumed) { 2692 if (QWidget *caused = d->causedPopup.widget) {2693 while(QMenu *m = qobject_cast<QMenu*>(caused))2694 caused = m->d_func()->causedPopup.widget;2695 2765 #ifndef QT_NO_MENUBAR 2696 if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) { 2697 QAction *oldAct = mb->d_func()->currentAction; 2698 QApplication::sendEvent(mb, e); 2699 if (mb->d_func()->currentAction != oldAct) 2700 key_consumed = true; 2701 } 2702 #endif 2766 if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->topCausedWidget())) { 2767 QAction *oldAct = mb->d_func()->currentAction; 2768 QApplication::sendEvent(mb, e); 2769 if (mb->d_func()->currentAction != oldAct) 2770 key_consumed = true; 2703 2771 } 2772 #endif 2704 2773 } 2705 2774 2706 2775 #ifdef Q_OS_WIN32 2707 2776 if (key_consumed && (e->key() == Qt::Key_Control || e->key() == Qt::Key_Shift || e->key() == Qt::Key_Meta)) 2708 qApp->beep();2777 QApplication::beep(); 2709 2778 #endif // Q_OS_WIN32 2710 2779 } … … 2726 2795 if (d->motions == 0) // ignore first mouse move event (see enterEvent()) 2727 2796 return; 2728 d->hasHadMouse |=rect().contains(e->pos());2797 d->hasHadMouse = d->hasHadMouse || rect().contains(e->pos()); 2729 2798 2730 2799 QAction *action = d->actionAt(e->pos()); 2731 2800 if (!action) { 2732 if (d->hasHadMouse && !rect().contains(e->pos()))2801 if (d->hasHadMouse) 2733 2802 d->setCurrentAction(0); 2734 2803 return; 2735 } else if(e->buttons() & (Qt::LeftButton | Qt::RightButton)) {2804 } else if(e->buttons()) { 2736 2805 d->mouseDown = this; 2737 2806 } … … 2761 2830 if (!d->sloppyRegion.isEmpty()) 2762 2831 d->sloppyRegion = QRegion(); 2832 if (!d->activeMenu && d->currentAction) 2833 setActiveAction(0); 2763 2834 } 2764 2835 … … 2770 2841 { 2771 2842 Q_D(QMenu); 2772 if (d->scroll && d->scroll->scrollTimer && d->scroll->scrollTimer->timerId() == e->timerId()) {2843 if (d->scroll && d->scroll->scrollTimer.timerId() == e->timerId()) { 2773 2844 d->scrollMenu((QMenuPrivate::QMenuScroller::ScrollDirection)d->scroll->scrollDirection); 2774 2845 if (d->scroll->scrollFlags == QMenuPrivate::QMenuScroller::ScrollNone) 2775 d->scroll->scrollTimer ->stop();2846 d->scroll->scrollTimer.stop(); 2776 2847 } else if(QMenuPrivate::menuDelayTimer.timerId() == e->timerId()) { 2777 2848 QMenuPrivate::menuDelayTimer.stop(); … … 2800 2871 connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered())); 2801 2872 } 2802 2803 2873 if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) { 2804 2874 QWidget *widget = wa->requestWidget(this); … … 2807 2877 } 2808 2878 } else if (e->type() == QEvent::ActionRemoved) { 2809 d->actionRects.clear();2810 d->actionList.clear();2811 2879 e->action()->disconnect(this); 2812 2880 if (e->action() == d->currentAction) 2813 2881 d->currentAction = 0; 2814 2882 if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) { 2815 QWidget *widget = d->widgetItems.take(wa); 2816 if (widget) 2883 if (QWidget *widget = d->widgetItems.value(wa)) 2817 2884 wa->releaseWidget(widget); 2818 } else { 2819 // If this is called from the QAction destructor, the 2820 // previous call to qobject_cast will fail because the 2821 // QWidgetAction has been destroyed already. We need to 2822 // remove it from the hash anyway or it might crash later 2823 // the widget itself has been already destroyed in 2824 // ~QWidgetAction 2825 d->widgetItems.remove(e->action()); 2826 } 2885 } 2886 d->widgetItems.remove(e->action()); 2827 2887 } 2828 2888 … … 2838 2898 #endif 2839 2899 2840 #if defined(Q_ OS_WINCE) && !defined(QT_NO_MENUBAR)2900 #if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR) 2841 2901 if (!d->wce_menu) 2842 2902 d->wce_menu = new QMenuPrivate::QWceMenuPrivate; … … 2849 2909 #endif 2850 2910 2911 #ifdef Q_WS_S60 2912 if (!d->symbian_menu) 2913 d->symbian_menu = new QMenuPrivate::QSymbianMenuPrivate; 2914 if (e->type() == QEvent::ActionAdded) 2915 d->symbian_menu->addAction(e->action(), d->symbian_menu->findAction(e->before())); 2916 else if (e->type() == QEvent::ActionRemoved) 2917 d->symbian_menu->removeAction(e->action()); 2918 else if (e->type() == QEvent::ActionChanged) 2919 d->symbian_menu->syncAction(e->action()); 2920 #endif 2851 2921 if (isVisible()) { 2852 d->updateAction s();2922 d->updateActionRects(); 2853 2923 resize(sizeHint()); 2854 2924 update(); … … 2896 2966 QMenu *caused = qobject_cast<QMenu*>(d->activeMenu->d_func()->causedPopup.widget); 2897 2967 2898 const QRect availGeometry(d->popupGeometry( QApplication::desktop()->screenNumber(caused)));2968 const QRect availGeometry(d->popupGeometry(caused)); 2899 2969 if (isRightToLeft()) { 2900 2970 pos = leftPos; … … 3028 3098 { 3029 3099 Q_D(QMenu); 3100 if (d->collapsibleSeparators == collapse) 3101 return; 3102 3030 3103 d->collapsibleSeparators = collapse; 3031 3104 d->itemsDirty = 1; 3032 3105 if (isVisible()) { 3033 d->updateAction s();3106 d->updateActionRects(); 3034 3107 update(); 3035 3108 } 3109 #ifdef Q_WS_MAC 3110 if (d->mac_menu) 3111 d->syncSeparatorsCollapsible(collapse); 3112 #endif 3036 3113 } 3037 3114 … … 3090 3167 QAction *QMenu::findActionForId(int id) const 3091 3168 { 3092 Q List<QAction *> list = actions();3093 for (int i = 0; i < list.size(); ++i) {3094 QAction *act = list.at(i);3169 Q_D(const QMenu); 3170 for (int i = 0; i < d->actions.size(); ++i) { 3171 QAction *act = d->actions.at(i); 3095 3172 if (findIdForAction(act)== id) 3096 3173 return act;
Note:
See TracChangeset
for help on using the changeset viewer.