diff --git a/src/apps/marble-maps/FlatButton.qml b/src/apps/marble-maps/FlatButton.qml index 347389ce8..7536e71bb 100644 --- a/src/apps/marble-maps/FlatButton.qml +++ b/src/apps/marble-maps/FlatButton.qml @@ -1,36 +1,38 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Dennis Nienhüser // import QtQuick 2.3 import QtQuick.Controls 1.3 import QtQuick.Controls.Styles 1.3 Button { id: root property string imageSource SystemPalette{ id: palette colorGroup: SystemPalette.Active } style: ButtonStyle { - background: Rectangle { + background: Item { anchors.fill: parent - color: root.pressed ? palette.highlight : palette.base Image { id: icon anchors.fill: parent source: root.imageSource + smooth: true + sourceSize.width: width + sourceSize.height: height } } } } diff --git a/src/apps/marble-maps/MainScreen.qml b/src/apps/marble-maps/MainScreen.qml index c073c7fbc..02b736eaa 100644 --- a/src/apps/marble-maps/MainScreen.qml +++ b/src/apps/marble-maps/MainScreen.qml @@ -1,611 +1,707 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Gábor Péterffy // Copyright 2015 Dennis Nienhüser // Copyright 2015 Mikhail Ivchenko // - -import QtQuick 2.3 -import QtQuick.Controls 2.0 +import QtQuick 2.7 +import QtQuick.Controls 2.2 import QtQuick.Window 2.2 +import QtQuick.Controls.Material 2.0 + import org.kde.marble 0.20 import org.kde.kirigami 2.0 as Kirigami Kirigami.ApplicationWindow { id: app title: qsTr("Marble Maps") visible: true width: 600 height: 400 + Material.theme: Material.Light + Material.accent: Material.Blue + color: "#f9f9f9" // Keep the background white while no dialog is loaded property alias state: stateTracker.state property var selectedPlacemark property bool showOsmTags: false property int currentWaypointIndex: 0 property real animatedMargin: app.state === "none" ? 0 : -dialogLoader.height property bool dialogExpanded: animatedMargin === -dialogLoader.height property real mapOffset: !dialogExpanded ? animatedMargin / 2 : 0 Behavior on animatedMargin { NumberAnimation { id: dialogAnimation duration: 200 easing.type: Easing.OutQuart } } onSelectedPlacemarkChanged: { if (!selectedPlacemark) { app.state = "none" } + else { + bookmarkButton.bookmark = bookmarks.isBookmark(selectedPlacemark.longitude, selectedPlacemark.latitude) + } } SystemPalette{ id: palette colorGroup: SystemPalette.Active } Settings { id: settings } + + property bool aboutToQuit: false + + onClosing: { + if (app.aboutToQuit === true) { + close.accepted = true // we will quit + return + } else if (sidePanel.drawerOpen) { + sidePanel.close() + } else if (pageStack.depth > 1) { + pageStack.pop() + } else if (navigationManager.visible) { + navigationManager.visible = false + } else if (app.state !== "none") { + app.state = "none" + } + else if(search.searchResultsVisible.visible === true && !sidePanel.drawerOpen){ + search.searchResultsVisible = false + } + else { + if(search.searchResultsVisible === true){ + search.searchResultsVisible = false + } + app.aboutToQuit = true + quitHelper.visible = true + } + close.accepted = false + } + globalDrawer: Kirigami.GlobalDrawer { id: sidePanel title: "Settings" handleVisible: false property alias showAccessibility: accessibilityAction.checked Settings { id: sidePanelSettings property bool showUpdateInfo: Number(value("MarbleMaps", "updateInfoVersion", "0")) < 1 Component.onDestruction: { sidePanelSettings.setValue("MarbleMaps", "showAccessibility", accessibilityAction.checked ? "true" : "false") } } actions: [ Kirigami.Action { id: publicTransportAction text: qsTr("Public Transport") checkable: true checked: marbleMaps.showPublicTransport iconName: "qrc:///material/directions-bus.svg" visible: true onTriggered: { sidePanel.close() marbleMaps.showPublicTransport = checked publicTransportDialog.open() } }, Kirigami.Action { id: outdoorActivitiesAction checkable: true checked: marbleMaps.showOutdoorActivities text: qsTr("Outdoor Activities") visible: true iconName: "qrc:///material/directions-run.svg" onTriggered: { sidePanel.close() marbleMaps.showOutdoorActivities = checked } }, Kirigami.Action { id: accessibilityAction checkable: true checked: settings.value("MarbleMaps", "showAccessibility", "false") === "true" text: qsTr("Accessibility") visible: true iconName: "qrc:///material/wheelchair.svg" onTriggered: { sidePanelSettings.value("MarbleMaps", "showAccessibility", "false") === "true" } }, Kirigami.Action{ enabled: false}, Kirigami.Action { text: "About" iconName: "qrc:///marble.svg" visible: true onTriggered: { app.state = "about" sidePanel.close() source = "" app.pageStack.push("qrc:///AboutDialog.qml") } }, Kirigami.Action { text: "Bookmarks" iconName: "qrc:///material/star.svg" onTriggered: { app.state = "bookmarks" sidePanel.close() app.pageStack.push("qrc:///Bookmarks.qml") } }, Kirigami.Action { text: "Layer Options" iconName: "qrc:///settings.png" onTriggered: { app.state = "options" sidePanel.close() app.pageStack.push("qrc:///Options.qml") } + }, + Kirigami.Action { + text: "Routing" + iconName: "qrc:///material/directions.svg" + onTriggered: { + app.state = "route" + } } ] Binding { target: pageStack.currentItem property: "marbleQuickItem" value: marbleMaps when: app.state === "bookmarks" } } pageStack.initialPage: page pageStack.interactive: false Kirigami.Page { id: page padding: 0 topPadding: 0 leftPadding: 0 rightPadding: 0 bottomPadding: 0 title: "Marble Maps" - Item { - id: mapItem - anchors { - top: parent.top - topMargin: mapOffset - left: parent.left - right: parent.right - } - - height: !dialogExpanded - ? parent.height - : parent.height + animatedMargin + Item { + id: mapItem - PinchArea { - anchors.fill: parent - enabled: true + width: parent.width + height: dialogLoader.height === 0 ? parent.height - bottomMenu.height : parent.height - dialogLoader.height - bottomMenu.height - onPinchStarted: marbleMaps.handlePinchStarted(pinch.center) - onPinchFinished: marbleMaps.handlePinchFinished(pinch.center) - onPinchUpdated: marbleMaps.handlePinchUpdated(pinch.center, pinch.scale); - MarbleMaps { - id: marbleMaps + PinchArea { + anchors.fill: parent + enabled: true - property string currentPositionProvider: "QtPositioning" - property bool wlanOnly: false - property bool smallZoom : radius < 2 * Math.max(app.width, app.height) + onPinchStarted: marbleMaps.handlePinchStarted(pinch.center) + onPinchFinished: marbleMaps.handlePinchFinished(pinch.center) + onPinchUpdated: marbleMaps.handlePinchUpdated(pinch.center, pinch.scale); - anchors.fill: parent + MarbleMaps { + id: marbleMaps - visible: true + property string currentPositionProvider: "QtPositioning" + property bool wlanOnly: false + property bool smallZoom : radius < 2 * Math.max(app.width, app.height) - // Theme settings. - projection: smallZoom ? MarbleItem.Spherical : MarbleItem.Mercator - mapThemeId: settings.value("MarbleMaps", "mapThemeId", "earth/vectorosm/vectorosm.dgml") - - // Visibility of layers/plugins. - showFrameRate: false - showAtmosphere: smallZoom - showCompass: false - showClouds: false - showCrosshairs: false - showGrid: smallZoom - showOverviewMap: false - showOtherPlaces: false - showScaleBar: false - showBackground: smallZoom - showPublicTransport: settings.value("MarbleMaps", "showPublicTransport", "false") === "true" - positionProvider: suspended ? "" : currentPositionProvider - keepScreenOn: !suspended && navigationManager.guidanceModeEnabled - showPositionMarker: false - animationViewContext: dialogAnimation.running - - placemarkDelegate: Image { - id: balloon - property int xPos: 0 - property int yPos: 0 - property real animationOffset: 0 - property var placemark: null - x: xPos - 0.5 * width - y: yPos - height - 30 * Screen.pixelDensity * animationOffset - opacity: 1.0 - animationOffset + anchors.fill: parent - Connections { - target: app - onSelectedPlacemarkChanged: balloonAnimation.restart() - } + visible: true + + // Theme settings. + projection: smallZoom ? MarbleItem.Spherical : MarbleItem.Mercator + mapThemeId: settings.value("MarbleMaps", "mapThemeId", "earth/vectorosm/vectorosm.dgml") + + // Visibility of layers/plugins. + showFrameRate: false + showAtmosphere: smallZoom + showCompass: false + showClouds: false + showCrosshairs: false + showGrid: smallZoom + showOverviewMap: false + showOtherPlaces: false + showScaleBar: false + showBackground: smallZoom + showPublicTransport: settings.value("MarbleMaps", "showPublicTransport", "false") === "true" + positionProvider: suspended ? "" : currentPositionProvider + keepScreenOn: !suspended && navigationManager.guidanceModeEnabled + showPositionMarker: false + animationViewContext: dialogAnimation.running + + placemarkDelegate: Image { + id: balloon + property int xPos: 0 + property int yPos: 0 + property real animationOffset: 0 + property var placemark: null + x: xPos - 0.5 * width + y: yPos - height - 30 * Screen.pixelDensity * animationOffset + opacity: 1.0 - animationOffset + + Connections { + target: app + onSelectedPlacemarkChanged: balloonAnimation.restart() + } - NumberAnimation { - id: balloonAnimation - target: balloon - property: "animationOffset" - from: 1 - to: 0 - duration: 1000 - easing.type: Easing.OutBounce - } + NumberAnimation { + id: balloonAnimation + target: balloon + property: "animationOffset" + from: 1 + to: 0 + duration: 1000 + easing.type: Easing.OutBounce + } - width: Screen.pixelDensity*6 - height: width - source: "qrc:///ic_place.png" - onPlacemarkChanged: { - app.selectedPlacemark = placemark - if (placemark) { - app.state = "place" - } else { - app.state = "none" + width: Screen.pixelDensity*6 + height: width + source: "qrc:///ic_place.png" + onPlacemarkChanged: { + app.selectedPlacemark = placemark + if (placemark) { + app.state = "place" + } else { + app.state = "none" + } } } - } - onPositionAvailableChanged: { - updateIndicator(); - } - onPositionVisibleChanged: { - updateIndicator(); - } - onVisibleLatLonAltBoxChanged: { - !panningDetectionTimer.restart(); - updateIndicator(); - } - onCurrentPositionChanged: { - updateIndicator(); - } + onPositionAvailableChanged: { + updateIndicator(); + } + onPositionVisibleChanged: { + updateIndicator(); + } + onVisibleLatLonAltBoxChanged: { + !panningDetectionTimer.restart(); + updateIndicator(); + } + onCurrentPositionChanged: { + updateIndicator(); + } - onZoomChanged: { - zoomDetectionTimer.restart() - } + onZoomChanged: { + zoomDetectionTimer.restart() + } - Component.onCompleted: { - setPluginSetting("coordinate-grid", "gridColor", "#999999"); - setPluginSetting("coordinate-grid", "tropicsColor", "#888888"); - setPluginSetting("coordinate-grid", "equatorColor", "#777777"); - setPluginSetting("coordinate-grid", "primaryLabels", "false"); - setPluginSetting("coordinate-grid", "secondaryLabels", "false"); - marbleMaps.loadSettings() - } - Component.onDestruction: marbleMaps.writeSettings() + Component.onCompleted: { + setPluginSetting("coordinate-grid", "gridColor", "#999999"); + setPluginSetting("coordinate-grid", "tropicsColor", "#888888"); + setPluginSetting("coordinate-grid", "equatorColor", "#777777"); + setPluginSetting("coordinate-grid", "primaryLabels", "false"); + setPluginSetting("coordinate-grid", "secondaryLabels", "false"); + marbleMaps.loadSettings() + } + Component.onDestruction: marbleMaps.writeSettings() - Connections { - target: Qt.application - onStateChanged: { - if (Qt.application.state === Qt.ApplicationInactive || Qt.application.state === Qt.ApplicationSuspended) { - marbleMaps.writeSettings() + Connections { + target: Qt.application + onStateChanged: { + if (Qt.application.state === Qt.ApplicationInactive || Qt.application.state === Qt.ApplicationSuspended) { + marbleMaps.writeSettings() + } } } - } - function updateIndicator() { - if ( !positionVisible && positionAvailable ) { - zoomToPositionButton.updateIndicator(); + function updateIndicator() { + if ( !positionVisible && positionAvailable ) { + zoomToPositionButton.updateIndicator(); + } } - } - RoutingManager { - id: routingManager - anchors.fill: parent - marbleItem: marbleMaps - visible: hasRoute - - function addToRoute() { - ensureRouteHasDeparture() - routingManager.addViaByPlacemarkAtIndex(routingManager.waypointCount(), selectedPlacemark) - routingManager.clearSearchResultPlacemarks() - selectedPlacemark = null - app.state = "route" - } - function ensureRouteHasDeparture() { - if (routingManager.routeRequestModel.count === 0) { - if (marbleMaps.positionAvailable) { - routingManager.addViaByPlacemark(marbleMaps.currentPosition) + RoutingManager { + id: routingManager + anchors.fill: parent + marbleItem: marbleMaps + visible: hasRoute + + function addToRoute() { + ensureRouteHasDeparture() + routingManager.addViaByPlacemarkAtIndex(routingManager.waypointCount(), selectedPlacemark) + routingManager.clearSearchResultPlacemarks() + selectedPlacemark = null + app.state = "route" + } + function ensureRouteHasDeparture() { + if (routingManager.routeRequestModel.count === 0) { + if (marbleMaps.positionAvailable) { + routingManager.addViaByPlacemark(marbleMaps.currentPosition) + } } } - } - } + } - Timer { - id: zoomDetectionTimer - interval: 1000 - } - Timer { - id: panningDetectionTimer - interval: 1000 - } + Timer { + id: zoomDetectionTimer + interval: 1000 + } + Timer { + id: panningDetectionTimer + interval: 1000 + } - PositionMarker { - id: positionMarker - x: navigationManager.snappedPositionMarkerScreenPosition.x - positionMarker.width / 2 - y: navigationManager.snappedPositionMarkerScreenPosition.y - positionMarker.height / 2 - angle: marbleMaps.angle - visible: marbleMaps.positionAvailable && marbleMaps.positionVisible - radius: navigationManager.screenAccuracy / 2 - showAccuracy: navigationManager.deviated - allowRadiusAnimation: !zoomDetectionTimer.running - allowPositionAnimation: !panningDetectionTimer.running - speed: marbleMaps.speed + PositionMarker { + id: positionMarker + x: navigationManager.snappedPositionMarkerScreenPosition.x - positionMarker.width / 2 + y: navigationManager.snappedPositionMarkerScreenPosition.y - positionMarker.height / 2 + angle: marbleMaps.angle + visible: marbleMaps.positionAvailable && marbleMaps.positionVisible + radius: navigationManager.screenAccuracy / 2 + showAccuracy: navigationManager.deviated + allowRadiusAnimation: !zoomDetectionTimer.running + allowPositionAnimation: !panningDetectionTimer.running + speed: marbleMaps.speed + + MouseArea { + anchors.fill: parent + onPressed: app.state = "position" + } + } MouseArea { anchors.fill: parent - onPressed: app.state = "position" + propagateComposedEvents: true + onPressed: { + marbleMaps.focus = true; + mouse.accepted = false; + } } + + } - MouseArea { - anchors.fill: parent - propagateComposedEvents: true - onPressed: { - marbleMaps.focus = true; - mouse.accepted = false; - } + NavigationManager { + id: navigationManager + width: parent.width + height: parent.height + visible: false + marbleItem: marbleMaps + hasRoute: routingManager.hasRoute } + } + BoxedText { + id: distanceIndicator + text: qsTr("%1 km").arg(zoomToPositionButton.distance < 10 ? zoomToPositionButton.distance.toFixed(1) : zoomToPositionButton.distance.toFixed(0)) + anchors { + bottom: zoomToPositionButton.top + horizontalCenter: zoomToPositionButton.horizontalCenter + } + visible: marbleMaps.positionAvailable && !marbleMaps.positionVisible } - NavigationManager { - id: navigationManager - width: parent.width - height: parent.height - visible: false - marbleItem: marbleMaps - hasRoute: routingManager.hasRoute - } - } + PositionButton { + id: zoomToPositionButton + anchors { + right: parent.right + rightMargin: Screen.pixelDensity * 1 + bottom: mapItem.bottom + bottomMargin: 10 + } - BoxedText { - id: distanceIndicator - text: qsTr("%1 km").arg(zoomToPositionButton.distance < 10 ? zoomToPositionButton.distance.toFixed(1) : zoomToPositionButton.distance.toFixed(0)) - anchors { - bottom: zoomToPositionButton.top - horizontalCenter: zoomToPositionButton.horizontalCenter - } + enabled: marbleMaps.positionAvailable - visible: marbleMaps.positionAvailable && !marbleMaps.positionVisible - } + iconSource: marbleMaps.positionAvailable ? "qrc:///gps_fixed.png" : "qrc:///gps_not_fixed.png" - PositionButton { - id: zoomToPositionButton - anchors { - right: parent.right - rightMargin: Screen.pixelDensity * 1 - bottom: routeEditorButton.top - bottomMargin: 10 + onClicked: marbleMaps.centerOnCurrentPosition() + + property real distance: 0 + + function updateIndicator() { + var point = marbleMaps.mapFromItem(zoomToPositionButton, diameter * 0.5, diameter * 0.5); + distance = 0.001 * marbleMaps.distanceFromPointToCurrentLocation(point); + angle = marbleMaps.angleFromPointToCurrentLocation(point); + } + + showDirection: marbleMaps.positionAvailable && !marbleMaps.positionVisible } + } - enabled: marbleMaps.positionAvailable - iconSource: marbleMaps.positionAvailable ? "qrc:///gps_fixed.png" : "qrc:///gps_not_fixed.png" + Row { + id: bottomMenu + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: dialogLoader.top + width: parent.width + height: bottomMenu.visible ? routeEditorButton.height + Screen.pixelDensity * 2 : 0 + anchors.topMargin: app.animatedMargin + visible: app.state === "place" || app.state === "route" + + onVisibleChanged: bottomMenuAnimation.start() + + NumberAnimation { + id: bottomMenuAnimation + target: bottomMenu + property: "y" + from: app.height - bottomMenu.height + to: 0 + duration: 500 + easing.type: Easing.InExpo + } - onClicked: marbleMaps.centerOnCurrentPosition() + Item { + id: bottomMenuBackground + anchors.fill: parent + Rectangle { + color: Material.accent + anchors.fill : parent + } + } - property real distance: 0 + Row { + anchors.centerIn: parent + spacing: Kirigami.Units.gridUnit * 2 + + FlatButton { + id: routeEditorButton + property string currentProfileIcon: "qrc:///material/directions-car.svg" + height: Screen.pixelDensity * 6 + width: height + enabled: app.state !== "route" || routingManager.hasRoute + imageSource: "qrc:///material/directions.svg" + + onClicked: { + if (app.state === "route") { + app.state = "none" + navigationManager.visible = true + } else if (app.state === "place") { + app.state = "route" + routingManager.addToRoute() + } else { + app.state = "route" + navigationManager.visible = false + } + } + states: [ + State { + name: "" + PropertyChanges { target: routeEditorButton; imageSource: "qrc:///material/directions.svg"; } + }, + State { + name: "routingAction" + when: app.state === "route" + PropertyChanges { target: routeEditorButton; imageSource: "qrc:///material/navigation.svg"; } + }, + State { + name: "placeAction" + when: app.state === "place" + PropertyChanges { target: routeEditorButton; imageSource: "qrc:///material/directions.svg" } + } + ] + } - function updateIndicator() { - var point = marbleMaps.mapFromItem(zoomToPositionButton, diameter * 0.5, diameter * 0.5); - distance = 0.001 * marbleMaps.distanceFromPointToCurrentLocation(point); - angle = marbleMaps.angleFromPointToCurrentLocation(point); + FlatButton { + id: bookmarkButton + anchors.verticalCenter: parent.verticalCenter + height: Screen.pixelDensity * 6 + width: height + property bool bookmark: bookmarks.isBookmark(app.selectedPlacemark.longitude, app.selectedPlacemark.latitude) + enabled: app.state === "place" + visible: app.state === "place" + imageSource: bookmark ? "qrc:///material/star.svg" : "qrc:///material/star_border.svg" + onClicked: { + if (bookmarkButton.bookmark) { + bookmarks.removeBookmark(app.selectedPlacemark.longitude, app.selectedPlacemark.latitude) + } else { + bookmarks.addBookmark(app.selectedPlacemark, "Default") + } + bookmarkButton.bookmark = !bookmarkButton.bookmark + } + } + } } - showDirection: marbleMaps.positionAvailable && !marbleMaps.positionVisible + + BorderImage { + anchors.top: mapItem.bottom + anchors.bottom: dialogLoader.bottom + anchors.right: parent.right + anchors.left: parent.left + anchors.margins: -14 + border { top: 14; left: 14; right: 14; bottom: 14 } + source: "qrc:///border_shadow.png" } - CircularButton { - id: routeEditorButton + Search { + id: search + anchors.fill: parent + marbleQuickItem: marbleMaps + visible: !navigationManager.visible + + onItemSelected: { + if (routingManager) { + routingManager.addSearchResultAsPlacemark(suggestedPlacemark); + } + app.selectedPlacemark = suggestedPlacemark; + app.state = "place" + } + onMenuButtonClicked: sidePanel.open() + } - property string currentProfileIcon: "qrc:///material/directions-car.svg" + Loader { + id: dialogLoader + focus: true + width: childrenRect.width + height : childrenRect.height anchors { - bottom: parent.bottom - bottomMargin: Screen.pixelDensity * 4 - mapOffset - horizontalCenter: zoomToPositionButton.horizontalCenter + left: parent.left + right: parent.right + top: parent.bottom + bottom: bottomMenu.top + topMargin: app.animatedMargin + bottomMargin: Kirigami.Units.gridUnits * 10 } - enabled: app.state !== "route" || routingManager.hasRoute + NumberAnimation { + id: loaderAnimation + target: dialogLoader.item + property: "y" + from: dialogLoader.height === 0 ? app.height : app.height - dialogLoader.item.height + to: 0 + duration: 500 + easing.type: Easing.InExpo + } - onClicked: { - if (app.state === "route") { - app.state = "none" - navigationManager.visible = true - } else if (app.state === "place") { - app.state = "route" - routingManager.addToRoute() - } else { - app.state = "route" - navigationManager.visible = false + onLoaded: { + app.state != "none" ? loaderAnimation.running = true : loaderAnimation.running = false + if (app.state === "place") { + dialogLoader.item.map = marbleMaps + dialogLoader.item.placemark = app.selectedPlacemark + dialogLoader.item.showOsmTags = app.showOsmTags + dialogLoader.item.showAccessibility = sidePanel.showAccessibility + } else if (app.state === "route") { + item.routingManager = routingManager + item.routingProfile = routingManager.routingProfile + item.currentIndex = Qt.binding(function() { return app.currentWaypointIndex }) + } else if (app.state == "position") { + dialogLoader.item.map = marbleMaps + dialogLoader.item.navigationManager = navigationManager + } else if (app.state == "none"){ + dialogLoader.height = 0 } } - iconSource: "qrc:///material/directions.svg"; + + Connections { + target: dialogLoader.item + onCurrentProfileIconChanged: routeEditorButton.currentProfileIcon = dialogLoader.item.currentProfileIcon + ignoreUnknownSignals: true + } + } + + Rectangle { + width: parent.width + color: Kirigami.Theme.textColor + opacity: 0.4 + height: 1 + anchors.bottom: dialogLoader.top + } + + Item { + id: stateTracker + state: "none" states: [ State { - name: "" - PropertyChanges { target: routeEditorButton; iconSource: "qrc:///material/directions.svg"; } + name: "none" + PropertyChanges { target: dialogLoader; source: "" } + }, + State { + name: "position" + PropertyChanges { target: dialogLoader; source: "CurrentPosition.qml" } }, State { - name: "routingAction" - when: app.state === "route" - PropertyChanges { target: routeEditorButton; iconSource: "qrc:///material/navigation.svg"; } + name: "route" + PropertyChanges { target: dialogLoader; source: "RouteEditor.qml" } }, State { - name: "placeAction" - when: app.state === "place" - PropertyChanges { target: routeEditorButton; iconSource: currentProfileIcon } + name: "place" + PropertyChanges { target: dialogLoader; source: "PlacemarkDialog.qml" } + }, + State { + name: "about" + PropertyChanges { target: dialogLoader; source: "" } + }, + State { + name: "settings" + PropertyChanges { target: dialogLoader; source: "SettingsDialog.qml" } + }, + State { + name: "developer" + PropertyChanges { target: dialogLoader; source: "DeveloperDialog.qml" } + }, + State { + name: "options" + PropertyChanges { target: dialogLoader; source: "" } + }, + State { + name: "bookmarks" + PropertyChanges { target: dialogLoader; source: "" } } ] } - } - Search { - id: search - anchors.fill: parent - marbleQuickItem: marbleMaps - visible: !navigationManager.visible - - onItemSelected: { - if (routingManager) { - routingManager.addSearchResultAsPlacemark(suggestedPlacemark); + BoxedText { + id: quitHelper + visible: false + text: qsTr("Press again to close.") + anchors.bottom: parent.bottom + anchors.bottomMargin: Screen.pixelDensity * 5 + anchors.horizontalCenter: parent.horizontalCenter + onVisibleChanged: { + if (visible) { + quitTimer.restart() + } } - app.selectedPlacemark = suggestedPlacemark; - app.state = "place" - } - onMenuButtonClicked: sidePanel.open() - } - Loader { - id: dialogLoader - focus: true - width: childrenRect.width - height : childrenRect.height - - anchors { - left: parent.left - right: parent.right - top: parent.bottom - topMargin: app.animatedMargin - } - - onLoaded: { - if (app.state === "place") { - dialogLoader.item.map = marbleMaps - dialogLoader.item.placemark = app.selectedPlacemark - dialogLoader.item.showOsmTags = app.showOsmTags - dialogLoader.item.showAccessibility = sidePanel.showAccessibility - } else if (app.state === "route") { - item.routingManager = routingManager - item.routingProfile = routingManager.routingProfile - item.currentIndex = Qt.binding(function() { return app.currentWaypointIndex }) - } else if (app.state == "position") { - dialogLoader.item.map = marbleMaps - dialogLoader.item.navigationManager = navigationManager - } - } - - Connections { - target: dialogLoader.item - onCurrentProfileIconChanged: routeEditorButton.currentProfileIcon = dialogLoader.item.currentProfileIcon - ignoreUnknownSignals: true - } - } - - BorderImage { - visible: app.state != "none" - anchors.fill: dialogLoader - anchors.margins: -14 - border { top: 14; left: 14; right: 14; bottom: 14 } - source: "qrc:///border_shadow.png" - } - - BoxedText { - id: quitHelper - visible: false - text: qsTr("Press again to close.") - anchors.bottom: parent.bottom - anchors.bottomMargin: Screen.pixelDensity * 5 - anchors.horizontalCenter: parent.horizontalCenter - onVisibleChanged: { - if (visible) { - quitTimer.restart() + Timer { + id: quitTimer + interval: 3000; + running: false; + repeat: false + onTriggered: { + app.aboutToQuit = false + quitHelper.visible = false + } } } - Timer { - id: quitTimer - interval: 3000; - running: false; - repeat: false - onTriggered: { - app.aboutToQuit = false - quitHelper.visible = false - } + Bookmarks { + id: bookmarks + map: marbleMaps } } - - Item { - id: stateTracker - - state: "none" - - states: [ - State { - name: "none" - PropertyChanges { target: dialogLoader; source: "" } - }, - State { - name: "position" - PropertyChanges { target: dialogLoader; source: "CurrentPosition.qml" } - }, - State { - name: "route" - PropertyChanges { target: dialogLoader; source: "RouteEditor.qml" } - }, - State { - name: "place" - PropertyChanges { target: dialogLoader; source: "PlacemarkDialog.qml" } - }, - State { - name: "about" - PropertyChanges { target: dialogLoader; source: "" } - }, - State { - name: "settings" - PropertyChanges { target: dialogLoader; source: "SettingsDialog.qml" } - }, - State { - name: "developer" - PropertyChanges { target: dialogLoader; source: "DeveloperDialog.qml" } - }, - State { - name: "options" - PropertyChanges { target: dialogLoader; source: "" } - }, - State { - name: "bookmarks" - PropertyChanges { target: dialogLoader; source: "" } - } - ] - } } - property bool aboutToQuit: false - - onClosing: { - if (app.aboutToQuit === true) { - close.accepted = true // we will quit - return - } else if (navigationManager.visible) { - navigationManager.visible = false - } else if (sidePanel.drawerOpen) { - sidePanel.close() - } else if (pageStack.depth > 1) { - pageStack.pop() - } - else if (app.state !== "none") { - app.state = "none" - } else { - app.aboutToQuit = true - quitHelper.visible = true - } - close.accepted = false - } -} diff --git a/src/apps/marble-maps/MarbleMaps.qrc b/src/apps/marble-maps/MarbleMaps.qrc index 8e236777b..2d454299e 100644 --- a/src/apps/marble-maps/MarbleMaps.qrc +++ b/src/apps/marble-maps/MarbleMaps.qrc @@ -1,97 +1,98 @@ AboutDialog.qml FlatButton.qml Completion.qml MainScreen.qml SearchResults.qml SearchField.qml Search.qml CircularButton.qml IconText.qml PositionButton.qml BoxedText.qml ImageButton.qml WaypointImage.qml RoutingManager.qml PlacemarkDialog.qml SettingsDialog.qml DeveloperDialog.qml ProfileSelectorMenu.qml FloatingMenuButton.qml RouteEditor.qml RoutesItem.qml MenuIcon.qml NavigationInfoBar.qml NavigationManager.qml PositionMarker.qml Waypoint.qml CurrentPosition.qml SidePanel.qml PublicTransport.qml OutdoorActivities.qml Options.qml Bookmarks.qml drawer.svg ../../../data/android/drawable-xxxhdpi/search.png ../../../data/android/drawable-xxxhdpi/ic_menu_black_48dp.png ../../../data/android/drawable-xxxhdpi/gps_fixed.png ../../../data/android/drawable-xxxhdpi/gps_not_fixed.png ../../../data/android/drawable-xxxhdpi/backdrop.png ../../../data/android/drawable-xxxhdpi/border_shadow.png ../../../data/android/drawable-xxxhdpi/map.png ../../../data/android/drawable-xxxhdpi/waypoint.png ../../../data/android/drawable-xxxhdpi/up.png ../../../data/android/drawable-xxxhdpi/down.png ../../../data/android/drawable-xxxhdpi/delete.png ../../../data/android/drawable-xxxhdpi/delete_white.png ../../../data/android/drawable-xxxhdpi/ic_close_black_18dp.png ../../../data/android/drawable-xxxhdpi/busy_indicator.png ../../../data/android/drawable-xxxhdpi/navigation_blue.png ../../../data/svg/navigation_blue.svg ../../../data/android/drawable-xxxhdpi/circular_menu_backdrop.png ../../../data/android/drawable-xxxhdpi/ic_place.png ../../../data/android/drawable-xxxhdpi/ic_place_arrival.png ../../../data/android/drawable-xxxhdpi/ic_place_departure.png ../../../data/android/drawable-xxxhdpi/ic_place_unknown.png ../../../data/android/drawable-xxxhdpi/ic_place_via.png ../../../data/android/drawable-xxxhdpi/ic_add_black_48dp.png ../../../data/android/drawable-xxxhdpi/ic_settings_black_48dp.png icons/marble-lineart-simplified-logo.svg material-icons/ic_local_gas_station_48px.svg material-icons/ic_open_in_browser_48px.svg material-icons/ic_volume_off_48px.svg material-icons/ic_volume_up_48px.svg material-icons/ic_directions_48px.svg ../../../data/svg/material/maps/ic_directions_bike_48px.svg ../../../data/svg/material/maps/ic_directions_boat_48px.svg ../../../data/svg/material/maps/ic_directions_bus_48px.svg ../../../data/svg/material/maps/ic_directions_car_48px.svg ../../../data/svg/material/maps/ic_directions_railway_48px.svg ../../../data/svg/material/maps/ic_directions_run_48px.svg ../../../data/svg/material/maps/ic_directions_subway_48px.svg ../../../data/svg/material/maps/ic_directions_walk_48px.svg ../../../data/svg/material/maps/ic_tram_48px.svg ../../../data/svg/thenounproject/204712-hiker.svg ../../../data/svg/thenounproject/61698-mountain-biking.svg ../../../data/svg/thenounproject/101965-inline-skater.svg ../../../data/svg/thenounproject/78374-horse-riding.svg material-icons/ic_navigation_48px.svg material-icons/ic_access_time_48px.svg material-icons/ic_accessible_black_48px.svg material-icons/ic_network_wifi_black_48px.svg material-icons/ic_place_black_48px.svg material-icons/ic_star_24px.svg material-icons/ic_star_border_24px.svg material-icons/ic_label_48px.svg konqi/konqi-app-dev.png konqi/konqi-dev-qt.png konqi/konqi-group.png konqi/konqi-globe.png konqi/konqi-books.png RouteProfileRadioButton.qml MarbleScrollBar.qml material-icons/ic_phone_black_48px.svg material-icons/ic_drag_handle_black_48dp.png + qtquickcontrols2.conf diff --git a/src/apps/marble-maps/PlacemarkDialog.qml b/src/apps/marble-maps/PlacemarkDialog.qml index a31f3a44c..af68b809a 100644 --- a/src/apps/marble-maps/PlacemarkDialog.qml +++ b/src/apps/marble-maps/PlacemarkDialog.qml @@ -1,209 +1,175 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Dennis Nienhüser // import QtQuick 2.3 import QtQuick.Window 2.2 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.3 import QtQuick.Dialogs 1.2 import org.kde.marble 0.20 Item { id: root property var placemark: null property variant map property alias showOsmTags: tagsView.visible property bool showAccessibility: false - height: placemark === null ? 0 : Screen.pixelDensity * 4 + - (infoLayout.height > bookmarkButton.height ? infoLayout.height : bookmarkButton.height) + height: placemark === null ? 0 : Screen.pixelDensity * 4 +infoLayout.height - onPlacemarkChanged: { - if (placemark) { - bookmarkButton.bookmark = bookmarks.isBookmark(placemark.longitude, placemark.latitude) - } - } SystemPalette { id: palette colorGroup: SystemPalette.Active } Rectangle { anchors.fill: parent color: palette.base } Bookmarks { id: bookmarks } onMapChanged: bookmarks.map = root.map Column { id: infoLayout anchors { top: parent.top left: parent.left - right: bookmarkButton.left + right: parent.right margins: Screen.pixelDensity * 2 } IconText { id: name width: parent.width visible: text.length > 0 text: placemark === null ? "" : placemark.name maximumLineCount: 2 font.pointSize: 20 } IconText { width: parent.width visible: text.length > 0 text: placemark === null ? "" : placemark.description } IconText { width: parent.width visible: text.length > 0 text: placemark === null ? "" : placemark.address maximumLineCount: 4 } IconText { width: parent.width visible: routesItem.count > 0 text: "Part of " + routesItem.count + " routes" maximumLineCount: 4 linkColor: palette.text onLinkActivated: routesDialog.open() } IconText { width: parent.width visible: url.length > 0 property string url: placemark === null ? "" : placemark.website text: "" + url + "" icon: "qrc:/material/browser.svg" maximumLineCount: 4 onLinkActivated: Qt.openUrlExternally(link) } IconText { width: parent.width visible: phone.length > 0 property string phone: placemark === null ? "" : placemark.phone text: "" + phone + "" icon: "qrc:/material/phone.svg" maximumLineCount: 1 onLinkActivated: Qt.openUrlExternally(link) } IconText { width: parent.width visible: url.length > 0 property string url: placemark === null ? "" : placemark.wikipedia text: "Wikipedia" icon: "qrc:/material/browser.svg" maximumLineCount: 4 onLinkActivated: Qt.openUrlExternally(link) } IconText { width: parent.width visible: text.length > 0 text: placemark === null ? "" : placemark.openingHours icon: "qrc:/material/access_time.svg" } IconText { width: parent.width visible: root.showAccessibility && text.length > 0 text: placemark === null ? "" : placemark.wheelchairInfo icon: "qrc:/material/wheelchair.svg" } IconText { width: parent.width visible: text.length > 0 text: placemark === null ? "" : placemark.wifiAvailable icon: "qrc:/material/wlan-available.svg" } IconText { width: parent.width visible: text.length > 0 text: placemark === null ? "" : "" + placemark.coordinates + "" icon: "qrc:/material/place.svg" linkColor: palette.text onLinkActivated: marbleMaps.centerOnCoordinates(placemark.longitude, placemark.latitude) } ListView { id: tagsView visible: false width: parent.width height: Math.min(contentHeight, Screen.pixelDensity * 24) clip: true model: placemark ? placemark.tags : undefined delegate: IconText { width: tagsView.width; icon: "qrc:/material/label.svg" text: modelData } ScrollBar.vertical: ScrollBar {} } } - Image { - id: bookmarkButton - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Screen.pixelDensity * 2 - visible: root.height > 0 - - property bool bookmark: false - - width: Screen.pixelDensity * 6 - height: width - sourceSize.height: height - sourceSize.width: width - source: bookmark ? "qrc:/material/star.svg" : "qrc:/material/star_border.svg" - - MouseArea { - id: touchArea - anchors.fill: parent - onClicked: { - if (bookmarkButton.bookmark) { - bookmarks.removeBookmark(root.placemark.longitude, root.placemark.latitude) - } else { - bookmarks.addBookmark(root.placemark, "Default") - } - bookmarkButton.bookmark = !bookmarkButton.bookmark - } - } - } Dialog { id: routesDialog title: qsTr("Routes") RoutesItem { id: routesItem implicitWidth: parent.width model: placemark === null ? undefined : placemark.routeRelationModel onHighlightChanged: map.highlightRouteRelation(oid, enabled) } } } diff --git a/src/apps/marble-maps/Search.qml b/src/apps/marble-maps/Search.qml index 47ae6d54d..d42aa5c92 100644 --- a/src/apps/marble-maps/Search.qml +++ b/src/apps/marble-maps/Search.qml @@ -1,191 +1,199 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Gábor Péterffy // -import QtQuick 2.3 +import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Window 2.2 import org.kde.marble 0.20 Item { id: root property var marbleQuickItem: null signal itemSelected(var suggestedPlacemark) signal menuButtonClicked() readonly property alias searchResultPlacemark: backend.selectedPlacemark readonly property alias searchResultsVisible: searchResults.visible onVisibleChanged: { if( !visible ) { searchResults.visible = false; searchField.query = ""; } } SystemPalette { id: palette colorGroup: SystemPalette.Active } SystemPalette { id: paletteDisabled colorGroup: SystemPalette.Disabled } SearchResults { id: searchResults anchors { top: searchField.bottom left: searchField.left } width: searchField.width height: delegateHeight * Math.min(10,count) visible: false onItemSelected: { backend.setSelectedPlacemark(index); root.itemSelected(backend.selectedPlacemark); searchResults.visible = false; } } Rectangle { id: background visible: searchField.hasFocus && searchField.query === "" anchors.top: searchField.bottom anchors.left: searchField.left width: searchField.width height: childrenRect.height + 2 * itemSpacing color: palette.base property int delegateHeight: 0 property double itemSpacing: Screen.pixelDensity * 1 Column { anchors.top: parent.top - anchors.topMargin: background.itemSpacing anchors.left: parent.left anchors.right: parent.right - anchors.margins: background.itemSpacing spacing: background.itemSpacing ListView { id: bookmarksView anchors.left: parent.left anchors.right: parent.right height: background.delegateHeight * Math.min(6, model.count) clip: true ScrollIndicator.vertical: ScrollIndicator { } model: bookmarks.model delegate: Row { width: bookmarksView.width height: background.itemSpacing + Math.max(bookmarkIcon.height, bookmarkText.height) spacing: background.itemSpacing + leftPadding: 10 + rightPadding: 10 + Image { id: bookmarkIcon anchors.verticalCenter: parent.verticalCenter source: iconPath.substr(0,1) === '/' ? "file://" + iconPath : iconPath width: Screen.pixelDensity * 4 height: width sourceSize.width: width sourceSize.height: height } Text { id: bookmarkText anchors.verticalCenter: parent.verticalCenter anchors.leftMargin: Screen.pixelDensity * 2 width: bookmarksView.width - bookmarksView.spacing - bookmarkIcon.width text: display - font.pointSize: 18 + font.pointSize: 14 color: palette.text elide: Text.ElideMiddle MouseArea { anchors.fill: parent onClicked: { bookmarksView.currentIndex = index app.selectedPlacemark = bookmarks.placemark(index); itemSelected(bookmarks.placemark(index)) marbleMaps.centerOn(selectedPlacemark.longitude, selectedPlacemark.latitude) dialogLoader.focus = true } } } onHeightChanged: { if( background.delegateHeight !== height ) { background.delegateHeight = height; } } } } Row { visible: bookmarksView.model.count === 0 width: parent.width + anchors.left: parent.left + anchors.right: parent.right + spacing: Screen.pixelDensity * 2 + anchors.margins: Screen.pixelDensity * 2 Text { anchors.bottom: parent.bottom - width: 0.8 * parent.width - font.pointSize: 18 + leftPadding: 10 + bottomPadding: 3 + width: parent.width - Screen.pixelDensity * 2 - emptyImage.width + font.pointSize: 14 color: paletteDisabled.text text: qsTr("Your bookmarks will appear here.") + wrapMode: Text.WrapAtWordBoundaryOrAnywhere elide: Text.ElideRight } Image { + id: emptyImage anchors.bottom: parent.bottom - width: 0.2 * parent.width + width: Screen.pixelDensity* 10 + fillMode: Image.PreserveAspectFit source: "qrc:/konqi/books.png" } } } } SearchBackend { id: backend marbleQuickItem: root.marbleQuickItem onSearchResultChanged: { searchResults.model = model; searchResults.visible = true; } onSearchFinished: searchField.busy = false } SearchField { id: searchField - width: parent.width - 2 * anchors.margins <= Screen.pixelDensity * 70 ? - parent.width - 2 * anchors.margins - : Screen.pixelDensity * 50 + width: parent.width anchors { top: parent.top left: parent.left - margins: Screen.pixelDensity * 3 + right: parent.right } completionModel: backend.completionModel onSearchRequested: backend.search(query) onCompletionRequested: backend.setCompletionPrefix(query) onCleared: searchResults.visible = false onMenuButtonClicked: root.menuButtonClicked() } Bookmarks { id: bookmarks map: root.marbleQuickItem } } diff --git a/src/apps/marble-maps/SearchField.qml b/src/apps/marble-maps/SearchField.qml index 7921b3fda..9752e188e 100644 --- a/src/apps/marble-maps/SearchField.qml +++ b/src/apps/marble-maps/SearchField.qml @@ -1,159 +1,158 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Gábor Péterffy // Copyright 2015 Dennis Nienhüser // Copyright 2015 Mikhail Ivchenko // import QtQuick 2.3 import QtQuick.Controls 1.3 import QtQuick.Controls.Styles 1.3 Item { id: root height: field.height property alias query: field.text property alias hasFocus: field.activeFocus property alias completionModel: completion.model property bool busy: false signal searchRequested(string query) signal completionRequested(string query) signal cleared() signal menuButtonClicked() function search(query) { routingManager.clearSearchResultPlacemarks(); query = query.trim(); if(query.toLowerCase() === "ok marble" || query.toLowerCase() === "okdbg") { app.state = "developer"; } else if(query !== "") { root.busy = true; searchRequested(query); field.focus = false; } } SystemPalette{ id: palette colorGroup: SystemPalette.Active } Rectangle { anchors.fill: parent color: palette.base border.color: palette.shadow border.width: 1 } FlatButton { id: menuButton anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 10 height: 0.7 * field.height width: height imageSource: "qrc:///menu.png" MouseArea { anchors.fill: parent onClicked: root.menuButtonClicked() } } TextField { id: field anchors.left: menuButton.right anchors.right: parent.right placeholderText: qsTr("Search") - font.pointSize: 18 + font.pointSize: 16 textColor: palette.text inputMethodHints: Qt.ImhNoPredictiveText onAccepted: root.search(text) onTextChanged: root.completionRequested(text) BusyIndicator { id: searchBusyIndicator anchors.verticalCenter: parent.verticalCenter anchors.right: clearButton.visible ? clearButton.left : clearButton.right anchors.rightMargin: 10 visible: running height: 0.7 * field.height width: height running: root.busy style: BusyIndicatorStyle { indicator: Image { visible: control.running source: "busy_indicator.png" RotationAnimator on rotation { running: control.running loops: Animation.Infinite duration: 1500 from: 0 ; to: 360 } } } } FlatButton { id: clearButton anchors.verticalCenter: parent.verticalCenter anchors.right: searchButton.visible ? searchButton.left : parent.right anchors.rightMargin: 10 height: 0.7 * field.height width: height visible: field.text !== "" imageSource: "qrc:///clear.png" MouseArea { anchors.fill: parent onClicked: { app.selectedPlacemark = null; app.state = "none" routingManager.clearSearchResultPlacemarks(); field.text = ""; field.focus = true; cleared(); } } } FlatButton { id: searchButton anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: 10 height: 0.7 * field.height width: height visible: !root.busy enabled: field.text !== "" imageSource: "qrc:///search.png" - onClicked: root.search(field.text) } } Completion { id: completion anchors { top: parent.bottom left: parent.left right: parent.right } height: delegateHeight * Math.min(2,count) visible: count > 0 && field.activeFocus onItemSelected: { field.text = name; search(name); } } }