8#include <private/qtquicktemplates2-config_p.h>
9#if QT_CONFIG(quicktemplates2_container)
10#include "qquickmenubaritem_p.h"
11#include "qquickmenubar_p_p.h"
21#include <QtCore/qloggingcategory.h>
22#include <QtGui/qevent.h>
23#include <QtGui/qcursor.h>
24#if QT_CONFIG(shortcut)
25#include <QtGui/qkeysequence.h>
27#include <QtGui/qpa/qplatformintegration.h>
28#include <QtGui/qpa/qplatformtheme.h>
29#include <QtGui/private/qhighdpiscaling_p.h>
30#include <QtGui/private/qguiapplication_p.h>
31#include <QtQml/qqmlcontext.h>
32#include <QtQml/qqmlcomponent.h>
33#include <QtQml/private/qqmlengine_p.h>
34#include <QtQml/private/qqmldata_p.h>
35#include <QtQml/private/qv4scopedvalue_p.h>
36#include <QtQml/private/qv4variantobject_p.h>
37#include <QtQml/private/qv4qobjectwrapper_p.h>
38#include <private/qqmlobjectmodel_p.h>
39#include <QtQuick/private/qquickitem_p.h>
40#include <QtQuick/private/qquickitemchangelistener_p.h>
41#include <QtQuick/private/qquickitemview_p_p.h>
42#include <QtQuick/private/qquickevents_p_p.h>
43#include <QtQuick/private/qquicklistview_p.h>
44#include <QtQuick/private/qquickrendercontrol_p.h>
45#include <QtQuick/private/qquickwindow_p.h>
49Q_STATIC_LOGGING_CATEGORY(lcMenu,
"qt.quick.controls.menu")
50Q_STATIC_LOGGING_CATEGORY(lcNativeMenus,
"qt.quick.controls.nativemenus")
53static const int SUBMENU_DELAY = 225;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
254
255
256
257
258
259
260
261
262
263
264
265
266
267
274 return QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::MultipleWindows);
288QQuickMenuPrivate::QQuickMenuPrivate()
290 cascade = shouldCascade();
291#if QT_CONFIG(wayland)
292 extendedWindowType = QNativeInterface::Private::QWaylandWindow::Menu;
295 wmWindowType = QNativeInterface::Private::QXcbWindow::PopupMenu;
299void QQuickMenuPrivate::init()
302 contentModel =
new QQmlObjectModel(q);
305QQuickMenu *QQuickMenuPrivate::rootMenu()
const
307 Q_Q(
const QQuickMenu);
308 const QQuickMenu *rootMenu = q;
309 const QObject *p = q->parent();
311 if (
auto menu = qobject_cast<
const QQuickMenu *>(p))
316 return const_cast<QQuickMenu *>(rootMenu);
319QQuickPopup::PopupType QQuickMenuPrivate::resolvedPopupType()
const
323 QQuickMenu *root = rootMenu();
324 QQuickMenuPrivate *root_d = QQuickMenuPrivate::get(rootMenu());
326#if QT_CONFIG(quicktemplates2_container)
327 if (
auto menuBar = QQuickMenuPrivate::get(root)->menuBar.get()) {
332 if (QQuickMenuBarPrivate::get(menuBar)->useNativeMenu(q_func()))
333 return QQuickPopup::Native;
338 if (root_d->maybeNativeHandle()) {
339 return QQuickPopup::Native;
340 }
else if (!root_d->triedToCreateNativeMenu) {
346 if (root->popupType() == QQuickPopup::Native
347 && !QGuiApplication::testAttribute(Qt::AA_DontUseNativeMenuWindows)) {
348 return QQuickPopup::Native;
356 const auto type = root_d->QQuickPopupPrivate::resolvedPopupType();
357 Q_ASSERT(type != QQuickPopup::Native);
361bool QQuickMenuPrivate::useNativeMenu()
const
363 return resolvedPopupType() == QQuickPopup::Native;
366QPlatformMenu *QQuickMenuPrivate::nativeHandle()
368 Q_ASSERT(handle || useNativeMenu());
369 if (!handle && !triedToCreateNativeMenu)
374QPlatformMenu *QQuickMenuPrivate::maybeNativeHandle()
const
379bool QQuickMenuPrivate::createNativeMenu()
383 qCDebug(lcNativeMenus) <<
"createNativeMenu called on" << q;
385 if (
auto menuBar = QQuickMenuPrivate::get(rootMenu())->menuBar) {
386#if QT_CONFIG(quicktemplates2_container)
387 auto menuBarPrivate = QQuickMenuBarPrivate::get(menuBar);
388 if (menuBarPrivate->useNativeMenuBar()) {
389 qCDebug(lcNativeMenus) <<
"- creating native menu from native menubar";
390 if (QPlatformMenuBar *menuBarHandle = menuBarPrivate->nativeHandle())
391 handle.reset(menuBarHandle->createMenu());
397 QPlatformMenu *parentMenuHandle(parentMenu ? get(parentMenu)->handle.get() :
nullptr);
398 if (parentMenu && parentMenuHandle) {
399 qCDebug(lcNativeMenus) <<
"- creating native sub-menu";
400 handle.reset(parentMenuHandle->createSubMenu());
402 qCDebug(lcNativeMenus) <<
"- creating native menu";
403 handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformMenu());
407 triedToCreateNativeMenu =
true;
412 q->connect(handle.get(), &QPlatformMenu::aboutToShow, q, [q,
this](){
413 emit q->aboutToShow();
415 emit q->visibleChanged();
416 emit q->openedChanged();
419 q->connect(handle.get(), &QPlatformMenu::aboutToHide, q, [q](){
420 qCDebug(lcNativeMenus) <<
"QPlatformMenu::aboutToHide called; about to call setVisible(false) on Menu";
421 emit q->aboutToHide();
427 q->connect(handle.get(), &QPlatformMenu::aboutToHide, q, [q,
this](){
429 emit q->visibleChanged();
430 emit q->openedChanged();
432 }, Qt::QueuedConnection);
434 recursivelyCreateNativeMenuItems(q);
435 syncWithNativeMenu();
442 if (nativeItems.isEmpty())
443 return QStringLiteral(
"(Empty)");
446 QTextStream debug(&str);
447 for (
const auto *nativeItem : nativeItems)
448 debug << nativeItem->debugText() <<
", ";
450 if (!nativeItems.isEmpty())
455void QQuickMenuPrivate::syncWithNativeMenu()
458 if (!complete || !handle)
461 qCDebug(lcNativeMenus).nospace() <<
"syncWithNativeMenu called on " << q
462 <<
" (complete: " << complete <<
" visible: " << visible <<
") - "
463 <<
"syncing " << nativeItems.size() <<
" item(s)...";
467 handle->setText(title);
468 handle->setEnabled(q->isEnabled());
469 handle->setMinimumWidth(q->implicitWidth());
471 handle->setFont(q->font());
489 for (QQuickNativeMenuItem *item : std::as_const(nativeItems)) {
490 qCDebug(lcNativeMenus) <<
"- syncing" << item <<
"action" << item->action()
491 <<
"sub-menu" << item->subMenu() << item->debugText();
495 qCDebug(lcNativeMenus) <<
"... finished syncing" << q;
499
500
501
502
503
504
505
506void QQuickMenuPrivate::removeNativeMenu()
509 const int qtyItemsToRemove = nativeItems.size();
510 if (qtyItemsToRemove != 0)
511 Q_ASSERT(q->count() == qtyItemsToRemove);
512 for (
int i = 0; i < qtyItemsToRemove; ++i)
514 Q_ASSERT(nativeItems.isEmpty());
521void QQuickMenuPrivate::syncWithUseNativeMenu()
526 if (q->isVisible() || parentMenu)
529 if (maybeNativeHandle() && !useNativeMenu()) {
533 }
else if (useNativeMenu()) {
534 Q_ASSERT(nativeItems.isEmpty());
542 QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(window);
544 QWindow *renderWindow = QQuickRenderControl::renderWindowFor(quickWindow, offset);
551void QQuickMenuPrivate::setNativeMenuVisible(
bool visible)
554 qCDebug(lcNativeMenus) <<
"setNativeMenuVisible called with visible" << visible;
556 emit q->aboutToShow();
558 emit q->aboutToHide();
560 this->visible = visible;
561 syncWithNativeMenu();
565 QWindow *window =
nullptr;
567 window = effectiveWindow(parentItem->window(), &offset);
569 lastDevicePixelRatio = window ? window->devicePixelRatio() : qGuiApp->devicePixelRatio();
571 const QPointF globalPos = parentItem->mapToGlobal(x, y);
572 const QPoint windowPos = window ? window->mapFromGlobal(globalPos.toPoint()) : parentItem->mapToScene(QPoint(x, y)).toPoint();
573 QRect targetRect(windowPos, QSize(0, 0));
574 auto *daPriv = QQuickItemPrivate::get(parentItem)->deliveryAgentPrivate();
581 if (QPointerEvent *openingEvent = daPriv->eventInDelivery()) {
582 auto *devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(openingEvent->pointingDevice()));
583 for (
const auto &pt : std::as_const(openingEvent->points())) {
584 qCDebug(lcNativeMenus) <<
"popup over" << window <<
"its DA" << daPriv->q_func() <<
"opening due to" << openingEvent
585 <<
"with grabbers" << openingEvent->exclusiveGrabber(pt) << openingEvent->passiveGrabbers(pt);
587 if (
auto *opener = openingEvent->exclusiveGrabber(pt))
588 devPriv->removeGrabber(opener,
true);
589 for (
auto passiveGrabber : openingEvent->passiveGrabbers(pt)) {
590 if (
auto *opener = passiveGrabber.get())
591 devPriv->removeGrabber(opener,
true);
595 handle->showPopup(window, QHighDpi::toNativeLocalPosition(targetRect, window),
603void QQuickMenuPrivate::makeEditMenu()
605 handle->setMenuType(QPlatformMenu::EditMenu);
608QQuickItem *QQuickMenuPrivate::itemAt(
int index)
const
610 return qobject_cast<QQuickItem *>(contentModel->get(index));
613void QQuickMenuPrivate::insertItem(
int index, QQuickItem *item)
615 qCDebug(lcMenu) <<
"insert called with index" << index <<
"item" << item;
618 contentData.append(item);
619 item->setParentItem(contentItem);
620 QQuickItemPrivate::get(item)->setCulled(
true);
623 QQuickItemPrivate::get(item)->addItemChangeListener(
this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent | QQuickItemPrivate::ImplicitWidth);
624 QQuickItemPrivate::get(item)->updateOrAddGeometryChangeListener(
this, QQuickGeometryChange::Width);
625 contentModel->insert(index, item);
627 QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
629 QQuickMenuItemPrivate::get(menuItem)->setMenu(q);
630 if (QQuickMenu *subMenu = menuItem->subMenu())
631 QQuickMenuPrivate::get(subMenu)->setParentMenu(q);
632 QObjectPrivate::connect(menuItem, &QQuickMenuItem::triggered,
this, &QQuickMenuPrivate::onItemTriggered);
633 QObjectPrivate::connect(menuItem, &QQuickMenuItem::implicitTextPaddingChanged,
this, &QQuickMenuPrivate::updateTextPadding);
634 QObjectPrivate::connect(menuItem, &QQuickMenuItem::visibleChanged,
this, &QQuickMenuPrivate::onItemVisibleChanged);
635 QObjectPrivate::connect(menuItem, &QQuickItem::activeFocusChanged,
this, &QQuickMenuPrivate::onItemActiveFocusChanged);
636 QObjectPrivate::connect(menuItem, &QQuickControl::hoveredChanged,
this, &QQuickMenuPrivate::onItemHovered);
639 QQuickMenuSeparator *separator = qobject_cast<QQuickMenuSeparator *>(item);
641 QObjectPrivate::connect(separator, &QQuickMenuSeparator::visibleChanged,
this, &QQuickMenuPrivate::updateCollapsedSeparators);
643 if (maybeNativeHandle() && complete)
644 maybeCreateAndInsertNativeItem(index, item);
646 if (lcMenu().isDebugEnabled())
647 printContentModelItems();
650 updateContentWidth();
652 updateCollapsedSeparators();
655void QQuickMenuPrivate::maybeCreateAndInsertNativeItem(
int index, QQuickItem *item)
659 Q_ASSERT_X(handle, Q_FUNC_INFO, qPrintable(QString::fromLatin1(
660 "Expected %1 to be using a native menu").arg(QDebug::toString(q))));
661 std::unique_ptr<QQuickNativeMenuItem> nativeMenuItem(QQuickNativeMenuItem::createFromNonNativeItem(q, item));
662 if (!nativeMenuItem) {
664 qmlWarning(q) <<
"Native menu failed to create a native menu item for item at index" << index;
668 nativeItems.insert(index, nativeMenuItem.get());
672 if (nativeMenuItem->handle()) {
673 QQuickNativeMenuItem *before = nativeItems.value(index + 1);
674 handle->insertMenuItem(nativeMenuItem->handle(), before ? before->handle() :
nullptr);
675 qCDebug(lcNativeMenus) <<
"inserted native menu item at index" << index
676 <<
"before" << (before ? before->debugText() : QStringLiteral(
"null"));
678 if (nativeMenuItem->subMenu() && QQuickMenuPrivate::get(nativeMenuItem->subMenu())->nativeItems.count()
679 < nativeMenuItem->subMenu()->count()) {
685 recursivelyCreateNativeMenuItems(nativeMenuItem->subMenu());
689 nativeMenuItem.release();
691 qCDebug(lcNativeMenus) <<
"nativeItems now contains the following items:"
692 << nativeMenuItemListToString(nativeItems);
695void QQuickMenuPrivate::moveItem(
int from,
int to)
697 contentModel->move(from, to);
699 if (maybeNativeHandle())
700 nativeItems.move(from, to);
704
705
706
707
708
709
710
711
712
713void QQuickMenuPrivate::removeItem(
int index, QQuickItem *item, DestructionPolicy destructionPolicy)
715 qCDebug(lcMenu) <<
"removeItem called with index" << index <<
"item" << item;
717 if (maybeNativeHandle())
718 removeNativeItem(index);
720 contentData.removeOne(item);
722 QQuickItemPrivate::get(item)->removeItemChangeListener(
this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent | QQuickItemPrivate::ImplicitWidth);
723 QQuickItemPrivate::get(item)->removeItemChangeListener(
this, QQuickItemPrivate::Geometry);
724 item->setParentItem(
nullptr);
725 contentModel->remove(index);
727 QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
729 QQuickMenuItemPrivate::get(menuItem)->setMenu(
nullptr);
730 if (QQuickMenu *subMenu = menuItem->subMenu())
731 QQuickMenuPrivate::get(subMenu)->setParentMenu(
nullptr);
732 QObjectPrivate::disconnect(menuItem, &QQuickMenuItem::triggered,
this, &QQuickMenuPrivate::onItemTriggered);
733 QObjectPrivate::disconnect(menuItem, &QQuickMenuItem::implicitTextPaddingChanged,
this, &QQuickMenuPrivate::updateTextPadding);
734 QObjectPrivate::disconnect(menuItem, &QQuickMenuItem::visibleChanged,
this, &QQuickMenuPrivate::onItemVisibleChanged);
735 QObjectPrivate::disconnect(menuItem, &QQuickItem::activeFocusChanged,
this, &QQuickMenuPrivate::onItemActiveFocusChanged);
736 QObjectPrivate::disconnect(menuItem, &QQuickControl::hoveredChanged,
this, &QQuickMenuPrivate::onItemHovered);
739 QQuickMenuSeparator *separator = qobject_cast<QQuickMenuSeparator *>(item);
741 QObjectPrivate::disconnect(separator, &QQuickMenuSeparator::visibleChanged,
this, &QQuickMenuPrivate::updateCollapsedSeparators);
742 collapsedSeparators.remove(item);
745 if (destructionPolicy == DestructionPolicy::Destroy)
748 if (lcMenu().isDebugEnabled())
749 printContentModelItems();
751 updateContentWidth();
753 updateCollapsedSeparators();
757
758
759
760
761
762
763
764
765
766void QQuickMenuPrivate::removeNativeItem(
int index, SyncPolicy syncPolicy)
771 Q_ASSERT_X(index >= 0 && index < nativeItems.size(), Q_FUNC_INFO, qPrintable(QString::fromLatin1(
772 "index %1 is less than 0 or greater than or equal to %2").arg(index).arg(nativeItems.size())));
776 std::unique_ptr<QQuickNativeMenuItem> nativeItem(nativeItems.takeAt(index));
777 qCDebug(lcNativeMenus) <<
"removing native item" << nativeItem->debugText() <<
"at index" << index
778 <<
"from" << q_func() <<
"...";
779 QQuickMenu *subMenu = nativeItem->subMenu();
781 Q_ASSERT(nativeItem->handle());
782 auto *subMenuPrivate = QQuickMenuPrivate::get(subMenu);
783 while (!subMenuPrivate->nativeItems.isEmpty()) {
784 subMenuPrivate->removeNativeItem(0, SyncPolicy::DoNotSync);
788 Q_ASSERT(nativeItem->handle());
789 handle->removeMenuItem(nativeItem->handle());
790 if (syncPolicy == SyncPolicy::Sync)
791 syncWithNativeMenu();
794 auto *subMenuPrivate = QQuickMenuPrivate::get(subMenu);
800 subMenuPrivate->resetNativeData();
803 qCDebug(lcNativeMenus).nospace() <<
"... after removing item at index " << index
804 <<
", nativeItems now contains the following items: " << nativeMenuItemListToString(nativeItems);
807void QQuickMenuPrivate::resetNativeData()
809 qCDebug(lcNativeMenus) <<
"resetNativeData called on" << q_func();
811 triedToCreateNativeMenu =
false;
814void QQuickMenuPrivate::recursivelyCreateNativeMenuItems(QQuickMenu *menu)
816 auto *menuPrivate = QQuickMenuPrivate::get(menu);
819 if (!menuPrivate->triedToCreateNativeMenu)
820 menuPrivate->createNativeMenu();
822 const int qtyItemsToCreate = menuPrivate->contentModel->count();
823 if (menuPrivate->nativeItems.count() == qtyItemsToCreate)
826 qCDebug(lcNativeMenus) <<
"recursively creating" << qtyItemsToCreate <<
"menu item(s) for" << menu;
827 Q_ASSERT(menuPrivate->nativeItems.count() == 0);
828 for (
int i = 0; i < qtyItemsToCreate; ++i) {
829 QQuickItem *item = menu->itemAt(i);
830 menuPrivate->maybeCreateAndInsertNativeItem(i, item);
831 auto *menuItem = qobject_cast<QQuickMenuItem *>(item);
832 if (menuItem && menuItem->subMenu())
833 recursivelyCreateNativeMenuItems(menuItem->subMenu());
837void QQuickMenuPrivate::printContentModelItems()
const
839 qCDebug(lcMenu) <<
"contentModel now contains:";
840 for (
int i = 0; i < contentModel->count(); ++i)
841 qCDebug(lcMenu) <<
"-" << itemAt(i);
844QQuickItem *QQuickMenuPrivate::beginCreateItem()
850 QQmlContext *context = delegate->creationContext();
852 context = qmlContext(q);
854 QObject *object = delegate->beginCreate(context);
855 QQuickItem *item = qobject_cast<QQuickItem *>(object);
859 QQml_setParent_noEvent(item, q);
864void QQuickMenuPrivate::completeCreateItem()
869 delegate->completeCreate();
872QQuickItem *QQuickMenuPrivate::createItem(QQuickMenu *menu)
874 QQuickItem *item = beginCreateItem();
875 if (QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item))
876 QQuickMenuItemPrivate::get(menuItem)->setSubMenu(menu);
877 completeCreateItem();
881QQuickItem *QQuickMenuPrivate::createItem(QQuickAction *action)
883 QQuickItem *item = beginCreateItem();
884 if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(item))
885 button->setAction(action);
886 completeCreateItem();
890void QQuickMenuPrivate::resizeItem(QQuickItem *item)
892 if (!item || !contentItem)
895 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
896 if (!p->widthValid()) {
897 item->setWidth(contentItem->width());
898 p->widthValidFlag =
false;
902void QQuickMenuPrivate::resizeItems()
907 for (
int i = 0; i < contentModel->count(); ++i)
908 resizeItem(itemAt(i));
911void QQuickMenuPrivate::itemChildAdded(QQuickItem *, QQuickItem *child)
914 if (!QQuickItemPrivate::get(child)->isTransparentForPositioner() && !contentData.contains(child))
915 insertItem(contentModel->count(), child);
918void QQuickMenuPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent)
922 removeItem(contentModel->indexOf(item,
nullptr), item);
925void QQuickMenuPrivate::itemSiblingOrderChanged(QQuickItem *)
929 QList<QQuickItem *> siblings = contentItem->childItems();
932 for (
int i = 0; i < siblings.size(); ++i) {
933 QQuickItem* sibling = siblings.at(i);
934 if (QQuickItemPrivate::get(sibling)->isTransparentForPositioner())
936 int index = contentModel->indexOf(sibling,
nullptr);
937 q->moveItem(index, to++);
941void QQuickMenuPrivate::itemDestroyed(QQuickItem *item)
943 if (item == contentItem) {
946 QQuickPopupPrivate::itemDestroyed(item);
948 int index = contentModel->indexOf(item,
nullptr);
950 removeItem(index, item);
955void QQuickMenuPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange,
const QRectF &)
960 if (item == contentItem) {
971void QQuickMenuPrivate::itemImplicitWidthChanged(QQuickItem *item)
973 if (item != contentItem)
974 updateContentWidth();
977void QQuickMenuPrivate::updateContentWidth()
979 if (!contentModel || !contentItem)
984 for (
int i = 0; i < contentModel->count(); ++i) {
985 QQuickItem *item = q->itemAt(i);
986 if (item && QQuickItemPrivate::get(item)->explicitVisible)
987 maxWidth = qMax(maxWidth, item->implicitWidth());
993 if (!qFuzzyIsNull(maxWidth))
994 contentItem->setImplicitWidth(maxWidth);
997QQuickPopupPositioner *QQuickMenuPrivate::getPositioner()
1001 positioner =
new QQuickMenuPositioner(q);
1007 QQuickMenu *menu =
static_cast<QQuickMenu *>(popup());
1008 QQuickMenuPrivate *menu_d = QQuickMenuPrivate::get(menu);
1010 if (QQuickMenu *parentMenu = menu_d->parentMenu) {
1011 if (menu_d->cascade) {
1014 if (menu_d->popupItem->isMirrored()) {
1015 const qreal distanceToFrame = parentMenu->leftPadding();
1016 const qreal menuX = -menu->width() - distanceToFrame + menu->overlap();
1017 menu->setPosition({menuX, -menu->topPadding()});
1018 }
else if (menu_d->parentItem) {
1019 const qreal distanceToFrame = parentMenu->rightPadding();
1020 const qreal menuX = menu_d->parentItem->width() + distanceToFrame - menu->overlap();
1021 menu->setPosition({menuX, -menu->topPadding()});
1024 const qreal menuX = parentMenu->x() + (parentMenu->width() - menu->width()) / 2;
1025 const qreal menuY = parentMenu->y() + (parentMenu->height() - menu->height()) / 2;
1026 menu->setPosition({menuX, menuY});
1030 QQuickPopupPositioner::reposition();
1033bool QQuickMenuPrivate::prepareEnterTransition()
1036 if (parentMenu && !cascade)
1037 parentMenu->close();
1041 allowHorizontalFlip = cascade && parentMenu;
1043 updateCollapsedSeparators();
1055 auto *contentItemAsListView = qobject_cast<QQuickListView *>(contentItem);
1056 if (contentItemAsListView) {
1057 if (QQuickItemViewPrivate::get(contentItemAsListView)->currentChanges.hasPendingChanges())
1058 contentItemAsListView->forceLayout();
1061 if (!QQuickPopupPrivate::prepareEnterTransition())
1064 if (!hasClosePolicy) {
1065 if (cascade && parentMenu)
1066 closePolicy = cascadingSubMenuClosePolicy;
1068 q->resetClosePolicy();
1073bool QQuickMenuPrivate::prepareExitTransition()
1075 if (!QQuickPopupPrivate::prepareExitTransition())
1080 QQuickMenu *subMenu = currentSubMenu();
1082 QPointer<QQuickMenuItem> currentSubMenuItem = QQuickMenuPrivate::get(subMenu)->currentItem;
1084 subMenu = currentSubMenuItem ? currentSubMenuItem->subMenu() :
nullptr;
1089bool QQuickMenuPrivate::blockInput(QQuickItem *item,
const QPointF &point)
const
1092 return (cascade && parentMenu && contains(point)) || QQuickPopupPrivate::blockInput(item, point);
1095bool QQuickMenuPrivate::handlePress(QQuickItem *item,
const QPointF &point, ulong timestamp)
1099 return QQuickPopupPrivate::handlePress(item, point, timestamp)
1100 || (popupItem == item);
1105
1106
1107
1108
1109
1110
1111bool QQuickMenuPrivate::handleReleaseWithoutGrab(
const QEventPoint &eventPoint)
1113 const QPointF scenePos = eventPoint.scenePosition();
1114 if (!contains(scenePos))
1117 auto *list = qobject_cast<QQuickListView *>(contentItem);
1121 const QPointF listPos = list->mapFromScene(scenePos);
1123 auto *menuItem = qobject_cast<QQuickMenuItem *>(list->itemAt(listPos.x(), listPos.y()));
1124 if (menuItem && menuItem->isHighlighted()) {
1125 menuItem->animateClick();
1132void QQuickMenuPrivate::onItemHovered()
1135 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->sender());
1136 if (!button || !button->isHovered() || !button->isEnabled() || QQuickAbstractButtonPrivate::get(button)->touchId != -1)
1139 QQuickMenuItem *oldCurrentItem = currentItem;
1141 int index = contentModel->indexOf(button,
nullptr);
1143 setCurrentIndex(index, Qt::OtherFocusReason);
1144 if (oldCurrentItem != currentItem) {
1145 if (oldCurrentItem) {
1146 QQuickMenu *subMenu = oldCurrentItem->subMenu();
1151 QQuickMenu *subMenu = currentItem->menu();
1152 if (subMenu && subMenu->cascade())
1159void QQuickMenuPrivate::onItemTriggered()
1162 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(q->sender());
1166 if (QQuickMenu *subMenu = item->subMenu()) {
1167 auto subMenuPrivate = QQuickMenuPrivate::get(subMenu);
1168 subMenuPrivate->popup(subMenuPrivate->firstEnabledMenuItem());
1174void QQuickMenuPrivate::onItemActiveFocusChanged()
1177 QQuickItem *item = qobject_cast<QQuickItem*>(q->sender());
1178 if (!item->hasActiveFocus())
1181 int indexOfItem = contentModel->indexOf(item,
nullptr);
1182 QQuickControl *control = qobject_cast<QQuickControl *>(item);
1183 setCurrentIndex(indexOfItem, control ? control->focusReason() : Qt::OtherFocusReason);
1186void QQuickMenuPrivate::onItemVisibleChanged()
1188 updateTextPadding();
1189 updateCollapsedSeparators();
1192void QQuickMenuPrivate::updateTextPadding()
1199 for (
int i = 0; i < q->count(); ++i) {
1200 if (
const auto menuItem = qobject_cast<QQuickMenuItem *>(itemAt(i)))
1201 if (menuItem->isVisible())
1202 padding = qMax(padding, menuItem->implicitTextPadding());
1205 if (padding == textPadding)
1208 textPadding = padding;
1210 for (
int i = 0; i < q->count(); ++i) {
1211 if (
const auto menuItem = qobject_cast<QQuickMenuItem *>(itemAt(i)))
1212 emit menuItem->textPaddingChanged();
1216void QQuickMenuPrivate::updateCollapsedSeparators()
1218 if (!complete || updatingCollapsedSeparators)
1223 QScopedValueRollback guard(updatingCollapsedSeparators,
true);
1225 auto isExplicitlyVisible = [](
const QQuickItem *item) {
1226 return QQuickItemPrivate::get(item)->explicitVisible;
1229 auto hasVisibleBinding = [](QQuickItem *item) {
1230 static const int visibleIndex = QQuickItem::staticMetaObject.indexOfProperty(
"visible");
1231 auto ddata = QQmlData::get(item,
false);
1234 return ddata->hasBindingBit(visibleIndex);
1237 auto hideSeparator = [
this](QQuickItem *separatorItem) {
1238 separatorItem->setVisible(
false);
1239 separatorItem->setHeight(0);
1240 collapsedSeparators.insert(separatorItem);
1243 auto showSeparator = [
this](QQuickItem *separatorItem) {
1244 if (!collapsedSeparators.contains(separatorItem))
1246 separatorItem->setVisible(
true);
1247 separatorItem->resetHeight();
1248 collapsedSeparators.remove(separatorItem);
1251 const int count = contentModel->count();
1253 if (!collapsibleSeparators) {
1254 for (
int i = 0; i < count; ++i)
1255 showSeparator(itemAt(i));
1259 QQuickItem *visibleSeparatorBefore =
nullptr;
1260 bool hasVisibleItemBefore =
false;
1262 for (
int i = 0; i < count; ++i) {
1263 QQuickItem *item = itemAt(i);
1267 if (qobject_cast<QQuickMenuSeparator *>(item)) {
1268 if (hasVisibleBinding(item)) {
1269 if (isExplicitlyVisible(item) && !visibleSeparatorBefore)
1270 visibleSeparatorBefore = item;
1274 if (visibleSeparatorBefore) {
1275 hideSeparator(item);
1276 }
else if (hasVisibleItemBefore) {
1277 visibleSeparatorBefore = item;
1278 showSeparator(item);
1280 hideSeparator(item);
1282 }
else if (isExplicitlyVisible(item)) {
1283 hasVisibleItemBefore =
true;
1284 visibleSeparatorBefore =
nullptr;
1289 if (visibleSeparatorBefore && !hasVisibleBinding(visibleSeparatorBefore))
1290 hideSeparator(visibleSeparatorBefore);
1293QQuickMenu *QQuickMenuPrivate::currentSubMenu()
const
1298 return currentItem->subMenu();
1301void QQuickMenuPrivate::setParentMenu(QQuickMenu *parent)
1304 if (parentMenu == parent)
1308 QObject::disconnect(parentMenu.data(), &QQuickMenu::cascadeChanged, q, &QQuickMenu::setCascade);
1309 disconnect(parentMenu.data(), &QQuickMenu::parentChanged,
this, &QQuickMenuPrivate::resolveParentItem);
1312 QObject::connect(parent, &QQuickMenu::cascadeChanged, q, &QQuickMenu::setCascade);
1313 connect(parent, &QQuickMenu::parentChanged,
this, &QQuickMenuPrivate::resolveParentItem);
1316 parentMenu = parent;
1318 resolveParentItem();
1323 QQuickMenu *menu = QQuickMenuPrivate::get(subMenu)->parentMenu;
1324 for (
int i = 0; i < QQuickMenuPrivate::get(menu)->contentModel->count(); ++i) {
1325 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(menu->itemAt(i));
1326 if (item && item->subMenu() == subMenu)
1332void QQuickMenuPrivate::resolveParentItem()
1336 q->resetParentItem();
1338 q->setParentItem(parentMenu->parentItem());
1340 q->setParentItem(findParentMenuItem(q));
1343void QQuickMenuPrivate::propagateKeyEvent(QKeyEvent *event)
1345 if (QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(parentItem)) {
1346 if (QQuickMenu *menu = menuItem->menu())
1347 QQuickMenuPrivate::get(menu)->propagateKeyEvent(event);
1348#if QT_CONFIG(quicktemplates2_container)
1349 }
else if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(parentItem)) {
1350 if (QQuickMenuBar *menuBar = menuBarItem->menuBar()) {
1352 QCoreApplication::sendEvent(menuBar, event);
1358void QQuickMenuPrivate::startHoverTimer()
1362 hoverTimer = q->startTimer(SUBMENU_DELAY);
1365void QQuickMenuPrivate::stopHoverTimer()
1371 q->killTimer(hoverTimer);
1375void QQuickMenuPrivate::setCurrentIndex(
int index, Qt::FocusReason reason)
1378 if (currentIndex == index)
1381 QQuickMenuItem *newCurrentItem = qobject_cast<QQuickMenuItem *>(itemAt(index));
1382 if (currentItem != newCurrentItem) {
1385 currentItem->setHighlighted(
false);
1386 if (!newCurrentItem && window) {
1387 QQuickItem *focusItem = QQuickItemPrivate::get(contentItem)->subFocusItem;
1389 auto *daPriv = QQuickWindowPrivate::get(window)->deliveryAgentPrivate();
1390 daPriv->clearFocusInScope(contentItem, focusItem, Qt::OtherFocusReason);
1394 if (newCurrentItem) {
1395 newCurrentItem->setHighlighted(
true);
1396 newCurrentItem->forceActiveFocus(reason);
1398 currentItem = newCurrentItem;
1401 currentIndex = index;
1402 emit q->currentIndexChanged();
1405bool QQuickMenuPrivate::activateNextItem()
1407 int index = currentIndex;
1408 int count = contentModel->count();
1409 while (++index < count) {
1410 QQuickItem *item = itemAt(index);
1411 if (!item || !item->activeFocusOnTab() || !item->isEnabled())
1413 setCurrentIndex(index, Qt::TabFocusReason);
1419bool QQuickMenuPrivate::activatePreviousItem()
1421 int index = currentIndex;
1422 while (--index >= 0) {
1423 QQuickItem *item = itemAt(index);
1424 if (!item || !item->activeFocusOnTab() || !item->isEnabled())
1426 setCurrentIndex(index, Qt::BacktabFocusReason);
1432QQuickMenuItem *QQuickMenuPrivate::firstEnabledMenuItem()
const
1434 for (
int i = 0; i < contentModel->count(); ++i) {
1435 QQuickItem *item = itemAt(i);
1436 if (!item || !item->isEnabled())
1439 QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
1448void QQuickMenuPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
1450 QQuickMenu *q = qobject_cast<QQuickMenu *>(prop->object);
1451 QQuickMenuPrivate *p = QQuickMenuPrivate::get(q);
1453 QQuickItem *item = qobject_cast<QQuickItem *>(obj);
1455 if (QQuickAction *action = qobject_cast<QQuickAction *>(obj))
1456 item = p->createItem(action);
1457 else if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(obj))
1458 item = p->createItem(menu);
1462 if (QQuickItemPrivate::get(item)->isTransparentForPositioner()) {
1463 QQuickItemPrivate::get(item)->addItemChangeListener(p, QQuickItemPrivate::SiblingOrder);
1464 item->setParentItem(p->contentItem);
1465 }
else if (p->contentModel->indexOf(item,
nullptr) == -1) {
1469 p->contentData.append(obj);
1473qsizetype QQuickMenuPrivate::contentData_count(QQmlListProperty<QObject> *prop)
1475 QQuickMenu *q =
static_cast<QQuickMenu *>(prop->object);
1476 return QQuickMenuPrivate::get(q)->contentData.size();
1479QObject *QQuickMenuPrivate::contentData_at(QQmlListProperty<QObject> *prop, qsizetype index)
1481 QQuickMenu *q =
static_cast<QQuickMenu *>(prop->object);
1482 return QQuickMenuPrivate::get(q)->contentData.value(index);
1485QPalette QQuickMenuPrivate::defaultPalette()
const
1487 return QQuickTheme::palette(QQuickTheme::Menu);
1490void QQuickMenuPrivate::contentData_clear(QQmlListProperty<QObject> *prop)
1492 QQuickMenu *q =
static_cast<QQuickMenu *>(prop->object);
1493 QQuickMenuPrivate::get(q)->contentData.clear();
1496void QQuickMenuPrivate::resetContentItem()
1499 QQuickItemPrivate::get(contentItem)->removeItemChangeListener(
this, QQuickItemPrivate::Children);
1500 QQuickItemPrivate::get(contentItem)->removeItemChangeListener(
this, QQuickItemPrivate::Destroyed);
1501 QQuickItemPrivate::get(contentItem)->removeItemChangeListener(
this, QQuickItemPrivate::Geometry);
1503 const auto children = contentItem->childItems();
1504 for (QQuickItem *child : std::as_const(children))
1505 QQuickItemPrivate::get(child)->removeItemChangeListener(
this, QQuickItemPrivate::SiblingOrder);
1506 contentItem =
nullptr;
1510QQuickMenu::QQuickMenu(QObject *parent)
1511 : QQuickPopup(*(
new QQuickMenuPrivate), parent)
1516 connect(d->contentModel, &QQmlObjectModel::countChanged,
this, &QQuickMenu::countChanged);
1519QQuickMenu::~QQuickMenu()
1522 qCDebug(lcNativeMenus) <<
"destroying" <<
this
1524 << d->contentModel->count()
1525 <<
"native item count:" << d->nativeItems.count();
1529 if (
auto *menuItem = qobject_cast<QQuickMenuItem *>(d->parentItem)) {
1530 if (menuItem->subMenu() ==
this) {
1531 auto *menuItemPriv = QQuickMenuItemPrivate::get(menuItem);
1532 menuItemPriv->setSubMenu(
nullptr);
1540 while (d->contentModel->count() > 0)
1541 d->removeItem(0, d->itemAt(0), QQuickMenuPrivate::DestructionPolicy::Destroy);
1543 d->resetContentItem();
1547
1548
1549
1550
1551QQuickItem *QQuickMenu::itemAt(
int index)
const
1553 Q_D(
const QQuickMenu);
1554 return d->itemAt(index);
1558
1559
1560
1561
1562
1563
1564
1565void QQuickMenu::addItem(QQuickItem *item)
1568 insertItem(d->contentModel->count(), item);
1572
1573
1574
1575
1576
1577
1578
1579void QQuickMenu::insertItem(
int index, QQuickItem *item)
1584 const int count = d->contentModel->count();
1585 if (index < 0 || index > count)
1588 int oldIndex = d->contentModel->indexOf(item,
nullptr);
1589 if (oldIndex != -1) {
1590 if (oldIndex < index)
1592 if (oldIndex != index) {
1593 d->moveItem(oldIndex, index);
1596 d->insertItem(index, item);
1601
1602
1603
1604
1605void QQuickMenu::moveItem(
int from,
int to)
1608 const int count = d->contentModel->count();
1609 if (from < 0 || from > count - 1)
1611 if (to < 0 || to > count - 1)
1615 d->moveItem(from, to);
1619
1620
1621
1622
1623
1624void QQuickMenu::removeItem(QQuickItem *item)
1630 const int index = d->contentModel->indexOf(item,
nullptr);
1634 d->removeItem(index, item, QQuickMenuPrivate::DestructionPolicy::Destroy);
1638
1639
1640
1641
1642
1643
1644
1645QQuickItem *QQuickMenu::takeItem(
int index)
1648 const int count = d->contentModel->count();
1649 if (index < 0 || index >= count)
1652 QQuickItem *item = itemAt(index);
1654 d->removeItem(index, item);
1659
1660
1661
1662
1663
1664
1665QQuickMenu *QQuickMenu::menuAt(
int index)
const
1667 Q_D(
const QQuickMenu);
1668 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
1672 return item->subMenu();
1676
1677
1678
1679
1680
1681
1682void QQuickMenu::addMenu(QQuickMenu *menu)
1685 insertMenu(d->contentModel->count(), menu);
1689
1690
1691
1692
1693
1694
1695void QQuickMenu::insertMenu(
int index, QQuickMenu *menu)
1701 insertItem(index, d->createItem(menu));
1705
1706
1707
1708
1709
1710void QQuickMenu::removeMenu(QQuickMenu *menu)
1716 const int count = d->contentModel->count();
1717 for (
int i = 0; i < count; ++i) {
1718 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(i));
1719 if (!item || item->subMenu() != menu)
1726 menu->deleteLater();
1730
1731
1732
1733
1734
1735
1736
1737
1738QQuickMenu *QQuickMenu::takeMenu(
int index)
1741 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
1745 QQuickMenu *subMenu = item->subMenu();
1749 d->removeItem(index, item);
1750 item->deleteLater();
1756
1757
1758
1759
1760
1761
1762QQuickAction *QQuickMenu::actionAt(
int index)
const
1764 Q_D(
const QQuickMenu);
1765 if (!
const_cast<QQuickMenuPrivate *>(d)->maybeNativeHandle()) {
1766 QQuickAbstractButton *item = qobject_cast<QQuickAbstractButton *>(d->itemAt(index));
1770 return item->action();
1772 if (index < 0 || index >= d->nativeItems.size())
1775 return d->nativeItems.at(index)->action();
1780
1781
1782
1783
1784
1785
1786void QQuickMenu::addAction(QQuickAction *action)
1789 insertAction(d->contentModel->count(), action);
1793
1794
1795
1796
1797
1798
1799void QQuickMenu::insertAction(
int index, QQuickAction *action)
1805 insertItem(index, d->createItem(action));
1809
1810
1811
1812
1813
1814void QQuickMenu::removeAction(QQuickAction *action)
1820 const int count = d->contentModel->count();
1821 for (
int i = 0; i < count; ++i) {
1822 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(i));
1823 if (!item || item->action() != action)
1830 action->deleteLater();
1834
1835
1836
1837
1838
1839
1840
1841
1842QQuickAction *QQuickMenu::takeAction(
int index)
1845 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
1849 QQuickAction *action = item->action();
1853 d->removeItem(index, item);
1854 item->deleteLater();
1858bool QQuickMenu::isVisible()
const
1860 Q_D(
const QQuickMenu);
1861 if (d->maybeNativeHandle())
1863 return QQuickPopup::isVisible();
1866void QQuickMenu::setVisible(
bool visible)
1869 if (visible == d->visible)
1872 auto *window =
this->window();
1873 if (visible && window) {
1876 QQuickWindowPrivate::get(window)->rmbContextMenuEventEnabled =
false;
1881 if (!d->parentMenu) {
1882 QQuickOverlay *overlay = QQuickOverlay::overlay(window, parentItem());
1884 const QList<QQuickPopup *> allPopups = QQuickOverlayPrivate::get(overlay)->allPopups;
1885 for (
auto *popup : allPopups) {
1886 if (popup !=
this && qobject_cast<QQuickMenu *>(popup))
1893 if (visible && ((d->useNativeMenu() && !d->maybeNativeHandle())
1894 || (!d->useNativeMenu() && d->maybeNativeHandle()))) {
1898 qCDebug(lcNativeMenus) <<
"setVisible called - useNativeMenu:" << d->useNativeMenu()
1899 <<
"maybeNativeHandle:" << d->maybeNativeHandle();
1900 d->syncWithUseNativeMenu();
1902 if (d->maybeNativeHandle()) {
1903 d->setNativeMenuVisible(visible);
1908 if (QQuickMenuPrivate::get(d->rootMenu())->menuBar)
1909 d->wmWindowType = QNativeInterface::Private::QXcbWindow::DropDownMenu;
1911 d->wmWindowType = QNativeInterface::Private::QXcbWindow::PopupMenu;
1916 QQuickPopup::setVisible(visible);
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940QVariant QQuickMenu::contentModel()
const
1942 Q_D(
const QQuickMenu);
1943 return QVariant::fromValue(d->contentModel);
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961QQmlListProperty<QObject> QQuickMenu::contentData()
1964 if (!d->contentItem)
1965 QQuickControlPrivate::get(d->popupItem)->executeContentItem();
1966 return QQmlListProperty<QObject>(
this,
nullptr,
1967 QQuickMenuPrivate::contentData_append,
1968 QQuickMenuPrivate::contentData_count,
1969 QQuickMenuPrivate::contentData_at,
1970 QQuickMenuPrivate::contentData_clear);
1974
1975
1976
1977
1978
1979
1980
1981
1982QString QQuickMenu::title()
const
1984 Q_D(
const QQuickMenu);
1988void QQuickMenu::setTitle(
const QString &title)
1991 if (title == d->title)
1995 d->handle->setText(title);
1996 emit titleChanged(title);
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2016QQuickIcon QQuickMenu::icon()
const
2018 Q_D(
const QQuickMenu);
2022void QQuickMenu::setIcon(
const QQuickIcon &icon)
2025 if (icon == d->icon)
2028 d->icon.ensureRelativeSourceResolved(
this);
2029 emit iconChanged(icon);
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057bool QQuickMenu::separatorsCollapsible()
const
2059 Q_D(
const QQuickMenu);
2060 return d->collapsibleSeparators;
2063void QQuickMenu::setSeparatorsCollapsible(
bool collapsible)
2066 if (d->collapsibleSeparators == collapsible)
2068 d->collapsibleSeparators = collapsible;
2069 emit separatorsCollapsibleChanged();
2070 d->updateCollapsedSeparators();
2072 d->handle->syncSeparatorsCollapsible(collapsible);
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091bool QQuickMenu::cascade()
const
2093 Q_D(
const QQuickMenu);
2097void QQuickMenu::setCascade(
bool cascade)
2100 if (d->cascade == cascade)
2102 d->cascade = cascade;
2104 d->resolveParentItem();
2105 emit cascadeChanged(cascade);
2108void QQuickMenu::resetCascade()
2112 setCascade(d->parentMenu->cascade());
2114 setCascade(shouldCascade());
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133qreal QQuickMenu::overlap()
const
2135 Q_D(
const QQuickMenu);
2139void QQuickMenu::setOverlap(qreal overlap)
2142 if (d->overlap == overlap)
2144 d->overlap = overlap;
2145 emit overlapChanged();
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170QQmlComponent *QQuickMenu::delegate()
const
2172 Q_D(
const QQuickMenu);
2176void QQuickMenu::setDelegate(QQmlComponent *delegate)
2179 if (d->delegate == delegate)
2182 d->delegate = delegate;
2183 emit delegateChanged();
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198int QQuickMenu::currentIndex()
const
2200 Q_D(
const QQuickMenu);
2201 return d->currentIndex;
2204void QQuickMenu::setCurrentIndex(
int index)
2207 d->setCurrentIndex(index, Qt::OtherFocusReason);
2211
2212
2213
2214
2215
2216
2217int QQuickMenu::count()
const
2219 Q_D(
const QQuickMenu);
2220 return d->contentModel->count();
2223void QQuickMenuPrivate::popup(QQuickItem *menuItem)
2228 QQmlNullableValue<QPointF> pos;
2229#if QT_CONFIG(cursor)
2230 if (parentItem && QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::MultipleWindows))
2231 pos = parentItem->mapFromGlobal(QCursor::pos());
2235 if (!pos.isValid() && parentItem)
2236 pos = QPointF((parentItem->width() - q->width()) / 2, (parentItem->height() - q->height()) / 2);
2238 q->popup(pos.isValid() ? pos.value() : QPointF(), menuItem);
2241void QQuickMenu::popup(
const QPointF &position, QQuickItem *menuItem)
2245#if QT_CONFIG(cursor)
2247 offset = d->popupItem->mapFromItem(menuItem, QPointF(0, 0)).y();
2249 setPosition(position - QPointF(0, offset));
2252 d->setCurrentIndex(d->contentModel->indexOf(menuItem,
nullptr), Qt::PopupFocusReason);
2254 d->setCurrentIndex(-1, Qt::PopupFocusReason);
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2304void QQuickMenu::popup(QQuickItem *parent, qreal x, qreal y, QQuickItem *menuItem)
2306 popup(parent, QPointF {x, y}, menuItem);
2309void QQuickMenu::popup(QQuickItem *parent,
const QPointF &position, QQuickItem *menuItem)
2312 if (parent && !d->popupItem->isAncestorOf(parent))
2313 setParentItem(parent);
2314 popup(position, menuItem);
2317void QQuickMenu::popup(QQuickItem *parent, QQuickItem *menuItem)
2320 QQuickItem *parentItem =
nullptr;
2321 if (parent && !d->popupItem->isAncestorOf(parent))
2322 parentItem = parent;
2324 setParentItem(parentItem);
2330void QQuickMenu::popup(QQuickItem *parent)
2333 QQuickItem *menuItem =
nullptr;
2335 if (!d->popupItem->isAncestorOf(parent))
2336 setParentItem(parent);
2337 if (d->popupItem->isAncestorOf(parent))
2343void QQuickMenu::popup(qreal x, qreal y, QQuickItem *menuItem)
2345 popup(QPointF {x, y}, menuItem);
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363void QQuickMenu::dismiss()
2365 QQuickMenu *menu =
this;
2368 menu = QQuickMenuPrivate::get(menu)->parentMenu;
2372void QQuickMenu::componentComplete()
2375 QQuickPopup::componentComplete();
2377 d->updateTextPadding();
2378 d->syncWithUseNativeMenu();
2381void QQuickMenu::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
2384 QQuickPopup::contentItemChange(newItem, oldItem);
2387 QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Children);
2388 QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Destroyed);
2389 QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
2392 QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Children);
2393 QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Destroyed);
2394 QQuickItemPrivate::get(newItem)->updateOrAddGeometryChangeListener(d, QQuickGeometryChange::Width);
2397 d->contentItem = newItem;
2400void QQuickMenu::itemChange(QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData &data)
2403 QQuickPopup::itemChange(change, data);
2406 case QQuickItem::ItemVisibleHasChanged:
2407 if (!data.boolValue && d->cascade) {
2410 d->setCurrentIndex(-1, Qt::OtherFocusReason);
2418void QQuickMenu::keyPressEvent(QKeyEvent *event)
2421 QQuickPopup::keyPressEvent(event);
2429 switch (event->key()) {
2431 if (!d->activatePreviousItem())
2432 d->propagateKeyEvent(event);
2436 d->activateNextItem();
2442 if (d->popupItem->isMirrored() == (event->key() == Qt::Key_Right)) {
2443 if (d->parentMenu && d->currentItem) {
2445 d->parentMenu->open();
2450 if (QQuickMenu *subMenu = d->currentSubMenu()) {
2451 auto subMenuPrivate = QQuickMenuPrivate::get(subMenu);
2452 subMenuPrivate->popup(subMenuPrivate->firstEnabledMenuItem());
2456 if (!event->isAccepted())
2457 d->propagateKeyEvent(event);
2460#if QT_CONFIG(shortcut)
2464 if (!QKeySequence::mnemonic(QStringLiteral(
"&A")).isEmpty())
2473#if QT_CONFIG(shortcut)
2474 if (event->modifiers() == Qt::NoModifier) {
2475 for (
int i = 0; i < count(); ++i) {
2476 QQuickAbstractButton *item = qobject_cast<QQuickAbstractButton*>(d->itemAt(i));
2479 const QKeySequence keySequence = QKeySequence::mnemonic(item->text());
2480 if (keySequence.isEmpty())
2482 if (keySequence[0].key() == event->key()) {
2491void QQuickMenu::timerEvent(QTimerEvent *event)
2494 if (event->timerId() == d->hoverTimer) {
2495 if (QQuickMenu *subMenu = d->currentSubMenu())
2497 d->stopHoverTimer();
2500 QQuickPopup::timerEvent(event);
2503QFont QQuickMenu::defaultFont()
const
2505 return QQuickTheme::font(QQuickTheme::Menu);
2508#if QT_CONFIG(accessibility)
2509QAccessible::Role QQuickMenu::accessibleRole()
const
2511 return QAccessible::PopupMenu;
2517#include "moc_qquickmenu_p.cpp"
Combined button and popup list for selecting options.