Revision control
++ // Copyright (C) 2023 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
++
++ //![0]
++ import QtQuick
++
++ Rectangle {
++ id: rect
++ width: 140; height: 100
++
++ //![1]
++ TapHandler {
++ id: menuPopupHandler
++ gesturePolicy: TapHandler.DragWithinBounds
++ onPressedChanged:
++ if (pressed) {
++ menu.x = point.position.x - menu.width / 2
++ menu.y = point.position.y - menu.height / 2
++ } else {
++ feedback.text = menu.highlightedMenuItem
++ selectFlash.start()
++ }
++ onCanceled: feedback.text = "canceled"
++ }
++ //![1]
++
++ Column {
++ id: menu
++ visible: menuPopupHandler.pressed
++ opacity: Math.min(1, menuPopupHandler.timeHeld)
++ property string highlightedMenuItem: ""
++ Repeater {
++ model: [ "top", "middle", "bottom" ]
++ delegate: Rectangle {
++ property bool highlighted: menuPopupHandler.pressed &&
++ contains(mapFromItem(rect, menuPopupHandler.point.position))
++ onHighlightedChanged: {
++ if (highlighted)
++ menu.highlightedMenuItem = menuItemText.text
++ else if (menu.highlightedMenuItem === menuItemText.text)
++ menu.highlightedMenuItem = ""
++ }
++ width: 100
++ height: 20
++ color: highlighted ? "lightsteelblue" : "aliceblue"
++ Text {
++ id: menuItemText
++ anchors.centerIn: parent
++ text: modelData
++ }
++ }
++ }
++ }
++
++ Text {
++ id: feedback
++ y: 6; anchors.horizontalCenter: parent.horizontalCenter
++ textFormat: Text.MarkdownText
++ text: "hold for context menu"
++
++ SequentialAnimation on font.weight {
++ id: selectFlash
++ running: false
++ loops: 3
++ PropertyAction { value: Font.Black }
++ PauseAnimation { duration: 100 }
++ PropertyAction { value: Font.Normal }
++ PauseAnimation { duration: 100 }
++ }
++ }
++ }
++ //![0]