1 /****************************************************************************
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
52 #include "qapplication.h"
53 #include "qdesktopwidget.h"
54 #ifndef QT_NO_ACCESSIBILITY
55 # include "qaccessible.h"
58 # include <private/qeffects_p.h>
60 #ifndef QT_NO_WHATSTHIS
61 # include <qwhatsthis.h>
65 #include "qmenubar_p.h"
66 #include "qwidgetaction.h"
67 #include "qtoolbutton.h"
68 #include "qpushbutton.h"
69 #include <private/qpushbutton_p.h>
70 #include <private/qaction_p.h>
71 #include <private/qsoftkeymanager_p.h>
73 #include <qmenudata.h>
77 # include <private/qt_x11_p.h>
80 #if defined(Q_WS_MAC) && !defined(QT_NO_EFFECTS)
81 # include <private/qcore_mac_p.h>
82 # include <private/qt_cocoa_helpers_mac_p.h>
86 # include "private/qt_s60_p.h"
92 QMenu *QMenuPrivate::mouseDown = 0;
95 // internal class used for the torn off popup
96 class QTornOffMenu : public QMenu
99 class QTornOffMenuPrivate : public QMenuPrivate
101 Q_DECLARE_PUBLIC(QMenu)
103 QTornOffMenuPrivate(QMenu *p) : causedMenu(p) {
105 causedPopup.widget = 0;
106 causedPopup.action = ((QTornOffMenu*)p)->d_func()->causedPopup.action;
107 causedStack = ((QTornOffMenu*)p)->d_func()->calcCausedStack();
109 QList<QPointer<QWidget> > calcCausedStack() const { return causedStack; }
110 QPointer<QMenu> causedMenu;
111 QList<QPointer<QWidget> > causedStack;
114 QTornOffMenu(QMenu *p) : QMenu(*(new QTornOffMenuPrivate(p)))
117 // make the torn-off menu a sibling of p (instead of a child)
118 QWidget *parentWidget = d->causedStack.isEmpty() ? p : d->causedStack.last();
119 if (parentWidget->parentWidget())
120 parentWidget = parentWidget->parentWidget();
121 setParent(parentWidget, Qt::Window | Qt::Tool);
122 setAttribute(Qt::WA_DeleteOnClose, true);
123 setAttribute(Qt::WA_X11NetWmWindowTypeMenu, true);
124 setWindowTitle(p->windowTitle());
125 setEnabled(p->isEnabled());
126 //QObject::connect(this, SIGNAL(triggered(QAction*)), this, SLOT(onTrigger(QAction*)));
127 //QObject::connect(this, SIGNAL(hovered(QAction*)), this, SLOT(onHovered(QAction*)));
128 QList<QAction*> items = p->actions();
129 for(int i = 0; i < items.count(); i++)
130 addAction(items.at(i));
132 void syncWithMenu(QMenu *menu, QActionEvent *act)
135 if(menu != d->causedMenu)
137 if (act->type() == QEvent::ActionAdded) {
138 insertAction(act->before(), act->action());
139 } else if (act->type() == QEvent::ActionRemoved)
140 removeAction(act->action());
142 void actionEvent(QActionEvent *e)
144 QMenu::actionEvent(e);
145 setFixedSize(sizeHint());
148 void onTrigger(QAction *action) { d_func()->activateAction(action, QAction::Trigger, false); }
149 void onHovered(QAction *action) { d_func()->activateAction(action, QAction::Hover, false); }
151 Q_DECLARE_PRIVATE(QTornOffMenu)
152 friend class QMenuPrivate;
155 void QMenuPrivate::init()
158 #ifndef QT_NO_WHATSTHIS
159 q->setAttribute(Qt::WA_CustomWhatsThis);
161 q->setAttribute(Qt::WA_X11NetWmWindowTypePopupMenu);
162 defaultMenuAction = menuAction = new QAction(q);
163 menuAction->d_func()->menu = q;
164 q->setMouseTracking(q->style()->styleHint(QStyle::SH_Menu_MouseTracking, 0, q));
165 if (q->style()->styleHint(QStyle::SH_Menu_Scrollable, 0, q)) {
166 scroll = new QMenuPrivate::QMenuScroller;
167 scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
170 #ifdef QT_SOFTKEYS_ENABLED
171 selectAction = QSoftKeyManager::createKeyedAction(QSoftKeyManager::SelectSoftKey, Qt::Key_Select, q);
172 cancelAction = QSoftKeyManager::createKeyedAction(QSoftKeyManager::CancelSoftKey, Qt::Key_Back, q);
173 selectAction->setPriority(QAction::HighPriority);
174 cancelAction->setPriority(QAction::HighPriority);
175 q->addAction(selectAction);
176 q->addAction(cancelAction);
180 if (S60->avkonComponentsSupportTransparency) {
181 bool noSystemBackground = q->testAttribute(Qt::WA_NoSystemBackground);
182 q->setAttribute(Qt::WA_TranslucentBackground); // also sets WA_NoSystemBackground
183 q->setAttribute(Qt::WA_NoSystemBackground, noSystemBackground); // restore system background attribute
188 int QMenuPrivate::scrollerHeight() const
191 return qMax(QApplication::globalStrut().height(), q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q));
194 //Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
195 QRect QMenuPrivate::popupGeometry(const QWidget *widget) const
198 return QApplication::desktop()->screenGeometry(widget);
199 #elif defined Q_WS_X11
200 if (X11->desktopEnvironment == DE_KDE)
201 return QApplication::desktop()->screenGeometry(widget);
203 return QApplication::desktop()->availableGeometry(widget);
205 return QApplication::desktop()->availableGeometry(widget);
209 //Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
210 QRect QMenuPrivate::popupGeometry(int screen) const
213 return QApplication::desktop()->screenGeometry(screen);
214 #elif defined Q_WS_X11
215 if (X11->desktopEnvironment == DE_KDE)
216 return QApplication::desktop()->screenGeometry(screen);
218 return QApplication::desktop()->availableGeometry(screen);
220 return QApplication::desktop()->availableGeometry(screen);
224 QList<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const
226 QList<QPointer<QWidget> > ret;
227 for(QWidget *widget = causedPopup.widget; widget; ) {
229 if (QTornOffMenu *qtmenu = qobject_cast<QTornOffMenu*>(widget))
230 ret += qtmenu->d_func()->causedStack;
231 if (QMenu *qmenu = qobject_cast<QMenu*>(widget))
232 widget = qmenu->d_func()->causedPopup.widget;
239 void QMenuPrivate::updateActionRects() const
242 updateActionRects(popupGeometry(q));
245 void QMenuPrivate::updateActionRects(const QRect &screen) const
253 //let's reinitialize the buffer
254 actionRects.resize(actions.count());
255 actionRects.fill(QRect());
257 int lastVisibleAction = getLastVisibleAction();
259 int max_column_width = 0,
260 dh = screen.height(),
262 QStyle *style = q->style();
265 const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q),
266 vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q),
267 icone = style->pixelMetric(QStyle::PM_SmallIconSize, &opt, q);
268 const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, q);
269 const int deskFw = style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, &opt, q);
270 const int tearoffHeight = tearoff ? style->pixelMetric(QStyle::PM_MenuTearoffHeight, &opt, q) : 0;
272 //for compatibility now - will have to refactor this away
275 hasCheckableItems = false;
279 for (int i = 0; i < actions.count(); ++i) {
280 QAction *action = actions.at(i);
281 if (action->isSeparator() || !action->isVisible() || widgetItems.contains(action))
284 hasCheckableItems |= action->isCheckable();
285 QIcon is = action->icon();
287 maxIconWidth = qMax<uint>(maxIconWidth, icone + 4);
292 QFontMetrics qfm = q->fontMetrics();
293 bool previousWasSeparator = true; // this is true to allow removing the leading separators
294 for(int i = 0; i <= lastVisibleAction; i++) {
295 QAction *action = actions.at(i);
297 if (!action->isVisible() ||
298 (collapsibleSeparators && previousWasSeparator && action->isSeparator()))
299 continue; // we continue, this action will get an empty QRect
301 previousWasSeparator = action->isSeparator();
303 //let the style modify the above size..
304 QStyleOptionMenuItem opt;
305 q->initStyleOption(&opt, action);
306 const QFontMetrics &fm = opt.fontMetrics;
309 if (QWidget *w = widgetItems.value(action)) {
310 sz = w->sizeHint().expandedTo(w->minimumSize()).expandedTo(w->minimumSizeHint()).boundedTo(w->maximumSize());
312 //calc what I think the size is..
313 if (action->isSeparator()) {
316 QString s = action->text();
317 int t = s.indexOf(QLatin1Char('\t'));
319 tabWidth = qMax(int(tabWidth), qfm.width(s.mid(t+1)));
321 #ifndef QT_NO_SHORTCUT
323 QKeySequence seq = action->shortcut();
325 tabWidth = qMax(int(tabWidth), qfm.width(seq));
328 sz.setWidth(fm.boundingRect(QRect(), Qt::TextSingleLine | Qt::TextShowMnemonic, s).width());
329 sz.setHeight(qMax(fm.height(), qfm.height()));
331 QIcon is = action->icon();
333 QSize is_sz = QSize(icone, icone);
334 if (is_sz.height() > sz.height())
335 sz.setHeight(is_sz.height());
338 sz = style->sizeFromContents(QStyle::CT_MenuItem, &opt, sz, q);
343 max_column_width = qMax(max_column_width, sz.width());
346 y+sz.height()+vmargin > dh - (deskFw * 2)) {
352 actionRects[i] = QRect(0, 0, sz.width(), sz.height());
356 max_column_width += tabWidth; //finally add in the tab width
357 const int sfcMargin = style->sizeFromContents(QStyle::CT_Menu, &opt, QApplication::globalStrut(), q).width() - QApplication::globalStrut().width();
358 const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin));
359 max_column_width = qMax(min_column_width, max_column_width);
362 const int base_y = vmargin + fw + topmargin +
363 (scroll ? scroll->scrollOffset : 0) +
365 int x = hmargin + fw + leftmargin;
368 for(int i = 0; i < actions.count(); i++) {
369 QRect &rect = actionRects[i];
373 y+rect.height() > dh - deskFw * 2) {
374 x += max_column_width + hmargin;
377 rect.translate(x, y); //move
378 rect.setWidth(max_column_width); //uniform width
380 //we need to update the widgets geometry
381 if (QWidget *widget = widgetItems.value(actions.at(i))) {
382 widget->setGeometry(rect);
383 widget->setVisible(actions.at(i)->isVisible());
391 QSize QMenuPrivate::adjustMenuSizeForScreen(const QRect &screen)
394 QSize ret = screen.size();
396 updateActionRects(screen);
397 const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
398 ret.setWidth(actionRects.at(getLastVisibleAction()).right() + fw);
402 int QMenuPrivate::getLastVisibleAction() const
404 //let's try to get the last visible action
405 int lastVisibleAction = actions.count() - 1;
406 for (;lastVisibleAction >= 0; --lastVisibleAction) {
407 const QAction *action = actions.at(lastVisibleAction);
408 if (action->isVisible()) {
409 //removing trailing separators
410 if (action->isSeparator() && collapsibleSeparators)
415 return lastVisibleAction;
419 QRect QMenuPrivate::actionRect(QAction *act) const
421 int index = actions.indexOf(act);
427 //we found the action
428 return actionRects.at(index);
431 #if defined(Q_WS_MAC)
432 static const qreal MenuFadeTimeInSec = 0.150;
435 void QMenuPrivate::hideUpToMenuBar()
438 bool fadeMenus = q->style()->styleHint(QStyle::SH_Menu_FadeOutOnHide);
440 QWidget *caused = causedPopup.widget;
441 hideMenu(q); //hide after getting causedPopup
443 #ifndef QT_NO_MENUBAR
444 if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
445 mb->d_func()->setCurrentAction(0);
446 mb->d_func()->setKeyboardMode(false);
450 if (QMenu *m = qobject_cast<QMenu*>(caused)) {
451 caused = m->d_func()->causedPopup.widget;
452 if (!m->d_func()->tornoff)
453 hideMenu(m, fadeMenus);
454 if (!fadeMenus) // Mac doesn't clear the action until after hidden.
455 m->d_func()->setCurrentAction(0);
459 #if defined(Q_WS_MAC)
461 QEventLoop eventLoop;
462 QTimer::singleShot(int(MenuFadeTimeInSec * 1000), &eventLoop, SLOT(quit()));
463 QMacWindowFader::currentFader()->performFade();
471 void QMenuPrivate::hideMenu(QMenu *menu, bool justRegister)
475 #if !defined(QT_NO_EFFECTS)
476 menu->blockSignals(true);
478 // Flash item which is about to trigger (if any).
479 if (menu->style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)
480 && currentAction && currentAction == actionAboutToTrigger
481 && menu->actions().contains(currentAction)) {
482 QEventLoop eventLoop;
483 QAction *activeAction = currentAction;
485 menu->setActiveAction(0);
486 QTimer::singleShot(60, &eventLoop, SLOT(quit()));
489 // Select and wait 20 ms.
490 menu->setActiveAction(activeAction);
491 QTimer::singleShot(20, &eventLoop, SLOT(quit()));
496 if (menu->style()->styleHint(QStyle::SH_Menu_FadeOutOnHide)) {
498 // Should be something like: q->transitionWindow(Qt::FadeOutTransition, MenuFadeTimeInSec);
499 // Hopefully we'll integrate qt/research/windowtransitions into main before 4.4.
500 // Talk to Richard, Trenton or Bjoern.
501 #if defined(Q_WS_MAC)
503 QMacWindowFader::currentFader()->setFadeDuration(MenuFadeTimeInSec);
504 QMacWindowFader::currentFader()->registerWindowToFade(menu);
506 macWindowFade(qt_mac_window_for(menu), MenuFadeTimeInSec);
512 menu->blockSignals(false);
513 #endif // QT_NO_EFFECTS
518 void QMenuPrivate::popupAction(QAction *action, int delay, bool activateFirst)
521 if (action && action->isEnabled()) {
523 q->internalDelayedPopup();
524 else if (!menuDelayTimer.isActive() && (!action->menu() || !action->menu()->isVisible()))
525 menuDelayTimer.start(delay, q);
526 if (activateFirst && action->menu())
527 action->menu()->d_func()->setFirstActionActive();
528 } else if (QMenu *menu = activeMenu) { //hide the current item
534 void QMenuPrivate::setSyncAction()
537 QAction *current = currentAction;
538 if(current && (!current->isEnabled() || current->menu() || current->isSeparator()))
540 for(QWidget *caused = q; caused;) {
541 if (QMenu *m = qobject_cast<QMenu*>(caused)) {
542 caused = m->d_func()->causedPopup.widget;
543 if (m->d_func()->eventLoop)
544 m->d_func()->syncAction = current; // synchronous operation
552 void QMenuPrivate::setFirstActionActive()
556 for(int i = 0, saccum = 0; i < actions.count(); i++) {
557 const QRect &rect = actionRects.at(i);
560 if (scroll && scroll->scrollFlags & QMenuScroller::ScrollUp) {
561 saccum -= rect.height();
562 if (saccum > scroll->scrollOffset - scrollerHeight())
565 QAction *act = actions.at(i);
566 if (!act->isSeparator() &&
567 (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
568 || act->isEnabled())) {
569 setCurrentAction(act);
575 // popup == -1 means do not popup, 0 means immediately, others mean use a timer
576 void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason reason, bool activateFirst)
579 tearoffHighlighted = 0;
580 // Reselect the currently active action in case mouse moved over other menu items when
581 // moving from sub menu action to sub menu (QTBUG-20094).
582 if (reason != SelectedFromKeyboard && action == currentAction && !(action && action->menu() && action->menu() != activeMenu)) {
583 if (QMenu *menu = qobject_cast<QMenu*>(causedPopup.widget)) {
584 if (causedPopup.action && menu->d_func()->activeMenu == q)
585 menu->d_func()->setCurrentAction(causedPopup.action, 0, reason, false);
591 q->update(actionRect(currentAction));
594 if (!sloppyRegion.isEmpty())
595 sloppyRegion = QRegion();
596 QMenu *hideActiveMenu = activeMenu;
597 #ifndef QT_NO_STATUSTIP
598 QAction *previousAction = currentAction;
601 emitHighlighted = action;
604 currentAction = action;
606 if (!action->isSeparator()) {
607 activateAction(action, QAction::Hover);
609 hideActiveMenu = 0; //will be done "later"
610 // if the menu is visible then activate the required action,
611 // otherwise we just mark the action as currentAction
612 // and activate it when the menu will be popuped.
614 popupAction(currentAction, popup, activateFirst);
616 q->update(actionRect(action));
618 if (reason == SelectedFromKeyboard) {
619 QWidget *widget = widgetItems.value(action);
621 if (widget->focusPolicy() != Qt::NoFocus)
622 widget->setFocus(Qt::TabFocusReason);
624 //when the action has no QWidget, the QMenu itself should
626 // Since the menu is a pop-up, it uses the popup reason.
627 if (!q->hasFocus()) {
628 q->setFocus(Qt::PopupFocusReason);
632 } else { //action is a separator
634 hideActiveMenu = 0; //will be done "later"
636 #ifndef QT_NO_STATUSTIP
637 } else if (previousAction) {
638 previousAction->d_func()->showStatusText(topCausedWidget(), QString());
641 if (hideActiveMenu) {
643 #ifndef QT_NO_EFFECTS
644 // kill any running effect
648 hideMenu(hideActiveMenu);
652 //return the top causedPopup.widget that is not a QMenu
653 QWidget *QMenuPrivate::topCausedWidget() const
655 QWidget* top = causedPopup.widget;
656 while (QMenu* m = qobject_cast<QMenu *>(top))
657 top = m->d_func()->causedPopup.widget;
661 QAction *QMenuPrivate::actionAt(QPoint p) const
663 if (!q_func()->rect().contains(p)) //sanity check
666 for(int i = 0; i < actionRects.count(); i++) {
667 if (actionRects.at(i).contains(p))
668 return actions.at(i);
673 void QMenuPrivate::setOverrideMenuAction(QAction *a)
676 QObject::disconnect(menuAction, SIGNAL(destroyed()), q, SLOT(_q_overrideMenuActionDestroyed()));
679 QObject::connect(a, SIGNAL(destroyed()), q, SLOT(_q_overrideMenuActionDestroyed()));
680 } else { //we revert back to the default action created by the QMenu itself
681 menuAction = defaultMenuAction;
685 void QMenuPrivate::_q_overrideMenuActionDestroyed()
687 menuAction=defaultMenuAction;
691 void QMenuPrivate::updateLayoutDirection()
694 //we need to mimic the cause of the popup's layout direction
695 //to allow setting it on a mainwindow for example
696 //we call setLayoutDirection_helper to not overwrite a user-defined value
697 if (!q->testAttribute(Qt::WA_SetLayoutDirection)) {
698 if (QWidget *w = causedPopup.widget)
699 setLayoutDirection_helper(w->layoutDirection());
700 else if (QWidget *w = q->parentWidget())
701 setLayoutDirection_helper(w->layoutDirection());
703 setLayoutDirection_helper(QApplication::layoutDirection());
709 Returns the action associated with this menu.
711 QAction *QMenu::menuAction() const
713 return d_func()->menuAction;
717 \property QMenu::title
718 \brief The title of the menu
720 This is equivalent to the QAction::text property of the menuAction().
722 By default, this property contains an empty string.
724 QString QMenu::title() const
726 return d_func()->menuAction->text();
729 void QMenu::setTitle(const QString &text)
731 d_func()->menuAction->setText(text);
735 \property QMenu::icon
737 \brief The icon of the menu
739 This is equivalent to the QAction::icon property of the menuAction().
741 By default, if no icon is explicitly set, this property contains a null icon.
743 QIcon QMenu::icon() const
745 return d_func()->menuAction->icon();
748 void QMenu::setIcon(const QIcon &icon)
750 d_func()->menuAction->setIcon(icon);
754 //actually performs the scrolling
755 void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation location, bool active)
758 if (!scroll || !scroll->scrollFlags)
762 const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollerHeight() : 0;
763 const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollerHeight() : 0;
764 const int vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q);
765 const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
767 if (location == QMenuScroller::ScrollTop) {
768 for(int i = 0, saccum = 0; i < actions.count(); i++) {
769 if (actions.at(i) == action) {
770 newOffset = topScroll - saccum;
773 saccum += actionRects.at(i).height();
776 for(int i = 0, saccum = 0; i < actions.count(); i++) {
777 saccum += actionRects.at(i).height();
778 if (actions.at(i) == action) {
779 if (location == QMenuScroller::ScrollCenter)
780 newOffset = ((q->height() / 2) - botScroll) - (saccum - topScroll);
782 newOffset = (q->height() - botScroll) - saccum;
790 //figure out which scroll flags
791 uint newScrollFlags = QMenuScroller::ScrollNone;
792 if (newOffset < 0) //easy and cheap one
793 newScrollFlags |= QMenuScroller::ScrollUp;
794 int saccum = newOffset;
795 for(int i = 0; i < actionRects.count(); i++) {
796 saccum += actionRects.at(i).height();
797 if (saccum > q->height()) {
798 newScrollFlags |= QMenuScroller::ScrollDown;
803 if (!(newScrollFlags & QMenuScroller::ScrollDown) && (scroll->scrollFlags & QMenuScroller::ScrollDown)) {
804 newOffset = q->height() - (saccum - newOffset) - fw*2 - vmargin; //last item at bottom
807 if (!(newScrollFlags & QMenuScroller::ScrollUp) && (scroll->scrollFlags & QMenuScroller::ScrollUp)) {
808 newOffset = 0; //first item at top
811 if (newScrollFlags & QMenuScroller::ScrollUp)
812 newOffset -= vmargin;
814 QRect screen = popupGeometry(q);
815 const int desktopFrame = q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q);
816 if (q->height() < screen.height()-(desktopFrame*2)-1) {
817 QRect geom = q->geometry();
818 if (newOffset > scroll->scrollOffset && (scroll->scrollFlags & newScrollFlags & QMenuScroller::ScrollUp)) { //scroll up
819 const int newHeight = geom.height()-(newOffset-scroll->scrollOffset);
820 if(newHeight > geom.height())
821 geom.setHeight(newHeight);
822 } else if(scroll->scrollFlags & newScrollFlags & QMenuScroller::ScrollDown) {
823 int newTop = geom.top() + (newOffset-scroll->scrollOffset);
824 if (newTop < desktopFrame+screen.top())
825 newTop = desktopFrame+screen.top();
826 if (newTop < geom.top()) {
829 newScrollFlags &= ~QMenuScroller::ScrollUp;
832 if (geom.bottom() > screen.bottom() - desktopFrame)
833 geom.setBottom(screen.bottom() - desktopFrame);
834 if (geom.top() < desktopFrame+screen.top())
835 geom.setTop(desktopFrame+screen.top());
836 if (geom != q->geometry()) {
838 if (newScrollFlags & QMenuScroller::ScrollDown &&
839 q->geometry().top() - geom.top() >= -newOffset)
840 newScrollFlags &= ~QMenuScroller::ScrollDown;
842 q->setGeometry(geom);
846 //actually update flags
847 const int delta = qMin(0, newOffset) - scroll->scrollOffset; //make sure the new offset is always negative
848 if (!itemsDirty && delta) {
849 //we've scrolled so we need to update the action rects
850 for (int i = 0; i < actionRects.count(); ++i) {
851 QRect ¤t = actionRects[i];
852 current.moveTop(current.top() + delta);
854 //we need to update the widgets geometry
855 if (QWidget *w = widgetItems.value(actions.at(i)))
856 w->setGeometry(current);
859 scroll->scrollOffset += delta;
860 scroll->scrollFlags = newScrollFlags;
862 setCurrentAction(action);
864 q->update(); //issue an update so we see all the new state..
867 void QMenuPrivate::scrollMenu(QMenuScroller::ScrollLocation location, bool active)
871 if(location == QMenuScroller::ScrollBottom) {
872 for(int i = actions.size()-1; i >= 0; --i) {
873 QAction *act = actions.at(i);
874 if (actionRects.at(i).isNull())
876 if (!act->isSeparator() &&
877 (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
878 || act->isEnabled())) {
879 if(scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
880 scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollBottom, active);
882 setCurrentAction(act, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
886 } else if(location == QMenuScroller::ScrollTop) {
887 for(int i = 0; i < actions.size(); ++i) {
888 QAction *act = actions.at(i);
889 if (actionRects.at(i).isNull())
891 if (!act->isSeparator() &&
892 (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
893 || act->isEnabled())) {
894 if(scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
895 scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollTop, active);
897 setCurrentAction(act, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
905 void QMenuPrivate::scrollMenu(QMenuScroller::ScrollDirection direction, bool page, bool active)
908 if (!scroll || !(scroll->scrollFlags & direction)) //not really possible...
911 const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollerHeight() : 0;
912 const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollerHeight() : 0;
913 const int vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q);
914 const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
915 const int offset = topScroll ? topScroll-vmargin : 0;
916 if (direction == QMenuScroller::ScrollUp) {
917 for(int i = 0, saccum = 0; i < actions.count(); i++) {
918 saccum -= actionRects.at(i).height();
919 if (saccum <= scroll->scrollOffset-offset) {
920 scrollMenu(actions.at(i), page ? QMenuScroller::ScrollBottom : QMenuScroller::ScrollTop, active);
924 } else if (direction == QMenuScroller::ScrollDown) {
925 bool scrolled = false;
926 for(int i = 0, saccum = 0; i < actions.count(); i++) {
927 const int iHeight = actionRects.at(i).height();
929 if (saccum <= scroll->scrollOffset-offset) {
930 const int scrollerArea = q->height() - botScroll - fw*2;
931 int visible = (scroll->scrollOffset-offset) - saccum;
932 for(i++ ; i < actions.count(); i++) {
933 visible += actionRects.at(i).height();
934 if (visible > scrollerArea - topScroll) {
936 scrollMenu(actions.at(i), page ? QMenuScroller::ScrollTop : QMenuScroller::ScrollBottom, active);
944 scroll->scrollFlags &= ~QMenuScroller::ScrollDown;
950 /* This is poor-mans eventfilters. This avoids the use of
951 eventFilter (which can be nasty for users of QMenuBar's). */
952 bool QMenuPrivate::mouseEventTaken(QMouseEvent *e)
955 QPoint pos = q->mapFromGlobal(e->globalPos());
956 if (scroll && !activeMenu) { //let the scroller "steal" the event
957 bool isScroll = false;
958 if (pos.x() >= 0 && pos.x() < q->width()) {
959 for(int dir = QMenuScroller::ScrollUp; dir <= QMenuScroller::ScrollDown; dir = dir << 1) {
960 if (scroll->scrollFlags & dir) {
961 if (dir == QMenuScroller::ScrollUp)
962 isScroll = (pos.y() <= scrollerHeight());
963 else if (dir == QMenuScroller::ScrollDown)
964 isScroll = (pos.y() >= q->height() - scrollerHeight());
966 scroll->scrollDirection = dir;
973 scroll->scrollTimer.start(50, q);
976 scroll->scrollTimer.stop();
980 if (tearoff) { //let the tear off thingie "steal" the event..
981 QRect tearRect(0, 0, q->width(), q->style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, q));
982 if (scroll && scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
983 tearRect.translate(0, scrollerHeight());
985 if (tearRect.contains(pos) && hasMouseMoved(e->globalPos())) {
987 tearoffHighlighted = 1;
988 if (e->type() == QEvent::MouseButtonRelease) {
990 tornPopup = new QTornOffMenu(q);
991 tornPopup->setGeometry(q->geometry());
997 tearoffHighlighted = 0;
1000 if (q->frameGeometry().contains(e->globalPos())) //otherwise if the event is in our rect we want it..
1003 for(QWidget *caused = causedPopup.widget; caused;) {
1004 bool passOnEvent = false;
1005 QWidget *next_widget = 0;
1006 QPoint cpos = caused->mapFromGlobal(e->globalPos());
1007 #ifndef QT_NO_MENUBAR
1008 if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
1009 passOnEvent = mb->rect().contains(cpos);
1012 if (QMenu *m = qobject_cast<QMenu*>(caused)) {
1013 passOnEvent = m->rect().contains(cpos);
1014 next_widget = m->d_func()->causedPopup.widget;
1017 if(e->type() != QEvent::MouseButtonRelease || mouseDown == caused) {
1018 QMouseEvent new_e(e->type(), cpos, e->button(), e->buttons(), e->modifiers());
1019 QApplication::sendEvent(caused, &new_e);
1025 caused = next_widget;
1030 void QMenuPrivate::activateCausedStack(const QList<QPointer<QWidget> > &causedStack, QAction *action, QAction::ActionEvent action_e, bool self)
1032 QBoolBlocker guard(activationRecursionGuard);
1034 const int actionId = q_func()->findIdForAction(action);
1037 action->activate(action_e);
1039 for(int i = 0; i < causedStack.size(); ++i) {
1040 QPointer<QWidget> widget = causedStack.at(i);
1044 if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) {
1045 widget = qmenu->d_func()->causedPopup.widget;
1046 if (action_e == QAction::Trigger) {
1047 emit qmenu->triggered(action);
1048 } else if (action_e == QAction::Hover) {
1049 emit qmenu->hovered(action);
1051 if (emitHighlighted) {
1052 emit qmenu->highlighted(actionId);
1053 emitHighlighted = false;
1057 #ifndef QT_NO_MENUBAR
1058 } else if (QMenuBar *qmenubar = qobject_cast<QMenuBar*>(widget)) {
1059 if (action_e == QAction::Trigger) {
1060 emit qmenubar->triggered(action);
1062 emit qmenubar->activated(actionId);
1064 } else if (action_e == QAction::Hover) {
1065 emit qmenubar->hovered(action);
1067 if (emitHighlighted) {
1068 emit qmenubar->highlighted(actionId);
1069 emitHighlighted = false;
1073 break; //nothing more..
1079 void QMenuPrivate::activateAction(QAction *action, QAction::ActionEvent action_e, bool self)
1082 #ifndef QT_NO_WHATSTHIS
1083 bool inWhatsThisMode = QWhatsThis::inWhatsThisMode();
1085 if (!action || !q->isEnabled()
1086 || (action_e == QAction::Trigger
1087 #ifndef QT_NO_WHATSTHIS
1090 && (action->isSeparator() ||!action->isEnabled())))
1093 /* I have to save the caused stack here because it will be undone after popup execution (ie in the hide).
1094 Then I iterate over the list to actually send the events. --Sam
1096 const QList<QPointer<QWidget> > causedStack = calcCausedStack();
1097 if (action_e == QAction::Trigger) {
1098 #ifndef QT_NO_WHATSTHIS
1099 if (!inWhatsThisMode)
1100 actionAboutToTrigger = action;
1103 if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
1106 for(QWidget *widget = QApplication::activePopupWidget(); widget; ) {
1107 if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) {
1110 widget = qmenu->d_func()->causedPopup.widget;
1117 #ifndef QT_NO_WHATSTHIS
1118 if (inWhatsThisMode) {
1119 QString s = action->whatsThis();
1122 QWhatsThis::showText(q->mapToGlobal(actionRect(action).center()), s, q);
1129 activateCausedStack(causedStack, action, action_e, self);
1132 if (action_e == QAction::Hover) {
1133 #ifndef QT_NO_ACCESSIBILITY
1134 if (QAccessible::isActive()) {
1135 int actionIndex = indexOf(action) + 1;
1136 QAccessible::updateAccessibility(q, actionIndex, QAccessible::Focus);
1137 QAccessible::updateAccessibility(q, actionIndex, QAccessible::Selection);
1140 action->showStatusText(topCausedWidget());
1142 actionAboutToTrigger = 0;
1146 void QMenuPrivate::_q_actionTriggered()
1149 if (QAction *action = qobject_cast<QAction *>(q->sender())) {
1150 QWeakPointer<QAction> actionGuard = action;
1152 //we store it here because the action might be deleted/changed by connected slots
1153 const int id = q->findIdForAction(action);
1155 emit q->triggered(action);
1157 emit q->activated(id);
1160 if (!activationRecursionGuard && actionGuard) {
1161 //in case the action has not been activated by the mouse
1162 //we check the parent hierarchy
1163 QList< QPointer<QWidget> > list;
1164 for(QWidget *widget = q->parentWidget(); widget; ) {
1165 if (qobject_cast<QMenu*>(widget)
1166 #ifndef QT_NO_MENUBAR
1167 || qobject_cast<QMenuBar*>(widget)
1170 list.append(widget);
1171 widget = widget->parentWidget();
1176 activateCausedStack(list, action, QAction::Trigger, false);
1181 void QMenuPrivate::_q_actionHovered()
1184 if (QAction * action = qobject_cast<QAction *>(q->sender())) {
1186 //we store it here because the action might be deleted/changed by connected slots
1187 const int id = q->findIdForAction(action);
1189 emit q->hovered(action);
1191 if (emitHighlighted) {
1192 emit q->highlighted(id);
1193 emitHighlighted = false;
1199 bool QMenuPrivate::hasMouseMoved(const QPoint &globalPos)
1201 //determines if the mouse has moved (ie its initial position has
1202 //changed by more than QApplication::startDragDistance()
1203 //or if there were at least 6 mouse motions)
1204 return motions > 6 ||
1205 QApplication::startDragDistance() < (mousePopupPos - globalPos).manhattanLength();
1210 Initialize \a option with the values from this menu and information from \a action. This method
1211 is useful for subclasses when they need a QStyleOptionMenuItem, but don't want
1212 to fill in all the information themselves.
1214 \sa QStyleOption::initFrom() QMenuBar::initStyleOption()
1216 void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) const
1218 if (!option || !action)
1222 option->initFrom(this);
1223 option->palette = palette();
1224 option->state = QStyle::State_None;
1226 if (window()->isActiveWindow())
1227 option->state |= QStyle::State_Active;
1228 if (isEnabled() && action->isEnabled()
1229 && (!action->menu() || action->menu()->isEnabled()))
1230 option->state |= QStyle::State_Enabled;
1232 option->palette.setCurrentColorGroup(QPalette::Disabled);
1234 option->font = action->font().resolve(font());
1235 option->fontMetrics = QFontMetrics(option->font);
1237 if (d->currentAction && d->currentAction == action && !d->currentAction->isSeparator()) {
1238 option->state |= QStyle::State_Selected
1239 | (d->mouseDown ? QStyle::State_Sunken : QStyle::State_None);
1242 option->menuHasCheckableItems = d->hasCheckableItems;
1243 if (!action->isCheckable()) {
1244 option->checkType = QStyleOptionMenuItem::NotCheckable;
1246 option->checkType = (action->actionGroup() && action->actionGroup()->isExclusive())
1247 ? QStyleOptionMenuItem::Exclusive : QStyleOptionMenuItem::NonExclusive;
1248 option->checked = action->isChecked();
1251 option->menuItemType = QStyleOptionMenuItem::SubMenu;
1252 else if (action->isSeparator())
1253 option->menuItemType = QStyleOptionMenuItem::Separator;
1254 else if (d->defaultAction == action)
1255 option->menuItemType = QStyleOptionMenuItem::DefaultItem;
1257 option->menuItemType = QStyleOptionMenuItem::Normal;
1258 if (action->isIconVisibleInMenu())
1259 option->icon = action->icon();
1260 QString textAndAccel = action->text();
1261 #ifndef QT_NO_SHORTCUT
1262 if (textAndAccel.indexOf(QLatin1Char('\t')) == -1) {
1263 QKeySequence seq = action->shortcut();
1265 textAndAccel += QLatin1Char('\t') + QString(seq);
1268 option->text = textAndAccel;
1269 option->tabWidth = d->tabWidth;
1270 option->maxIconWidth = d->maxIconWidth;
1271 option->menuRect = rect();
1276 \brief The QMenu class provides a menu widget for use in menu
1277 bars, context menus, and other popup menus.
1279 \ingroup mainwindow-classes
1280 \ingroup basicwidgets
1283 A menu widget is a selection menu. It can be either a pull-down
1284 menu in a menu bar or a standalone context menu. Pull-down menus
1285 are shown by the menu bar when the user clicks on the respective
1286 item or presses the specified shortcut key. Use
1287 QMenuBar::addMenu() to insert a menu into a menu bar. Context
1288 menus are usually invoked by some special keyboard key or by
1289 right-clicking. They can be executed either asynchronously with
1290 popup() or synchronously with exec(). Menus can also be invoked in
1291 response to button presses; these are just like context menus
1292 except for how they are invoked.
1296 \o \inlineimage plastique-menu.png
1297 \o \inlineimage windowsxp-menu.png
1298 \o \inlineimage macintosh-menu.png
1300 \caption Fig. A menu shown in \l{Plastique Style Widget Gallery}{Plastique widget style},
1301 \l{Windows XP Style Widget Gallery}{Windows XP widget style},
1302 and \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
1306 A menu consists of a list of action items. Actions are added with
1307 the addAction(), addActions() and insertAction() functions. An action
1308 is represented vertically and rendered by QStyle. In addition, actions
1309 can have a text label, an optional icon drawn on the very left side,
1310 and shortcut key sequence such as "Ctrl+X".
1312 The existing actions held by a menu can be found with actions().
1314 There are four kinds of action items: separators, actions that
1315 show a submenu, widgets, and actions that perform an action.
1316 Separators are inserted with addSeparator(), submenus with addMenu(),
1317 and all other items are considered action items.
1319 When inserting action items you usually specify a receiver and a
1320 slot. The receiver will be notifed whenever the item is
1321 \l{QAction::triggered()}{triggered()}. In addition, QMenu provides
1322 two signals, activated() and highlighted(), which signal the
1323 QAction that was triggered from the menu.
1325 You clear a menu with clear() and remove individual action items
1326 with removeAction().
1328 A QMenu can also provide a tear-off menu. A tear-off menu is a
1329 top-level window that contains a copy of the menu. This makes it
1330 possible for the user to "tear off" frequently used menus and
1331 position them in a convenient place on the screen. If you want
1332 this functionality for a particular menu, insert a tear-off handle
1333 with setTearOffEnabled(). When using tear-off menus, bear in mind
1334 that the concept isn't typically used on Microsoft Windows so
1335 some users may not be familiar with it. Consider using a QToolBar
1338 Widgets can be inserted into menus with the QWidgetAction class.
1339 Instances of this class are used to hold widgets, and are inserted
1340 into menus with the addAction() overload that takes a QAction.
1342 Conversely, actions can be added to widgets with the addAction(),
1343 addActions() and insertAction() functions.
1345 \warning To make QMenu visible on the screen, exec() or popup() should be
1346 used instead of show().
1348 \section1 QMenu on Qt for Windows CE
1350 If a menu is integrated into the native menubar on Windows Mobile we
1351 do not support the signals: aboutToHide (), aboutToShow () and hovered ().
1352 It is not possible to display an icon in a native menu on Windows Mobile.
1354 \section1 QMenu on Mac OS X with Qt build against Cocoa
1356 QMenu can be inserted only once in a menu/menubar. Subsequent insertions will
1357 have no effect or will result in a disabled menu item.
1359 See the \l{mainwindows/menus}{Menus} example for an example of how
1360 to use QMenuBar and QMenu in your application.
1362 \bold{Important inherited functions:} addAction(), removeAction(), clear(),
1363 addSeparator(), and addMenu().
1365 \sa QMenuBar, {fowler}{GUI Design Handbook: Menu, Drop-Down and Pop-Up},
1366 {Application Example}, {Menus Example}, {Recent Files Example}
1371 Constructs a menu with parent \a parent.
1373 Although a popup menu is always a top-level widget, if a parent is
1374 passed the popup menu will be deleted when that parent is
1375 destroyed (as with any other QObject).
1377 QMenu::QMenu(QWidget *parent)
1378 : QWidget(*new QMenuPrivate, parent, Qt::Popup)
1385 Constructs a menu with a \a title and a \a parent.
1387 Although a popup menu is always a top-level widget, if a parent is
1388 passed the popup menu will be deleted when that parent is
1389 destroyed (as with any other QObject).
1393 QMenu::QMenu(const QString &title, QWidget *parent)
1394 : QWidget(*new QMenuPrivate, parent, Qt::Popup)
1398 d->menuAction->setText(title);
1403 QMenu::QMenu(QMenuPrivate &dd, QWidget *parent)
1404 : QWidget(dd, parent, Qt::Popup)
1416 if (!d->widgetItems.isEmpty()) { // avoid detach on shared null hash
1417 QHash<QAction *, QWidget *>::iterator it = d->widgetItems.begin();
1418 for (; it != d->widgetItems.end(); ++it) {
1419 if (QWidget *widget = it.value()) {
1420 QWidgetAction *action = static_cast<QWidgetAction *>(it.key());
1421 action->releaseWidget(widget);
1428 d->eventLoop->exit();
1435 This convenience function creates a new action with \a text.
1436 The function adds the newly created action to the menu's
1437 list of actions, and returns it.
1439 \sa QWidget::addAction()
1441 QAction *QMenu::addAction(const QString &text)
1443 QAction *ret = new QAction(text, this);
1451 This convenience function creates a new action with an \a icon
1452 and some \a text. The function adds the newly created action to
1453 the menu's list of actions, and returns it.
1455 \sa QWidget::addAction()
1457 QAction *QMenu::addAction(const QIcon &icon, const QString &text)
1459 QAction *ret = new QAction(icon, text, this);
1467 This convenience function creates a new action with the text \a
1468 text and an optional shortcut \a shortcut. The action's
1469 \l{QAction::triggered()}{triggered()} signal is connected to the
1470 \a receiver's \a member slot. The function adds the newly created
1471 action to the menu's list of actions and returns it.
1473 \sa QWidget::addAction()
1475 QAction *QMenu::addAction(const QString &text, const QObject *receiver, const char* member, const QKeySequence &shortcut)
1477 QAction *action = new QAction(text, this);
1478 #ifdef QT_NO_SHORTCUT
1481 action->setShortcut(shortcut);
1483 QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
1491 This convenience function creates a new action with an \a icon and
1492 some \a text and an optional shortcut \a shortcut. The action's
1493 \l{QAction::triggered()}{triggered()} signal is connected to the
1494 \a member slot of the \a receiver object. The function adds the
1495 newly created action to the menu's list of actions, and returns it.
1497 \sa QWidget::addAction()
1499 QAction *QMenu::addAction(const QIcon &icon, const QString &text, const QObject *receiver,
1500 const char* member, const QKeySequence &shortcut)
1502 QAction *action = new QAction(icon, text, this);
1503 #ifdef QT_NO_SHORTCUT
1506 action->setShortcut(shortcut);
1508 QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
1514 This convenience function adds \a menu as a submenu to this menu.
1515 It returns \a menu's menuAction(). This menu does not take
1516 ownership of \a menu.
1518 \sa QWidget::addAction() QMenu::menuAction()
1520 QAction *QMenu::addMenu(QMenu *menu)
1522 QAction *action = menu->menuAction();
1528 Appends a new QMenu with \a title to the menu. The menu
1529 takes ownership of the menu. Returns the new menu.
1531 \sa QWidget::addAction() QMenu::menuAction()
1533 QMenu *QMenu::addMenu(const QString &title)
1535 QMenu *menu = new QMenu(title, this);
1536 addAction(menu->menuAction());
1541 Appends a new QMenu with \a icon and \a title to the menu. The menu
1542 takes ownership of the menu. Returns the new menu.
1544 \sa QWidget::addAction() QMenu::menuAction()
1546 QMenu *QMenu::addMenu(const QIcon &icon, const QString &title)
1548 QMenu *menu = new QMenu(title, this);
1549 menu->setIcon(icon);
1550 addAction(menu->menuAction());
1555 This convenience function creates a new separator action, i.e. an
1556 action with QAction::isSeparator() returning true, and adds the new
1557 action to this menu's list of actions. It returns the newly
1560 \sa QWidget::addAction()
1562 QAction *QMenu::addSeparator()
1564 QAction *action = new QAction(this);
1565 action->setSeparator(true);
1571 This convenience function inserts \a menu before action \a before
1572 and returns the menus menuAction().
1574 \sa QWidget::insertAction(), addMenu()
1576 QAction *QMenu::insertMenu(QAction *before, QMenu *menu)
1578 QAction *action = menu->menuAction();
1579 insertAction(before, action);
1584 This convenience function creates a new separator action, i.e. an
1585 action with QAction::isSeparator() returning true. The function inserts
1586 the newly created action into this menu's list of actions before
1587 action \a before and returns it.
1589 \sa QWidget::insertAction(), addSeparator()
1591 QAction *QMenu::insertSeparator(QAction *before)
1593 QAction *action = new QAction(this);
1594 action->setSeparator(true);
1595 insertAction(before, action);
1600 This sets the default action to \a act. The default action may have
1601 a visual cue, depending on the current QStyle. A default action
1602 usually indicates what will happen by default when a drop occurs.
1606 void QMenu::setDefaultAction(QAction *act)
1608 d_func()->defaultAction = act;
1612 Returns the current default action.
1614 \sa setDefaultAction()
1616 QAction *QMenu::defaultAction() const
1618 return d_func()->defaultAction;
1622 \property QMenu::tearOffEnabled
1623 \brief whether the menu supports being torn off
1625 When true, the menu contains a special tear-off item (often shown as a dashed
1626 line at the top of the menu) that creates a copy of the menu when it is
1629 This "torn-off" copy lives in a separate window. It contains the same menu
1630 items as the original menu, with the exception of the tear-off handle.
1632 By default, this property is false.
1634 void QMenu::setTearOffEnabled(bool b)
1637 if (d->tearoff == b)
1643 d->itemsDirty = true;
1648 bool QMenu::isTearOffEnabled() const
1650 return d_func()->tearoff;
1654 When a menu is torn off a second menu is shown to display the menu
1655 contents in a new window. When the menu is in this mode and the menu
1656 is visible returns true; otherwise false.
1658 \sa hideTearOffMenu() isTearOffEnabled()
1660 bool QMenu::isTearOffMenuVisible() const
1662 if (d_func()->tornPopup)
1663 return d_func()->tornPopup->isVisible();
1668 This function will forcibly hide the torn off menu making it
1669 disappear from the users desktop.
1671 \sa isTearOffMenuVisible() isTearOffEnabled()
1673 void QMenu::hideTearOffMenu()
1675 if (QWidget *w = d_func()->tornPopup)
1681 Sets the currently highlighted action to \a act.
1683 void QMenu::setActiveAction(QAction *act)
1686 d->setCurrentAction(act, 0);
1688 d->scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollCenter);
1693 Returns the currently highlighted action, or 0 if no
1694 action is currently highlighted.
1696 QAction *QMenu::activeAction() const
1698 return d_func()->currentAction;
1704 Returns true if there are no visible actions inserted into the menu, false
1707 \sa QWidget::actions()
1710 bool QMenu::isEmpty() const
1713 for(int i = 0; ret && i < actions().count(); ++i) {
1714 const QAction *action = actions().at(i);
1715 if (!action->isSeparator() && action->isVisible()) {
1723 Removes all the menu's actions. Actions owned by the menu and not
1724 shown in any other widget are deleted.
1730 QList<QAction*> acts = actions();
1732 for(int i = 0; i < acts.size(); i++) {
1733 #ifdef QT_SOFTKEYS_ENABLED
1735 // Lets not touch to our internal softkey actions
1736 if(acts[i] == d->selectAction || acts[i] == d->cancelAction)
1739 removeAction(acts[i]);
1740 if (acts[i]->parent() == this && acts[i]->d_func()->widgets.isEmpty())
1746 If a menu does not fit on the screen it lays itself out so that it
1747 does fit. It is style dependent what layout means (for example, on
1748 Windows it will use multiple columns).
1750 This functions returns the number of columns necessary.
1752 int QMenu::columnCount() const
1754 return d_func()->ncols;
1758 Returns the item at \a pt; returns 0 if there is no item there.
1760 QAction *QMenu::actionAt(const QPoint &pt) const
1762 if (QAction *ret = d_func()->actionAt(pt))
1768 Returns the geometry of action \a act.
1770 QRect QMenu::actionGeometry(QAction *act) const
1772 return d_func()->actionRect(act);
1778 QSize QMenu::sizeHint() const
1781 d->updateActionRects();
1784 for (int i = 0; i < d->actionRects.count(); ++i) {
1785 const QRect &rect = d->actionRects.at(i);
1788 if (rect.bottom() >= s.height())
1789 s.setHeight(rect.y() + rect.height());
1790 if (rect.right() >= s.width())
1791 s.setWidth(rect.x() + rect.width());
1793 // Note that the action rects calculated above already include
1794 // the top and left margins, so we only need to add margins for
1795 // the bottom and right.
1796 QStyleOption opt(0);
1798 const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, this);
1799 s.rwidth() += style()->pixelMetric(QStyle::PM_MenuHMargin, &opt, this) + fw + d->rightmargin;
1800 s.rheight() += style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, this) + fw + d->bottommargin;
1802 return style()->sizeFromContents(QStyle::CT_Menu, &opt,
1803 s.expandedTo(QApplication::globalStrut()), this);
1807 Displays the menu so that the action \a atAction will be at the
1808 specified \e global position \a p. To translate a widget's local
1809 coordinates into global coordinates, use QWidget::mapToGlobal().
1811 When positioning a menu with exec() or popup(), bear in mind that
1812 you cannot rely on the menu's current size(). For performance
1813 reasons, the menu adapts its size only when necessary, so in many
1814 cases, the size before and after the show is different. Instead,
1815 use sizeHint() which calculates the proper size depending on the
1816 menu's current contents.
1818 \sa QWidget::mapToGlobal(), exec()
1820 void QMenu::popup(const QPoint &p, QAction *atAction)
1823 #ifndef Q_OS_SYMBIAN
1824 if (d->scroll) { // reset scroll state from last popup
1825 if (d->scroll->scrollOffset)
1826 d->itemsDirty = 1; // sizeHint will be incorrect if there is previous scroll
1827 d->scroll->scrollOffset = 0;
1828 d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
1831 d->tearoffHighlighted = 0;
1833 d->doChildEffects = true;
1834 d->updateLayoutDirection();
1836 #ifndef QT_NO_MENUBAR
1837 // if this menu is part of a chain attached to a QMenuBar, set the
1838 // _NET_WM_WINDOW_TYPE_DROPDOWN_MENU X11 window type
1839 setAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu, qobject_cast<QMenuBar *>(d->topCausedWidget()) != 0);
1842 ensurePolished(); // Get the right font
1844 const bool actionListChanged = d->itemsDirty;
1845 d->updateActionRects();
1847 QPushButton *causedButton = qobject_cast<QPushButton*>(d->causedPopup.widget);
1848 if (actionListChanged && causedButton)
1849 pos = QPushButtonPrivate::get(causedButton)->adjustedMenuPosition();
1853 QSize size = sizeHint();
1855 #ifndef QT_NO_GRAPHICSVIEW
1856 bool isEmbedded = !bypassGraphicsProxyWidget(this) && d->nearestGraphicsProxyWidget(this);
1858 screen = d->popupGeometry(this);
1861 screen = d->popupGeometry(QApplication::desktop()->screenNumber(p));
1862 const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this);
1863 bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen);
1865 // if the screens have very different geometries and the menu is too big, we have to recalculate
1866 if (size.height() > screen.height() || size.width() > screen.width()) {
1867 size = d->adjustMenuSizeForScreen(screen);
1868 adjustToDesktop = true;
1870 // Layout is not right, we might be able to save horizontal space
1871 if (d->ncols >1 && size.height() < screen.height()) {
1872 size = d->adjustMenuSizeForScreen(screen);
1873 adjustToDesktop = true;
1877 #ifdef QT_KEYPAD_NAVIGATION
1878 if (!atAction && QApplication::keypadNavigationEnabled()) {
1879 // Try to have one item activated
1880 if (d->defaultAction && d->defaultAction->isEnabled()) {
1881 atAction = d->defaultAction;
1882 // TODO: This works for first level menus, not yet sub menus
1884 foreach (QAction *action, d->actions)
1885 if (action->isEnabled()) {
1890 d->currentAction = atAction;
1894 pos.setY(screen.top() + desktopFrame);
1895 } else if (atAction) {
1896 for (int i = 0, above_height = 0; i < d->actions.count(); i++) {
1897 QAction *action = d->actions.at(i);
1898 if (action == atAction) {
1899 int newY = pos.y() - above_height;
1900 if (d->scroll && newY < desktopFrame) {
1901 d->scroll->scrollFlags = d->scroll->scrollFlags
1902 | QMenuPrivate::QMenuScroller::ScrollUp;
1903 d->scroll->scrollOffset = newY;
1904 newY = desktopFrame;
1908 if (d->scroll && d->scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone
1909 && !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, 0, this)) {
1910 int below_height = above_height + d->scroll->scrollOffset;
1911 for (int i2 = i; i2 < d->actionRects.count(); i2++)
1912 below_height += d->actionRects.at(i2).height();
1913 size.setHeight(below_height);
1917 above_height += d->actionRects.at(i).height();
1922 QPoint mouse = QCursor::pos();
1923 d->mousePopupPos = mouse;
1924 const bool snapToMouse = !d->causedPopup.widget && (QRect(p.x() - 3, p.y() - 3, 6, 6).contains(mouse));
1926 const QSize menuSize(sizeHint());
1927 if (adjustToDesktop) {
1928 // handle popup falling "off screen"
1929 if (isRightToLeft()) {
1930 if (snapToMouse) // position flowing left from the mouse
1931 pos.setX(mouse.x() - size.width());
1933 #ifndef QT_NO_MENUBAR
1934 // if in a menubar, it should be right-aligned
1935 if (qobject_cast<QMenuBar*>(d->causedPopup.widget))
1936 pos.rx() -= size.width();
1937 #endif //QT_NO_MENUBAR
1939 if (pos.x() < screen.left() + desktopFrame)
1940 pos.setX(qMax(p.x(), screen.left() + desktopFrame));
1941 if (pos.x() + size.width() - 1 > screen.right() - desktopFrame)
1942 pos.setX(qMax(p.x() - size.width(), screen.right() - desktopFrame - size.width() + 1));
1944 if (pos.x() + size.width() - 1 > screen.right() - desktopFrame)
1945 pos.setX(screen.right() - desktopFrame - size.width() + 1);
1946 if (pos.x() < screen.left() + desktopFrame)
1947 pos.setX(screen.left() + desktopFrame);
1949 if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) {
1951 pos.setY(qMin(mouse.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
1953 pos.setY(qMax(p.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
1954 } else if (pos.y() < screen.top() + desktopFrame) {
1955 pos.setY(screen.top() + desktopFrame);
1958 if (pos.y() < screen.top() + desktopFrame)
1959 pos.setY(screen.top() + desktopFrame);
1960 if (pos.y() + menuSize.height() - 1 > screen.bottom() - desktopFrame) {
1962 d->scroll->scrollFlags |= uint(QMenuPrivate::QMenuScroller::ScrollDown);
1963 int y = qMax(screen.y(),pos.y());
1964 size.setHeight(screen.bottom() - (desktopFrame * 2) - y);
1966 // Too big for screen, bias to see bottom of menu (for some reason)
1967 pos.setY(screen.bottom() - size.height() + 1);
1971 const int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this);
1972 QMenu *caused = qobject_cast<QMenu*>(d_func()->causedPopup.widget);
1973 if (caused && caused->geometry().width() + menuSize.width() + subMenuOffset < screen.width()) {
1974 QRect parentActionRect(caused->d_func()->actionRect(caused->d_func()->currentAction));
1975 const QPoint actionTopLeft = caused->mapToGlobal(parentActionRect.topLeft());
1976 parentActionRect.moveTopLeft(actionTopLeft);
1977 if (isRightToLeft()) {
1978 if ((pos.x() + menuSize.width() > parentActionRect.left() - subMenuOffset)
1979 && (pos.x() < parentActionRect.right()))
1981 pos.rx() = parentActionRect.left() - menuSize.width();
1982 if (pos.x() < screen.x())
1983 pos.rx() = parentActionRect.right();
1984 if (pos.x() + menuSize.width() > screen.x() + screen.width())
1985 pos.rx() = screen.x();
1988 if ((pos.x() < parentActionRect.right() + subMenuOffset)
1989 && (pos.x() + menuSize.width() > parentActionRect.left()))
1991 pos.rx() = parentActionRect.right();
1992 if (pos.x() + menuSize.width() > screen.x() + screen.width())
1993 pos.rx() = parentActionRect.left() - menuSize.width();
1994 if (pos.x() < screen.x())
1995 pos.rx() = screen.x() + screen.width() - menuSize.width();
1999 setGeometry(QRect(pos, size));
2000 #ifndef QT_NO_EFFECTS
2001 int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
2002 int vGuess = QEffects::DownScroll;
2003 if (isRightToLeft()) {
2004 if ((snapToMouse && (pos.x() + size.width() / 2 > mouse.x())) ||
2005 (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width() / 2 > d->causedPopup.widget->x()))
2006 hGuess = QEffects::RightScroll;
2008 if ((snapToMouse && (pos.x() + size.width() / 2 < mouse.x())) ||
2009 (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width() / 2 < d->causedPopup.widget->x()))
2010 hGuess = QEffects::LeftScroll;
2013 #ifndef QT_NO_MENUBAR
2014 if ((snapToMouse && (pos.y() + size.height() / 2 < mouse.y())) ||
2015 (qobject_cast<QMenuBar*>(d->causedPopup.widget) &&
2016 pos.y() + size.width() / 2 < d->causedPopup.widget->mapToGlobal(d->causedPopup.widget->pos()).y()))
2017 vGuess = QEffects::UpScroll;
2019 if (QApplication::isEffectEnabled(Qt::UI_AnimateMenu)) {
2020 bool doChildEffects = true;
2021 #ifndef QT_NO_MENUBAR
2022 if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget)) {
2023 doChildEffects = mb->d_func()->doChildEffects;
2024 mb->d_func()->doChildEffects = false;
2027 if (QMenu *m = qobject_cast<QMenu*>(d->causedPopup.widget)) {
2028 doChildEffects = m->d_func()->doChildEffects;
2029 m->d_func()->doChildEffects = false;
2032 if (doChildEffects) {
2033 if (QApplication::isEffectEnabled(Qt::UI_FadeMenu))
2035 else if (d->causedPopup.widget)
2036 qScrollEffect(this, qobject_cast<QMenu*>(d->causedPopup.widget) ? hGuess : vGuess);
2038 qScrollEffect(this, hGuess | vGuess);
2040 // kill any running effect
2052 #ifndef QT_NO_ACCESSIBILITY
2053 QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuStart);
2058 Executes this menu synchronously.
2060 This is equivalent to \c{exec(pos())}.
2062 This returns the triggered QAction in either the popup menu or one
2063 of its submenus, or 0 if no item was triggered (normally because
2064 the user pressed Esc).
2066 In most situations you'll want to specify the position yourself,
2067 for example, the current mouse position:
2068 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 0
2069 or aligned to a widget:
2070 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 1
2071 or in reaction to a QMouseEvent *e:
2072 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 2
2074 QAction *QMenu::exec()
2083 Executes this menu synchronously.
2085 Pops up the menu so that the action \a action will be at the
2086 specified \e global position \a p. To translate a widget's local
2087 coordinates into global coordinates, use QWidget::mapToGlobal().
2089 This returns the triggered QAction in either the popup menu or one
2090 of its submenus, or 0 if no item was triggered (normally because
2091 the user pressed Esc).
2093 Note that all signals are emitted as usual. If you connect a
2094 QAction to a slot and call the menu's exec(), you get the result
2095 both via the signal-slot connection and in the return value of
2098 Common usage is to position the menu at the current mouse
2100 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 3
2101 or aligned to a widget:
2102 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 4
2103 or in reaction to a QMouseEvent *e:
2104 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 5
2106 When positioning a menu with exec() or popup(), bear in mind that
2107 you cannot rely on the menu's current size(). For performance
2108 reasons, the menu adapts its size only when necessary. So in many
2109 cases, the size before and after the show is different. Instead,
2110 use sizeHint() which calculates the proper size depending on the
2111 menu's current contents.
2113 \sa popup(), QWidget::mapToGlobal()
2115 QAction *QMenu::exec(const QPoint &p, QAction *action)
2119 QEventLoop eventLoop;
2120 d->eventLoop = &eventLoop;
2123 QPointer<QObject> guard = this;
2124 (void) eventLoop.exec();
2128 action = d->syncAction;
2137 Executes a menu synchronously.
2139 The menu's actions are specified by the list of \a actions. The menu will
2140 pop up so that the specified action, \a at, appears at global position \a
2141 pos. If \a at is not specified then the menu appears at position \a
2142 pos. \a parent is the menu's parent widget; specifying the parent will
2143 provide context when \a pos alone is not enough to decide where the menu
2144 should go (e.g., with multiple desktops or when the parent is embedded in
2147 The function returns the triggered QAction in either the popup
2148 menu or one of its submenus, or 0 if no item was triggered
2149 (normally because the user pressed Esc).
2151 This is equivalent to:
2152 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 6
2154 \sa popup(), QWidget::mapToGlobal()
2156 QAction *QMenu::exec(QList<QAction*> actions, const QPoint &pos, QAction *at, QWidget *parent)
2159 menu.addActions(actions);
2160 return menu.exec(pos, at);
2166 Executes a menu synchronously.
2168 The menu's actions are specified by the list of \a actions. The menu
2169 will pop up so that the specified action, \a at, appears at global
2170 position \a pos. If \a at is not specified then the menu appears
2173 The function returns the triggered QAction in either the popup
2174 menu or one of its submenus, or 0 if no item was triggered
2175 (normally because the user pressed Esc).
2177 This is equivalent to:
2178 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 6
2180 \sa popup(), QWidget::mapToGlobal()
2182 QAction *QMenu::exec(QList<QAction*> actions, const QPoint &pos, QAction *at)
2185 return exec(actions, pos, at, 0);
2191 void QMenu::hideEvent(QHideEvent *)
2196 d->eventLoop->exit();
2197 d->setCurrentAction(0);
2198 #ifndef QT_NO_ACCESSIBILITY
2199 QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuEnd);
2201 #ifndef QT_NO_MENUBAR
2202 if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget))
2203 mb->d_func()->setCurrentAction(0);
2206 d->hasHadMouse = false;
2207 d->causedPopup.widget = 0;
2208 d->causedPopup.action = 0;
2210 d->scroll->scrollTimer.stop(); //make sure the timer stops
2216 void QMenu::paintEvent(QPaintEvent *e)
2219 d->updateActionRects();
2221 QRegion emptyArea = QRegion(rect());
2223 QStyleOptionMenuItem menuOpt;
2224 menuOpt.initFrom(this);
2225 menuOpt.state = QStyle::State_None;
2226 menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
2227 menuOpt.maxIconWidth = 0;
2228 menuOpt.tabWidth = 0;
2229 style()->drawPrimitive(QStyle::PE_PanelMenu, &menuOpt, &p, this);
2231 //draw the items that need updating..
2232 for (int i = 0; i < d->actions.count(); ++i) {
2233 QAction *action = d->actions.at(i);
2234 QRect adjustedActionRect = d->actionRects.at(i);
2235 if (!e->rect().intersects(adjustedActionRect)
2236 || d->widgetItems.value(action))
2238 //set the clip region to be extra safe (and adjust for the scrollers)
2239 QRegion adjustedActionReg(adjustedActionRect);
2240 emptyArea -= adjustedActionReg;
2241 p.setClipRegion(adjustedActionReg);
2243 QStyleOptionMenuItem opt;
2244 initStyleOption(&opt, action);
2245 opt.rect = adjustedActionRect;
2246 style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this);
2249 const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this);
2250 //draw the scroller regions..
2252 menuOpt.menuItemType = QStyleOptionMenuItem::Scroller;
2253 menuOpt.state |= QStyle::State_Enabled;
2254 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) {
2255 menuOpt.rect.setRect(fw, fw, width() - (fw * 2), d->scrollerHeight());
2256 emptyArea -= QRegion(menuOpt.rect);
2257 p.setClipRect(menuOpt.rect);
2258 style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this);
2260 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown) {
2261 menuOpt.rect.setRect(fw, height() - d->scrollerHeight() - fw, width() - (fw * 2),
2262 d->scrollerHeight());
2263 emptyArea -= QRegion(menuOpt.rect);
2264 menuOpt.state |= QStyle::State_DownArrow;
2265 p.setClipRect(menuOpt.rect);
2266 style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this);
2269 //paint the tear off..
2271 menuOpt.menuItemType = QStyleOptionMenuItem::TearOff;
2272 menuOpt.rect.setRect(fw, fw, width() - (fw * 2),
2273 style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this));
2274 if (d->scroll && d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
2275 menuOpt.rect.translate(0, d->scrollerHeight());
2276 emptyArea -= QRegion(menuOpt.rect);
2277 p.setClipRect(menuOpt.rect);
2278 menuOpt.state = QStyle::State_None;
2279 if (d->tearoffHighlighted)
2280 menuOpt.state |= QStyle::State_Selected;
2281 style()->drawControl(QStyle::CE_MenuTearoff, &menuOpt, &p, this);
2286 borderReg += QRect(0, 0, fw, height()); //left
2287 borderReg += QRect(width()-fw, 0, fw, height()); //right
2288 borderReg += QRect(0, 0, width(), fw); //top
2289 borderReg += QRect(0, height()-fw, width(), fw); //bottom
2290 p.setClipRegion(borderReg);
2291 emptyArea -= borderReg;
2292 QStyleOptionFrame frame;
2293 frame.rect = rect();
2294 frame.palette = palette();
2295 frame.state = QStyle::State_None;
2296 frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth);
2297 frame.midLineWidth = 0;
2298 style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, &p, this);
2301 //finally the rest of the space
2302 p.setClipRegion(emptyArea);
2303 menuOpt.state = QStyle::State_None;
2304 menuOpt.menuItemType = QStyleOptionMenuItem::EmptyArea;
2305 menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
2306 menuOpt.rect = rect();
2307 menuOpt.menuRect = rect();
2308 style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOpt, &p, this);
2311 #ifndef QT_NO_WHEELEVENT
2315 void QMenu::wheelEvent(QWheelEvent *e)
2318 if (d->scroll && rect().contains(e->pos()))
2319 d->scrollMenu(e->delta() > 0 ?
2320 QMenuPrivate::QMenuScroller::ScrollUp : QMenuPrivate::QMenuScroller::ScrollDown);
2327 void QMenu::mousePressEvent(QMouseEvent *e)
2330 if (d->aboutToHide || d->mouseEventTaken(e))
2332 if (!rect().contains(e->pos())) {
2334 && QRect(d->noReplayFor->mapToGlobal(QPoint()), d->noReplayFor->size()).contains(e->globalPos()))
2335 setAttribute(Qt::WA_NoMouseReplay);
2336 if (d->eventLoop) // synchronous operation
2338 d->hideUpToMenuBar();
2341 d->mouseDown = this;
2343 QAction *action = d->actionAt(e->pos());
2344 d->setCurrentAction(action, 20);
2351 void QMenu::mouseReleaseEvent(QMouseEvent *e)
2354 if (d->aboutToHide || d->mouseEventTaken(e))
2356 if(d->mouseDown != this) {
2363 QAction *action = d->actionAt(e->pos());
2365 if (action && action == d->currentAction) {
2366 if (!action->menu()){
2367 #if defined(Q_WS_WIN)
2368 //On Windows only context menus can be activated with the right button
2369 if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0)
2371 d->activateAction(action, QAction::Trigger);
2373 } else if (d->hasMouseMoved(e->globalPos())) {
2374 d->hideUpToMenuBar();
2381 void QMenu::changeEvent(QEvent *e)
2384 if (e->type() == QEvent::StyleChange || e->type() == QEvent::FontChange ||
2385 e->type() == QEvent::LayoutDirectionChange) {
2387 setMouseTracking(style()->styleHint(QStyle::SH_Menu_MouseTracking, 0, this));
2390 if (!style()->styleHint(QStyle::SH_Menu_Scrollable, 0, this)) {
2393 } else if (!d->scroll) {
2394 d->scroll = new QMenuPrivate::QMenuScroller;
2395 d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
2397 } else if (e->type() == QEvent::EnabledChange) {
2398 if (d->tornPopup) // torn-off menu
2399 d->tornPopup->setEnabled(isEnabled());
2400 d->menuAction->setEnabled(isEnabled());
2401 #if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
2403 d->setMacMenuEnabled(isEnabled());
2406 QWidget::changeEvent(e);
2414 QMenu::event(QEvent *e)
2417 switch (e->type()) {
2418 case QEvent::Polish:
2419 d->updateLayoutDirection();
2421 case QEvent::ShortcutOverride: {
2422 QKeyEvent *kev = static_cast<QKeyEvent*>(e);
2423 if (kev->key() == Qt::Key_Up || kev->key() == Qt::Key_Down
2424 || kev->key() == Qt::Key_Left || kev->key() == Qt::Key_Right
2425 || kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return
2426 || kev->key() == Qt::Key_Escape) {
2432 case QEvent::KeyPress: {
2433 QKeyEvent *ke = (QKeyEvent*)e;
2434 if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
2439 case QEvent::ContextMenu:
2440 if(d->menuDelayTimer.isActive()) {
2441 d->menuDelayTimer.stop();
2442 internalDelayedPopup();
2445 case QEvent::Resize: {
2446 QStyleHintReturnMask menuMask;
2447 QStyleOption option;
2448 option.initFrom(this);
2449 if (style()->styleHint(QStyle::SH_Menu_Mask, &option, this, &menuMask)) {
2450 setMask(menuMask.region);
2453 d->updateActionRects();
2457 d->updateActionRects();
2458 if (d->currentAction)
2459 d->popupAction(d->currentAction, 0, false);
2461 #ifndef QT_NO_WHATSTHIS
2462 case QEvent::QueryWhatsThis:
2463 e->setAccepted(d->whatsThis.size());
2464 if (QAction *action = d->actionAt(static_cast<QHelpEvent*>(e)->pos())) {
2465 if (action->whatsThis().size() || action->menu())
2470 #ifdef QT_SOFTKEYS_ENABLED
2471 case QEvent::LanguageChange: {
2472 d->selectAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::SelectSoftKey));
2473 d->cancelAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::CancelSoftKey));
2480 return QWidget::event(e);
2486 bool QMenu::focusNextPrevChild(bool next)
2489 QKeyEvent ev(QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
2497 void QMenu::keyPressEvent(QKeyEvent *e)
2500 d->updateActionRects();
2502 if (isRightToLeft()) { // in reverse mode open/close key for submenues are reversed
2503 if (key == Qt::Key_Left)
2504 key = Qt::Key_Right;
2505 else if (key == Qt::Key_Right)
2509 if (key == Qt::Key_Tab) //means down
2511 if (key == Qt::Key_Backtab) //means up
2515 bool key_consumed = false;
2518 key_consumed = true;
2520 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollTop, true);
2523 key_consumed = true;
2525 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollBottom, true);
2527 case Qt::Key_PageUp:
2528 key_consumed = true;
2529 if (d->currentAction && d->scroll) {
2530 if(d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
2531 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollUp, true, true);
2533 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollTop, true);
2536 case Qt::Key_PageDown:
2537 key_consumed = true;
2538 if (d->currentAction && d->scroll) {
2539 if(d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
2540 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollDown, true, true);
2542 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollBottom, true);
2546 case Qt::Key_Down: {
2547 key_consumed = true;
2548 QAction *nextAction = 0;
2549 QMenuPrivate::QMenuScroller::ScrollLocation scroll_loc = QMenuPrivate::QMenuScroller::ScrollStay;
2550 if (!d->currentAction) {
2551 if(key == Qt::Key_Down) {
2552 for(int i = 0; i < d->actions.count(); ++i) {
2553 QAction *act = d->actions.at(i);
2554 if (d->actionRects.at(i).isNull())
2556 if (!act->isSeparator() &&
2557 (style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)
2558 || act->isEnabled())) {
2564 for(int i = d->actions.count()-1; i >= 0; --i) {
2565 QAction *act = d->actions.at(i);
2566 if (d->actionRects.at(i).isNull())
2568 if (!act->isSeparator() &&
2569 (style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)
2570 || act->isEnabled())) {
2577 for(int i = 0, y = 0; !nextAction && i < d->actions.count(); i++) {
2578 QAction *act = d->actions.at(i);
2579 if (act == d->currentAction) {
2580 if (key == Qt::Key_Up) {
2581 for(int next_i = i-1; true; next_i--) {
2583 if(!style()->styleHint(QStyle::SH_Menu_SelectionWrap, 0, this))
2586 scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom;
2587 next_i = d->actionRects.count()-1;
2589 QAction *next = d->actions.at(next_i);
2590 if (next == d->currentAction)
2592 if (d->actionRects.at(next_i).isNull())
2594 if (next->isSeparator() ||
2595 (!next->isEnabled() &&
2596 !style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)))
2599 if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)) {
2600 int topVisible = d->scrollerHeight();
2602 topVisible += style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this);
2603 if (((y + d->scroll->scrollOffset) - topVisible) <= d->actionRects.at(next_i).height())
2604 scroll_loc = QMenuPrivate::QMenuScroller::ScrollTop;
2608 if (!nextAction && d->tearoff)
2609 d->tearoffHighlighted = 1;
2611 y += d->actionRects.at(i).height();
2612 for(int next_i = i+1; true; next_i++) {
2613 if (next_i == d->actionRects.count()) {
2614 if(!style()->styleHint(QStyle::SH_Menu_SelectionWrap, 0, this))
2617 scroll_loc = QMenuPrivate::QMenuScroller::ScrollTop;
2620 QAction *next = d->actions.at(next_i);
2621 if (next == d->currentAction)
2623 if (d->actionRects.at(next_i).isNull())
2625 if (next->isSeparator() ||
2626 (!next->isEnabled() &&
2627 !style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)))
2630 if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)) {
2631 int bottomVisible = height() - d->scrollerHeight();
2632 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
2633 bottomVisible -= d->scrollerHeight();
2635 bottomVisible -= style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this);
2636 if ((y + d->scroll->scrollOffset + d->actionRects.at(next_i).height()) > bottomVisible)
2637 scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom;
2644 y += d->actionRects.at(i).height();
2648 if (d->scroll && scroll_loc != QMenuPrivate::QMenuScroller::ScrollStay) {
2649 d->scroll->scrollTimer.stop();
2650 d->scrollMenu(nextAction, scroll_loc);
2652 d->setCurrentAction(nextAction, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
2657 if (d->currentAction && d->currentAction->isEnabled() && d->currentAction->menu()) {
2658 d->popupAction(d->currentAction, 0, true);
2659 key_consumed = true;
2663 case Qt::Key_Left: {
2664 if (d->currentAction && !d->scroll) {
2665 QAction *nextAction = 0;
2666 if (key == Qt::Key_Left) {
2667 QRect actionR = d->actionRect(d->currentAction);
2668 for(int x = actionR.left()-1; !nextAction && x >= 0; x--)
2669 nextAction = d->actionAt(QPoint(x, actionR.center().y()));
2671 QRect actionR = d->actionRect(d->currentAction);
2672 for(int x = actionR.right()+1; !nextAction && x < width(); x++)
2673 nextAction = d->actionAt(QPoint(x, actionR.center().y()));
2676 d->setCurrentAction(nextAction, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
2677 key_consumed = true;
2680 if (!key_consumed && key == Qt::Key_Left && qobject_cast<QMenu*>(d->causedPopup.widget)) {
2681 QPointer<QWidget> caused = d->causedPopup.widget;
2685 key_consumed = true;
2693 key_consumed = true;
2694 if (style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this))
2697 #ifndef QT_NO_MENUBAR
2698 if (QMenuBar *mb = qobject_cast<QMenuBar*>(QApplication::focusWidget())) {
2699 mb->d_func()->setKeyboardMode(false);
2705 case Qt::Key_Escape:
2706 #ifdef QT_KEYPAD_NAVIGATION
2709 key_consumed = true;
2715 QPointer<QWidget> caused = d->causedPopup.widget;
2716 d->hideMenu(this); // hide after getting causedPopup
2717 #ifndef QT_NO_MENUBAR
2718 if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
2719 mb->d_func()->setCurrentAction(d->menuAction);
2720 mb->d_func()->setKeyboardMode(true);
2727 if (!style()->styleHint(QStyle::SH_Menu_SpaceActivatesItem, 0, this))
2729 // for motif, fall through
2730 #ifdef QT_KEYPAD_NAVIGATION
2731 case Qt::Key_Select:
2733 case Qt::Key_Return:
2734 case Qt::Key_Enter: {
2735 if (!d->currentAction) {
2736 d->setFirstActionActive();
2737 key_consumed = true;
2743 if (d->currentAction->menu())
2744 d->popupAction(d->currentAction, 0, true);
2746 d->activateAction(d->currentAction, QAction::Trigger);
2747 key_consumed = true;
2750 #ifndef QT_NO_WHATSTHIS
2752 if (!d->currentAction || d->currentAction->whatsThis().isNull())
2754 QWhatsThis::enterWhatsThisMode();
2755 d->activateAction(d->currentAction, QAction::Trigger);
2759 key_consumed = false;
2762 if (!key_consumed) { // send to menu bar
2763 if ((!e->modifiers() || e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ShiftModifier) &&
2764 e->text().length()==1) {
2765 bool activateAction = false;
2766 QAction *nextAction = 0;
2767 if (style()->styleHint(QStyle::SH_Menu_KeyboardSearch, 0, this) && !e->modifiers()) {
2768 int best_match_count = 0;
2769 d->searchBufferTimer.start(2000, this);
2770 d->searchBuffer += e->text();
2771 for(int i = 0; i < d->actions.size(); ++i) {
2772 int match_count = 0;
2773 if (d->actionRects.at(i).isNull())
2775 QAction *act = d->actions.at(i);
2776 const QString act_text = act->text();
2777 for(int c = 0; c < d->searchBuffer.size(); ++c) {
2778 if(act_text.indexOf(d->searchBuffer.at(c), 0, Qt::CaseInsensitive) != -1)
2781 if(match_count > best_match_count) {
2782 best_match_count = match_count;
2787 #ifndef QT_NO_SHORTCUT
2790 QAction *first = 0, *currentSelected = 0, *firstAfterCurrent = 0;
2791 QChar c = e->text().at(0).toUpper();
2792 for(int i = 0; i < d->actions.size(); ++i) {
2793 if (d->actionRects.at(i).isNull())
2795 QAction *act = d->actions.at(i);
2796 QKeySequence sequence = QKeySequence::mnemonic(act->text());
2797 int key = sequence[0] & 0xffff;
2798 if (key == c.unicode()) {
2802 if (act == d->currentAction)
2803 currentSelected = act;
2804 else if (!firstAfterCurrent && currentSelected)
2805 firstAfterCurrent = act;
2808 if (clashCount == 1)
2809 activateAction = true;
2810 if (clashCount >= 1) {
2811 if (clashCount == 1 || !currentSelected || !firstAfterCurrent)
2814 nextAction = firstAfterCurrent;
2819 key_consumed = true;
2821 d->scrollMenu(nextAction, QMenuPrivate::QMenuScroller::ScrollCenter, false);
2822 d->setCurrentAction(nextAction, 0, QMenuPrivate::SelectedFromElsewhere, true);
2823 if (!nextAction->menu() && activateAction) {
2825 d->activateAction(nextAction, QAction::Trigger);
2829 if (!key_consumed) {
2830 #ifndef QT_NO_MENUBAR
2831 if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->topCausedWidget())) {
2832 QAction *oldAct = mb->d_func()->currentAction;
2833 QApplication::sendEvent(mb, e);
2834 if (mb->d_func()->currentAction != oldAct)
2835 key_consumed = true;
2841 if (key_consumed && (e->key() == Qt::Key_Control || e->key() == Qt::Key_Shift || e->key() == Qt::Key_Meta))
2842 QApplication::beep();
2843 #endif // Q_OS_WIN32
2854 void QMenu::mouseMoveEvent(QMouseEvent *e)
2857 if (!isVisible() || d->aboutToHide || d->mouseEventTaken(e))
2860 if (d->motions == 0) // ignore first mouse move event (see enterEvent())
2862 d->hasHadMouse = d->hasHadMouse || rect().contains(e->pos());
2864 QAction *action = d->actionAt(e->pos());
2865 if (!action || action->isSeparator()) {
2867 && (!d->currentAction || (action && action->isSeparator())
2868 || !(d->currentAction->menu() && d->currentAction->menu()->isVisible())))
2869 d->setCurrentAction(0);
2871 } else if(e->buttons()) {
2872 d->mouseDown = this;
2874 if (d->sloppyRegion.contains(e->pos())) {
2875 d->sloppyAction = action;
2876 d->sloppyDelayTimer = startTimer(style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this)*6);
2877 } else if (action != d->currentAction) {
2878 d->setCurrentAction(action, style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this));
2885 void QMenu::enterEvent(QEvent *)
2887 d_func()->motions = -1; // force us to ignore the generate mouse move in mouseMoveEvent()
2893 void QMenu::leaveEvent(QEvent *)
2896 d->sloppyAction = 0;
2897 if (!d->sloppyRegion.isEmpty())
2898 d->sloppyRegion = QRegion();
2899 if (!d->activeMenu && d->currentAction)
2907 QMenu::timerEvent(QTimerEvent *e)
2910 if (d->scroll && d->scroll->scrollTimer.timerId() == e->timerId()) {
2911 d->scrollMenu((QMenuPrivate::QMenuScroller::ScrollDirection)d->scroll->scrollDirection);
2912 if (d->scroll->scrollFlags == QMenuPrivate::QMenuScroller::ScrollNone)
2913 d->scroll->scrollTimer.stop();
2914 } else if(d->menuDelayTimer.timerId() == e->timerId()) {
2915 d->menuDelayTimer.stop();
2916 internalDelayedPopup();
2917 } else if (d->sloppyDelayTimer == e->timerId()) {
2918 killTimer(d->sloppyDelayTimer);
2919 d->sloppyDelayTimer = 0;
2920 internalSetSloppyAction();
2921 } else if(d->searchBufferTimer.timerId() == e->timerId()) {
2922 d->searchBuffer.clear();
2929 void QMenu::actionEvent(QActionEvent *e)
2933 setAttribute(Qt::WA_Resized, false);
2935 d->tornPopup->syncWithMenu(this, e);
2936 if (e->type() == QEvent::ActionAdded) {
2938 connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
2939 connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered()));
2941 if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
2942 QWidget *widget = wa->requestWidget(this);
2944 d->widgetItems.insert(wa, widget);
2946 } else if (e->type() == QEvent::ActionRemoved) {
2947 e->action()->disconnect(this);
2948 if (e->action() == d->currentAction)
2949 d->currentAction = 0;
2950 if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
2951 if (QWidget *widget = d->widgetItems.value(wa))
2952 wa->releaseWidget(widget);
2954 d->widgetItems.remove(e->action());
2959 if (e->type() == QEvent::ActionAdded)
2960 d->mac_menu->addAction(e->action(), d->mac_menu->findAction(e->before()), d);
2961 else if (e->type() == QEvent::ActionRemoved)
2962 d->mac_menu->removeAction(e->action());
2963 else if (e->type() == QEvent::ActionChanged)
2964 d->mac_menu->syncAction(e->action());
2968 #if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR)
2970 d->wce_menu = new QMenuPrivate::QWceMenuPrivate;
2971 if (e->type() == QEvent::ActionAdded)
2972 d->wce_menu->addAction(e->action(), d->wce_menu->findAction(e->before()));
2973 else if (e->type() == QEvent::ActionRemoved)
2974 d->wce_menu->removeAction(e->action());
2975 else if (e->type() == QEvent::ActionChanged)
2976 d->wce_menu->syncAction(e->action());
2980 if (!d->symbian_menu)
2981 d->symbian_menu = new QMenuPrivate::QSymbianMenuPrivate;
2982 if (e->type() == QEvent::ActionAdded)
2983 d->symbian_menu->addAction(e->action(), d->symbian_menu->findAction(e->before()));
2984 else if (e->type() == QEvent::ActionRemoved)
2985 d->symbian_menu->removeAction(e->action());
2986 else if (e->type() == QEvent::ActionChanged)
2987 d->symbian_menu->syncAction(e->action());
2990 d->updateActionRects();
2999 void QMenu::internalSetSloppyAction()
3001 if (d_func()->sloppyAction)
3002 d_func()->setCurrentAction(d_func()->sloppyAction, 0);
3008 void QMenu::internalDelayedPopup()
3012 //hide the current item
3013 if (QMenu *menu = d->activeMenu) {
3018 if (!d->currentAction || !d->currentAction->isEnabled() || !d->currentAction->menu() ||
3019 !d->currentAction->menu()->isEnabled() || d->currentAction->menu()->isVisible())
3023 d->activeMenu = d->currentAction->menu();
3024 d->activeMenu->d_func()->causedPopup.widget = this;
3025 d->activeMenu->d_func()->causedPopup.action = d->currentAction;
3027 int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this);
3028 const QRect actionRect(d->actionRect(d->currentAction));
3029 const QSize menuSize(d->activeMenu->sizeHint());
3030 const QPoint rightPos(mapToGlobal(QPoint(actionRect.right() + subMenuOffset + 1, actionRect.top())));
3032 QPoint pos(rightPos);
3034 //calc sloppy focus buffer
3035 if (style()->styleHint(QStyle::SH_Menu_SloppySubMenus, 0, this)) {
3036 QPoint cur = QCursor::pos();
3037 if (actionRect.contains(mapFromGlobal(cur))) {
3039 pts[0] = QPoint(cur.x(), cur.y() - 2);
3040 pts[3] = QPoint(cur.x(), cur.y() + 2);
3041 if (pos.x() >= cur.x()) {
3042 pts[1] = QPoint(geometry().right(), pos.y());
3043 pts[2] = QPoint(geometry().right(), pos.y() + menuSize.height());
3045 pts[1] = QPoint(pos.x() + menuSize.width(), pos.y());
3046 pts[2] = QPoint(pos.x() + menuSize.width(), pos.y() + menuSize.height());
3049 for(int i = 0; i < 4; i++)
3050 points.setPoint(i, mapFromGlobal(pts[i]));
3051 d->sloppyRegion = QRegion(points);
3056 d->activeMenu->popup(pos);
3060 \fn void QMenu::addAction(QAction *action)
3063 Appends the action \a action to the menu's list of actions.
3065 \sa QMenuBar::addAction(), QWidget::addAction()
3069 \fn void QMenu::aboutToHide()
3072 This signal is emitted just before the menu is hidden from the user.
3074 \sa aboutToShow(), hide()
3078 \fn void QMenu::aboutToShow()
3080 This signal is emitted just before the menu is shown to the user.
3082 \sa aboutToHide(), show()
3086 \fn void QMenu::triggered(QAction *action)
3088 This signal is emitted when an action in this menu is triggered.
3090 \a action is the action that caused the signal to be emitted.
3092 Normally, you connect each menu action's \l{QAction::}{triggered()} signal
3093 to its own custom slot, but sometimes you will want to connect several
3094 actions to a single slot, for example, when you have a group of closely
3095 related actions, such as "left justify", "center", "right justify".
3097 \note This signal is emitted for the main parent menu in a hierarchy.
3098 Hence, only the parent menu needs to be connected to a slot; sub-menus need
3101 \sa hovered(), QAction::triggered()
3105 \fn void QMenu::hovered(QAction *action)
3107 This signal is emitted when a menu action is highlighted; \a action
3108 is the action that caused the signal to be emitted.
3110 Often this is used to update status information.
3112 \sa triggered(), QAction::hovered()
3118 void QMenu::setNoReplayFor(QWidget *noReplayFor)
3121 d_func()->noReplayFor = noReplayFor;
3123 Q_UNUSED(noReplayFor);
3128 \property QMenu::separatorsCollapsible
3131 \brief whether consecutive separators should be collapsed
3133 This property specifies whether consecutive separators in the menu
3134 should be visually collapsed to a single one. Separators at the
3135 beginning or the end of the menu are also hidden.
3137 By default, this property is true.
3139 bool QMenu::separatorsCollapsible() const
3142 return d->collapsibleSeparators;
3145 void QMenu::setSeparatorsCollapsible(bool collapse)
3148 if (d->collapsibleSeparators == collapse)
3151 d->collapsibleSeparators = collapse;
3154 d->updateActionRects();
3159 d->syncSeparatorsCollapsible(collapse);
3165 int QMenu::insertAny(const QIcon *icon, const QString *text, const QObject *receiver, const char *member,
3166 const QKeySequence *shortcut, const QMenu *popup, int id, int index)
3168 QAction *act = popup ? popup->menuAction() : new QAction(this);
3170 static_cast<QMenuItem*>(act)->setId(id);
3172 act->setIcon(*icon);
3174 act->setText(*text);
3176 act->setShortcut(*shortcut);
3177 if (receiver && member)
3178 QObject::connect(act, SIGNAL(activated(int)), receiver, member);
3179 if (index == -1 || index >= actions().count())
3182 insertAction(actions().value(index), act);
3183 return findIdForAction(act);
3187 Use insertAction() or one of the addAction() overloads instead.
3189 int QMenu::insertItem(QMenuItem *item, int id, int index)
3191 if (index == -1 || index >= actions().count())
3194 insertAction(actions().value(index), item);
3196 item->d_func()->id = id;
3197 return findIdForAction(item);
3201 Use the insertSeparator() overload that takes a QAction *
3204 int QMenu::insertSeparator(int index)
3206 QAction *act = new QAction(this);
3207 act->setSeparator(true);
3208 if (index == -1 || index >= actions().count())
3211 insertAction(actions().value(index), act);
3212 return findIdForAction(act);
3215 QAction *QMenu::findActionForId(int id) const
3218 for (int i = 0; i < d->actions.size(); ++i) {
3219 QAction *act = d->actions.at(i);
3220 if (findIdForAction(act)== id)
3227 Use QAction and actions() instead.
3229 QMenuItem *QMenu::findPopup( QMenu *popup, int *index )
3231 QList<QAction *> list = actions();
3232 for (int i = 0; i < list.size(); ++i) {
3233 QAction *act = list.at(i);
3234 if (act->menu() == popup) {
3235 QMenuItem *item = static_cast<QMenuItem *>(act);
3237 *index = act->d_func()->id;
3246 Use QAction::setData() instead.
3248 bool QMenu::setItemParameter(int id, int param)
3250 if (QAction *act = findActionForId(id)) {
3251 act->d_func()->param = param;
3258 Use QAction::data() instead.
3260 int QMenu::itemParameter(int id) const
3262 if (QAction *act = findActionForId(id))
3263 return act->d_func()->param;
3268 Use actions instead.
3270 void QMenu::setId(int index, int id)
3272 if(QAction *act = actions().value(index))
3273 act->d_func()->id = id;
3277 Use style()->pixelMetric(QStyle::PM_MenuPanelWidth, this) instead.
3279 int QMenu::frameWidth() const
3281 return style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this);
3284 int QMenu::findIdForAction(QAction *act) const
3288 return act->d_func()->id;
3290 #endif // QT3_SUPPORT
3293 \fn uint QMenu::count() const
3295 Use actions().count() instead.
3299 \fn int QMenu::insertItem(const QString &text, const QObject *receiver, const char* member, const QKeySequence& shortcut, int id, int index)
3301 Use insertAction() or one of the addAction() overloads instead.
3305 \fn int QMenu::insertItem(const QIcon& icon, const QString &text, const QObject *receiver, const char* member, const QKeySequence& shortcut, int id, int index)
3307 Use insertAction() or one of the addAction() overloads instead.
3311 \fn int QMenu::insertItem(const QPixmap &pixmap, const QObject *receiver, const char* member, const QKeySequence& shortcut, int id, int index)
3313 Use insertAction() or one of the addAction() overloads instead.
3317 \fn int QMenu::insertItem(const QString &text, int id, int index)
3319 Use insertAction() or one of the addAction() overloads instead.
3323 \fn int QMenu::insertItem(const QIcon& icon, const QString &text, int id, int index)
3325 Use insertAction() or one of the addAction() overloads instead.
3329 \fn int QMenu::insertItem(const QString &text, QMenu *popup, int id, int index)
3331 Use insertMenu() or one of the addMenu() overloads instead.
3335 \fn int QMenu::insertItem(const QIcon& icon, const QString &text, QMenu *popup, int id, int index)
3337 Use insertMenu() or one of the addMenu() overloads instead.
3341 \fn int QMenu::insertItem(const QPixmap &pixmap, int id, int index)
3343 Use insertAction() or one of the addAction() overloads instead.
3347 \fn int QMenu::insertItem(const QPixmap &pixmap, QMenu *popup, int id, int index)
3349 Use insertMenu() or one of the addMenu() overloads instead.
3353 \fn void QMenu::removeItem(int id)
3355 Use removeAction() instead.
3359 \fn void QMenu::removeItemAt(int index)
3361 Use removeAction() instead.
3365 \fn QKeySequence QMenu::accel(int id) const
3367 Use shortcut() on the relevant QAction instead.
3371 \fn void QMenu::setAccel(const QKeySequence& key, int id)
3373 Use setShortcut() on the relevant QAction instead.
3377 \fn QIcon QMenu::iconSet(int id) const
3379 Use icon() on the relevant QAction instead.
3383 \fn QString QMenu::text(int id) const
3385 Use text() on the relevant QAction instead.
3389 \fn QPixmap QMenu::pixmap(int id) const
3391 Use QPixmap(icon()) on the relevant QAction instead.
3395 \fn void QMenu::setWhatsThis(int id, const QString &w)
3397 Use setWhatsThis() on the relevant QAction instead.
3401 \fn QString QMenu::whatsThis(int id) const
3403 Use whatsThis() on the relevant QAction instead.
3407 \fn void QMenu::changeItem(int id, const QString &text)
3409 Use setText() on the relevant QAction instead.
3413 \fn void QMenu::changeItem(int id, const QPixmap &pixmap)
3415 Use setText() on the relevant QAction instead.
3419 \fn void QMenu::changeItem(int id, const QIcon &icon, const QString &text)
3421 Use setIcon() and setText() on the relevant QAction instead.
3425 \fn bool QMenu::isItemActive(int id) const
3427 Use activeAction() instead.
3431 \fn bool QMenu::isItemEnabled(int id) const
3433 Use isEnabled() on the relevant QAction instead.
3437 \fn void QMenu::setItemEnabled(int id, bool enable)
3439 Use setEnabled() on the relevant QAction instead.
3443 \fn bool QMenu::isItemChecked(int id) const
3445 Use isChecked() on the relevant QAction instead.
3449 \fn void QMenu::setItemChecked(int id, bool check)
3451 Use setChecked() on the relevant QAction instead.
3455 \fn bool QMenu::isItemVisible(int id) const
3457 Use isVisible() on the relevant QAction instead.
3461 \fn void QMenu::setItemVisible(int id, bool visible)
3463 Use setVisible() on the relevant QAction instead.
3467 \fn QRect QMenu::itemGeometry(int index)
3469 Use actionGeometry() on the relevant QAction instead.
3473 \fn QFont QMenu::itemFont(int id) const
3475 Use font() on the relevant QAction instead.
3479 \fn void QMenu::setItemFont(int id, const QFont &font)
3481 Use setFont() on the relevant QAction instead.
3485 \fn int QMenu::indexOf(int id) const
3487 Use actions().indexOf(action) on the relevant QAction instead.
3491 \fn int QMenu::idAt(int index) const
3493 Use actions instead.
3497 \fn void QMenu::activateItemAt(int index)
3499 Use activate() on the relevant QAction instead.
3503 \fn bool QMenu::connectItem(int id, const QObject *receiver, const char* member)
3505 Use connect() on the relevant QAction instead.
3509 \fn bool QMenu::disconnectItem(int id,const QObject *receiver, const char* member)
3510 Use disconnect() on the relevant QAction instead.
3515 \fn QMenuItem *QMenu::findItem(int id) const
3517 Use actions instead.
3521 \fn void QMenu::popup(const QPoint & pos, int indexAtPoint)
3523 Use popup() on the relevant QAction instead.
3527 \fn int QMenu::insertTearOffHandle(int a, int b)
3529 Use setTearOffEnabled() instead.
3533 \fn int QMenu::itemAtPos(const QPoint &p, bool ignoreSeparator)
3535 Use actions instead.
3539 \fn int QMenu::columns() const
3541 Use columnCount() instead.
3545 \fn int QMenu::itemHeight(int index)
3547 Use actionGeometry(actions().value(index)).height() instead.
3551 \fn int QMenu::itemHeight(QMenuItem *mi)
3553 Use actionGeometry() instead.
3557 \fn void QMenu::activated(int itemId);
3559 Use triggered() instead.
3563 \fn void QMenu::highlighted(int itemId);
3565 Use hovered() instead.
3569 \fn void QMenu::setCheckable(bool checkable)
3571 Not necessary anymore. The \a checkable parameter is ignored.
3575 \fn bool QMenu::isCheckable() const
3577 Not necessary anymore. Always returns true.
3581 \fn void QMenu::setActiveItem(int id)
3583 Use setActiveAction() instead.
3588 // for private slots
3589 #include "moc_qmenu.cpp"
3590 #include "qmenu.moc"
3592 #endif // QT_NO_MENU