1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
|
// SPDX-License-Identifier: GPL-2.0
import QtQuick 2.5
Item {
id: container
signal actionSelected(int action)
readonly property var actions: {
"OPEN_LOCATION_IN_GOOGLE_MAPS": 0,
"COPY_LOCATION_DECIMAL": 1,
"COPY_LOCATION_SEXAGESIMAL": 2,
"SELECT_VISIBLE_LOCATIONS": 3
}
readonly property var menuItemData: [
{ idx: actions.OPEN_LOCATION_IN_GOOGLE_MAPS, itemText: qsTr("Open in Google Maps") },
{ idx: actions.COPY_LOCATION_DECIMAL, itemText: qsTr("Copy coordinates to clipboard (decimal)") },
{ idx: actions.COPY_LOCATION_SEXAGESIMAL, itemText: qsTr("Copy coordinates to clipboard (sexagesimal)") },
{ idx: actions.SELECT_VISIBLE_LOCATIONS, itemText: qsTr("Select visible dive locations") }
]
readonly property real itemTextPadding: 10.0
readonly property real itemHeight: 34.0
readonly property int itemAnimationDuration: 100
readonly property color colorItemBackground: "#dedede"
readonly property color colorItemBackgroundSelected: "grey"
readonly property color colorItemText: "black"
readonly property color colorItemTextSelected: "#dedede"
readonly property color colorItemBorder: "black"
property int listViewIsVisible: -1
property real maxItemWidth: 0.0
Image {
id: contextMenuImage
x: -width
source: "qrc:///open-menu-icon"
SequentialAnimation {
id:contextMenuImageAnimation
PropertyAnimation { target: contextMenuImage; property: "scale"; from: 1.0; to: 0.8; duration: 80 }
PropertyAnimation { target: contextMenuImage; property: "scale"; from: 0.8; to: 1.0; duration: 60 }
}
MouseArea {
anchors.fill: parent
onClicked: {
contextMenuImageAnimation.restart()
listViewIsVisible = (listViewIsVisible !== 1) ? 1 : 0
}
}
}
ListModel {
id: listModel
property int selectedIdx: -1
Component.onCompleted: {
for (var i = 0; i < menuItemData.length; i++)
append(menuItemData[i]);
}
}
Component {
id: listItemDelegate
Rectangle {
color: model.idx === listModel.selectedIdx ? colorItemBackgroundSelected : colorItemBackground
width: maxItemWidth
height: itemHeight
border.color: colorItemBorder
Text {
x: itemTextPadding
height: itemHeight
verticalAlignment: Text.AlignVCenter
text: model.itemText
font.pointSize: 10.0
color: model.idx === listModel.selectedIdx ? colorItemTextSelected : colorItemText
onWidthChanged: {
if (width + itemTextPadding * 2.0 > maxItemWidth)
maxItemWidth = width + itemTextPadding * 2.0
}
Behavior on color { ColorAnimation { duration: itemAnimationDuration }}
}
Behavior on color { ColorAnimation { duration: itemAnimationDuration }}
}
}
ListView {
id: listView
y: contextMenuImage.y + contextMenuImage.height + 10;
width: maxItemWidth;
height: listModel.count * itemHeight
visible: false
opacity: 0.0
interactive: false
model: listModel
delegate: listItemDelegate
onCountChanged: x = -maxItemWidth
onVisibleChanged: listModel.selectedIdx = -1
onOpacityChanged: visible = opacity != 0.0
Timer {
id: timerListViewVisible
running: false
repeat: false
interval: itemAnimationDuration + 50
onTriggered: listViewIsVisible = 0
}
MouseArea {
anchors.fill: parent
onClicked: {
if (opacity < 1.0)
return;
var idx = listView.indexAt(mouseX, mouseY)
listModel.selectedIdx = idx
container.actionSelected(idx)
timerListViewVisible.restart()
}
}
states: [
State { when: listViewIsVisible === 1; PropertyChanges { target: listView; opacity: 1.0 }},
State { when: listViewIsVisible === 0; PropertyChanges { target: listView; opacity: 0.0 }}
]
transitions: Transition { NumberAnimation { properties: "opacity"; easing.type: Easing.InOutQuad }}
}
}
|