[Qt] Remove the QML app

We are now on Qt 5.9 and this is where the plugin will be developed
from now on.
This commit is contained in:
Thiago Marcos P. Santos
2017-03-04 09:06:04 -08:00
committed by Thiago Marcos P. Santos
parent b5d0a661c5
commit 2b7319d529
14 changed files with 3 additions and 1322 deletions

View File

@@ -189,7 +189,6 @@ matrix:
- mapbox_export_mesa_library_path
script:
- make qt-app
- make qt-qml-app
- make qt-test
- make qt-docs
- scripts/valgrind.sh build/qt-linux-x86_64/Release/mbgl-test --gtest_filter=-*.Load --gtest_filter=-Memory.Vector

View File

@@ -405,7 +405,6 @@ $(MACOS_QT_PROJ_PATH): $(BUILD_DEPS)
@# Create Xcode schemes so that we can use xcodebuild from the command line. CMake doesn't
@# create these automatically.
XCODEPROJ=$(MACOS_QT_PROJ_PATH) SCHEME_NAME=mbgl-qt SCHEME_TYPE=executable platform/macos/scripts/create_scheme.sh
XCODEPROJ=$(MACOS_QT_PROJ_PATH) SCHEME_NAME=mbgl-qt-qml SCHEME_TYPE=executable platform/macos/scripts/create_scheme.sh
XCODEPROJ=$(MACOS_QT_PROJ_PATH) SCHEME_NAME=mbgl-test SCHEME_TYPE=executable platform/macos/scripts/create_scheme.sh
XCODEPROJ=$(MACOS_QT_PROJ_PATH) SCHEME_NAME=mbgl-benchmark SCHEME_TYPE=executable platform/macos/scripts/create_scheme.sh
XCODEPROJ=$(MACOS_QT_PROJ_PATH) SCHEME_NAME=mbgl-core SCHEME_TYPE=library BUILDABLE_NAME=libmbgl-core.a BLUEPRINT_NAME=mbgl-core platform/macos/scripts/create_scheme.sh
@@ -429,14 +428,6 @@ qt-app: $(QT_BUILD)
run-qt-app: qt-app
$(QT_OUTPUT_PATH)/mbgl-qt
.PHONY: qt-qml-app
qt-qml-app: $(QT_BUILD)
$(NINJA) $(NINJA_ARGS) -j$(JOBS) -C $(QT_OUTPUT_PATH) mbgl-qt-qml
.PHONY: run-qt-qml-app
run-qt-qml-app: qt-qml-app
$(QT_OUTPUT_PATH)/mbgl-qt-qml
.PHONY: qt-test
qt-test: $(QT_BUILD)
$(NINJA) $(NINJA_ARGS) -j$(JOBS) -C $(QT_OUTPUT_PATH) mbgl-test

View File

