diff --git a/src/apps/behaim/CMakeLists.txt b/src/apps/behaim/CMakeLists.txt index e992ab93f..858960a13 100644 --- a/src/apps/behaim/CMakeLists.txt +++ b/src/apps/behaim/CMakeLists.txt @@ -1,64 +1,66 @@ set(marble_SRCS main.cpp) qt5_add_resources(marble_QRCS MarbleBehaim.qrc) include_directories(${CMAKE_CURRENT_BINARY_DIR}) if (CMAKE_SYSTEM_NAME STREQUAL Android) set(TARGET MarbleBehaim) find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS AndroidExtras) add_library (${TARGET} SHARED ${marble_SRCS} ${marble_QRCS}) # while not directly linked, need to be listed here to have deployqt pick up those libs target_link_libraries ( ${TARGET} marblewidget astro Qt5::Concurrent Qt5::Xml Qt5::Widgets Qt5::PrintSupport Qt5::Network Qt5::Sql Qt5::Svg Qt5::Positioning Qt5::AndroidExtras Qt5::Multimedia ) else() set(TARGET marble-behaim) add_executable (${TARGET} ${marble_SRCS} ${marble_QRCS}) endif() target_link_libraries ( ${TARGET} marbledeclarative ) FILE(GLOB QML_FILES *.qml) add_custom_target(marble-behaim_resources ALL SOURCES ${QML_FILES} package/AndroidManifest.xml) if (CMAKE_SYSTEM_NAME STREQUAL Android) install(DIRECTORY "../../../data/android/" DESTINATION "${CMAKE_INSTALL_PREFIX}/res") set(ABSOLUTE_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}") if(NOT IS_ABSOLUTE "${ABSOLUTE_INSTALL_PATH}") set(ABSOLUTE_INSTALL_PATH "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_PREFIX}") endif() get_filename_component(ABSOLUTE_INSTALL_PATH "${ABSOLUTE_INSTALL_PATH}" ABSOLUTE) get_filename_component(QT_ANDROID_QT_ROOT "${Qt5Core_DIR}/../../.." ABSOLUTE) set(ANDROID_SDK_ROOT $ENV{ANDROID_SDK_ROOT}) set(ANDROID_NDK_ROOT $ENV{ANDROID_NDK_ROOT}) set(QT_ANDROID_APP_PATH "${ABSOLUTE_INSTALL_PATH}/libs/${ANDROID_ABI}/libMarbleBehaim.so") set(QT_ANDROID_APP_EXTRA_LIBS "${ABSOLUTE_INSTALL_PATH}/lib/libastro.so,${ABSOLUTE_INSTALL_PATH}/lib/libmarblewidget-qt5.so,${ABSOLUTE_INSTALL_PATH}/lib/libmarbledeclarative.so") + set(QML_ROOT_PATH "${ABSOLUTE_INSTALL_PATH}/") + set(QT_ANDROID_APP_EXTRA_PLUGINS "${ABSOLUTE_INSTALL_PATH}//share,${ABSOLUTE_INSTALL_PATH}//lib/qml") set(QT_ANDROID_APP_PACKAGE_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/package") set(QT_ANDROID_APP_PACKAGE_NAME "org.kde.marble.behaim") set(QT_ANDROID_APP_NAME "Marble Globe: Behaim's Erdapfel") configure_file(package/deploy-behaim.json.in ${CMAKE_CURRENT_BINARY_DIR}/deploy-behaim.json @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/deploy-behaim.json DESTINATION "${CMAKE_INSTALL_PREFIX}/share") install(TARGETS ${TARGET} LIBRARY DESTINATION libs/${ANDROID_ABI}) else() if(MARBLE_INSTALL_ANDROID_APPS) install(TARGETS ${TARGET} RUNTIME DESTINATION bin) endif() endif() diff --git a/src/apps/behaim/MainScreen.qml b/src/apps/behaim/MainScreen.qml index 3c7472c0f..f890258a4 100644 --- a/src/apps/behaim/MainScreen.qml +++ b/src/apps/behaim/MainScreen.qml @@ -1,141 +1,290 @@ // // 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.Window 2.2 import QtQuick.Layouts 1.1 +import org.kde.kirigami 2.0 as Kirigami import org.kde.marble 0.20 -ApplicationWindow { +Kirigami.ApplicationWindow { id: root - title: qsTr("Behaim Globe") - visible: true - - width: 600 - height: 400 + Layout.fillWidth: true - property bool landscape: root.width > root.height SystemPalette { id: palette colorGroup: SystemPalette.Active } - Rectangle { - id: background - anchors.fill: parent - color: palette.window + globalDrawer: Kirigami.GlobalDrawer { + id: drawer + title: "Settings" + handleVisible: !aboutDrawer.drawerOpen && !infoDrawer.drawerOpen + topContent: [ + CheckBox { + text: qsTr("Show Behaim places") + onCheckedChanged: marbleMaps.setPropertyEnabled("cities", checked) + }, + CheckBox { + text: qsTr("Show texts and illustrations") + onCheckedChanged: marbleMaps.setPropertyEnabled("otherplaces", checked) + }, + CheckBox { + text: qsTr("Show the accurate coastline") + onCheckedChanged: marbleMaps.setPropertyEnabled("coastlines", checked) + }, + Label { + wrapMode: Text.WordWrap + text: qsTr("

