Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickmenu.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickmenu_p.h"
5#include "qquickmenu_p_p.h"
7#include <private/qtquicktemplates2-config_p.h>
8#if QT_CONFIG(quicktemplates2_container)
10#include "qquickmenubar_p.h"
11#endif
12#include "qquickpopupitem_p_p.h"
14#include "qquickaction_p.h"
15
16#include <QtGui/qevent.h>
17#include <QtGui/qcursor.h>
18#if QT_CONFIG(shortcut)
19#include <QtGui/qkeysequence.h>
20#endif
21#include <QtGui/qpa/qplatformintegration.h>
22#include <QtGui/private/qguiapplication_p.h>
23#include <QtQml/qqmlcontext.h>
24#include <QtQml/qqmlcomponent.h>
25#include <QtQml/private/qqmlengine_p.h>
26#include <QtQml/private/qv4scopedvalue_p.h>
27#include <QtQml/private/qv4variantobject_p.h>
28#include <QtQml/private/qv4qobjectwrapper_p.h>
29#include <private/qqmlobjectmodel_p.h>
30#include <QtQuick/private/qquickitem_p.h>
31#include <QtQuick/private/qquickitemchangelistener_p.h>
32#include <QtQuick/private/qquickevents_p_p.h>
33#include <QtQuick/private/qquickwindow_p.h>
34
36
37// copied from qfusionstyle.cpp
38static const int SUBMENU_DELAY = 225;
39
44
203static const QQuickPopup::ClosePolicy cascadingSubMenuClosePolicy = QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutsideParent;
204
205static bool shouldCascade()
206{
207#if QT_CONFIG(cursor)
209#else
210 return false;
211#endif
212}
213
215{
216public:
218
219 void reposition() override;
220};
221
226
228{
229 Q_Q(QQuickMenu);
231}
232
237
239{
242 QQuickItemPrivate::get(item)->setCulled(true); // QTBUG-53262
243 if (complete)
246 QQuickItemPrivate::get(item)->updateOrAddGeometryChangeListener(this, QQuickGeometryChange::Width);
247 contentModel->insert(index, item);
248
249 QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
250 if (menuItem) {
251 Q_Q(QQuickMenu);
252 QQuickMenuItemPrivate::get(menuItem)->setMenu(q);
253 if (QQuickMenu *subMenu = menuItem->subMenu())
254 QQuickMenuPrivate::get(subMenu)->setParentMenu(q);
258 }
259}
260
261void QQuickMenuPrivate::moveItem(int from, int to)
262{
263 contentModel->move(from, to);
264}
265
267{
269
271 QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
272 item->setParentItem(nullptr);
273 contentModel->remove(index);
274
275 QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
276 if (menuItem) {
277 QQuickMenuItemPrivate::get(menuItem)->setMenu(nullptr);
278 if (QQuickMenu *subMenu = menuItem->subMenu())
279 QQuickMenuPrivate::get(subMenu)->setParentMenu(nullptr);
283 }
284}
285
287{
288 Q_Q(QQuickMenu);
289 if (!delegate)
290 return nullptr;
291
293 if (!context)
295
298 if (!item)
299 delete object;
300 else
302
303 return item;
304}
305
307{
308 if (!delegate)
309 return;
310
312}
313
315{
317 if (QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item))
318 QQuickMenuItemPrivate::get(menuItem)->setSubMenu(menu);
320 return item;
321}
322
324{
326 if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(item))
327 button->setAction(action);
329 return item;
330}
331
333{
334 if (!item || !contentItem)
335 return;
336
338 if (!p->widthValid()) {
339 item->setWidth(contentItem->width());
340 p->widthValidFlag = false;
341 }
342}
343
345{
346 if (!contentModel)
347 return;
348
349 for (int i = 0; i < contentModel->count(); ++i)
351}
352
354{
355 // add dynamically reparented items (eg. by a Repeater)
356 if (!QQuickItemPrivate::get(child)->isTransparentForPositioner() && !contentData.contains(child))
358}
359
361{
362 // remove dynamically unparented items (eg. by a Repeater)
363 if (!parent)
365}
366
368{
369 // reorder the restacked items (eg. by a Repeater)
370 Q_Q(QQuickMenu);
371 QList<QQuickItem *> siblings = contentItem->childItems();
372
373 int to = 0;
374 for (int i = 0; i < siblings.size(); ++i) {
375 QQuickItem* sibling = siblings.at(i);
376 if (QQuickItemPrivate::get(sibling)->isTransparentForPositioner())
377 continue;
378 int index = contentModel->indexOf(sibling, nullptr);
379 q->moveItem(index, to++);
380 }
381}
382
390
392{
393 if (!complete)
394 return;
395
396 if (item == contentItem) {
397 // The contentItem's geometry changed, so resize any items
398 // that don't have explicit widths set so that they fill the width of the menu.
399 resizeItems();
400 } else {
401 // The geometry of an item in the menu changed. If the item
402 // doesn't have an explicit width set, make it fill the width of the menu.
404 }
405}
406
414
416{
417 QQuickMenu *menu = static_cast<QQuickMenu *>(popup());
419 if (p->parentMenu) {
420 if (p->cascade) {
421 if (p->popupItem->isMirrored())
422 menu->setPosition(QPointF(-menu->width() - p->parentMenu->leftPadding() + menu->overlap(), -menu->topPadding()));
423 else if (p->parentItem)
424 menu->setPosition(QPointF(p->parentItem->width() + p->parentMenu->rightPadding() - menu->overlap(), -menu->topPadding()));
425 } else {
426 menu->setPosition(QPointF(p->parentMenu->x() + (p->parentMenu->width() - menu->width()) / 2,
427 p->parentMenu->y() + (p->parentMenu->height() - menu->height()) / 2));
428 }
429 }
431}
432
434{
435 Q_Q(QQuickMenu);
436 if (parentMenu && !cascade)
437 parentMenu->close();
438
439 // If a cascading sub-menu doesn't have enough space to open on
440 // the right, it flips on the other side of the parent menu.
442
444 return false;
445
446 if (!hasClosePolicy) {
447 if (cascade && parentMenu)
449 else
450 q->resetClosePolicy();
451 }
452 return true;
453}
454
456{
458 return false;
459
461
462 QQuickMenu *subMenu = currentSubMenu();
463 while (subMenu) {
464 QPointer<QQuickMenuItem> currentSubMenuItem = QQuickMenuPrivate::get(subMenu)->currentItem;
465 subMenu->close();
466 subMenu = currentSubMenuItem ? currentSubMenuItem->subMenu() : nullptr;
467 }
468 return true;
469}
470
472{
473 // keep the parent menu open when a cascading sub-menu (this menu) is interacted with
474 return (cascade && parentMenu && contains(point)) || QQuickPopupPrivate::blockInput(item, point);
475}
476
478{
479 Q_Q(QQuickMenu);
480 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->sender());
481 if (!button || !button->isHovered() || !button->isEnabled() || QQuickAbstractButtonPrivate::get(button)->touchId != -1)
482 return;
483
484 QQuickMenuItem *oldCurrentItem = currentItem;
485
486 int index = contentModel->indexOf(button, nullptr);
487 if (index != -1) {
489 if (oldCurrentItem != currentItem) {
490 if (oldCurrentItem) {
491 QQuickMenu *subMenu = oldCurrentItem->subMenu();
492 if (subMenu)
493 subMenu->close();
494 }
495 if (currentItem) {
496 QQuickMenu *subMenu = currentItem->menu();
497 if (subMenu && subMenu->cascade())
499 }
500 }
501 }
502}
503
505{
506 Q_Q(QQuickMenu);
507 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(q->sender());
508 if (!item)
509 return;
510
511 if (QQuickMenu *subMenu = item->subMenu()) {
512 auto subMenuPrivate = QQuickMenuPrivate::get(subMenu);
513 subMenu->popup(subMenuPrivate->firstEnabledMenuItem());
514 } else {
515 q->dismiss();
516 }
517}
518
520{
521 Q_Q(QQuickMenu);
523 if (!item->hasActiveFocus())
524 return;
525
526 int indexOfItem = contentModel->indexOf(item, nullptr);
527 QQuickControl *control = qobject_cast<QQuickControl *>(item);
528 setCurrentIndex(indexOfItem, control ? control->focusReason() : Qt::OtherFocusReason);
529}
530
532{
533 if (!currentItem)
534 return nullptr;
535
536 return currentItem->subMenu();
537}
538
540{
541 Q_Q(QQuickMenu);
542 if (parentMenu == parent)
543 return;
544
545 if (parentMenu) {
546 QObject::disconnect(parentMenu.data(), &QQuickMenu::cascadeChanged, q, &QQuickMenu::setCascade);
548 }
549 if (parent) {
550 QObject::connect(parent, &QQuickMenu::cascadeChanged, q, &QQuickMenu::setCascade);
552 }
553
555 q->resetCascade();
557}
558
560{
561 QQuickMenu *menu = QQuickMenuPrivate::get(subMenu)->parentMenu;
562 for (int i = 0; i < QQuickMenuPrivate::get(menu)->contentModel->count(); ++i) {
563 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(menu->itemAt(i));
564 if (item && item->subMenu() == subMenu)
565 return item;
566 }
567 return nullptr;
568}
569
571{
572 Q_Q(QQuickMenu);
573 if (!parentMenu)
574 q->resetParentItem();
575 else if (!cascade)
576 q->setParentItem(parentMenu->parentItem());
577 else
578 q->setParentItem(findParentMenuItem(q));
579}
580
582{
583 if (QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(parentItem)) {
584 if (QQuickMenu *menu = menuItem->menu())
585 QQuickMenuPrivate::get(menu)->propagateKeyEvent(event);
586#if QT_CONFIG(quicktemplates2_container)
587 } else if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(parentItem)) {
588 if (QQuickMenuBar *menuBar = menuBarItem->menuBar()) {
589 event->accept();
591 }
592#endif
593 }
594}
595
597{
598 Q_Q(QQuickMenu);
600 hoverTimer = q->startTimer(SUBMENU_DELAY);
601}
602
604{
605 Q_Q(QQuickMenu);
606 if (!hoverTimer)
607 return;
608
609 q->killTimer(hoverTimer);
610 hoverTimer = 0;
611}
612
614{
615 Q_Q(QQuickMenu);
616 if (currentIndex == index)
617 return;
618
619 QQuickMenuItem *newCurrentItem = qobject_cast<QQuickMenuItem *>(itemAt(index));
620 if (currentItem != newCurrentItem) {
622 if (currentItem) {
624 if (!newCurrentItem && window) {
625 QQuickItem *focusItem = QQuickItemPrivate::get(contentItem)->subFocusItem;
626 if (focusItem)
627 QQuickWindowPrivate::get(window)->clearFocusInScope(contentItem, focusItem, Qt::OtherFocusReason);
628 }
629 }
630 if (newCurrentItem) {
631 newCurrentItem->setHighlighted(true);
632 newCurrentItem->forceActiveFocus(reason);
633 }
634 currentItem = newCurrentItem;
635 }
636
638 emit q->currentIndexChanged();
639}
640
642{
643 int index = currentIndex;
644 int count = contentModel->count();
645 while (++index < count) {
647 if (!item || !item->activeFocusOnTab() || !item->isEnabled())
648 continue;
650 return true;
651 }
652 return false;
653}
654
656{
657 int index = currentIndex;
658 while (--index >= 0) {
660 if (!item || !item->activeFocusOnTab() || !item->isEnabled())
661 continue;
663 return true;
664 }
665 return false;
666}
667
669{
670 for (int i = 0; i < contentModel->count(); ++i) {
672 if (!item || !item->isEnabled())
673 continue;
674
675 QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
676 if (!menuItem)
677 continue;
678
679 return menuItem;
680 }
681 return nullptr;
682}
683
684void QQuickMenuPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
685{
686 QQuickMenu *q = qobject_cast<QQuickMenu *>(prop->object);
688
690 if (!item) {
691 if (QQuickAction *action = qobject_cast<QQuickAction *>(obj))
692 item = p->createItem(action);
693 else if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(obj))
694 item = p->createItem(menu);
695 }
696
697 if (item) {
698 if (QQuickItemPrivate::get(item)->isTransparentForPositioner()) {
700 item->setParentItem(p->contentItem);
701 } else if (p->contentModel->indexOf(item, nullptr) == -1) {
702 q->addItem(item);
703 }
704 } else {
705 p->contentData.append(obj);
706 }
707}
708
709qsizetype QQuickMenuPrivate::contentData_count(QQmlListProperty<QObject> *prop)
710{
711 QQuickMenu *q = static_cast<QQuickMenu *>(prop->object);
712 return QQuickMenuPrivate::get(q)->contentData.size();
713}
714
716{
717 QQuickMenu *q = static_cast<QQuickMenu *>(prop->object);
718 return QQuickMenuPrivate::get(q)->contentData.value(index);
719}
720
725
726void QQuickMenuPrivate::contentData_clear(QQmlListProperty<QObject> *prop)
727{
728 QQuickMenu *q = static_cast<QQuickMenu *>(prop->object);
729 QQuickMenuPrivate::get(q)->contentData.clear();
730}
731
733 : QQuickPopup(*(new QQuickMenuPrivate), parent)
734{
735 Q_D(QQuickMenu);
736 setFocus(true);
737 d->init();
738 connect(d->contentModel, &QQmlObjectModel::countChanged, this, &QQuickMenu::countChanged);
739}
740
742{
743 Q_D(QQuickMenu);
744 // We have to do this to ensure that the change listeners are removed.
745 // It's too late to do this in ~QQuickMenuPrivate, as contentModel has already
746 // been destroyed before that is called.
747 while (d->contentModel->count() > 0)
748 d->removeItem(0, d->itemAt(0));
749
750 if (d->contentItem) {
751 QQuickItemPrivate::get(d->contentItem)->removeItemChangeListener(d, QQuickItemPrivate::Children);
752 QQuickItemPrivate::get(d->contentItem)->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
753
754 const auto children = d->contentItem->childItems();
755 for (QQuickItem *child : std::as_const(children))
757 }
758}
759
766{
767 Q_D(const QQuickMenu);
768 return d->itemAt(index);
769}
770
777{
778 Q_D(QQuickMenu);
779 insertItem(d->contentModel->count(), item);
780}
781
788{
789 Q_D(QQuickMenu);
790 if (!item)
791 return;
792 const int count = d->contentModel->count();
793 if (index < 0 || index > count)
794 index = count;
795
796 int oldIndex = d->contentModel->indexOf(item, nullptr);
797 if (oldIndex != -1) {
798 if (oldIndex < index)
799 --index;
800 if (oldIndex != index)
801 d->moveItem(oldIndex, index);
802 } else {
803 d->insertItem(index, item);
804 }
805}
806
812void QQuickMenu::moveItem(int from, int to)
813{
814 Q_D(QQuickMenu);
815 const int count = d->contentModel->count();
816 if (from < 0 || from > count - 1)
817 return;
818 if (to < 0 || to > count - 1)
819 to = count - 1;
820
821 if (from != to)
822 d->moveItem(from, to);
823}
824
832{
833 Q_D(QQuickMenu);
834 if (!item)
835 return;
836
837 const int index = d->contentModel->indexOf(item, nullptr);
838 if (index == -1)
839 return;
840
841 d->removeItem(index, item);
842 item->deleteLater();
843}
844
853QQuickItem *QQuickMenu::takeItem(int index)
854{
855 Q_D(QQuickMenu);
856 const int count = d->contentModel->count();
857 if (index < 0 || index >= count)
858 return nullptr;
859
861 if (item)
862 d->removeItem(index, item);
863 return item;
864}
865
873QQuickMenu *QQuickMenu::menuAt(int index) const
874{
875 Q_D(const QQuickMenu);
876 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
877 if (!item)
878 return nullptr;
879
880 return item->subMenu();
881}
882
889void QQuickMenu::addMenu(QQuickMenu *menu)
890{
891 Q_D(QQuickMenu);
892 insertMenu(d->contentModel->count(), menu);
893}
894
901void QQuickMenu::insertMenu(int index, QQuickMenu *menu)
902{
903 Q_D(QQuickMenu);
904 if (!menu)
905 return;
906
907 insertItem(index, d->createItem(menu));
908}
909
916void QQuickMenu::removeMenu(QQuickMenu *menu)
917{
918 Q_D(QQuickMenu);
919 if (!menu)
920 return;
921
922 const int count = d->contentModel->count();
923 for (int i = 0; i < count; ++i) {
924 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(i));
925 if (!item || item->subMenu() != menu)
926 continue;
927
929 break;
930 }
931
932 menu->deleteLater();
933}
934
943QQuickMenu *QQuickMenu::takeMenu(int index)
944{
945 Q_D(QQuickMenu);
946 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
947 if (!item)
948 return nullptr;
949
950 QQuickMenu *subMenu = item->subMenu();
951 if (!subMenu)
952 return nullptr;
953
954 d->removeItem(index, item);
955 item->deleteLater();
956 return subMenu;
957}
958
966QQuickAction *QQuickMenu::actionAt(int index) const
967{
968 Q_D(const QQuickMenu);
969 QQuickAbstractButton *item = qobject_cast<QQuickAbstractButton *>(d->itemAt(index));
970 if (!item)
971 return nullptr;
972
973 return item->action();
974}
975
982void QQuickMenu::addAction(QQuickAction *action)
983{
984 Q_D(QQuickMenu);
985 insertAction(d->contentModel->count(), action);
986}
987
994void QQuickMenu::insertAction(int index, QQuickAction *action)
995{
996 Q_D(QQuickMenu);
997 if (!action)
998 return;
999
1000 insertItem(index, d->createItem(action));
1001}
1002
1009void QQuickMenu::removeAction(QQuickAction *action)
1010{
1011 Q_D(QQuickMenu);
1012 if (!action)
1013 return;
1014
1015 const int count = d->contentModel->count();
1016 for (int i = 0; i < count; ++i) {
1017 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(i));
1018 if (!item || item->action() != action)
1019 continue;
1020
1022 break;
1023 }
1024
1026}
1027
1036QQuickAction *QQuickMenu::takeAction(int index)
1037{
1038 Q_D(QQuickMenu);
1039 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
1040 if (!item)
1041 return nullptr;
1042
1043 QQuickAction *action = item->action();
1044 if (!action)
1045 return nullptr;
1046
1047 d->removeItem(index, item);
1048 item->deleteLater();
1049 return action;
1050}
1051
1074{
1075 Q_D(const QQuickMenu);
1076 return QVariant::fromValue(d->contentModel);
1077}
1078
1094QQmlListProperty<QObject> QQuickMenu::contentData()
1095{
1096 Q_D(QQuickMenu);
1097 if (!d->contentItem)
1098 QQuickControlPrivate::get(d->popupItem)->executeContentItem();
1099 return QQmlListProperty<QObject>(this, nullptr,
1104}
1105
1116{
1117 Q_D(const QQuickMenu);
1118 return d->title;
1119}
1120
1122{
1123 Q_D(QQuickMenu);
1124 if (title == d->title)
1125 return;
1126 d->title = title;
1128}
1129
1146{
1147 Q_D(const QQuickMenu);
1148 return d->icon;
1149}
1150
1152{
1153 Q_D(QQuickMenu);
1154 if (icon == d->icon)
1155 return;
1156 d->icon = icon;
1157 d->icon.ensureRelativeSourceResolved(this);
1158 emit iconChanged(icon);
1159}
1160
1176{
1177 Q_D(const QQuickMenu);
1178 return d->cascade;
1179}
1180
1181void QQuickMenu::setCascade(bool cascade)
1182{
1183 Q_D(QQuickMenu);
1184 if (d->cascade == cascade)
1185 return;
1186 d->cascade = cascade;
1187 if (d->parentMenu)
1188 d->resolveParentItem();
1189 emit cascadeChanged(cascade);
1190}
1191
1193{
1194 Q_D(QQuickMenu);
1195 if (d->parentMenu)
1196 setCascade(d->parentMenu->cascade());
1197 else
1199}
1200
1216{
1217 Q_D(const QQuickMenu);
1218 return d->overlap;
1219}
1220
1222{
1223 Q_D(QQuickMenu);
1224 if (d->overlap == overlap)
1225 return;
1226 d->overlap = overlap;
1227 emit overlapChanged();
1228}
1229
1248{
1249 Q_D(const QQuickMenu);
1250 return d->delegate;
1251}
1252
1254{
1255 Q_D(QQuickMenu);
1256 if (d->delegate == delegate)
1257 return;
1258
1259 d->delegate = delegate;
1260 emit delegateChanged();
1261}
1262
1274{
1275 Q_D(const QQuickMenu);
1276 return d->currentIndex;
1277}
1278
1280{
1281 Q_D(QQuickMenu);
1282 d->setCurrentIndex(index, Qt::OtherFocusReason);
1283}
1284
1293{
1294 Q_D(const QQuickMenu);
1295 return d->contentModel->count();
1296}
1297
1299{
1300 Q_D(QQuickMenu);
1301 // No position has been explicitly specified, so position the menu at the mouse cursor
1302 // on desktop platforms that have a mouse cursor available and support multiple windows.
1303 QQmlNullableValue<QPointF> pos;
1304#if QT_CONFIG(cursor)
1306 pos = d->parentItem->mapFromGlobal(QCursor::pos());
1307#endif
1308
1309 // As a fallback, center the menu over its parent item.
1310 if (!pos.isValid() && d->parentItem)
1311 pos = QPointF((d->parentItem->width() - width()) / 2, (d->parentItem->height() - height()) / 2);
1312
1313 popup(pos.isValid() ? pos.value() : QPointF(), menuItem);
1314}
1315
1317{
1318 Q_D(QQuickMenu);
1319 qreal offset = 0;
1320#if QT_CONFIG(cursor)
1321 if (menuItem)
1322 offset = d->popupItem->mapFromItem(menuItem, QPointF(0, 0)).y();
1323#endif
1325
1326 if (menuItem)
1327 d->setCurrentIndex(d->contentModel->indexOf(menuItem, nullptr), Qt::PopupFocusReason);
1328 open();
1329}
1330
1370{
1371 Q_D(QQuickMenu);
1372 const int len = args->length();
1373 if (len > 4) {
1374 args->v4engine()->throwTypeError();
1375 return;
1376 }
1377
1378 QV4::ExecutionEngine *v4 = args->v4engine();
1379 QV4::Scope scope(v4);
1380
1381 QQmlNullableValue<QPointF> pos;
1382 QQuickItem *menuItem = nullptr;
1383 QQuickItem *parentItem = nullptr;
1384
1385 if (len > 0) {
1386 // Item parent
1387 QV4::ScopedValue firstArg(scope, (*args)[0]);
1388 if (const QV4::QObjectWrapper *obj = firstArg->as<QV4::QObjectWrapper>()) {
1390 if (item && !d->popupItem->isAncestorOf(item))
1391 parentItem = item;
1392 } else if (firstArg->isUndefined()) {
1393 resetParentItem();
1394 parentItem = d->parentItem;
1395 }
1396
1397 // MenuItem item
1398 QV4::ScopedValue lastArg(scope, (*args)[len - 1]);
1399 if (const QV4::QObjectWrapper *obj = lastArg->as<QV4::QObjectWrapper>()) {
1401 if (item && d->popupItem->isAncestorOf(item))
1402 menuItem = item;
1403 }
1404 }
1405
1406 if (len >= 3 || (!parentItem && len >= 2)) {
1407 // real x, real y
1408 QV4::ScopedValue xArg(scope, (*args)[parentItem ? 1 : 0]);
1409 QV4::ScopedValue yArg(scope, (*args)[parentItem ? 2 : 1]);
1410 if (xArg->isNumber() && yArg->isNumber())
1411 pos = QPointF(xArg->asDouble(), yArg->asDouble());
1412 }
1413
1414 if (!pos.isValid() && (len >= 2 || (!parentItem && len >= 1))) {
1415 // point pos
1416 QV4::ScopedValue posArg(scope, (*args)[parentItem ? 1 : 0]);
1418 if (var.userType() == QMetaType::QPointF)
1419 pos = var.toPointF();
1420 }
1421
1422 if (parentItem)
1423 setParentItem(parentItem);
1424
1425 if (pos.isValid())
1426 popup(pos, menuItem);
1427 else
1428 popup(menuItem);
1429}
1430
1445void QQuickMenu::dismiss()
1446{
1447 QQuickMenu *menu = this;
1448 while (menu) {
1449 menu->close();
1450 menu = QQuickMenuPrivate::get(menu)->parentMenu;
1451 }
1452}
1453
1455{
1456 Q_D(QQuickMenu);
1458 d->resizeItems();
1459}
1460
1462{
1463 Q_D(QQuickMenu);
1464 QQuickPopup::contentItemChange(newItem, oldItem);
1465
1466 if (oldItem) {
1467 QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Children);
1468 QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
1469 }
1470 if (newItem) {
1471 QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Children);
1472 QQuickItemPrivate::get(newItem)->updateOrAddGeometryChangeListener(d, QQuickGeometryChange::Width);
1473 }
1474
1475 d->contentItem = newItem;
1476}
1477
1479{
1480 Q_D(QQuickMenu);
1482
1483 if (change == QQuickItem::ItemVisibleHasChanged) {
1484 if (!data.boolValue && d->cascade) {
1485 // Ensure that when the menu isn't visible, there's no current item
1486 // the next time it's opened.
1487 d->setCurrentIndex(-1, Qt::OtherFocusReason);
1488 }
1489 }
1490}
1491
1493{
1494 Q_D(QQuickMenu);
1496
1497 // QTBUG-17051
1498 // Work around the fact that ListView has no way of distinguishing between
1499 // mouse and keyboard interaction, thanks to the "interactive" bool in Flickable.
1500 // What we actually want is to have a way to always allow keyboard interaction but
1501 // only allow flicking with the mouse when there are too many menu items to be
1502 // shown at once.
1503 switch (event->key()) {
1504 case Qt::Key_Up:
1505 if (!d->activatePreviousItem())
1506 d->propagateKeyEvent(event);
1507 break;
1508
1509 case Qt::Key_Down:
1510 d->activateNextItem();
1511 break;
1512
1513 case Qt::Key_Left:
1514 case Qt::Key_Right:
1515 event->ignore();
1516 if (d->popupItem->isMirrored() == (event->key() == Qt::Key_Right)) {
1517 if (d->parentMenu && d->currentItem) {
1518 if (!d->cascade)
1519 d->parentMenu->open();
1520 close();
1521 event->accept();
1522 }
1523 } else {
1524 if (QQuickMenu *subMenu = d->currentSubMenu()) {
1525 auto subMenuPrivate = QQuickMenuPrivate::get(subMenu);
1526 subMenu->popup(subMenuPrivate->firstEnabledMenuItem());
1527 event->accept();
1528 }
1529 }
1530 if (!event->isAccepted())
1531 d->propagateKeyEvent(event);
1532 break;
1533
1534#if QT_CONFIG(shortcut)
1535 case Qt::Key_Alt:
1536 // If &mnemonic shortcut is enabled, go back to (possibly) the parent
1537 // menu bar so the shortcut key will be processed by the menu bar.
1538 if (!QKeySequence::mnemonic(QStringLiteral("&A")).isEmpty())
1539 close();
1540 break;
1541#endif
1542
1543 default:
1544 break;
1545 }
1546}
1547
1549{
1550 Q_D(QQuickMenu);
1551 if (event->timerId() == d->hoverTimer) {
1552 if (QQuickMenu *subMenu = d->currentSubMenu())
1553 subMenu->open();
1554 d->stopHoverTimer();
1555 return;
1556 }
1558}
1559
1564
1565#if QT_CONFIG(accessibility)
1566QAccessible::Role QQuickMenu::accessibleRole() const
1567{
1568 return QAccessible::PopupMenu;
1569}
1570#endif
1571
1573
1574#include "moc_qquickmenu_p.cpp"
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
static QPoint pos()
Returns the position of the cursor (hot spot) of the primary screen in global screen coordinates.
Definition qcursor.cpp:188
\reentrant
Definition qfont.h:22
bool isEnabled() const
Returns true if the item is enabled; otherwise, false is returned.
void setParentItem(QGraphicsItem *parent)
Sets this item's parent item to newParent.
static QPlatformIntegration * platformIntegration()
The QKeyEvent class describes a key event.
Definition qevent.h:424
static QKeySequence mnemonic(const QString &text)
Returns the shortcut key sequence for the mnemonic in text, or an empty key sequence if no mnemonics ...
bool removeOne(const AT &t)
Definition qlist.h:598
qsizetype length() const noexcept
Definition qlist.h:399
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qmetatype.h:341
QObject * parent
Definition qobject.h:73
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:299
static bool disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot)
Definition qobject_p.h:328
\inmodule QtCore
Definition qobject.h:103
const QObjectList & children() const
Returns a list of child objects.
Definition qobject.h:201
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
virtual void timerEvent(QTimerEvent *event)
This event handler can be reimplemented in a subclass to receive timer events for the object.
Definition qobject.cpp:1470
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
The QPalette class contains color groups for each widget state.
Definition qpalette.h:19
\inmodule QtCore\reentrant
Definition qpoint.h:217
T * data() const noexcept
Definition qpointer.h:73
The QQmlComponent class encapsulates a QML component definition.
virtual QObject * beginCreate(QQmlContext *)
Create an object instance from this component, within the specified context.
virtual void completeCreate()
This method provides advanced control over component instance creation.
QQmlContext * creationContext() const
Returns the QQmlContext the component was created in.
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
int count() const override
\qmlproperty int QtQml.Models::ObjectModel::count
int indexOf(QObject *object, QObject *objectContext) const override
static QQuickAbstractButtonPrivate * get(QQuickAbstractButton *button)
static QQuickControlPrivate * get(QQuickControl *control)
void hoveredChanged()
Qt::FocusReason focusReason
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
void activeFocusChanged(bool)
QList< QQuickItem * > childItems() const
Returns the children of this item.
qreal width
This property holds the width of this item.
Definition qquickitem.h:75
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:144
@ ItemVisibleHasChanged
Definition qquickitem.h:148
static QQuickMenuItemPrivate * get(QQuickMenuItem *item)
void setHighlighted(bool highlighted)
QQuickMenu * menu
QQuickMenu * subMenu
QQuickMenuPositioner(QQuickMenu *menu)
void reposition() override
QQmlObjectModel * contentModel
bool blockInput(QQuickItem *item, const QPointF &point) const override
void setParentMenu(QQuickMenu *parent)
bool prepareEnterTransition() override
QQmlComponent * delegate
QQuickMenu * currentSubMenu() const
QQuickPopupPositioner * getPositioner() override
void propagateKeyEvent(QKeyEvent *event)
void itemSiblingOrderChanged(QQuickItem *item) override
static QObject * contentData_at(QQmlListProperty< QObject > *prop, qsizetype index)
static void contentData_clear(QQmlListProperty< QObject > *prop)
QQuickItem * itemAt(int index) const
void moveItem(int from, int to)
QPalette defaultPalette() const override
static qsizetype contentData_count(QQmlListProperty< QObject > *prop)
QList< QObject * > contentData
void setCurrentIndex(int index, Qt::FocusReason reason)
QQuickItem * beginCreateItem()
QPointer< QQuickMenu > parentMenu
void itemDestroyed(QQuickItem *item) override
bool activatePreviousItem()
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &diff) override
void removeItem(int index, QQuickItem *item)
QPointer< QQuickMenuItem > currentItem
void itemParentChanged(QQuickItem *item, QQuickItem *parent) override
void onItemActiveFocusChanged()
void resizeItem(QQuickItem *item)
void insertItem(int index, QQuickItem *item)
static QQuickMenuPrivate * get(QQuickMenu *menu)
QQuickMenuItem * firstEnabledMenuItem() const
QQuickItem * contentItem
void itemChildAdded(QQuickItem *item, QQuickItem *child) override
QQuickItem * createItem(QQuickMenu *menu)
static void contentData_append(QQmlListProperty< QObject > *prop, QObject *obj)
bool prepareExitTransition() override
void setCurrentIndex(int index)
QString title
Q_INVOKABLE void addItem(QQuickItem *item)
\qmlmethod void QtQuick.Controls::Menu::addItem(Item item)
void timerEvent(QTimerEvent *event) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
QQuickMenu * menu
void setCascade(bool cascade)
QQmlComponent * delegate
Q_INVOKABLE void removeItem(QQuickItem *item)
void setTitle(const QString &title)
QQuickMenu(QObject *parent=nullptr)
void resetCascade()
void popup(QQuickItem *menuItem=nullptr)
Q_INVOKABLE void insertItem(int index, QQuickItem *item)
\qmlmethod void QtQuick.Controls::Menu::insertItem(int index, Item item)
Q_INVOKABLE QQuickItem * itemAt(int index) const
\qmlmethod Item QtQuick.Controls::Menu::itemAt(int index)
void setDelegate(QQmlComponent *delegate)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override
void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) override
void setOverlap(qreal overlap)
void keyPressEvent(QKeyEvent *event) override
QVariant contentModel
QQuickAction * action
Q_INVOKABLE void moveItem(int from, int to)
\qmlmethod void QtQuick.Controls::Menu::moveItem(int from, int to)
QQuickIcon icon
QFont defaultFont() const override
void setIcon(const QQuickIcon &icon)
qreal overlap
QQmlListProperty< QObject > contentData
\qmlproperty list<QtObject> QtQuick.Controls::Menu::contentData \qmldefault
void titleChanged(const QString &title)
QQuickPopup * popup() const
virtual bool blockInput(QQuickItem *item, const QPointF &point) const
QQuickItem * parentItem
void itemDestroyed(QQuickItem *item) override
QQuickPopupPositioner * positioner
QPointer< QQuickWindow > window
QQuickPopup::ClosePolicy closePolicy
bool contains(const QPointF &scenePos) const
virtual bool prepareExitTransition()
virtual bool prepareEnterTransition()
virtual void keyPressEvent(QKeyEvent *event)
void parentChanged()
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void close()
\qmlmethod void QtQuick.Controls::Popup::close()
virtual void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
void open()
\qmlmethod void QtQuick.Controls::Popup::open()
virtual void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
static QPalette palette(Scope scope)
static QFont font(Scope scope)
static QQuickWindowPrivate * get(QQuickWindow *c)
\inmodule QtCore\reentrant
Definition qrect.h:484
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
Definition qcoreevent.h:366
\inmodule QtCore
Definition qvariant.h:65
QPointF toPointF() const
Returns the variant as a QPointF if the variant has userType() \l QMetaType::QPoint or \l QMetaType::...
int userType() const
Definition qvariant.h:339
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
int width
the width of the widget excluding any window frame
Definition qwidget.h:114
int height
the height of the widget excluding any window frame
Definition qwidget.h:115
bool isEnabled() const
Definition qwidget.h:814
QPushButton * button
[2]
Combined button and popup list for selecting options.
@ Key_Right
Definition qnamespace.h:679
@ Key_Left
Definition qnamespace.h:677
@ Key_Alt
Definition qnamespace.h:686
@ Key_Up
Definition qnamespace.h:678
@ Key_Down
Definition qnamespace.h:680
FocusReason
@ PopupFocusReason
@ BacktabFocusReason
@ OtherFocusReason
@ TabFocusReason
static void * context
n void setPosition(void) \n\
GLint GLsizei GLsizei height
GLuint index
[2]
GLenum GLenum GLsizei count
GLuint object
[3]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei width
GLenum GLuint GLintptr offset
struct _cl_event * event
GLhandleARB obj
[2]
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
GLenum GLsizei len
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
void QQml_setParent_noEvent(QObject *object, QObject *parent)
Makes the object a child of parent.
QQuickItem * qobject_cast< QQuickItem * >(QObject *o)
Definition qquickitem.h:492
static QQuickItem * findParentMenuItem(QQuickMenu *subMenu)
static const QQuickPopup::ClosePolicy cascadingSubMenuClosePolicy
Menu popup that can be used as a context menu or popup menu.
static bool shouldCascade()
static QT_BEGIN_NAMESPACE const int SUBMENU_DELAY
#define QStringLiteral(str)
#define emit
ptrdiff_t qsizetype
Definition qtypes.h:165
double qreal
Definition qtypes.h:187
QString title
[35]
myObject disconnect()
[26]
QGraphicsItem * item
QLayoutItem * child
[0]
QMenu menu
[5]
QMenuBar * menuBar
[0]
QJSValueList args
bool contains(const AT &t) const noexcept
Definition qlist.h:45
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols=true)
const T * as() const
Definition qv4value_p.h:132
\inmodule QtQuick
Definition qquickitem.h:159