diff --git a/src/apps/marble-maps/Bookmarks.qml b/src/apps/marble-maps/Bookmarks.qml new file mode 100644 --- /dev/null +++ b/src/apps/marble-maps/Bookmarks.qml @@ -0,0 +1,247 @@ +// +// 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 2016 Dennis Nienhüser +// + +import QtQuick 2.8 +import QtQuick.Controls 2.2 +import QtQuick.Window 2.2 +import QtQuick.Layouts 1.3 +import QtQml.Models 2.1 +import QtQuick.Controls.Material 2.1 +import QtGraphicalEffects 1.0 + +import org.kde.kirigami 2.0 as Kirigami + +import org.kde.marble 0.20 + +Kirigami.Page { + id: bookmarkPage + title: "Bookmarks" + + property variant marbleQuickItem + signal backTriggered() + + Flickable { + id: root + anchors.fill: parent + property int currentIndex: 0 + + SystemPalette { + id: palette + colorGroup: SystemPalette.Active + } + + Column { + id: column + anchors { + fill: parent + margins: Screen.pixelDensity * 2 + } + + Text { + text: "

Bookmarks

" + } + + ListView { + id: bookmarksView + interactive: false + width: parent.width + spacing: 5 + height: contentHeight + + model: DelegateModel { + id: visualModel + model: bookmarks.model + + delegate: + MouseArea { + id: delegateRoot + propagateComposedEvents: true + property int visualIndex: DelegateModel.itemsIndex + width: bookmarksView.width + height: 100 + drag.target: icon + drag.axis: Drag.YAxis + + SwipeDelegate { + id: delegate + text: model.display + width: parent.width + height: Screen.pixelDensity * 2 + Math.max(bookmarkText.height, imageButton.height) + + contentItem: Rectangle { + id: icon + width: parent.width + height: Screen.pixelDensity + Math.max(bookmarkText.height, imageButton.height) + + anchors { + horizontalCenter: parent.horizontalCenter; + verticalCenter: parent.verticalCenter + } + + Drag.active: delegateRoot.drag.active + Drag.source: delegateRoot + Drag.hotSpot.x: 50 //150 + Drag.hotSpot.y: 50 //150 + color: "transparent" + + Text{ + id: bookmarkText + anchors.left: imageButton.right + leftPadding: 5 + text: delegate.text + elide: Text.ElideRight + horizontalAlignment: Text.AlignLeft + anchors.verticalCenter: parent.verticalCenter + font.pointSize: 12 + color: palette.text + } + + Image { + id: imageButton + anchors { + left: bookmarksView.left + verticalCenter: parent.verticalCenter + } + source: "qrc:///material/place.svg" + width: Screen.pixelDensity * 6 + verticalAlignment: Qt.AlignVCenter + + height: width + smooth: true + } + + ColorOverlay{ + anchors.fill: imageButton + source: imageButton + color: palette.highlight + } + } + + swipe.behind: Item { + width: parent.width + height: parent.height + + Rectangle{ + width: parent.width + color: "#333333" + height: parent.height + z: 200 + Text { + font.pointSize: 10 + text: qsTr("Removed") + color: "white" + + padding: 20 + anchors.fill: parent + horizontalAlignment: Qt.AlignRight + verticalAlignment: Qt.AlignVCenter + + opacity: delegate.swipe.complete ? 1 : 0 + Behavior on opacity { + NumberAnimation {} + } + } + } + + SwipeDelegate.onClicked: delegate.swipe.close() + SwipeDelegate.onPressedChanged: undoTimer.stop() + } + + + Timer { + id: undoTimer + interval: 1600 + onTriggered: { + var currentBookmark = bookmarks.placemark(index) + bookmarks.removeBookmark(currentBookmark.longitude, currentBookmark.latitude) + } + } + + swipe.onCompleted: undoTimer.start() + swipe.onClosed: delegate.swipe.close() + swipe.transition: Transition { + SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } + } + + states: [ + State { + when: icon.Drag.active + ParentChange { + target: icon + parent: root + } + + AnchorChanges { + target: icon; + anchors.horizontalCenter: undefined; + anchors.verticalCenter: undefined + } + } + ] + + background: Rectangle { + color: "transparent" + } + } + + DropArea { + anchors.fill: parent + onEntered: visualModel.items.move(drag.source.visualIndex, delegateRoot.visualIndex) + } + } + } + + remove: Transition { + SequentialAnimation { + PauseAnimation { duration: 125 } + NumberAnimation { property: "height"; to: 0; easing.type: Easing.InOutQuad } + } + } + + displaced: Transition { + SequentialAnimation { + PauseAnimation { duration: 125 } + NumberAnimation { property: "y"; easing.type: Easing.InOutQuad } + } + } + } + + Column { + visible: bookmarksView.model.count === 0 + width: parent.width + + Text { + width: 0.8 * parent.width + font.pointSize: 18 + color: paletteDisabled.text + text: qsTr("Your bookmarks will appear here.") + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + elide: Text.ElideRight + } + + Image { + anchors.right: parent.right + anchors.bottom: column.bottom + width: 0.3 * parent.width + fillMode: Image.PreserveAspectFit + source: "qrc:/konqi/books.png" + } + } + } + + } + + Bookmarks { + id: bookmarks + map: marbleQuickItem + } + + //onMapChanged: bookmarks.map = map +} diff --git a/src/apps/marble-maps/FlatButton.qml b/src/apps/marble-maps/FlatButton.qml --- a/src/apps/marble-maps/FlatButton.qml +++ b/src/apps/marble-maps/FlatButton.qml @@ -23,13 +23,15 @@ } 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 --- a/src/apps/marble-maps/MainScreen.qml +++ b/src/apps/marble-maps/MainScreen.qml @@ -10,10 +10,11 @@ // 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 @@ -26,6 +27,9 @@ 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 @@ -50,6 +54,9 @@ if (!selectedPlacemark) { app.state = "none" } + else { + bookmarkButton.bookmark = bookmarks.isBookmark(selectedPlacemark.longitude, selectedPlacemark.latitude) + } } SystemPalette{ @@ -61,6 +68,35 @@ 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" @@ -125,11 +161,44 @@ 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 @@ -140,437 +209,499 @@ 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: "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: "routingAction" - when: app.state === "route" - PropertyChanges { target: routeEditorButton; iconSource: "qrc:///material/navigation.svg"; } + name: "options" + PropertyChanges { target: dialogLoader; source: "" } }, State { - name: "placeAction" - when: app.state === "place" - PropertyChanges { target: routeEditorButton; iconSource: currentProfileIcon } + 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 - - 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" } - } - ] - } } - 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 --- a/src/apps/marble-maps/MarbleMaps.qrc +++ b/src/apps/marble-maps/MarbleMaps.qrc @@ -30,6 +30,8 @@ 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 @@ -90,5 +92,7 @@ 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/Options.qml b/src/apps/marble-maps/Options.qml new file mode 100644 --- /dev/null +++ b/src/apps/marble-maps/Options.qml @@ -0,0 +1,80 @@ +// +// 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 2016 Dennis Nienhüser +// + +import QtQuick 2.8 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +import org.kde.kirigami 2.0 as Kirigami + +import org.kde.marble 0.20 + +Kirigami.ScrollablePage { + id: optionsPage + padding: 0 + topPadding: 0 + leftPadding: 0 + rightPadding: 0 + bottomPadding: 0 + + signal backTriggered() + + Column { + anchors { + fill: parent + margins: Kirigami.Units.gridUnit + } + + Label { + text: qsTr("

