mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-26 09:48:45 -05:00
24d80f8ab0
VOR localizer: Allow plugin to be compiled as static lib. SID feature: Allow plugin to be compiled as static lib. Satellite Tracker: Allow building without texttospeech or timezone. Map: Allow plugin to be compiled as static lib. Allow building without SSL. APT: Allow plugin to be compiled as static lib. Radio Astronomy: Allow plugin to be compiled as static lib. Allow building without process. ChannelWebAPIUtils: Fix memory leaks. DeviceSampleSource: Add signals that indicate when the position or direction of a device (or it's antenna) has changed. This is to support per device position, which is useful for remote devices not at My Position.
540 lines
20 KiB
QML
540 lines
20 KiB
QML
import QtQuick 2.14
|
|
import QtQuick.Window 2.14
|
|
import QtQuick.Controls 2.14
|
|
import QtPositioning 6.5
|
|
import QtLocation 6.5
|
|
import QtQuick.Effects
|
|
|
|
Item {
|
|
id: qmlMap
|
|
property int aircraftZoomLevel: 11
|
|
property int aircraftMinZoomLevel: 11
|
|
property int airportZoomLevel: 11
|
|
property string mapProvider: "osm"
|
|
property variant mapPtr
|
|
property string requestedMapType
|
|
property bool lightIcons
|
|
property variant guiPtr
|
|
property bool smoothing
|
|
|
|
function createMap(pluginParameters, requestedMap, gui) {
|
|
requestedMapType = requestedMap
|
|
guiPtr = gui
|
|
|
|
var paramString = ""
|
|
for (var prop in pluginParameters) {
|
|
var parameter = 'PluginParameter { name: "' + prop + '"; value: "' + pluginParameters[prop] + '"}'
|
|
paramString = paramString + parameter
|
|
}
|
|
var pluginString = 'import QtLocation 6.5; Plugin{ name:"' + mapProvider + '"; ' + paramString + '}'
|
|
var plugin = Qt.createQmlObject (pluginString, qmlMap)
|
|
|
|
if (mapPtr) {
|
|
// Objects aren't destroyed immediately, so don't call findChild("map")
|
|
mapPtr.destroy()
|
|
mapPtr = null
|
|
}
|
|
mapPtr = actualMapComponent.createObject(page)
|
|
mapPtr.map.plugin = plugin
|
|
mapPtr.map.forceActiveFocus()
|
|
return mapPtr
|
|
}
|
|
|
|
Item {
|
|
id: page
|
|
anchors.fill: parent
|
|
}
|
|
|
|
Component {
|
|
id: actualMapComponent
|
|
|
|
ModifiedMapView {
|
|
id: mapView
|
|
objectName: "mapView"
|
|
anchors.fill: parent
|
|
map.center: QtPositioning.coordinate(51.5, 0.125) // London
|
|
map.zoomLevel: 10
|
|
map.objectName: "map"
|
|
|
|
// not in 6
|
|
//gesture.enabled: true
|
|
//gesture.acceptedGestures: MapGestureArea.PinchGesture | MapGestureArea.PanGesture
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
propagateComposedEvents: true
|
|
onClicked: {
|
|
// Unhighlight current aircraft
|
|
guiPtr.clearHighlighted()
|
|
mouse.accepted = false
|
|
}
|
|
}
|
|
|
|
MapStation {
|
|
id: station
|
|
objectName: "station"
|
|
stationName: "Home"
|
|
parent: mapView.map
|
|
}
|
|
|
|
MapItemView {
|
|
model: airspaceModel
|
|
delegate: airspaceComponent
|
|
parent: mapView.map
|
|
}
|
|
|
|
MapItemView {
|
|
model: navAidModel
|
|
delegate: navAidComponent
|
|
parent: mapView.map
|
|
}
|
|
|
|
MapItemView {
|
|
model: airspaceModel
|
|
delegate: airspaceNameComponent
|
|
parent: mapView.map
|
|
}
|
|
|
|
MapItemView {
|
|
model: airportModel
|
|
delegate: airportComponent
|
|
parent: mapView.map
|
|
}
|
|
|
|
// This needs to be before aircraftComponent MapItemView, so it's drawn underneath
|
|
MapItemView {
|
|
model: aircraftModel
|
|
delegate: aircraftPathComponent
|
|
parent: mapView.map
|
|
}
|
|
|
|
MapItemView {
|
|
model: aircraftModel
|
|
delegate: aircraftComponent
|
|
parent: mapView.map
|
|
}
|
|
|
|
map.onZoomLevelChanged: {
|
|
if (map.zoomLevel > aircraftMinZoomLevel) {
|
|
aircraftZoomLevel = map.zoomLevel
|
|
} else {
|
|
aircraftZoomLevel = aircraftMinZoomLevel
|
|
}
|
|
if (map.zoomLevel > 11) {
|
|
station.zoomLevel = map.zoomLevel
|
|
airportZoomLevel = map.zoomLevel
|
|
} else {
|
|
station.zoomLevel = 11
|
|
airportZoomLevel = 11
|
|
}
|
|
}
|
|
|
|
map.onSupportedMapTypesChanged : {
|
|
for (var i = 0; i < map.supportedMapTypes.length; i++) {
|
|
if (requestedMapType == map.supportedMapTypes[i].name) {
|
|
map.activeMapType = map.supportedMapTypes[i]
|
|
}
|
|
}
|
|
lightIcons = (requestedMapType == "Night Transit Map") || (requestedMapType == "mapbox://styles/mapbox/dark-v9")
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: navAidComponent
|
|
MapQuickItem {
|
|
id: navAid
|
|
anchorPoint.x: image.width/2
|
|
anchorPoint.y: image.height/2
|
|
coordinate: position
|
|
zoomLevel: airportZoomLevel
|
|
|
|
sourceItem: Grid {
|
|
columns: 1
|
|
Grid {
|
|
horizontalItemAlignment: Grid.AlignHCenter
|
|
columnSpacing: 5
|
|
layer.enabled: smoothing
|
|
layer.smooth: smoothing
|
|
Image {
|
|
id: image
|
|
source: navAidImage
|
|
visible: !lightIcons
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: (mouse) => {
|
|
selected = !selected
|
|
}
|
|
}
|
|
}
|
|
MultiEffect {
|
|
width: image.width
|
|
height: image.height
|
|
source: image
|
|
brightness: 1.0
|
|
colorization: 1.0
|
|
colorizationColor: "#c0ffffff"
|
|
visible: lightIcons
|
|
}
|
|
Rectangle {
|
|
id: bubble
|
|
color: bubbleColour
|
|
border.width: 1
|
|
width: text.width + 5
|
|
height: text.height + 5
|
|
radius: 5
|
|
Text {
|
|
id: text
|
|
anchors.centerIn: parent
|
|
text: navAidData
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: (mouse) => {
|
|
selected = !selected
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: airspaceComponent
|
|
MapPolygon {
|
|
border.width: 1
|
|
border.color: airspaceBorderColor
|
|
color: airspaceFillColor
|
|
path: airspacePolygon
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: airspaceNameComponent
|
|
MapQuickItem {
|
|
coordinate: position
|
|
anchorPoint.x: airspaceText.width/2
|
|
anchorPoint.y: airspaceText.height/2
|
|
zoomLevel: airportZoomLevel
|
|
sourceItem: Grid {
|
|
columns: 1
|
|
Grid {
|
|
layer.enabled: smoothing
|
|
layer.smooth: smoothing
|
|
horizontalItemAlignment: Grid.AlignHCenter
|
|
Text {
|
|
id: airspaceText
|
|
text: details
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: aircraftPathComponent
|
|
MapPolyline {
|
|
line.width: 2
|
|
line.color: 'gray'
|
|
path: aircraftPath
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: aircraftComponent
|
|
MapQuickItem {
|
|
id: aircraft
|
|
anchorPoint.x: image.width/2
|
|
anchorPoint.y: image.height/2
|
|
coordinate: position
|
|
zoomLevel: aircraftZoomLevel
|
|
|
|
sourceItem: Grid {
|
|
columns: 1
|
|
Grid {
|
|
layer.enabled: smoothing
|
|
layer.smooth: smoothing
|
|
horizontalItemAlignment: Grid.AlignHCenter
|
|
Image {
|
|
id: image
|
|
rotation: heading
|
|
source: aircraftImage
|
|
visible: !lightIcons
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
onClicked: {
|
|
if (mouse.button === Qt.LeftButton) {
|
|
highlighted = true
|
|
console.log("z=" + aircraft.sourceItem.z)
|
|
aircraft.sourceItem.z = aircraft.sourceItem.z + 1
|
|
} else if (mouse.button === Qt.RightButton) {
|
|
contextMenu.popup()
|
|
}
|
|
}
|
|
onDoubleClicked: {
|
|
target = true
|
|
}
|
|
}
|
|
}
|
|
MultiEffect {
|
|
width: image.width
|
|
height: image.height
|
|
rotation: heading
|
|
source: image
|
|
brightness: 1.0
|
|
colorization: 1.0
|
|
colorizationColor: "#c0ffffff"
|
|
visible: lightIcons
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
highlighted = true
|
|
}
|
|
onDoubleClicked: {
|
|
target = true
|
|
}
|
|
}
|
|
}
|
|
Rectangle {
|
|
id: bubble
|
|
color: bubbleColour
|
|
border.width: 1
|
|
width: text.width * 1.1
|
|
height: text.height * 1.1
|
|
radius: 5
|
|
Text {
|
|
id: text
|
|
anchors.centerIn: parent
|
|
text: adsbData
|
|
textFormat: TextEdit.RichText
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
onClicked: {
|
|
if (mouse.button === Qt.LeftButton) {
|
|
showAll = !showAll
|
|
} else if (mouse.button === Qt.RightButton) {
|
|
contextMenu.popup()
|
|
}
|
|
}
|
|
Menu {
|
|
id: contextMenu
|
|
MenuItem {
|
|
text: "Set as target"
|
|
onTriggered: target = true
|
|
}
|
|
MenuItem {
|
|
text: "Find on feature map"
|
|
onTriggered: aircraftModel.findOnMap(index)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: airportComponent
|
|
MapItemGroup {
|
|
MapItemGroup {
|
|
property var groupVisible: false
|
|
id: rangeGroup
|
|
MapCircle {
|
|
id: circle5nm
|
|
center: position
|
|
color: "transparent"
|
|
border.color: "gray"
|
|
radius: 9260 // 5nm in metres
|
|
visible: rangeGroup.groupVisible
|
|
}
|
|
MapCircle {
|
|
id: circle10nm
|
|
center: position
|
|
color: "transparent"
|
|
border.color: "gray"
|
|
radius: 18520
|
|
visible: rangeGroup.groupVisible
|
|
}
|
|
MapCircle {
|
|
id: circle15nm
|
|
center: airport.coordinate
|
|
color: "transparent"
|
|
border.color: "gray"
|
|
radius: 27780
|
|
visible: rangeGroup.groupVisible
|
|
}
|
|
MapQuickItem {
|
|
id: text5nm
|
|
coordinate {
|
|
latitude: position.latitude
|
|
longitude: position.longitude + (5/60)/Math.cos(Math.abs(position.latitude)*Math.PI/180)
|
|
}
|
|
anchorPoint.x: 0
|
|
anchorPoint.y: height/2
|
|
sourceItem: Text {
|
|
color: "grey"
|
|
text: "5nm"
|
|
}
|
|
visible: rangeGroup.groupVisible
|
|
}
|
|
MapQuickItem {
|
|
id: text10nm
|
|
coordinate {
|
|
latitude: position.latitude
|
|
longitude: position.longitude + (10/60)/Math.cos(Math.abs(position.latitude)*Math.PI/180)
|
|
}
|
|
anchorPoint.x: 0
|
|
anchorPoint.y: height/2
|
|
sourceItem: Text {
|
|
color: "grey"
|
|
text: "10nm"
|
|
}
|
|
visible: rangeGroup.groupVisible
|
|
}
|
|
MapQuickItem {
|
|
id: text15nm
|
|
coordinate {
|
|
latitude: position.latitude
|
|
longitude: position.longitude + (15/60)/Math.cos(Math.abs(position.latitude)*Math.PI/180)
|
|
}
|
|
anchorPoint.x: 0
|
|
anchorPoint.y: height/2
|
|
sourceItem: Text {
|
|
color: "grey"
|
|
text: "15nm"
|
|
}
|
|
visible: rangeGroup.groupVisible
|
|
}
|
|
}
|
|
|
|
MapQuickItem {
|
|
id: airport
|
|
anchorPoint.x: image.width/2
|
|
anchorPoint.y: image.height/2
|
|
coordinate: position
|
|
zoomLevel: airportZoomLevel
|
|
sourceItem: Grid {
|
|
columns: 1
|
|
Grid {
|
|
horizontalItemAlignment: Grid.AlignHCenter
|
|
layer.enabled: smoothing
|
|
layer.smooth: smoothing
|
|
Image {
|
|
id: image
|
|
source: airportImage
|
|
visible: !lightIcons
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
onClicked: (mouse) => {
|
|
if (mouse.button === Qt.RightButton) {
|
|
showRangeItem.visible = !rangeGroup.groupVisible
|
|
hideRangeItem.visible = rangeGroup.groupVisible
|
|
menuItems.clear()
|
|
var scanners = airportModel.getFreqScanners()
|
|
for (var i = 0; i < scanners.length; i++) {
|
|
menuItems.append({
|
|
text: "Send to Frequency Scanner " + scanners[i],
|
|
airport: index,
|
|
scanner: scanners[i]
|
|
})
|
|
}
|
|
contextMenu.popup()
|
|
}
|
|
}
|
|
onDoubleClicked: (mouse) => {
|
|
rangeGroup.groupVisible = !rangeGroup.groupVisible
|
|
}
|
|
|
|
ListModel {
|
|
id: menuItems
|
|
}
|
|
|
|
Menu {
|
|
id: contextMenu
|
|
MenuItem {
|
|
id: showRangeItem
|
|
text: "Show range rings"
|
|
onTriggered: rangeGroup.groupVisible = true
|
|
height: visible ? implicitHeight : 0
|
|
}
|
|
MenuItem {
|
|
id: hideRangeItem
|
|
text: "Hide range rings"
|
|
onTriggered: rangeGroup.groupVisible = false
|
|
height: visible ? implicitHeight : 0
|
|
}
|
|
Instantiator {
|
|
model: menuItems
|
|
MenuItem {
|
|
text: model.text
|
|
onTriggered: airportModel.sendToFreqScanner(model.airport, model.scanner)
|
|
}
|
|
onObjectAdded: function(index, object) {
|
|
contextMenu.insertItem(index, object)
|
|
}
|
|
onObjectRemoved: function(index, object) {
|
|
contextMenu.removeItem(object)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
MultiEffect {
|
|
width: image.width
|
|
height: image.height
|
|
source: image
|
|
brightness: 1.0
|
|
colorization: 1.0
|
|
colorizationColor: "#c0ffffff"
|
|
visible: lightIcons
|
|
}
|
|
Rectangle {
|
|
id: bubble
|
|
color: bubbleColour
|
|
border.width: 1
|
|
width: text.width + 5
|
|
height: text.height + 5
|
|
radius: 5
|
|
Text {
|
|
id: text
|
|
anchors.centerIn: parent
|
|
text: airportData
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: (mouse) => {
|
|
if (showFreq) {
|
|
var freqIdx = Math.floor((mouse.y-5)/((height-10)/airportDataRows))
|
|
if (freqIdx == 0) {
|
|
showFreq = false
|
|
}
|
|
} else {
|
|
showFreq = true
|
|
}
|
|
}
|
|
onDoubleClicked: (mouse) => {
|
|
if (showFreq) {
|
|
var freqIdx = Math.floor((mouse.y-5)/((height-10)/airportDataRows))
|
|
if (freqIdx != 0) {
|
|
selectedFreq = freqIdx - 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|