/**************************************************************************** * * (c) 2009-2016 QGROUNDCONTROL PROJECT * * QGroundControl is licensed according to the terms in the file * COPYING.md in the root of the source code directory. * ****************************************************************************/ import QtQuick 2.3 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.2 import QtQuick.Layouts 1.2 import QtLocation 5.3 import QtPositioning 5.3 import QGroundControl 1.0 import QGroundControl.Controls 1.0 import QGroundControl.ScreenTools 1.0 import QGroundControl.Palette 1.0 import QGroundControl.FlightMap 1.0 import QGroundControl.QGCMapEngineManager 1.0 import QGroundControl.FactSystem 1.0 import QGroundControl.FactControls 1.0 QGCView { id: offlineMapView viewPanel: panel anchors.fill: parent property var _currentSelection: null property string mapKey: "lastMapType" property Fact _mapboxFact: QGroundControl.settingsManager.appSettings.mapboxToken property Fact _esriFact: QGroundControl.settingsManager.appSettings.esriToken property string mapType: _settings.mapProvider.enumStringValue + " " + _settings.mapType.enumStringValue property bool isMapInteractive: false property var savedCenter: undefined property real savedZoom: 3 property string savedMapType: "" property bool _showPreview: true property bool _defaultSet: offlineMapView && offlineMapView._currentSelection && offlineMapView._currentSelection.defaultSet property real _margins: ScreenTools.defaultFontPixelWidth * 0.5 property real _buttonSize: ScreenTools.defaultFontPixelWidth * 12 property real _bigButtonSize: ScreenTools.defaultFontPixelWidth * 16 property bool _saveRealEstate: ScreenTools.isTinyScreen || ScreenTools.isShortScreen property real _adjustableFontPointSize: _saveRealEstate ? ScreenTools.smallFontPointSize : ScreenTools.defaultFontPointSize property var _mapAdjustedColor: _map.isSatelliteMap ? "white" : "black" property bool _tooManyTiles: QGroundControl.mapEngineManager.tileCount > _maxTilesForDownload property var _settings: QGroundControl.settingsManager.flightMapSettings readonly property real minZoomLevel: 1 readonly property real maxZoomLevel: 20 readonly property real sliderTouchArea: ScreenTools.defaultFontPixelWidth * (ScreenTools.isTinyScreen ? 5 : (ScreenTools.isMobile ? 6 : 3)) readonly property int _maxTilesForDownload: 100000 QGCPalette { id: qgcPal } Component.onCompleted: { QGroundControl.mapEngineManager.loadTileSets() updateMap() savedCenter = _map.toCoordinate(Qt.point(_map.width / 2, _map.height / 2), false /* clipToViewPort */) } Connections { target: QGroundControl.mapEngineManager onTileSetsChanged: { setName.text = QGroundControl.mapEngineManager.getUniqueName() } onErrorMessageChanged: { errorDialog.visible = true } } ExclusiveGroup { id: setGroup } function handleChanges() { if(isMapInteractive) { var xl = 0 var yl = 0 var xr = _map.width.toFixed(0) - 1 // Must be within boundaries of visible map var yr = _map.height.toFixed(0) - 1 // Must be within boundaries of visible map var c0 = _map.toCoordinate(Qt.point(xl, yl), false /* clipToViewPort */) var c1 = _map.toCoordinate(Qt.point(xr, yr), false /* clipToViewPort */) QGroundControl.mapEngineManager.updateForCurrentView(c0.longitude, c0.latitude, c1.longitude, c1.latitude, sliderMinZoom.value, sliderMaxZoom.value, mapType) } } function updateMap() { for (var i = 0; i < _map.supportedMapTypes.length; i++) { //console.log(_map.supportedMapTypes[i].name) if (mapType === _map.supportedMapTypes[i].name) { _map.activeMapType = _map.supportedMapTypes[i] //console.log("Update Map:" + " " + _map.activeMapType) handleChanges() return } } } function addNewSet() { isMapInteractive = true mapType = _settings.mapProvider.enumStringValue + " " + _settings.mapType.enumStringValue resetMapToDefaults() handleChanges() _map.visible = true _tileSetList.visible = false infoView.visible = false _exporTiles.visible = false addNewSetView.visible = true } function showList() { _exporTiles.visible = false isMapInteractive = false _map.visible = false _tileSetList.visible = true infoView.visible = false addNewSetView.visible = false QGroundControl.mapEngineManager.resetAction(); } function showExport() { isMapInteractive = false _map.visible = false _tileSetList.visible = false infoView.visible = false addNewSetView.visible = false _exporTiles.visible = true } function showInfo() { isMapInteractive = false if(_currentSelection && !offlineMapView._currentSelection.deleting) { enterInfoView() } else showList() } function toRadian(deg) { return deg * Math.PI / 180 } function toDegree(rad) { return rad * 180 / Math.PI } function midPoint(lat1, lat2, lon1, lon2) { var dLon = toRadian(lon2 - lon1); lat1 = toRadian(lat1); lat2 = toRadian(lat2); lon1 = toRadian(lon1); var Bx = Math.cos(lat2) * Math.cos(dLon); var By = Math.cos(lat2) * Math.sin(dLon); var lat3 = Math.atan2(Math.sin(lat1) + Math.sin(lat2), Math.sqrt((Math.cos(lat1) + Bx) * (Math.cos(lat1) + Bx) + By * By)); var lon3 = lon1 + Math.atan2(By, Math.cos(lat1) + Bx); return QtPositioning.coordinate(toDegree(lat3), toDegree(lon3)) } function enterInfoView() { _map.visible = true isMapInteractive = false savedCenter = _map.toCoordinate(Qt.point(_map.width / 2, _map.height / 2), false /* clipToViewPort */) savedZoom = _map.zoomLevel savedMapType = mapType if(!offlineMapView._currentSelection.defaultSet) { mapType = offlineMapView._currentSelection.mapTypeStr _map.center = midPoint(offlineMapView._currentSelection.topleftLat, offlineMapView._currentSelection.bottomRightLat, offlineMapView._currentSelection.topleftLon, offlineMapView._currentSelection.bottomRightLon) //-- Delineate Set Region var x0 = offlineMapView._currentSelection.topleftLon var x1 = offlineMapView._currentSelection.bottomRightLon var y0 = offlineMapView._currentSelection.topleftLat var y1 = offlineMapView._currentSelection.bottomRightLat mapBoundary.topLeft = QtPositioning.coordinate(y0, x0) mapBoundary.bottomRight = QtPositioning.coordinate(y1, x1) mapBoundary.visible = true // Some times, for whatever reason, the bounding box is correct (around ETH for instance), but the rectangle is drawn across the planet. // When that happens, the "_map.fitViewportToMapItems()" below makes the map to zoom to the entire earth. //console.log("Map boundary: " + mapBoundary.topLeft + " " + mapBoundary.bottomRight) _map.fitViewportToMapItems() } _tileSetList.visible = false addNewSetView.visible = false infoView.visible = true } function leaveInfoView() { mapBoundary.visible = false _map.center = savedCenter _map.zoomLevel = savedZoom mapType = savedMapType } function resetMapToDefaults() { _map.center = QGroundControl.flightMapPosition _map.zoomLevel = QGroundControl.flightMapZoom } ExclusiveGroup { id: _dropButtonsExclusiveGroup } onMapTypeChanged: { updateMap() if(isMapInteractive) { QGroundControl.mapEngineManager.saveSetting(mapKey, mapType) } } MessageDialog { id: errorDialog visible: false text: QGroundControl.mapEngineManager.errorMessage icon: StandardIcon.Critical standardButtons: StandardButton.Ok title: qsTr("Error Message") onYes: { errorDialog.visible = false } } Component { id: optionsDialogComponent QGCViewDialog { id: optionDialog function accept() { QGroundControl.mapEngineManager.maxDiskCache = parseInt(maxCacheSize.text) QGroundControl.mapEngineManager.maxMemCache = parseInt(maxCacheMemSize.text) optionDialog.hideDialog() } QGCFlickable { anchors.fill: parent contentHeight: optionsColumn.height Column { id: optionsColumn anchors.margins: ScreenTools.defaultFontPixelWidth anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top spacing: ScreenTools.defaultFontPixelHeight / 2 QGCLabel { text: qsTr("Max Cache Disk Size (MB):") } QGCTextField { id: maxCacheSize maximumLength: 6 inputMethodHints: Qt.ImhDigitsOnly validator: IntValidator {bottom: 1; top: 262144;} text: QGroundControl.mapEngineManager.maxDiskCache } Item { width: 1; height: 1 } QGCLabel { text: qsTr("Max Cache Memory Size (MB):") } QGCTextField { id: maxCacheMemSize maximumLength: 4 inputMethodHints: Qt.ImhDigitsOnly validator: IntValidator {bottom: 1; top: 1024;} text: QGroundControl.mapEngineManager.maxMemCache } QGCLabel { font.pointSize: _adjustableFontPointSize text: qsTr("Memory cache changes require a restart to take effect.") } Item { width: 1; height: 1; visible: _mapboxFact ? _mapboxFact.visible : false } QGCLabel { text: qsTr("Mapbox Access Token"); visible: _mapboxFact ? _mapboxFact.visible : false } FactTextField { fact: _mapboxFact visible: _mapboxFact ? _mapboxFact.visible : false maximumLength: 256 width: ScreenTools.defaultFontPixelWidth * 30 } QGCLabel { text: qsTr("To enable Mapbox maps, enter your access token.") visible: _mapboxFact ? _mapboxFact.visible : false font.pointSize: _adjustableFontPointSize } Item { width: 1; height: 1; visible: _esriFact ? _esriFact.visible : false } QGCLabel { text: qsTr("Esri Access Token"); visible: _esriFact ? _esriFact.visible : false } FactTextField { fact: _esriFact visible: _esriFact ? _esriFact.visible : false maximumLength: 256 width: ScreenTools.defaultFontPixelWidth * 30 } QGCLabel { text: qsTr("To enable Esri maps, enter your access token.") visible: _esriFact ? _esriFact.visible : false font.pointSize: _adjustableFontPointSize } } // GridLayout } // QGCFlickable } // QGCViewDialog - optionsDialog } // Component - optionsDialogComponent Component { id: deleteConfirmationDialogComponent QGCViewMessage { id: deleteConfirmationDialog message: { if(offlineMapView._currentSelection.defaultSet) return qsTr("This will delete all tiles INCLUDING the tile sets you have created yourself.\n\nIs this really what you want?"); else return qsTr("Delete %1 and all its tiles.\n\nIs this really what you want?").arg(offlineMapView._currentSelection.name); } function accept() { QGroundControl.mapEngineManager.deleteTileSet(offlineMapView._currentSelection) deleteConfirmationDialog.hideDialog() leaveInfoView() showList() } } } QGCViewPanel { id: panel anchors.fill: parent FlightMap { id: _map anchors.fill: parent visible: false allowGCSLocationCenter: true allowVehicleLocationCenter: false gesture.flickDeceleration: 3000 mapName: "OfflineMap" property bool isSatelliteMap: activeMapType.name.indexOf("Satellite") > -1 || activeMapType.name.indexOf("Hybrid") > -1 MapRectangle { id: mapBoundary border.width: 2 border.color: "red" color: Qt.rgba(1,0,0,0.05) smooth: true antialiasing: true } Component.onCompleted: resetMapToDefaults() onCenterChanged: handleChanges() onZoomLevelChanged: handleChanges() onWidthChanged: handleChanges() onHeightChanged: handleChanges() // Used to make pinch zoom work MouseArea { anchors.fill: parent } MapScale { anchors.leftMargin: ScreenTools.defaultFontPixelWidth / 2 anchors.bottomMargin: anchors.leftMargin anchors.left: parent.left anchors.bottom: parent.bottom mapControl: _map } //----------------------------------------------------------------- //-- Show Set Info Rectangle { id: infoView anchors.margins: ScreenTools.defaultFontPixelHeight anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter width: tileInfoColumn.width + (ScreenTools.defaultFontPixelWidth * 2) height: tileInfoColumn.height + (ScreenTools.defaultFontPixelHeight * 2) color: Qt.rgba(qgcPal.window.r, qgcPal.window.g, qgcPal.window.b, 0.85) radius: ScreenTools.defaultFontPixelWidth * 0.5 visible: false property bool _extraButton: { if(!offlineMapView._currentSelection) return false; var curSel = offlineMapView._currentSelection; return !_defaultSet && ((!curSel.complete && !curSel.downloading) || (!curSel.complete && curSel.downloading)); } property real _labelWidth: ScreenTools.defaultFontPixelWidth * 10 property real _valueWidth: ScreenTools.defaultFontPixelWidth * 14 Column { id: tileInfoColumn anchors.margins: ScreenTools.defaultFontPixelHeight * 0.5 spacing: ScreenTools.defaultFontPixelHeight * 0.5 anchors.centerIn: parent QGCLabel { anchors.left: parent.left anchors.right: parent.right wrapMode: Text.WordWrap text: offlineMapView._currentSelection ? offlineMapView._currentSelection.name : "" font.pointSize: _saveRealEstate ? ScreenTools.defaultFontPointSize : ScreenTools.mediumFontPointSize horizontalAlignment: Text.AlignHCenter visible: _defaultSet } QGCTextField { id: editSetName anchors.left: parent.left anchors.right: parent.right visible: !_defaultSet text: offlineMapView._currentSelection ? offlineMapView._currentSelection.name : "" } QGCLabel { anchors.left: parent.left anchors.right: parent.right wrapMode: Text.WordWrap text: { if(offlineMapView._currentSelection) { if(offlineMapView._currentSelection.defaultSet) return qsTr("System Wide Tile Cache"); else return "(" + offlineMapView._currentSelection.mapTypeStr + ")" } else return ""; } horizontalAlignment: Text.AlignHCenter } //-- Tile Sets Row { spacing: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter visible: !_defaultSet QGCLabel { text: qsTr("Zoom Levels:"); width: infoView._labelWidth; } QGCLabel { text: offlineMapView._currentSelection ? (offlineMapView._currentSelection.minZoom + " - " + offlineMapView._currentSelection.maxZoom) : ""; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth; } } Row { spacing: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter visible: !_defaultSet QGCLabel { text: qsTr("Total:"); width: infoView._labelWidth; } QGCLabel { text: (offlineMapView._currentSelection ? offlineMapView._currentSelection.totalTileCountStr : "") + " (" + (offlineMapView._currentSelection ? offlineMapView._currentSelection.totalTilesSizeStr : "") + ")"; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth; } } Row { spacing: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter visible: offlineMapView && offlineMapView._currentSelection && !_defaultSet && offlineMapView._currentSelection.uniqueTileCount > 0 QGCLabel { text: qsTr("Unique:"); width: infoView._labelWidth; } QGCLabel { text: (offlineMapView._currentSelection ? offlineMapView._currentSelection.uniqueTileCountStr : "") + " (" + (offlineMapView._currentSelection ? offlineMapView._currentSelection.uniqueTileSizeStr : "") + ")"; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth; } } Row { spacing: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter visible: offlineMapView && offlineMapView._currentSelection && !_defaultSet && !offlineMapView._currentSelection.complete QGCLabel { text: qsTr("Downloaded:"); width: infoView._labelWidth; } QGCLabel { text: (offlineMapView._currentSelection ? offlineMapView._currentSelection.savedTileCountStr : "") + " (" + (offlineMapView._currentSelection ? offlineMapView._currentSelection.savedTileSizeStr : "") + ")"; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth; } } Row { spacing: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter visible: offlineMapView && offlineMapView._currentSelection && !_defaultSet && !offlineMapView._currentSelection.complete && offlineMapView._currentSelection.errorCount > 0 QGCLabel { text: qsTr("Error Count:"); width: infoView._labelWidth; } QGCLabel { text: offlineMapView._currentSelection ? offlineMapView._currentSelection.errorCountStr : ""; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth; } } //-- Default Tile Set Row { spacing: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter visible: _defaultSet QGCLabel { text: qsTr("Size:"); width: infoView._labelWidth; } QGCLabel { text: offlineMapView._currentSelection ? offlineMapView._currentSelection.savedTileSizeStr : ""; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth; } } Row { spacing: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter visible: _defaultSet QGCLabel { text: qsTr("Tile Count:"); width: infoView._labelWidth; } QGCLabel { text: offlineMapView._currentSelection ? offlineMapView._currentSelection.savedTileCountStr : ""; horizontalAlignment: Text.AlignRight; width: infoView._valueWidth; } } Row { spacing: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter QGCButton { text: qsTr("Resume Download") visible: offlineMapView._currentSelection && offlineMapView._currentSelection && !_defaultSet && (!offlineMapView._currentSelection.complete && !offlineMapView._currentSelection.downloading) width: ScreenTools.defaultFontPixelWidth * 16 onClicked: { if(offlineMapView._currentSelection) offlineMapView._currentSelection.resumeDownloadTask() } } QGCButton { text: qsTr("Cancel Download") visible: offlineMapView._currentSelection && offlineMapView._currentSelection && !_defaultSet && (!offlineMapView._currentSelection.complete && offlineMapView._currentSelection.downloading) width: ScreenTools.defaultFontPixelWidth * 16 onClicked: { if(offlineMapView._currentSelection) offlineMapView._currentSelection.cancelDownloadTask() } } QGCButton { text: qsTr("Delete") width: ScreenTools.defaultFontPixelWidth * (infoView._extraButton ? 6 : 10) onClicked: showDialog(deleteConfirmationDialogComponent, qsTr("Confirm Delete"), qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No) } QGCButton { text: qsTr("Ok") width: ScreenTools.defaultFontPixelWidth * (infoView._extraButton ? 6 : 10) visible: !_defaultSet enabled: editSetName.text !== "" onClicked: { if(editSetName.text !== _currentSelection.name) { QGroundControl.mapEngineManager.renameTileSet(_currentSelection, editSetName.text) } leaveInfoView() showList() } } QGCButton { text: _defaultSet ? qsTr("Close") : qsTr("Cancel") width: ScreenTools.defaultFontPixelWidth * (infoView._extraButton ? 6 : 10) onClicked: { leaveInfoView() showList() } } } } } // Rectangle - infoView //----------------------------------------------------------------- //-- Add new set Item { id: addNewSetView anchors.fill: parent visible: false Column { anchors.verticalCenter: parent.verticalCenter anchors.leftMargin: _margins anchors.left: parent.left spacing: _margins QGCButton { text: "Show zoom previews" visible: !_showPreview onClicked: _showPreview = !_showPreview } Map { id: minZoomPreview width: addNewSetView.width / 4 height: addNewSetView.height / 4 center: _map.center activeMapType: _map.activeMapType zoomLevel: sliderMinZoom.value gesture.enabled: false visible: _showPreview property bool isSatelliteMap: activeMapType.name.indexOf("Satellite") > -1 || activeMapType.name.indexOf("Hybrid") > -1 plugin: Plugin { name: "QGroundControl" } MapScale { anchors.leftMargin: ScreenTools.defaultFontPixelWidth / 2 anchors.bottomMargin: anchors.leftMargin anchors.left: parent.left anchors.bottom: parent.bottom mapControl: parent } Rectangle { anchors.fill: parent border.color: _mapAdjustedColor color: "transparent" QGCMapLabel { anchors.centerIn: parent map: minZoomPreview text: qsTr("Min Zoom: %1").arg(sliderMinZoom.value) } MouseArea { anchors.fill: parent onClicked: _showPreview = false } } } // Map Map { id: maxZoomPreview width: minZoomPreview.width height: minZoomPreview.height center: _map.center activeMapType: _map.activeMapType zoomLevel: sliderMaxZoom.value gesture.enabled: false visible: _showPreview property bool isSatelliteMap: activeMapType.name.indexOf("Satellite") > -1 || activeMapType.name.indexOf("Hybrid") > -1 plugin: Plugin { name: "QGroundControl" } MapScale { anchors.leftMargin: ScreenTools.defaultFontPixelWidth / 2 anchors.bottomMargin: anchors.leftMargin anchors.left: parent.left anchors.bottom: parent.bottom mapControl: parent } Rectangle { anchors.fill: parent border.color: _mapAdjustedColor color: "transparent" QGCMapLabel { anchors.centerIn: parent map: maxZoomPreview text: qsTr("Max Zoom: %1").arg(sliderMaxZoom.value) } MouseArea { anchors.fill: parent onClicked: _showPreview = false } } } // Map } } // Item - Add new set view CenterMapDropButton { topMargin: 0 anchors.margins: _margins anchors.left: map.left anchors.top: map.top map: _map showMission: false showAllItems: false visible: addNewSetView.visible } } // Map //-- Add new set dialog Rectangle { anchors.margins: ScreenTools.defaultFontPixelWidth anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right visible: addNewSetView.visible width: ScreenTools.defaultFontPixelWidth * (ScreenTools.isTinyScreen ? 24 : 28) height: Math.min(parent.height - (anchors.margins * 2), addNewSetFlickable.y + addNewSetColumn.height + addNewSetLabel.anchors.margins) color: Qt.rgba(qgcPal.window.r, qgcPal.window.g, qgcPal.window.b, 0.85) radius: ScreenTools.defaultFontPixelWidth * 0.5 //-- Eat mouse events DeadMouseArea { anchors.fill: parent } QGCLabel { id: addNewSetLabel anchors.margins: ScreenTools.defaultFontPixelHeight / 2 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right wrapMode: Text.WordWrap text: qsTr("Add New Set") font.pointSize: _saveRealEstate ? ScreenTools.defaultFontPointSize : ScreenTools.mediumFontPointSize horizontalAlignment: Text.AlignHCenter } QGCFlickable { id: addNewSetFlickable anchors.leftMargin: ScreenTools.defaultFontPixelWidth anchors.rightMargin: anchors.leftMargin anchors.topMargin: ScreenTools.defaultFontPixelWidth / 3 anchors.bottomMargin: anchors.topMargin anchors.top: addNewSetLabel.bottom anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom clip: true contentHeight: addNewSetColumn.height Column { id: addNewSetColumn anchors.left: parent.left anchors.right: parent.right spacing: ScreenTools.defaultFontPixelHeight * (ScreenTools.isTinyScreen ? 0.25 : 0.5) Column { spacing: ScreenTools.isTinyScreen ? 0 : ScreenTools.defaultFontPixelHeight * 0.25 anchors.left: parent.left anchors.right: parent.right QGCLabel { text: qsTr("Name:") } QGCTextField { id: setName anchors.left: parent.left anchors.right: parent.right } } Column { spacing: ScreenTools.isTinyScreen ? 0 : ScreenTools.defaultFontPixelHeight * 0.25 anchors.left: parent.left anchors.right: parent.right QGCLabel { text: qsTr("Map type:") visible: !_saveRealEstate } QGCComboBox { id: mapCombo anchors.left: parent.left anchors.right: parent.right model: QGroundControl.mapEngineManager.mapList onActivated: { mapType = textAt(index) if(_dropButtonsExclusiveGroup.current) _dropButtonsExclusiveGroup.current.checked = false _dropButtonsExclusiveGroup.current = null } Component.onCompleted: { var index = mapCombo.find(mapType) if (index === -1) { console.warn("Active map name not in combo", mapType) } else { mapCombo.currentIndex = index } } } } Rectangle { anchors.left: parent.left anchors.right: parent.right height: zoomColumn.height + ScreenTools.defaultFontPixelHeight * 0.5 color: qgcPal.window border.color: qgcPal.text radius: ScreenTools.defaultFontPixelWidth * 0.5 Column { id: zoomColumn spacing: ScreenTools.isTinyScreen ? 0 : ScreenTools.defaultFontPixelHeight * 0.5 anchors.margins: ScreenTools.defaultFontPixelHeight * 0.25 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right QGCLabel { text: qsTr("Min/Max Zoom Levels") font.pointSize: _adjustableFontPointSize anchors.horizontalCenter: parent.horizontalCenter } Slider { id: sliderMinZoom anchors.left: parent.left anchors.right: parent.right height: sliderTouchArea * 1.25 minimumValue: minZoomLevel maximumValue: maxZoomLevel stepSize: 1 updateValueWhileDragging: true property real _savedZoom Component.onCompleted: Math.max(sliderMinZoom.value = _map.zoomLevel - 4, 2) onValueChanged: { if(sliderMinZoom.value > sliderMaxZoom.value) { sliderMaxZoom.value = sliderMinZoom.value } handleChanges() } style: SliderStyle { groove: Rectangle { implicitWidth: sliderMinZoom.width implicitHeight: 4 color: qgcPal.colorBlue radius: 4 } handle: Rectangle { anchors.centerIn: parent color: qgcPal.button border.color: qgcPal.buttonText border.width: 1 implicitWidth: sliderTouchArea implicitHeight: sliderTouchArea radius: sliderTouchArea * 0.5 Label { text: sliderMinZoom.value anchors.centerIn: parent font.family: ScreenTools.normalFontFamily font.pointSize: ScreenTools.smallFontPointSize color: qgcPal.buttonText } } } } // Slider - min zoom Slider { id: sliderMaxZoom anchors.left: parent.left anchors.right: parent.right height: sliderTouchArea * 1.25 minimumValue: minZoomLevel maximumValue: maxZoomLevel stepSize: 1 updateValueWhileDragging: true property real _savedZoom Component.onCompleted: Math.min(sliderMaxZoom.value = _map.zoomLevel + 2, 20) onValueChanged: { if(sliderMaxZoom.value < sliderMinZoom.value) { sliderMinZoom.value = sliderMaxZoom.value } handleChanges() } style: SliderStyle { groove: Rectangle { implicitWidth: sliderMaxZoom.width implicitHeight: 4 color: qgcPal.colorBlue radius: 4 } handle: Rectangle { anchors.centerIn: parent color: qgcPal.button border.color: qgcPal.buttonText border.width: 1 implicitWidth: sliderTouchArea implicitHeight: sliderTouchArea radius: sliderTouchArea * 0.5 Label { text: sliderMaxZoom.value anchors.centerIn: parent font.family: ScreenTools.normalFontFamily font.pointSize: ScreenTools.smallFontPointSize color: qgcPal.buttonText } } } } // Slider - max zoom GridLayout { columns: 2 rowSpacing: ScreenTools.isTinyScreen ? 0 : ScreenTools.defaultFontPixelHeight * 0.5 QGCLabel { text: qsTr("Tile Count:") font.pointSize: _adjustableFontPointSize } QGCLabel { text: QGroundControl.mapEngineManager.tileCountStr font.pointSize: _adjustableFontPointSize } QGCLabel { text: qsTr("Est Size:") font.pointSize: _adjustableFontPointSize } QGCLabel { text: QGroundControl.mapEngineManager.tileSizeStr font.pointSize: _adjustableFontPointSize } } } // Column - Zoom info } // Rectangle - Zoom info QGCLabel { text: qsTr("Too many tiles") visible: _tooManyTiles color: qgcPal.warningText anchors.horizontalCenter: parent.horizontalCenter } Row { id: addButtonRow spacing: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter QGCButton { text: qsTr("Download") width: (addNewSetColumn.width * 0.5) - (addButtonRow.spacing * 0.5) enabled: !_tooManyTiles && setName.text.length > 0 onClicked: { if(QGroundControl.mapEngineManager.findName(setName.text)) { duplicateName.visible = true } else { QGroundControl.mapEngineManager.startDownload(setName.text, mapType); showList() } } } QGCButton { text: qsTr("Cancel") width: (addNewSetColumn.width * 0.5) - (addButtonRow.spacing * 0.5) onClicked: { showList() } } } } // Column } // QGCFlickable } // Rectangle - Add new set dialog QGCFlickable { id: _tileSetList clip: true anchors.margins: ScreenTools.defaultFontPixelWidth anchors.top: parent.top anchors.bottom: _listButtonRow.top anchors.left: parent.left anchors.right: parent.right contentHeight: _cacheList.height Column { id: _cacheList width: Math.min(_tileSetList.width, (ScreenTools.defaultFontPixelWidth * 50).toFixed(0)) spacing: ScreenTools.defaultFontPixelHeight * 0.5 anchors.horizontalCenter: parent.horizontalCenter ExclusiveGroup { id: selectionGroup } OfflineMapButton { id: firstButton text: qsTr("Add New Set") width: _cacheList.width height: ScreenTools.defaultFontPixelHeight * (ScreenTools.isMobile ? 3 : 2) currentSet: _currentSelection exclusiveGroup: selectionGroup onClicked: { offlineMapView._currentSelection = null addNewSet() } } Repeater { model: QGroundControl.mapEngineManager.tileSets delegate: OfflineMapButton { text: object.name size: object.downloadStatus tiles: object.totalTileCount complete: object.complete width: firstButton.width height: ScreenTools.defaultFontPixelHeight * (ScreenTools.isMobile ? 3 : 2) exclusiveGroup: selectionGroup currentSet: _currentSelection tileSet: object onClicked: { offlineMapView._currentSelection = object showInfo() } } } } } Row { id: _listButtonRow visible: _tileSetList.visible spacing: _margins anchors.bottom: parent.bottom anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter QGCButton { text: qsTr("Import") width: _buttonSize visible: QGroundControl.corePlugin.options.showOfflineMapImport onClicked: { QGroundControl.mapEngineManager.importAction = QGCMapEngineManager.ActionNone rootLoader.sourceComponent = importDialog } } QGCButton { text: qsTr("Export") width: _buttonSize visible: QGroundControl.corePlugin.options.showOfflineMapExport enabled: QGroundControl.mapEngineManager.tileSets.count > 1 onClicked: showExport() } QGCButton { text: qsTr("Options") width: _buttonSize onClicked: showDialog(optionsDialogComponent, qsTr("Offline Maps Options"), qgcView.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel) } } //-- Export Tile Sets QGCFlickable { id: _exporTiles clip: true visible: false anchors.margins: ScreenTools.defaultFontPixelWidth anchors.top: parent.top anchors.bottom: _exportButtonRow.top anchors.left: parent.left anchors.right: parent.right contentHeight: _exportList.height Column { id: _exportList width: Math.min(_exporTiles.width, (ScreenTools.defaultFontPixelWidth * 50).toFixed(0)) spacing: ScreenTools.defaultFontPixelHeight * 0.5 anchors.horizontalCenter: parent.horizontalCenter QGCLabel { text: qsTr("Select Tile Sets to Export") font.pointSize: ScreenTools.mediumFontPointSize } Item { width: 1; height: ScreenTools.defaultFontPixelHeight; } Repeater { model: QGroundControl.mapEngineManager.tileSets delegate: QGCCheckBox { text: object.name checked: object.selected onClicked: { object.selected = checked } } } } } Row { id: _exportButtonRow visible: _exporTiles.visible spacing: _margins anchors.bottom: parent.bottom anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter QGCButton { text: qsTr("Select All") width: _bigButtonSize onClicked: QGroundControl.mapEngineManager.selectAll() } QGCButton { text: qsTr("Select None") width: _bigButtonSize onClicked: QGroundControl.mapEngineManager.selectNone() } QGCButton { text: qsTr("Export") width: _bigButtonSize enabled: QGroundControl.mapEngineManager.selectedCount > 0 onClicked: { showList(); if(QGroundControl.mapEngineManager.exportSets()) { rootLoader.sourceComponent = exportToDiskProgress } } } QGCButton { text: qsTr("Cancel") width: _bigButtonSize onClicked: showList() } } } // QGCViewPanel Component { id: exportToDiskProgress Rectangle { width: mainWindow.width height: mainWindow.height color: "black" anchors.centerIn: parent Rectangle { width: parent.width * 0.5 height: exportCol.height * 1.25 radius: ScreenTools.defaultFontPixelWidth color: qgcPal.windowShadeDark border.color: qgcPal.text anchors.centerIn: parent Column { id: exportCol spacing: ScreenTools.defaultFontPixelHeight width: parent.width anchors.centerIn: parent QGCLabel { text: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionExporting ? qsTr("Tile Set Export Progress") : qsTr("Tile Set Export Completed") font.family: ScreenTools.demiboldFontFamily font.pointSize: ScreenTools.mediumFontPointSize anchors.horizontalCenter: parent.horizontalCenter } ProgressBar { id: progressBar width: parent.width * 0.45 maximumValue: 100 value: QGroundControl.mapEngineManager.actionProgress anchors.horizontalCenter: parent.horizontalCenter } BusyIndicator { visible: QGroundControl.mapEngineManager ? QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionExporting : false running: QGroundControl.mapEngineManager ? QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionExporting : false width: exportCloseButton.height height: exportCloseButton.height anchors.horizontalCenter: parent.horizontalCenter } QGCButton { id: exportCloseButton text: qsTr("Close") width: _buttonSize visible: !QGroundControl.mapEngineManager.exporting anchors.horizontalCenter: parent.horizontalCenter onClicked: { mainWindow.enableToolbar() rootLoader.sourceComponent = null } } } } } } Component { id: importDialog Rectangle { width: mainWindow.width height: mainWindow.height color: "black" anchors.centerIn: parent Rectangle { width: parent.width * 0.5 height: importCol.height * 1.5 radius: ScreenTools.defaultFontPixelWidth color: qgcPal.windowShadeDark border.color: qgcPal.text anchors.centerIn: parent Column { id: importCol spacing: ScreenTools.defaultFontPixelHeight width: parent.width anchors.centerIn: parent QGCLabel { text: { if(QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionNone) { return qsTr("Map Tile Set Import"); } else if(QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionImporting) { return qsTr("Map Tile Set Import Progress"); } else { return qsTr("Map Tile Set Import Completed"); } } font.family: ScreenTools.demiboldFontFamily font.pointSize: ScreenTools.mediumFontPointSize anchors.horizontalCenter: parent.horizontalCenter } ProgressBar { id: progressBar width: parent.width * 0.45 maximumValue: 100 visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionImporting value: QGroundControl.mapEngineManager.actionProgress anchors.horizontalCenter: parent.horizontalCenter } BusyIndicator { visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionImporting running: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionImporting width: ScreenTools.defaultFontPixelWidth * 2 height: width anchors.horizontalCenter: parent.horizontalCenter } ExclusiveGroup { id: radioGroup } Column { spacing: ScreenTools.defaultFontPixelHeight width: ScreenTools.defaultFontPixelWidth * 24 anchors.horizontalCenter: parent.horizontalCenter QGCRadioButton { exclusiveGroup: radioGroup text: qsTr("Append to existing set") checked: !QGroundControl.mapEngineManager.importReplace onClicked: QGroundControl.mapEngineManager.importReplace = !checked visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionNone } QGCRadioButton { exclusiveGroup: radioGroup text: qsTr("Replace existing set") checked: QGroundControl.mapEngineManager.importReplace onClicked: QGroundControl.mapEngineManager.importReplace = checked visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionNone } } QGCButton { text: qsTr("Close") width: _bigButtonSize * 1.25 visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionDone anchors.horizontalCenter: parent.horizontalCenter onClicked: { showList(); mainWindow.enableToolbar() rootLoader.sourceComponent = null } } Row { spacing: _margins visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionNone anchors.horizontalCenter: parent.horizontalCenter QGCButton { text: qsTr("Import") width: _bigButtonSize * 1.25 onClicked: { if(!QGroundControl.mapEngineManager.importSets()) { showList(); mainWindow.enableToolbar() rootLoader.sourceComponent = null } } } QGCButton { text: qsTr("Cancel") width: _bigButtonSize * 1.25 onClicked: { showList(); mainWindow.enableToolbar() rootLoader.sourceComponent = null } } } } } } } } // QGCView