Warning, /education/marble/src/apps/marble-maps/MainScreen.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2015 Gábor Péterffy <peterffy95@gmail.com>
0004 // SPDX-FileCopyrightText: 2015 Dennis Nienhüser <nienhueser@kde.org>
0005 // SPDX-FileCopyrightText: 2015 Mikhail Ivchenko <ematirov@gmail.com>
0006 //
0007
0008 import QtQuick 2.7
0009 import QtQuick.Controls 2.2
0010 import QtQuick.Window 2.2
0011 import QtQuick.Controls.Material 2.0
0012
0013
0014 import org.kde.marble 0.20
0015 import org.kde.kirigami 2.0 as Kirigami
0016
0017 Kirigami.AbstractApplicationWindow {
0018 id: app
0019 title: qsTr("Marble Maps")
0020 visible: true
0021
0022 width: 600
0023 height: 400
0024
0025 Material.theme: Material.Light
0026 Material.accent: Material.Blue
0027
0028 color: "#f9f9f9" // Keep the background white while no dialog is loaded
0029
0030 property alias state: stateTracker.state
0031
0032 property var selectedPlacemark
0033 property bool showOsmTags: false
0034 property int currentWaypointIndex: 0
0035
0036 property real animatedMargin: app.state === "none" ? 0 : -dialogLoader.height
0037 property bool dialogExpanded: animatedMargin === -dialogLoader.height
0038 property real mapOffset: !dialogExpanded ? animatedMargin / 2 : 0
0039
0040 Behavior on animatedMargin {
0041 NumberAnimation {
0042 id: dialogAnimation
0043 duration: 200
0044 easing.type: Easing.OutQuart
0045 }
0046 }
0047
0048 onSelectedPlacemarkChanged: {
0049 if (!selectedPlacemark) {
0050 app.state = "none"
0051 }
0052 else {
0053 bookmarkButton.bookmark = bookmarks.isBookmark(selectedPlacemark.longitude, selectedPlacemark.latitude)
0054 }
0055 }
0056
0057 SystemPalette{
0058 id: palette
0059 colorGroup: SystemPalette.Active
0060 }
0061
0062 Settings {
0063 id: settings
0064 }
0065
0066
0067 property bool aboutToQuit: false
0068
0069 onClosing: {
0070 if (app.aboutToQuit || Qt.platform.os !== "android") {
0071 close.accepted = true // we will quit
0072 return
0073 } else if (sidePanel.drawerOpen) {
0074 sidePanel.close()
0075 } else if (pageStack.depth > 1) {
0076 pageStack.pop()
0077 } else if (navigationManager.visible) {
0078 navigationManager.visible = false
0079 } else if (app.state !== "none") {
0080 app.state = "none"
0081 } else if(search.searchResultsVisible.visible){
0082 search.searchResultsVisible = false
0083 }
0084 else {
0085 if(search.searchResultsVisible){
0086 search.searchResultsVisible = false
0087 }
0088 app.aboutToQuit = true
0089 quitHelper.visible = true
0090 }
0091 close.accepted = false
0092 }
0093
0094 globalDrawer: Kirigami.GlobalDrawer {
0095 id: sidePanel
0096 title: qsTr("Settings")
0097
0098 handleVisible: false
0099 property alias showAccessibility: accessibilityAction.checked
0100
0101 Settings {
0102 id: sidePanelSettings
0103 property bool showUpdateInfo: Number(value("MarbleMaps", "updateInfoVersion", "0")) < 1
0104 Component.onDestruction: {
0105 sidePanelSettings.setValue("MarbleMaps", "showAccessibility", accessibilityAction.checked ? "true" : "false")
0106 }
0107 }
0108
0109 actions: [
0110 Kirigami.Action {
0111 id: publicTransportAction
0112 text: qsTr("Public Transport")
0113 checkable: true
0114 checked: marbleMaps.showPublicTransport
0115 iconName: "qrc:///material/directions-bus.svg"
0116 visible: true
0117 onTriggered: {
0118 sidePanel.close()
0119 marbleMaps.showPublicTransport = checked
0120 publicTransportDialog.open()
0121 }
0122 },
0123 Kirigami.Action {
0124 id: outdoorActivitiesAction
0125 checkable: true
0126 checked: marbleMaps.showOutdoorActivities
0127 text: qsTr("Outdoor Activities")
0128 visible: true
0129 iconName: "qrc:///material/directions-run.svg"
0130 onTriggered: {
0131 sidePanel.close()
0132 marbleMaps.showOutdoorActivities = checked
0133 }
0134 },
0135 Kirigami.Action {
0136 id: accessibilityAction
0137 checkable: true
0138 checked: settings.value("MarbleMaps", "showAccessibility", "false") === "true"
0139 text: qsTr("Accessibility")
0140 visible: true
0141 iconName: "qrc:///material/wheelchair.svg"
0142 onTriggered: {
0143 sidePanelSettings.value("MarbleMaps", "showAccessibility", "false") === "true"
0144 }
0145 },
0146 Kirigami.Action{ enabled: false},
0147 Kirigami.Action {
0148 text: qsTr("About")
0149 iconName: "qrc:///marble.svg"
0150 visible: true
0151 onTriggered: {
0152 app.state = "about"
0153 sidePanel.close()
0154 source = ""
0155 app.pageStack.push("qrc:///AboutDialog.qml")
0156 }
0157 },
0158 Kirigami.Action {
0159 text: qsTr("Bookmarks")
0160 iconName: "qrc:///material/star.svg"
0161 onTriggered: {
0162 app.state = "bookmarks"
0163 sidePanel.close()
0164 app.pageStack.push("qrc:///Bookmarks.qml")
0165 }
0166 },
0167 Kirigami.Action {
0168 text: qsTr("Layer Options")
0169 iconName: "qrc:///settings.png"
0170 onTriggered: {
0171 app.state = "options"
0172 sidePanel.close()
0173 app.pageStack.push("qrc:///Options.qml")
0174 }
0175 },
0176 Kirigami.Action {
0177 text: qsTr("Routing")
0178 iconName: "qrc:///material/directions.svg"
0179 onTriggered: {
0180 app.state = "route"
0181 }
0182 }
0183 ]
0184
0185 Binding {
0186 target: pageStack.currentItem
0187 property: "marbleQuickItem"
0188 value: marbleMaps
0189 when: app.state === "bookmarks"
0190 }
0191 }
0192
0193 pageStack: StackView {
0194 anchors.fill: parent
0195 initialItem: page
0196 }
0197
0198 Kirigami.Page {
0199 id: page
0200 padding: 0
0201 topPadding: 0
0202 leftPadding: 0
0203 rightPadding: 0
0204 bottomPadding: 0
0205 title: qsTr("Marble Maps")
0206
0207 Item {
0208 id: mapItem
0209
0210 width: parent.width
0211 height: parent.height - dialogLoader.height - bottomMenu.height
0212
0213 PinchArea {
0214 anchors.fill: parent
0215 enabled: true
0216
0217 onPinchStarted: marbleMaps.handlePinchStarted(pinch.center)
0218 onPinchFinished: marbleMaps.handlePinchFinished(pinch.center)
0219 onPinchUpdated: marbleMaps.handlePinchUpdated(pinch.center, pinch.scale);
0220
0221 MarbleMaps {
0222 id: marbleMaps
0223
0224 property string currentPositionProvider: "QtPositioning"
0225 property bool wlanOnly: false
0226 property bool smallZoom : radius < 2 * Math.max(app.width, app.height)
0227
0228 anchors.fill: parent
0229 visible: true
0230
0231 // Theme settings.
0232 projection: smallZoom ? MarbleItem.Spherical : MarbleItem.Mercator
0233 mapThemeId: settings.value("MarbleMaps", "mapThemeId", "earth/vectorosm/vectorosm.dgml")
0234
0235 // Visibility of layers/plugins.
0236 showFrameRate: false
0237 showAtmosphere: smallZoom
0238 showCompass: false
0239 showClouds: false
0240 showCrosshairs: false
0241 showGrid: smallZoom
0242 showOverviewMap: false
0243 showOtherPlaces: false
0244 showScaleBar: false
0245 showBackground: smallZoom
0246 showPublicTransport: settings.value("MarbleMaps", "showPublicTransport", "false") === "true"
0247 positionProvider: suspended ? "" : currentPositionProvider
0248 keepScreenOn: !suspended && navigationManager.guidanceModeEnabled
0249 showPositionMarker: false
0250 animationViewContext: dialogAnimation.running
0251
0252 placemarkDelegate: Image {
0253 id: balloon
0254 property int xPos: 0
0255 property int yPos: 0
0256 property real animationOffset: 0
0257 property var placemark: null
0258 x: xPos - 0.5 * width
0259 y: yPos - height - 30 * Screen.pixelDensity * animationOffset
0260 opacity: 1.0 - animationOffset
0261
0262 Connections {
0263 target: app
0264 onSelectedPlacemarkChanged: balloonAnimation.restart()
0265 }
0266
0267 NumberAnimation {
0268 id: balloonAnimation
0269 target: balloon
0270 property: "animationOffset"
0271 from: 1
0272 to: 0
0273 duration: 1000
0274 easing.type: Easing.OutBounce
0275 }
0276
0277
0278 width: Screen.pixelDensity*6
0279 height: width
0280 source: "qrc:///ic_place.png"
0281 onPlacemarkChanged: {
0282 app.selectedPlacemark = placemark
0283 if (placemark) {
0284 app.state = "place"
0285 } else {
0286 app.state = "none"
0287 }
0288 }
0289 }
0290
0291 onPositionAvailableChanged: {
0292 updateIndicator();
0293 }
0294 onPositionVisibleChanged: {
0295 updateIndicator();
0296 }
0297 onVisibleLatLonAltBoxChanged: {
0298 !panningDetectionTimer.restart();
0299 updateIndicator();
0300 }
0301 onCurrentPositionChanged: {
0302 updateIndicator();
0303 }
0304
0305 onZoomChanged: {
0306 zoomDetectionTimer.restart()
0307 }
0308
0309 Component.onCompleted: {
0310 setPluginSetting("coordinate-grid", "gridColor", "#999999");
0311 setPluginSetting("coordinate-grid", "tropicsColor", "#888888");
0312 setPluginSetting("coordinate-grid", "equatorColor", "#777777");
0313 setPluginSetting("coordinate-grid", "primaryLabels", "false");
0314 setPluginSetting("coordinate-grid", "secondaryLabels", "false");
0315 marbleMaps.loadSettings()
0316 }
0317 Component.onDestruction: marbleMaps.writeSettings()
0318
0319 Connections {
0320 target: Qt.application
0321 onStateChanged: {
0322 if (Qt.application.state === Qt.ApplicationInactive || Qt.application.state === Qt.ApplicationSuspended) {
0323 marbleMaps.writeSettings()
0324 }
0325 }
0326 }
0327
0328 function updateIndicator() {
0329 if ( !positionVisible && positionAvailable ) {
0330 zoomToPositionButton.updateIndicator();
0331 }
0332 }
0333
0334 RoutingManager {
0335 id: routingManager
0336 anchors.fill: parent
0337 marbleItem: marbleMaps
0338 visible: hasRoute
0339
0340 function addToRoute() {
0341 ensureRouteHasDeparture()
0342 routingManager.addViaByPlacemarkAtIndex(routingManager.waypointCount(), selectedPlacemark)
0343 routingManager.clearSearchResultPlacemarks()
0344 selectedPlacemark = null
0345 app.state = "route"
0346 }
0347 function ensureRouteHasDeparture() {
0348 if (routingManager.routeRequestModel.count === 0) {
0349 if (marbleMaps.positionAvailable) {
0350 routingManager.addViaByPlacemark(marbleMaps.currentPosition)
0351 }
0352 }
0353 }
0354
0355 }
0356
0357 Timer {
0358 id: zoomDetectionTimer
0359 interval: 1000
0360 }
0361 Timer {
0362 id: panningDetectionTimer
0363 interval: 1000
0364 }
0365
0366 PositionMarker {
0367 id: positionMarker
0368 x: navigationManager.snappedPositionMarkerScreenPosition.x - positionMarker.width / 2
0369 y: navigationManager.snappedPositionMarkerScreenPosition.y - positionMarker.height / 2
0370 angle: marbleMaps.angle
0371 visible: marbleMaps.positionAvailable && marbleMaps.positionVisible
0372 radius: navigationManager.screenAccuracy / 2
0373 showAccuracy: navigationManager.deviated
0374 allowRadiusAnimation: !zoomDetectionTimer.running
0375 allowPositionAnimation: !panningDetectionTimer.running
0376 speed: marbleMaps.speed
0377
0378 MouseArea {
0379 anchors.fill: parent
0380 onPressed: app.state = "position"
0381 }
0382 }
0383
0384 MouseArea {
0385 anchors.fill: parent
0386 propagateComposedEvents: true
0387 onPressed: {
0388 marbleMaps.focus = true;
0389 mouse.accepted = false;
0390 }
0391 }
0392 }
0393
0394 NavigationManager {
0395 id: navigationManager
0396 width: parent.width
0397 height: parent.height
0398 visible: false
0399 marbleItem: marbleMaps
0400 hasRoute: routingManager.hasRoute
0401 }
0402 }
0403
0404 BoxedText {
0405 id: distanceIndicator
0406 text: qsTr("%1 km").arg(zoomToPositionButton.distance < 10 ? zoomToPositionButton.distance.toFixed(1) : zoomToPositionButton.distance.toFixed(0))
0407 anchors {
0408 bottom: zoomToPositionButton.top
0409 horizontalCenter: zoomToPositionButton.horizontalCenter
0410 }
0411
0412 visible: marbleMaps.positionAvailable && !marbleMaps.positionVisible
0413 }
0414
0415 PositionButton {
0416 id: zoomToPositionButton
0417 anchors {
0418 right: parent.right
0419 rightMargin: Screen.pixelDensity * 1
0420 bottom: mapItem.bottom
0421 bottomMargin: 10
0422 }
0423
0424 enabled: marbleMaps.positionAvailable
0425
0426 iconSource: marbleMaps.positionAvailable ? "qrc:///gps_fixed.png" : "qrc:///gps_not_fixed.png"
0427
0428 onClicked: marbleMaps.centerOnCurrentPosition()
0429
0430 property real distance: 0
0431
0432 function updateIndicator() {
0433 var point = marbleMaps.mapFromItem(zoomToPositionButton, diameter * 0.5, diameter * 0.5);
0434 distance = 0.001 * marbleMaps.distanceFromPointToCurrentLocation(point);
0435 angle = marbleMaps.angleFromPointToCurrentLocation(point);
0436 }
0437
0438 showDirection: marbleMaps.positionAvailable && !marbleMaps.positionVisible
0439 }
0440 }
0441
0442
0443 Row {
0444 id: bottomMenu
0445 anchors.left: parent.left
0446 anchors.right: parent.right
0447 anchors.bottom: dialogLoader.top
0448 width: parent.width
0449 height: bottomMenu.visible ? routeEditorButton.height + Screen.pixelDensity * 2 : 0
0450 anchors.topMargin: app.animatedMargin
0451 visible: app.state === "place" || app.state === "route"
0452
0453 onVisibleChanged: bottomMenuAnimation.start()
0454
0455 NumberAnimation {
0456 id: bottomMenuAnimation
0457 target: bottomMenu
0458 property: "y"
0459 from: app.height - bottomMenu.height
0460 to: 0
0461 duration: 500
0462 easing.type: Easing.InExpo
0463 }
0464
0465 Item {
0466 id: bottomMenuBackground
0467 anchors.fill: parent
0468 Rectangle {
0469 color: Material.accent
0470 anchors.fill : parent
0471 }
0472 }
0473
0474 Row {
0475 anchors.centerIn: parent
0476 spacing: Kirigami.Units.gridUnit * 2
0477
0478 FlatButton {
0479 id: routeEditorButton
0480 property string currentProfileIcon: "qrc:///material/directions-car.svg"
0481 height: Screen.pixelDensity * 6
0482 width: height
0483 enabled: app.state !== "route" || routingManager.hasRoute
0484 imageSource: "qrc:///material/directions.svg"
0485
0486 onClicked: {
0487 if (app.state === "route") {
0488 app.state = "none"
0489 navigationManager.visible = true
0490 } else if (app.state === "place") {
0491 app.state = "route"
0492 routingManager.addToRoute()
0493 } else {
0494 app.state = "route"
0495 navigationManager.visible = false
0496 }
0497 }
0498 states: [
0499 State {
0500 name: ""
0501 PropertyChanges { target: routeEditorButton; imageSource: "qrc:///material/directions.svg"; }
0502 },
0503 State {
0504 name: "routingAction"
0505 when: app.state === "route"
0506 PropertyChanges { target: routeEditorButton; imageSource: "qrc:///material/navigation.svg"; }
0507 },
0508 State {
0509 name: "placeAction"
0510 when: app.state === "place"
0511 PropertyChanges { target: routeEditorButton; imageSource: "qrc:///material/directions.svg" }
0512 }
0513 ]
0514 }
0515
0516 FlatButton {
0517 id: bookmarkButton
0518 anchors.verticalCenter: parent.verticalCenter
0519 height: Screen.pixelDensity * 6
0520 width: height
0521 property bool bookmark: bookmarks.isBookmark(app.selectedPlacemark.longitude, app.selectedPlacemark.latitude)
0522 enabled: app.state === "place"
0523 visible: app.state === "place"
0524 imageSource: bookmark ? "qrc:///material/star.svg" : "qrc:///material/star_border.svg"
0525 onClicked: {
0526 if (bookmarkButton.bookmark) {
0527 bookmarks.removeBookmark(app.selectedPlacemark.longitude, app.selectedPlacemark.latitude)
0528 } else {
0529 bookmarks.addBookmark(app.selectedPlacemark, "Default")
0530 }
0531 bookmarkButton.bookmark = !bookmarkButton.bookmark
0532 }
0533 }
0534 }
0535 }
0536
0537
0538 BorderImage {
0539 anchors.top: mapItem.bottom
0540 anchors.bottom: dialogLoader.bottom
0541 anchors.right: parent.right
0542 anchors.left: parent.left
0543 anchors.margins: -14
0544 border { top: 14; left: 14; right: 14; bottom: 14 }
0545 source: "qrc:///border_shadow.png"
0546 }
0547
0548 Search {
0549 id: search
0550 anchors.fill: parent
0551 marbleQuickItem: marbleMaps
0552 visible: !navigationManager.visible
0553
0554 onItemSelected: {
0555 if (routingManager) {
0556 routingManager.addSearchResultAsPlacemark(suggestedPlacemark);
0557 }
0558 app.selectedPlacemark = suggestedPlacemark;
0559 app.state = "place"
0560 }
0561 onMenuButtonClicked: sidePanel.open()
0562 }
0563
0564 Loader {
0565 id: dialogLoader
0566 focus: true
0567 width: childrenRect.width
0568 height : childrenRect.height
0569
0570 anchors {
0571 left: parent.left
0572 right: parent.right
0573 top: parent.bottom
0574 bottom: bottomMenu.top
0575 topMargin: app.animatedMargin
0576 bottomMargin: Kirigami.Units.gridUnits * 10
0577 }
0578
0579 NumberAnimation {
0580 id: loaderAnimation
0581 target: dialogLoader.item
0582 property: "y"
0583 from: dialogLoader.height === 0 ? app.height : app.height - dialogLoader.item.height
0584 to: 0
0585 duration: 500
0586 easing.type: Easing.InExpo
0587 }
0588
0589 onLoaded: {
0590 app.state != "none" ? loaderAnimation.running = true : loaderAnimation.running = false
0591 if (app.state === "place") {
0592 dialogLoader.item.map = marbleMaps
0593 dialogLoader.item.placemark = app.selectedPlacemark
0594 dialogLoader.item.showOsmTags = app.showOsmTags
0595 dialogLoader.item.showAccessibility = sidePanel.showAccessibility
0596 } else if (app.state === "route") {
0597 item.routingManager = routingManager
0598 item.routingProfile = routingManager.routingProfile
0599 item.currentIndex = Qt.binding(function() { return app.currentWaypointIndex })
0600 } else if (app.state == "position") {
0601 dialogLoader.item.map = marbleMaps
0602 dialogLoader.item.navigationManager = navigationManager
0603 } else if (app.state == "none"){
0604 dialogLoader.height = 0
0605 }
0606 }
0607
0608 Connections {
0609 target: dialogLoader.item
0610 onCurrentProfileIconChanged: routeEditorButton.currentProfileIcon = dialogLoader.item.currentProfileIcon
0611 ignoreUnknownSignals: true
0612 }
0613 }
0614
0615 Rectangle {
0616 width: parent.width
0617 color: Kirigami.Theme.textColor
0618 opacity: 0.4
0619 height: 1
0620 anchors.bottom: dialogLoader.top
0621 }
0622
0623 Item {
0624 id: stateTracker
0625 state: "none"
0626
0627 states: [
0628 State {
0629 name: "none"
0630 PropertyChanges { target: dialogLoader; source: "" }
0631 },
0632 State {
0633 name: "position"
0634 PropertyChanges { target: dialogLoader; source: "CurrentPosition.qml" }
0635 },
0636 State {
0637 name: "route"
0638 PropertyChanges { target: dialogLoader; source: "RouteEditor.qml" }
0639 },
0640 State {
0641 name: "place"
0642 PropertyChanges { target: dialogLoader; source: "PlacemarkDialog.qml" }
0643 },
0644 State {
0645 name: "about"
0646 PropertyChanges { target: dialogLoader; source: "" }
0647 },
0648 State {
0649 name: "settings"
0650 PropertyChanges { target: dialogLoader; source: "SettingsDialog.qml" }
0651 },
0652 State {
0653 name: "developer"
0654 PropertyChanges { target: dialogLoader; source: "DeveloperDialog.qml" }
0655 },
0656 State {
0657 name: "options"
0658 PropertyChanges { target: dialogLoader; source: "" }
0659 },
0660 State {
0661 name: "bookmarks"
0662 PropertyChanges { target: dialogLoader; source: "" }
0663 }
0664 ]
0665 }
0666
0667 BoxedText {
0668 id: quitHelper
0669 visible: false
0670 text: qsTr("Press again to close.")
0671 anchors.bottom: parent.bottom
0672 anchors.bottomMargin: Screen.pixelDensity * 5
0673 anchors.horizontalCenter: parent.horizontalCenter
0674 onVisibleChanged: {
0675 if (visible) {
0676 quitTimer.restart()
0677 }
0678 }
0679
0680 Timer {
0681 id: quitTimer
0682 interval: 3000;
0683 running: false;
0684 repeat: false
0685 onTriggered: {
0686 app.aboutToQuit = false
0687 quitHelper.visible = false
0688 }
0689 }
0690 }
0691
0692 Bookmarks {
0693 id: bookmarks
0694 map: marbleMaps
0695 }
0696 }
0697 }
0698