src/gui/widgets/qmenu.cpp
changeset 30 5dc02b23752f
parent 29 b72c6db6890b
child 37 758a864f9613
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    83 #endif
    83 #endif
    84 
    84 
    85 
    85 
    86 QT_BEGIN_NAMESPACE
    86 QT_BEGIN_NAMESPACE
    87 
    87 
    88 QPointer<QMenu> QMenuPrivate::mouseDown;
    88 QMenu *QMenuPrivate::mouseDown = 0;
    89 QBasicTimer QMenuPrivate::menuDelayTimer;
    89 int QMenuPrivate::sloppyDelayTimer = 0;
    90 QBasicTimer QMenuPrivate::sloppyDelayTimer;
       
    91 
    90 
    92 /* QMenu code */
    91 /* QMenu code */
    93 // internal class used for the torn off popup
    92 // internal class used for the torn off popup
    94 class QTornOffMenu : public QMenu
    93 class QTornOffMenu : public QMenu
    95 {
    94 {
   486 {
   485 {
   487     Q_Q(QMenu);
   486     Q_Q(QMenu);
   488     if (action && action->isEnabled()) {
   487     if (action && action->isEnabled()) {
   489         if (!delay)
   488         if (!delay)
   490             q->internalDelayedPopup();
   489             q->internalDelayedPopup();
   491         else
   490         else if (!menuDelayTimer.isActive() && (!action->menu() || !action->menu()->isVisible()))
   492             QMenuPrivate::menuDelayTimer.start(delay, q);
   491             menuDelayTimer.start(delay, q);
   493         if (activateFirst && action->menu())
   492         if (activateFirst && action->menu())
   494             action->menu()->d_func()->setFirstActionActive();
   493             action->menu()->d_func()->setFirstActionActive();
   495     } else if (QMenu *menu = activeMenu) {  //hide the current item
   494     } else if (QMenu *menu = activeMenu) {  //hide the current item
   496         activeMenu = 0;
   495         activeMenu = 0;
   497         hideMenu(menu);
   496         hideMenu(menu);
   542 // popup == -1 means do not popup, 0 means immediately, others mean use a timer
   541 // popup == -1 means do not popup, 0 means immediately, others mean use a timer
   543 void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason reason, bool activateFirst)
   542 void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason reason, bool activateFirst)
   544 {
   543 {
   545     Q_Q(QMenu);
   544     Q_Q(QMenu);
   546     tearoffHighlighted = 0;
   545     tearoffHighlighted = 0;
   547     if (action == currentAction) {
       
   548         if (!action || !action->menu() || action->menu() == activeMenu) {
       
   549             if(QMenu *menu = qobject_cast<QMenu*>(causedPopup.widget)) {
       
   550                 if(causedPopup.action && menu->d_func()->activeMenu == q)
       
   551                     menu->d_func()->setCurrentAction(causedPopup.action, 0, reason, false);
       
   552             }
       
   553         }
       
   554         return;
       
   555     }
       
   556     if (currentAction)
   546     if (currentAction)
   557         q->update(actionRect(currentAction));
   547         q->update(actionRect(currentAction));
   558 
   548 
   559     sloppyAction = 0;
   549     sloppyAction = 0;
   560     if (!sloppyRegion.isEmpty())
   550     if (!sloppyRegion.isEmpty())
   564     QAction *previousAction = currentAction;
   554     QAction *previousAction = currentAction;
   565 #endif
   555 #endif
   566 #ifdef QT3_SUPPORT
   556 #ifdef QT3_SUPPORT
   567     emitHighlighted = action;
   557     emitHighlighted = action;
   568 #endif
   558 #endif
       
   559 
   569     currentAction = action;
   560     currentAction = action;
   570     if (action) {
   561     if (action) {
   571         if (!action->isSeparator()) {
   562         if (!action->isSeparator()) {
   572             activateAction(action, QAction::Hover);
   563             activateAction(action, QAction::Hover);
   573             if (popup != -1) {
   564             if (popup != -1) {
  1802     \sa QWidget::mapToGlobal(), exec()
  1793     \sa QWidget::mapToGlobal(), exec()
  1803 */
  1794 */
  1804 void QMenu::popup(const QPoint &p, QAction *atAction)
  1795 void QMenu::popup(const QPoint &p, QAction *atAction)
  1805 {
  1796 {
  1806     Q_D(QMenu);
  1797     Q_D(QMenu);
  1807     if (d->scroll) { //reset scroll state from last popup
  1798     if (d->scroll) { // reset scroll state from last popup
  1808         d->scroll->scrollOffset = 0;
  1799         d->scroll->scrollOffset = 0;
  1809         d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
  1800         d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
  1810     }
  1801     }
  1811     d->tearoffHighlighted = 0;
  1802     d->tearoffHighlighted = 0;
  1812     d->motions = 0;
  1803     d->motions = 0;
  1831         pos = p;
  1822         pos = p;
  1832 
  1823 
  1833     QSize size = sizeHint();
  1824     QSize size = sizeHint();
  1834     QRect screen;
  1825     QRect screen;
  1835 #ifndef QT_NO_GRAPHICSVIEW
  1826 #ifndef QT_NO_GRAPHICSVIEW
  1836     bool isEmbedded = d->nearestGraphicsProxyWidget(this);
  1827     bool isEmbedded = !bypassGraphicsProxyWidget(this) && d->nearestGraphicsProxyWidget(this);
  1837     if (isEmbedded)
  1828     if (isEmbedded)
  1838         screen = d->popupGeometry(this);
  1829         screen = d->popupGeometry(this);
  1839     else
  1830     else
  1840 #endif
  1831 #endif
  1841     screen = d->popupGeometry(QApplication::desktop()->screenNumber(p));
  1832     screen = d->popupGeometry(QApplication::desktop()->screenNumber(p));
  1857         }
  1848         }
  1858         d->currentAction = atAction;
  1849         d->currentAction = atAction;
  1859     }
  1850     }
  1860 #endif
  1851 #endif
  1861     if (d->ncols > 1) {
  1852     if (d->ncols > 1) {
  1862         pos.setY(screen.top()+desktopFrame);
  1853         pos.setY(screen.top() + desktopFrame);
  1863     } else if (atAction) {
  1854     } else if (atAction) {
  1864         for(int i = 0, above_height = 0; i < d->actions.count(); i++) {
  1855         for (int i = 0, above_height = 0; i < d->actions.count(); i++) {
  1865             QAction *action = d->actions.at(i);
  1856             QAction *action = d->actions.at(i);
  1866             if (action == atAction) {
  1857             if (action == atAction) {
  1867                 int newY = pos.y() - above_height;
  1858                 int newY = pos.y() - above_height;
  1868                 if (d->scroll && newY < desktopFrame) {
  1859                 if (d->scroll && newY < desktopFrame) {
  1869                     d->scroll->scrollFlags = d->scroll->scrollFlags
  1860                     d->scroll->scrollFlags = d->scroll->scrollFlags
  1874                 pos.setY(newY);
  1865                 pos.setY(newY);
  1875 
  1866 
  1876                 if (d->scroll && d->scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone
  1867                 if (d->scroll && d->scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone
  1877                     && !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, 0, this)) {
  1868                     && !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, 0, this)) {
  1878                     int below_height = above_height + d->scroll->scrollOffset;
  1869                     int below_height = above_height + d->scroll->scrollOffset;
  1879                     for(int i2 = i; i2 < d->actionRects.count(); i2++)
  1870                     for (int i2 = i; i2 < d->actionRects.count(); i2++)
  1880                         below_height += d->actionRects.at(i2).height();
  1871                         below_height += d->actionRects.at(i2).height();
  1881                     size.setHeight(below_height);
  1872                     size.setHeight(below_height);
  1882                 }
  1873                 }
  1883                 break;
  1874                 break;
  1884             } else {
  1875             } else {
  1887         }
  1878         }
  1888     }
  1879     }
  1889 
  1880 
  1890     QPoint mouse = QCursor::pos();
  1881     QPoint mouse = QCursor::pos();
  1891     d->mousePopupPos = mouse;
  1882     d->mousePopupPos = mouse;
  1892     const bool snapToMouse = (QRect(p.x()-3, p.y()-3, 6, 6).contains(mouse));
  1883     const bool snapToMouse = (QRect(p.x() - 3, p.y() - 3, 6, 6).contains(mouse));
  1893 
  1884 
  1894     if (adjustToDesktop) {
  1885     if (adjustToDesktop) {
  1895         //handle popup falling "off screen"
  1886         // handle popup falling "off screen"
  1896         if (isRightToLeft()) {
  1887         if (isRightToLeft()) {
  1897             if(snapToMouse) //position flowing left from the mouse
  1888             if (snapToMouse) // position flowing left from the mouse
  1898                 pos.setX(mouse.x()-size.width());
  1889                 pos.setX(mouse.x() - size.width());
  1899 
  1890 
  1900 #ifndef QT_NO_MENUBAR
  1891 #ifndef QT_NO_MENUBAR
  1901             //if in a menubar, it should be right-aligned
  1892             // if in a menubar, it should be right-aligned
  1902             if (qobject_cast<QMenuBar*>(d->causedPopup.widget))
  1893             if (qobject_cast<QMenuBar*>(d->causedPopup.widget))
  1903                 pos.rx() -= size.width();
  1894                 pos.rx() -= size.width();
  1904 #endif //QT_NO_MENUBAR
  1895 #endif //QT_NO_MENUBAR
  1905 
  1896 
  1906             if (pos.x() < screen.left()+desktopFrame)
  1897             if (pos.x() < screen.left() + desktopFrame)
  1907                 pos.setX(qMax(p.x(), screen.left()+desktopFrame));
  1898                 pos.setX(qMax(p.x(), screen.left() + desktopFrame));
  1908             if (pos.x()+size.width()-1 > screen.right()-desktopFrame)
  1899             if (pos.x() + size.width() - 1 > screen.right() - desktopFrame)
  1909                 pos.setX(qMax(p.x()-size.width(), screen.right()-desktopFrame-size.width()+1));
  1900                 pos.setX(qMax(p.x() - size.width(), screen.right() - desktopFrame - size.width() + 1));
  1910         } else {
  1901         } else {
  1911             if (pos.x()+size.width()-1 > screen.right()-desktopFrame)
  1902             if (pos.x() + size.width() - 1 > screen.right() - desktopFrame)
  1912                 pos.setX(screen.right()-desktopFrame-size.width()+1);
  1903                 pos.setX(screen.right() - desktopFrame - size.width() + 1);
  1913             if (pos.x() < screen.left()+desktopFrame)
  1904             if (pos.x() < screen.left() + desktopFrame)
  1914                 pos.setX(screen.left() + desktopFrame);
  1905                 pos.setX(screen.left() + desktopFrame);
  1915         }
  1906         }
  1916         if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) {
  1907         if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) {
  1917             if(snapToMouse)
  1908             if(snapToMouse)
  1918                 pos.setY(qMin(mouse.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
  1909                 pos.setY(qMin(mouse.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
  1922             pos.setY(screen.top() + desktopFrame);
  1913             pos.setY(screen.top() + desktopFrame);
  1923         }
  1914         }
  1924 
  1915 
  1925         if (pos.y() < screen.top() + desktopFrame)
  1916         if (pos.y() < screen.top() + desktopFrame)
  1926             pos.setY(screen.top() + desktopFrame);
  1917             pos.setY(screen.top() + desktopFrame);
  1927         if (pos.y()+size.height()-1 > screen.bottom() - desktopFrame) {
  1918         if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) {
  1928             if (d->scroll) {
  1919             if (d->scroll) {
  1929                 d->scroll->scrollFlags |= uint(QMenuPrivate::QMenuScroller::ScrollDown);
  1920                 d->scroll->scrollFlags |= uint(QMenuPrivate::QMenuScroller::ScrollDown);
  1930                 int y = qMax(screen.y(),pos.y());
  1921                 int y = qMax(screen.y(),pos.y());
  1931                 size.setHeight(screen.bottom()-(desktopFrame*2)-y);
  1922                 size.setHeight(screen.bottom() - (desktopFrame * 2) - y);
  1932             } else {
  1923             } else {
  1933                 // Too big for screen, bias to see bottom of menu (for some reason)
  1924                 // Too big for screen, bias to see bottom of menu (for some reason)
  1934                 pos.setY(screen.bottom()-size.height()+1);
  1925                 pos.setY(screen.bottom() - size.height() + 1);
  1935             }
  1926             }
  1936         }
  1927         }
  1937     }
  1928     }
  1938     setGeometry(QRect(pos, size));
  1929     setGeometry(QRect(pos, size));
  1939 #ifndef QT_NO_EFFECTS
  1930 #ifndef QT_NO_EFFECTS
  1940     int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
  1931     int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
  1941     int vGuess = QEffects::DownScroll;
  1932     int vGuess = QEffects::DownScroll;
  1942     if (isRightToLeft()) {
  1933     if (isRightToLeft()) {
  1943         if ((snapToMouse && (pos.x() + size.width()/2 > mouse.x())) ||
  1934         if ((snapToMouse && (pos.x() + size.width() / 2 > mouse.x())) ||
  1944            (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width()/2 > d->causedPopup.widget->x()))
  1935            (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width() / 2 > d->causedPopup.widget->x()))
  1945             hGuess = QEffects::RightScroll;
  1936             hGuess = QEffects::RightScroll;
  1946     } else {
  1937     } else {
  1947         if ((snapToMouse && (pos.x() + size.width()/2 < mouse.x())) ||
  1938         if ((snapToMouse && (pos.x() + size.width() / 2 < mouse.x())) ||
  1948            (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width()/2 < d->causedPopup.widget->x()))
  1939            (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width() / 2 < d->causedPopup.widget->x()))
  1949             hGuess = QEffects::LeftScroll;
  1940             hGuess = QEffects::LeftScroll;
  1950     }
  1941     }
  1951 
  1942 
  1952 #ifndef QT_NO_MENUBAR
  1943 #ifndef QT_NO_MENUBAR
  1953     if ((snapToMouse && (pos.y() + size.height()/2 < mouse.y())) ||
  1944     if ((snapToMouse && (pos.y() + size.height() / 2 < mouse.y())) ||
  1954        (qobject_cast<QMenuBar*>(d->causedPopup.widget) &&
  1945        (qobject_cast<QMenuBar*>(d->causedPopup.widget) &&
  1955         pos.y() + size.width()/2 < d->causedPopup.widget->mapToGlobal(d->causedPopup.widget->pos()).y()))
  1946         pos.y() + size.width() / 2 < d->causedPopup.widget->mapToGlobal(d->causedPopup.widget->pos()).y()))
  1956        vGuess = QEffects::UpScroll;
  1947        vGuess = QEffects::UpScroll;
  1957 #endif
  1948 #endif
  1958     if (QApplication::isEffectEnabled(Qt::UI_AnimateMenu)) {
  1949     if (QApplication::isEffectEnabled(Qt::UI_AnimateMenu)) {
  1959         bool doChildEffects = true;
  1950         bool doChildEffects = true;
  1960 #ifndef QT_NO_MENUBAR
  1951 #ifndef QT_NO_MENUBAR
  2300     d->mouseDown = 0;
  2291     d->mouseDown = 0;
  2301     d->setSyncAction();
  2292     d->setSyncAction();
  2302     QAction *action = d->actionAt(e->pos());
  2293     QAction *action = d->actionAt(e->pos());
  2303 
  2294 
  2304     if (action && action == d->currentAction) {
  2295     if (action && action == d->currentAction) {
  2305         if (action->menu())
  2296         if (!action->menu()){
  2306             action->menu()->d_func()->setFirstActionActive();
       
  2307         else {
       
  2308 #if defined(Q_WS_WIN)
  2297 #if defined(Q_WS_WIN)
  2309             //On Windows only context menus can be activated with the right button
  2298             //On Windows only context menus can be activated with the right button
  2310             if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0)
  2299             if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0)
  2311 #endif
  2300 #endif
  2312                 d->activateAction(action, QAction::Trigger);
  2301                 d->activateAction(action, QAction::Trigger);
  2376             keyPressEvent(ke);
  2365             keyPressEvent(ke);
  2377             return true;
  2366             return true;
  2378         }
  2367         }
  2379     } break;
  2368     } break;
  2380     case QEvent::ContextMenu:
  2369     case QEvent::ContextMenu:
  2381         if(QMenuPrivate::menuDelayTimer.isActive()) {
  2370         if(d->menuDelayTimer.isActive()) {
  2382             QMenuPrivate::menuDelayTimer.stop();
  2371             d->menuDelayTimer.stop();
  2383             internalDelayedPopup();
  2372             internalDelayedPopup();
  2384         }
  2373         }
  2385         break;
  2374         break;
  2386     case QEvent::Resize: {
  2375     case QEvent::Resize: {
  2387         QStyleHintReturnMask menuMask;
  2376         QStyleHintReturnMask menuMask;
  2812     } else if(e->buttons()) {
  2801     } else if(e->buttons()) {
  2813         d->mouseDown = this;
  2802         d->mouseDown = this;
  2814     }
  2803     }
  2815     if (d->sloppyRegion.contains(e->pos())) {
  2804     if (d->sloppyRegion.contains(e->pos())) {
  2816         d->sloppyAction = action;
  2805         d->sloppyAction = action;
  2817         QMenuPrivate::sloppyDelayTimer.start(style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this)*6, this);
  2806         QMenuPrivate::sloppyDelayTimer = startTimer(style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this)*6);
  2818     } else {
  2807     } else {
  2819         d->setCurrentAction(action, style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this));
  2808         d->setCurrentAction(action, style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this));
  2820     }
  2809     }
  2821 }
  2810 }
  2822 
  2811 
  2850     Q_D(QMenu);
  2839     Q_D(QMenu);
  2851     if (d->scroll && d->scroll->scrollTimer.timerId() == e->timerId()) {
  2840     if (d->scroll && d->scroll->scrollTimer.timerId() == e->timerId()) {
  2852         d->scrollMenu((QMenuPrivate::QMenuScroller::ScrollDirection)d->scroll->scrollDirection);
  2841         d->scrollMenu((QMenuPrivate::QMenuScroller::ScrollDirection)d->scroll->scrollDirection);
  2853         if (d->scroll->scrollFlags == QMenuPrivate::QMenuScroller::ScrollNone)
  2842         if (d->scroll->scrollFlags == QMenuPrivate::QMenuScroller::ScrollNone)
  2854             d->scroll->scrollTimer.stop();
  2843             d->scroll->scrollTimer.stop();
  2855     } else if(QMenuPrivate::menuDelayTimer.timerId() == e->timerId()) {
  2844     } else if(d->menuDelayTimer.timerId() == e->timerId()) {
  2856         QMenuPrivate::menuDelayTimer.stop();
  2845         d->menuDelayTimer.stop();
  2857         internalDelayedPopup();
  2846         internalDelayedPopup();
  2858     } else if(QMenuPrivate::sloppyDelayTimer.timerId() == e->timerId()) {
  2847     } else if(QMenuPrivate::sloppyDelayTimer == e->timerId()) {
  2859         QMenuPrivate::sloppyDelayTimer.stop();
  2848         killTimer(QMenuPrivate::sloppyDelayTimer);
       
  2849         QMenuPrivate::sloppyDelayTimer = 0;
  2860         internalSetSloppyAction();
  2850         internalSetSloppyAction();
  2861     } else if(d->searchBufferTimer.timerId() == e->timerId()) {
  2851     } else if(d->searchBufferTimer.timerId() == e->timerId()) {
  2862         d->searchBuffer.clear();
  2852         d->searchBuffer.clear();
  2863     }
  2853     }
  2864 }
  2854 }