Globe Variant

") + Layout.fillWidth: true + }, + ExclusiveGroup { + id: layerGroup + onCurrentChanged: current.apply() + }, + RadioButton { + text: qsTr("Original (1492)") + checked: true + exclusiveGroup: layerGroup + property string description: qsTr("Digital imagery taken directly from the original Behaim globe.") + function apply() { + marbleMaps.setPropertyEnabled("ravenstein", false) + marbleMaps.setPropertyEnabled("ghillany", false) + } + }, + + RadioButton { + text: qsTr("Ghillany (1853)") + property string description: qsTr("A (rough) facsimile created by Friedrich Wilhelm Ghillany in 1853.") + exclusiveGroup: layerGroup + + function apply() { + marbleMaps.setPropertyEnabled("ravenstein", false) + marbleMaps.setPropertyEnabled("ghillany", true) + } + }, + + RadioButton { + text: qsTr("Ravenstein (1908)") + property string description: qsTr("A (rough) facsimile created by Ernest George Ravenstein in 1908.") + exclusiveGroup: layerGroup + function apply() { + marbleMaps.setPropertyEnabled("ghillany", false) + marbleMaps.setPropertyEnabled("ravenstein", true) + } + }, + Item { width: 1; height: Screen.pixelDensity * 2; } + ] + actions: [ + Kirigami.Action { + text: "Information" + onTriggered: { + infoDrawer.open() + if(aboutDrawer.drawerOpen){ + aboutDrawer.close() + } + } + }, + Kirigami.Action { + text: "About" + iconSource: "menu.png" + onTriggered: { + aboutDrawer.open() + if(infoDrawer.drawerOpen){ + infoDrawer.close() + } + } + } + ] } - Grid { - id: mainLayout - columns: root.landscape ? 2 : 1 - columnSpacing: 0 - rows: root.landscape ? 1 : 2 - rowSpacing: 0 - layoutDirection: root.landscape ? Qt.RightToLeft : Qt.LeftToRight + Kirigami.Page { + id: page + property alias marbleMaps: mainLayout.marbleMaps + anchors.fill: parent + title: qsTr("Behaim Globe") + visible: true - Item { - id: mapItem + property bool landscape: root.width > root.height - width: root.landscape ? root.width - infoItem.width : root.width - height: root.landscape ? root.height : root.height - infoItem.height + Rectangle { + id: background + anchors.fill: parent + color: palette.base + } - Rectangle { - color: "black" - anchors.fill: parent - } + Grid { + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter - PinchArea { - anchors.fill: parent - enabled: true + id: mainLayout + property alias marbleMaps: mapItem.marbleMaps + columns: root.landscape ? 2 : 1 + columnSpacing: 0 + rows: root.landscape ? 1 : 2 + rowSpacing: 0 + layoutDirection: root.landscape ? Qt.RightToLeft : Qt.LeftToRight - onPinchStarted: marbleMaps.handlePinchStarted(pinch.center) - onPinchFinished: marbleMaps.handlePinchFinished(pinch.center) - onPinchUpdated: marbleMaps.handlePinchUpdated(pinch.center, pinch.scale); + Item { + id: mapItem + property alias marbleMaps: pinchArea.marbleItem + width: root.width + height: root.height - MarbleItem { - id: marbleMaps + Rectangle { + color: "black" anchors.fill: parent + } + + PinchArea { + id: pinchArea + anchors.fill: parent + enabled: true + property alias marbleItem: marbleMaps + onPinchStarted: marbleMaps.handlePinchStarted(pinch.center) + onPinchFinished: marbleMaps.handlePinchFinished(pinch.center) + onPinchUpdated: marbleMaps.handlePinchUpdated(pinch.center, pinch.scale); + + MarbleItem { + id: marbleMaps + anchors.fill: parent + + focus: true + zoom: 1150 + inertialGlobeRotation: true + + // Theme settings. + projection: MarbleItem.Spherical + mapThemeId: "earth/behaim1492/behaim1492.dgml" + + // Visibility of layers/plugins. + showFrameRate: false + showAtmosphere: true + showCompass: false + showClouds: false + showCrosshairs: false + showGrid: false + showOverviewMap: false + showOtherPlaces: false + showScaleBar: false + showBackground: true + showPositionMarker: false + + Component.onCompleted: { + setPluginSetting("stars", "renderConstellationLines", "false"); + setPluginSetting("stars", "renderConstellationLabels", "false"); + setPluginSetting("stars", "renderDsoLabels", "false"); + setPluginSetting("stars", "viewSolarSystemLabel", "false"); + setPluginSetting("stars", "zoomSunMoon", "false"); + setPluginSetting("stars", "renderEcliptic", "false"); + setPluginSetting("stars", "renderCelestialEquator", "false"); + setPluginSetting("stars", "renderCelestialPole", "false"); + marbleMaps.forceActiveFocus() + } - focus: true - zoom: 1150 - inertialGlobeRotation: true - - // Theme settings. - projection: MarbleItem.Spherical - mapThemeId: "earth/behaim1492/behaim1492.dgml" - - // Visibility of layers/plugins. - showFrameRate: false - showAtmosphere: true - showCompass: false - showClouds: false - showCrosshairs: false - showGrid: false - showOverviewMap: false - showOtherPlaces: false - showScaleBar: false - showBackground: true - showPositionMarker: false - - Component.onCompleted: { - setPluginSetting("stars", "renderConstellationLines", "false"); - setPluginSetting("stars", "renderConstellationLabels", "false"); - setPluginSetting("stars", "renderDsoLabels", "false"); - setPluginSetting("stars", "viewSolarSystemLabel", "false"); - setPluginSetting("stars", "zoomSunMoon", "false"); - setPluginSetting("stars", "renderEcliptic", "false"); - setPluginSetting("stars", "renderCelestialEquator", "false"); - setPluginSetting("stars", "renderCelestialPole", "false"); } } + } + } - Button { - id: minimizeLandscapeButton - visible: root.landscape - anchors.left: marbleMaps.left - anchors.top: marbleMaps.top - anchors.leftMargin: Screen.pixelDensity * (infoItem.minimized ? 0.5 : 1.5) - anchors.topMargin: Screen.pixelDensity * 0.5 - iconSource: "menu.png" - onClicked: infoItem.minimized = !infoItem.minimized - } + Kirigami.OverlayDrawer { + id: infoDrawer + edge: Qt.BottomEdge - Button { - id: minimizePortraitButton - visible: !root.landscape - anchors.right: marbleMaps.right - anchors.bottom: marbleMaps.bottom - anchors.rightMargin: Screen.pixelDensity * 0.5 - anchors.bottomMargin: Screen.pixelDensity * (infoItem.minimized ? 0.5 : 1.5) - iconSource: "menu.png" - onClicked: infoItem.minimized = !infoItem.minimized + contentItem: Item { + Layout.fillWidth: true + implicitHeight: columnLayoutInfo.text.height + Kirigami.Units.gridUnit + ColumnLayout { + id: columnLayoutInfo + property alias text: flickableInfo.text + anchors.fill: parent + Flickable { + id: flickableInfo + property alias text: infoText + anchors.fill: parent + contentWidth: infoText.width + contentHeight: infoText.height + flickableDirection: Flickable.VerticalFlick + clip: true + + Text { + id: infoText + text: qsTr("

