66QQuickItem *QQuickMenuBarPrivate::createItemFromDelegate()
70 QQmlContext *context = delegate->creationContext();
72 context = qmlContext(q);
74 QObject *object = delegate->beginCreate(context);
75 QQuickItem *item = qobject_cast<QQuickItem *>(object);
81 QQml_setParent_noEvent(item, q);
82 delegate->completeCreate();
87QQuickMenuBarItem *QQuickMenuBarPrivate::createMenuBarItem(QQuickMenu *menu)
91 QQuickMenuBarItem *menuBarItem =
nullptr;
93 QQuickItem *item = createItemFromDelegate();
94 menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
96 qmlWarning(q) <<
"cannot insert menu: the delegate is not a MenuBarItem.";
106 qCDebug(lcMenuBar) <<
"creating hidden placeholder MenuBarItem for:" << menu->title();
107 menuBarItem =
new QQuickMenuBarItem(q);
108 menuBarItem->setParentItem(q);
109 menuBarItem->setVisible(
false);
112 menuBarItem->setMenu(menu);
117 menuBarItem->setProperty(kCreatedFromDelegate,
true);
122void QQuickMenuBarPrivate::openCurrentMenu()
124 if (!currentItem || currentMenuOpen)
126 QQuickMenu *menu = currentItem->menu();
127 if (!menu || menu->isOpened())
133 const QPointF posInParentItem = q->mapToItem(currentItem, {currentItem->x(), q->height()});
136 const QPointF posInParentItem{0, currentItem->y() + currentItem->height()};
143 currentMenuOpen =
true;
148 menu->popup(posInParentItem);
151void QQuickMenuBarPrivate::closeCurrentMenu()
153 if (!currentItem || !currentMenuOpen)
155 currentMenuOpen =
false;
156 QQuickMenu *menu = currentItem->menu();
157 QScopedValueRollback triggerRollback(closingCurrentMenu,
true);
192void QQuickMenuBarPrivate::activateNextItem()
194 int index = currentItem ? contentModel->indexOf(currentItem,
nullptr) : -1;
195 if (index >= contentModel->count() - 1)
197 activateItem(qobject_cast<QQuickMenuBarItem *>(itemAt(++index)));
200void QQuickMenuBarPrivate::activatePreviousItem()
202 int index = currentItem ? contentModel->indexOf(currentItem,
nullptr) : contentModel->count();
204 index = contentModel->count();
205 activateItem(qobject_cast<QQuickMenuBarItem *>(itemAt(--index)));
257qreal QQuickMenuBarPrivate::getContentWidth()
const
259 Q_Q(
const QQuickMenuBar);
260 const int count = contentModel->count();
261 qreal totalWidth = qMax(0, count - 1) * spacing;
262 for (
int i = 0; i < count; ++i) {
263 QQuickItem *item = q->itemAt(i);
265 totalWidth += item->implicitWidth();
270qreal QQuickMenuBarPrivate::getContentHeight()
const
272 Q_Q(
const QQuickMenuBar);
273 const int count = contentModel->count();
275 for (
int i = 0; i < count; ++i) {
276 QQuickItem *item = q->itemAt(i);
278 maxHeight = qMax(maxHeight, item->implicitHeight());
297void QQuickMenuBarPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
299 auto menuBar =
static_cast<QQuickMenuBar *>(prop->object);
300 auto menuBarPriv = QQuickMenuBarPrivate::get(menuBar);
302 if (
auto *menu = qobject_cast<QQuickMenu *>(obj)) {
303 QQuickMenuBarItem *delegateItem = menuBarPriv->createMenuBarItem(menu);
304 menuBarPriv->insertMenu(menuBar->count(), menu, delegateItem);
305 QQuickContainerPrivate::contentData_append(prop, delegateItem);
309 if (
auto *menuBarItem = qobject_cast<QQuickMenuBarItem *>(obj)) {
310 menuBarPriv->insertMenu(menuBar->count(), menuBarItem->menu(), menuBarItem);
311 QQuickContainerPrivate::contentData_append(prop, menuBarItem);
315 QQuickContainerPrivate::contentData_append(prop, obj);
384void QQuickMenuBarPrivate::insertNativeMenu(QQuickMenu *menu)
390 QPlatformMenu *insertBeforeHandle =
nullptr;
397 bool foundInContainer =
false;
398 for (
int i = 0; i < q->count(); ++i) {
399 if (q->menuAt(i) != menu)
401 foundInContainer =
true;
403 for (
int j = i + 1; j < q->count(); ++j) {
404 insertBeforeHandle = QQuickMenuPrivate::get(q->menuAt(j))->maybeNativeHandle();
405 if (insertBeforeHandle)
412 Q_ASSERT(foundInContainer);
413 QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
414 if (QPlatformMenu *menuHandle = menuPrivate->nativeHandle()) {
415 qCDebug(lcMenuBar) <<
"insert native menu:" << menu->title() << menuHandle <<
"before:" << insertBeforeHandle;
416 handle->insertMenu(menuPrivate->nativeHandle(), insertBeforeHandle);
418 qmlWarning(q) <<
"failed to create native menu for:" << menu->title();
422void QQuickMenuBarPrivate::removeNativeMenu(QQuickMenu *menu)
427 QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
428 if (!menuPrivate->maybeNativeHandle())
431 qCDebug(lcMenuBar) <<
"remove native menu:" << menu << menu->title();
432 handle->removeMenu(menuPrivate->nativeHandle());
433 menuPrivate->removeNativeMenu();
436void QQuickMenuBarPrivate::syncMenuBarItemVisibilty(QQuickMenuBarItem *menuBarItem)
443 QQuickMenu *menu = menuBarItem->menu();
446 QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
448 if (menuBarItem->isVisible()) {
449 Q_ASSERT(!menuPrivate->maybeNativeHandle());
450 insertNativeMenu(menu);
452 if (menuPrivate->maybeNativeHandle())
453 removeNativeMenu(menu);
457void QQuickMenuBarPrivate::insertMenu(
int index, QQuickMenu *menu, QQuickMenuBarItem *menuBarItem)
461 qmlWarning(q) <<
"cannot insert menu: menu is null.";
465 auto menuPrivate = QQuickMenuPrivate::get(menu);
466 menuPrivate->menuBar = q;
468 QObject::connect(menuBarItem, &QQuickMenuBarItem::visibleChanged, q, [
this, menuBarItem]{
469 syncMenuBarItemVisibilty(menuBarItem);
475 q->insertItem(index, menuBarItem);
479 if (menuBarItem->isVisible()) {
481 insertNativeMenu(menu);
483 if (menuPrivate->maybeNativeHandle()) {
489 menuPrivate->removeNativeMenu();
494QQuickMenu *QQuickMenuBarPrivate::takeMenu(
int index)
497 QQuickItem *item = q->itemAt(index);
499 QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
501 qmlWarning(q) <<
"cannot take/remove menu: item at index " << index <<
" is not a MenuBarItem.";
504 QQuickMenu *menu = menuBarItem->menu();
506 qmlWarning(q) <<
"cannot take/remove menu: MenuBarItem.menu at index " << index <<
" is null.";
515 if (item == currentItem)
516 activateItem(
nullptr);
518 if (QQuickMenuPrivate::get(menu)->maybeNativeHandle())
519 removeNativeMenu(menu);
521 removeItem(index, item);
529 QQuickMenuPrivate::get(menu)->menuBar =
nullptr;
530 menuBarItem->disconnect(q);
579void QQuickMenuBarPrivate::createNativeMenuBar()
583 qCDebug(lcMenuBar) <<
"creating native menubar";
585 handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar());
587 qCDebug(lcMenuBar) <<
"QPlatformTheme failed to create a QPlatformMenuBar!";
591 handle->handleReparent(window());
592 qCDebug(lcMenuBar) <<
"native menubar parented to window:" << handle->parentWindow();
596 for (
int i = q->count() - 1; i >= 0; --i) {
597 if (QQuickMenu *menu = q->menuAt(i)) {
598 if (useNativeMenu(menu))
599 insertNativeMenu(menu);
632QQuickMenuBar::QQuickMenuBar(QQuickItem *parent)
633 : QQuickContainer(*(
new QQuickMenuBarPrivate), parent)
636 d->changeTypes |= QQuickItemPrivate::Geometry;
637 setFlag(ItemIsFocusScope);
638 setFocusPolicy(Qt::ClickFocus);
664void QQuickMenuBar::setDelegate(QQmlComponent *delegate)
667 if (d->delegate == delegate)
670 d->delegate = delegate;
672 for (
int i = count() - 1; i >= 0; --i) {
673 auto item = itemAt(i);
674 if (!item || !item->property(kCreatedFromDelegate).toBool())
677 QQuickMenuBarItem *menuBarItem =
static_cast<QQuickMenuBarItem *>(item);
678 if (QQuickMenu *menu = menuBarItem->menu()) {
680 d->insertMenu(i, menu, d->createMenuBarItem(menu));
682 removeItem(menuBarItem);
686 emit delegateChanged();
784QQmlListProperty<QQuickMenu> QQuickMenuBarPrivate::menus()
787 return QQmlListProperty<QQuickMenu>(q,
nullptr,
788 QQuickMenuBarPrivate::menus_append,
789 QQuickMenuBarPrivate::menus_count,
790 QQuickMenuBarPrivate::menus_at,
791 QQuickMenuBarPrivate::menus_clear);
794QQmlListProperty<QObject> QQuickMenuBarPrivate::contentData()
797 return QQmlListProperty<QObject>(q,
nullptr,
798 QQuickMenuBarPrivate::contentData_append,
799 QQuickContainerPrivate::contentData_count,
800 QQuickContainerPrivate::contentData_at,
801 QQuickContainerPrivate::contentData_clear);
804bool QQuickMenuBar::eventFilter(QObject *object, QEvent *event)
809 switch (event->type()) {
810 case QEvent::KeyRelease: {
811 const QKeyEvent *keyEvent =
static_cast<
const QKeyEvent *>(event);
812 if ((keyEvent->key() == Qt::Key_Alt || keyEvent->key() == Qt::Key_Meta)
813 && keyEvent->modifiers() == Qt::NoModifier) {
814 for (
int i = 0; i < count(); ++i) {
815 if (
auto *item = qobject_cast<QQuickMenuBarItem *>(d->itemAt(i))) {
816 d->activateItem(item);
817 setFocusReason(Qt::MenuBarFocusReason);
825 case QEvent::MouseButtonPress:
826 case QEvent::MouseButtonRelease:
827 case QEvent::MouseMove:
828 case QEvent::TabletPress:
829 case QEvent::TabletMove:
830 case QEvent::TabletRelease:
831 case QEvent::TouchBegin:
832 case QEvent::TouchUpdate:
833 case QEvent::TouchEnd:
834 case QEvent::FocusIn:
835 case QEvent::FocusOut:
836 case QEvent::ActivationChange:
837 case QEvent::Shortcut:
838 d->altPressed =
false;
839 qApp->removeEventFilter(
this);
844 }
else if (isVisible() && event->type() == QEvent::ShortcutOverride) {
845 const bool altKeyNavigation = QGuiApplicationPrivate::platformTheme()
846 ->themeHint(QPlatformTheme::MenuBarFocusOnAltPressRelease).toBool();
847 if (altKeyNavigation) {
848 const QKeyEvent *keyEvent =
static_cast<
const QKeyEvent *>(event);
849 if ((keyEvent->key() == Qt::Key_Alt || keyEvent->key() == Qt::Key_Meta)
850 && keyEvent->modifiers() == Qt::AltModifier) {
851 d->altPressed =
true;
852 qApp->installEventFilter(
this);
856 return QObject::eventFilter(object, event);
859void QQuickMenuBar::keyPressEvent(QKeyEvent *event)
862 QQuickContainer::keyReleaseEvent(event);
864 switch (event->key()) {
866 d->closeCurrentMenu();
870 d->openCurrentMenu();
871 d->activateMenuItem(0);
876 if (isMirrored() == (event->key() == Qt::Key_Left))
877 d->activateNextItem();
879 d->activatePreviousItem();
883 if (d->currentItem) {
884 d->activateItem(
nullptr);
889#if QT_CONFIG(shortcut)
890 if (!event->text().isEmpty() && event->modifiers() == Qt::NoModifier) {
891 const QKeyCombination mnemonic(Qt::AltModifier, Qt::Key(event->key()));
892 for (
int i = 0; i < count(); ++i) {
893 if (
auto *item = qobject_cast<QQuickMenuBarItem *>(d->itemAt(i))) {
894 if (item->shortcut() == mnemonic) {
895 d->activateItem(item);
896 d->openCurrentMenu();
897 d->activateMenuItem(0);
939void QQuickMenuBar::itemChange(QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData &value)
942 QQuickContainer::itemChange(change, value);
944 case ItemSceneChange:
945 if (d->windowContentItem)
946 d->windowContentItem->removeEventFilter(
this);
948 d->windowContentItem = value.window->contentItem();
949 if (d->windowContentItem)
950 d->windowContentItem->installEventFilter(
this);
953 case ItemVisibleHasChanged:
954 qCDebug(lcMenuBar) <<
"visibility of" <<
this <<
"changed to" << isVisible();
955 d->syncNativeMenuBarVisible();
962void QQuickMenuBar::itemAdded(
int index, QQuickItem *item)
965 QQuickContainer::itemAdded(index, item);
966 if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item)) {
967 QQuickMenuBarItemPrivate::get(menuBarItem)->setMenuBar(
this);
968 QObjectPrivate::connect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered);
969 QObjectPrivate::connect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered);
970 if (QQuickMenu *menu = menuBarItem->menu())
971 connect(menu, &QQuickPopup::aboutToHide,
this,
972 [
this, menu] { d_func()->onMenuAboutToHide(menu); });
974 d->updateImplicitContentSize();
984void QQuickMenuBar::itemRemoved(
int index, QQuickItem *item)
987 QQuickContainer::itemRemoved(index, item);
988 if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item)) {
989 QQuickMenuBarItemPrivate::get(menuBarItem)->setMenuBar(
nullptr);
990 QObjectPrivate::disconnect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered);
991 QObjectPrivate::disconnect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered);
992 if (QQuickMenu *menu = menuBarItem->menu())
993 menu->disconnect(
this);
995 d->updateImplicitContentSize();