2017-07-20 13:58:21 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2017-12-24 19:06:43 +00:00
|
|
|
import QtQuick 2.5
|
2017-07-20 13:58:21 +00:00
|
|
|
|
|
|
|
Item {
|
2017-07-20 22:28:58 +00:00
|
|
|
id: container
|
|
|
|
signal actionSelected(int action)
|
|
|
|
|
|
|
|
readonly property var actions: {
|
2017-07-20 21:55:13 +00:00
|
|
|
"OPEN_LOCATION_IN_GOOGLE_MAPS": 0,
|
|
|
|
"COPY_LOCATION_DECIMAL": 1,
|
2017-08-07 00:02:16 +00:00
|
|
|
"COPY_LOCATION_SEXAGESIMAL": 2,
|
|
|
|
"SELECT_VISIBLE_LOCATIONS": 3
|
2017-07-20 21:55:13 +00:00
|
|
|
}
|
|
|
|
readonly property var menuItemData: [
|
2018-03-14 17:02:36 +00:00
|
|
|
{ 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)") },
|
2017-08-07 00:02:16 +00:00
|
|
|
{ idx: actions.SELECT_VISIBLE_LOCATIONS, itemText: qsTr("Select visible dive locations") }
|
2017-07-20 21:55:13 +00:00
|
|
|
]
|
|
|
|
readonly property real itemTextPadding: 10.0
|
2017-07-25 20:54:16 +00:00
|
|
|
readonly property real itemHeight: 34.0
|
2017-07-20 21:55:13 +00:00
|
|
|
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
|
|
|
|
|
2017-07-20 15:25:01 +00:00
|
|
|
Image {
|
|
|
|
id: contextMenuImage
|
2017-07-20 16:25:59 +00:00
|
|
|
x: -width
|
2017-11-29 09:57:08 +00:00
|
|
|
source: "qrc:///open-menu-icon"
|
2017-07-20 15:25:01 +00:00
|
|
|
|
|
|
|
SequentialAnimation {
|
|
|
|
id:contextMenuImageAnimation
|
2017-07-28 13:40:28 +00:00
|
|
|
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 }
|
2017-07-20 15:25:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MouseArea {
|
|
|
|
anchors.fill: parent
|
|
|
|
onClicked: {
|
|
|
|
contextMenuImageAnimation.restart()
|
2017-07-20 21:41:37 +00:00
|
|
|
listViewIsVisible = (listViewIsVisible !== 1) ? 1 : 0
|
2017-07-20 15:25:01 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-20 13:58:21 +00:00
|
|
|
}
|
2017-07-20 16:30:34 +00:00
|
|
|
|
|
|
|
ListModel {
|
|
|
|
id: listModel
|
|
|
|
property int selectedIdx: -1
|
|
|
|
Component.onCompleted: {
|
|
|
|
for (var i = 0; i < menuItemData.length; i++)
|
|
|
|
append(menuItemData[i]);
|
|
|
|
}
|
|
|
|
}
|
2017-07-20 21:38:03 +00:00
|
|
|
|
|
|
|
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
|
2017-07-25 20:54:16 +00:00
|
|
|
font.pointSize: 10.0
|
2017-07-20 21:38:03 +00:00
|
|
|
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 }}
|
|
|
|
}
|
|
|
|
}
|
2017-07-20 21:41:37 +00:00
|
|
|
|
2017-07-20 21:49:31 +00:00
|
|
|
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
|
|
|
|
|
2017-07-20 21:55:13 +00:00
|
|
|
Timer {
|
|
|
|
id: timerListViewVisible
|
|
|
|
running: false
|
|
|
|
repeat: false
|
|
|
|
interval: itemAnimationDuration + 50
|
|
|
|
onTriggered: listViewIsVisible = 0
|
|
|
|
}
|
|
|
|
|
2017-07-20 21:49:31 +00:00
|
|
|
MouseArea {
|
|
|
|
anchors.fill: parent
|
|
|
|
onClicked: {
|
|
|
|
if (opacity < 1.0)
|
|
|
|
return;
|
2017-07-20 22:28:58 +00:00
|
|
|
var idx = listView.indexAt(mouseX, mouseY)
|
|
|
|
listModel.selectedIdx = idx
|
|
|
|
container.actionSelected(idx)
|
2017-07-20 21:55:13 +00:00
|
|
|
timerListViewVisible.restart()
|
2017-07-20 21:49:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
states: [
|
|
|
|
State { when: listViewIsVisible === 1; PropertyChanges { target: listView; opacity: 1.0 }},
|
|
|
|
State { when: listViewIsVisible === 0; PropertyChanges { target: listView; opacity: 0.0 }}
|
|
|
|
]
|
2017-07-28 13:40:28 +00:00
|
|
|
transitions: Transition { NumberAnimation { properties: "opacity"; easing.type: Easing.InOutQuad }}
|
2017-07-20 21:49:31 +00:00
|
|
|
}
|
2017-07-20 13:58:21 +00:00
|
|
|
}
|