Layer Options

") + } + + Label { + text: qsTr("

Public Transport Layers

") + } + + Item{ + implicitHeight: publicTransportLoader.height + Kirigami.Units.gridUnit * 4 + width: parent.width + + Loader { + anchors.fill: parent + id: publicTransportLoader + source: "PublicTransport.qml" + + onLoaded: { + item.implicitWidth = parent.width + item.marbleMaps = marbleMaps + } + } + } + + Label { + topPadding: Kirigami.Units.gridUnit + text: qsTr("

Outdoor Activities Layers

") + } + + Item{ + implicitHeight: outdoorActivitiesLoader.height + Kirigami.Units.gridUnit * 6 + width: parent.width + + Loader { + anchors.fill: parent + id: outdoorActivitiesLoader + source: "OutdoorActivities.qml" + + onLoaded: { + item.implicitWidth = parent.width + item.marbleMaps = marbleMaps + } + } + } + } +} diff --git a/src/apps/marble-maps/PlacemarkDialog.qml b/src/apps/marble-maps/PlacemarkDialog.qml --- a/src/apps/marble-maps/PlacemarkDialog.qml +++ b/src/apps/marble-maps/PlacemarkDialog.qml @@ -14,6 +14,8 @@ import QtQuick.Layouts 1.3 import QtQuick.Dialogs 1.2 +import org.kde.kirigami 2.0 as Kirigami + import org.kde.marble 0.20 Item { @@ -24,14 +26,8 @@ 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 @@ -55,7 +51,7 @@ anchors { top: parent.top left: parent.left - right: bookmarkButton.left + right: parent.right margins: Screen.pixelDensity * 2 } @@ -167,43 +163,23 @@ } } - 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 + Kirigami.OverlaySheet { + id: routesDialog + ColumnLayout { + property int implicitWidth: root.width//Units.gridUnit * 30 + id: columnLayout + Label{ + Layout.fillWidth: true + text: qsTr("

Routes

") + + } + RoutesItem { + id: routesItem + Layout.fillWidth: true + model: placemark === null ? undefined : placemark.routeRelationModel + onHighlightChanged: map.highlightRouteRelation(oid, enabled) } - } - } - 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 --- a/src/apps/marble-maps/Search.qml +++ b/src/apps/marble-maps/Search.qml @@ -8,7 +8,7 @@ // Copyright 2015 Gábor Péterffy // -import QtQuick 2.3 +import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Window 2.2 @@ -73,10 +73,8 @@ 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 { @@ -93,6 +91,9 @@ height: background.itemSpacing + Math.max(bookmarkIcon.height, bookmarkText.height) spacing: background.itemSpacing + leftPadding: 10 + rightPadding: 10 + Image { id: bookmarkIcon anchors.verticalCenter: parent.verticalCenter @@ -109,7 +110,7 @@ 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 @@ -136,20 +137,29 @@ 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" } @@ -169,13 +179,11 @@ 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) diff --git a/src/apps/marble-maps/SearchField.qml b/src/apps/marble-maps/SearchField.qml --- a/src/apps/marble-maps/SearchField.qml +++ b/src/apps/marble-maps/SearchField.qml @@ -74,7 +74,7 @@ anchors.right: parent.right placeholderText: qsTr("Search") - font.pointSize: 18 + font.pointSize: 16 textColor: palette.text inputMethodHints: Qt.ImhNoPredictiveText onAccepted: root.search(text) @@ -137,7 +137,6 @@ visible: !root.busy enabled: field.text !== "" imageSource: "qrc:///search.png" - onClicked: root.search(field.text) } }