Martin Behaim's Erdapfel

\ +

The oldest existent globe of the Earth.\ + Martin Behaim and collaborators created the globe around 1492 at the time of \ + Columbus' first sea travel to the west.\ + Hence the American continent is missing on this globe.\ + Also note the detailed inscriptions in early modern German.

\ +

Please see Wikipedia: Erdapfel \ + for further information about the Behaim globe.") + width: columnLayoutInfo.width + wrapMode: Text.WordWrap + onLinkActivated: Qt.openUrlExternally(link) + } + } + Item { + Layout.minimumHeight: Kirigami.Units.gridUnit * 4 + } } } } - Item { - id: infoItem - property bool minimized: false - width: root.landscape ? (minimized ? 0 : root.width / 2.5) : root.width - height: root.landscape ? root.height : (minimized ? 0 : root.height / 2.5) + Kirigami.OverlayDrawer { + id: aboutDrawer + edge: Qt.BottomEdge + contentItem: Item { + Layout.fillWidth: true + implicitHeight: columnLayoutInfo.text.height + Kirigami.Units.gridUnit - Legend { - id: legend - anchors.fill: parent - visible: !infoItem.minimized + ColumnLayout { + id: columnLayoutAbout + property alias text: flickableAbout.text + anchors.fill: parent + Flickable { + id: flickableAbout + property alias text: aboutText + anchors.fill: parent + contentWidth: aboutText.width + contentHeight: aboutText.height + flickableDirection: Flickable.VerticalFlick + clip: true + Text { + id: aboutText + anchors { + margins: Screen.pixelDensity * 2 + topMargin: Screen.pixelDensity * 14 + } + text: qsTr("

