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.cpp511
1 files changed, 243 insertions, 268 deletions
diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp
index fc55a2c..35b68b4 100644
--- a/src/gui/widgets/qmenu.cpp
+++ b/src/gui/widgets/qmenu.cpp
@@ -150,7 +150,6 @@ private:
void QMenuPrivate::init()
{
Q_Q(QMenu);
- activationRecursionGuard = false;
#ifndef QT_NO_WHATSTHIS
q->setAttribute(Qt::WA_CustomWhatsThis);
#endif
@@ -164,6 +163,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 +199,75 @@ 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;
+
+ //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();
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();
+ const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, 0, q),
+ vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, 0, q),
+ icone = style->pixelMetric(QStyle::PM_SmallIconSize, 0, q);
//for compatability now - will have to refactor this away..
tabWidth = 0;
maxIconWidth = 0;
hasCheckableItems = false;
- QList<QAction*> items = filteredActions();
- 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()) {
@@ -275,7 +298,7 @@ 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);
}
@@ -283,119 +306,59 @@ void QMenuPrivate::calcActionRects(QMap<QAction*, QRect> &actionRects, QList<QAc
max_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 - (style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q) * 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 fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
+ const int base_y = vmargin + fw + topmargin +
+ (scroll ? scroll->scrollOffset : 0) +
+ (tearoff ? style->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, q) : 0);
+ 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 - (style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q) * 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::filteredActions() 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;
-}
-
-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;
+ //we found the action
+ return actionRects.at(index);
}
static const qreal MenuFadeTimeInSec = 0.150;
@@ -525,14 +488,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())) {
@@ -582,9 +548,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);
@@ -628,10 +595,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;
}
@@ -705,27 +671,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
@@ -734,7 +698,7 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc
}
}
if(newOffset)
- newOffset -= fw*2;
+ newOffset -= fw * 2;
}
//figure out which scroll flags
@@ -742,8 +706,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;
@@ -794,9 +758,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);
@@ -807,9 +781,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())) {
@@ -821,8 +798,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())) {
@@ -842,38 +821,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;
}
}
@@ -896,13 +870,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;
@@ -911,19 +884,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);
@@ -1178,7 +1149,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
@@ -1373,19 +1345,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();
}
/*!
@@ -1596,8 +1566,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;
@@ -1632,8 +1602,8 @@ bool QMenu::isTearOffMenuVisible() const
*/
void QMenu::hideTearOffMenu()
{
- if (d_func()->tornPopup)
- d_func()->tornPopup->close();
+ if (QWidget *w = d_func()->tornPopup)
+ w->close();
}
@@ -1732,35 +1702,34 @@ 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.
+ if (const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, this)) {
+ s.rwidth() += fw;
+ s.rheight() += fw;
+ }
+
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);
+ s += QSize(d->rightmargin, d->bottommargin);
return style()->sizeFromContents(QStyle::CT_Menu, &opt,
s.expandedTo(QApplication::globalStrut()), this);
@@ -1802,7 +1771,7 @@ 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));
@@ -1811,10 +1780,10 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
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;
@@ -1826,13 +1795,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 < 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();
}
}
}
@@ -2039,8 +2008,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);
}
@@ -2090,6 +2058,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
}
/*!
@@ -2098,6 +2068,7 @@ void QMenu::hideEvent(QHideEvent *)
void QMenu::paintEvent(QPaintEvent *e)
{
Q_D(QMenu);
+ d->updateActionRects();
QPainter p(this);
QRegion emptyArea = QRegion(rect());
@@ -2110,11 +2081,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);
@@ -2130,18 +2101,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);
@@ -2154,7 +2124,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;
@@ -2263,7 +2233,7 @@ void QMenu::mouseReleaseEvent(QMouseEvent *e)
break;
}
}
- if (e->button() || isContextMenu)
+ if (e->button() == Qt::LeftButton || isContextMenu)
#endif
d->activateAction(action, QAction::Trigger);
}
@@ -2344,11 +2314,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;
@@ -2384,6 +2354,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)
@@ -2435,8 +2406,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())) {
@@ -2445,8 +2418,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())) {
@@ -2456,8 +2431,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--) {
@@ -2466,21 +2441,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;
@@ -2488,31 +2465,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;
@@ -2520,13 +2498,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);
@@ -2648,9 +2625,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)
@@ -2667,8 +2646,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()) {
@@ -2739,7 +2720,7 @@ 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) {
@@ -2783,10 +2764,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();
@@ -2813,31 +2794,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
@@ -2863,7 +2838,7 @@ void QMenu::actionEvent(QActionEvent *e)
#endif
if (isVisible()) {
- d->updateActions();
+ d->updateActionRects();
resize(sizeHint());
update();
}
@@ -3044,7 +3019,7 @@ void QMenu::setSeparatorsCollapsible(bool collapse)
d->collapsibleSeparators = collapse;
d->itemsDirty = 1;
if (isVisible()) {
- d->updateActions();
+ d->updateActionRects();
update();
}
}
@@ -3103,9 +3078,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;
}