@@ -3,43 +3,10 @@
[![Travis](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds)
[![Bitrise](https://www.bitrise.io/app/96cfbc97e0245c22.svg?token=GxsqIOGPXhn0F23sSVSsYA&branch=master)](https://www.bitrise.io/app/96cfbc97e0245c22)
Provides [Qt](http://www.qt.io/) example applications and APIs via `QMapboxGL`
and `QQuickMapboxGL`:
**QMapboxGL** - implements a C++03x-conformant API that has been tested from Qt
4.7 onwards (Travis CI currently builds it using both Qt 4 and Qt 5).
**QQuickMapboxGL** - implements a Qt Quick (QML) item that can be added to a
scene. Because `QQuickFramebufferObject` has been added in Qt version 5.2, we
support this API from this version onwards.
![Mapbox Qt QML
example](https://c2.staticflickr.com/8/7689/26247088394_01541b34de_o.png)
### Developing
[Qt supports many platforms](https://www.qt.io/qt-framework/#section-4) - so far
we have been testing our code on Linux and macOS desktops, as well as embedded
devices such as Raspberry Pi 3.
If you need to maintain backwards compatibility with prior releases of
Qt, chose `QMapboxGL`. Otherwise, go for `QQuickMapboxGL`.
Both `QMapboxGL` and `QQuickMapboxGL` requires a [Mapbox access
token](https://www.mapbox.com/help/define-access-token/) at runtime - you need
to provide it by setting the environment variable `MAPBOX_ACCESS_TOKEN`:
export MAPBOX_ACCESS_TOKEN=MYTOKEN
Optionally, you can specify a custom style to the QMapboxGL example application:
export MAPBOX_STYLE_URL=MYSTYLEURL
#### Using QMapboxGL
`QMapboxGL` is a [QObject](http://doc.qt.io/qt-5/qobject.html) - [MapWindow](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/qt/app/mapwindow.hpp) provides an example [QGLWidget](http://doc.qt.io/qt-5/qglwidget.html) that contains a `QMapboxGL` object. If you use `QMapboxGL` in non-standard Qt widgets, make sure to initialize the GL extensions required by Mapbox whenever possible:
QMapbox::initializeGLExtensions();
This is the foundation for the Mapbox GL plugin available since Qt 5.9. Use the Qt bugtracker
for bugs related to the plugin and this GitHub repository for bugs related to Mapbox GL Native.
#### Linux
@@ -47,9 +14,7 @@ For Linux (Ubuntu) desktop, together with these [build
instructions](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/linux#build),
you also need:
sudo apt-get install qt5-default qtlocation5-dev qtpositioning5-dev \
qml-module-qtquick2 qml-module-qtpositioning qml-module-qtgraphicaleffects \
qml-module-qtquick-layouts qml-module-qtquick-controls
sudo apt-get install qt5-default
#### macOS
@@ -74,8 +39,3 @@ can be found in [platform/qt/include](https://github.com/mapbox/mapbox-gl-native
```make qt-app``` or ```make run-qt-app``` to run the application at the end of
build.
#### QQuickMapboxGL example application:
```make qt-qml-app``` or ```make run-qt-qml-app``` to run the application at the
end of build.

View File

@@ -39,7 +39,6 @@ workflows:
ln -s /usr/local/Cellar/qt5/$HOMEBREW_QT5_VERSION/plugins /usr/local/plugins
export BUILDTYPE=Debug
make qt-app
make qt-qml-app
make run-qt-test
- is_debug: 'yes'
- deploy-to-bitrise-io:

View File

@@ -1,176 +0,0 @@
#pragma once
#include "qmapbox.hpp"
#include "qmapboxgl.hpp"
#include "qquickmapboxglmapparameter.hpp"
#include <QColor>
#include <QGeoCoordinate>
#include <QGeoServiceProvider>
#include <QGeoShape>
#include <QImage>
#include <QPointF>
#include <QQmlListProperty>
#include <QQuickFramebufferObject>
#include <QQuickItem>
class QDeclarativeGeoServiceProvider;
class QQuickMapboxGLRenderer;
class Q_DECL_EXPORT QQuickMapboxGL : public QQuickFramebufferObject
{
Q_OBJECT
// Map QML Type interface.
Q_ENUMS(QGeoServiceProvider::Error)
Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
Q_PROPERTY(qreal minimumZoomLevel READ minimumZoomLevel WRITE setMinimumZoomLevel NOTIFY minimumZoomLevelChanged)
Q_PROPERTY(qreal maximumZoomLevel READ maximumZoomLevel WRITE setMaximumZoomLevel NOTIFY maximumZoomLevelChanged)
Q_PROPERTY(qreal zoomLevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged)
Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged)
Q_PROPERTY(QGeoServiceProvider::Error error READ error NOTIFY errorChanged)
Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
Q_PROPERTY(QGeoShape visibleRegion READ visibleRegion WRITE setVisibleRegion)
Q_PROPERTY(bool copyrightsVisible READ copyrightsVisible WRITE setCopyrightsVisible NOTIFY copyrightsVisibleChanged)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
// Proposed Qt interface - based on the example documentation below:
// http://doc.qt.io/qt-5/qtqml-referenceexamples-properties-example.html
Q_PROPERTY(QQmlListProperty<QQuickMapboxGLMapParameter> parameters READ parameters)
public:
QQuickMapboxGL(QQuickItem *parent = 0);
virtual ~QQuickMapboxGL();
// QQuickFramebufferObject implementation.
virtual Renderer *createRenderer() const Q_DECL_FINAL;
// Map QML Type interface implementation.
void setPlugin(QDeclarativeGeoServiceProvider *plugin);
QDeclarativeGeoServiceProvider *plugin() const;
void setMinimumZoomLevel(qreal minimumZoomLevel);
qreal minimumZoomLevel() const;
void setMaximumZoomLevel(qreal maximumZoomLevel);
qreal maximumZoomLevel() const;
void setZoomLevel(qreal zoomLevel);
qreal zoomLevel() const;
QGeoCoordinate center() const;
QGeoServiceProvider::Error error() const;
QString errorString() const;
void setVisibleRegion(const QGeoShape &shape);
QGeoShape visibleRegion() const;
void setCopyrightsVisible(bool visible);
bool copyrightsVisible() const;
void setColor(const QColor &color);
QColor color() const;
Q_INVOKABLE void pan(int dx, int dy);
// Proposed Qt interface implementation.
QQmlListProperty<QQuickMapboxGLMapParameter> parameters();
protected:
// QQmlParserStatus implementation
void componentComplete() override;
signals:
// Map QML Type signals.
void minimumZoomLevelChanged();
void maximumZoomLevelChanged();
void zoomLevelChanged(qreal zoomLevel);
void centerChanged(const QGeoCoordinate &coordinate);
void colorChanged(const QColor &color);
void errorChanged();
// Compatibility with Map QML Type, but no-op.
void pluginChanged(QDeclarativeGeoServiceProvider *plugin);
void copyrightLinkActivated(const QString &link);
void copyrightsVisibleChanged(bool visible);
public slots:
void setCenter(const QGeoCoordinate &center);
private slots:
void onMapChanged(QMapboxGL::MapChange);
void onParameterPropertyUpdated(const QString &name);
private:
static void appendParameter(QQmlListProperty<QQuickMapboxGLMapParameter> *prop, QQuickMapboxGLMapParameter *mapObject);
static int countParameters(QQmlListProperty<QQuickMapboxGLMapParameter> *prop);
static QQuickMapboxGLMapParameter *parameterAt(QQmlListProperty<QQuickMapboxGLMapParameter> *prop, int index);
static void clearParameter(QQmlListProperty<QQuickMapboxGLMapParameter> *prop);
enum SyncState {
NothingNeedsSync = 0,
ZoomNeedsSync = 1 << 0,
CenterNeedsSync = 1 << 1,
StyleNeedsSync = 1 << 2,
PanNeedsSync = 1 << 3,
BearingNeedsSync = 1 << 4,
PitchNeedsSync = 1 << 5,
};
struct Image {
QString name;
QImage sprite;
};
struct StyleProperty {
enum Type {
Paint = 0,
Layout
};
Type type;
QString layer;
QString property;
QVariant value;
QString klass;
};
void processMapParameter(QQuickMapboxGLMapParameter *);
bool parseImage(QQuickMapboxGLMapParameter *);
bool parseStyle(QQuickMapboxGLMapParameter *);
bool parseStyleProperty(QQuickMapboxGLMapParameter *, const QString &name);
bool parseStyleLayer(QQuickMapboxGLMapParameter *);
bool parseStyleSource(QQuickMapboxGLMapParameter *);
bool parseStyleFilter(QQuickMapboxGLMapParameter *);
bool parseBearing(QQuickMapboxGLMapParameter *);
bool parsePitch(QQuickMapboxGLMapParameter *);
qreal m_minimumZoomLevel = 0;
qreal m_maximumZoomLevel = 20;
qreal m_zoomLevel = 20;
QPointF m_pan;
QGeoCoordinate m_center;
QGeoShape m_visibleRegion;
QColor m_color;
QString m_styleUrl;
QList<Image> m_imageChanges;
QList<StyleProperty> m_stylePropertyChanges;
QList<QVariantMap> m_layerChanges;
QList<QVariantMap> m_sourceChanges;
QList<QVariantMap> m_filterChanges;
QList<QQuickMapboxGLMapParameter*> m_parameters;
QGeoServiceProvider::Error m_error = QGeoServiceProvider::NoError;
QString m_errorString;
qreal m_bearing = 0;
qreal m_pitch = 0;
int m_syncState = NothingNeedsSync;
bool m_styleLoaded = false;
friend class QQuickMapboxGLRenderer;
};

View File

@@ -1,34 +0,0 @@
#pragma once
#include <QObject>
#include <QQmlParserStatus>
#include <QString>
#include <qqml.h>
class Q_DECL_EXPORT QQuickMapboxGLMapParameter : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
public:
QQuickMapboxGLMapParameter(QObject *parent = 0);
virtual ~QQuickMapboxGLMapParameter() {};
int propertyOffset() const { return m_metaPropertyOffset; }
signals:
void propertyUpdated(const QString &name);
protected:
// QQmlParserStatus implementation
void classBegin() override {}
void componentComplete() override;
private slots:
void onPropertyUpdated(int index);
private:
int m_metaPropertyOffset;
};
QML_DECLARE_TYPE(QQuickMapboxGLMapParameter)

View File

@@ -1,24 +0,0 @@
#include <QQuickMapboxGL>
#include <QQuickMapboxGLMapParameter>
#include <QGuiApplication>
#include <QIcon>
#include <QQmlApplicationEngine>
#include <qqml.h>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
#if QT_VERSION >= 0x050300
app.setWindowIcon(QIcon(":icon.png"));
#endif
qmlRegisterType<QQuickMapboxGL>("QQuickMapboxGL", 1, 0, "MapboxMap");
qmlRegisterType<QQuickMapboxGLMapParameter>("QQuickMapboxGL", 1, 0, "MapParameter");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}

View File

@@ -1,347 +0,0 @@
import QtGraphicalEffects 1.0
import QtPositioning 5.0
import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Dialogs 1.0
import QtQuick.Layouts 1.0
import QQuickMapboxGL 1.0
ApplicationWindow {
title: "Mapbox GL QML example"
width: 1024
height: 768
visible: true
MapboxMap {
id: map
anchors.fill: parent
parameters: [
MapParameter {
id: style
property var type: "style"
property var url: "mapbox://styles/mapbox/streets-v9"
},
MapParameter {
id: waterPaint
property var type: "paint"
property var layer: "water"
property var fillColor: waterColorDialog.color
},
MapParameter {
id: source
property var type: "source"
property var name: "routeSource"
property var sourceType: "geojson"
property var data: ":source1.geojson"
},
MapParameter {
property var type: "layer"
property var name: "routeCase"
property var layerType: "line"
property var source: "routeSource"
},
MapParameter {
property var type: "paint"
property var layer: "routeCase"
property var lineColor: "white"
property var lineWidth: 20.0
},
MapParameter {
property var type: "layout"
property var layer: "routeCase"
property var lineJoin: "round"
property var lineCap: lineJoin
property var visibility: toggleRoute.checked ? "visible" : "none"
},
MapParameter {
property var type: "layer"
property var name: "route"
property var layerType: "line"
property var source: "routeSource"
},
MapParameter {
id: linePaint
property var type: "paint"
property var layer: "route"
property var lineColor: "blue"
property var lineWidth: 8.0
},
MapParameter {
property var type: "layout"
property var layer: "route"
property var lineJoin: "round"
property var lineCap: "round"
property var visibility: toggleRoute.checked ? "visible" : "none"
},
MapParameter {
property var type: "image"
property var name: "label-arrow"
property var sprite: ":label-arrow.svg"
},
MapParameter {
property var type: "image"
property var name: "label-background"
property var sprite: ":label-background.svg"
},
MapParameter {
property var type: "layer"
property var name: "markerArrow"
property var layerType: "symbol"
property var source: "routeSource"
},
MapParameter {
property var type: "layout"
property var layer: "markerArrow"
property var iconImage: "label-arrow"
property var iconSize: 0.5
property var iconIgnorePlacement: true
property var iconOffset: [ 0.0, -15.0 ]
property var visibility: toggleRoute.checked ? "visible" : "none"
},
MapParameter {
property var type: "layer"
property var name: "markerBackground"
property var layerType: "symbol"
property var source: "routeSource"
},
MapParameter {
property var type: "layout"
property var layer: "markerBackground"
property var iconImage: "label-background"
property var textField: "{name}"
property var iconTextFit: "both"
property var iconIgnorePlacement: true
property var textIgnorePlacement: true
property var textAnchor: "left"
property var textSize: 16.0
property var textPadding: 0.0
property var textLineHeight: 1.0
property var textMaxWidth: 8.0
property var iconTextFitPadding: [ 15.0, 10.0, 15.0, 10.0 ]
property var textOffset: [ -0.5, -1.5 ]
property var visibility: toggleRoute.checked ? "visible" : "none"
},
MapParameter {
property var type: "paint"
property var layer: "markerBackground"
property var textColor: "white"
},
MapParameter {
property var type: "filter"
property var layer: "markerArrow"
property var filter: [ "==", "$type", "Point" ]
},
MapParameter {
property var type: "filter"
property var layer: "markerBackground"
property var filter: [ "==", "$type", "Point" ]
},
MapParameter {
property var type: "bearing"
property var angle: bearingSlider.value
},
MapParameter {
property var type: "pitch"
property var angle: pitchSlider.value
}
]
center: QtPositioning.coordinate(60.170448, 24.942046) // Helsinki
zoomLevel: 12.25
minimumZoomLevel: 0
maximumZoomLevel: 20
color: landColorDialog.color
copyrightsVisible: true
states: State {
name: "moved"; when: mouseArea.pressed
PropertyChanges { target: linePaint; lineColor: "red"; }
}
transitions: Transition {
ColorAnimation { properties: "lineColor"; easing.type: Easing.InOutQuad; duration: 500 }
}
Image {
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 20
opacity: .75
sourceSize.width: 80
sourceSize.height: 80
source: "icon.png"
}
MouseArea {
id: mouseArea
anchors.fill: parent
property var lastX: 0
property var lastY: 0
onWheel: map.zoomLevel += 0.2 * wheel.angleDelta.y / 120
onPressed: {
lastX = mouse.x
lastY = mouse.y
}
onPositionChanged: {
map.pan(mouse.x - lastX, mouse.y - lastY)
lastX = mouse.x
lastY = mouse.y
}
}
}
ColorDialog {
id: landColorDialog
title: "Land color"
color: "#e0ded8"
}
ColorDialog {
id: waterColorDialog
title: "Water color"
color: "#63c5ee"
}
Rectangle {
anchors.fill: menu
anchors.margins: -20
radius: 30
clip: true
}
ColumnLayout {
id: menu
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 30
Label {
text: "Bearing:"
}
Slider {
id: bearingSlider
anchors.left: parent.left
anchors.right: parent.right
maximumValue: 180
}
Label {
text: "Pitch:"
}
Slider {
id: pitchSlider
anchors.left: parent.left
anchors.right: parent.right
maximumValue: 60
}
GroupBox {
anchors.left: parent.left
anchors.right: parent.right
title: "Style:"
ColumnLayout {
ExclusiveGroup { id: styleGroup }
RadioButton {
text: "Streets"
checked: true
exclusiveGroup: styleGroup
onClicked: {
style.url = "mapbox://styles/mapbox/streets-v9"
landColorDialog.color = "#e0ded8"
waterColorDialog.color = "#63c5ee"
}
}
RadioButton {
text: "Dark"
exclusiveGroup: styleGroup
onClicked: {
style.url = "mapbox://styles/mapbox/dark-v9"
landColorDialog.color = "#343332"
waterColorDialog.color = "#191a1a"
}
}
RadioButton {
text: "Satellite"
exclusiveGroup: styleGroup
onClicked: {
style.url = "mapbox://styles/mapbox/satellite-v9"
}
}
}
}
Button {
anchors.left: parent.left
anchors.right: parent.right
text: "Select land color"
onClicked: landColorDialog.open()
}
Button {
anchors.left: parent.left
anchors.right: parent.right
text: "Select water color"
onClicked: waterColorDialog.open()
}
GroupBox {
anchors.left: parent.left
anchors.right: parent.right
title: "Route:"
ColumnLayout {
ExclusiveGroup { id: sourceGroup }
RadioButton {
text: "Route 1"
checked: true
exclusiveGroup: sourceGroup
onClicked: {
source.data = ":source1.geojson"
}
}
RadioButton {
text: "Route 2"
exclusiveGroup: sourceGroup
onClicked: {
source.data = ":source2.geojson"
}
}
RadioButton {
text: "Route 3"
exclusiveGroup: sourceGroup
onClicked: {
source.data = '{ "type": "FeatureCollection", "features": \
[{ "type": "Feature", "properties": {}, "geometry": { \
"type": "LineString", "coordinates": [[ 24.934938848018646, \
60.16830257086771 ], [ 24.943315386772156, 60.16227776476442 ]]}}]}'
}
}
}
}
CheckBox {
id: toggleRoute
anchors.left: parent.left
anchors.right: parent.right
text: "Toggle route"
checked: true
}
}
}

View File

@@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
</qresource>
</RCC>

View File

@@ -3,7 +3,6 @@ find_package(Qt5Gui REQUIRED)
find_package(Qt5Location REQUIRED)
find_package(Qt5Network REQUIRED)
find_package(Qt5OpenGL REQUIRED)
find_package(Qt5Quick REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Sql REQUIRED)
@@ -21,21 +20,11 @@ set(MBGL_QT_TEST_LIBRARIES
PRIVATE Qt5::OpenGL
)
target_sources(qmapboxgl
PRIVATE platform/qt/include/qquickmapboxgl.hpp
PRIVATE platform/qt/include/qquickmapboxglmapparameter.hpp
PRIVATE platform/qt/src/qquickmapboxgl.cpp
PRIVATE platform/qt/src/qquickmapboxglmapparameter.cpp
PRIVATE platform/qt/src/qquickmapboxglrenderer.cpp
PRIVATE platform/qt/src/qquickmapboxglrenderer.hpp
)
target_link_libraries(qmapboxgl
PRIVATE mbgl-core
PRIVATE Qt5::Core
PRIVATE Qt5::Gui
PRIVATE Qt5::Location
PRIVATE Qt5::Quick
PRIVATE Qt5::Sql
)
@@ -44,16 +33,3 @@ target_link_libraries(mbgl-qt
PRIVATE Qt5::OpenGL
PRIVATE Qt5::Widgets
)
# QtQuick app
add_executable(mbgl-qt-qml
platform/qt/qmlapp/main.cpp
platform/qt/qmlapp/qml.qrc
platform/qt/resources/common.qrc
)
target_link_libraries(mbgl-qt-qml
PRIVATE qmapboxgl
PRIVATE Qt5::Location
PRIVATE Qt5::Quick
)

View File

@@ -1,469 +0,0 @@
#include "qquickmapboxgl.hpp"
#include "qquickmapboxglmapparameter.hpp"
#include "qquickmapboxglrenderer.hpp"
#include <mbgl/util/constants.hpp>
#include <QDebug>
#include <QQuickItem>
#include <QRegularExpression>
#include <QString>
#include <QtGlobal>
#include <QQmlListProperty>
#include <QJSValue>
namespace {
static const QRegularExpression s_camelCase {"([a-z0-9])([A-Z])"};
static const QStringList s_parameterTypes = QStringList()
<< "style" << "paint" << "layout" << "layer" << "source" << "filter" << "image"
<< "bearing" << "pitch";
} // namespace
QQuickMapboxGL::QQuickMapboxGL(QQuickItem *parent_)
: QQuickFramebufferObject(parent_)
{
}
QQuickMapboxGL::~QQuickMapboxGL()
{
}
QQuickFramebufferObject::Renderer *QQuickMapboxGL::createRenderer() const
{
return new QQuickMapboxGLRenderer;
}
void QQuickMapboxGL::setPlugin(QDeclarativeGeoServiceProvider *)
{
m_error = QGeoServiceProvider::NotSupportedError;
m_errorString = "QQuickMapboxGL does not support plugins.";
emit errorChanged();
}
QDeclarativeGeoServiceProvider *QQuickMapboxGL::plugin() const
{
return nullptr;
}
void QQuickMapboxGL::componentComplete()
{
QQuickFramebufferObject::componentComplete();
for (const auto& param : m_parameters) {
processMapParameter(param);
}
}
void QQuickMapboxGL::setMinimumZoomLevel(qreal zoom)
{
zoom = qMax(mbgl::util::MIN_ZOOM, zoom);
zoom = qMin(m_maximumZoomLevel, zoom);
if (m_minimumZoomLevel == zoom) {
return;
}
m_minimumZoomLevel = zoom;
setZoomLevel(m_zoomLevel); // Constrain.
emit minimumZoomLevelChanged();
}
qreal QQuickMapboxGL::minimumZoomLevel() const
{
return m_minimumZoomLevel;
}
void QQuickMapboxGL::setMaximumZoomLevel(qreal zoom)
{
zoom = qMin(mbgl::util::MAX_ZOOM, zoom);
zoom = qMax(m_minimumZoomLevel, zoom);
if (m_maximumZoomLevel == zoom) {
return;
}
m_maximumZoomLevel = zoom;
setZoomLevel(m_zoomLevel); // Constrain.
emit maximumZoomLevelChanged();
}
qreal QQuickMapboxGL::maximumZoomLevel() const
{
return m_maximumZoomLevel;
}
void QQuickMapboxGL::setZoomLevel(qreal zoom)
{
zoom = qMin(m_maximumZoomLevel, zoom);
zoom = qMax(m_minimumZoomLevel, zoom);
if (m_zoomLevel == zoom) {
return;
}
m_zoomLevel = zoom;
m_syncState |= ZoomNeedsSync;
update();
emit zoomLevelChanged(m_zoomLevel);
}
qreal QQuickMapboxGL::zoomLevel() const
{
return m_zoomLevel;
}
void QQuickMapboxGL::setCenter(const QGeoCoordinate &coordinate)
{
if (m_center == coordinate) {
return;
}
m_center = coordinate;
m_syncState |= CenterNeedsSync;
update();
emit centerChanged(m_center);
}
QGeoCoordinate QQuickMapboxGL::center() const
{
return m_center;
}
QGeoServiceProvider::Error QQuickMapboxGL::error() const
{
return m_error;
}
QString QQuickMapboxGL::errorString() const
{
return m_errorString;
}
void QQuickMapboxGL::setVisibleRegion(const QGeoShape &shape)
{
m_visibleRegion = shape;
}
QGeoShape QQuickMapboxGL::visibleRegion() const
{
return m_visibleRegion;
}
void QQuickMapboxGL::setCopyrightsVisible(bool)
{
qWarning() << Q_FUNC_INFO << "Not implemented.";
}
bool QQuickMapboxGL::copyrightsVisible() const
{
return false;
}
void QQuickMapboxGL::setColor(const QColor &color)
{
if (m_color == color) {
return;
}
m_color = color;
StyleProperty change;
change.type = StyleProperty::Paint;
change.layer = "background";
change.property = "background-color";
change.value = color;
m_stylePropertyChanges << change;
update();
emit colorChanged(m_color);
}
QColor QQuickMapboxGL::color() const
{
return m_color;
}
void QQuickMapboxGL::pan(int dx, int dy)
{
m_pan += QPointF(dx, -dy);
m_syncState |= PanNeedsSync;
update();
}
void QQuickMapboxGL::onMapChanged(QMapboxGL::MapChange change)
{
if (change == QMapboxGL::MapChangeDidFinishLoadingStyle) {
m_styleLoaded = true;
update();
}
}
bool QQuickMapboxGL::parseImage(QQuickMapboxGLMapParameter *param)
{
m_imageChanges << Image {
param->property("name").toString(),
QImage(param->property("sprite").toString())
};
return true;
}
bool QQuickMapboxGL::parseStyle(QQuickMapboxGLMapParameter *param)
{
QString url = param->property("url").toString();
if (m_styleUrl == url) {
return false;
}
// Reload parameters if switching style URLs.
if (!m_styleUrl.isEmpty()) {
for (const auto& param_ : m_parameters) {
if (param_->property("type").toString() == "style") continue;
processMapParameter(param_);
}
}
m_styleUrl = url;
m_styleLoaded = false;
m_syncState |= StyleNeedsSync;
return true;
}
bool QQuickMapboxGL::parseStyleProperty(QQuickMapboxGLMapParameter *param, const QString &name)
{
// Ignore meta-properties "type", "layer" and "class".
if (name == "type" || name == "layer" || name == "class") {
return false;
}
QString formattedName(name);
formattedName = formattedName.replace(s_camelCase, "\\1-\\2").toLower();
QVariant value = param->property(name.toLatin1());
if (value.canConvert<QJSValue>()) {
value = value.value<QJSValue>().toVariant();
}
m_stylePropertyChanges << QQuickMapboxGL::StyleProperty {
param->property("type").toString().at(0) == 'p' ? StyleProperty::Paint : StyleProperty::Layout,
param->property("layer").toString(),
formattedName,
value,
param->property("class").toString()
};
return true;
}
bool QQuickMapboxGL::parseStyleLayer(QQuickMapboxGLMapParameter *param)
{
QVariantMap layer;
layer["id"] = param->property("name");
layer["source"] = param->property("source");
layer["type"] = param->property("layerType");
if (param->property("sourceLayer").isValid()) {
layer["source-layer"] = param->property("sourceLayer");
}
m_layerChanges << layer;
return true;
}
bool QQuickMapboxGL::parseStyleSource(QQuickMapboxGLMapParameter *param)
{
QString sourceType = param->property("sourceType").toString();
QVariantMap source;
source["id"] = param->property("name");
source["type"] = sourceType;
if (sourceType == "vector" || sourceType == "raster") {
source["url"] = param->property("url");
m_sourceChanges << source;
} else if (sourceType == "geojson") {
auto data = param->property("data").toString();
if (data.startsWith(':')) {
QFile geojson(data);
geojson.open(QIODevice::ReadOnly);
source["data"] = geojson.readAll();
} else {
source["data"] = data.toUtf8();
}
m_sourceChanges << source;
} else {
m_error = QGeoServiceProvider::UnknownParameterError;
m_errorString = "Invalid source type: " + sourceType;
emit errorChanged();
return false;
}
return true;
}
bool QQuickMapboxGL::parseStyleFilter(QQuickMapboxGLMapParameter *param)
{
QVariantMap filter;
filter["layer"] = param->property("layer");
filter["filter"] = param->property("filter");
m_filterChanges << filter;
return true;
}
bool QQuickMapboxGL::parseBearing(QQuickMapboxGLMapParameter *param)
{
qreal angle = param->property("angle").toReal();
if (m_bearing == angle) return false;
m_bearing = angle;
m_syncState |= BearingNeedsSync;
update();
return true;
}
bool QQuickMapboxGL::parsePitch(QQuickMapboxGLMapParameter *param)
{
qreal angle = param->property("angle").toReal();
angle = qMin(qMax(0., angle), mbgl::util::PITCH_MAX * mbgl::util::RAD2DEG);
if (m_pitch == angle) return false;
m_pitch = angle;
m_syncState |= PitchNeedsSync;
update();
return true;
}
void QQuickMapboxGL::processMapParameter(QQuickMapboxGLMapParameter *param)
{
bool needsUpdate = false;
switch (s_parameterTypes.indexOf(param->property("type").toString())) {
case -1:
m_error = QGeoServiceProvider::UnknownParameterError;
m_errorString = "Invalid value for property 'type': " + param->property("type").toString();
emit errorChanged();
break;
case 0: // style
needsUpdate |= parseStyle(param);
break;
case 1: // paint
case 2: // layout
for (int i = param->propertyOffset(); i < param->metaObject()->propertyCount(); ++i) {
needsUpdate |= parseStyleProperty(param, QString(param->metaObject()->property(i).name()));
}
break;
case 3: // layer
needsUpdate |= parseStyleLayer(param);
break;
case 4: // source
needsUpdate |= parseStyleSource(param);
break;
case 5: // filter
needsUpdate |= parseStyleFilter(param);
break;
case 6: // image
needsUpdate |= parseImage(param);
break;
case 7: // bearing
needsUpdate |= parseBearing(param);
break;
case 8: // pitch
needsUpdate |= parsePitch(param);
break;
}
if (needsUpdate) update();
}
void QQuickMapboxGL::onParameterPropertyUpdated(const QString &propertyName)
{
QQuickMapboxGLMapParameter *param = qobject_cast<QQuickMapboxGLMapParameter *>(sender());
if (!param) {
m_error = QGeoServiceProvider::NotSupportedError;
m_errorString = "QQuickMapboxGL::onParameterPropertyUpdated should be called from a QQuickMapboxGLMapParameter.";
emit errorChanged();
return;
}
if (propertyName == "type") {
m_error = QGeoServiceProvider::NotSupportedError;
m_errorString = "Property 'type' is a write-once.";
emit errorChanged();
return;
}
bool needsUpdate = false;
switch (s_parameterTypes.indexOf(param->property("type").toString())) {
case -1:
m_error = QGeoServiceProvider::UnknownParameterError;
m_errorString = "Invalid value for property 'type': " + param->property("type").toString();
emit errorChanged();
break;
case 0: // style
needsUpdate |= parseStyle(param);
break;
case 1: // paint
case 2: // layout
needsUpdate |= parseStyleProperty(param, propertyName);
break;
case 3: // layer
needsUpdate |= parseStyleLayer(param);
break;
case 4: // source
needsUpdate |= parseStyleSource(param);
break;
case 5: // filter
needsUpdate |= parseStyleFilter(param);
break;
case 6: // image
needsUpdate |= parseImage(param);
break;
case 7: // bearing
needsUpdate |= parseBearing(param);
break;
case 8: // pitch
needsUpdate |= parsePitch(param);
break;
}
if (needsUpdate) update();
}
void QQuickMapboxGL::appendParameter(QQmlListProperty<QQuickMapboxGLMapParameter> *prop, QQuickMapboxGLMapParameter *param)
{
QQuickMapboxGL *map = static_cast<QQuickMapboxGL *>(prop->object);
map->m_parameters.append(param);
QObject::connect(param, SIGNAL(propertyUpdated(QString)), map, SLOT(onParameterPropertyUpdated(QString)));
}
int QQuickMapboxGL::countParameters(QQmlListProperty<QQuickMapboxGLMapParameter> *prop)
{
QQuickMapboxGL *map = static_cast<QQuickMapboxGL *>(prop->object);
return map->m_parameters.count();
}
QQuickMapboxGLMapParameter *QQuickMapboxGL::parameterAt(QQmlListProperty<QQuickMapboxGLMapParameter> *prop, int index)
{
QQuickMapboxGL *map = static_cast<QQuickMapboxGL *>(prop->object);
return map->m_parameters[index];
}
void QQuickMapboxGL::clearParameter(QQmlListProperty<QQuickMapboxGLMapParameter> *prop)
{
QQuickMapboxGL *map = static_cast<QQuickMapboxGL *>(prop->object);
for (auto param : map->m_parameters) {
QObject::disconnect(param, SIGNAL(propertyUpdated(QString)), map, SLOT(onParameterPropertyUpdated(QString)));
}
map->m_parameters.clear();
}
QQmlListProperty<QQuickMapboxGLMapParameter> QQuickMapboxGL::parameters()
{
return QQmlListProperty<QQuickMapboxGLMapParameter>(this,
nullptr,
appendParameter,
countParameters,
parameterAt,
clearParameter);
}

View File

@@ -1,35 +0,0 @@
#include "qquickmapboxglmapparameter.hpp"
#include <QByteArray>
#include <QMetaObject>
#include <QMetaProperty>
#include <QSignalMapper>
QQuickMapboxGLMapParameter::QQuickMapboxGLMapParameter(QObject *parent)
: QObject(parent)
, m_metaPropertyOffset(metaObject()->propertyCount())
{
}
void QQuickMapboxGLMapParameter::componentComplete()
{
for (int i = m_metaPropertyOffset; i < metaObject()->propertyCount(); ++i) {
QMetaProperty property = metaObject()->property(i);
if (!property.hasNotifySignal()) {
return;
}
auto mapper = new QSignalMapper(this);
mapper->setMapping(this, i);
const QByteArray signalName = '2' + property.notifySignal().methodSignature();
QObject::connect(this, signalName, mapper, SLOT(map()));
QObject::connect(mapper, SIGNAL(mapped(int)), this, SLOT(onPropertyUpdated(int)));
}
}
void QQuickMapboxGLMapParameter::onPropertyUpdated(int index)
{
emit propertyUpdated(metaObject()->property(index).name());
}

View File

@@ -1,120 +0,0 @@
#include "qquickmapboxglrenderer.hpp"
#include "qmapboxgl.hpp"
#include "qquickmapboxgl.hpp"
#include <QSize>
#include <QOpenGLFramebufferObject>
#include <QOpenGLFramebufferObjectFormat>
#include <QQuickWindow>
#include <QThread>
QQuickMapboxGLRenderer::QQuickMapboxGLRenderer()
{
QMapbox::initializeGLExtensions();
QMapboxGLSettings settings;
settings.setAccessToken(qgetenv("MAPBOX_ACCESS_TOKEN"));
settings.setCacheDatabasePath("/tmp/mbgl-cache.db");
settings.setCacheDatabaseMaximumSize(20 * 1024 * 1024);
settings.setViewportMode(QMapboxGLSettings::FlippedYViewport);
m_map.reset(new QMapboxGL(nullptr, settings, QSize(256, 256), 1));
}
QQuickMapboxGLRenderer::~QQuickMapboxGLRenderer()
{
}
QOpenGLFramebufferObject* QQuickMapboxGLRenderer::createFramebufferObject(const QSize &size)
{
m_map->resize(size / m_pixelRatio, size);
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
return new QOpenGLFramebufferObject(size, format);
}
void QQuickMapboxGLRenderer::render()
{
framebufferObject()->bind();
m_map->render();
framebufferObject()->release();
}
void QQuickMapboxGLRenderer::synchronize(QQuickFramebufferObject *item)
{
auto quickMap = qobject_cast<QQuickMapboxGL*>(item);
if (!m_initialized) {
QObject::connect(m_map.data(), &QMapboxGL::needsRendering, quickMap, &QQuickMapboxGL::update);
QObject::connect(m_map.data(), SIGNAL(mapChanged(QMapboxGL::MapChange)), quickMap, SLOT(onMapChanged(QMapboxGL::MapChange)));
QObject::connect(this, &QQuickMapboxGLRenderer::centerChanged, quickMap, &QQuickMapboxGL::setCenter);
m_initialized = true;
}
if (auto window = quickMap->window()) {
m_pixelRatio = window->devicePixelRatio();
} else {
m_pixelRatio = 1;
}
auto syncStatus = quickMap->m_syncState;
quickMap->m_syncState = QQuickMapboxGL::NothingNeedsSync;
if (syncStatus & QQuickMapboxGL::CenterNeedsSync || syncStatus & QQuickMapboxGL::ZoomNeedsSync) {
const auto& center = quickMap->center();
m_map->setCoordinateZoom({ center.latitude(), center.longitude() }, quickMap->zoomLevel());
}
if (syncStatus & QQuickMapboxGL::StyleNeedsSync && !quickMap->m_styleUrl.isEmpty()) {
m_map->setStyleUrl(quickMap->m_styleUrl);
}
if (syncStatus & QQuickMapboxGL::PanNeedsSync) {
m_map->moveBy(quickMap->m_pan);
quickMap->m_pan = QPointF();
emit centerChanged(QGeoCoordinate(m_map->latitude(), m_map->longitude()));
}
if (syncStatus & QQuickMapboxGL::BearingNeedsSync) {
m_map->setBearing(quickMap->m_bearing);
}
if (syncStatus & QQuickMapboxGL::PitchNeedsSync) {
m_map->setPitch(quickMap->m_pitch);
}
if (!quickMap->m_styleLoaded) {
return;
}
for (const auto& change : quickMap->m_sourceChanges) {
m_map->updateSource(change.value("id").toString(), change);
}
quickMap->m_sourceChanges.clear();
for (const auto& change : quickMap->m_layerChanges) {
m_map->addLayer(change);
}
quickMap->m_layerChanges.clear();
for (const auto& change : quickMap->m_filterChanges) {
m_map->setFilter(change.value("layer").toString(), change.value("filter"));
}
quickMap->m_filterChanges.clear();
for (const auto& change : quickMap->m_imageChanges) {
m_map->addImage(change.name, change.sprite);
}
quickMap->m_imageChanges.clear();
for (const auto& change : quickMap->m_stylePropertyChanges) {
if (change.type == QQuickMapboxGL::StyleProperty::Paint) {
m_map->setPaintProperty(change.layer, change.property, change.value, change.klass);
} else {
m_map->setLayoutProperty(change.layer, change.property, change.value);
}
}
quickMap->m_stylePropertyChanges.clear();
}

View File

@@ -1,34 +0,0 @@
#pragma once
#include "qmapbox.hpp"
#include "qmapboxgl.hpp"
#include <QGeoCoordinate>
#include <QObject>
#include <QOpenGLFramebufferObject>
#include <QQuickFramebufferObject>
#include <QScopedPointer>
#include <QSize>
class QQuickMapboxGLRenderer : public QObject, public QQuickFramebufferObject::Renderer
{
Q_OBJECT
public:
QQuickMapboxGLRenderer();
virtual ~QQuickMapboxGLRenderer();
virtual QOpenGLFramebufferObject * createFramebufferObject(const QSize &);
virtual void render();
virtual void synchronize(QQuickFramebufferObject *);
signals:
void centerChanged(const QGeoCoordinate &);
private:
bool m_initialized = false;
qreal m_pixelRatio = 1;
QScopedPointer<QMapboxGL> m_map;
};