📄 qmenubar.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include <qmenubar.h>#include <qstyle.h>#include <qlayout.h>#include <qapplication.h>#include <qdesktopwidget.h>#ifndef QT_NO_ACCESSIBILITY# include <qaccessible.h>#endif#include <qpainter.h>#include <qevent.h>#include <qmainwindow.h>#include <qtoolbar.h>#include <qtoolbutton.h>#include <qwhatsthis.h>#ifndef QT_NO_MENUBAR#ifdef QT3_SUPPORT#include <private/qaction_p.h>#include <qmenudata.h>#endif#include "qmenu_p.h"#include "qmenubar_p.h"#include "qdebug.h"class QMenuBarExtension : public QToolButton{public: explicit QMenuBarExtension(QWidget *parent); QSize sizeHint() const;};QMenuBarExtension::QMenuBarExtension(QWidget *parent) : QToolButton(parent){ setObjectName(QLatin1String("qt_menubar_ext_button")); setAutoRaise(true);#ifndef QT_NO_MENU setPopupMode(QToolButton::InstantPopup);#endif setIcon(style()->standardPixmap(QStyle::SP_ToolBarHorizontalExtensionButton));}QSize QMenuBarExtension::sizeHint() const{ int ext = style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent); return QSize(ext, ext);}QAction *QMenuBarPrivate::actionAt(QPoint p) const{ Q_Q(const QMenuBar); QList<QAction*> items = q->actions(); for(int i = 0; i < items.size(); ++i) { if(actionRect(items.at(i)).contains(p)) return items.at(i); } return 0;}bool QMenuBarPrivate::isVisible(QAction *action){ Q_Q(QMenuBar); if (!extension->isHidden()) { int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q); QRect menuRect = q->rect(); if (QApplication::layoutDirection() == Qt::RightToLeft) menuRect.setLeft(menuRect.left() + extension->width() + hmargin); else menuRect.setWidth(menuRect.width() - extension->width() - hmargin); if (menuRect.contains(actionRect(action))) return true; else return false; } return true;}void QMenuBarPrivate::updateGeometries(){ Q_Q(QMenuBar); if(!itemsDirty) return; int q_width = q->width()-(q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q)*2); int q_start = -1; if(leftWidget || rightWidget) { int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q) + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q); int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarHMargin, 0, q) + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q); if(leftWidget && leftWidget->isVisible()) { QSize sz = leftWidget->sizeHint(); q_width -= sz.width(); q_start = sz.width(); leftWidget->setGeometry(QRect(QPoint(hmargin, vmargin), sz)); } if(rightWidget && rightWidget->isVisible()) { QSize sz = rightWidget->sizeHint(); q_width -= sz.width(); rightWidget->setGeometry(QRect(QPoint(q->width() - sz.width() - hmargin, vmargin), sz)); } }#ifdef Q_WS_MAC if(mac_menubar) {//nothing to see here folks, move along.. itemsDirty = false; return; }#endif calcActionRects(q_width, q_start, actionRects, actionList); itemsWidth = q_width; itemsStart = q_start; currentAction = 0;#ifndef QT_NO_SHORTCUT if(itemsDirty) { for(int j = 0; j < shortcutIndexMap.size(); ++j) q->releaseShortcut(shortcutIndexMap.value(j)); shortcutIndexMap.resize(0); // faster than clear for(int i = 0; i < actionList.count(); i++) shortcutIndexMap.append(q->grabShortcut(QKeySequence::mnemonic(actionList.at(i)->text()))); }#endif itemsDirty = false; QList<QAction *> hiddenActions; int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q); QRect menuRect = q->rect(); if (!extension->isHidden() && (menuRect.width() < q->sizeHint().width())) { if (QApplication::layoutDirection() == Qt::RightToLeft) menuRect.setLeft(menuRect.left() + extension->width() + hmargin); else menuRect.setWidth(menuRect.width() - extension->width() - hmargin); } for (int i = 0; i < actionList.count(); ++i) { if (!menuRect.contains(actionRect(actionList.at(i)))) hiddenActions.append(actionList.at(i)); } if (hiddenActions.count() > 0) { QMenu *pop = extension->menu(); if (!pop) { pop = new QMenu(q); extension->setMenu(pop); } pop->clear(); pop->addActions(hiddenActions); int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q); int x = QApplication::layoutDirection() == Qt::RightToLeft ? hmargin : q->width() - extension->sizeHint().width() - hmargin; extension->setGeometry(x, vmargin, extension->sizeHint().width(), menuRect.height() - vmargin*2); extension->show(); } else { extension->hide(); } q->updateGeometry();#ifdef QT3_SUPPORT if (q->parentWidget() != 0) { QMenubarUpdatedEvent menubarUpdated(q); QApplication::sendEvent(q->parentWidget(), &menubarUpdated); }#endif}QRect QMenuBarPrivate::actionRect(QAction *act) const{ Q_Q(const QMenuBar); QRect ret = actionRects.value(act); const int fw = q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q); ret.translate(fw, fw); return QStyle::visualRect(q->layoutDirection(), q->rect(), ret);}void QMenuBarPrivate::setKeyboardMode(bool b){ Q_Q(QMenuBar); if (b && !q->style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, q)) { setCurrentAction(0); return; } keyboardState = b; if(b) { QWidget *fw = qApp->focusWidget(); if (fw != q) keyboardFocusWidget = qApp->focusWidget(); if(!currentAction && !actionList.isEmpty()) setCurrentAction(actionList.first()); q->setFocus(); } else { if(!popupState) setCurrentAction(0); if(keyboardFocusWidget) { keyboardFocusWidget->setFocus(); keyboardFocusWidget = 0; } } q->update();}void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst){ Q_Q(QMenuBar); if(!action || !action->menu()) return; popupState = true; if (action->isEnabled() && action->menu()->isEnabled()) { closePopupMode = 0; activeMenu = action->menu(); activeMenu->d_func()->causedPopup.widget = q; activeMenu->d_func()->causedPopup.action = action; QRect adjustedActionRect = actionRect(action); QPoint pos(q->mapToGlobal(QPoint(adjustedActionRect.left(), adjustedActionRect.bottom() + 1))); QSize popup_size = activeMenu->sizeHint(); if(q->isRightToLeft()) pos.setX(pos.x()-(popup_size.width()-adjustedActionRect.width())); QRect screenRect = QApplication::desktop()->screenGeometry(pos); if(pos.x() < screenRect.x()) { pos.setX(screenRect.x()); } else { const int off = pos.x()+popup_size.width() - screenRect.right(); if(off > 0) pos.setX(qMax(screenRect.x(), pos.x()-off)); } if(!defaultPopDown || (pos.y() + popup_size.height() > screenRect.bottom())) pos.setY(qMax(screenRect.y(), q->mapToGlobal(QPoint(0, adjustedActionRect.top()-popup_size.height())).y())); activeMenu->popup(pos); if(activateFirst) activeMenu->d_func()->setFirstActionActive(); } q->update(actionRect(action));}void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activateFirst){ if(currentAction == action && popup == popupState) return; doChildEffects = (popup && !activeMenu); Q_Q(QMenuBar); QWidget *fw = 0; if(activeMenu) { QMenu *menu = activeMenu; activeMenu = NULL; if (popup) { fw = q->window()->focusWidget(); q->setFocus(Qt::NoFocusReason); } menu->hide(); } if(currentAction) q->update(actionRect(currentAction)); popupState = popup; QAction *previousAction = currentAction; currentAction = action; if(action) { activateAction(action, QAction::Hover); if(popup) popupAction(action, activateFirst); q->update(actionRect(action)); } else if (previousAction) { QString empty; QStatusTipEvent tip(empty); QApplication::sendEvent(q, &tip); } if (fw) fw->setFocus(Qt::NoFocusReason);}void QMenuBarPrivate::calcActionRects(int max_width, int start, QMap<QAction*, QRect> &actionRects, QList<QAction*> &actionList) const{ Q_Q(const QMenuBar); if(!itemsDirty && itemsWidth == max_width && itemsStart == start) { actionRects = actionRects; actionList = actionList; return; } actionRects.clear(); actionList.clear(); const int itemSpacing = q->style()->pixelMetric(QStyle::PM_MenuBarItemSpacing, 0, q); int max_item_height = 0, separator = -1, separator_start = 0, separator_len = 0; QList<QAction*> items = q->actions(); //calculate size const QFontMetrics fm = q->fontMetrics(); const int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarHMargin, 0, q), vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q), icone = q->style()->pixelMetric(QStyle::PM_SmallIconSize, 0, q); for(int i = 0; i < items.count(); i++) { QAction *action = items.at(i); if(!action->isVisible()) continue; QSize sz; //calc what I think the size is.. if(action->isSeparator()) { if (q->style()->styleHint(QStyle::SH_DrawMenuBarSeparator, 0, q)) separator = actionRects.count(); continue; //we don't really position these! } else { QString s = action->text(); if(!s.isEmpty()) { int w = fm.width(s); w -= s.count('&') * fm.width('&'); w += s.count("&&") * fm.width('&'); sz = QSize(w, fm.height()); } QIcon is = action->icon(); if (!is.isNull()) { QSize is_sz = QSize(icone, icone); if (is_sz.height() > sz.height()) sz.setHeight(is_sz.height()); if (is_sz.width() > sz.width()) sz.setWidth(is_sz.width()); } } //let the style modify the above size.. QStyleOptionMenuItem opt = getStyleOption(action); sz = q->style()->sizeFromContents(QStyle::CT_MenuBarItem, &opt, sz, q); if(!sz.isEmpty()) { { //update the separator state int iWidth = sz.width(); iWidth += itemSpacing; if(separator == -1) separator_start += iWidth; else separator_len += iWidth; } //maximum height max_item_height = qMax(max_item_height, sz.height()); //append actionRects.insert(action, QRect(0, 0, sz.width(), sz.height())); actionList.append(action); } } //calculate position int x = ((start == -1) ? hmargin : start) + itemSpacing; int y = vmargin; for(int i = 0; i < actionList.count(); i++) { QAction *action = actionList.at(i); QRect &rect = actionRects[action]; //resize rect.setHeight(max_item_height); //move if(separator != -1 && i >= separator) { //after the separator int left = (max_width - separator_len - hmargin - itemSpacing) + (x - separator_start - hmargin); if(left < separator_start) { //wrap separator_start = x = hmargin; y += max_item_height; } rect.moveLeft(left); } else { rect.moveLeft(x); } rect.moveTop(y); //keep moving along.. x += rect.width() + itemSpacing; }}void QMenuBarPrivate::activateAction(QAction *action, QAction::ActionEvent action_e){ Q_Q(QMenuBar); if (!action || !action->isEnabled()) return; action->activate(action_e); if (action_e == QAction::Hover) action->showStatusText(q);// if(action_e == QAction::Trigger)// emit q->activated(action);// else if(action_e == QAction::Hover)// emit q->highlighted(action);}void QMenuBarPrivate::_q_actionTriggered(){ Q_Q(QMenuBar); if (QAction *action = qobject_cast<QAction *>(q->sender())) { emit q->triggered(action);#ifdef QT3_SUPPORT emit q->activated(q->findIdForAction(action));#endif }}void QMenuBarPrivate::_q_actionHovered(){ Q_Q(QMenuBar); if (QAction *action = qobject_cast<QAction *>(q->sender())) { emit q->hovered(action);#ifdef QT3_SUPPORT emit q->highlighted(q->findIdForAction(action));#endif }}QStyleOptionMenuItem QMenuBarPrivate::getStyleOption(const QAction *action) const{ Q_Q(const QMenuBar); QStyleOptionMenuItem opt; opt.palette = q->palette(); opt.state = QStyle::State_None; if (q->isEnabled() && action->isEnabled()) opt.state |= QStyle::State_Enabled; else opt.palette.setCurrentColorGroup(QPalette::Disabled); opt.fontMetrics = q->fontMetrics(); if (currentAction && currentAction == action) { opt.state |= QStyle::State_Selected; if (popupState && !closePopupMode) opt.state |= QStyle::State_Sunken; } if (q->hasFocus() || currentAction) opt.state |= QStyle::State_HasFocus; opt.menuRect = q->rect(); opt.menuItemType = QStyleOptionMenuItem::Normal; opt.checkType = QStyleOptionMenuItem::NotCheckable; opt.text = action->text(); opt.icon = action->icon(); return opt;}/*! \class QMenuBar \brief The QMenuBar class provides a horizontal menu bar. \ingroup application \mainclass A menu bar consists of a list of pull-down menu items. You add menu items with addMenu(). For example, asuming that \c menubar is a pointer to a QMenuBar and \c fileMenu is a pointer to a QMenu, the following statement inserts the menu into the menu bar: \code menubar->addMenu(fileMenu); \endcode
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -