summaryrefslogtreecommitdiffstats
path: root/src/gui/widgets/qmenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/widgets/qmenu.cpp')
-rw-r--r--src/gui/widgets/qmenu.cpp664
1 files changed, 349 insertions, 315 deletions
diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp
index 5acf134..ee1ec6f 100644
--- a/src/gui/widgets/qmenu.cpp
+++ b/src/gui/widgets/qmenu.cpp
@@ -1,7 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -21,9 +20,10 @@
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
@@ -60,6 +60,7 @@
#ifndef QT_NO_WHATSTHIS
# include <qwhatsthis.h>
#endif
+#include <private/qactiontokeyeventmapper_p.h>
#include "qmenu_p.h"
#include "qmenubar_p.h"
@@ -150,7 +151,6 @@ private:
void QMenuPrivate::init()
{
Q_Q(QMenu);
- activationRecursionGuard = false;
#ifndef QT_NO_WHATSTHIS
q->setAttribute(Qt::WA_CustomWhatsThis);
#endif
@@ -164,6 +164,12 @@ void QMenuPrivate::init()
}
}
+int QMenuPrivate::scrollerHeight() const
+{
+ Q_Q(const QMenu);
+ return qMax(QApplication::globalStrut().height(), q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q));
+}
+
//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
QRect QMenuPrivate::popupGeometry(int screen) const
{
@@ -194,57 +200,85 @@ QList<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const
return ret;
}
-void QMenuPrivate::calcActionRects(QMap<QAction*, QRect> &actionRects, QList<QAction*> &actionList) const
+void QMenuPrivate::updateActionRects() const
{
Q_Q(const QMenu);
- if (!itemsDirty) {
- actionRects = this->actionRects;
- actionList = this->actionList;
+ if (!itemsDirty)
return;
+
+ q->ensurePolished();
+
+ //let's reinitialize the buffer
+ actionRects.resize(actions.count());
+ actionRects.fill(QRect());
+
+ //let's try to get the last visible action
+ int lastVisibleAction = actions.count() - 1;
+ for(;lastVisibleAction >= 0; --lastVisibleAction) {
+ const QAction *action = actions.at(lastVisibleAction);
+ if (action->isVisible()) {
+ //removing trailing separators
+ if (action->isSeparator() && collapsibleSeparators)
+ continue;
+ break;
+ }
}
- actionRects.clear();
- actionList.clear();
- QList<QAction*> items = filterActions(q->actions());
int max_column_width = 0,
dh = popupGeometry(QApplication::desktop()->screenNumber(q)).height(),
- ncols = 1,
y = 0;
- const int hmargin = q->style()->pixelMetric(QStyle::PM_MenuHMargin, 0, q),
- vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q),
- icone = q->style()->pixelMetric(QStyle::PM_SmallIconSize, 0, q);
+ QStyle *style = q->style();
+ QStyleOption opt;
+ opt.init(q);
+ const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q),
+ vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q),
+ icone = style->pixelMetric(QStyle::PM_SmallIconSize, &opt, q);
+ const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, q);
+ const int deskFw = style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, &opt, q);
+
+ const int sfcMargin = style->sizeFromContents(QStyle::CT_Menu, &opt, QApplication::globalStrut(), q).width() - QApplication::globalStrut().width();
+ const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin));
+ const int tearoffHeight = tearoff ? style->pixelMetric(QStyle::PM_MenuTearoffHeight, &opt, q) : 0;
//for compatability now - will have to refactor this away..
tabWidth = 0;
maxIconWidth = 0;
hasCheckableItems = false;
- for(int i = 0; i < items.count(); i++) {
- QAction *action = items.at(i);
- if (widgetItems.value(action))
+ ncols = 1;
+ sloppyAction = 0;
+
+ for (int i = 0; i < actions.count(); ++i) {
+ QAction *action = actions.at(i);
+ if (action->isSeparator() || !action->isVisible() || widgetItems.at(i))
continue;
+ //..and some members
hasCheckableItems |= action->isCheckable();
QIcon is = action->icon();
if (!is.isNull()) {
- uint miw = maxIconWidth;
- maxIconWidth = qMax<uint>(miw, icone + 4);
+ maxIconWidth = qMax<uint>(maxIconWidth, icone + 4);
}
}
//calculate size
QFontMetrics qfm = q->fontMetrics();
- for(int i = 0; i < items.count(); i++) {
- QAction *action = items.at(i);
+ bool previousWasSeparator = true; // this is true to allow removing the leading separators
+ for(int i = 0; i <= lastVisibleAction; i++) {
+ QAction *action = actions.at(i);
- QFontMetrics fm(action->font().resolve(q->font()));
- QSize sz;
+ if (!action->isVisible() ||
+ (collapsibleSeparators && previousWasSeparator && action->isSeparator()))
+ continue; // we continue, this action will get an empty QRect
+
+ previousWasSeparator = action->isSeparator();
//let the style modify the above size..
QStyleOptionMenuItem opt;
q->initStyleOption(&opt, action);
- opt.rect = q->rect();
+ const QFontMetrics &fm = opt.fontMetrics;
- if (QWidget *w = widgetItems.value(action)) {
- sz=w->sizeHint().expandedTo(w->minimumSize()).expandedTo(w->minimumSizeHint()).boundedTo(w->maximumSize());
+ QSize sz;
+ if (QWidget *w = widgetItems.at(i)) {
+ sz = w->sizeHint().expandedTo(w->minimumSize()).expandedTo(w->minimumSizeHint()).boundedTo(w->maximumSize());
} else {
//calc what I think the size is..
if (action->isSeparator()) {
@@ -262,10 +296,7 @@ void QMenuPrivate::calcActionRects(QMap<QAction*, QRect> &actionRects, QList<QAc
tabWidth = qMax(int(tabWidth), qfm.width(seq));
#endif
}
- int w = fm.boundingRect(QRect(), Qt::TextSingleLine, s).width();
- w -= s.count(QLatin1Char('&')) * fm.width(QLatin1Char('&'));
- w += s.count(QLatin1String("&&")) * fm.width(QLatin1Char('&'));
- sz.setWidth(w);
+ sz.setWidth(fm.boundingRect(QRect(), Qt::TextSingleLine | Qt::TextShowMnemonic, s).width());
sz.setHeight(qMax(fm.height(), qfm.height()));
QIcon is = action->icon();
@@ -275,132 +306,76 @@ void QMenuPrivate::calcActionRects(QMap<QAction*, QRect> &actionRects, QList<QAc
sz.setHeight(is_sz.height());
}
}
- sz = q->style()->sizeFromContents(QStyle::CT_MenuItem, &opt, sz, q);
+ sz = style->sizeFromContents(QStyle::CT_MenuItem, &opt, sz, q);
}
if (!sz.isEmpty()) {
- max_column_width = qMax(max_column_width, sz.width());
+ max_column_width = qMax(min_column_width, qMax(max_column_width, sz.width()));
//wrapping
if (!scroll &&
- y+sz.height()+vmargin > dh - (q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q) * 2)) {
+ y+sz.height()+vmargin > dh - (deskFw * 2)) {
ncols++;
y = vmargin;
}
y += sz.height();
- //append item
- actionRects.insert(action, QRect(0, 0, sz.width(), sz.height()));
- actionList.append(action);
+ //update the item
+ actionRects[i] = QRect(0, 0, sz.width(), sz.height());
}
}
- if (tabWidth)
- max_column_width += tabWidth; //finally add in the tab width
+ max_column_width += tabWidth; //finally add in the tab width
//calculate position
- int x = hmargin;
- y = vmargin;
-
- for(int i = 0; i < actionList.count(); i++) {
- QAction *action = actionList.at(i);
- QRect &rect = actionRects[action];
+ const int base_y = vmargin + fw + topmargin +
+ (scroll ? scroll->scrollOffset : 0) +
+ tearoffHeight;
+ int x = hmargin + fw + leftmargin;
+ y = base_y;
+
+ for(int i = 0; i < actions.count(); i++) {
+ QRect &rect = actionRects[i];
if (rect.isNull())
continue;
if (!scroll &&
- y+rect.height() > dh - (q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q) * 2)) {
- ncols--;
- if (ncols < 0)
- qWarning("QMenu: Column calculation mismatch (%d)", ncols);
+ y+rect.height() > dh - deskFw * 2) {
x += max_column_width + hmargin;
- y = vmargin;
+ y = base_y;
}
rect.translate(x, y); //move
rect.setWidth(max_column_width); //uniform width
- y += rect.height();
- }
-}
-void QMenuPrivate::updateActions()
-{
- Q_Q(const QMenu);
- if (!itemsDirty)
- return;
- sloppyAction = 0;
- calcActionRects(actionRects, actionList);
- for (QHash<QAction *, QWidget *>::ConstIterator item = widgetItems.constBegin(),
- end = widgetItems.constEnd(); item != end; ++item) {
- QAction *action = item.key();
- QWidget *widget = item.value();
- widget->setGeometry(actionRect(action));
- widget->setVisible(action->isVisible());
- }
- ncols = 1;
- int last_left = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q);
- if (!scroll) {
- for(int i = 0; i < actionList.count(); i++) {
- int left = actionRects.value(actionList.at(i)).left();
- if (left > last_left) {
- last_left = left;
- ncols++;
- }
+ //we need to update the widgets geometry
+ if (QWidget *widget = widgetItems.at(i)) {
+ widget->setGeometry(rect);
+ widget->setVisible(actions.at(i)->isVisible());
}
+
+ y += rect.height();
}
itemsDirty = 0;
}
-QList<QAction *> QMenuPrivate::filterActions(const QList<QAction *> &actions) const
+QRect QMenuPrivate::actionRect(QAction *act) const
{
- QList<QAction *> visibleActions;
- int i = 0;
- while (i < actions.count()) {
- QAction *action = actions.at(i);
- if (!action->isVisible()) {
- ++i;
- continue;
- }
- if (!action->isSeparator() || !collapsibleSeparators) {
- visibleActions.append(action);
- ++i;
- continue;
- }
+ int index = actions.indexOf(act);
+ if (index == -1)
+ return QRect();
- // no leading separators
- if (!visibleActions.isEmpty())
- visibleActions.append(action);
-
- // skip double/tripple/etc. separators
- while (i < actions.count()
- && (!actions.at(i)->isVisible() || actions.at(i)->isSeparator()))
- ++i;
- }
+ updateActionRects();
- if (collapsibleSeparators) {
- // remove trailing separators
- while (!visibleActions.isEmpty() && visibleActions.last()->isSeparator())
- visibleActions.removeLast();
- }
-
- return visibleActions;
+ //we found the action
+ return actionRects.at(index);
}
-QRect QMenuPrivate::actionRect(QAction *act) const
-{
- Q_Q(const QMenu);
- QRect ret = actionRects.value(act);
- if (ret.isNull())
- return ret;
- if (scroll)
- ret.translate(0, scroll->scrollOffset);
- if (tearoff)
- ret.translate(0, q->style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, q));
- const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
- ret.translate(fw+leftmargin, fw+topmargin);
- return ret;
-}
+#if defined(Q_WS_MAC)
+static const qreal MenuFadeTimeInSec = 0.150;
+#endif
void QMenuPrivate::hideUpToMenuBar()
{
Q_Q(QMenu);
+ bool fadeMenus = q->style()->styleHint(QStyle::SH_Menu_FadeOutOnHide);
if (!tornoff) {
QWidget *caused = causedPopup.widget;
hideMenu(q); //hide after getting causedPopup
@@ -415,8 +390,9 @@ void QMenuPrivate::hideUpToMenuBar()
if (QMenu *m = qobject_cast<QMenu*>(caused)) {
caused = m->d_func()->causedPopup.widget;
if (!m->d_func()->tornoff)
- hideMenu(m);
- m->d_func()->setCurrentAction(0);
+ hideMenu(m, fadeMenus);
+ if (!fadeMenus) // Mac doesn't clear the action until after hidden.
+ m->d_func()->setCurrentAction(0);
} else {
#ifndef QT_NO_TOOLBUTTON
if (qobject_cast<QToolButton*>(caused) == 0)
@@ -425,26 +401,32 @@ void QMenuPrivate::hideUpToMenuBar()
caused = 0;
}
}
+#if defined(Q_WS_MAC)
+ if (fadeMenus) {
+ QEventLoop eventLoop;
+ QTimer::singleShot(int(MenuFadeTimeInSec * 1000), &eventLoop, SLOT(quit()));
+ QMacWindowFader::currentFader()->performFade();
+ eventLoop.exec();
+ }
+#endif
}
setCurrentAction(0);
}
-void QMenuPrivate::hideMenu(QMenu *menu)
+void QMenuPrivate::hideMenu(QMenu *menu, bool justRegister)
{
if (!menu)
return;
-
#if !defined(QT_NO_EFFECTS)
menu->blockSignals(true);
aboutToHide = true;
// Flash item which is about to trigger (if any).
if (menu->style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)
- && currentAction && currentAction == actionAboutToTrigger) {
-
+ && currentAction && currentAction == actionAboutToTrigger
+ && menu->actions().contains(currentAction)) {
QEventLoop eventLoop;
QAction *activeAction = currentAction;
- // Deselect and wait 60 ms.
menu->setActiveAction(0);
QTimer::singleShot(60, &eventLoop, SLOT(quit()));
eventLoop.exec();
@@ -458,22 +440,24 @@ void QMenuPrivate::hideMenu(QMenu *menu)
// Fade out.
if (menu->style()->styleHint(QStyle::SH_Menu_FadeOutOnHide)) {
// ### Qt 4.4:
- // Should be something like: q->transitionWindow(Qt::FadeOutTransition, 150);
+ // Should be something like: q->transitionWindow(Qt::FadeOutTransition, MenuFadeTimeInSec);
// Hopefully we'll integrate qt/research/windowtransitions into main before 4.4.
// Talk to Richard, Trenton or Bjoern.
#if defined(Q_WS_MAC)
- macWindowFade(qt_mac_window_for(menu)); // FIXME - what is the default duration for view animations
+ if (justRegister) {
+ QMacWindowFader::currentFader()->setFadeDuration(MenuFadeTimeInSec);
+ QMacWindowFader::currentFader()->registerWindowToFade(menu);
+ } else {
+ macWindowFade(qt_mac_window_for(menu), MenuFadeTimeInSec);
+ }
- // Wait for the transition to complete.
- QEventLoop eventLoop;
- QTimer::singleShot(150, &eventLoop, SLOT(quit()));
- eventLoop.exec();
#endif // Q_WS_MAC
}
aboutToHide = false;
menu->blockSignals(false);
#endif // QT_NO_EFFECTS
- menu->hide();
+ if (!justRegister)
+ menu->hide();
}
void QMenuPrivate::popupAction(QAction *action, int delay, bool activateFirst)
@@ -513,14 +497,17 @@ void QMenuPrivate::setSyncAction()
void QMenuPrivate::setFirstActionActive()
{
Q_Q(QMenu);
- const int scrollerHeight = q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q);
- for(int i = 0, saccum = 0; i < actionList.count(); i++) {
- QAction *act = actionList[i];
+ updateActionRects();
+ for(int i = 0, saccum = 0; i < actions.count(); i++) {
+ const QRect &rect = actionRects.at(i);
+ if (rect.isNull())
+ continue;
if (scroll && scroll->scrollFlags & QMenuScroller::ScrollUp) {
- saccum -= actionRects.value(act).height();
- if (saccum > scroll->scrollOffset-scrollerHeight)
+ saccum -= rect.height();
+ if (saccum > scroll->scrollOffset - scrollerHeight())
continue;
}
+ QAction *act = actions.at(i);
if (!act->isSeparator() &&
(q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
|| act->isEnabled())) {
@@ -535,10 +522,12 @@ void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason
{
Q_Q(QMenu);
tearoffHighlighted = 0;
- if (action == currentAction && !(action && action->menu() && action->menu() != activeMenu)) {
- if(QMenu *menu = qobject_cast<QMenu*>(causedPopup.widget)) {
- if(causedPopup.action && menu->d_func()->activeMenu == q)
- menu->d_func()->setCurrentAction(causedPopup.action, 0, reason, false);
+ if (action == currentAction) {
+ if (!action || !action->menu() || action->menu() == activeMenu) {
+ if(QMenu *menu = qobject_cast<QMenu*>(causedPopup.widget)) {
+ if(causedPopup.action && menu->d_func()->activeMenu == q)
+ menu->d_func()->setCurrentAction(causedPopup.action, 0, reason, false);
+ }
}
return;
}
@@ -553,7 +542,7 @@ void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason
QAction *previousAction = currentAction;
#endif
#ifdef QT3_SUPPORT
- emitHighlighted = (action && action != currentAction);
+ emitHighlighted = action;
#endif
currentAction = action;
if (action) {
@@ -568,9 +557,10 @@ void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason
popupAction(currentAction, popup, activateFirst);
}
q->update(actionRect(action));
- QWidget *widget = widgetItems.value(action);
if (reason == SelectedFromKeyboard) {
+ const int actionIndex = actions.indexOf(action);
+ QWidget *widget = widgetItems.at(actionIndex);
if (widget) {
if (widget->focusPolicy() != Qt::NoFocus)
widget->setFocus(Qt::TabFocusReason);
@@ -578,8 +568,14 @@ void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason
//when the action has no QWidget, the QMenu itself should
// get the focus
// Since the menu is a pop-up, it uses the popup reason.
- if (!q->hasFocus())
+ if (!q->hasFocus()) {
q->setFocus(Qt::PopupFocusReason);
+#ifdef QT_KEYPAD_NAVIGATION
+ // TODO: aportale, remove KEYPAD_NAVIGATION_HACK when softkey stack
+ // handles focus related and user related actions separately...
+ QActionToKeyEventMapper::addSoftKey(QAction::CancelSoftKey, Qt::Key_Back, q);
+#endif
+ }
}
}
} else { //action is a separator
@@ -614,10 +610,9 @@ QAction *QMenuPrivate::actionAt(QPoint p) const
if (!q_func()->rect().contains(p)) //sanity check
return 0;
- for(int i = 0; i < actionList.count(); i++) {
- QAction *act = actionList[i];
- if (actionRect(act).contains(p))
- return act;
+ for(int i = 0; i < actionRects.count(); i++) {
+ if (actionRects.at(i).contains(p))
+ return actions.at(i);
}
return 0;
}
@@ -691,27 +686,25 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc
Q_Q(QMenu);
if (!scroll || !scroll->scrollFlags)
return;
+ updateActionRects();
int newOffset = 0;
- const int scrollHeight = q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q);
- const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollHeight : 0;
- const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollHeight : 0;
+ const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollerHeight() : 0;
+ const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollerHeight() : 0;
const int vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q);
const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
if (location == QMenuScroller::ScrollTop) {
- for(int i = 0, saccum = 0; i < actionList.count(); i++) {
- QAction *act = actionList.at(i);
- if (act == action) {
+ for(int i = 0, saccum = 0; i < actions.count(); i++) {
+ if (actions.at(i) == action) {
newOffset = topScroll - saccum;
break;
}
- saccum += actionRects.value(act).height();
+ saccum += actionRects.at(i).height();
}
} else {
- for(int i = 0, saccum = 0; i < actionList.count(); i++) {
- QAction *act = actionList.at(i);
- saccum += actionRects.value(act).height();
- if (act == action) {
+ for(int i = 0, saccum = 0; i < actions.count(); i++) {
+ saccum += actionRects.at(i).height();
+ if (actions.at(i) == action) {
if (location == QMenuScroller::ScrollCenter)
newOffset = ((q->height() / 2) - botScroll) - (saccum - topScroll);
else
@@ -720,7 +713,7 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc
}
}
if(newOffset)
- newOffset -= fw*2;
+ newOffset -= fw * 2;
}
//figure out which scroll flags
@@ -728,8 +721,8 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc
if (newOffset < 0) //easy and cheap one
newScrollFlags |= QMenuScroller::ScrollUp;
int saccum = newOffset;
- for(int i = 0; i < actionList.count(); i++) {
- saccum += actionRects.value(actionList.at(i)).height();
+ for(int i = 0; i < actionRects.count(); i++) {
+ saccum += actionRects.at(i).height();
if (saccum > q->height()) {
newScrollFlags |= QMenuScroller::ScrollDown;
break;
@@ -780,9 +773,19 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc
}
//actually update flags
- scroll->scrollOffset = newOffset;
- if (scroll->scrollOffset > 0)
- scroll->scrollOffset = 0;
+ const int delta = qMin(0, newOffset) - scroll->scrollOffset; //make sure the new offset is always negative
+ if (!itemsDirty && delta) {
+ //we've scrolled so we need to update the action rects
+ for (int i = 0; i < actionRects.count(); ++i) {
+ QRect &current = actionRects[i];
+ current.moveTop(current.top() + delta);
+
+ //we need to update the widgets geometry
+ if (QWidget *w = widgetItems.at(i))
+ w->setGeometry(current);
+ }
+ }
+ scroll->scrollOffset += delta;
scroll->scrollFlags = newScrollFlags;
if (active)
setCurrentAction(action);
@@ -793,9 +796,12 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc
void QMenuPrivate::scrollMenu(QMenuScroller::ScrollLocation location, bool active)
{
Q_Q(QMenu);
+ updateActionRects();
if(location == QMenuScroller::ScrollBottom) {
- for(int i = actionList.size()-1; i >= 0; --i) {
- QAction *act = actionList.at(i);
+ for(int i = actions.size()-1; i >= 0; --i) {
+ QAction *act = actions.at(i);
+ if (actionRects.at(i).isNull())
+ continue;
if (!act->isSeparator() &&
(q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
|| act->isEnabled())) {
@@ -807,8 +813,10 @@ void QMenuPrivate::scrollMenu(QMenuScroller::ScrollLocation location, bool activ
}
}
} else if(location == QMenuScroller::ScrollTop) {
- for(int i = 0; i < actionList.size(); ++i) {
- QAction *act = actionList.at(i);
+ for(int i = 0; i < actions.size(); ++i) {
+ QAction *act = actions.at(i);
+ if (actionRects.at(i).isNull())
+ continue;
if (!act->isSeparator() &&
(q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
|| act->isEnabled())) {
@@ -828,38 +836,33 @@ void QMenuPrivate::scrollMenu(QMenuScroller::ScrollDirection direction, bool pag
Q_Q(QMenu);
if (!scroll || !(scroll->scrollFlags & direction)) //not really possible...
return;
- const int scrollHeight = q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q);
- const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollHeight : 0;
- const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollHeight : 0;
+ updateActionRects();
+ const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollerHeight() : 0;
+ const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollerHeight() : 0;
const int vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q);
const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
const int offset = topScroll ? topScroll-vmargin : 0;
if (direction == QMenuScroller::ScrollUp) {
- for(int i = 0, saccum = 0; i < actionList.count(); i++) {
- QAction *act = actionList.at(i);
- const int iHeight = actionRects.value(act).height();
- saccum -= iHeight;
+ for(int i = 0, saccum = 0; i < actions.count(); i++) {
+ saccum -= actionRects.at(i).height();
if (saccum <= scroll->scrollOffset-offset) {
- scrollMenu(act, page ? QMenuScroller::ScrollBottom : QMenuScroller::ScrollTop, active);
+ scrollMenu(actions.at(i), page ? QMenuScroller::ScrollBottom : QMenuScroller::ScrollTop, active);
break;
}
}
} else if (direction == QMenuScroller::ScrollDown) {
bool scrolled = false;
- for(int i = 0, saccum = 0; i < actionList.count(); i++) {
- QAction *act = actionList.at(i);
- const int iHeight = actionRects.value(act).height();
+ for(int i = 0, saccum = 0; i < actions.count(); i++) {
+ const int iHeight = actionRects.at(i).height();
saccum -= iHeight;
if (saccum <= scroll->scrollOffset-offset) {
const int scrollerArea = q->height() - botScroll - fw*2;
int visible = (scroll->scrollOffset-offset) - saccum;
- for(i++ ; i < actionList.count(); i++) {
- act = actionList.at(i);
- const int iHeight = actionRects.value(act).height();
- visible += iHeight;
+ for(i++ ; i < actions.count(); i++) {
+ visible += actionRects.at(i).height();
if (visible > scrollerArea - topScroll) {
scrolled = true;
- scrollMenu(act, page ? QMenuScroller::ScrollTop : QMenuScroller::ScrollBottom, active);
+ scrollMenu(actions.at(i), page ? QMenuScroller::ScrollTop : QMenuScroller::ScrollBottom, active);
break;
}
}
@@ -882,13 +885,12 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e)
if (scroll && !activeMenu) { //let the scroller "steal" the event
bool isScroll = false;
if (pos.x() >= 0 && pos.x() < q->width()) {
- const int scrollerHeight = q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q);
for(int dir = QMenuScroller::ScrollUp; dir <= QMenuScroller::ScrollDown; dir = dir << 1) {
if (scroll->scrollFlags & dir) {
if (dir == QMenuScroller::ScrollUp)
- isScroll = (pos.y() <= scrollerHeight);
+ isScroll = (pos.y() <= scrollerHeight());
else if (dir == QMenuScroller::ScrollDown)
- isScroll = (pos.y() >= q->height()-scrollerHeight);
+ isScroll = (pos.y() >= q->height() - scrollerHeight());
if (isScroll) {
scroll->scrollDirection = dir;
break;
@@ -897,19 +899,17 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e)
}
}
if (isScroll) {
- if (!scroll->scrollTimer)
- scroll->scrollTimer = new QBasicTimer;
- scroll->scrollTimer->start(50, q);
+ scroll->scrollTimer.start(50, q);
return true;
- } else if (scroll->scrollTimer && scroll->scrollTimer->isActive()) {
- scroll->scrollTimer->stop();
+ } else {
+ scroll->scrollTimer.stop();
}
}
if (tearoff) { //let the tear off thingie "steal" the event..
QRect tearRect(0, 0, q->width(), q->style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, q));
if (scroll && scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
- tearRect.translate(0, q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q));
+ tearRect.translate(0, scrollerHeight());
q->update(tearRect);
if (tearRect.contains(pos) && hasMouseMoved(e->globalPos())) {
setCurrentAction(0);
@@ -1034,7 +1034,7 @@ void QMenuPrivate::activateAction(QAction *action, QAction::ActionEvent action_e
if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
hideUpToMenuBar();
} else {
- for(QWidget *widget = qApp->activePopupWidget(); widget; ) {
+ for(QWidget *widget = QApplication::activePopupWidget(); widget; ) {
if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) {
if(qmenu == q)
hideUpToMenuBar();
@@ -1164,7 +1164,8 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action)
else
option->palette.setCurrentColorGroup(QPalette::Disabled);
- option->font = action->font();
+ option->font = action->font().resolve(font());
+ option->fontMetrics = QFontMetrics(option->font);
if (d->currentAction && d->currentAction == action && !d->currentAction->isSeparator()) {
option->state |= QStyle::State_Selected
@@ -1208,9 +1209,9 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action)
\brief The QMenu class provides a menu widget for use in menu
bars, context menus, and other popup menus.
- \ingroup application
+ \ingroup mainwindow-classes
\ingroup basicwidgets
- \mainclass
+
A menu widget is a selection menu. It can be either a pull-down
menu in a menu bar or a standalone context menu. Pull-down menus
@@ -1359,19 +1360,17 @@ QMenu::QMenu(QMenuPrivate &dd, QWidget *parent)
QMenu::~QMenu()
{
Q_D(QMenu);
- for (QHash<QAction *, QWidget *>::ConstIterator item = d->widgetItems.constBegin(),
- end = d->widgetItems.constEnd(); item != end; ++item) {
- QWidgetAction *action = static_cast<QWidgetAction *>(item.key());
- QWidget *widget = item.value();
- if (action && widget)
+ for (int i = 0; i < d->widgetItems.count(); ++i) {
+ if (QWidget *widget = d->widgetItems.at(i)) {
+ QWidgetAction *action = static_cast<QWidgetAction *>(d->actions.at(i));
action->releaseWidget(widget);
+ d->widgetItems[i] = 0;
+ }
}
- d->widgetItems.clear();
if (d->eventLoop)
d->eventLoop->exit();
- if (d->tornPopup)
- d->tornPopup->close();
+ hideTearOffMenu();
}
/*!
@@ -1582,8 +1581,8 @@ void QMenu::setTearOffEnabled(bool b)
Q_D(QMenu);
if (d->tearoff == b)
return;
- if (!b && d->tornPopup)
- d->tornPopup->close();
+ if (!b)
+ hideTearOffMenu();
d->tearoff = b;
d->itemsDirty = true;
@@ -1618,8 +1617,8 @@ bool QMenu::isTearOffMenuVisible() const
*/
void QMenu::hideTearOffMenu()
{
- if (d_func()->tornPopup)
- d_func()->tornPopup->close();
+ if (QWidget *w = d_func()->tornPopup)
+ w->close();
}
@@ -1717,36 +1716,26 @@ QRect QMenu::actionGeometry(QAction *act) const
QSize QMenu::sizeHint() const
{
Q_D(const QMenu);
- ensurePolished();
- QMap<QAction*, QRect> actionRects;
- QList<QAction*> actionList;
- d->calcActionRects(actionRects, actionList);
+ d->updateActionRects();
QSize s;
- QStyleOption opt(0);
- opt.rect = rect();
- opt.palette = palette();
- opt.state = QStyle::State_None;
- for (QMap<QAction*, QRect>::const_iterator i = actionRects.constBegin();
- i != actionRects.constEnd(); ++i) {
- if (i.value().bottom() > s.height())
- s.setHeight(i.value().y()+i.value().height());
- if (i.value().right() > s.width())
- s.setWidth(i.value().right());
- }
- if (d->tearoff)
- s.rheight() += style()->pixelMetric(QStyle::PM_MenuTearoffHeight, &opt, this);
- if (const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, this)) {
- s.rwidth() += fw*2;
- s.rheight() += fw*2;
+ for (int i = 0; i < d->actionRects.count(); ++i) {
+ const QRect &rect = d->actionRects.at(i);
+ if (rect.isNull())
+ continue;
+ if (rect.bottom() >= s.height())
+ s.setHeight(rect.y() + rect.height());
+ if (rect.right() >= s.width())
+ s.setWidth(rect.x() + rect.width());
}
// Note that the action rects calculated above already include
// the top and left margins, so we only need to add margins for
// the bottom and right.
- s.rwidth() += style()->pixelMetric(QStyle::PM_MenuHMargin, &opt, this);
- s.rheight() += style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, this);
-
- s += QSize(d->leftmargin + d->rightmargin, d->topmargin + d->bottommargin);
+ QStyleOption opt(0);
+ opt.init(this);
+ const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, this);
+ s.rwidth() += style()->pixelMetric(QStyle::PM_MenuHMargin, &opt, this) + fw + d->rightmargin;
+ s.rheight() += style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, this) + fw + d->bottommargin;
return style()->sizeFromContents(QStyle::CT_Menu, &opt,
s.expandedTo(QApplication::globalStrut()), this);
@@ -1788,19 +1777,35 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
ensurePolished(); // Get the right font
emit aboutToShow();
- d->updateActions();
+ d->updateActionRects();
QPoint pos = p;
QSize size = sizeHint();
QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(p));
const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this);
bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!atAction && QApplication::keypadNavigationEnabled()) {
+ // Try to have one item activated
+ if (d->defaultAction && d->defaultAction->isEnabled()) {
+ atAction = d->defaultAction;
+ // TODO: This works for first level menus, not yet sub menus
+ } else {
+ foreach (QAction *action, d->actions)
+ if (action->isEnabled()) {
+ atAction = action;
+ break;
+ }
+ }
+ d->currentAction = atAction;
+ }
+#endif
if (d->ncols > 1) {
pos.setY(screen.top()+desktopFrame);
} else if (atAction) {
- for(int i=0, above_height=0; i<(int)d->actionList.count(); i++) {
- QAction *action = d->actionList.at(i);
+ for(int i = 0, above_height = 0; i < d->actions.count(); i++) {
+ QAction *action = d->actions.at(i);
if (action == atAction) {
- int newY = pos.y()-above_height;
+ int newY = pos.y() - above_height;
if (d->scroll && newY < desktopFrame) {
d->scroll->scrollFlags = d->scroll->scrollFlags
| QMenuPrivate::QMenuScroller::ScrollUp;
@@ -1812,13 +1817,13 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
if (d->scroll && d->scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone
&& !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, 0, this)) {
int below_height = above_height + d->scroll->scrollOffset;
- for(int i2 = i; i2 < (int)d->actionList.count(); i2++)
- below_height += d->actionRects.value(d->actionList.at(i2)).height();
+ for(int i2 = i; i2 < d->actionRects.count(); i2++)
+ below_height += d->actionRects.at(i2).height();
size.setHeight(below_height);
}
break;
} else {
- above_height += d->actionRects.value(action).height();
+ above_height += d->actionRects.at(i).height();
}
}
}
@@ -1829,7 +1834,7 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
if (adjustToDesktop) {
//handle popup falling "off screen"
- if (qApp->layoutDirection() == Qt::RightToLeft) {
+ if (isRightToLeft()) {
if(snapToMouse) //position flowing left from the mouse
pos.setX(mouse.x()-size.width());
@@ -1867,9 +1872,9 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
}
setGeometry(QRect(pos, size));
#ifndef QT_NO_EFFECTS
- int hGuess = qApp->layoutDirection() == Qt::RightToLeft ? QEffects::LeftScroll : QEffects::RightScroll;
+ int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
int vGuess = QEffects::DownScroll;
- if (qApp->layoutDirection() == Qt::RightToLeft) {
+ if (isRightToLeft()) {
if ((snapToMouse && (pos.x() + size.width()/2 > mouse.x())) ||
(qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width()/2 > d->causedPopup.widget->x()))
hGuess = QEffects::RightScroll;
@@ -1921,6 +1926,9 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
#ifndef QT_NO_ACCESSIBILITY
QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuStart);
#endif
+#ifdef QT_KEYPAD_NAVIGATION
+ QActionToKeyEventMapper::addSoftKey(QAction::CancelSoftKey, Qt::Key_Back, this);
+#endif
}
/*!
@@ -2025,8 +2033,7 @@ QAction *QMenu::exec(const QPoint &p, QAction *action)
QAction *QMenu::exec(QList<QAction*> actions, const QPoint &pos, QAction *at, QWidget *parent)
{
QMenu menu(parent);
- for(QList<QAction*>::ConstIterator it = actions.constBegin(); it != actions.constEnd(); ++it)
- menu.addAction((*it));
+ menu.addActions(actions);
return menu.exec(pos, at);
}
@@ -2076,6 +2083,8 @@ void QMenu::hideEvent(QHideEvent *)
d->hasHadMouse = false;
d->causedPopup.widget = 0;
d->causedPopup.action = 0;
+ if (d->scroll)
+ d->scroll->scrollTimer.stop(); //make sure the timer stops
}
/*!
@@ -2084,6 +2093,7 @@ void QMenu::hideEvent(QHideEvent *)
void QMenu::paintEvent(QPaintEvent *e)
{
Q_D(QMenu);
+ d->updateActionRects();
QPainter p(this);
QRegion emptyArea = QRegion(rect());
@@ -2096,11 +2106,11 @@ void QMenu::paintEvent(QPaintEvent *e)
style()->drawPrimitive(QStyle::PE_PanelMenu, &menuOpt, &p, this);
//draw the items that need updating..
- for (int i = 0; i < d->actionList.count(); ++i) {
- QAction *action = d->actionList.at(i);
- QRect adjustedActionRect = d->actionRect(action);
+ for (int i = 0; i < d->actions.count(); ++i) {
+ QAction *action = d->actions.at(i);
+ QRect adjustedActionRect = d->actionRects.at(i);
if (!e->rect().intersects(adjustedActionRect)
- || d->widgetItems.value(action))
+ || d->widgetItems.at(i))
continue;
//set the clip region to be extra safe (and adjust for the scrollers)
QRegion adjustedActionReg(adjustedActionRect);
@@ -2116,18 +2126,17 @@ void QMenu::paintEvent(QPaintEvent *e)
const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this);
//draw the scroller regions..
if (d->scroll) {
- const int scrollerHeight = style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, this);
menuOpt.menuItemType = QStyleOptionMenuItem::Scroller;
menuOpt.state |= QStyle::State_Enabled;
if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) {
- menuOpt.rect.setRect(fw, fw, width() - (fw * 2), scrollerHeight);
+ menuOpt.rect.setRect(fw, fw, width() - (fw * 2), d->scrollerHeight());
emptyArea -= QRegion(menuOpt.rect);
p.setClipRect(menuOpt.rect);
style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this);
}
if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown) {
- menuOpt.rect.setRect(fw, height() - scrollerHeight - fw, width() - (fw * 2),
- scrollerHeight);
+ menuOpt.rect.setRect(fw, height() - d->scrollerHeight() - fw, width() - (fw * 2),
+ d->scrollerHeight());
emptyArea -= QRegion(menuOpt.rect);
menuOpt.state |= QStyle::State_DownArrow;
p.setClipRect(menuOpt.rect);
@@ -2140,7 +2149,7 @@ void QMenu::paintEvent(QPaintEvent *e)
menuOpt.rect.setRect(fw, fw, width() - (fw * 2),
style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this));
if (d->scroll && d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
- menuOpt.rect.translate(0, style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, this));
+ menuOpt.rect.translate(0, d->scrollerHeight());
emptyArea -= QRegion(menuOpt.rect);
p.setClipRect(menuOpt.rect);
menuOpt.state = QStyle::State_None;
@@ -2249,7 +2258,7 @@ void QMenu::mouseReleaseEvent(QMouseEvent *e)
break;
}
}
- if (e->button() == Qt::LeftButton || (e->button() == Qt::RightButton && isContextMenu))
+ if (e->button() == Qt::LeftButton || isContextMenu)
#endif
d->activateAction(action, QAction::Trigger);
}
@@ -2330,11 +2339,11 @@ QMenu::event(QEvent *e)
setMask(menuMask.region);
}
d->itemsDirty = 1;
- d->updateActions();
+ d->updateActionRects();
break; }
case QEvent::Show:
d->mouseDown = 0;
- d->updateActions();
+ d->updateActionRects();
if (d->currentAction)
d->popupAction(d->currentAction, 0, false);
break;
@@ -2370,6 +2379,7 @@ bool QMenu::focusNextPrevChild(bool next)
void QMenu::keyPressEvent(QKeyEvent *e)
{
Q_D(QMenu);
+ d->updateActionRects();
int key = e->key();
if (isRightToLeft()) { // in reverse mode open/close key for submenues are reversed
if (key == Qt::Key_Left)
@@ -2421,8 +2431,10 @@ void QMenu::keyPressEvent(QKeyEvent *e)
QMenuPrivate::QMenuScroller::ScrollLocation scroll_loc = QMenuPrivate::QMenuScroller::ScrollStay;
if (!d->currentAction) {
if(key == Qt::Key_Down) {
- for(int i = 0; i < d->actionList.size(); ++i) {
- QAction *act = d->actionList.at(i);
+ for(int i = 0; i < d->actions.count(); ++i) {
+ QAction *act = d->actions.at(i);
+ if (d->actionRects.at(i).isNull())
+ continue;
if (!act->isSeparator() &&
(style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)
|| act->isEnabled())) {
@@ -2431,8 +2443,10 @@ void QMenu::keyPressEvent(QKeyEvent *e)
}
}
} else {
- for(int i = d->actionList.size()-1; i >= 0; --i) {
- QAction *act = d->actionList.at(i);
+ for(int i = d->actions.count()-1; i >= 0; --i) {
+ QAction *act = d->actions.at(i);
+ if (d->actionRects.at(i).isNull())
+ continue;
if (!act->isSeparator() &&
(style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)
|| act->isEnabled())) {
@@ -2442,8 +2456,8 @@ void QMenu::keyPressEvent(QKeyEvent *e)
}
}
} else {
- for(int i=0, y=0; !nextAction && i < (int)d->actionList.count(); i++) {
- QAction *act = d->actionList.at(i);
+ for(int i = 0, y = 0; !nextAction && i < d->actions.count(); i++) {
+ QAction *act = d->actions.at(i);
if (act == d->currentAction) {
if (key == Qt::Key_Up) {
for(int next_i = i-1; true; next_i--) {
@@ -2452,21 +2466,23 @@ void QMenu::keyPressEvent(QKeyEvent *e)
break;
if (d->scroll)
scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom;
- next_i = d->actionList.count()-1;
+ next_i = d->actionRects.count()-1;
}
- QAction *next = d->actionList.at(next_i);
+ QAction *next = d->actions.at(next_i);
if (next == d->currentAction)
break;
+ if (d->actionRects.at(next_i).isNull())
+ continue;
if (next->isSeparator() ||
(!next->isEnabled() &&
!style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)))
continue;
nextAction = next;
if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)) {
- int topVisible = style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, this);
+ int topVisible = d->scrollerHeight();
if (d->tearoff)
topVisible += style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this);
- if (((y + d->scroll->scrollOffset) - topVisible) <= d->actionRects.value(nextAction).height())
+ if (((y + d->scroll->scrollOffset) - topVisible) <= d->actionRects.at(next_i).height())
scroll_loc = QMenuPrivate::QMenuScroller::ScrollTop;
}
break;
@@ -2474,31 +2490,32 @@ void QMenu::keyPressEvent(QKeyEvent *e)
if (!nextAction && d->tearoff)
d->tearoffHighlighted = 1;
} else {
- y += d->actionRects.value(act).height();
+ y += d->actionRects.at(i).height();
for(int next_i = i+1; true; next_i++) {
- if (next_i == d->actionList.count()) {
+ if (next_i == d->actionRects.count()) {
if(!style()->styleHint(QStyle::SH_Menu_SelectionWrap, 0, this))
break;
if (d->scroll)
scroll_loc = QMenuPrivate::QMenuScroller::ScrollTop;
next_i = 0;
}
- QAction *next = d->actionList.at(next_i);
+ QAction *next = d->actions.at(next_i);
if (next == d->currentAction)
break;
+ if (d->actionRects.at(next_i).isNull())
+ continue;
if (next->isSeparator() ||
(!next->isEnabled() &&
!style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)))
continue;
nextAction = next;
if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)) {
- const int scrollerHeight = style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, this);
- int bottomVisible = height()-scrollerHeight;
+ int bottomVisible = height() - d->scrollerHeight();
if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
- bottomVisible -= scrollerHeight;
+ bottomVisible -= d->scrollerHeight();
if (d->tearoff)
bottomVisible -= style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this);
- if ((y + d->scroll->scrollOffset + d->actionRects.value(nextAction).height()) > bottomVisible)
+ if ((y + d->scroll->scrollOffset + d->actionRects.at(next_i).height()) > bottomVisible)
scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom;
}
break;
@@ -2506,13 +2523,12 @@ void QMenu::keyPressEvent(QKeyEvent *e)
}
break;
}
- y += d->actionRects.value(act).height();
+ y += d->actionRects.at(i).height();
}
}
if (nextAction) {
if (d->scroll && scroll_loc != QMenuPrivate::QMenuScroller::ScrollStay) {
- if (d->scroll->scrollTimer)
- d->scroll->scrollTimer->stop();
+ d->scroll->scrollTimer.stop();
d->scrollMenu(nextAction, scroll_loc);
}
d->setCurrentAction(nextAction, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
@@ -2561,7 +2577,7 @@ void QMenu::keyPressEvent(QKeyEvent *e)
{
d->hideMenu(this);
#ifndef QT_NO_MENUBAR
- if (QMenuBar *mb = qobject_cast<QMenuBar*>(qApp->focusWidget())) {
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(QApplication::focusWidget())) {
mb->d_func()->setKeyboardMode(false);
}
#endif
@@ -2571,6 +2587,7 @@ void QMenu::keyPressEvent(QKeyEvent *e)
case Qt::Key_Escape:
#ifdef QT_KEYPAD_NAVIGATION
case Qt::Key_Back:
+ QActionToKeyEventMapper::removeSoftkey(this);
#endif
key_consumed = true;
if (d->tornoff) {
@@ -2634,9 +2651,11 @@ void QMenu::keyPressEvent(QKeyEvent *e)
int best_match_count = 0;
d->searchBufferTimer.start(2000, this);
d->searchBuffer += e->text();
- for(int i = 0; i < d->actionList.size(); ++i) {
+ for(int i = 0; i < d->actions.size(); ++i) {
int match_count = 0;
- register QAction *act = d->actionList.at(i);
+ if (d->actionRects.at(i).isNull())
+ continue;
+ QAction *act = d->actions.at(i);
const QString act_text = act->text();
for(int c = 0; c < d->searchBuffer.size(); ++c) {
if(act_text.indexOf(d->searchBuffer.at(c), 0, Qt::CaseInsensitive) != -1)
@@ -2653,8 +2672,10 @@ void QMenu::keyPressEvent(QKeyEvent *e)
int clashCount = 0;
QAction *first = 0, *currentSelected = 0, *firstAfterCurrent = 0;
QChar c = e->text().at(0).toUpper();
- for(int i = 0; i < d->actionList.size(); ++i) {
- register QAction *act = d->actionList.at(i);
+ for(int i = 0; i < d->actions.size(); ++i) {
+ if (d->actionRects.at(i).isNull())
+ continue;
+ QAction *act = d->actions.at(i);
QKeySequence sequence = QKeySequence::mnemonic(act->text());
int key = sequence[0] & 0xffff;
if (key == c.unicode()) {
@@ -2705,7 +2726,7 @@ void QMenu::keyPressEvent(QKeyEvent *e)
#ifdef Q_OS_WIN32
if (key_consumed && (e->key() == Qt::Key_Control || e->key() == Qt::Key_Shift || e->key() == Qt::Key_Meta))
- qApp->beep();
+ QApplication::beep();
#endif // Q_OS_WIN32
}
if (key_consumed)
@@ -2725,14 +2746,14 @@ void QMenu::mouseMoveEvent(QMouseEvent *e)
d->motions++;
if (d->motions == 0) // ignore first mouse move event (see enterEvent())
return;
- d->hasHadMouse |= rect().contains(e->pos());
+ d->hasHadMouse = d->hasHadMouse || rect().contains(e->pos());
QAction *action = d->actionAt(e->pos());
if (!action) {
- if (d->hasHadMouse && !rect().contains(e->pos()))
+ if (d->hasHadMouse)
d->setCurrentAction(0);
return;
- } else if(e->buttons() & (Qt::LeftButton | Qt::RightButton)) {
+ } else if(e->buttons()) {
d->mouseDown = this;
}
if (d->sloppyRegion.contains(e->pos())) {
@@ -2760,6 +2781,8 @@ void QMenu::leaveEvent(QEvent *)
d->sloppyAction = 0;
if (!d->sloppyRegion.isEmpty())
d->sloppyRegion = QRegion();
+ if (!d->activeMenu && d->currentAction)
+ setActiveAction(0);
}
/*!
@@ -2769,10 +2792,10 @@ void
QMenu::timerEvent(QTimerEvent *e)
{
Q_D(QMenu);
- if (d->scroll && d->scroll->scrollTimer && d->scroll->scrollTimer->timerId() == e->timerId()) {
+ if (d->scroll && d->scroll->scrollTimer.timerId() == e->timerId()) {
d->scrollMenu((QMenuPrivate::QMenuScroller::ScrollDirection)d->scroll->scrollDirection);
if (d->scroll->scrollFlags == QMenuPrivate::QMenuScroller::ScrollNone)
- d->scroll->scrollTimer->stop();
+ d->scroll->scrollTimer.stop();
} else if(QMenuPrivate::menuDelayTimer.timerId() == e->timerId()) {
QMenuPrivate::menuDelayTimer.stop();
internalDelayedPopup();
@@ -2799,31 +2822,25 @@ void QMenu::actionEvent(QActionEvent *e)
connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered()));
}
+ QWidget *widget = 0;
+ if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action()))
+ widget = wa->requestWidget(this);
+
+ int index = d->actions.indexOf(e->action());
+ Q_ASSERT(index != -1);
+ d->widgetItems.insert(index, widget);
- if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
- QWidget *widget = wa->requestWidget(this);
- if (widget)
- d->widgetItems.insert(wa, widget);
- }
} else if (e->type() == QEvent::ActionRemoved) {
- d->actionRects.clear();
- d->actionList.clear();
e->action()->disconnect(this);
if (e->action() == d->currentAction)
d->currentAction = 0;
+ int index = d->actions.indexOf(e->before()) + 1;
if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
- QWidget *widget = d->widgetItems.take(wa);
- if (widget)
+ if (QWidget *widget = d->widgetItems.at(index))
wa->releaseWidget(widget);
- } else {
- // If this is called from the QAction destructor, the
- // previous call to qobject_cast will fail because the
- // QWidgetAction has been destroyed already. We need to
- // remove it from the hash anyway or it might crash later
- // the widget itself has been already destroyed in
- // ~QWidgetAction
- d->widgetItems.remove(e->action());
}
+ Q_ASSERT(index != -1);
+ d->widgetItems.removeAt(index);
}
#ifdef Q_WS_MAC
@@ -2837,7 +2854,7 @@ void QMenu::actionEvent(QActionEvent *e)
}
#endif
-#if defined(Q_OS_WINCE) && !defined(QT_NO_MENUBAR)
+#if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR)
if (!d->wce_menu)
d->wce_menu = new QMenuPrivate::QWceMenuPrivate;
if (e->type() == QEvent::ActionAdded)
@@ -2848,8 +2865,18 @@ void QMenu::actionEvent(QActionEvent *e)
d->wce_menu->syncAction(e->action());
#endif
+#ifdef Q_WS_S60
+ if (!d->symbian_menu)
+ d->symbian_menu = new QMenuPrivate::QSymbianMenuPrivate;
+ if (e->type() == QEvent::ActionAdded)
+ d->symbian_menu->addAction(e->action(), d->symbian_menu->findAction(e->before()));
+ else if (e->type() == QEvent::ActionRemoved)
+ d->symbian_menu->removeAction(e->action());
+ else if (e->type() == QEvent::ActionChanged)
+ d->symbian_menu->syncAction(e->action());
+#endif
if (isVisible()) {
- d->updateActions();
+ d->updateActionRects();
resize(sizeHint());
update();
}
@@ -3027,12 +3054,19 @@ bool QMenu::separatorsCollapsible() const
void QMenu::setSeparatorsCollapsible(bool collapse)
{
Q_D(QMenu);
+ if (d->collapsibleSeparators == collapse)
+ return;
+
d->collapsibleSeparators = collapse;
d->itemsDirty = 1;
if (isVisible()) {
- d->updateActions();
+ d->updateActionRects();
update();
}
+#ifdef Q_WS_MAC
+ if (d->mac_menu)
+ d->syncSeparatorsCollapsible(collapse);
+#endif
}
#ifdef QT3_SUPPORT
@@ -3089,9 +3123,9 @@ int QMenu::insertSeparator(int index)
QAction *QMenu::findActionForId(int id) const
{
- QList<QAction *> list = actions();
- for (int i = 0; i < list.size(); ++i) {
- QAction *act = list.at(i);
+ Q_D(const QMenu);
+ for (int i = 0; i < d->actions.size(); ++i) {
+ QAction *act = d->actions.at(i);
if (findIdForAction(act)== id)
return act;
}