259 const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q), |
258 const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q), |
260 vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q), |
259 vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q), |
261 icone = style->pixelMetric(QStyle::PM_SmallIconSize, &opt, q); |
260 icone = style->pixelMetric(QStyle::PM_SmallIconSize, &opt, q); |
262 const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, q); |
261 const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, q); |
263 const int deskFw = style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, &opt, q); |
262 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; |
263 const int tearoffHeight = tearoff ? style->pixelMetric(QStyle::PM_MenuTearoffHeight, &opt, q) : 0; |
268 |
264 |
269 //for compatability now - will have to refactor this away.. |
265 //for compatability now - will have to refactor this away.. |
270 tabWidth = 0; |
266 tabWidth = 0; |
271 maxIconWidth = 0; |
267 maxIconWidth = 0; |
349 actionRects[i] = QRect(0, 0, sz.width(), sz.height()); |
345 actionRects[i] = QRect(0, 0, sz.width(), sz.height()); |
350 } |
346 } |
351 } |
347 } |
352 |
348 |
353 max_column_width += tabWidth; //finally add in the tab width |
349 max_column_width += tabWidth; //finally add in the tab width |
|
350 const int sfcMargin = style->sizeFromContents(QStyle::CT_Menu, &opt, QApplication::globalStrut(), q).width() - QApplication::globalStrut().width(); |
|
351 const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin)); |
|
352 max_column_width = qMax(min_column_width, max_column_width); |
|
353 |
354 |
354 |
355 //calculate position |
355 //calculate position |
356 const int base_y = vmargin + fw + topmargin + |
356 const int base_y = vmargin + fw + topmargin + |
357 (scroll ? scroll->scrollOffset : 0) + |
357 (scroll ? scroll->scrollOffset : 0) + |
358 tearoffHeight; |
358 tearoffHeight; |
485 { |
485 { |
486 Q_Q(QMenu); |
486 Q_Q(QMenu); |
487 if (action && action->isEnabled()) { |
487 if (action && action->isEnabled()) { |
488 if (!delay) |
488 if (!delay) |
489 q->internalDelayedPopup(); |
489 q->internalDelayedPopup(); |
490 else |
490 else if (!menuDelayTimer.isActive() && (!action->menu() || !action->menu()->isVisible())) |
491 QMenuPrivate::menuDelayTimer.start(delay, q); |
491 menuDelayTimer.start(delay, q); |
492 if (activateFirst && action->menu()) |
492 if (activateFirst && action->menu()) |
493 action->menu()->d_func()->setFirstActionActive(); |
493 action->menu()->d_func()->setFirstActionActive(); |
494 } else if (QMenu *menu = activeMenu) { //hide the current item |
494 } else if (QMenu *menu = activeMenu) { //hide the current item |
495 activeMenu = 0; |
495 activeMenu = 0; |
496 hideMenu(menu); |
496 hideMenu(menu); |
541 // 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 |
542 void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason reason, bool activateFirst) |
542 void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason reason, bool activateFirst) |
543 { |
543 { |
544 Q_Q(QMenu); |
544 Q_Q(QMenu); |
545 tearoffHighlighted = 0; |
545 tearoffHighlighted = 0; |
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 } |
|
552 } |
|
553 return; |
|
554 } |
|
555 if (currentAction) |
546 if (currentAction) |
556 q->update(actionRect(currentAction)); |
547 q->update(actionRect(currentAction)); |
557 |
548 |
558 sloppyAction = 0; |
549 sloppyAction = 0; |
559 if (!sloppyRegion.isEmpty()) |
550 if (!sloppyRegion.isEmpty()) |
989 caused = next_widget; |
981 caused = next_widget; |
990 } |
982 } |
991 return false; |
983 return false; |
992 } |
984 } |
993 |
985 |
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 |
|
1004 void QMenuPrivate::activateCausedStack(const QList<QPointer<QWidget> > &causedStack, QAction *action, QAction::ActionEvent action_e, bool self) |
986 void QMenuPrivate::activateCausedStack(const QList<QPointer<QWidget> > &causedStack, QAction *action, QAction::ActionEvent action_e, bool self) |
1005 { |
987 { |
1006 ExceptionGuard guard(&activationRecursionGuard); |
988 QBoolBlocker guard(activationRecursionGuard); |
1007 #ifdef QT3_SUPPORT |
989 #ifdef QT3_SUPPORT |
1008 const int actionId = q_func()->findIdForAction(action); |
990 const int actionId = q_func()->findIdForAction(action); |
1009 #endif |
991 #endif |
1010 if(self) |
992 if(self) |
1011 action->activate(action_e); |
993 action->activate(action_e); |
1811 \sa QWidget::mapToGlobal(), exec() |
1793 \sa QWidget::mapToGlobal(), exec() |
1812 */ |
1794 */ |
1813 void QMenu::popup(const QPoint &p, QAction *atAction) |
1795 void QMenu::popup(const QPoint &p, QAction *atAction) |
1814 { |
1796 { |
1815 Q_D(QMenu); |
1797 Q_D(QMenu); |
1816 if (d->scroll) { //reset scroll state from last popup |
1798 if (d->scroll) { // reset scroll state from last popup |
1817 d->scroll->scrollOffset = 0; |
1799 d->scroll->scrollOffset = 0; |
1818 d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone; |
1800 d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone; |
1819 } |
1801 } |
1820 d->tearoffHighlighted = 0; |
1802 d->tearoffHighlighted = 0; |
1821 d->motions = 0; |
1803 d->motions = 0; |
1866 } |
1848 } |
1867 d->currentAction = atAction; |
1849 d->currentAction = atAction; |
1868 } |
1850 } |
1869 #endif |
1851 #endif |
1870 if (d->ncols > 1) { |
1852 if (d->ncols > 1) { |
1871 pos.setY(screen.top()+desktopFrame); |
1853 pos.setY(screen.top() + desktopFrame); |
1872 } else if (atAction) { |
1854 } else if (atAction) { |
1873 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++) { |
1874 QAction *action = d->actions.at(i); |
1856 QAction *action = d->actions.at(i); |
1875 if (action == atAction) { |
1857 if (action == atAction) { |
1876 int newY = pos.y() - above_height; |
1858 int newY = pos.y() - above_height; |
1877 if (d->scroll && newY < desktopFrame) { |
1859 if (d->scroll && newY < desktopFrame) { |
1878 d->scroll->scrollFlags = d->scroll->scrollFlags |
1860 d->scroll->scrollFlags = d->scroll->scrollFlags |
1883 pos.setY(newY); |
1865 pos.setY(newY); |
1884 |
1866 |
1885 if (d->scroll && d->scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone |
1867 if (d->scroll && d->scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone |
1886 && !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, 0, this)) { |
1868 && !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, 0, this)) { |
1887 int below_height = above_height + d->scroll->scrollOffset; |
1869 int below_height = above_height + d->scroll->scrollOffset; |
1888 for(int i2 = i; i2 < d->actionRects.count(); i2++) |
1870 for (int i2 = i; i2 < d->actionRects.count(); i2++) |
1889 below_height += d->actionRects.at(i2).height(); |
1871 below_height += d->actionRects.at(i2).height(); |
1890 size.setHeight(below_height); |
1872 size.setHeight(below_height); |
1891 } |
1873 } |
1892 break; |
1874 break; |
1893 } else { |
1875 } else { |
1896 } |
1878 } |
1897 } |
1879 } |
1898 |
1880 |
1899 QPoint mouse = QCursor::pos(); |
1881 QPoint mouse = QCursor::pos(); |
1900 d->mousePopupPos = mouse; |
1882 d->mousePopupPos = mouse; |
1901 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)); |
1902 |
1884 |
1903 if (adjustToDesktop) { |
1885 if (adjustToDesktop) { |
1904 //handle popup falling "off screen" |
1886 // handle popup falling "off screen" |
1905 if (isRightToLeft()) { |
1887 if (isRightToLeft()) { |
1906 if(snapToMouse) //position flowing left from the mouse |
1888 if (snapToMouse) // position flowing left from the mouse |
1907 pos.setX(mouse.x()-size.width()); |
1889 pos.setX(mouse.x() - size.width()); |
1908 |
1890 |
1909 #ifndef QT_NO_MENUBAR |
1891 #ifndef QT_NO_MENUBAR |
1910 //if in a menubar, it should be right-aligned |
1892 // if in a menubar, it should be right-aligned |
1911 if (qobject_cast<QMenuBar*>(d->causedPopup.widget)) |
1893 if (qobject_cast<QMenuBar*>(d->causedPopup.widget)) |
1912 pos.rx() -= size.width(); |
1894 pos.rx() -= size.width(); |
1913 #endif //QT_NO_MENUBAR |
1895 #endif //QT_NO_MENUBAR |
1914 |
1896 |
1915 if (pos.x() < screen.left()+desktopFrame) |
1897 if (pos.x() < screen.left() + desktopFrame) |
1916 pos.setX(qMax(p.x(), screen.left()+desktopFrame)); |
1898 pos.setX(qMax(p.x(), screen.left() + desktopFrame)); |
1917 if (pos.x()+size.width()-1 > screen.right()-desktopFrame) |
1899 if (pos.x() + size.width() - 1 > screen.right() - desktopFrame) |
1918 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)); |
1919 } else { |
1901 } else { |
1920 if (pos.x()+size.width()-1 > screen.right()-desktopFrame) |
1902 if (pos.x() + size.width() - 1 > screen.right() - desktopFrame) |
1921 pos.setX(screen.right()-desktopFrame-size.width()+1); |
1903 pos.setX(screen.right() - desktopFrame - size.width() + 1); |
1922 if (pos.x() < screen.left()+desktopFrame) |
1904 if (pos.x() < screen.left() + desktopFrame) |
1923 pos.setX(screen.left() + desktopFrame); |
1905 pos.setX(screen.left() + desktopFrame); |
1924 } |
1906 } |
1925 if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) { |
1907 if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) { |
1926 if(snapToMouse) |
1908 if(snapToMouse) |
1927 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)); |
1931 pos.setY(screen.top() + desktopFrame); |
1913 pos.setY(screen.top() + desktopFrame); |
1932 } |
1914 } |
1933 |
1915 |
1934 if (pos.y() < screen.top() + desktopFrame) |
1916 if (pos.y() < screen.top() + desktopFrame) |
1935 pos.setY(screen.top() + desktopFrame); |
1917 pos.setY(screen.top() + desktopFrame); |
1936 if (pos.y()+size.height()-1 > screen.bottom() - desktopFrame) { |
1918 if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) { |
1937 if (d->scroll) { |
1919 if (d->scroll) { |
1938 d->scroll->scrollFlags |= uint(QMenuPrivate::QMenuScroller::ScrollDown); |
1920 d->scroll->scrollFlags |= uint(QMenuPrivate::QMenuScroller::ScrollDown); |
1939 int y = qMax(screen.y(),pos.y()); |
1921 int y = qMax(screen.y(),pos.y()); |
1940 size.setHeight(screen.bottom()-(desktopFrame*2)-y); |
1922 size.setHeight(screen.bottom() - (desktopFrame * 2) - y); |
1941 } else { |
1923 } else { |
1942 // 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) |
1943 pos.setY(screen.bottom()-size.height()+1); |
1925 pos.setY(screen.bottom() - size.height() + 1); |
1944 } |
1926 } |
1945 } |
1927 } |
1946 } |
1928 } |
1947 setGeometry(QRect(pos, size)); |
1929 setGeometry(QRect(pos, size)); |
1948 #ifndef QT_NO_EFFECTS |
1930 #ifndef QT_NO_EFFECTS |
1949 int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll; |
1931 int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll; |
1950 int vGuess = QEffects::DownScroll; |
1932 int vGuess = QEffects::DownScroll; |
1951 if (isRightToLeft()) { |
1933 if (isRightToLeft()) { |
1952 if ((snapToMouse && (pos.x() + size.width()/2 > mouse.x())) || |
1934 if ((snapToMouse && (pos.x() + size.width() / 2 > mouse.x())) || |
1953 (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())) |
1954 hGuess = QEffects::RightScroll; |
1936 hGuess = QEffects::RightScroll; |
1955 } else { |
1937 } else { |
1956 if ((snapToMouse && (pos.x() + size.width()/2 < mouse.x())) || |
1938 if ((snapToMouse && (pos.x() + size.width() / 2 < mouse.x())) || |
1957 (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())) |
1958 hGuess = QEffects::LeftScroll; |
1940 hGuess = QEffects::LeftScroll; |
1959 } |
1941 } |
1960 |
1942 |
1961 #ifndef QT_NO_MENUBAR |
1943 #ifndef QT_NO_MENUBAR |
1962 if ((snapToMouse && (pos.y() + size.height()/2 < mouse.y())) || |
1944 if ((snapToMouse && (pos.y() + size.height() / 2 < mouse.y())) || |
1963 (qobject_cast<QMenuBar*>(d->causedPopup.widget) && |
1945 (qobject_cast<QMenuBar*>(d->causedPopup.widget) && |
1964 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())) |
1965 vGuess = QEffects::UpScroll; |
1947 vGuess = QEffects::UpScroll; |
1966 #endif |
1948 #endif |
1967 if (QApplication::isEffectEnabled(Qt::UI_AnimateMenu)) { |
1949 if (QApplication::isEffectEnabled(Qt::UI_AnimateMenu)) { |
1968 bool doChildEffects = true; |
1950 bool doChildEffects = true; |
1969 #ifndef QT_NO_MENUBAR |
1951 #ifndef QT_NO_MENUBAR |
2309 d->mouseDown = 0; |
2291 d->mouseDown = 0; |
2310 d->setSyncAction(); |
2292 d->setSyncAction(); |
2311 QAction *action = d->actionAt(e->pos()); |
2293 QAction *action = d->actionAt(e->pos()); |
2312 |
2294 |
2313 if (action && action == d->currentAction) { |
2295 if (action && action == d->currentAction) { |
2314 if (action->menu()) |
2296 if (!action->menu()){ |
2315 action->menu()->d_func()->setFirstActionActive(); |
|
2316 else { |
|
2317 #if defined(Q_WS_WIN) |
2297 #if defined(Q_WS_WIN) |
2318 //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 |
2319 if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0) |
2299 if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0) |
2320 #endif |
2300 #endif |
2321 d->activateAction(action, QAction::Trigger); |
2301 d->activateAction(action, QAction::Trigger); |
2811 return; |
2791 return; |
2812 d->hasHadMouse = d->hasHadMouse || rect().contains(e->pos()); |
2792 d->hasHadMouse = d->hasHadMouse || rect().contains(e->pos()); |
2813 |
2793 |
2814 QAction *action = d->actionAt(e->pos()); |
2794 QAction *action = d->actionAt(e->pos()); |
2815 if (!action) { |
2795 if (!action) { |
2816 if (d->hasHadMouse) |
2796 if (d->hasHadMouse |
|
2797 && (!d->currentAction |
|
2798 || !(d->currentAction->menu() && d->currentAction->menu()->isVisible()))) |
2817 d->setCurrentAction(0); |
2799 d->setCurrentAction(0); |
2818 return; |
2800 return; |
2819 } else if(e->buttons()) { |
2801 } else if(e->buttons()) { |
2820 d->mouseDown = this; |
2802 d->mouseDown = this; |
2821 } |
2803 } |
2822 if (d->sloppyRegion.contains(e->pos())) { |
2804 if (d->sloppyRegion.contains(e->pos())) { |
2823 d->sloppyAction = action; |
2805 d->sloppyAction = action; |
2824 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); |
2825 } else { |
2807 } else { |
2826 d->setCurrentAction(action, style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this)); |
2808 d->setCurrentAction(action, style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this)); |
2827 } |
2809 } |
2828 } |
2810 } |
2829 |
2811 |
2857 Q_D(QMenu); |
2839 Q_D(QMenu); |
2858 if (d->scroll && d->scroll->scrollTimer.timerId() == e->timerId()) { |
2840 if (d->scroll && d->scroll->scrollTimer.timerId() == e->timerId()) { |
2859 d->scrollMenu((QMenuPrivate::QMenuScroller::ScrollDirection)d->scroll->scrollDirection); |
2841 d->scrollMenu((QMenuPrivate::QMenuScroller::ScrollDirection)d->scroll->scrollDirection); |
2860 if (d->scroll->scrollFlags == QMenuPrivate::QMenuScroller::ScrollNone) |
2842 if (d->scroll->scrollFlags == QMenuPrivate::QMenuScroller::ScrollNone) |
2861 d->scroll->scrollTimer.stop(); |
2843 d->scroll->scrollTimer.stop(); |
2862 } else if(QMenuPrivate::menuDelayTimer.timerId() == e->timerId()) { |
2844 } else if(d->menuDelayTimer.timerId() == e->timerId()) { |
2863 QMenuPrivate::menuDelayTimer.stop(); |
2845 d->menuDelayTimer.stop(); |
2864 internalDelayedPopup(); |
2846 internalDelayedPopup(); |
2865 } else if(QMenuPrivate::sloppyDelayTimer.timerId() == e->timerId()) { |
2847 } else if(QMenuPrivate::sloppyDelayTimer == e->timerId()) { |
2866 QMenuPrivate::sloppyDelayTimer.stop(); |
2848 killTimer(QMenuPrivate::sloppyDelayTimer); |
|
2849 QMenuPrivate::sloppyDelayTimer = 0; |
2867 internalSetSloppyAction(); |
2850 internalSetSloppyAction(); |
2868 } else if(d->searchBufferTimer.timerId() == e->timerId()) { |
2851 } else if(d->searchBufferTimer.timerId() == e->timerId()) { |
2869 d->searchBuffer.clear(); |
2852 d->searchBuffer.clear(); |
2870 } |
2853 } |
2871 } |
2854 } |