Qt 6.x
The Qt SDK
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"
8#include "qquickmenubar_p.h"
11#include "qquickaction_p.h"
12
13#include <QtGui/qevent.h>
14#include <QtGui/qcursor.h>
15#if QT_CONFIG(shortcut)
16#include <QtGui/qkeysequence.h>
17#endif
18#include <QtGui/qpa/qplatformintegration.h>
19#include <QtGui/private/qguiapplication_p.h>
20#include <QtQml/qqmlcontext.h>
21#include <QtQml/qqmlcomponent.h>
22#include <QtQml/private/qqmlengine_p.h>
23#include <QtQml/private/qv4scopedvalue_p.h>
24#include <QtQml/private/qv4variantobject_p.h>
25#include <QtQml/private/qv4qobjectwrapper_p.h>
26#include <private/qqmlobjectmodel_p.h>
27#include <QtQuick/private/qquickitem_p.h>
28#include <QtQuick/private/qquickitemchangelistener_p.h>
29#include <QtQuick/private/qquickevents_p_p.h>
30#include <QtQuick/private/qquickwindow_p.h>
31
33
34// copied from qfusionstyle.cpp
35static const int SUBMENU_DELAY = 225;
36
41
200static const QQuickPopup::ClosePolicy cascadingSubMenuClosePolicy = QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutsideParent;
201
202static bool shouldCascade()
203{
204#if QT_CONFIG(cursor)
206#else
207 return false;
208#endif
209}
210
212{
213public:
215
216 void reposition() override;
217};
218
220{
222}
223
225{
226 Q_Q(QQuickMenu);
228}
229
231{
233}
234
236{
239 QQuickItemPrivate::get(item)->setCulled(true); // QTBUG-53262
240 if (complete)
244 contentModel->insert(index, item);
245
246 QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
247 if (menuItem) {
248 Q_Q(QQuickMenu);
250 if (QQuickMenu *subMenu = menuItem->subMenu())
255 }
256}
257
258void QQuickMenuPrivate::moveItem(int from, int to)
259{
260 contentModel->move(from, to);
261}
262
264{
266
269 item->setParentItem(nullptr);
270 contentModel->remove(index);
271
272 QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
273 if (menuItem) {
274 QQuickMenuItemPrivate::get(menuItem)->setMenu(nullptr);
275 if (QQuickMenu *subMenu = menuItem->subMenu())
276 QQuickMenuPrivate::get(subMenu)->setParentMenu(nullptr);
280 }
281}
282
284{
285 Q_Q(QQuickMenu);
286 if (!delegate)
287 return nullptr;
288
290 if (!context)
292
295 if (!item)
296 delete object;
297 else
299
300 return item;
301}
302
304{
305 if (!delegate)
306 return;
307
309}
310
312{
314 if (QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item))
317 return item;
318}
319
321{
323 if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(item))
324 button->setAction(action);
326 return item;
327}
328
330{
331 if (!item || !contentItem)
332 return;
333
335 if (!p->widthValid()) {
336 item->setWidth(contentItem->width());
337 p->widthValidFlag = false;
338 }
339}
340
342{
343 if (!contentModel)
344 return;
345
346 for (int i = 0; i < contentModel->count(); ++i)
348}
349
351{
352 // add dynamically reparented items (eg. by a Repeater)
353 if (!QQuickItemPrivate::get(child)->isTransparentForPositioner() && !contentData.contains(child))
355}
356
358{
359 // remove dynamically unparented items (eg. by a Repeater)
360 if (!parent)
362}
363
365{
366 // reorder the restacked items (eg. by a Repeater)
367 Q_Q(QQuickMenu);
369
370 int to = 0;
371 for (int i = 0; i < siblings.size(); ++i) {
372 QQuickItem* sibling = siblings.at(i);
373 if (QQuickItemPrivate::get(sibling)->isTransparentForPositioner())
374 continue;
375 int index = contentModel->indexOf(sibling, nullptr);
376 q->moveItem(index, to++);
377 }
378}
379
381{
383 int index = contentModel->indexOf(item, nullptr);
384 if (index != -1)
386}
387
389{
390 if (!complete)
391 return;
392
393 if (item == contentItem) {
394 // The contentItem's geometry changed, so resize any items
395 // that don't have explicit widths set so that they fill the width of the menu.
396 resizeItems();
397 } else {
398 // The geometry of an item in the menu changed. If the item
399 // doesn't have an explicit width set, make it fill the width of the menu.
401 }
402}
403
405{
406 Q_Q(QQuickMenu);
407 if (!positioner)
409 return positioner;
410}
411
413{
414 QQuickMenu *menu = static_cast<QQuickMenu *>(popup());
416 if (p->parentMenu) {
417 if (p->cascade) {
418 if (p->popupItem->isMirrored())
419 menu->setPosition(QPointF(-menu->width() - p->parentMenu->leftPadding() + menu->overlap(), -menu->topPadding()));
420 else if (p->parentItem)
421 menu->setPosition(QPointF(p->parentItem->width() + p->parentMenu->rightPadding() - menu->overlap(), -menu->topPadding()));
422 } else {
423 menu->setPosition(QPointF(p->parentMenu->x() + (p->parentMenu->width() - menu->width()) / 2,
424 p->parentMenu->y() + (p->parentMenu->height() - menu->height()) / 2));
425 }
426 }
428}
429
431{
432 Q_Q(QQuickMenu);
433 if (parentMenu && !cascade)
434 parentMenu->close();
435
436 // If a cascading sub-menu doesn't have enough space to open on
437 // the right, it flips on the other side of the parent menu.
439
441 return false;
442
443 if (!hasClosePolicy) {
444 if (cascade && parentMenu)
446 else
447 q->resetClosePolicy();
448 }
449 return true;
450}
451
453{
455 return false;
456
458
459 QQuickMenu *subMenu = currentSubMenu();
460 while (subMenu) {
461 QPointer<QQuickMenuItem> currentSubMenuItem = QQuickMenuPrivate::get(subMenu)->currentItem;
462 subMenu->close();
463 subMenu = currentSubMenuItem ? currentSubMenuItem->subMenu() : nullptr;
464 }
465 return true;
466}
467
469{
470 // keep the parent menu open when a cascading sub-menu (this menu) is interacted with
471 return (cascade && parentMenu && contains(point)) || QQuickPopupPrivate::blockInput(item, point);
472}
473
475{
476 Q_Q(QQuickMenu);
477 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->sender());
478 if (!button || !button->isHovered() || !button->isEnabled() || QQuickAbstractButtonPrivate::get(button)->touchId != -1)
479 return;
480
481 QQuickMenuItem *oldCurrentItem = currentItem;
482
483 int index = contentModel->indexOf(button, nullptr);
484 if (index != -1) {
486 if (oldCurrentItem != currentItem) {
487 if (oldCurrentItem) {
488 QQuickMenu *subMenu = oldCurrentItem->subMenu();
489 if (subMenu)
490 subMenu->close();
491 }
492 if (currentItem) {
493 QQuickMenu *subMenu = currentItem->menu();
494 if (subMenu && subMenu->cascade())
496 }
497 }
498 }
499}
500
502{
503 Q_Q(QQuickMenu);
504 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(q->sender());
505 if (!item)
506 return;
507
508 if (QQuickMenu *subMenu = item->subMenu()) {
509 auto subMenuPrivate = QQuickMenuPrivate::get(subMenu);
510 subMenu->popup(subMenuPrivate->firstEnabledMenuItem());
511 } else {
512 q->dismiss();
513 }
514}
515
517{
518 Q_Q(QQuickMenu);
520 if (!item->hasActiveFocus())
521 return;
522
523 int indexOfItem = contentModel->indexOf(item, nullptr);
524 QQuickControl *control = qobject_cast<QQuickControl *>(item);
525 setCurrentIndex(indexOfItem, control ? control->focusReason() : Qt::OtherFocusReason);
526}
527
529{
530 if (!currentItem)
531 return nullptr;
532
533 return currentItem->subMenu();
534}
535
537{
538 Q_Q(QQuickMenu);
539 if (parentMenu == parent)
540 return;
541
542 if (parentMenu) {
543 QObject::disconnect(parentMenu.data(), &QQuickMenu::cascadeChanged, q, &QQuickMenu::setCascade);
545 }
546 if (parent) {
547 QObject::connect(parent, &QQuickMenu::cascadeChanged, q, &QQuickMenu::setCascade);
549 }
550
552 q->resetCascade();
554}
555
557{
559 for (int i = 0; i < QQuickMenuPrivate::get(menu)->contentModel->count(); ++i) {
560 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(menu->itemAt(i));
561 if (item && item->subMenu() == subMenu)
562 return item;
563 }
564 return nullptr;
565}
566
568{
569 Q_Q(QQuickMenu);
570 if (!parentMenu)
571 q->resetParentItem();
572 else if (!cascade)
573 q->setParentItem(parentMenu->parentItem());
574 else
575 q->setParentItem(findParentMenuItem(q));
576}
577
579{
580 if (QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(parentItem)) {
581 if (QQuickMenu *menu = menuItem->menu())
583 } else if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(parentItem)) {
584 if (QQuickMenuBar *menuBar = menuBarItem->menuBar()) {
585 event->accept();
587 }
588 }
589}
590
592{
593 Q_Q(QQuickMenu);
595 hoverTimer = q->startTimer(SUBMENU_DELAY);
596}
597
599{
600 Q_Q(QQuickMenu);
601 if (!hoverTimer)
602 return;
603
604 q->killTimer(hoverTimer);
605 hoverTimer = 0;
606}
607
609{
610 Q_Q(QQuickMenu);
611 if (currentIndex == index)
612 return;
613
614 QQuickMenuItem *newCurrentItem = qobject_cast<QQuickMenuItem *>(itemAt(index));
615 if (currentItem != newCurrentItem) {
617 if (currentItem) {
619 if (!newCurrentItem && window) {
621 if (focusItem)
623 }
624 }
625 if (newCurrentItem) {
626 newCurrentItem->setHighlighted(true);
627 newCurrentItem->forceActiveFocus(reason);
628 }
629 currentItem = newCurrentItem;
630 }
631
633 emit q->currentIndexChanged();
634}
635
637{
638 int index = currentIndex;
639 int count = contentModel->count();
640 while (++index < count) {
642 if (!item || !item->activeFocusOnTab() || !item->isEnabled())
643 continue;
645 return true;
646 }
647 return false;
648}
649
651{
652 int index = currentIndex;
653 while (--index >= 0) {
655 if (!item || !item->activeFocusOnTab() || !item->isEnabled())
656 continue;
658 return true;
659 }
660 return false;
661}
662
664{
665 for (int i = 0; i < contentModel->count(); ++i) {
667 if (!item || !item->isEnabled())
668 continue;
669
670 QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
671 if (!menuItem)
672 continue;
673
674 return menuItem;
675 }
676 return nullptr;
677}
678
680{
681 QQuickMenu *q = qobject_cast<QQuickMenu *>(prop->object);
683
685 if (!item) {
686 if (QQuickAction *action = qobject_cast<QQuickAction *>(obj))
687 item = p->createItem(action);
688 else if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(obj))
689 item = p->createItem(menu);
690 }
691
692 if (item) {
693 if (QQuickItemPrivate::get(item)->isTransparentForPositioner()) {
695 item->setParentItem(p->contentItem);
696 } else if (p->contentModel->indexOf(item, nullptr) == -1) {
697 q->addItem(item);
698 }
699 } else {
700 p->contentData.append(obj);
701 }
702}
703
705{
706 QQuickMenu *q = static_cast<QQuickMenu *>(prop->object);
708}
709
711{
712 QQuickMenu *q = static_cast<QQuickMenu *>(prop->object);
714}
715
717{
719}
720
722{
723 QQuickMenu *q = static_cast<QQuickMenu *>(prop->object);
725}
726
729{
730 Q_D(QQuickMenu);
731 setFocus(true);
732 d->init();
733 connect(d->contentModel, &QQmlObjectModel::countChanged, this, &QQuickMenu::countChanged);
734}
735
737{
738 Q_D(QQuickMenu);
739 // We have to do this to ensure that the change listeners are removed.
740 // It's too late to do this in ~QQuickMenuPrivate, as contentModel has already
741 // been destroyed before that is called.
742 while (d->contentModel->count() > 0)
743 d->removeItem(0, d->itemAt(0));
744
745 if (d->contentItem) {
748 }
749}
750
757{
758 Q_D(const QQuickMenu);
759 return d->itemAt(index);
760}
761
768{
769 Q_D(QQuickMenu);
770 insertItem(d->contentModel->count(), item);
771}
772
779{
780 Q_D(QQuickMenu);
781 if (!item)
782 return;
783 const int count = d->contentModel->count();
784 if (index < 0 || index > count)
785 index = count;
786
787 int oldIndex = d->contentModel->indexOf(item, nullptr);
788 if (oldIndex != -1) {
789 if (oldIndex < index)
790 --index;
791 if (oldIndex != index)
792 d->moveItem(oldIndex, index);
793 } else {
794 d->insertItem(index, item);
795 }
796}
797
803void QQuickMenu::moveItem(int from, int to)
804{
805 Q_D(QQuickMenu);
806 const int count = d->contentModel->count();
807 if (from < 0 || from > count - 1)
808 return;
809 if (to < 0 || to > count - 1)
810 to = count - 1;
811
812 if (from != to)
813 d->moveItem(from, to);
814}
815
823{
824 Q_D(QQuickMenu);
825 if (!item)
826 return;
827
828 const int index = d->contentModel->indexOf(item, nullptr);
829 if (index == -1)
830 return;
831
832 d->removeItem(index, item);
833 item->deleteLater();
834}
835
844QQuickItem *QQuickMenu::takeItem(int index)
845{
846 Q_D(QQuickMenu);
847 const int count = d->contentModel->count();
848 if (index < 0 || index >= count)
849 return nullptr;
850
852 if (item)
853 d->removeItem(index, item);
854 return item;
855}
856
864QQuickMenu *QQuickMenu::menuAt(int index) const
865{
866 Q_D(const QQuickMenu);
867 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
868 if (!item)
869 return nullptr;
870
871 return item->subMenu();
872}
873
880void QQuickMenu::addMenu(QQuickMenu *menu)
881{
882 Q_D(QQuickMenu);
883 insertMenu(d->contentModel->count(), menu);
884}
885
892void QQuickMenu::insertMenu(int index, QQuickMenu *menu)
893{
894 Q_D(QQuickMenu);
895 if (!menu)
896 return;
897
898 insertItem(index, d->createItem(menu));
899}
900
907void QQuickMenu::removeMenu(QQuickMenu *menu)
908{
909 Q_D(QQuickMenu);
910 if (!menu)
911 return;
912
913 const int count = d->contentModel->count();
914 for (int i = 0; i < count; ++i) {
915 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(i));
916 if (!item || item->subMenu() != menu)
917 continue;
918
920 break;
921 }
922
923 menu->deleteLater();
924}
925
934QQuickMenu *QQuickMenu::takeMenu(int index)
935{
936 Q_D(QQuickMenu);
937 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
938 if (!item)
939 return nullptr;
940
941 QQuickMenu *subMenu = item->subMenu();
942 if (!subMenu)
943 return nullptr;
944
945 d->removeItem(index, item);
946 item->deleteLater();
947 return subMenu;
948}
949
957QQuickAction *QQuickMenu::actionAt(int index) const
958{
959 Q_D(const QQuickMenu);
960 QQuickAbstractButton *item = qobject_cast<QQuickAbstractButton *>(d->itemAt(index));
961 if (!item)
962 return nullptr;
963
964 return item->action();
965}
966
973void QQuickMenu::addAction(QQuickAction *action)
974{
975 Q_D(QQuickMenu);
976 insertAction(d->contentModel->count(), action);
977}
978
985void QQuickMenu::insertAction(int index, QQuickAction *action)
986{
987 Q_D(QQuickMenu);
988 if (!action)
989 return;
990
991 insertItem(index, d->createItem(action));
992}
993
1000void QQuickMenu::removeAction(QQuickAction *action)
1001{
1002 Q_D(QQuickMenu);
1003 if (!action)
1004 return;
1005
1006 const int count = d->contentModel->count();
1007 for (int i = 0; i < count; ++i) {
1008 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(i));
1009 if (!item || item->action() != action)
1010 continue;
1011
1013 break;
1014 }
1015
1017}
1018
1027QQuickAction *QQuickMenu::takeAction(int index)
1028{
1029 Q_D(QQuickMenu);
1030 QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
1031 if (!item)
1032 return nullptr;
1033
1034 QQuickAction *action = item->action();
1035 if (!action)
1036 return nullptr;
1037
1038 d->removeItem(index, item);
1039 item->deleteLater();
1040 return action;
1041}
1042
1065{
1066 Q_D(const QQuickMenu);
1067 return QVariant::fromValue(d->contentModel);
1068}
1069
1086{
1087 Q_D(QQuickMenu);
1088 if (!d->contentItem)
1090 return QQmlListProperty<QObject>(this, nullptr,
1095}
1096
1107{
1108 Q_D(const QQuickMenu);
1109 return d->title;
1110}
1111
1113{
1114 Q_D(QQuickMenu);
1115 if (title == d->title)
1116 return;
1117 d->title = title;
1119}
1120
1137{
1138 Q_D(const QQuickMenu);
1139 return d->icon;
1140}
1141
1143{
1144 Q_D(QQuickMenu);
1145 if (icon == d->icon)
1146 return;
1147 d->icon = icon;
1148 d->icon.ensureRelativeSourceResolved(this);
1149 emit iconChanged(icon);
1150}
1151
1167{
1168 Q_D(const QQuickMenu);
1169 return d->cascade;
1170}
1171
1172void QQuickMenu::setCascade(bool cascade)
1173{
1174 Q_D(QQuickMenu);
1175 if (d->cascade == cascade)
1176 return;
1177 d->cascade = cascade;
1178 if (d->parentMenu)
1179 d->resolveParentItem();
1180 emit cascadeChanged(cascade);
1181}
1182
1184{
1185 Q_D(QQuickMenu);
1186 if (d->parentMenu)
1187 setCascade(d->parentMenu->cascade());
1188 else
1190}
1191
1207{
1208 Q_D(const QQuickMenu);
1209 return d->overlap;
1210}
1211
1213{
1214 Q_D(QQuickMenu);
1215 if (d->overlap == overlap)
1216 return;
1217 d->overlap = overlap;
1218 emit overlapChanged();
1219}
1220
1239{
1240 Q_D(const QQuickMenu);
1241 return d->delegate;
1242}
1243
1245{
1246 Q_D(QQuickMenu);
1247 if (d->delegate == delegate)
1248 return;
1249
1250 d->delegate = delegate;
1251 emit delegateChanged();
1252}
1253
1265{
1266 Q_D(const QQuickMenu);
1267 return d->currentIndex;
1268}
1269
1271{
1272 Q_D(QQuickMenu);
1273 d->setCurrentIndex(index, Qt::OtherFocusReason);
1274}
1275
1284{
1285 Q_D(const QQuickMenu);
1286 return d->contentModel->count();
1287}
1288
1290{
1291 Q_D(QQuickMenu);
1292 // No position has been explicitly specified, so position the menu at the mouse cursor
1293 // on desktop platforms that have a mouse cursor available and support multiple windows.
1295#if QT_CONFIG(cursor)
1297 pos = d->parentItem->mapFromGlobal(QCursor::pos());
1298#endif
1299
1300 // As a fallback, center the menu over its parent item.
1301 if (pos.isNull && d->parentItem)
1302 pos = QPointF((d->parentItem->width() - width()) / 2, (d->parentItem->height() - height()) / 2);
1303
1304 popup(pos.isNull ? QPointF() : pos.value, menuItem);
1305}
1306
1308{
1309 Q_D(QQuickMenu);
1310 qreal offset = 0;
1311#if QT_CONFIG(cursor)
1312 if (menuItem)
1313 offset = d->popupItem->mapFromItem(menuItem, QPointF(0, 0)).y();
1314#endif
1316
1317 if (menuItem)
1318 d->setCurrentIndex(d->contentModel->indexOf(menuItem, nullptr), Qt::PopupFocusReason);
1319 open();
1320}
1321
1361{
1362 Q_D(QQuickMenu);
1363 const int len = args->length();
1364 if (len > 4) {
1365 args->v4engine()->throwTypeError();
1366 return;
1367 }
1368
1369 QV4::ExecutionEngine *v4 = args->v4engine();
1370 QV4::Scope scope(v4);
1371
1373 QQuickItem *menuItem = nullptr;
1374 QQuickItem *parentItem = nullptr;
1375
1376 if (len > 0) {
1377 // Item parent
1378 QV4::ScopedValue firstArg(scope, (*args)[0]);
1379 if (const QV4::QObjectWrapper *obj = firstArg->as<QV4::QObjectWrapper>()) {
1381 if (item && !d->popupItem->isAncestorOf(item))
1382 parentItem = item;
1383 } else if (firstArg->isUndefined()) {
1384 resetParentItem();
1385 parentItem = d->parentItem;
1386 }
1387
1388 // MenuItem item
1389 QV4::ScopedValue lastArg(scope, (*args)[len - 1]);
1390 if (const QV4::QObjectWrapper *obj = lastArg->as<QV4::QObjectWrapper>()) {
1392 if (item && d->popupItem->isAncestorOf(item))
1393 menuItem = item;
1394 }
1395 }
1396
1397 if (len >= 3 || (!parentItem && len >= 2)) {
1398 // real x, real y
1399 QV4::ScopedValue xArg(scope, (*args)[parentItem ? 1 : 0]);
1400 QV4::ScopedValue yArg(scope, (*args)[parentItem ? 2 : 1]);
1401 if (xArg->isNumber() && yArg->isNumber())
1402 pos = QPointF(xArg->asDouble(), yArg->asDouble());
1403 }
1404
1405 if (pos.isNull && (len >= 2 || (!parentItem && len >= 1))) {
1406 // point pos
1407 QV4::ScopedValue posArg(scope, (*args)[parentItem ? 1 : 0]);
1409 if (var.userType() == QMetaType::QPointF)
1410 pos = var.toPointF();
1411 }
1412
1413 if (parentItem)
1414 setParentItem(parentItem);
1415
1416 if (pos.isNull)
1417 popup(menuItem);
1418 else
1419 popup(pos, menuItem);
1420}
1421
1436void QQuickMenu::dismiss()
1437{
1438 QQuickMenu *menu = this;
1439 while (menu) {
1440 menu->close();
1442 }
1443}
1444
1446{
1447 Q_D(QQuickMenu);
1449 d->resizeItems();
1450}
1451
1453{
1454 Q_D(QQuickMenu);
1455 QQuickPopup::contentItemChange(newItem, oldItem);
1456
1457 if (oldItem) {
1460 }
1461 if (newItem) {
1464 }
1465
1466 d->contentItem = newItem;
1467}
1468
1470{
1471 Q_D(QQuickMenu);
1473
1474 if (change == QQuickItem::ItemVisibleHasChanged) {
1475 if (!data.boolValue && d->cascade) {
1476 // Ensure that when the menu isn't visible, there's no current item
1477 // the next time it's opened.
1478 d->setCurrentIndex(-1, Qt::OtherFocusReason);
1479 }
1480 }
1481}
1482
1484{
1485 Q_D(QQuickMenu);
1487
1488 // QTBUG-17051
1489 // Work around the fact that ListView has no way of distinguishing between
1490 // mouse and keyboard interaction, thanks to the "interactive" bool in Flickable.
1491 // What we actually want is to have a way to always allow keyboard interaction but
1492 // only allow flicking with the mouse when there are too many menu items to be
1493 // shown at once.
1494 switch (event->key()) {
1495 case Qt::Key_Up:
1496 if (!d->activatePreviousItem())
1497 d->propagateKeyEvent(event);
1498 break;
1499
1500 case Qt::Key_Down:
1501 d->activateNextItem();
1502 break;
1503
1504 case Qt::Key_Left:
1505 case Qt::Key_Right:
1506 event->ignore();
1507 if (d->popupItem->isMirrored() == (event->key() == Qt::Key_Right)) {
1508 if (d->parentMenu && d->currentItem) {
1509 if (!d->cascade)
1510 d->parentMenu->open();
1511 close();
1512 event->accept();
1513 }
1514 } else {
1515 if (QQuickMenu *subMenu = d->currentSubMenu()) {
1516 auto subMenuPrivate = QQuickMenuPrivate::get(subMenu);
1517 subMenu->popup(subMenuPrivate->firstEnabledMenuItem());
1518 event->accept();
1519 }
1520 }
1521 if (!event->isAccepted())
1522 d->propagateKeyEvent(event);
1523 break;
1524
1525#if QT_CONFIG(shortcut)
1526 case Qt::Key_Alt:
1527 // If &mnemonic shortcut is enabled, go back to (possibly) the parent
1528 // menu bar so the shortcut key will be processed by the menu bar.
1529 if (!QKeySequence::mnemonic(QStringLiteral("&A")).isEmpty())
1530 close();
1531 break;
1532#endif
1533
1534 default:
1535 break;
1536 }
1537}
1538
1540{
1541 Q_D(QQuickMenu);
1542 if (event->timerId() == d->hoverTimer) {
1543 if (QQuickMenu *subMenu = d->currentSubMenu())
1544 subMenu->open();
1545 d->stopHoverTimer();
1546 return;
1547 }
1549}
1550
1552{
1554}
1555
1556#if QT_CONFIG(accessibility)
1557QAccessible::Role QQuickMenu::accessibleRole() const
1558{
1559 return QAccessible::PopupMenu;
1560}
1561#endif
1562
1564
1565#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:20
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:423
static QKeySequence mnemonic(const QString &text)
Returns the shortcut key sequence for the mnemonic in text, or an empty key sequence if no mnemonics ...
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool removeOne(const AT &t)
Definition qlist.h:581
qsizetype length() const noexcept
Definition qlist.h:388
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
T value(qsizetype i) const
Definition qlist.h:661
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
\inmodule QtCore
Definition qmetatype.h:320
QObject * parent
Definition qobject.h:61
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:298
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:327
\inmodule QtCore
Definition qobject.h:90
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3099
virtual void timerEvent(QTimerEvent *event)
This event handler can be reimplemented in a subclass to receive timer events for the object.
Definition qobject.cpp:1433
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
The QPalette class contains color groups for each widget state.
Definition qpalette.h:19
virtual bool hasCapability(Capability cap) const
\inmodule QtCore\reentrant
Definition qpoint.h:214
\inmodule QtCore
Definition qpointer.h:18
T * data() const
Definition qpointer.h:56
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
The QQmlListProperty class allows applications to expose list-like properties of QObject-derived clas...
Definition qqmllist.h:24
QObject * object
Definition qqmllist.h:81
int count() const override
\qmlproperty int QtQml.Models::ObjectModel::count
int indexOf(QObject *object, QObject *objectContext) const override
static QQuickAbstractButtonPrivate * get(QQuickAbstractButton *button)
virtual void executeContentItem(bool complete=false)
static QQuickControlPrivate * get(QQuickControl *control)
void hoveredChanged()
Qt::FocusReason focusReason
void updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener, QQuickGeometryChange types)
QPointer< QQuickItem > subFocusItem
void removeItemChangeListener(QQuickItemChangeListener *, ChangeTypes types)
void addItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types)
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:64
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:76
Q_INVOKABLE void forceActiveFocus()
\qmlmethod point QtQuick::Item::mapToItem(Item item, real x, real y) \qmlmethod point QtQuick::Item::...
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:143
@ ItemVisibleHasChanged
Definition qquickitem.h:147
void setMenu(QQuickMenu *menu)
Presents an item within a Menu.
void setSubMenu(QQuickMenu *subMenu)
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)
void setTitle(QString &title)
QQmlComponent * delegate
Q_INVOKABLE void removeItem(QQuickItem *item)
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)
void clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason)
\inmodule QtCore\reentrant
Definition qrect.h:483
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
\inmodule QtCore
Definition qcoreevent.h:359
\inmodule QtCore
Definition qvariant.h:64
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:336
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:531
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:674
@ Key_Left
Definition qnamespace.h:672
@ Key_Alt
Definition qnamespace.h:681
@ Key_Up
Definition qnamespace.h:673
@ Key_Down
Definition qnamespace.h:675
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 width
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
struct _cl_event * event
GLhandleARB obj
[2]
GLenum GLsizei len
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:71
void QQml_setParent_noEvent(QObject *object, QObject *parent)
Makes the object a child of parent.
QQuickItem * qobject_cast< QQuickItem * >(QObject *o)
Definition qquickitem.h:483
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:70
double qreal
Definition qtypes.h:92
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:44
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols=true)
bool isNumber() const
double asDouble() const
const T * as() const
Definition qv4value_p.h:132
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent
\inmodule QtQuick
Definition qquickitem.h:158