Germanisches Nationalmuseum

\ +

The original Behaim globe can be visited in the + Germanisches Nationalmuseum in Nuremberg, Germany.

\ +

KDE Marble

\ +

This app is part of the Marble project.\ + The Marble community works on maps and virtual globes with the goal to produce visually appealing, easy-to-use Free Software.

\ +

Map Content

\ +

Digitized map based on orthophotographic gores by TU Vienna, 1990. Germanisches Nationalmuseum and\ + Friedrich-Alexander-Universität Erlangen-Nürnberg, CC BY-SA 3.0.\ + Ghillany map based on two planiglobes which are provided as a map supplement\ + to F.W. Ghillany's \"Geschichte des Seefahrers Ritter Martin Behaim nach den ältesten vorhandenen Urkunden\",\ + Nuremberg 1853. CC BY-SA 3.0.

") + width: columnLayoutAbout.width + wrapMode: Text.WordWrap + onLinkActivated: Qt.openUrlExternally(link) + } + } + + } } } } } + + diff --git a/src/apps/behaim/package/deploy-behaim.json.in b/src/apps/behaim/package/deploy-behaim.json.in index 707c05e16..ffda99504 100644 --- a/src/apps/behaim/package/deploy-behaim.json.in +++ b/src/apps/behaim/package/deploy-behaim.json.in @@ -1,16 +1,18 @@ { "description": "This file is to be read by androiddeployqt", "qt": "@QT_ANDROID_QT_ROOT@", "sdk": "@ANDROID_SDK_ROOT@", "ndk": "@ANDROID_NDK_ROOT@", "toolchain-prefix": "@ANDROID_TOOLCHAIN@", "tool-prefix": "@ANDROID_TOOLCHAIN@", "toolchain-version": "@ANDROID_GCC_VERSION@", "ndk-host": "@_HOST@", "target-architecture": "@ANDROID_ABI@", "application-binary": "@QT_ANDROID_APP_PATH@", "android-package": "@QT_ANDROID_APP_PACKAGE_NAME@", "android-app-name": "@QT_ANDROID_APP_NAME@", "android-extra-libs": "@QT_ANDROID_APP_EXTRA_LIBS@", + "qml-root-path": "@QML_ROOT_PATH@", + "android-extra-plugins": "@QT_ANDROID_APP_EXTRA_PLUGINS@", "android-package-source-directory": "@QT_ANDROID_APP_PACKAGE_SOURCE_ROOT@" } diff --git a/src/apps/marble-maps/Bookmarks.qml b/src/apps/marble-maps/Bookmarks.qml new file mode 100644 index 000000000..a99c3d677 --- /dev/null +++ b/src/apps/marble-maps/Bookmarks.qml @@ -0,0 +1,245 @@ +// +// 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 + Drag.hotSpot.y: 50 + 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 + } +} 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 3205f9806..02b736eaa 100644 --- a/src/apps/marble-maps/MainScreen.qml +++ b/src/apps/marble-maps/MainScreen.qml @@ -1,576 +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: "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 index 9e35f32ec..8e236777b 100644 --- a/src/apps/marble-maps/MarbleMaps.qrc +++ b/src/apps/marble-maps/MarbleMaps.qrc @@ -1,94 +1,97 @@ 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 diff --git a/src/apps/marble-maps/Options.qml b/src/apps/marble-maps/Options.qml new file mode 100644 index 000000000..4585ee487 --- /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 index a31f3a44c..f55e9f062 100644 --- a/src/apps/marble-maps/PlacemarkDialog.qml +++ b/src/apps/marble-maps/PlacemarkDialog.qml @@ -1,209 +1,185 @@ // // 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.kirigami 2.0 as Kirigami + 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 + Kirigami.OverlaySheet { + id: routesDialog + ColumnLayout { + property int implicitWidth: root.width + 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 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); } } } diff --git a/src/apps/marble-maps/material-icons/ic_drag_handle_black_48dp.png b/src/apps/marble-maps/material-icons/ic_drag_handle_black_48dp.png new file mode 100644 index 000000000..b1fc31d5a Binary files /dev/null and b/src/apps/marble-maps/material-icons/ic_drag_handle_black_48dp.png differ