diff options
Diffstat (limited to 'src/location/quickmapitems/qdeclarativegeomapitembase.cpp')
-rw-r--r-- | src/location/quickmapitems/qdeclarativegeomapitembase.cpp | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/src/location/quickmapitems/qdeclarativegeomapitembase.cpp b/src/location/quickmapitems/qdeclarativegeomapitembase.cpp new file mode 100644 index 00000000..3767351c --- /dev/null +++ b/src/location/quickmapitems/qdeclarativegeomapitembase.cpp @@ -0,0 +1,337 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtLocation module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativegeomapitembase_p.h" +#include "qgeocameradata_p.h" + +#include <QtQml/QQmlInfo> +#include <QtQuick/QSGOpacityNode> + +#include <QtQuick/private/qquickmousearea_p.h> +#include <QtQuick/private/qquickitem_p.h> +#include <QtPositioning/private/qdoublevector2d_p.h> +#include <QtLocation/private/qgeomap_p.h> +#include <QtLocation/private/qgeoprojection_p.h> + +QT_BEGIN_NAMESPACE + +QDeclarativeGeoMapItemBase::QDeclarativeGeoMapItemBase(QQuickItem *parent) + : QQuickItem(parent) +{ + setFiltersChildMouseEvents(true); + connect(this, &QDeclarativeGeoMapItemBase::childrenChanged, + this, &QDeclarativeGeoMapItemBase::afterChildrenChanged); + // Changing opacity on a mapItemGroup should affect also the opacity on the children. + // This must be notified to plugins, if they are to render the item. + connect(this, &QQuickItem::opacityChanged, this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged); +} + +QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase() +{ + disconnect(this, &QDeclarativeGeoMapItemBase::childrenChanged, + this, &QDeclarativeGeoMapItemBase::afterChildrenChanged); + if (quickMap_) + quickMap_->removeMapItem(this); +} + +/*! + \internal +*/ +void QDeclarativeGeoMapItemBase::afterChildrenChanged() +{ + const QList<QQuickItem *> kids = childItems(); + if (kids.size() > 0) { + bool printedWarning = false; + for (auto *i : kids) { + if (i->flags() & QQuickItem::ItemHasContents + && !qobject_cast<QQuickMouseArea *>(i)) { + if (!printedWarning) { + qmlWarning(this) << "Geographic map items do not support child items"; + printedWarning = true; + } + + qmlWarning(i) << "deleting this child"; + i->deleteLater(); + } + } + } +} + +/*! + \internal +*/ +void QDeclarativeGeoMapItemBase::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) +{ + if (quickMap == quickMap_) + return; + if (quickMap && quickMap_) + return; // don't allow association to more than one map + + quickMap_ = quickMap; + map_ = map; + + if (map_ && quickMap_) { + // For performance reasons we're not connecting map_'s and quickMap_'s signals to this. + // Rather, the handling of cameraDataChanged, visibleAreaChanged, heightChanged and widthChanged is done explicitly in QDeclarativeGeoMap by directly calling methods on the items. + // See QTBUG-76950 + lastSize_ = QSizeF(quickMap_->width(), quickMap_->height()); + lastCameraData_ = map_->cameraData(); + } +} + +/*! + \internal +*/ +void QDeclarativeGeoMapItemBase::baseCameraDataChanged(const QGeoCameraData &cameraData) +{ + QGeoMapViewportChangeEvent evt; + evt.cameraData = cameraData; + evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height()); + + if (evt.mapSize != lastSize_) + evt.mapSizeChanged = true; + + if (cameraData.bearing() != lastCameraData_.bearing()) + evt.bearingChanged = true; + if (cameraData.center() != lastCameraData_.center()) + evt.centerChanged = true; + if (cameraData.roll() != lastCameraData_.roll()) + evt.rollChanged = true; + if (cameraData.tilt() != lastCameraData_.tilt()) + evt.tiltChanged = true; + if (cameraData.zoomLevel() != lastCameraData_.zoomLevel()) + evt.zoomLevelChanged = true; + + lastSize_ = evt.mapSize; + lastCameraData_ = cameraData; + + afterViewportChanged(evt); +} + +void QDeclarativeGeoMapItemBase::visibleAreaChanged() +{ + QGeoMapViewportChangeEvent evt; + evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height()); + afterViewportChanged(evt); +} + +/*! + \internal +*/ +void QDeclarativeGeoMapItemBase::setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset) +{ + if (!map_ || !quickMap_) + return; + + QDoubleVector2D pos; + if (map()->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) { + const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection()); + QDoubleVector2D wrappedProjection = p.geoToWrappedMapProjection(coordinate); + if (!p.isProjectable(wrappedProjection)) + return; + pos = p.wrappedMapProjectionToItemPosition(wrappedProjection); + } else { + pos = map()->geoProjection().coordinateToItemPosition(coordinate, false); + if (qIsNaN(pos.x())) + return; + } + + QPointF topLeft = pos.toPointF() - offset; + + setPosition(topLeft); +} + +bool QDeclarativeGeoMapItemBase::autoFadeIn() const +{ + return m_autoFadeIn; +} + +static const double opacityRampMin = 1.5; +static const double opacityRampMax = 2.5; + +void QDeclarativeGeoMapItemBase::setAutoFadeIn(bool fadeIn) +{ + if (fadeIn == m_autoFadeIn) + return; + m_autoFadeIn = fadeIn; + if (quickMap_ && quickMap_->zoomLevel() < opacityRampMax) + polishAndUpdate(); +} + +int QDeclarativeGeoMapItemBase::lodThreshold() const +{ + return m_lodThreshold; +} + +void QDeclarativeGeoMapItemBase::setLodThreshold(int lt) +{ + if (lt == m_lodThreshold) + return; + m_lodThreshold = lt; + update(); +} + +/*! + \internal + + This returns the zoom level to be used when requesting the LOD. + Essentially it clamps to m_lodThreshold, and if above, it selects + a ZL higher than the maximum LODable level. +*/ +unsigned int QDeclarativeGeoMapItemBase::zoomForLOD(int zoom) const +{ + if (zoom >= m_lodThreshold) + return 30; // some arbitrarily large zoom + return uint(zoom); +} + +/*! + \internal +*/ +float QDeclarativeGeoMapItemBase::zoomLevelOpacity() const +{ + if (!m_autoFadeIn) // Consider skipping the opacity node instead. + return 1.0; + else if (quickMap_->zoomLevel() > opacityRampMax) + return 1.0; + else if (quickMap_->zoomLevel() > opacityRampMin) + return quickMap_->zoomLevel() - opacityRampMin; + else + return 0.0; +} + +bool QDeclarativeGeoMapItemBase::childMouseEventFilter(QQuickItem *item, QEvent *event) +{ + Q_UNUSED(item); + if (event->type() == QEvent::MouseButtonPress && !contains(static_cast<QMouseEvent*>(event)->pos())) { + // In case of items that are not rectangles, this filter is used to test if the event has landed + // inside the actual item shape. + // If so, the method returns true, meaning that it prevents the event delivery to child "*item" (for example, + // a mouse area that is on top of this map item). + // However, this method sets "accepted" to false, so that the event can still be passed further up, + // specifically to the parent Map, that is a sort of flickable. + // Otherwise, if the event is not contained within the map item, the method returns false, meaning the event + // is delivered to the child *item (like the mouse area associated). + event->setAccepted(false); + return true; + } + return false; +} + +/*! + \internal +*/ +QSGNode *QDeclarativeGeoMapItemBase::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *pd) +{ + if (!map_ || !quickMap_ || map_->supportedMapItemTypes() & itemType()) { + if (oldNode) + delete oldNode; + oldNode = nullptr; + return nullptr; + } + + QSGOpacityNode *opn = static_cast<QSGOpacityNode *>(oldNode); + if (!opn) + opn = new QSGOpacityNode(); + + opn->setOpacity(zoomLevelOpacity()); + + QSGNode *oldN = opn->childCount() ? opn->firstChild() : 0; + opn->removeAllChildNodes(); + if (opn->opacity() > 0.0) { + QSGNode *n = this->updateMapItemPaintNode(oldN, pd); + if (n) + opn->appendChildNode(n); + } else { + delete oldN; + } + + return opn; +} + +/*! + \internal +*/ +QSGNode *QDeclarativeGeoMapItemBase::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +{ + delete oldNode; + return nullptr; +} + +QGeoMap::ItemType QDeclarativeGeoMapItemBase::itemType() const +{ + return m_itemType; +} + +/*! + \internal + + The actual combined opacity of the item. Needed by custom renderer to look like + the scene-graph one. +*/ +qreal QDeclarativeGeoMapItemBase::mapItemOpacity() const +{ + if (parentGroup_) + return parentGroup_->mapItemOpacity() * opacity(); + return opacity(); +} + +void QDeclarativeGeoMapItemBase::setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup) +{ + parentGroup_ = &parentGroup; + if (parentGroup_) { + connect(parentGroup_, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged, + this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged); + } +} + +bool QDeclarativeGeoMapItemBase::isPolishScheduled() const +{ + return QQuickItemPrivate::get(this)->polishScheduled; +} + +void QDeclarativeGeoMapItemBase::setMaterialDirty() {} + +void QDeclarativeGeoMapItemBase::polishAndUpdate() +{ + polish(); + update(); +} + +QT_END_NAMESPACE |