65QQuickItem *QQuickMenuBarPrivate::createItemFromDelegate()
69 QQmlContext *context = delegate->creationContext();
71 context = qmlContext(q);
73 QObject *object = delegate->beginCreate(context);
74 QQuickItem *item = qobject_cast<QQuickItem *>(object);
80 QQml_setParent_noEvent(item, q);
81 delegate->completeCreate();
86QQuickMenuBarItem *QQuickMenuBarPrivate::createMenuBarItem(QQuickMenu *menu)
90 QQuickMenuBarItem *menuBarItem =
nullptr;
92 QQuickItem *item = createItemFromDelegate();
93 menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
95 qmlWarning(q) <<
"cannot insert menu: the delegate is not a MenuBarItem.";
105 qCDebug(lcMenuBar) <<
"creating hidden placeholder MenuBarItem for:" << menu->title();
106 menuBarItem =
new QQuickMenuBarItem(q);
107 menuBarItem->setParentItem(q);
108 menuBarItem->setVisible(
false);
111 menuBarItem->setMenu(menu);
116 menuBarItem->setProperty(kCreatedFromDelegate,
true);
121void QQuickMenuBarPrivate::openCurrentMenu()
123 if (!currentItem || currentMenuOpen)
125 QQuickMenu *menu = currentItem->menu();
126 if (!menu || menu->isOpened())
132 const QPointF posInParentItem = q->mapToItem(currentItem, {currentItem->x(), q->height()});
135 const QPointF posInParentItem{0, currentItem->y() + currentItem->height()};
142 currentMenuOpen =
true;
147 menu->popup(posInParentItem);
150void QQuickMenuBarPrivate::closeCurrentMenu()
152 if (!currentItem || !currentMenuOpen)
154 currentMenuOpen =
false;
155 QQuickMenu *menu = currentItem->menu();
156 QScopedValueRollback triggerRollback(closingCurrentMenu,
true);
191void QQuickMenuBarPrivate::activateNextItem()
193 int index = currentItem ? contentModel->indexOf(currentItem,
nullptr) : -1;
194 if (index >= contentModel->count() - 1)
196 activateItem(qobject_cast<QQuickMenuBarItem *>(itemAt(++index)));
199void QQuickMenuBarPrivate::activatePreviousItem()
201 int index = currentItem ? contentModel->indexOf(currentItem,
nullptr) : contentModel->count();
203 index = contentModel->count();
204 activateItem(qobject_cast<QQuickMenuBarItem *>(itemAt(--index)));
256qreal QQuickMenuBarPrivate::getContentWidth()
const
258 Q_Q(
const QQuickMenuBar);
259 const int count = contentModel->count();
260 qreal totalWidth = qMax(0, count - 1) * spacing;
261 for (
int i = 0; i < count; ++i) {
262 QQuickItem *item = q->itemAt(i);
264 totalWidth += item->implicitWidth();
269qreal QQuickMenuBarPrivate::getContentHeight()
const
271 Q_Q(
const QQuickMenuBar);
272 const int count = contentModel->count();
274 for (
int i = 0; i < count; ++i) {
275 QQuickItem *item = q->itemAt(i);
277 maxHeight = qMax(maxHeight, item->implicitHeight());
296void QQuickMenuBarPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
298 auto menuBar =
static_cast<QQuickMenuBar *>(prop->object);
299 auto menuBarPriv = QQuickMenuBarPrivate::get(menuBar);
301 if (
auto *menu = qobject_cast<QQuickMenu *>(obj)) {
302 QQuickMenuBarItem *delegateItem = menuBarPriv->createMenuBarItem(menu);
303 menuBarPriv->insertMenu(menuBar->count(), menu, delegateItem);
304 QQuickContainerPrivate::contentData_append(prop, delegateItem);
308 if (
auto *menuBarItem = qobject_cast<QQuickMenuBarItem *>(obj)) {
309 menuBarPriv->insertMenu(menuBar->count(), menuBarItem->menu(), menuBarItem);
310 QQuickContainerPrivate::contentData_append(prop, menuBarItem);
314 QQuickContainerPrivate::contentData_append(prop, obj);
383void QQuickMenuBarPrivate::insertNativeMenu(QQuickMenu *menu)
389 QPlatformMenu *insertBeforeHandle =
nullptr;
396 bool foundInContainer =
false;
397 for (
int i = 0; i < q->count(); ++i) {
398 if (q->menuAt(i) != menu)
400 foundInContainer =
true;
402 for (
int j = i + 1; j < q->count(); ++j) {
403 insertBeforeHandle = QQuickMenuPrivate::get(q->menuAt(j))->maybeNativeHandle();
404 if (insertBeforeHandle)
411 Q_ASSERT(foundInContainer);
412 QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
413 if (QPlatformMenu *menuHandle = menuPrivate->nativeHandle()) {
414 qCDebug(lcMenuBar) <<
"insert native menu:" << menu->title() << menuHandle <<
"before:" << insertBeforeHandle;
415 handle->insertMenu(menuPrivate->nativeHandle(), insertBeforeHandle);
417 qmlWarning(q) <<
"failed to create native menu for:" << menu->title();
421void QQuickMenuBarPrivate::removeNativeMenu(QQuickMenu *menu)
426 QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
427 if (!menuPrivate->maybeNativeHandle())
430 qCDebug(lcMenuBar) <<
"remove native menu:" << menu << menu->title();
431 handle->removeMenu(menuPrivate->nativeHandle());
432 menuPrivate->removeNativeMenu();
435void QQuickMenuBarPrivate::syncMenuBarItemVisibilty(QQuickMenuBarItem *menuBarItem)
442 QQuickMenu *menu = menuBarItem->menu();
445 QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
447 if (menuBarItem->isVisible()) {
448 Q_ASSERT(!menuPrivate->maybeNativeHandle());
449 insertNativeMenu(menu);
451 if (menuPrivate->maybeNativeHandle())
452 removeNativeMenu(menu);
456void QQuickMenuBarPrivate::insertMenu(
int index, QQuickMenu *menu, QQuickMenuBarItem *menuBarItem)
460 qmlWarning(q) <<
"cannot insert menu: menu is null.";
464 auto menuPrivate = QQuickMenuPrivate::get(menu);
465 menuPrivate->menuBar = q;
467 QObject::connect(menuBarItem, &QQuickMenuBarItem::visibleChanged, [
this, menuBarItem]{
468 syncMenuBarItemVisibilty(menuBarItem);
474 q->insertItem(index, menuBarItem);
478 if (menuBarItem->isVisible()) {
480 insertNativeMenu(menu);
482 if (menuPrivate->maybeNativeHandle()) {
488 menuPrivate->removeNativeMenu();
493QQuickMenu *QQuickMenuBarPrivate::takeMenu(
int index)
496 QQuickItem *item = q->itemAt(index);
498 QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
500 qmlWarning(q) <<
"cannot take/remove menu: item at index " << index <<
" is not a MenuBarItem.";
503 QQuickMenu *menu = menuBarItem->menu();
505 qmlWarning(q) <<
"cannot take/remove menu: MenuBarItem.menu at index " << index <<
" is null.";
514 if (item == currentItem)
515 activateItem(
nullptr);
517 if (QQuickMenuPrivate::get(menu)->maybeNativeHandle())
518 removeNativeMenu(menu);
520 removeItem(index, item);
528 QQuickMenuPrivate::get(menu)->menuBar =
nullptr;
529 menuBarItem->disconnect(q);
578void QQuickMenuBarPrivate::createNativeMenuBar()
582 qCDebug(lcMenuBar) <<
"creating native menubar";
584 handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar());
586 qCDebug(lcMenuBar) <<
"QPlatformTheme failed to create a QPlatformMenuBar!";
590 handle->handleReparent(window());
591 qCDebug(lcMenuBar) <<
"native menubar parented to window:" << handle->parentWindow();
595 for (
int i = q->count() - 1; i >= 0; --i) {
596 if (QQuickMenu *menu = q->menuAt(i)) {
597 if (useNativeMenu(menu))
598 insertNativeMenu(menu);
631QQuickMenuBar::QQuickMenuBar(QQuickItem *parent)
632 : QQuickContainer(*(
new QQuickMenuBarPrivate), parent)
635 d->changeTypes |= QQuickItemPrivate::Geometry;
636 setFlag(ItemIsFocusScope);
637 setFocusPolicy(Qt::ClickFocus);
663void QQuickMenuBar::setDelegate(QQmlComponent *delegate)
666 if (d->delegate == delegate)
669 d->delegate = delegate;
671 for (
int i = count() - 1; i >= 0; --i) {
672 auto item = itemAt(i);
673 if (!item || !item->property(kCreatedFromDelegate).toBool())
676 QQuickMenuBarItem *menuBarItem =
static_cast<QQuickMenuBarItem *>(item);
677 if (QQuickMenu *menu = menuBarItem->menu()) {
679 d->insertMenu(i, menu, d->createMenuBarItem(menu));
681 removeItem(menuBarItem);
685 emit delegateChanged();
809QQmlListProperty<QQuickMenu> QQuickMenuBarPrivate::menus()
812 return QQmlListProperty<QQuickMenu>(q,
nullptr,
813 QQuickMenuBarPrivate::menus_append,
814 QQuickMenuBarPrivate::menus_count,
815 QQuickMenuBarPrivate::menus_at,
816 QQuickMenuBarPrivate::menus_clear);
819QQmlListProperty<QObject> QQuickMenuBarPrivate::contentData()
822 return QQmlListProperty<QObject>(q,
nullptr,
823 QQuickMenuBarPrivate::contentData_append,
824 QQuickContainerPrivate::contentData_count,
825 QQuickContainerPrivate::contentData_at,
826 QQuickContainerPrivate::contentData_clear);
829bool QQuickMenuBar::eventFilter(QObject *object, QEvent *event)
834 switch (event->type()) {
835 case QEvent::KeyRelease: {
836 const QKeyEvent *keyEvent =
static_cast<
const QKeyEvent *>(event);
837 if ((keyEvent->key() == Qt::Key_Alt || keyEvent->key() == Qt::Key_Meta)
838 && keyEvent->modifiers() == Qt::NoModifier) {
839 for (
int i = 0; i < count(); ++i) {
840 if (
auto *item = qobject_cast<QQuickMenuBarItem *>(d->itemAt(i))) {
841 d->activateItem(item);
842 setFocusReason(Qt::MenuBarFocusReason);
850 case QEvent::MouseButtonPress:
851 case QEvent::MouseButtonRelease:
852 case QEvent::MouseMove:
853 case QEvent::TabletPress:
854 case QEvent::TabletMove:
855 case QEvent::TabletRelease:
856 case QEvent::TouchBegin:
857 case QEvent::TouchUpdate:
858 case QEvent::TouchEnd:
859 case QEvent::FocusIn:
860 case QEvent::FocusOut:
861 case QEvent::ActivationChange:
862 case QEvent::Shortcut:
863 d->altPressed =
false;
864 qApp->removeEventFilter(
this);
869 }
else if (isVisible() && event->type() == QEvent::ShortcutOverride) {
870 const bool altKeyNavigation = QGuiApplicationPrivate::platformTheme()
871 ->themeHint(QPlatformTheme::MenuBarFocusOnAltPressRelease).toBool();
872 if (altKeyNavigation) {
873 const QKeyEvent *keyEvent =
static_cast<
const QKeyEvent *>(event);
874 if ((keyEvent->key() == Qt::Key_Alt || keyEvent->key() == Qt::Key_Meta)
875 && keyEvent->modifiers() == Qt::AltModifier) {
876 d->altPressed =
true;
877 qApp->installEventFilter(
this);
881 return QObject::eventFilter(object, event);
884void QQuickMenuBar::keyPressEvent(QKeyEvent *event)
887 QQuickContainer::keyReleaseEvent(event);
889 switch (event->key()) {
891 d->closeCurrentMenu();
895 d->openCurrentMenu();
896 d->activateMenuItem(0);
901 if (isMirrored() == (event->key() == Qt::Key_Left))
902 d->activateNextItem();
904 d->activatePreviousItem();
908 if (d->currentItem) {
909 d->activateItem(
nullptr);
914#if QT_CONFIG(shortcut)
915 if (!event->text().isEmpty() && event->modifiers() == Qt::NoModifier) {
916 const QKeyCombination mnemonic(Qt::AltModifier, Qt::Key(event->key()));
917 for (
int i = 0; i < count(); ++i) {
918 if (
auto *item = qobject_cast<QQuickMenuBarItem *>(d->itemAt(i))) {
919 if (item->shortcut() == mnemonic) {
920 d->activateItem(item);
921 d->openCurrentMenu();
922 d->activateMenuItem(0);
964void QQuickMenuBar::itemChange(QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData &value)
967 QQuickContainer::itemChange(change, value);
969 case ItemSceneChange:
970 if (d->windowContentItem)
971 d->windowContentItem->removeEventFilter(
this);
973 d->windowContentItem = value.window->contentItem();
974 if (d->windowContentItem)
975 d->windowContentItem->installEventFilter(
this);
978 case ItemVisibleHasChanged:
979 qCDebug(lcMenuBar) <<
"visibility of" <<
this <<
"changed to" << isVisible();
980 d->syncNativeMenuBarVisible();
987void QQuickMenuBar::itemAdded(
int index, QQuickItem *item)
990 QQuickContainer::itemAdded(index, item);
991 if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item)) {
992 QQuickMenuBarItemPrivate::get(menuBarItem)->setMenuBar(
this);
993 QObjectPrivate::connect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered);
994 QObjectPrivate::connect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered);
995 if (QQuickMenu *menu = menuBarItem->menu())
996 connect(menu, &QQuickPopup::aboutToHide, [
this, menu]{ d_func()->onMenuAboutToHide(menu); });
998 d->updateImplicitContentSize();
1008void QQuickMenuBar::itemRemoved(
int index, QQuickItem *item)
1011 QQuickContainer::itemRemoved(index, item);
1012 if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item)) {
1013 QQuickMenuBarItemPrivate::get(menuBarItem)->setMenuBar(
nullptr);
1014 QObjectPrivate::disconnect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered);
1015 QObjectPrivate::disconnect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered);
1016 if (QQuickMenu *menu = menuBarItem->menu())
1017 menu->disconnect(
this);
1019 d->updateImplicitContentSize();
1020 emit menusChanged();